<?php
/**
 * SiteStaffr Usage Dashboard - Minute Balance and Usage Tracking
 *
 * Displays current minute balance, usage statistics, billing history,
 * and call details for the current billing period.
 *
 * Pricing tiers and quotas are data-driven from billing cache.
 * See CLAUDE.md Section 2 for current tier structure.
 *
 * @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

// Get subscription settings
$subscription = get_option( 'sitestaffr_subscription', array() );
$subscription = wp_parse_args(
	$subscription,
	array(
		'billing_cycle_start' => current_time( 'Y-m-d' ),
		'next_billing_date'   => current_datetime()->modify( '+1 month' )->format( 'Y-m-d' ),
	)
);

// Billing redirect params are only read when nonce is valid (protects against CSRF on redirect).
$billing_message = '';
$billing_error   = '';
$billing_code    = '';
if ( isset( $_GET['_wpnonce'] )
	&& wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'sitestaffr_usage_nav' ) ) {
	$billing_message = isset( $_GET['billing_message'] ) ? sanitize_key( wp_unslash( $_GET['billing_message'] ) ) : '';
	$billing_error   = isset( $_GET['billing_error'] ) ? sanitize_key( wp_unslash( $_GET['billing_error'] ) ) : '';
	$billing_code    = isset( $_GET['billing_code'] ) ? sanitize_key( wp_unslash( $_GET['billing_code'] ) ) : '';
}

// Get Usage Manager instance (legacy fallback only for balances/stats where needed).
$usage_manager = SiteStaffr_Usage_Manager::get_instance();

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();
}

// Get billing cache (middleware source of truth for plan/status display).
$billing_cache = array();
if ( class_exists( 'SiteStaffr_Billing_State' ) ) {
	// Force refresh on usage load to keep balance and cycle data accurate after recent calls.
	$force_refresh        = true;
	SiteStaffr_Billing_State::maybe_refresh_cache( $force_refresh );
	$billing_cache = SiteStaffr_Billing_State::get_cache();
}

$status_key = isset( $billing_cache['subscription_status'] ) ? sanitize_key( $billing_cache['subscription_status'] ) : 'active';
$plan_key   = isset( $billing_cache['plan_name'] ) ? sanitize_key( $billing_cache['plan_name'] ) : 'starter';
$scheduled_downgrade_plan = ! empty( $billing_cache['scheduled_downgrade_plan'] ) ? sanitize_key( $billing_cache['scheduled_downgrade_plan'] ) : null;

$plan_labels = array(
	'trial'    => __( 'Free Trial (30 voice mins)', 'sitestaffr' ),
	'starter'  => __( 'Starter ($29/month)', 'sitestaffr' ),
	'business' => __( 'Business ($69/month)', 'sitestaffr' ),
	'pro'      => __( 'Pro ($129/month)', 'sitestaffr' ),
);

$plan_upgrade_cards = array(
	'starter'  => array(
		'label'   => __( 'Starter', 'sitestaffr' ),
		'price'   => __( '$29/month', 'sitestaffr' ),
		'minutes' => 100,
		'rank'    => 1,
		'features' => array(
			__( 'Best for small businesses just getting started', 'sitestaffr' ),
			__( 'Unlimited AI text chat', 'sitestaffr' ),
		),
	),
	'business' => array(
		'label'   => __( 'Business', 'sitestaffr' ),
		'price'   => __( '$69/month', 'sitestaffr' ),
		'minutes' => 300,
		'rank'    => 2,
		'features' => array(
			__( 'Ideal for growing local businesses', 'sitestaffr' ),
			__( 'Unlimited AI text chat, more voice minutes', 'sitestaffr' ),
		),
	),
	'pro'      => array(
		'label'   => __( 'Pro', 'sitestaffr' ),
		'price'   => __( '$129/month', 'sitestaffr' ),
		'minutes' => 600,
		'rank'    => 3,
		'features' => array(
			__( 'Best fit for high-volume operations', 'sitestaffr' ),
			__( 'Unlimited AI text chat, most voice minutes', 'sitestaffr' ),
		),
	),
);

// Voice minutes per plan. Must match PLAN_CONFIG.included_seconds in the middleware
// (config/billing.js) — the middleware is authoritative; this is display only.
$plan_quotas = array(
	'trial'    => 30,
	'starter'  => 100,
	'business' => 300,
	'pro'      => 600,
);

$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' ),
);

$status_colors = array(
	'trial_active'  => '#2271b1',
	'active'        => '#4caf50',
	'past_due'      => '#ff9800',
	'canceled'      => '#999999',
	'trial_expired' => '#f44336',
	'unpaid'        => '#f44336',
);

$plan_label            = isset( $plan_labels[ $plan_key ] ) ? $plan_labels[ $plan_key ] : ucfirst( $plan_key );
$subscription_status   = isset( $status_labels[ $status_key ] ) ? $status_labels[ $status_key ] : ucfirst( str_replace( '_', ' ', $status_key ) );
$subscription_color    = isset( $status_colors[ $status_key ] ) ? $status_colors[ $status_key ] : '#4caf50';
$included_quota_minutes = isset( $plan_quotas[ $plan_key ] ) ? (int) $plan_quotas[ $plan_key ] : 60;

// Current balance: cache first, usage manager fallback.
$included = isset( $billing_cache['included_minutes_remaining'] ) ? (int) $billing_cache['included_minutes_remaining'] : null;
$purchased = isset( $billing_cache['addon_minutes_remaining'] ) ? (int) $billing_cache['addon_minutes_remaining'] : null;
$has_seconds_precision = isset( $billing_cache['included_seconds_remaining'] ) || isset( $billing_cache['addon_seconds_remaining'] );
if ( $has_seconds_precision ) {
	$included_seconds_remaining = isset( $billing_cache['included_seconds_remaining'] ) ? (int) $billing_cache['included_seconds_remaining'] : 0;
	$addon_seconds_remaining = isset( $billing_cache['addon_seconds_remaining'] ) ? (int) $billing_cache['addon_seconds_remaining'] : 0;
	$included = (int) floor( max( 0, $included_seconds_remaining ) / 60 );
	$purchased = (int) floor( max( 0, $addon_seconds_remaining ) / 60 );
}
if ( null === $included || null === $purchased ) {
	$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_minutes;
}
if ( null === $purchased ) {
	$purchased = 0;
}
$total = $included + $purchased;

// Resolve selected billing cycle offset from query string (0 = current cycle).
// Cycle offset requires nonce when explicitly navigating; default to 0 for initial menu load.
$selected_cycle_offset = 0;
if ( isset( $_GET['cycle_offset'], $_GET['_wpnonce'] )
	&& wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'sitestaffr_usage_nav' ) ) {
	$selected_cycle_offset = absint( wp_unslash( $_GET['cycle_offset'] ) );
}

// Base cycle bounds come from the shared cycle definition — the same one the
// shareable usage report reads, so the two can never disagree.
require_once SITESTAFFR_PLUGIN_DIR . 'includes/class-sitestaffr-usage-cycle.php';
$balance_option       = get_option( 'sitestaffr_minute_balance', array() );
$sitestaffr_base_cycle = SiteStaffr_Usage_Cycle::get_base_window();
$base_period_start_ts = $sitestaffr_base_cycle['start_ts'];
$base_cycle_end_ts    = $sitestaffr_base_cycle['end_ts'];

// Determine available historical cycle offsets from persisted non-test conversations.
$cycle_activity_rows = $sitestaffr_admin_view_query_service->get_cycle_activity_rows( current_time( 'mysql' ) );
$available_cycle_offsets = array( 0 => 0 );

// Prefer true billing cycle windows from snapshot table when available.
if ( $sitestaffr_admin_view_query_service->billing_snapshot_table_exists() ) {
	$snapshot_cycle_rows = $sitestaffr_admin_view_query_service->get_billing_snapshot_cycle_period_starts( 60 );
	foreach ( $snapshot_cycle_rows as $snapshot_cycle_row ) {
		$period_start_raw = isset( $snapshot_cycle_row->period_start ) ? $snapshot_cycle_row->period_start : '';
		$period_start_ts = ! empty( $period_start_raw ) ? strtotime( $period_start_raw ) : false;
		if ( false === $period_start_ts ) {
			continue;
		}
		$offset = ( (int) gmdate( 'Y', $base_period_start_ts ) - (int) gmdate( 'Y', $period_start_ts ) ) * 12;
		$offset += (int) gmdate( 'n', $base_period_start_ts ) - (int) gmdate( 'n', $period_start_ts );
		if ( $offset < 0 ) {
			$offset = 0;
		}
		$available_cycle_offsets[ $offset ] = $offset;
	}
}

if ( ! empty( $cycle_activity_rows ) ) {
	foreach ( $cycle_activity_rows as $cycle_activity_row ) {
		$first_call_raw = isset( $cycle_activity_row->first_call_at ) ? $cycle_activity_row->first_call_at : '';
		$first_call_ts = ! empty( $first_call_raw ) ? strtotime( $first_call_raw ) : false;
		if ( false === $first_call_ts ) {
			continue;
		}

		$offset = ( (int) gmdate( 'Y', $base_period_start_ts ) - (int) gmdate( 'Y', $first_call_ts ) ) * 12;
		$offset += (int) gmdate( 'n', $base_period_start_ts ) - (int) gmdate( 'n', $first_call_ts );
		if ( $offset < 0 ) {
			$offset = 0;
		}

		$candidate_start = strtotime( '-' . $offset . ' month', $base_period_start_ts );
		if ( false !== $candidate_start && $candidate_start > $first_call_ts ) {
			$offset++;
		}

		$available_cycle_offsets[ $offset ] = $offset;
	}
}
ksort( $available_cycle_offsets );
$available_cycle_offsets = array_values( $available_cycle_offsets );

if ( ! in_array( $selected_cycle_offset, $available_cycle_offsets, true ) ) {
	$selected_cycle_offset = 0;
}

// Shift into the selected historical cycle window (shared definition).
$sitestaffr_cycle        = SiteStaffr_Usage_Cycle::get_window( $selected_cycle_offset );
$selected_cycle_start_ts = $sitestaffr_cycle['start_ts'];
$selected_cycle_end_ts   = $sitestaffr_cycle['end_ts'];
$period_start_dt         = $sitestaffr_cycle['start_dt'];
$period_end_dt           = $sitestaffr_cycle['query_end_dt'];
$period_end_ts           = strtotime( $period_end_dt );

// When & Where. These call the same query methods that
// SiteStaffr_Usage_Cycle::get_stats() wraps for the shareable report, so both
// surfaces show the same numbers — but this view already runs the rest of that
// bundle itself further down, and calling get_stats() here would re-issue every
// one of those queries a second time.
$sitestaffr_hours_state    = SiteStaffr_Business_Hours::get_state();
$sitestaffr_hours_schedule = SiteStaffr_Business_Hours::get_schedule();
$sitestaffr_after_hours    = $sitestaffr_admin_view_query_service->get_after_hours_stats(
	$period_start_dt,
	$period_end_dt,
	is_array( $sitestaffr_hours_schedule ) ? $sitestaffr_hours_schedule : array()
);
$sitestaffr_top_pages       = $sitestaffr_admin_view_query_service->get_top_source_pages( $period_start_dt, $period_end_dt, 8 );
$sitestaffr_after_hours_pct = $sitestaffr_after_hours['after_hours_pct'];
$cycle_end_ts            = $selected_cycle_end_ts;

// Resolve historical cycle snapshot (if available) for plan/quota/remaining accuracy.
$historical_cycle_snapshot = array();
if ( $selected_cycle_offset > 0 ) {
	$historical_cycle_snapshot = $sitestaffr_admin_view_query_service->get_billing_cycle_snapshot(
		$period_start_dt,
		gmdate( 'Y-m-d H:i:s', $selected_cycle_end_ts )
	);
}

if ( $selected_cycle_offset > 0 && ! empty( $historical_cycle_snapshot ) ) {
	$snapshot_plan_key = isset( $historical_cycle_snapshot['plan_name'] ) ? sanitize_key( $historical_cycle_snapshot['plan_name'] ) : '';
	$snapshot_status_key = isset( $historical_cycle_snapshot['subscription_status'] ) ? sanitize_key( $historical_cycle_snapshot['subscription_status'] ) : '';
	if ( ! empty( $snapshot_plan_key ) ) {
		$plan_key = $snapshot_plan_key;
	}
	if ( ! empty( $snapshot_status_key ) ) {
		$status_key = $snapshot_status_key;
	}
	$plan_label = isset( $plan_labels[ $plan_key ] ) ? $plan_labels[ $plan_key ] : ucfirst( $plan_key );
	$subscription_status = isset( $status_labels[ $status_key ] ) ? $status_labels[ $status_key ] : ucfirst( str_replace( '_', ' ', $status_key ) );
	$subscription_color = isset( $status_colors[ $status_key ] ) ? $status_colors[ $status_key ] : '#4caf50';
	$included_quota_minutes = isset( $plan_quotas[ $plan_key ] ) ? (int) $plan_quotas[ $plan_key ] : $included_quota_minutes;
}

// Get usage statistics for current billing period (datetime-precise).
$usage_stats = $usage_manager->get_usage_stats( $period_start_dt, $period_end_dt );
$included_used = $usage_stats['included_used'];
$purchased_used = $usage_stats['purchased_used'];
$total_used = $included_used + $purchased_used;
$billable_calls = isset( $usage_stats['billable_calls'] ) ? (int) $usage_stats['billable_calls'] : 0;
$period_counts = $sitestaffr_admin_view_query_service->get_dashboard_period_counts( $period_start_dt, $period_end_dt );
$total_conversations_count = isset( $period_counts['total_calls'] ) ? (int) $period_counts['total_calls'] : (int) $usage_stats['total_calls'];
$filtered_calls = max( 0, $total_conversations_count - $billable_calls );
// Voice vs Text split (the useful breakdown); filtered/spam is shown separately.
$voice_calls = isset( $period_counts['voice_calls'] ) ? (int) $period_counts['voice_calls'] : 0;
$text_calls  = isset( $period_counts['text_calls'] ) ? (int) $period_counts['text_calls'] : 0;

// Get billable calls for this period.
$recent_calls = $sitestaffr_admin_view_query_service->get_recent_billable_calls_for_period( $period_start_dt, $period_end_dt, 10 );


// Calculate average call duration for same period window.
$avg_duration_seconds = $sitestaffr_admin_view_query_service->get_average_call_duration_seconds_for_period( $period_start_dt, $period_end_dt );
$avg_duration_display = __( '0m 00s', 'sitestaffr' );
if ( $avg_duration_seconds > 0 ) {
	$avg_minutes = (int) floor( $avg_duration_seconds / 60 );
	$avg_seconds = (int) round( fmod( $avg_duration_seconds, 60 ) );
	if ( 60 === $avg_seconds ) {
		$avg_minutes += 1;
		$avg_seconds = 0;
	}
	$avg_duration_display = sprintf(
		/* translators: 1: minutes, 2: seconds */
		__( '%1$dm %2$02ds', 'sitestaffr' ),
		$avg_minutes,
		$avg_seconds
	);
}

// Build daily conversation volume series for current billing period.
$volume_rows = $sitestaffr_admin_view_query_service->get_daily_conversation_rows( $period_start_dt, $period_end_dt );

$daily_volume_map = array();
if ( ! empty( $volume_rows ) ) {
	foreach ( $volume_rows as $volume_row ) {
		$day_key = isset( $volume_row->day_key ) ? (string) $volume_row->day_key : '';
		if ( '' === $day_key ) {
			continue;
		}
		$daily_volume_map[ $day_key ] = (int) $volume_row->total;
	}
}

// Build daily billable conversation counts (is_billable = 1).
$billable_rows = $sitestaffr_admin_view_query_service->get_daily_conversation_rows( $period_start_dt, $period_end_dt, true );

$daily_billable_map = array();
if ( ! empty( $billable_rows ) ) {
	foreach ( $billable_rows as $row ) {
		$day_key = isset( $row->day_key ) ? (string) $row->day_key : '';
		if ( '' !== $day_key ) {
			$daily_billable_map[ $day_key ] = (int) $row->total;
		}
	}
}

// Build daily filtered conversation counts (is_billable = 0).
$filtered_rows = $sitestaffr_admin_view_query_service->get_daily_conversation_rows( $period_start_dt, $period_end_dt, false );

$daily_filtered_map = array();
if ( ! empty( $filtered_rows ) ) {
	foreach ( $filtered_rows as $row ) {
		$day_key = isset( $row->day_key ) ? (string) $row->day_key : '';
		if ( '' !== $day_key ) {
			$daily_filtered_map[ $day_key ] = (int) $row->total;
		}
	}
}

$chart_labels         = array();
$chart_values         = array();
$chart_billable_values = array();
$chart_filtered_values = array();
$chart_cursor = strtotime( gmdate( 'Y-m-d', strtotime( $period_start_dt ) ) );
$chart_cycle_end = strtotime( gmdate( 'Y-m-d', $cycle_end_ts ) );
$chart_today_end = strtotime( gmdate( 'Y-m-d', strtotime( $period_end_dt ) ) );
$chart_end = min( $chart_cycle_end, $chart_today_end );

while ( false !== $chart_cursor && false !== $chart_end && $chart_cursor <= $chart_end ) {
	$cursor_key              = gmdate( 'Y-m-d', $chart_cursor );
	$chart_labels[]          = gmdate( 'M j', $chart_cursor );
	$chart_values[]          = isset( $daily_volume_map[ $cursor_key ] ) ? (int) $daily_volume_map[ $cursor_key ] : 0;
	$chart_billable_values[] = isset( $daily_billable_map[ $cursor_key ] ) ? (int) $daily_billable_map[ $cursor_key ] : 0;
	$chart_filtered_values[] = isset( $daily_filtered_map[ $cursor_key ] ) ? (int) $daily_filtered_map[ $cursor_key ] : 0;
	$chart_cursor            = strtotime( '+1 day', $chart_cursor );
}

$chart_max = ! empty( $chart_values ) ? max( $chart_values ) : 0;
$chart_points_attr = '';
$chart_area_points_attr = '';
$chart_point_markers = array();
$chart_ticks = array();
if ( ! empty( $chart_values ) ) {
	$chart_width = 640;
	$chart_height = 200;
	$chart_padding_x = 18;
	$chart_padding_y = 14;
	$chart_inner_width = $chart_width - ( $chart_padding_x * 2 );
	$chart_inner_height = $chart_height - ( $chart_padding_y * 2 );
	$chart_baseline_y = $chart_padding_y + $chart_inner_height;
	$chart_count = count( $chart_values );
	$chart_label_interval = 1;
	if ( $chart_count > 21 ) {
		$chart_label_interval = 5;
	} elseif ( $chart_count > 14 ) {
		$chart_label_interval = 3;
	} elseif ( $chart_count > 7 ) {
		$chart_label_interval = 2;
	}
	$chart_step_x = ( $chart_count > 1 ) ? ( $chart_inner_width / ( $chart_count - 1 ) ) : 0;
	$chart_scale_max = max( 10, (int) ( ceil( $chart_max / 10 ) * 10 ) );
	$chart_points = array();
	for ( $i = 0; $i < $chart_count; $i++ ) {
		$x = $chart_padding_x + ( $chart_step_x * $i );
		$normalized = $chart_values[ $i ] / $chart_scale_max;
		$y = $chart_padding_y + ( $chart_inner_height - ( $normalized * $chart_inner_height ) );
		$chart_points[] = number_format( $x, 2, '.', '' ) . ',' . number_format( $y, 2, '.', '' );
		$chart_point_markers[] = array(
			'x'        => $x,
			'y'        => $y,
			'label'    => $chart_labels[ $i ],
			'value'    => (int) $chart_values[ $i ],
			'billable' => (int) $chart_billable_values[ $i ],
			'filtered' => (int) $chart_filtered_values[ $i ],
		);
	}
	$chart_points_attr = implode( ' ', $chart_points );

	if ( ! empty( $chart_point_markers ) ) {
		$first_marker = $chart_point_markers[0];
		$last_marker  = $chart_point_markers[ $chart_count - 1 ];
		$area_points  = array(
			number_format( $first_marker['x'], 2, '.', '' ) . ',' . number_format( $chart_baseline_y, 2, '.', '' ),
		);
		foreach ( $chart_points as $chart_point ) {
			$area_points[] = $chart_point;
		}
		$area_points[] = number_format( $last_marker['x'], 2, '.', '' ) . ',' . number_format( $chart_baseline_y, 2, '.', '' );
		$chart_area_points_attr = implode( ' ', $area_points );
	}

	$tick_count = 5;
	for ( $t = 0; $t < $tick_count; $t++ ) {
		$ratio = $t / ( $tick_count - 1 );
		$tick_value = (int) round( $chart_scale_max * ( 1 - $ratio ) );
		$tick_y = $chart_padding_y + ( $chart_inner_height * $ratio );
		$chart_ticks[] = array(
			'value' => $tick_value,
			'y'     => $tick_y,
		);
	}
} else {
	$chart_width = 640;
	$chart_height = 200;
	$chart_padding_x = 18;
	$chart_padding_y = 14;
}

$next_billing_raw = isset( $billing_cache['subscription_current_period_end'] ) ? $billing_cache['subscription_current_period_end'] : $subscription['next_billing_date'];
$next_billing_ts  = ! empty( $next_billing_raw ) ? strtotime( $next_billing_raw ) : false;
$next_billing_label = __( 'Next Billing:', 'sitestaffr' );

if ( 'trial_active' === $status_key && ! empty( $billing_cache['trial_expires_at'] ) ) {
	$trial_ts = strtotime( $billing_cache['trial_expires_at'] );
	if ( $trial_ts ) {
		$next_billing_ts    = $trial_ts;
		$next_billing_label = __( 'Trial Ends:', 'sitestaffr' );
	}
}

// All dates display in Eastern Time (site-wide convention).
$usage_display_tz = new DateTimeZone( 'America/New_York' );
$next_billing_display = $next_billing_ts ? wp_date( 'F j, Y', $next_billing_ts, $usage_display_tz ) : esc_html__( 'N/A', 'sitestaffr' );
$plan_cycle_label = ( 0 === $selected_cycle_offset ) ? __( 'Current cycle', 'sitestaffr' ) : __( 'Selected cycle', 'sitestaffr' );
$selected_cycle_date_text = sprintf(
	/* translators: %1$s: cycle start date, %2$s: cycle end date */
	__( '%1$s - %2$s', 'sitestaffr' ),
	wp_date( 'M j, Y', $selected_cycle_start_ts, $usage_display_tz ),
	wp_date( 'M j, Y', $selected_cycle_end_ts, $usage_display_tz )
);
$selected_cycle_index = array_search( $selected_cycle_offset, $available_cycle_offsets, true );
if ( false === $selected_cycle_index ) {
	$selected_cycle_index = 0;
}
$can_go_older = ( $selected_cycle_index < ( count( $available_cycle_offsets ) - 1 ) );
$can_go_newer = ( $selected_cycle_index > 0 );
$older_offset = $can_go_older ? $available_cycle_offsets[ $selected_cycle_index + 1 ] : $selected_cycle_offset;
$newer_offset = $can_go_newer ? $available_cycle_offsets[ $selected_cycle_index - 1 ] : $selected_cycle_offset;
$older_cycle_url = $can_go_older ? wp_nonce_url(
	add_query_arg(
		array(
			'page'         => 'sitestaffr-usage',
			'cycle_offset' => $older_offset,
		),
		admin_url( 'admin.php' )
	),
	'sitestaffr_usage_nav'
) : '';
$newer_cycle_url = $can_go_newer ? wp_nonce_url(
	add_query_arg(
		array(
			'page'         => 'sitestaffr-usage',
			'cycle_offset' => $newer_offset,
		),
		admin_url( 'admin.php' )
	),
	'sitestaffr_usage_nav'
) : '';
$cycle_options = array();
foreach ( $available_cycle_offsets as $offset ) {
	$option_start_ts = strtotime( '-' . $offset . ' month', $base_period_start_ts );
	$option_end_ts   = strtotime( '-' . $offset . ' month', $base_cycle_end_ts );
	if ( false === $option_start_ts || false === $option_end_ts ) {
		continue;
	}

	$label = sprintf(
		/* translators: %1$s: cycle start date, %2$s: cycle end date */
		__( '%1$s - %2$s', 'sitestaffr' ),
		wp_date( 'M j, Y', $option_start_ts, $usage_display_tz ),
		wp_date( 'M j, Y', $option_end_ts, $usage_display_tz )
	);

	$cycle_options[] = array(
		'offset' => $offset,
		'label'  => $label,
		'url'    => wp_nonce_url(
			add_query_arg(
				array(
					'page'         => 'sitestaffr-usage',
					'cycle_offset' => $offset,
				),
				admin_url( 'admin.php' )
			),
			'sitestaffr_usage_nav'
		),
	);
}

$billing_success_messages = array(
	'checkout_success'  => __( 'Checkout completed. Billing state will sync automatically in a few moments.', 'sitestaffr' ),
	'checkout_canceled' => __( 'Checkout was canceled. No changes were made.', 'sitestaffr' ),
	'portal_return'     => __( 'Returned from customer portal.', 'sitestaffr' ),
	'downgrade_canceled' => __( 'Scheduled downgrade canceled. Your current plan will continue.', 'sitestaffr' ),
);

$billing_error_messages = array(
	'missing_account'      => __( 'Billing account ID is missing. Re-run site registration before using billing actions.', 'sitestaffr' ),
	'invalid_request'      => __( 'Invalid billing request.', 'sitestaffr' ),
	'invalid_plan'         => __( 'Invalid plan selected.', 'sitestaffr' ),
	'invalid_addon'        => __( 'Invalid add-on selected.', 'sitestaffr' ),
	'request_failed'       => __( 'Could not reach billing service. Please try again.', 'sitestaffr' ),
	'invalid_response'     => __( 'Billing service returned an unexpected response. Please try again.', 'sitestaffr' ),
	'missing_middleware_url' => __( 'Billing configuration is incomplete (missing middleware URL).', 'sitestaffr' ),
	'missing_api_secret'   => __( 'Billing configuration is incomplete (missing API secret).', 'sitestaffr' ),
	'invalid_redirect_host' => __( 'Billing service returned an untrusted redirect URL.', 'sitestaffr' ),
);

// Plan meta values should align with selected cycle context.
$is_historical_cycle = ( $selected_cycle_offset > 0 );
$included_quota_display = $included_quota_minutes;
$plan_meta_addon_remaining_display = $purchased;

if ( $is_historical_cycle ) {
	if ( ! empty( $historical_cycle_snapshot ) ) {
		$plan_meta_addon_remaining_display = isset( $historical_cycle_snapshot['addon_minutes_remaining'] ) ? max( 0, (int) $historical_cycle_snapshot['addon_minutes_remaining'] ) : null;
	} else {
		// Fallback when historical snapshots are unavailable.
		// Infer trial cycles from cached trial bounds when possible; otherwise use plan defaults.
		$trial_start_ts = ! empty( $billing_cache['trial_started_at'] ) ? strtotime( $billing_cache['trial_started_at'] ) : false;
		$trial_end_ts   = ! empty( $billing_cache['trial_expires_at'] ) ? strtotime( $billing_cache['trial_expires_at'] ) : false;
		$is_trial_cycle = false;
		if ( false !== $trial_start_ts && false !== $trial_end_ts ) {
			$is_trial_cycle = ( $selected_cycle_start_ts < $trial_end_ts ) && ( $selected_cycle_end_ts > $trial_start_ts );
		}

		if ( $is_trial_cycle ) {
			$included_quota_display = isset( $plan_quotas['trial'] ) ? (int) $plan_quotas['trial'] : 30;
			if ( isset( $plan_labels['trial'] ) ) {
				$plan_label = $plan_labels['trial'];
			}
		} else {
			$included_quota_display = isset( $plan_quotas[ $plan_key ] ) ? (int) $plan_quotas[ $plan_key ] : $included_quota_minutes;
		}

		// Treat unknown historical add-on remainder as zero for deterministic utilization.
		$plan_meta_addon_remaining_display = 0;
	}
}

$cycle_end_chip_label = ( 0 === $selected_cycle_offset ) ? __( 'Next Reset:', 'sitestaffr' ) : __( 'Cycle Ended:', 'sitestaffr' );
$cycle_end_chip_value = wp_date( 'M j, Y', $cycle_end_ts, $usage_display_tz );
$plan_chip_label = trim( (string) preg_replace( '/\s*\(.+\)$/', '', wp_strip_all_tags( $plan_label ) ) );
if ( '' === $plan_chip_label ) {
	$plan_chip_label = $plan_label;
}
$plan_chip_text = $plan_chip_label;
if ( false === stripos( $plan_chip_text, 'plan' ) ) {
	$plan_chip_text = trim( $plan_chip_text . ' ' . __( 'Plan', 'sitestaffr' ) );
}

$cycle_capacity_minutes = null;
if ( null !== $included_quota_display && null !== $plan_meta_addon_remaining_display ) {
	$cycle_capacity_minutes = max(
		0,
		(int) $included_quota_display + (int) $purchased_used + (int) $plan_meta_addon_remaining_display
	);
}

$cycle_utilization_meta = __( 'Capacity unavailable for this cycle', 'sitestaffr' );
if ( null !== $cycle_capacity_minutes && $cycle_capacity_minutes > 0 ) {
	$cycle_utilization_meta = sprintf(
		/* translators: 1: used minutes, 2: cycle capacity minutes */
		__( '%1$d of %2$d minutes', 'sitestaffr' ),
		(int) $total_used,
		(int) $cycle_capacity_minutes
	);
}

// Burn-rate projection (current cycle only): at the current pace, how many
// minutes will this cycle consume vs. its capacity?
$burn_rate_display = '';
$burn_rate_meta    = '';
$burn_rate_state   = '';
if ( 0 === $selected_cycle_offset && null !== $cycle_capacity_minutes && $cycle_capacity_minutes > 0 ) {
	$burn_cycle_span    = max( 1, $cycle_end_ts - $selected_cycle_start_ts );
	$burn_cycle_elapsed = min( $burn_cycle_span, max( 1, strtotime( current_time( 'mysql' ) ) - $selected_cycle_start_ts ) );
	$burn_pace_minutes  = (int) round( ( (float) $total_used / (float) $burn_cycle_elapsed ) * $burn_cycle_span );
	$burn_rate_state    = ( $burn_pace_minutes > $cycle_capacity_minutes ) ? 'will-run-short' : 'on-track';
	$burn_rate_display  = ( 'will-run-short' === $burn_rate_state )
		? __( 'Will run short', 'sitestaffr' )
		: __( 'On track', 'sitestaffr' );
	$burn_rate_meta     = sprintf(
		/* translators: 1: projected minutes at current pace, 2: cycle capacity minutes */
		__( 'On pace for ~%1$d of %2$d minutes', 'sitestaffr' ),
		$burn_pace_minutes,
		(int) $cycle_capacity_minutes
	);
}

// Leads captured this cycle — the outcome metric, so it leads the strip.
$cycle_leads_count = class_exists( 'SiteStaffr_Leads' )
	? SiteStaffr_Leads::get_lead_count_between( $period_start_dt, $period_end_dt )
	: 0;
$leads_meta = __( 'Contact details captured', 'sitestaffr' );
if ( $total_conversations_count > 0 ) {
	// The lead count and the conversation count filter rows differently (a
	// quota-exceeded lead counts as a lead but not as a conversation), so the
	// ratio is capped rather than allowed to read over 100%.
	$leads_pct = (int) round( ( (float) $cycle_leads_count / (float) $total_conversations_count ) * 100 );
	$leads_meta = sprintf(
		/* translators: %d: percentage of conversations that captured a lead */
		__( '%d%% of conversations', 'sitestaffr' ),
		min( 100, max( 0, $leads_pct ) )
	);
}

// Shareable analytics report (print-ready standalone page, leads-page model).
$usage_report_url = class_exists( 'SiteStaffr_Usage_Report' ) ? SiteStaffr_Usage_Report::get_page_url() : '';
?>

<div class="wrap sitestaffr-wrap sitestaffr-usage-dashboard" data-cycle-offset="<?php echo esc_attr( $selected_cycle_offset ); ?>">
	<?php
	$sitestaffr_page_title = __( 'Usage & Billing', 'sitestaffr' );
	include SITESTAFFR_PLUGIN_DIR . 'admin/partials/sitestaffr-header.php';
	?>

	<?php if ( ! empty( $billing_message ) && isset( $billing_success_messages[ $billing_message ] ) ) : ?>
		<div class="notice notice-success is-dismissible">
			<p><?php echo esc_html( $billing_success_messages[ $billing_message ] ); ?></p>
		</div>
	<?php endif; ?>

	<?php if ( ! empty( $billing_error ) ) : ?>
		<div class="notice notice-error is-dismissible">
			<p>
				<?php
				$error_text = isset( $billing_error_messages[ $billing_error ] ) ? $billing_error_messages[ $billing_error ] : __( 'Billing action failed.', 'sitestaffr' );
				echo esc_html( $error_text );
				if ( ! empty( $billing_code ) ) {
					// translators: %s: the error code.
					echo ' ' . esc_html( sprintf( __( '(Error: %s)', 'sitestaffr' ), $billing_code ) );
				}
				?>
			</p>
		</div>
	<?php endif; ?>

	<!-- Current Period Summary -->
	<div class="sitestaffr-usage-section">
		<div class="sitestaffr-section-header-with-actions">
			<h2><span class="dashicons dashicons-calendar-alt" aria-hidden="true"></span><?php esc_html_e( 'Billing Cycle', 'sitestaffr' ); ?></h2>
			<div class="sitestaffr-cycle-controls">
				<?php if ( $can_go_older ) : ?>
					<a class="sitestaffr-cycle-nav-btn" href="<?php echo esc_url( $older_cycle_url ); ?>" aria-label="<?php esc_attr_e( 'View older billing cycle', 'sitestaffr' ); ?>">
						<span class="dashicons dashicons-arrow-left-alt2" aria-hidden="true"></span>
					</a>
				<?php else : ?>
					<span class="sitestaffr-cycle-nav-btn is-disabled" aria-hidden="true">
						<span class="dashicons dashicons-arrow-left-alt2"></span>
					</span>
				<?php endif; ?>

				<details class="sitestaffr-cycle-picker">
					<summary class="sitestaffr-cycle-current-link"><?php echo esc_html( $selected_cycle_date_text ); ?></summary>
					<div class="sitestaffr-cycle-list" role="listbox" aria-label="<?php esc_attr_e( 'Billing cycle history', 'sitestaffr' ); ?>">
						<?php foreach ( $cycle_options as $cycle_option ) : ?>
							<a href="<?php echo esc_url( $cycle_option['url'] ); ?>" class="sitestaffr-cycle-option <?php echo esc_attr( ( (int) $cycle_option['offset'] === $selected_cycle_offset ) ? 'is-active' : '' ); ?>">
								<?php echo esc_html( $cycle_option['label'] ); ?>
							</a>
						<?php endforeach; ?>
					</div>
				</details>

				<?php if ( $can_go_newer ) : ?>
					<a class="sitestaffr-cycle-nav-btn" href="<?php echo esc_url( $newer_cycle_url ); ?>" aria-label="<?php esc_attr_e( 'View newer billing cycle', 'sitestaffr' ); ?>">
						<span class="dashicons dashicons-arrow-right-alt2" aria-hidden="true"></span>
					</a>
				<?php else : ?>
					<span class="sitestaffr-cycle-nav-btn is-disabled" aria-hidden="true">
						<span class="dashicons dashicons-arrow-right-alt2"></span>
					</span>
				<?php endif; ?>
			</div>
		</div>
		<div class="sitestaffr-cycle-summary-strip">
			<article class="sitestaffr-cycle-metric">
				<div class="sitestaffr-cycle-metric-label"><?php esc_html_e( 'Leads', 'sitestaffr' ); ?></div>
				<div class="sitestaffr-cycle-metric-value"><?php echo esc_html( $cycle_leads_count ); ?></div>
				<div class="sitestaffr-cycle-metric-meta"><?php echo esc_html( $leads_meta ); ?></div>
			</article>

			<article class="sitestaffr-cycle-metric">
				<div class="sitestaffr-cycle-metric-label"><?php esc_html_e( 'Conversations', 'sitestaffr' ); ?></div>
				<div class="sitestaffr-cycle-metric-value"><?php echo esc_html( $total_conversations_count ); ?></div>
				<div class="sitestaffr-cycle-metric-meta">
					<?php // translators: %1$d: voice conversation count, %2$d: text conversation count. ?>
					<?php echo esc_html( sprintf( __( 'Voice %1$d | Text %2$d', 'sitestaffr' ), $voice_calls, $text_calls ) ); ?>
				</div>
			</article>

			<article class="sitestaffr-cycle-metric">
				<div class="sitestaffr-cycle-metric-label"><?php esc_html_e( 'Minutes Used', 'sitestaffr' ); ?></div>
				<div class="sitestaffr-cycle-metric-value"><?php echo esc_html( $total_used ); ?></div>
				<div class="sitestaffr-cycle-metric-meta"><?php echo esc_html( $cycle_utilization_meta ); ?></div>
			</article>

			<article class="sitestaffr-cycle-metric">
				<div class="sitestaffr-cycle-metric-label"><?php esc_html_e( 'Avg Conversation Length', 'sitestaffr' ); ?></div>
				<div class="sitestaffr-cycle-metric-value"><?php echo esc_html( $avg_duration_display ); ?></div>
				<div class="sitestaffr-cycle-metric-meta"><?php esc_html_e( 'Across billable conversations', 'sitestaffr' ); ?></div>
			</article>
		</div>
		<div class="sitestaffr-cycle-chip-row">
			<span class="sitestaffr-cycle-chip"><?php echo esc_html( $plan_chip_text ); ?></span>
			<?php if ( $filtered_calls > 0 ) : ?>
				<?php // Spam/low-quality conversations the system screened out — reassurance, not a headline metric. ?>
				<span class="sitestaffr-cycle-chip" title="<?php esc_attr_e( 'Low-quality or spam conversations automatically filtered out and not billed.', 'sitestaffr' ); ?>">
					<span aria-hidden="true">🛡️</span>
					<?php
					/* translators: %d: number of filtered (spam/low-quality) conversations. */
					echo esc_html( sprintf( _n( '%d filtered as spam', '%d filtered as spam', $filtered_calls, 'sitestaffr' ), $filtered_calls ) );
					?>
				</span>
			<?php endif; ?>
			<span class="sitestaffr-cycle-chip">
				<strong><?php echo esc_html( $cycle_end_chip_label ); ?></strong>
				<?php echo esc_html( $cycle_end_chip_value ); ?>
			</span>
			<?php if ( '' !== $burn_rate_display ) : ?>
				<?php // Pace lives beside the cycle facts, not in a tile — it is a status, not a metric. ?>
				<span class="sitestaffr-cycle-chip sitestaffr-cycle-chip--pace is-<?php echo esc_attr( $burn_rate_state ); ?>">
					<strong><?php echo esc_html( $burn_rate_display ); ?></strong>
					<?php echo esc_html( $burn_rate_meta ); ?>
				</span>
				<?php if ( 'will-run-short' === $burn_rate_state ) : ?>
					<button type="button" class="button button-primary button-small sitestaffr-burn-cta" data-open-buy-modal><?php esc_html_e( 'Buy more minutes', 'sitestaffr' ); ?></button>
				<?php endif; ?>
			<?php endif; ?>
			<span class="sitestaffr-cycle-chip-actions">
				<?php if ( '' !== $usage_report_url ) : ?>
					<button type="button" class="button button-small sitestaffr-print-page" data-print-url="<?php echo esc_attr( add_query_arg( 'cycle', max( 0, $selected_cycle_offset ), $usage_report_url ) ); ?>">
						<span class="dashicons dashicons-printer" aria-hidden="true"></span>
						<?php esc_html_e( 'Print / Download', 'sitestaffr' ); ?>
					</button>
					<button type="button" class="button button-small sitestaffr-copy-report-link" data-report-url="<?php echo esc_attr( $usage_report_url ); ?>">
						<span class="dashicons dashicons-share" aria-hidden="true"></span>
						<?php esc_html_e( 'Copy share link', 'sitestaffr' ); ?>
					</button>
				<?php endif; ?>
			</span>
		</div>
	</div>

	<!-- Daily Trend (conversations or billed minutes) -->
	<div class="sitestaffr-usage-section">
		<div class="sitestaffr-section-header-with-filters">
			<h2><span class="dashicons dashicons-chart-line" aria-hidden="true"></span><?php esc_html_e( 'Daily Trend', 'sitestaffr' ); ?></h2>
			<div class="sitestaffr-metric-filters" data-section="chart-metric" aria-label="<?php esc_attr_e( 'Chart metric', 'sitestaffr' ); ?>">
				<button type="button" class="sitestaffr-filter-pill is-active" data-metric="conversations"><?php esc_html_e( 'Conversations', 'sitestaffr' ); ?></button>
				<button type="button" class="sitestaffr-filter-pill" data-metric="minutes"><?php esc_html_e( 'Minutes', 'sitestaffr' ); ?></button>
			</div>
			<div class="sitestaffr-channel-filters" data-section="chart">
				<button type="button" class="sitestaffr-filter-pill is-active" data-channel="all"><?php esc_html_e( 'All', 'sitestaffr' ); ?></button>
				<button type="button" class="sitestaffr-filter-pill" data-channel="widget"><?php esc_html_e( 'Widget', 'sitestaffr' ); ?></button>
				<button type="button" class="sitestaffr-filter-pill" data-channel="button"><?php esc_html_e( 'Button', 'sitestaffr' ); ?></button>
			</div>
		</div>
		<div class="sitestaffr-stats-box sitestaffr-filter-content sitestaffr-chart-panel" id="sitestaffr-chart-content" data-metric="conversations" data-channel="all">
			<?php if ( ! empty( $chart_values ) ) : ?>
				<svg class="sitestaffr-chart-svg" viewBox="0 0 <?php echo esc_attr( $chart_width ); ?> <?php echo esc_attr( $chart_height ); ?>" role="img" aria-label="<?php esc_attr_e( 'Daily conversation volume chart', 'sitestaffr' ); ?>">
					<?php foreach ( $chart_ticks as $chart_tick ) : ?>
						<line x1="<?php echo esc_attr( $chart_padding_x ); ?>" y1="<?php echo esc_attr( number_format( $chart_tick['y'], 2, '.', '' ) ); ?>" x2="<?php echo esc_attr( $chart_width - $chart_padding_x ); ?>" y2="<?php echo esc_attr( number_format( $chart_tick['y'], 2, '.', '' ) ); ?>" stroke="#e5e7eb" stroke-width="1" />
						<text x="2" y="<?php echo esc_attr( number_format( $chart_tick['y'] + 4, 2, '.', '' ) ); ?>" font-size="10" fill="#6b7280"><?php echo esc_html( $chart_tick['value'] ); ?></text>
					<?php endforeach; ?>
					<?php if ( '' !== $chart_area_points_attr ) : ?>
						<polygon points="<?php echo esc_attr( $chart_area_points_attr ); ?>" fill="rgba(0, 131, 143, 0.12)" />
					<?php endif; ?>
					<polyline points="<?php echo esc_attr( $chart_points_attr ); ?>" fill="none" stroke="#00838F" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
					<?php foreach ( $chart_point_markers as $chart_marker ) : ?>
						<circle cx="<?php echo esc_attr( number_format( $chart_marker['x'], 2, '.', '' ) ); ?>" cy="<?php echo esc_attr( number_format( $chart_marker['y'], 2, '.', '' ) ); ?>" r="3.5" fill="#ffffff" stroke="#00838F" stroke-width="2">
							<?php // translators: %1$s: date label, %2$d: billable count, %3$d: filtered count. ?>
							<title><?php echo esc_html( sprintf( __( '%1$s — Billable: %2$d | Filtered: %3$d', 'sitestaffr' ), $chart_marker['label'], $chart_marker['billable'], $chart_marker['filtered'] ) ); ?></title>
						</circle>
						<?php if ( $chart_marker['value'] > 0 ) : ?>
						<text x="<?php echo esc_attr( number_format( $chart_marker['x'], 2, '.', '' ) ); ?>" y="<?php echo esc_attr( number_format( $chart_marker['y'] - 8, 2, '.', '' ) ); ?>" text-anchor="middle" font-size="10" font-weight="600" fill="#00838F" stroke="#ffffff" stroke-width="3" paint-order="stroke"><?php echo esc_html( $chart_marker['value'] ); ?></text>
						<?php endif; ?>
					<?php endforeach; ?>
				<?php foreach ( $chart_point_markers as $idx => $marker ) : ?>
						<?php
						$is_first = ( 0 === $idx );
						$is_last  = ( $idx === $chart_count - 1 );
						$is_interval = ( 0 === $idx % $chart_label_interval );
						// Skip interval labels that are too close to the last label (avoids overlap).
						$too_close_to_last = ( ! $is_last && $is_interval && ( $chart_count - 1 - $idx ) < $chart_label_interval );
						if ( $is_first || $is_last || ( $is_interval && ! $too_close_to_last ) ) :
						?>
							<text x="<?php echo esc_attr( number_format( $marker['x'], 2, '.', '' ) ); ?>" y="<?php echo esc_attr( number_format( $chart_height - 2, 2, '.', '' ) ); ?>" text-anchor="middle" font-size="9" fill="#6b7280"><?php echo esc_html( $marker['label'] ); ?></text>
						<?php endif; ?>
					<?php endforeach; ?>
				</svg>
			<?php else : ?>
				<p class="sitestaffr-chart-empty"><?php esc_html_e( 'No conversation data yet in this billing period.', 'sitestaffr' ); ?></p>
			<?php endif; ?>
		</div>
	</div>

	<!-- When & Where -->
	<div class="sitestaffr-usage-section">
		<div class="sitestaffr-section-header-with-filters">
			<h2><span class="dashicons dashicons-clock" aria-hidden="true"></span><?php esc_html_e( 'When & Where', 'sitestaffr' ); ?></h2>
		</div>
		<div class="sitestaffr-stats-box sitestaffr-coverage-grid">

			<div class="sitestaffr-coverage-panel">
				<h3><?php esc_html_e( 'After Hours', 'sitestaffr' ); ?></h3>
				<?php if ( 'configured' === $sitestaffr_hours_state ) : ?>
					<p class="sitestaffr-coverage-figure"><?php echo esc_html( $sitestaffr_after_hours_pct . '%' ); ?></p>
					<p class="sitestaffr-coverage-sub">
						<?php
						printf(
							/* translators: %1$s: after-hours conversations, %2$s: total conversations, %3$s: after-hours qualified leads. */
							esc_html__( '%1$s of %2$s conversations arrived while you were closed — including %3$s qualified leads.', 'sitestaffr' ),
							esc_html( number_format_i18n( $sitestaffr_after_hours['after_hours'] ) ),
							esc_html( number_format_i18n( $sitestaffr_after_hours['total'] ) ),
							esc_html( number_format_i18n( $sitestaffr_after_hours['after_hours_leads'] ) )
						);
						?>
					</p>
				<?php else : ?>
					<div class="sitestaffr-coverage-empty">
						<p>
							<?php
							if ( 'always_open' === $sitestaffr_hours_state ) {
								esc_html_e( 'Your hours are set to 24/7, so there are no after-hours conversations to measure.', 'sitestaffr' );
							} else {
								esc_html_e( 'We could not read your opening hours, so after-hours conversations cannot be measured.', 'sitestaffr' );
							}
							?>
						</p>
						<p>
							<a class="button button-secondary" href="<?php echo esc_url( admin_url( 'admin.php?page=sitestaffr-settings' ) ); ?>">
								<?php esc_html_e( 'Set your opening hours', 'sitestaffr' ); ?>
							</a>
						</p>
					</div>
				<?php endif; ?>
			</div>

			<div class="sitestaffr-coverage-panel">
				<h3><?php esc_html_e( 'Top Pages', 'sitestaffr' ); ?></h3>
				<?php if ( empty( $sitestaffr_top_pages ) ) : ?>
					<p class="sitestaffr-chart-empty"><?php esc_html_e( 'No conversations in this billing period yet.', 'sitestaffr' ); ?></p>
				<?php else : ?>
					<table class="sitestaffr-pages-table">
						<thead>
							<tr>
								<th scope="col"><?php esc_html_e( 'Page', 'sitestaffr' ); ?></th>
								<th scope="col"><?php esc_html_e( 'Conversations', 'sitestaffr' ); ?></th>
								<th scope="col"><?php esc_html_e( 'Qualified Leads', 'sitestaffr' ); ?></th>
							</tr>
						</thead>
						<tbody>
							<?php foreach ( $sitestaffr_top_pages as $sitestaffr_page_row ) : ?>
								<tr<?php echo $sitestaffr_page_row['is_unknown'] ? ' class="sitestaffr-pages-unknown"' : ''; ?>>
									<td>
										<?php if ( $sitestaffr_page_row['is_unknown'] ) : ?>
											<?php esc_html_e( 'Not recorded', 'sitestaffr' ); ?>
										<?php else : ?>
											<a href="<?php echo esc_url( $sitestaffr_page_row['page'] ); ?>" target="_blank" rel="noopener">
												<?php echo esc_html( '' !== $sitestaffr_page_row['title'] ? $sitestaffr_page_row['title'] : $sitestaffr_page_row['page'] ); ?>
											</a>
										<?php endif; ?>
									</td>
									<td><?php echo esc_html( number_format_i18n( $sitestaffr_page_row['conversations'] ) ); ?></td>
									<td><?php echo esc_html( number_format_i18n( $sitestaffr_page_row['leads'] ) ); ?></td>
								</tr>
							<?php endforeach; ?>
						</tbody>
					</table>
				<?php endif; ?>
			</div>

		</div>
	</div>

	<!-- Recent Conversations Table -->
	<div class="sitestaffr-usage-section">
		<div class="sitestaffr-section-header-with-filters">
			<h2><span class="dashicons dashicons-format-chat" aria-hidden="true"></span><?php esc_html_e( 'Recent Conversations', 'sitestaffr' ); ?></h2>
			<div class="sitestaffr-channel-filters" data-section="recent">
				<button type="button" class="sitestaffr-filter-pill is-active" data-channel="all"><?php esc_html_e( 'All', 'sitestaffr' ); ?></button>
				<button type="button" class="sitestaffr-filter-pill" data-channel="widget"><?php esc_html_e( 'Widget', 'sitestaffr' ); ?></button>
				<button type="button" class="sitestaffr-filter-pill" data-channel="button"><?php esc_html_e( 'Button', 'sitestaffr' ); ?></button>
			</div>
		</div>
		<div class="sitestaffr-filter-content" id="sitestaffr-recent-content">
		<?php if ( ! empty( $recent_calls ) ) : ?>
		<table class="wp-list-table widefat fixed striped sitestaffr-usage-recent-table">
			<thead>
				<tr>
					<th><?php esc_html_e( 'Session', 'sitestaffr' ); ?></th>
					<th><?php esc_html_e( 'Date', 'sitestaffr' ); ?></th>
					<th><?php esc_html_e( 'Channel', 'sitestaffr' ); ?></th>
					<th><?php esc_html_e( 'Duration', 'sitestaffr' ); ?></th>
				</tr>
			</thead>
			<tbody>
				<?php foreach ( $recent_calls as $call ) : ?>
				<tr>
					<td data-colname="<?php esc_attr_e( 'Session', 'sitestaffr' ); ?>"><?php
						$session_id_val = isset( $call->session_id ) ? (string) $call->session_id : '';
						if ( '' !== $session_id_val ) {
							$sid_detail_url = wp_nonce_url( add_query_arg( array(
								'page'    => 'sitestaffr',
								'action'  => 'view',
								'call_id' => (int) $call->id,
							), admin_url( 'admin.php' ) ), 'sitestaffr_view_call' );
							echo '<a href="' . esc_url( $sid_detail_url ) . '" class="sitestaffr-call-sid-link" title="' . esc_attr( $session_id_val ) . '">' . esc_html( $session_id_val ) . '</a>';
						} else {
							echo '&mdash;';
						}
					?></td>
					<td data-colname="<?php esc_attr_e( 'Date', 'sitestaffr' ); ?>"><?php
						// Prefer created_at for billing-window consistency; fallback to started_at for legacy rows.
						$call_time_raw = ! empty( $call->created_at ) ? $call->created_at : $call->started_at;
						if ( is_numeric( $call_time_raw ) ) {
							$started_timestamp = (int) $call_time_raw;
						} else {
							// Stored via current_time('mysql') — site-local — so parse in the
							// site timezone (strtotime would read it as UTC).
							try {
								$started_timestamp = ( new DateTime( (string) $call_time_raw, wp_timezone() ) )->getTimestamp();
							} catch ( Exception $e ) {
								$started_timestamp = 0;
							}
						}
						$detail_url = wp_nonce_url( add_query_arg( array(
							'page'    => 'sitestaffr',
							'action'  => 'view',
							'call_id' => (int) $call->id,
						), admin_url( 'admin.php' ) ), 'sitestaffr_view_call' );
						echo esc_html( wp_date( 'M j', $started_timestamp, $usage_display_tz ) );
					?></td>
					<td data-colname="<?php esc_attr_e( 'Channel', 'sitestaffr' ); ?>">
						<?php
						$channel_value = isset( $call->service_type ) ? sanitize_key( $call->service_type ) : '';
						$session_id_value = isset( $call->session_id ) ? (string) $call->session_id : '';
						$is_widget_session = ( 0 === strpos( $session_id_value, 'sess_' ) );
						if ( 'webrtc_button' === $channel_value ) {
							echo esc_html__( 'Button', 'sitestaffr' );
						} elseif ( 'webrtc_widget' === $channel_value ) {
							echo esc_html__( 'Widget', 'sitestaffr' );
						} elseif ( 'chat_button' === $channel_value ) {
							echo esc_html__( 'Chat Button', 'sitestaffr' );
						} elseif ( 'chat_widget' === $channel_value ) {
							echo esc_html__( 'Chat Widget', 'sitestaffr' );
						} elseif ( $is_widget_session || 'webrtc' === $channel_value || '' === $channel_value || 'web' === $channel_value || 'widget' === $channel_value ) {
							echo esc_html__( 'Widget', 'sitestaffr' );
						} elseif ( 'phone' === $channel_value ) {
							echo esc_html__( 'Phone', 'sitestaffr' );
						} else {
							echo esc_html( ucwords( str_replace( '_', ' ', $channel_value ) ) );
						}
						?>
					</td>
					<td data-colname="<?php esc_attr_e( 'Duration', 'sitestaffr' ); ?>">
						<?php
						if ( $call->call_duration > 0 ) {
							$minutes = floor( $call->call_duration / 60 );
							$seconds = $call->call_duration % 60;
							echo esc_html( sprintf( '%dm %02ds', $minutes, $seconds ) );
						} else {
							echo esc_html__( 'N/A', 'sitestaffr' );
						}
						?>
					</td>
				</tr>
				<?php endforeach; ?>
			</tbody>
		</table>
		<?php else : ?>
		<div class="sitestaffr-empty-state">
			<p><?php esc_html_e( 'No conversations yet in this billing period.', 'sitestaffr' ); ?></p>
		</div>
		<?php endif; ?>
		</div>
	</div>

	<?php
	$action_plan_cards = array();
	foreach ( $plan_upgrade_cards as $action_plan_key => $action_plan_data ) {
		if ( $action_plan_key === $plan_key ) {
			continue;
		}
		if ( 'trial' === $plan_key && 'starter' === $action_plan_key ) {
			continue;
		}
		$action_plan_cards[ $action_plan_key ] = $action_plan_data;
	}

	$trial_starter_offer = null;
	if ( 'trial' === $plan_key && isset( $plan_upgrade_cards['starter'] ) ) {
		$trial_starter_offer = $plan_upgrade_cards['starter'];
	}
	?>

	<!-- Plan & Billing (Consolidated) -->
	<div class="sitestaffr-usage-section" id="purchase-minutes">
		<h2><span class="dashicons dashicons-money-alt" aria-hidden="true"></span><?php esc_html_e( 'Plan & Billing', 'sitestaffr' ); ?></h2>
		<div class="sitestaffr-plan-billing-grid">
			<div class="sitestaffr-plan-card">
				<div class="sitestaffr-plan-card-header">
					<h3><span class="dashicons dashicons-id-alt" aria-hidden="true"></span><?php esc_html_e( 'Current Plan', 'sitestaffr' ); ?></h3>
					<span class="sitestaffr-plan-status-pill" style="--sitestaffr-status-bg: <?php echo esc_attr( $subscription_color ); ?>; --sitestaffr-status-text: #ffffff;">
						<?php echo esc_html( $subscription_status ); ?>
					</span>
				</div>
				<div class="sitestaffr-plan-card-title"><?php echo esc_html( $plan_label ); ?></div>
				<?php if ( $scheduled_downgrade_plan && isset( $plan_labels[ $scheduled_downgrade_plan ] ) ) : ?>
					<div class="sitestaffr-plan-downgrade-note" style="font-size: 12px; color: #996800; background: #fff8e5; border: 1px solid #e6d5a8; border-radius: 4px; padding: 6px 10px; margin-top: 6px; display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap;">
						<span>
						<?php
						echo esc_html(
							sprintf(
								/* translators: %1$s: new plan label, %2$s: renewal date */
								__( 'Changing to %1$s on %2$s', 'sitestaffr' ),
								$plan_labels[ $scheduled_downgrade_plan ],
								$next_billing_display
							)
						);
						?>
						</span>
						<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin: 0;" onsubmit="var b=this.querySelector('button');b.disabled=true;b.innerHTML='<span class=\'spinner is-active\' style=\'float:none;margin:0 4px 0 0;vertical-align:middle;\'></span>Canceling downgrade\u2026';return true;">
							<input type="hidden" name="action" value="sitestaffr_cancel_downgrade">
							<?php wp_nonce_field( 'sitestaffr_cancel_downgrade' ); ?>
							<button type="submit" style="background: none; border: none; color: #996800; text-decoration: underline; cursor: pointer; font-size: 12px; padding: 0;"><?php esc_html_e( 'Cancel Downgrade', 'sitestaffr' ); ?></button>
						</form>
					</div>
				<?php endif; ?>
				<div class="sitestaffr-plan-cycle">
					<?php
					echo esc_html(
						sprintf(
							/* translators: %1$s: cycle context label, %2$s: cycle start date, %3$s: cycle end date */
							__( '%1$s: %2$s - %3$s', 'sitestaffr' ),
							$plan_cycle_label,
							wp_date( 'M j', $selected_cycle_start_ts, $usage_display_tz ),
							wp_date( 'M j', $cycle_end_ts, $usage_display_tz )
						)
					);
					?>
				</div>
				<div class="sitestaffr-plan-meta">
					<?php if ( null !== $trial_starter_offer ) : ?>
						<div class="sitestaffr-plan-meta-row sitestaffr-plan-meta-row-cta">
							<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" target="_blank">
								<input type="hidden" name="action" value="sitestaffr_billing_checkout">
								<input type="hidden" name="checkout_type" value="subscription">
								<input type="hidden" name="plan_name" value="starter">
								<?php wp_nonce_field( 'sitestaffr_billing_checkout' ); ?>
								<button type="submit" class="button button-primary sitestaffr-starter-cta-button">
									<?php
									echo esc_html(
										sprintf(
											/* translators: %s starter plan price */
											__( 'Upgrade to Starter Plan (%s)', 'sitestaffr' ),
											$trial_starter_offer['price']
										)
									);
									?>
								</button>
							</form>
						</div>
					<?php else : ?>
						<div class="sitestaffr-plan-meta-row">
							<span><?php echo esc_html( $next_billing_label ); ?></span>
							<strong><?php echo esc_html( $next_billing_display ); ?></strong>
						</div>
					<?php endif; ?>
					<div class="sitestaffr-plan-meta-row">
						<span><?php esc_html_e( 'Included Minutes', 'sitestaffr' ); ?></span>
						<strong><?php echo esc_html( null !== $included_quota_display ? $included_quota_display : __( 'N/A', 'sitestaffr' ) ); ?></strong>
					</div>
					<div class="sitestaffr-plan-meta-row">
						<span><?php esc_html_e( 'Add-on Minutes Remaining', 'sitestaffr' ); ?></span>
						<strong><?php echo esc_html( null !== $plan_meta_addon_remaining_display ? (int) $plan_meta_addon_remaining_display : __( 'N/A', 'sitestaffr' ) ); ?></strong>
					</div>
				</div>
			</div>

			<div class="sitestaffr-plan-actions-card">
				<div class="sitestaffr-actions-header">
					<h3><span class="dashicons dashicons-admin-tools" aria-hidden="true"></span><?php esc_html_e( 'Actions', 'sitestaffr' ); ?></h3>
					<button type="button" class="button sitestaffr-button-buy-more" id="sitestaffr-open-buy-modal" data-open-buy-modal><span class="dashicons dashicons-plus-alt2" aria-hidden="true"></span><?php esc_html_e( 'Buy More Minutes', 'sitestaffr' ); ?></button>
				</div>

				<?php if ( ! empty( $action_plan_cards ) ) : ?>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" target="_blank" class="sitestaffr-billing-note-manage-form">
						<input type="hidden" name="action" value="sitestaffr_billing_portal">
						<?php wp_nonce_field( 'sitestaffr_billing_portal' ); ?>
						<button type="submit" class="button button-secondary sitestaffr-button-manage-subscription">
							<span class="dashicons dashicons-admin-generic" aria-hidden="true"></span>
							<span class="sitestaffr-button-label"><?php esc_html_e( 'Manage Subscription', 'sitestaffr' ); ?></span>
						</button>
					</form>
					<div class="sitestaffr-upgrade-cards-grid">
						<?php foreach ( $action_plan_cards as $action_plan_key => $action_plan_data ) : ?>
							<div class="sitestaffr-upgrade-plan-form">
								<button type="button" class="sitestaffr-upgrade-plan-card sitestaffr-upgrade-plan-card--<?php echo esc_attr( $action_plan_key ); ?>" data-plan="<?php echo esc_attr( $action_plan_key ); ?>" data-plan-label="<?php echo esc_attr( $action_plan_data['label'] ); ?>" data-plan-price="<?php echo esc_attr( $action_plan_data['price'] ); ?>" data-plan-minutes="<?php echo esc_attr( (int) $action_plan_data['minutes'] ); ?>" data-plan-rank="<?php echo esc_attr( (int) $action_plan_data['rank'] ); ?>">
									<div class="sitestaffr-upgrade-plan-top">
										<span class="sitestaffr-upgrade-plan-name"><?php echo esc_html( $action_plan_data['label'] ); ?></span>
										<span class="sitestaffr-upgrade-plan-price"><?php echo esc_html( $action_plan_data['price'] ); ?></span>
									</div>
									<span class="sitestaffr-upgrade-plan-minutes">
										<?php
										echo esc_html(
											sprintf(
												/* translators: %d minutes */
												__( '%d minutes included', 'sitestaffr' ),
												(int) $action_plan_data['minutes']
											)
										);
										?>
									</span>
									<?php if ( ! empty( $action_plan_data['features'] ) && is_array( $action_plan_data['features'] ) ) : ?>
										<ul class="sitestaffr-upgrade-plan-features">
											<?php foreach ( $action_plan_data['features'] as $feature_text ) : ?>
												<li><?php echo esc_html( $feature_text ); ?></li>
											<?php endforeach; ?>
										</ul>
									<?php endif; ?>
								</button>
								<!-- Fallback form for no-JS -->
								<noscript>
									<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" target="_blank">
										<input type="hidden" name="action" value="sitestaffr_billing_checkout">
										<input type="hidden" name="checkout_type" value="subscription">
										<input type="hidden" name="plan_name" value="<?php echo esc_attr( $action_plan_key ); ?>">
										<?php wp_nonce_field( 'sitestaffr_billing_checkout' ); ?>
										<?php // translators: %s: the plan name. ?>
										<button type="submit" class="button button-primary"><?php echo esc_html( sprintf( __( 'Upgrade to %s', 'sitestaffr' ), $action_plan_data['label'] ) ); ?></button>
									</form>
								</noscript>
							</div>
						<?php endforeach; ?>
					</div>
				<?php else : ?>
					<p class="sitestaffr-billing-note"><?php esc_html_e( 'No plan changes available for this account state right now.', 'sitestaffr' ); ?></p>
				<?php endif; ?>
			</div>
		</div>
	</div>

</div>

<div class="sitestaffr-upgrade-context" style="display:none;" data-current-plan="<?php echo esc_attr( $plan_key ); ?>" data-current-plan-label="<?php echo esc_attr( isset( $plan_labels[ $plan_key ] ) ? $plan_labels[ $plan_key ] : ucfirst( $plan_key ) ); ?>" data-current-minutes="<?php echo esc_attr( isset( $plan_quotas[ $plan_key ] ) ? (int) $plan_quotas[ $plan_key ] : 0 ); ?>" data-current-rank="<?php echo esc_attr( isset( $plan_upgrade_cards[ $plan_key ]['rank'] ) ? (int) $plan_upgrade_cards[ $plan_key ]['rank'] : 0 ); ?>" data-next-billing-date="<?php echo esc_attr( $next_billing_display ); ?>" data-scheduled-downgrade="<?php echo esc_attr( $scheduled_downgrade_plan ? $scheduled_downgrade_plan : '' ); ?>"></div>

<!-- Upgrade Plan Modal -->
<div class="sitestaffr-modal-overlay" id="sitestaffr-upgrade-modal" role="dialog" aria-modal="true" aria-labelledby="sitestaffr-upgrade-modal-title" style="display: none;">
	<div class="sitestaffr-modal" role="document">
		<div class="sitestaffr-modal-header">
			<h2 id="sitestaffr-upgrade-modal-title">
				<span class="dashicons dashicons-upload" aria-hidden="true"></span>
				<span id="sitestaffr-upgrade-modal-heading"><?php esc_html_e( 'Upgrade Plan', 'sitestaffr' ); ?></span>
			</h2>
			<button type="button" class="sitestaffr-modal-close" aria-label="<?php esc_attr_e( 'Close', 'sitestaffr' ); ?>">
				<span class="dashicons dashicons-no-alt" aria-hidden="true"></span>
			</button>
		</div>
		<div class="sitestaffr-modal-body">
			<!-- Loading state (shown while fetching preview) -->
			<div class="sitestaffr-upgrade-loading" id="sitestaffr-upgrade-loading">
				<div class="sitestaffr-upgrade-spinner"></div>
				<p><?php esc_html_e( 'Calculating proration...', 'sitestaffr' ); ?></p>
			</div>
			<!-- Error state -->
			<div class="sitestaffr-upgrade-error" id="sitestaffr-upgrade-error" style="display: none;">
				<span class="dashicons dashicons-warning" aria-hidden="true"></span>
				<p id="sitestaffr-upgrade-error-message"></p>
			</div>
			<!-- Preview data (shown after successful fetch) -->
			<div class="sitestaffr-upgrade-preview" id="sitestaffr-upgrade-preview" style="display: none;">
				<div class="sitestaffr-upgrade-plan-comparison">
					<div class="sitestaffr-upgrade-from">
						<span class="sitestaffr-upgrade-direction"><?php esc_html_e( 'Current', 'sitestaffr' ); ?></span>
						<strong id="sitestaffr-upgrade-from-label"></strong>
					</div>
					<span class="sitestaffr-upgrade-arrow dashicons dashicons-arrow-right-alt" aria-hidden="true"></span>
					<div class="sitestaffr-upgrade-to">
						<span class="sitestaffr-upgrade-direction"><?php esc_html_e( 'New', 'sitestaffr' ); ?></span>
						<strong id="sitestaffr-upgrade-to-label"></strong>
					</div>
				</div>

				<div class="sitestaffr-upgrade-summary">
					<div class="sitestaffr-upgrade-summary-row">
						<span><?php esc_html_e( 'Due today (prorated)', 'sitestaffr' ); ?></span>
						<strong id="sitestaffr-upgrade-due-today"></strong>
					</div>
					<div class="sitestaffr-upgrade-summary-row">
						<span id="sitestaffr-upgrade-next-renewal-label"><?php esc_html_e( 'Next renewal', 'sitestaffr' ); ?></span>
						<strong id="sitestaffr-upgrade-next-renewal"></strong>
					</div>
				</div>

				<div class="sitestaffr-upgrade-details">
					<div class="sitestaffr-upgrade-detail-item">
						<span class="sitestaffr-upgrade-detail-icon dashicons dashicons-arrow-up-alt" aria-hidden="true"></span>
						<div class="sitestaffr-upgrade-detail-content">
							<span class="sitestaffr-upgrade-detail-label"><?php esc_html_e( 'Included minutes', 'sitestaffr' ); ?></span>
							<span class="sitestaffr-upgrade-detail-value" id="sitestaffr-upgrade-minutes-text"></span>
						</div>
					</div>
					<div class="sitestaffr-upgrade-detail-item" id="sitestaffr-upgrade-cycle-note" style="display: none;">
						<span class="sitestaffr-upgrade-detail-icon dashicons dashicons-update" aria-hidden="true"></span>
						<div class="sitestaffr-upgrade-detail-content">
							<span class="sitestaffr-upgrade-detail-label"><?php esc_html_e( 'Billing cycle', 'sitestaffr' ); ?></span>
							<span class="sitestaffr-upgrade-detail-value" id="sitestaffr-upgrade-cycle-text"></span>
						</div>
					</div>
					<div class="sitestaffr-upgrade-detail-item sitestaffr-upgrade-carryover-item" id="sitestaffr-upgrade-carryover-note" style="display: none;">
						<span class="sitestaffr-upgrade-detail-icon dashicons dashicons-backup" aria-hidden="true"></span>
						<div class="sitestaffr-upgrade-detail-content">
							<span class="sitestaffr-upgrade-detail-label"><?php esc_html_e( 'Trial balance', 'sitestaffr' ); ?></span>
							<span class="sitestaffr-upgrade-detail-value" id="sitestaffr-upgrade-carryover-text"></span>
						</div>
					</div>
				</div>
			</div>
		</div>
		<div class="sitestaffr-modal-footer" id="sitestaffr-upgrade-footer" style="display: none;">
			<button type="button" class="button sitestaffr-modal-cancel"><?php esc_html_e( 'Cancel', 'sitestaffr' ); ?></button>
			<button type="button" class="button button-primary sitestaffr-modal-confirm sitestaffr-upgrade-confirm-btn" id="sitestaffr-upgrade-confirm">
				<span class="dashicons dashicons-upload" aria-hidden="true"></span>
				<?php esc_html_e( 'Confirm Upgrade', 'sitestaffr' ); ?>
			</button>
		</div>
		<!-- Processing state footer (replaces normal footer during execution) -->
		<div class="sitestaffr-modal-footer sitestaffr-upgrade-processing-footer" id="sitestaffr-upgrade-processing" style="display: none;">
			<div class="sitestaffr-upgrade-processing-text">
				<span class="sitestaffr-upgrade-spinner sitestaffr-upgrade-spinner-small"></span>
				<?php esc_html_e( 'Processing upgrade...', 'sitestaffr' ); ?>
			</div>
		</div>
	</div>
</div>

<!-- Downgrade Plan Modal -->
<div class="sitestaffr-modal-overlay" id="sitestaffr-downgrade-modal" role="dialog" aria-modal="true" aria-labelledby="sitestaffr-downgrade-modal-title" style="display: none;">
	<div class="sitestaffr-modal" role="document">
		<div class="sitestaffr-modal-header sitestaffr-downgrade-modal-header">
			<h2 id="sitestaffr-downgrade-modal-title">
				<span class="dashicons dashicons-download" aria-hidden="true"></span>
				<span id="sitestaffr-downgrade-modal-heading"><?php esc_html_e( 'Downgrade Plan', 'sitestaffr' ); ?></span>
			</h2>
			<button type="button" class="sitestaffr-modal-close" aria-label="<?php esc_attr_e( 'Close', 'sitestaffr' ); ?>">
				<span class="dashicons dashicons-no-alt" aria-hidden="true"></span>
			</button>
		</div>
		<div class="sitestaffr-modal-body">
			<div class="sitestaffr-downgrade-info-box">
				<span class="dashicons dashicons-info-outline" aria-hidden="true"></span>
				<p id="sitestaffr-downgrade-info-text"><?php esc_html_e( 'Your plan change will take effect at the end of your current billing cycle.', 'sitestaffr' ); ?></p>
			</div>

			<div class="sitestaffr-downgrade-plan-comparison">
				<div class="sitestaffr-downgrade-from">
					<span class="sitestaffr-downgrade-direction"><?php esc_html_e( 'Current', 'sitestaffr' ); ?></span>
					<strong id="sitestaffr-downgrade-from-label"></strong>
					<span class="sitestaffr-downgrade-minutes" id="sitestaffr-downgrade-from-minutes"></span>
				</div>
				<span class="sitestaffr-downgrade-arrow dashicons dashicons-arrow-right-alt" aria-hidden="true"></span>
				<div class="sitestaffr-downgrade-to">
					<span class="sitestaffr-downgrade-direction"><?php esc_html_e( 'New', 'sitestaffr' ); ?></span>
					<strong id="sitestaffr-downgrade-to-label"></strong>
					<span class="sitestaffr-downgrade-minutes" id="sitestaffr-downgrade-to-minutes"></span>
				</div>
			</div>

			<div class="sitestaffr-downgrade-details">
				<div class="sitestaffr-downgrade-detail-row">
					<span class="dashicons dashicons-calendar-alt" aria-hidden="true"></span>
					<span id="sitestaffr-downgrade-effective-text"><?php esc_html_e( 'Effective at the end of your billing cycle.', 'sitestaffr' ); ?></span>
				</div>
				<div class="sitestaffr-downgrade-detail-row">
					<span class="dashicons dashicons-yes-alt" aria-hidden="true"></span>
					<span id="sitestaffr-downgrade-keep-text"><?php esc_html_e( 'You will keep your current plan benefits until then.', 'sitestaffr' ); ?></span>
				</div>
				<div class="sitestaffr-downgrade-detail-row sitestaffr-downgrade-detail-row--warning">
					<span class="dashicons dashicons-warning" aria-hidden="true"></span>
					<span id="sitestaffr-downgrade-minutes-warning"><?php esc_html_e( 'Your included minutes will decrease at renewal.', 'sitestaffr' ); ?></span>
				</div>
			</div>
		</div>
		<div class="sitestaffr-modal-footer" id="sitestaffr-downgrade-footer">
			<button type="button" class="button sitestaffr-modal-cancel"><?php esc_html_e( 'Cancel', 'sitestaffr' ); ?></button>
			<button type="button" class="button button-primary" id="sitestaffr-downgrade-confirm">
				<?php esc_html_e( 'Confirm Downgrade', 'sitestaffr' ); ?>
			</button>
		</div>
		<div class="sitestaffr-modal-footer sitestaffr-upgrade-processing-footer" id="sitestaffr-downgrade-processing" style="display: none;">
			<div class="sitestaffr-upgrade-processing-text">
				<span class="sitestaffr-upgrade-spinner sitestaffr-upgrade-spinner-small"></span>
				<?php esc_html_e( 'Processing your downgrade...', 'sitestaffr' ); ?>
			</div>
		</div>
		<div class="sitestaffr-upgrade-error" id="sitestaffr-downgrade-error" style="display: none;">
			<span class="dashicons dashicons-warning" aria-hidden="true"></span>
			<span id="sitestaffr-downgrade-error-message"></span>
		</div>
	</div>
</div>

<!-- Hidden checkout form for JS-based new subscription (no active sub) -->
<form id="sitestaffr-checkout-form" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" target="_blank" style="display:none;">
	<input type="hidden" name="action" value="sitestaffr_billing_checkout">
	<input type="hidden" name="checkout_type" value="subscription">
	<input type="hidden" name="plan_name" value="" id="sitestaffr-checkout-plan-name">
	<?php wp_nonce_field( 'sitestaffr_billing_checkout' ); ?>
</form>
<?php // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound ?>
