<?php
/**
 * Front-end shortcodes (student portal).
 *
 * @package TradeSchoolManager
 */

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

class TSM_Shortcodes {
	private static $instance = null;
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}
	private function __construct() {
		add_shortcode( 'tsm_student_login', array( $this, 'sc_login' ) );
		add_shortcode( 'tsm_student_portal', array( $this, 'sc_portal' ) );
		add_shortcode( 'tsm_student_gradebook', array( $this, 'sc_gradebook' ) );
		add_shortcode( 'tsm_student_payments', array( $this, 'sc_payments' ) );
		// [tsm_applications] and [tsm_application_form] are registered by the
		// standalone "TradeSchool Manager  -  Applications" add-on as of v1.18.5.
	}

	public function sc_login() {
		wp_enqueue_style( 'tsm-public' );
		// Logout is handled at init in TSM_Public::maybe_handle_logout(); cookies cannot be cleared after headers are sent.
		$sid = TSM_Public::current_student_id();
		ob_start();
		echo '<div class="tsm-portal-wrap">';

		// --- Already logged in ---
		if ( $sid ) {
			$s = TSM_Students::get( $sid );
			$portal_url = TSM_Public::get_page_url( 'student_portal_page', remove_query_arg( array( 'tsm_logged_out', 'tsm_login_error' ) ) );
			if ( $portal_url && ! self::is_current_url( $portal_url ) && ! headers_sent() ) {
				wp_safe_redirect( $portal_url );
				exit;
			}
			echo wp_kses_post( $this->already_signed_in_card(
				$s ? trim( $s->first_name . ' ' . $s->last_name ) : '',
				$portal_url,
				add_query_arg( 'tsm_logout', 1 ),
				__( 'You are already signed in to the student portal.', 'tradeschool-manager' ),
				__( 'Continue to Student Portal', 'tradeschool-manager' )
			) );
			echo '</div>';
			return ob_get_clean();
		}

		$school = tsm_get_setting( 'school_name', 'TradeSchool' );

		// --- Reset password screen (token in URL) ---
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reset token in URL is itself the credential; verified against DB before any state change.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reset token in URL is itself the credential; verified against DB before any state change.
		if ( isset( $_GET['tsm_reset'] ) ) {
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reset token in URL is itself the credential.
			$token = sanitize_text_field( wp_unslash( $_GET['tsm_reset'] ) );
			$student = TSM_Students::get_by_reset_token( $token );
			?>
			<div class="tsm-auth-shell">
				<div class="tsm-auth-card">
					<h2 class="tsm-auth-title"><?php echo esc_html( $school ); ?></h2>
					<p class="tsm-auth-sub"><?php esc_html_e( 'Choose a New Password', 'tradeschool-manager' ); ?></p>
					<?php if ( ! $student ) : ?>
						<div class="tsm-error"><?php esc_html_e( 'This reset link is invalid or has expired. Request a new one below.', 'tradeschool-manager' ); ?></div>
						<p><a class="tsm-link" href="<?php echo esc_url( remove_query_arg( array( 'tsm_reset', 'tsm_reset_error' ) ) ); ?>"><?php esc_html_e( 'Back to sign in', 'tradeschool-manager' ); ?></a></p>
					<?php else :
						// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only display flag from previous redirect.
						$err = isset( $_GET['tsm_reset_error'] ) ? sanitize_text_field( wp_unslash( $_GET['tsm_reset_error'] ) ) : ''; ?>
						<?php if ( 'short' === $err ) : ?><div class="tsm-error"><?php esc_html_e( 'Password must be at least 8 characters.', 'tradeschool-manager' ); ?></div><?php endif; ?>
						<?php if ( 'mismatch' === $err ) : ?><div class="tsm-error"><?php esc_html_e( 'Passwords do not match.', 'tradeschool-manager' ); ?></div><?php endif; ?>
						<form method="post" class="tsm-login-form">
							<?php wp_nonce_field( 'tsm_reset', 'tsm_reset_nonce' ); ?>
							<input type="hidden" name="tsm_reset_token" value="<?php echo esc_attr( $token ); ?>">
							<label class="tsm-field"><span><?php esc_html_e( 'New password', 'tradeschool-manager' ); ?></span><input type="password" name="tsm_new_password" autocomplete="new-password" required></label>
							<label class="tsm-field"><span><?php esc_html_e( 'Confirm new password', 'tradeschool-manager' ); ?></span><input type="password" name="tsm_new_password2" autocomplete="new-password" required></label>
							<button type="submit" class="tsm-btn tsm-btn--primary tsm-btn--block"><?php esc_html_e( 'Save New Password', 'tradeschool-manager' ); ?></button>
						</form>
					<?php endif; ?>
				</div>
			</div>
			<?php
			echo '</div>';
			return ob_get_clean();
		}

		// --- Forgot password screen ---
		if ( isset( $_GET['tsm_forgot'] ) ) { // phpcs:ignore
			?>
			<div class="tsm-auth-shell">
				<div class="tsm-auth-card">
					<h2 class="tsm-auth-title"><?php echo esc_html( $school ); ?></h2>
					<p class="tsm-auth-sub"><?php esc_html_e( 'Reset Your Password', 'tradeschool-manager' ); ?></p>
					<?php if ( isset( $_GET['tsm_forgot_sent'] ) ) : // phpcs:ignore ?>
						<div class="tsm-success"><?php esc_html_e( 'If that email matches a student account, we\'ve sent a password reset link. Please check your inbox.', 'tradeschool-manager' ); ?></div>
						<p><a class="tsm-link" href="<?php echo esc_url( remove_query_arg( array( 'tsm_forgot', 'tsm_forgot_sent' ) ) ); ?>"><?php esc_html_e( 'Back to sign in', 'tradeschool-manager' ); ?></a></p>
					<?php else : ?>
						<p class="tsm-auth-note"><?php esc_html_e( 'Enter the email address on file for your student account. We\'ll send you a secure link to choose a new password.', 'tradeschool-manager' ); ?></p>
						<form method="post" class="tsm-login-form">
							<?php wp_nonce_field( 'tsm_forgot', 'tsm_forgot_nonce' ); ?>
							<label class="tsm-field"><span><?php esc_html_e( 'Email address', 'tradeschool-manager' ); ?></span><input type="email" name="tsm_email" autocomplete="email" required></label>
							<button type="submit" class="tsm-btn tsm-btn--primary tsm-btn--block"><?php esc_html_e( 'Send Reset Link', 'tradeschool-manager' ); ?></button>
						</form>
						<p class="tsm-auth-note"><a class="tsm-link" href="<?php echo esc_url( remove_query_arg( 'tsm_forgot' ) ); ?>"><?php esc_html_e( 'Back to sign in', 'tradeschool-manager' ); ?></a></p>
					<?php endif; ?>
				</div>
			</div>
			<?php
			echo '</div>';
			return ob_get_clean();
		}

		// --- Default sign-in screen ---
		?>
		<div class="tsm-auth-shell">
			<div class="tsm-auth-card">
				<h2 class="tsm-auth-title"><?php echo esc_html( $school ); ?></h2>
				<p class="tsm-auth-sub"><?php esc_html_e( 'Student Portal Sign In', 'tradeschool-manager' ); ?></p>
				<?php if ( isset( $_GET['tsm_login_error'] ) ) : // phpcs:ignore ?>
					<div class="tsm-error"><?php esc_html_e( 'Invalid username or password.', 'tradeschool-manager' ); ?></div>
				<?php endif; ?>
				<?php if ( isset( $_GET['tsm_reset_done'] ) ) : // phpcs:ignore ?>
					<div class="tsm-success"><?php esc_html_e( 'Password updated. You can sign in with your new password now.', 'tradeschool-manager' ); ?></div>
				<?php endif; ?>
				<form method="post" class="tsm-login-form">
					<?php wp_nonce_field( 'tsm_login', 'tsm_login_nonce' ); ?>
					<input type="hidden" name="tsm_login" value="1">
					<label class="tsm-field">
						<span><?php esc_html_e( 'Username', 'tradeschool-manager' ); ?></span>
						<input type="text" name="tsm_username" autocomplete="username" required>
					</label>
					<label class="tsm-field">
						<span><?php esc_html_e( 'Password', 'tradeschool-manager' ); ?></span>
						<input type="password" name="tsm_password" autocomplete="current-password" required>
					</label>
					<button type="submit" class="tsm-btn tsm-btn--primary tsm-btn--block"><?php esc_html_e( 'Sign In', 'tradeschool-manager' ); ?></button>
				</form>
				<p class="tsm-auth-note">
					<a class="tsm-link" href="<?php echo esc_url( add_query_arg( 'tsm_forgot', 1 ) ); ?>"><?php esc_html_e( 'Forgot your password?', 'tradeschool-manager' ); ?></a>
				</p>
				<p class="tsm-auth-note"><?php esc_html_e( 'Accounts are created by your school. Contact the office if you need access.', 'tradeschool-manager' ); ?></p>
			</div>
		</div>
		<?php
		echo '</div>';
		return ob_get_clean();
	}

	private static function is_current_url( $url ) {
		$host        = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
		$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
		$current     = ( is_ssl() ? 'https://' : 'http://' ) . $host . $request_uri;
		return untrailingslashit( strtok( $current, '?' ) ) === untrailingslashit( strtok( $url, '?' ) );
	}

	private function already_signed_in_card( $name, $portal_url, $logout_url, $message, $button_label ) {
		$name = $name ?: __( 'your account', 'tradeschool-manager' );
		ob_start();
		?>
		<div class="tsm-auth-shell">
			<div class="tsm-auth-card tsm-auth-card--status">
				<div class="tsm-auth-badge"><?php esc_html_e( 'Signed in', 'tradeschool-manager' ); ?></div>
				<h2 class="tsm-auth-title"><?php echo esc_html( $message ); ?></h2>
				<p class="tsm-auth-note">
					<?php
					printf(
						/* translators: %s: account name. */
						esc_html__( 'You are signed in as %s.', 'tradeschool-manager' ),
						esc_html( $name )
					);
					?>
				</p>
				<div class="tsm-auth-actions">
					<a class="tsm-btn tsm-btn--primary" href="<?php echo esc_url( $portal_url ); ?>"><?php echo esc_html( $button_label ); ?></a>
					<a class="tsm-btn tsm-btn--ghost" href="<?php echo esc_url( $logout_url ); ?>"><?php esc_html_e( 'Log out', 'tradeschool-manager' ); ?></a>
				</div>
			</div>
		</div>
		<?php
		return ob_get_clean();
	}

	public function sc_portal() {
		wp_enqueue_style( 'tsm-public' );
		$sid = TSM_Public::current_student_id();
		if ( ! $sid ) {
			return $this->sc_login();
		}
		$student = TSM_Students::get( $sid );
		$classes = TSM_Classes::classes_for_student( $sid );
		$initials = strtoupper( substr( $student->first_name, 0, 1 ) . substr( $student->last_name, 0, 1 ) );
		$active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'grades'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only UI state.
		$allowed_tabs = array( 'grades', 'assignments', 'payments', 'certificates', 'workshops', 'settings' );
		if ( ! in_array( $active_tab, $allowed_tabs, true ) ) {
			$active_tab = 'grades';
		}

		// Aggregate stats.
		$class_count   = count( $classes );
		$assign_total  = 0;
		$avg_percents  = array();
		foreach ( $classes as $c ) {
			$assign_total += count( TSM_Assignments::for_class( $c->id ) );
			$g = TSM_Gradebook::calc_class_grade( $c->id, $sid );
			if ( null !== $g['percent'] ) $avg_percents[] = (float) $g['percent'];
		}
		$overall = $avg_percents ? round( array_sum( $avg_percents ) / count( $avg_percents ), 1 ) : null;
		$overall_letter = null !== $overall ? TSM_Gradebook::percent_to_letter( $overall ) : ' - ';
		$certs = ( tsm_addon_active( 'certificates' ) && class_exists( 'TSM_Certificates' ) ) ? TSM_Certificates::for_student( $sid ) : array();
		$portal_uid = 'tsm_student_portal_' . wp_generate_password( 6, false, false );

		ob_start();
		TSM_Inline_Assets::script(
			'tsm-student-portal-tabs-' . $portal_uid,
			'(function(){
				function ready(fn){
					if (document.readyState === "loading") {
						document.addEventListener("DOMContentLoaded", fn);
					} else {
						fn();
					}
				}
				ready(function(){
					var wrap = document.getElementById(' . wp_json_encode( $portal_uid ) . ');
					if (!wrap) return;
					var tabs = wrap.querySelectorAll(\'.tsm-tab[data-tab]\');
					var panels = wrap.querySelectorAll(\'.tsm-tabpanel[data-panel]\');
					tabs.forEach(function(t){
						t.addEventListener(\'click\', function(e){
							e.preventDefault();
							tabs.forEach(function(x){ x.classList.remove(\'is-active\'); });
							panels.forEach(function(p){ p.classList.remove(\'is-active\'); });
							t.classList.add(\'is-active\');
							var key = t.getAttribute(\'data-tab\');
							var panel = wrap.querySelector(\'.tsm-tabpanel[data-panel="\'+key+\'"]\');
							if (panel) panel.classList.add(\'is-active\');
						});
					});
					var subtabs = wrap.querySelectorAll(\'.tsm-subtab[data-sub]\');
					var subpanels = wrap.querySelectorAll(\'.tsm-subpanel[data-subpanel]\');
					subtabs.forEach(function(t){
						t.addEventListener(\'click\', function(e){
							e.preventDefault();
							subtabs.forEach(function(x){ x.classList.remove(\'is-active\'); });
							subpanels.forEach(function(p){ p.classList.remove(\'is-active\'); });
							t.classList.add(\'is-active\');
							var key = t.getAttribute(\'data-sub\');
							var panel = wrap.querySelector(\'.tsm-subpanel[data-subpanel="\'+key+\'"]\');
							if (panel) panel.classList.add(\'is-active\');
						});
					});
					var notice = wrap.querySelector(\'.tsm-tabpanel[data-panel="settings"] .tsm-error, .tsm-tabpanel[data-panel="settings"] .tsm-success\');
					if (notice) {
						setTimeout(function(){
							try { notice.scrollIntoView({ behavior: \'smooth\', block: \'center\' }); } catch(e) { notice.scrollIntoView(); }
						}, 60);
					}
					var assignmentLists = wrap.querySelectorAll(\'[data-tsm-assignment-list]\');
					assignmentLists.forEach(function(list){
						var table = list.closest(\'.tsm-student-assignment-table\');
						if (table) table.classList.add(\'is-enhanced\');
						var detailRows = list.querySelectorAll(\'[data-tsm-assignment-detail]\');
						detailRows.forEach(function(row){ row.hidden = true; });

						function closeRows(exceptId) {
							list.querySelectorAll(\'[data-tsm-assignment-toggle]\').forEach(function(row){
								var id = row.getAttribute(\'data-tsm-assignment-toggle\');
								if (exceptId && id === exceptId) return;
								row.classList.remove(\'is-expanded\');
								var button = row.querySelector(\'.tsm-assignment-toggle\');
								if (button) button.setAttribute(\'aria-expanded\', \'false\');
							});
							detailRows.forEach(function(row){
								if (exceptId && row.getAttribute(\'data-tsm-assignment-detail\') === exceptId) return;
								row.hidden = true;
							});
						}

						list.querySelectorAll(\'[data-tsm-assignment-toggle]\').forEach(function(row){
							var button = row.querySelector(\'.tsm-assignment-toggle\');
							if (!button) return;
							function toggleRow() {
								var id = row.getAttribute(\'data-tsm-assignment-toggle\');
								var detail = list.querySelector(\'[data-tsm-assignment-detail="\' + id + \'"]\');
								if (!detail) return;
								var opening = button.getAttribute(\'aria-expanded\') !== \'true\';
								closeRows(opening ? id : null);
								row.classList.toggle(\'is-expanded\', opening);
								button.setAttribute(\'aria-expanded\', opening ? \'true\' : \'false\');
								detail.hidden = !opening;
							}
							button.addEventListener(\'click\', function(e){
								e.stopPropagation();
								toggleRow();
							});
							row.addEventListener(\'click\', function(e){
								if (e.target.closest(\'a, button, input, select, textarea, label\')) return;
								toggleRow();
							});
						});
					});
				});
			})();'
		);
		?>
		<div class="tsm-portal-wrap tsm-portal" id="<?php echo esc_attr( $portal_uid ); ?>">

			<!-- Profile cover + identity -->
			<section class="tsm-profile-card">
				<div class="tsm-cover" style="background: var(--tsm-cover, linear-gradient(135deg, #1f6feb, #6ea8ff));"></div>
				<div class="tsm-profile-body">
					<div class="tsm-avatar-wrap">
						<?php if ( ! empty( $student->photo_url ) ) : ?>
							<img class="tsm-avatar" src="<?php echo esc_url( $student->photo_url ); ?>" alt="">
						<?php else : ?>
							<div class="tsm-avatar tsm-avatar--initials"><?php echo esc_html( $initials ); ?></div>
						<?php endif; ?>
					</div>
					<div class="tsm-identity">
						<h1 class="tsm-name"><?php echo esc_html( $student->first_name . ' ' . $student->last_name ); ?></h1>
						<p class="tsm-tagline">
							<span class="tsm-tagline-school"><?php echo esc_html( tsm_get_setting( 'school_name', 'TradeSchool' ) ); ?></span>
							<?php if ( ! empty( $student->status ) ) : ?>
								<span class="tsm-tagline-sep">*</span>
								<span class="tsm-chip tsm-chip--<?php echo esc_attr( $student->status ); ?>"><?php echo esc_html( ucfirst( $student->status ) ); ?></span>
							<?php endif; ?>
						</p>
					</div>
					<div class="tsm-profile-actions">
						<?php
						/**
						 * Allow add-ons (Reports & Transcripts, etc.) to inject portal header buttons
						 * such as "Print Report Card" or "Download Transcript".
						 */
						do_action( 'tradeschool_manager_portal_header_actions', $student );
						?>
						<a class="tsm-btn tsm-btn--ghost" href="<?php echo esc_url( add_query_arg( 'tsm_logout', 1 ) ); ?>"><?php esc_html_e( 'Log out', 'tradeschool-manager' ); ?></a>
					</div>
				</div>

				<!-- Stat strip -->
				<div class="tsm-stats">
					<div class="tsm-stat"><span class="tsm-stat-num"><?php echo (int) $class_count; ?></span><span class="tsm-stat-lbl"><?php esc_html_e( 'Classes', 'tradeschool-manager' ); ?></span></div>
					<div class="tsm-stat"><span class="tsm-stat-num"><?php echo (int) $assign_total; ?></span><span class="tsm-stat-lbl"><?php esc_html_e( 'Assignments', 'tradeschool-manager' ); ?></span></div>
					<div class="tsm-stat"><span class="tsm-stat-num"><?php echo null !== $overall ? esc_html( $overall . '%' ) : ' - '; ?></span><span class="tsm-stat-lbl"><?php esc_html_e( 'Avg Grade', 'tradeschool-manager' ); ?></span></div>
					<div class="tsm-stat"><span class="tsm-stat-num"><?php echo esc_html( $overall_letter ); ?></span><span class="tsm-stat-lbl"><?php esc_html_e( 'Letter', 'tradeschool-manager' ); ?></span></div>
					<?php if ( tsm_addon_active( 'certificates' ) ) : ?><div class="tsm-stat"><span class="tsm-stat-num"><?php echo count( $certs ); ?></span><span class="tsm-stat-lbl"><?php esc_html_e( 'Certificates', 'tradeschool-manager' ); ?></span></div><?php endif; ?>
				</div>
			</section>

			<!-- Profile information panel (always visible, sits between header and tabs) -->
			<section class="tsm-card tsm-card--pad tsm-info-card">
				<div class="tsm-info-grid">
					<div class="tsm-info-block">
						<h3 class="tsm-h3"><?php esc_html_e( 'Contact', 'tradeschool-manager' ); ?></h3>
						<dl class="tsm-dl">
							<?php if ( ! empty( $student->email ) ) : ?>
								<dt><?php esc_html_e( 'Email', 'tradeschool-manager' ); ?></dt><dd><?php echo esc_html( $student->email ); ?></dd>
							<?php endif; ?>
							<?php if ( ! empty( $student->phone ) ) : ?>
								<dt><?php esc_html_e( 'Phone', 'tradeschool-manager' ); ?></dt><dd><?php echo esc_html( tsm_format_phone( $student->phone ) ); ?></dd>
							<?php endif; ?>
							<?php if ( ! empty( $student->username ) ) : ?>
								<dt><?php esc_html_e( 'Username', 'tradeschool-manager' ); ?></dt><dd><?php echo esc_html( $student->username ); ?></dd>
							<?php endif; ?>
						</dl>
					</div>
					<?php if ( ! empty( $student->emergency_name ) || ! empty( $student->emergency_phone ) ) : ?>
					<div class="tsm-info-block">
						<h3 class="tsm-h3"><?php esc_html_e( 'Emergency Contact', 'tradeschool-manager' ); ?></h3>
						<dl class="tsm-dl">
							<?php if ( ! empty( $student->emergency_name ) ) : ?>
								<dt><?php esc_html_e( 'Name', 'tradeschool-manager' ); ?></dt>
								<dd><?php echo esc_html( $student->emergency_name ); ?><?php if ( ! empty( $student->emergency_relation ) ) echo ' (' . esc_html( $student->emergency_relation ) . ')'; ?></dd>
							<?php endif; ?>
							<?php if ( ! empty( $student->emergency_phone ) ) : ?>
								<dt><?php esc_html_e( 'Phone', 'tradeschool-manager' ); ?></dt><dd><?php echo esc_html( tsm_format_phone( $student->emergency_phone ) ); ?></dd>
							<?php endif; ?>
						</dl>
					</div>
					<?php endif; ?>
					<?php
					// Portal-visible custom fields, inline with profile.
					$cf_defs = class_exists( 'TSMP_Custom_Fields' ) ? TSMP_Custom_Fields::all_defs( 'portal' ) : array();
					$cf_rendered = false;
					if ( ! empty( $cf_defs ) ) :
						ob_start(); ?>
						<div class="tsm-info-block">
							<h3 class="tsm-h3"><?php esc_html_e( 'Additional Information', 'tradeschool-manager' ); ?></h3>
							<dl class="tsm-dl">
								<?php foreach ( $cf_defs as $def ) :
									$val = TSMP_Custom_Fields::get_value( $def->id, $sid );
									if ( '' === $val || null === $val ) continue;
									$cf_rendered = true; ?>
									<dt><?php echo esc_html( $def->label ); ?></dt>
									<dd><?php echo esc_html( $val ); ?></dd>
								<?php endforeach; ?>
							</dl>
						</div>
					<?php
						$cf_html = ob_get_clean();
						if ( $cf_rendered ) echo $cf_html; // phpcs:ignore
					endif; ?>
				</div>
			</section>

			<!-- Announcements (visible to all logged-in students) -->
			<?php
			if ( class_exists( 'TSM_Announcements' ) ) {
				$ann = TSM_Announcements::active( $sid );
				if ( ! empty( $ann ) ) : ?>
					<section class="tsm-card tsm-card--pad tsm-announcements">
						<h3 class="tsm-h3 tsm-announcements-title">
							<span class="tsm-megaphone" aria-hidden="true">📣</span>
							<?php esc_html_e( 'Announcements', 'tradeschool-manager' ); ?>
						</h3>
						<ul class="tsm-announce-list">
							<?php foreach ( $ann as $a ) : ?>
								<li class="tsm-announce-item">
									<div class="tsm-announce-head">
										<strong class="tsm-announce-title"><?php echo esc_html( $a->title ); ?></strong>
										<span class="tsm-announce-date"><?php echo esc_html( mysql2date( get_option( 'date_format', 'M j, Y' ), $a->created_at ) ); ?></span>
									</div>
									<div class="tsm-announce-body"><?php echo wp_kses_post( wpautop( $a->body ) ); ?></div>
								</li>
							<?php endforeach; ?>
						</ul>
					</section>
				<?php endif;
			}
			?>

			<!-- Tabs -->
			<nav class="tsm-tabs" role="tablist">
				<button type="button" class="tsm-tab<?php echo 'grades' === $active_tab ? ' is-active' : ''; ?>" data-tab="grades" role="tab"><?php esc_html_e( 'Grades', 'tradeschool-manager' ); ?></button>
				<button type="button" class="tsm-tab<?php echo 'assignments' === $active_tab ? ' is-active' : ''; ?>" data-tab="assignments" role="tab"><?php esc_html_e( 'Assignments', 'tradeschool-manager' ); ?></button>
				<?php if ( tsm_addon_active( 'invoicing' ) ) : ?><button type="button" class="tsm-tab<?php echo 'payments' === $active_tab ? ' is-active' : ''; ?>" data-tab="payments" role="tab"><?php esc_html_e( 'Payments &amp; Invoices', 'tradeschool-manager' ); ?></button><?php endif; ?>
				<?php if ( tsm_addon_active( 'certificates' ) ) : ?><button type="button" class="tsm-tab<?php echo 'certificates' === $active_tab ? ' is-active' : ''; ?>" data-tab="certificates" role="tab"><?php esc_html_e( 'Certificates', 'tradeschool-manager' ); ?></button><?php endif; ?>
				<?php if ( tsm_addon_active( 'workshops' ) ) : ?><button type="button" class="tsm-tab<?php echo 'workshops' === $active_tab ? ' is-active' : ''; ?>" data-tab="workshops" role="tab"><?php esc_html_e( 'Workshops', 'tradeschool-manager' ); ?></button><?php endif; ?>
				<button type="button" class="tsm-tab<?php echo 'settings' === $active_tab ? ' is-active' : ''; ?>" data-tab="settings" role="tab"><?php esc_html_e( 'Settings', 'tradeschool-manager' ); ?></button>
			</nav>

			<!-- GRADES -->
			<section class="tsm-tabpanel<?php echo 'grades' === $active_tab ? ' is-active' : ''; ?>" data-panel="grades">
				<div class="tsm-card tsm-card--pad">
					<h3 class="tsm-h3"><?php esc_html_e( 'My Grades', 'tradeschool-manager' ); ?></h3>
					<?php if ( empty( $classes ) ) : ?>
						<p class="tsm-empty"><?php esc_html_e( 'No grades yet.', 'tradeschool-manager' ); ?></p>
					<?php else : ?>
						<table class="tsm-table">
							<thead><tr><th><?php esc_html_e( 'Class', 'tradeschool-manager' ); ?></th><th><?php esc_html_e( 'Teacher', 'tradeschool-manager' ); ?></th><th><?php esc_html_e( 'Percent', 'tradeschool-manager' ); ?></th><th><?php esc_html_e( 'Letter', 'tradeschool-manager' ); ?></th></tr></thead>
							<tbody>
							<?php foreach ( $classes as $c ) :
								$teacher = $c->teacher_id ? TSM_Teachers::get( $c->teacher_id ) : null;
								$g       = TSM_Gradebook::calc_class_grade( $c->id, $sid ); ?>
								<tr>
									<td><?php echo esc_html( $c->name ); ?></td>
									<td><?php echo esc_html( $teacher ? $teacher->first_name . ' ' . $teacher->last_name : ' - ' ); ?></td>
									<td><?php echo esc_html( null !== $g['percent'] ? $g['percent'] . '%' : ' - ' ); ?></td>
									<td><strong><?php echo esc_html( $g['letter'] ?: ' - ' ); ?></strong></td>
								</tr>
							<?php endforeach; ?>
							</tbody>
						</table>
					<?php endif; ?>
				</div>
			</section>

			<!-- ASSIGNMENTS -->
			<section class="tsm-tabpanel<?php echo 'assignments' === $active_tab ? ' is-active' : ''; ?>" data-panel="assignments">
				<?php
				$any = false;
				foreach ( $classes as $c ) :
					$assignments = TSM_Assignments::for_class_visible( $c->id );
					if ( empty( $assignments ) ) continue;
					$any = true; ?>
					<div class="tsm-card tsm-card--pad">
						<h3 class="tsm-h3"><?php echo esc_html( $c->name ); ?></h3>
						<table class="tsm-table tsm-stack-table tsm-student-assignment-table">
							<thead><tr><th><?php esc_html_e( 'Assignment', 'tradeschool-manager' ); ?></th><th><?php esc_html_e( 'Category', 'tradeschool-manager' ); ?></th><th><?php esc_html_e( 'Due', 'tradeschool-manager' ); ?></th><th><?php esc_html_e( 'Score', 'tradeschool-manager' ); ?></th></tr></thead>
							<tbody data-tsm-assignment-list>
							<?php foreach ( $assignments as $a ) :
								$g = TSM_Gradebook::get_grade( $a->id, $sid );
								$score = $g && null !== $g->points_earned ? $g->points_earned . ' / ' . $a->points_possible : ' - ';
								$assignment_detail_id = 'tsm_assignment_' . (int) $c->id . '_' . (int) $a->id;
								$assignment_description = trim( (string) ( $a->description ?? '' ) );
								?>
								<tr class="tsm-assignment-summary-row" data-tsm-assignment-toggle="<?php echo esc_attr( $assignment_detail_id ); ?>">
									<td data-label="<?php esc_attr_e( 'Assignment', 'tradeschool-manager' ); ?>">
										<button type="button" class="tsm-assignment-toggle" aria-expanded="false" aria-controls="<?php echo esc_attr( $assignment_detail_id ); ?>">
											<span class="tsm-assignment-title"><?php echo esc_html( $a->title ); ?></span>
											<span class="tsm-assignment-chevron" aria-hidden="true"></span>
										</button>
									</td>
									<td data-label="<?php esc_attr_e( 'Category', 'tradeschool-manager' ); ?>"><?php echo esc_html( $a->category ?: ' - ' ); ?></td>
									<td data-label="<?php esc_attr_e( 'Due', 'tradeschool-manager' ); ?>"><?php echo esc_html( TSM_Date_Utils::display( $a->due_date ?? '' ) ); ?></td>
									<td data-label="<?php esc_attr_e( 'Score', 'tradeschool-manager' ); ?>"><?php echo esc_html( $score ); ?></td>
								</tr>
								<tr class="tsm-assignment-detail-row" id="<?php echo esc_attr( $assignment_detail_id ); ?>" data-tsm-assignment-detail="<?php echo esc_attr( $assignment_detail_id ); ?>">
									<td colspan="4">
										<div class="tsm-assignment-detail">
											<strong><?php esc_html_e( 'Description', 'tradeschool-manager' ); ?></strong>
											<?php if ( '' !== $assignment_description ) : ?>
												<div class="tsm-assignment-description"><?php echo wp_kses_post( wpautop( $assignment_description ) ); ?></div>
											<?php else : ?>
												<p class="tsm-muted"><?php esc_html_e( 'No description provided.', 'tradeschool-manager' ); ?></p>
											<?php endif; ?>
										</div>
									</td>
								</tr>
							<?php endforeach; ?>
							</tbody>
						</table>
					</div>
				<?php endforeach; ?>
				<?php if ( ! $any ) : ?>
					<div class="tsm-card tsm-card--pad"><p class="tsm-empty"><?php esc_html_e( 'No assignments yet.', 'tradeschool-manager' ); ?></p></div>
				<?php endif; ?>
			</section>

			<!-- PAYMENTS & INVOICES -->
			<?php if ( tsm_addon_active( 'invoicing' ) ) : ?>
			<section class="tsm-tabpanel<?php echo 'payments' === $active_tab ? ' is-active' : ''; ?>" data-panel="payments">
				<div class="tsm-card tsm-card--pad">
					<?php if ( class_exists( 'TSMP_Invoices' ) ) {
						TSMP_Invoices::render_portal( $sid );
					} elseif ( class_exists( 'TSMP_Payments' ) ) {
						TSMP_Payments::render_portal( $sid );
					} else {
						echo '<p class="tsm-empty">' . esc_html__( 'No payment information available.', 'tradeschool-manager' ) . '</p>';
					} ?>
				</div>
			</section>
			<?php endif; ?>

			<!-- CERTIFICATES -->
			<?php if ( tsm_addon_active( 'certificates' ) ) : ?>
			<section class="tsm-tabpanel<?php echo 'certificates' === $active_tab ? ' is-active' : ''; ?>" data-panel="certificates">
				<div class="tsm-card tsm-card--pad">
					<h3 class="tsm-h3"><?php esc_html_e( 'My Certificates', 'tradeschool-manager' ); ?></h3>
					<p class="tsm-muted"><?php esc_html_e( 'Class completion certificates issued by your school. Lost a copy? Download it any time.', 'tradeschool-manager' ); ?></p>
					<?php if ( empty( $certs ) ) : ?>
						<p class="tsm-empty"><?php esc_html_e( 'No certificates issued yet.', 'tradeschool-manager' ); ?></p>
					<?php else : ?>
						<div class="tsm-cert-list">
							<?php foreach ( $certs as $cert ) :
								$cls = $cert->class_id ? TSM_Classes::get( $cert->class_id ) : null;
								$dl  = add_query_arg(
									array(
										'action'   => 'tsm_portal_certificate',
										'cert_id'  => $cert->id,
										'_wpnonce' => wp_create_nonce( 'tsm_portal_certificate_' . $cert->id ),
									),
									admin_url( 'admin-post.php' )
								);
							?>
								<article class="tsm-cert">
									<div class="tsm-cert-icon" aria-hidden="true">
										<svg viewBox="0 0 24 24" width="28" height="28" fill="currentColor"><path d="M12 1l3.09 6.26L22 8.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 13.14l-5-4.87 6.91-1.01L12 1z"/></svg>
									</div>
									<div class="tsm-cert-meta">
										<h4><?php echo esc_html( $cert->title ?: ( $cls ? $cls->name : __( 'Certificate', 'tradeschool-manager' ) ) ); ?></h4>
										<p class="tsm-muted">
											<?php if ( $cls ) echo esc_html( $cls->name ) . ' - '; ?>
											<?php esc_html_e( 'Issued', 'tradeschool-manager' ); ?> <?php echo esc_html( $cert->issued_date ); ?>
										</p>
										<?php if ( method_exists( 'TSM_Certificates', 'status_for' ) ) :
											$st_key = TSM_Certificates::status_for( $cert );
											$st_lbl = TSM_Certificates::status_label( $cert );
											$st_col = TSM_Certificates::status_color( $st_key );
										?>
											<p style="margin:4px 0 0;"><span style="display:inline-block;padding:2px 8px;border-radius:10px;background:<?php echo esc_attr( $st_col ); ?>;color:#fff;font-size:11px;font-weight:600;"><?php echo esc_html( $st_lbl ); ?></span></p>
										<?php endif; ?>
									</div>
									<a class="tsm-btn tsm-btn--primary" href="<?php echo esc_url( $dl ); ?>"><?php esc_html_e( 'Download', 'tradeschool-manager' ); ?></a>
								</article>
							<?php endforeach; ?>
						</div>
					<?php endif; ?>
				</div>
			</section>
			<?php endif; ?>

			<!-- WORKSHOPS -->
			<?php if ( tsm_addon_active( 'workshops' ) ) : ?>
			<section class="tsm-tabpanel<?php echo 'workshops' === $active_tab ? ' is-active' : ''; ?>" data-panel="workshops">
				<div class="tsm-card tsm-card--pad">
					<h3 class="tsm-h3"><?php esc_html_e( 'My Workshops', 'tradeschool-manager' ); ?></h3>
					<p class="tsm-muted"><?php esc_html_e( 'One-off workshops are tracked separately from your school-year classes. Grades and assignments here do not affect your overall GPA.', 'tradeschool-manager' ); ?></p>
					<?php
					$ws_instances = class_exists( 'TSM_Workshop_Gradebook' ) ? TSM_Workshop_Gradebook::instances_for_student( $sid ) : array();
					if ( empty( $ws_instances ) ) : ?>
						<p class="tsm-empty"><?php esc_html_e( 'You are not enrolled in any workshops yet.', 'tradeschool-manager' ); ?></p>
					<?php else : ?>
						<table class="tsm-table">
							<thead><tr>
								<th><?php esc_html_e( 'Workshop', 'tradeschool-manager' ); ?></th>
								<th><?php esc_html_e( 'Dates', 'tradeschool-manager' ); ?></th>
								<th><?php esc_html_e( 'Status', 'tradeschool-manager' ); ?></th>
								<th><?php esc_html_e( 'Grade', 'tradeschool-manager' ); ?></th>
							</tr></thead>
							<tbody>
							<?php foreach ( $ws_instances as $wi ) :
								$g = TSM_Workshop_Gradebook::calc_instance_grade( (int) $wi->id, $sid );
								$dates = trim( ( $wi->start_date ?: '' ) . ( $wi->end_date && $wi->end_date !== $wi->start_date ? ' - ' . $wi->end_date : '' ) ); ?>
								<tr>
									<td><strong><?php echo esc_html( $wi->workshop_name ); ?></strong><?php if ( ! empty( $wi->label ) ) echo ' <span class="tsm-muted"> -  ' . esc_html( $wi->label ) . '</span>'; ?></td>
									<td><?php echo esc_html( $dates ?: ' - ' ); ?></td>
									<td><?php echo esc_html( ucfirst( (string) $wi->status ) ); ?></td>
									<td>
										<?php if ( null !== $g['percent'] ) : ?>
											<?php echo esc_html( $g['percent'] . '% - ' . ( $g['letter'] ?: ' - ' ) ); ?>
										<?php elseif ( 'enrolled' === $g['status'] ) : ?>
											<span class="tsm-muted"><?php esc_html_e( 'Enrolled', 'tradeschool-manager' ); ?></span>
										<?php else : ?>
											 - 
										<?php endif; ?>
									</td>
								</tr>
								<?php $assigns = TSM_Workshop_Gradebook::assignments_for_instance( (int) $wi->id );
								if ( ! empty( $assigns ) ) : ?>
									<tr><td colspan="4" style="background:#fafafa;">
										<details><summary style="cursor:pointer;"><?php esc_html_e( 'View assignments', 'tradeschool-manager' ); ?></summary>
										<table class="tsm-table" style="margin-top:8px;">
											<thead><tr><th><?php esc_html_e( 'Assignment', 'tradeschool-manager' ); ?></th><th><?php esc_html_e( 'Due', 'tradeschool-manager' ); ?></th><th><?php esc_html_e( 'Score', 'tradeschool-manager' ); ?></th></tr></thead>
											<tbody>
											<?php foreach ( $assigns as $a ) :
												$gr = TSM_Workshop_Gradebook::get_grade( $a->id, $sid );
												$score = $gr && null !== $gr->points_earned ? $gr->points_earned . ' / ' . $a->points_possible : ' - '; ?>
												<tr>
													<td><?php echo esc_html( $a->title ); ?></td>
													<td><?php echo esc_html( TSM_Date_Utils::display( $a->due_date ?? '' ) ); ?></td>
													<td><?php echo esc_html( $score ); ?></td>
												</tr>
											<?php endforeach; ?>
											</tbody>
										</table>
										</details>
									</td></tr>
								<?php endif; ?>
							<?php endforeach; ?>
							</tbody>
						</table>
					<?php endif; ?>
				</div>
			</section>
			<?php endif; ?>

			<!-- SETTINGS -->
			<?php
			$has_docs   = class_exists( 'TSM_Student_Docs' );
			$active_sub = isset( $_GET['sub'] ) ? sanitize_key( wp_unslash( $_GET['sub'] ) ) : 'info'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$allowed_subs = array( 'info', 'password' );
			if ( $has_docs ) { $allowed_subs[] = 'documents'; }
			if ( ! in_array( $active_sub, $allowed_subs, true ) ) { $active_sub = 'info'; }
			$info_saved = isset( $_GET['tsm_info_saved'] ); // phpcs:ignore
			?>
			<section class="tsm-tabpanel<?php echo 'settings' === $active_tab ? ' is-active' : ''; ?>" data-panel="settings">
				<nav class="tsm-subtabs" role="tablist" style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px;border-bottom:1px solid var(--tsm-border,#e5e7eb);padding-bottom:8px;">
					<button type="button" class="tsm-subtab<?php echo 'info' === $active_sub ? ' is-active' : ''; ?>" data-sub="info" role="tab"><?php esc_html_e( 'My Information', 'tradeschool-manager' ); ?></button>
					<button type="button" class="tsm-subtab<?php echo 'password' === $active_sub ? ' is-active' : ''; ?>" data-sub="password" role="tab"><?php esc_html_e( 'Change Password', 'tradeschool-manager' ); ?></button>
					<?php if ( $has_docs ) : ?>
					<button type="button" class="tsm-subtab<?php echo 'documents' === $active_sub ? ' is-active' : ''; ?>" data-sub="documents" role="tab"><?php esc_html_e( 'My Documents', 'tradeschool-manager' ); ?></button>
					<?php endif; ?>
				</nav>

				<!-- My Information sub-panel -->
				<div class="tsm-subpanel<?php echo 'info' === $active_sub ? ' is-active' : ''; ?>" data-subpanel="info">
					<div class="tsm-card tsm-card--pad">
						<h3 class="tsm-h3"><?php esc_html_e( 'My Information', 'tradeschool-manager' ); ?></h3>
						<?php if ( $info_saved ) : ?>
							<div class="tsm-success"><?php esc_html_e( 'Your information has been updated.', 'tradeschool-manager' ); ?></div>
						<?php endif; ?>
						<form method="post" enctype="multipart/form-data" class="tsm-login-form" style="max-width:520px;">
							<?php wp_nonce_field( 'tsm_photo_upload', 'tsm_photo_upload_nonce' ); ?>
							<input type="hidden" name="tsm_profile_fields" value="1">

							<div style="display:flex;align-items:center;gap:14px;margin-bottom:14px;">
								<?php if ( ! empty( $student->photo_url ) ) : ?>
									<img src="<?php echo esc_url( $student->photo_url ); ?>" alt="" style="width:72px;height:72px;border-radius:50%;object-fit:cover;border:1px solid var(--tsm-border,#e5e7eb);">
								<?php else : ?>
									<div style="width:72px;height:72px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--tsm-brand,#1f6feb);color:#fff;font-weight:600;font-size:22px;"><?php echo esc_html( $initials ); ?></div>
								<?php endif; ?>
								<label class="tsm-field" style="flex:1;margin:0;">
									<span><?php esc_html_e( 'Profile photo', 'tradeschool-manager' ); ?></span>
									<input type="file" name="photo_file" accept="image/png,image/jpeg,image/webp">
								</label>
							</div>

							<label class="tsm-field"><span><?php esc_html_e( 'Email', 'tradeschool-manager' ); ?></span><input type="email" name="tsm_email" value="<?php echo esc_attr( $student->email ); ?>" autocomplete="email"></label>
							<label class="tsm-field"><span><?php esc_html_e( 'Phone', 'tradeschool-manager' ); ?></span><input type="tel" name="tsm_phone" value="<?php echo esc_attr( $student->phone ); ?>" autocomplete="tel"></label>
							<button type="submit" class="tsm-btn tsm-btn--primary"><?php esc_html_e( 'Save Changes', 'tradeschool-manager' ); ?></button>
						</form>
					</div>
				</div>

				<!-- Change Password sub-panel -->
				<div class="tsm-subpanel<?php echo 'password' === $active_sub ? ' is-active' : ''; ?>" data-subpanel="password">
					<div class="tsm-card tsm-card--pad">
						<h3 class="tsm-h3"><?php esc_html_e( 'Change Password', 'tradeschool-manager' ); ?></h3>
						<?php
						$pw_err  = isset( $_GET['tsm_pw_error'] ) ? sanitize_text_field( wp_unslash( $_GET['tsm_pw_error'] ) ) : ''; // phpcs:ignore
						$pw_done = isset( $_GET['tsm_pw_done'] ); // phpcs:ignore
						if ( $pw_done ) : ?>
							<div class="tsm-success"><?php esc_html_e( 'Password updated successfully.', 'tradeschool-manager' ); ?></div>
						<?php endif;
						if ( 'current' === $pw_err ) : ?>
							<div class="tsm-error"><?php esc_html_e( 'Current password is incorrect.', 'tradeschool-manager' ); ?></div>
						<?php elseif ( 'short' === $pw_err ) : ?>
							<div class="tsm-error"><?php esc_html_e( 'New password must be at least 8 characters.', 'tradeschool-manager' ); ?></div>
						<?php elseif ( 'mismatch' === $pw_err ) : ?>
							<div class="tsm-error"><?php esc_html_e( 'New passwords do not match.', 'tradeschool-manager' ); ?></div>
						<?php elseif ( 'save' === $pw_err ) : ?>
							<div class="tsm-error"><?php esc_html_e( 'Could not save the new password. Please try again or contact your school.', 'tradeschool-manager' ); ?></div>
						<?php elseif ( 'session' === $pw_err ) : ?>
							<div class="tsm-error"><?php esc_html_e( 'Your portal session expired. Please sign in again and retry the password change.', 'tradeschool-manager' ); ?></div>
						<?php endif; ?>

						<form method="post" class="tsm-login-form" style="max-width:420px;">
							<?php wp_nonce_field( 'tsm_change_pw', 'tsm_change_pw_nonce' ); ?>
							<label class="tsm-field"><span><?php esc_html_e( 'Current password', 'tradeschool-manager' ); ?></span><input type="password" name="tsm_current_password" autocomplete="current-password" required></label>
							<label class="tsm-field"><span><?php esc_html_e( 'New password', 'tradeschool-manager' ); ?></span><input type="password" name="tsm_new_password" autocomplete="new-password" required></label>
							<label class="tsm-field"><span><?php esc_html_e( 'Confirm new password', 'tradeschool-manager' ); ?></span><input type="password" name="tsm_new_password2" autocomplete="new-password" required></label>
							<button type="submit" class="tsm-btn tsm-btn--primary"><?php esc_html_e( 'Update Password', 'tradeschool-manager' ); ?></button>
						</form>
					</div>
				</div>

				<?php if ( $has_docs ) : ?>
				<!-- My Documents sub-panel -->
				<div class="tsm-subpanel<?php echo 'documents' === $active_sub ? ' is-active' : ''; ?>" data-subpanel="documents">
					<div class="tsm-card tsm-card--pad">
						<h3 class="tsm-h3"><?php esc_html_e( 'My Documents', 'tradeschool-manager' ); ?></h3>
						<?php
						$doc_ok  = isset( $_GET['tsm_doc_ok'] );  // phpcs:ignore
						$doc_err = isset( $_GET['tsm_doc_err'] ) ? sanitize_text_field( wp_unslash( $_GET['tsm_doc_err'] ) ) : ''; // phpcs:ignore
						if ( $doc_ok )  : ?><div class="tsm-success"><?php esc_html_e( 'Document uploaded successfully.', 'tradeschool-manager' ); ?></div><?php endif;
						if ( $doc_err ) : ?><div class="tsm-error"><?php echo esc_html( $doc_err ); ?></div><?php endif;
						$docs_license_active = ! function_exists( 'tsm_cf_license_active' ) || tsm_cf_license_active();
						$doc_status = TSM_Student_Docs::status_for_student( $sid );
						$doc_other  = array();
						$type_ids   = array();
						foreach ( $doc_status as $row ) { $type_ids[ (int) $row['type']->id ] = true; }
						foreach ( TSM_Student_Docs::docs_for_student( $sid ) as $d ) {
							if ( ! $d->doc_type_id || empty( $type_ids[ (int) $d->doc_type_id ] ) ) {
								$doc_other[] = $d;
							}
						}
						?>
						<?php if ( empty( $doc_status ) && empty( $doc_other ) ) : ?>
							<p class="tsm-muted"><?php esc_html_e( 'No documents are required for your program at this time.', 'tradeschool-manager' ); ?></p>
						<?php else : ?>
							<p class="tsm-muted">
								<?php
								echo esc_html(
									$docs_license_active
										? __( 'Upload PDF or image files (JPG, PNG, WEBP, HEIC). Max 15 MB each.', 'tradeschool-manager' )
										: __( 'Existing documents remain available. New uploads are currently disabled by the school.', 'tradeschool-manager' )
								);
								?>
							</p>
							<table class="tsm-table">
								<thead><tr>
									<th><?php esc_html_e( 'Document', 'tradeschool-manager' ); ?></th>
									<th><?php esc_html_e( 'Status', 'tradeschool-manager' ); ?></th>
									<th><?php esc_html_e( 'Files', 'tradeschool-manager' ); ?></th>
									<th></th>
								</tr></thead>
								<tbody>
								<?php foreach ( $doc_status as $row ) :
									$t = $row['type'];
								?>
									<tr>
										<td>
											<strong><?php echo esc_html( $t->label ); ?></strong>
											<?php if ( ! empty( $t->description ) ) : ?><br><small><?php echo esc_html( $t->description ); ?></small><?php endif; ?>
										</td>
										<td>
											<?php if ( ! $t->required ) : ?>
												<?php esc_html_e( 'Optional', 'tradeschool-manager' ); ?>
											<?php elseif ( $row['satisfied'] ) : ?>
												<span style="color:#1a7d2e;font-weight:600;"><?php esc_html_e( 'Submitted', 'tradeschool-manager' ); ?></span>
											<?php else : ?>
												<span style="color:#a02828;font-weight:600;"><?php esc_html_e( 'Needed', 'tradeschool-manager' ); ?></span>
											<?php endif; ?>
										</td>
										<td>
											<?php if ( empty( $row['docs'] ) ) : ?>
												<em><?php esc_html_e( 'None yet', 'tradeschool-manager' ); ?></em>
											<?php else : foreach ( $row['docs'] as $d ) : ?>
												<div><a href="<?php echo esc_url( TSM_Student_Docs::download_url( $d->id, 'inline' ) ); ?>" target="_blank"><?php echo esc_html( $d->original_name ); ?></a></div>
											<?php endforeach; endif; ?>
										</td>
										<td>
											<?php if ( $docs_license_active ) : ?>
												<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" enctype="multipart/form-data" style="display:flex;gap:6px;align-items:center;flex-wrap:wrap;">
													<?php wp_nonce_field( 'tsm_doc_student_upload' ); ?>
													<input type="hidden" name="action" value="tsm_doc_student_upload">
													<input type="hidden" name="doc_type_id" value="<?php echo esc_attr( $t->id ); ?>">
													<input type="file" name="doc_file" required accept=".pdf,image/png,image/jpeg,image/webp,image/heic">
													<button type="submit" class="tsm-btn tsm-btn--primary"><?php esc_html_e( 'Upload', 'tradeschool-manager' ); ?></button>
												</form>
											<?php else : ?>
												<span class="tsm-muted"><?php esc_html_e( 'Upload disabled', 'tradeschool-manager' ); ?></span>
											<?php endif; ?>
										</td>
									</tr>
								<?php endforeach; ?>
								</tbody>
							</table>

							<?php if ( ! empty( $doc_other ) ) : ?>
								<h4 style="margin-top:14px;"><?php esc_html_e( 'Additional Files', 'tradeschool-manager' ); ?></h4>
								<ul>
								<?php foreach ( $doc_other as $d ) : ?>
									<li><a href="<?php echo esc_url( TSM_Student_Docs::download_url( $d->id, 'inline' ) ); ?>" target="_blank"><?php echo esc_html( $d->label ); ?></a> <small>(<?php echo esc_html( $d->original_name ); ?>)</small></li>
								<?php endforeach; ?>
								</ul>
							<?php endif; ?>
						<?php endif; ?>
					</div>
				</div>
				<?php endif; ?>
			</section>

		</div>

		<?php
		return ob_get_clean();
	}

	public function sc_gradebook() {
		wp_enqueue_style( 'tsm-public' );
		$sid = TSM_Public::current_student_id();
		if ( ! $sid ) {
			return $this->sc_login();
		}
		ob_start();
		echo '<div class="tsm-portal-wrap"><div class="tsm-card tsm-card--pad"><h3 class="tsm-h3">' . esc_html__( 'My Grades', 'tradeschool-manager' ) . '</h3>';
		foreach ( TSM_Classes::classes_for_student( $sid ) as $c ) {
			echo '<h4>' . esc_html( $c->name ) . '</h4>';
			$assignments = TSM_Assignments::for_class_visible( $c->id );
			echo '<table class="tsm-table"><thead><tr><th>' . esc_html__( 'Assignment', 'tradeschool-manager' ) . '</th><th>' . esc_html__( 'Due', 'tradeschool-manager' ) . '</th><th>' . esc_html__( 'Score', 'tradeschool-manager' ) . '</th></tr></thead><tbody>';
			foreach ( $assignments as $a ) {
				$g = TSM_Gradebook::get_grade( $a->id, $sid );
				$score = $g && null !== $g->points_earned ? $g->points_earned . ' / ' . $a->points_possible : ' - ';
				echo '<tr><td>' . esc_html( $a->title ) . '</td><td>' . esc_html( TSM_Date_Utils::display( $a->due_date ?? '' ) ) . '</td><td>' . esc_html( $score ) . '</td></tr>';
			}
			echo '</tbody></table>';
		}
		echo '</div></div>';
		return ob_get_clean();
	}

	public function sc_payments() {
		wp_enqueue_style( 'tsm-public' );
		// All-In-One: payment history is always available.
		$sid = TSM_Public::current_student_id();
		if ( ! $sid ) return $this->sc_login();
		ob_start();
		echo '<div class="tsm-portal-wrap"><div class="tsm-card tsm-card--pad">';
		TSMP_Payments::render_portal( $sid );
		echo '</div></div>';
		return ob_get_clean();
	}

	/* Application shortcodes ([tsm_applications], [tsm_application_form]) and their
	 * builder/wizard markup were extracted to the standalone Applications add-on
	 * in core v1.18.5.
	 */
}
