<?php
require_once __DIR__ . '/Includes.php';
check_login('admin');

// Ensure base schema exists for a fresh installation.
$pdo->exec("CREATE TABLE IF NOT EXISTS classes (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS subjects (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  class_id INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_subjects_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(150) NOT NULL UNIQUE,
  password_hash VARCHAR(255) NOT NULL,
  role ENUM('admin', 'teacher', 'hop', 'accountant', 'ancillary', 'parent') NOT NULL DEFAULT 'teacher',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS staff_profiles (
  user_id INT NOT NULL PRIMARY KEY,
  sex ENUM('Male','Female','Other') NULL,
  date_of_birth DATE NULL,
  ec_number VARCHAR(80) NULL,
  national_id VARCHAR(80) NULL,
  work_profile VARCHAR(255) NULL,
  qualifications TEXT NULL,
  subject_specialization VARCHAR(255) NULL,
  updated_by INT NULL,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_staff_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_staff_profiles_updated_by FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL
)");

try {
  $pdo->exec("ALTER TABLE staff_profiles ADD COLUMN work_profile VARCHAR(255) NULL AFTER national_id");
} catch (PDOException $e) {
  // Ignore duplicate column errors for idempotent upgrades.
}

$pdo->exec("CREATE TABLE IF NOT EXISTS password_reset_requests (
  id INT AUTO_INCREMENT PRIMARY KEY,
  user_id INT NOT NULL,
  email VARCHAR(150) NOT NULL,
  requested_password_hash VARCHAR(255) NOT NULL,
  status ENUM('pending','approved','rejected') NOT NULL DEFAULT 'pending',
  requester_note VARCHAR(255) NULL,
  admin_note VARCHAR(255) NULL,
  requested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  reviewed_at DATETIME NULL,
  reviewed_by INT NULL,
  CONSTRAINT fk_prr_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_prr_reviewer FOREIGN KEY (reviewed_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_prr_status_date (status, requested_at),
  INDEX idx_prr_user_status (user_id, status)
)");

try {
  $pdo->exec("ALTER TABLE users MODIFY role ENUM('admin', 'teacher', 'hop', 'accountant', 'ancillary', 'parent') NOT NULL DEFAULT 'teacher'");
} catch (PDOException $e) {
  // Ignore when schema is already updated.
}

$pdo->exec("CREATE TABLE IF NOT EXISTS teacher_subjects (
  id INT AUTO_INCREMENT PRIMARY KEY,
  teacher_id INT NOT NULL,
  subject_id INT NOT NULL,
  class_id INT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_ts_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_ts_subject FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE,
  CONSTRAINT fk_ts_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  UNIQUE KEY uq_teacher_subject_class (teacher_id, subject_id, class_id)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS hop_profiles (
  user_id INT NOT NULL PRIMARY KEY,
  department_name VARCHAR(150) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_hop_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS teacher_hop_assignments (
  id INT AUTO_INCREMENT PRIMARY KEY,
  hop_user_id INT NOT NULL,
  teacher_id INT NOT NULL UNIQUE,
  assigned_by INT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_tha_hop_user FOREIGN KEY (hop_user_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_tha_teacher_user FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_tha_assigned_by FOREIGN KEY (assigned_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_tha_hop_user (hop_user_id)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS class_teacher_assignments (
  id INT AUTO_INCREMENT PRIMARY KEY,
  class_id INT NOT NULL UNIQUE,
  teacher_id INT NOT NULL,
  assigned_by INT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_cta_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_cta_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_cta_assigned_by FOREIGN KEY (assigned_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_cta_teacher (teacher_id)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS learners (
  reg_number VARCHAR(30) NOT NULL PRIMARY KEY,
  id INT NOT NULL AUTO_INCREMENT UNIQUE,
  class_id INT NOT NULL,
  date_of_admission DATE NULL,
  surname VARCHAR(100) NULL,
  christian_names VARCHAR(150) NULL,
  full_name VARCHAR(150) NOT NULL,
  date_of_birth_info VARCHAR(40) NULL,
  birth_certificate_number VARCHAR(80) NULL,
  religious_denomination VARCHAR(120) NULL,
  gender ENUM('Male', 'Female', 'Other') NOT NULL DEFAULT 'Other',
  guardian_name VARCHAR(120) NULL,
  guardian_national_id VARCHAR(60) NULL,
  guardian_address VARCHAR(255) NULL,
  guardian_phone VARCHAR(40) NULL,
  student_photo_path VARCHAR(255) NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_learners_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS admissions_pending (
  id INT AUTO_INCREMENT PRIMARY KEY,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  date_of_admission DATE NULL,
  surname VARCHAR(100) NOT NULL,
  christian_names VARCHAR(150) NOT NULL,
  full_name VARCHAR(150) NOT NULL,
  date_of_birth_info VARCHAR(40) NULL,
  birth_certificate_number VARCHAR(80) NULL,
  religious_denomination VARCHAR(120) NULL,
  gender ENUM('Male', 'Female', 'Other') NOT NULL DEFAULT 'Other',
  guardian_name VARCHAR(120) NULL,
  guardian_national_id VARCHAR(60) NULL,
  guardian_address VARCHAR(255) NULL,
  guardian_phone VARCHAR(40) NULL,
  student_photo_path VARCHAR(255) NULL,
  status ENUM('pending', 'approved', 'rejected') NOT NULL DEFAULT 'pending',
  reviewed_by INT NULL,
  reviewed_at DATETIME NULL,
  review_comment VARCHAR(255) NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_ap_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_ap_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  INDEX idx_ap_status_created (status, created_at)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS teacher_documents (
  id INT AUTO_INCREMENT PRIMARY KEY,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  subject_id INT NULL,
  document_type VARCHAR(40) NOT NULL,
  title VARCHAR(180) NOT NULL,
  description TEXT NULL,
  original_name VARCHAR(255) NOT NULL,
  file_path VARCHAR(255) NOT NULL,
  mime_type VARCHAR(120) NULL,
  file_size BIGINT NULL,
  status ENUM('submitted','reviewed','needs_correction','approved') NOT NULL DEFAULT 'submitted',
  hop_status ENUM('submitted','reviewed','needs_correction','approved') NOT NULL DEFAULT 'submitted',
  admin_comment TEXT NULL,
  hop_comment TEXT NULL,
  reviewed_by INT NULL,
  hop_reviewed_by INT NULL,
  reviewed_at DATETIME NULL,
  hop_reviewed_at DATETIME NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_td_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_td_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_td_subject FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE SET NULL,
  CONSTRAINT fk_td_reviewer FOREIGN KEY (reviewed_by) REFERENCES users(id) ON DELETE SET NULL,
  CONSTRAINT fk_td_hop_reviewer FOREIGN KEY (hop_reviewed_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_td_teacher_created (teacher_id, created_at),
  INDEX idx_td_status (status)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS inventory_records (
  id INT AUTO_INCREMENT PRIMARY KEY,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  category ENUM('textbook','furniture','equipment','other') NOT NULL DEFAULT 'other',
  item_name VARCHAR(180) NOT NULL,
  quantity_recorded INT UNSIGNED NOT NULL DEFAULT 0,
  item_condition VARCHAR(80) NULL,
  inventory_note TEXT NULL,
  status ENUM('submitted','verified','discrepancy') NOT NULL DEFAULT 'submitted',
  stock_take_quantity INT UNSIGNED NULL,
  accountant_review TEXT NULL,
  reviewed_by INT NULL,
  reviewed_at DATETIME NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_ir_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_ir_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_ir_reviewer FOREIGN KEY (reviewed_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_ir_teacher_created (teacher_id, created_at),
  INDEX idx_ir_status_created (status, created_at)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS school_assets_register (
  id INT AUTO_INCREMENT PRIMARY KEY,
  source_inventory_id INT NOT NULL UNIQUE,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  category ENUM('textbook','furniture','equipment','other') NOT NULL DEFAULT 'other',
  item_name VARCHAR(180) NOT NULL,
  quantity INT UNSIGNED NOT NULL DEFAULT 0,
  item_condition VARCHAR(80) NULL,
  inventory_note TEXT NULL,
  approved_by INT NULL,
  approved_at DATETIME NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_sar_source_inventory FOREIGN KEY (source_inventory_id) REFERENCES inventory_records(id) ON DELETE CASCADE,
  CONSTRAINT fk_sar_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_sar_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_sar_approver FOREIGN KEY (approved_by) REFERENCES users(id) ON DELETE SET NULL,
  INDEX idx_sar_class (class_id),
  INDEX idx_sar_category (category),
  INDEX idx_sar_approved_at (approved_at)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS daily_attendance_register (
  id INT AUTO_INCREMENT PRIMARY KEY,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  learner_id INT NOT NULL,
  attendance_date DATE NOT NULL,
  status ENUM('present','absent','late','excused') NOT NULL DEFAULT 'present',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_dar_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_dar_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_dar_learner FOREIGN KEY (learner_id) REFERENCES learners(id) ON DELETE CASCADE,
  UNIQUE KEY uq_dar_teacher_class_learner_date (teacher_id, class_id, learner_id, attendance_date),
  INDEX idx_dar_teacher_date (teacher_id, attendance_date)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS parent_learner_links (
  id INT AUTO_INCREMENT PRIMARY KEY,
  parent_user_id INT NOT NULL,
  learner_id INT NOT NULL UNIQUE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_pl_parent FOREIGN KEY (parent_user_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_pl_learner FOREIGN KEY (learner_id) REFERENCES learners(id) ON DELETE CASCADE
)");

try {
  $pdo->exec("ALTER TABLE parent_learner_links DROP INDEX parent_user_id");
} catch (PDOException $e) {
  // Ignore when index name differs or is already removed.
}

try {
  $pdo->exec("ALTER TABLE parent_learner_links ADD INDEX idx_pl_parent_user (parent_user_id)");
} catch (PDOException $e) {
  // Ignore duplicate index errors.
}

try {
  $pdo->exec("ALTER TABLE parent_learner_links ADD UNIQUE KEY uq_pl_parent_learner (parent_user_id, learner_id)");
} catch (PDOException $e) {
  // Ignore duplicate index errors.
}

$pdo->exec("CREATE TABLE IF NOT EXISTS announcements (
  id INT AUTO_INCREMENT PRIMARY KEY,
  sender_id INT NOT NULL,
  sender_role ENUM('admin','teacher') NOT NULL,
  audience ENUM('teacher','learner','parent') NOT NULL,
  target_class_id INT NULL,
  target_learner_id INT NULL,
  title VARCHAR(180) NOT NULL,
  body TEXT NOT NULL,
  status ENUM('published','pending_admin_review','rejected') NOT NULL DEFAULT 'published',
  admin_review_comment TEXT NULL,
  reviewed_by INT NULL,
  reviewed_at DATETIME NULL,
  published_at DATETIME NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_ann_sender FOREIGN KEY (sender_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_ann_reviewer FOREIGN KEY (reviewed_by) REFERENCES users(id) ON DELETE SET NULL,
  CONSTRAINT fk_ann_target_class FOREIGN KEY (target_class_id) REFERENCES classes(id) ON DELETE SET NULL,
  CONSTRAINT fk_ann_target_learner FOREIGN KEY (target_learner_id) REFERENCES learners(id) ON DELETE SET NULL,
  INDEX idx_ann_audience_status_created (audience, status, created_at)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS app_settings (
  setting_key VARCHAR(120) NOT NULL PRIMARY KEY,
  setting_value TEXT NOT NULL,
  updated_by INT NULL,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  CONSTRAINT fk_app_settings_updated_by FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL
)");

try {
  $pdo->exec("ALTER TABLE learners CHANGE COLUMN admission_no reg_number VARCHAR(30) NOT NULL");
} catch (PDOException $e) {
  // Ignore if already renamed or source column no longer exists.
}

$learnerColumnsToEnsure = [
  "reg_number VARCHAR(30) NULL",
  "date_of_admission DATE NULL",
  "surname VARCHAR(100) NULL",
  "christian_names VARCHAR(150) NULL",
  "date_of_birth_info VARCHAR(40) NULL",
  "birth_certificate_number VARCHAR(80) NULL",
  "religious_denomination VARCHAR(120) NULL",
  "guardian_national_id VARCHAR(60) NULL",
  "guardian_address VARCHAR(255) NULL",
  "student_photo_path VARCHAR(255) NULL"
];
foreach ($learnerColumnsToEnsure as $columnSql) {
  try {
    $pdo->exec("ALTER TABLE learners ADD COLUMN " . $columnSql);
  } catch (PDOException $e) {
    // Ignore duplicate column errors so schema migration remains idempotent.
  }
}

$announcementColumnsToEnsure = [
  "target_class_id INT NULL",
  "target_learner_id INT NULL"
];
foreach ($announcementColumnsToEnsure as $columnSql) {
  try {
    $pdo->exec("ALTER TABLE announcements ADD COLUMN " . $columnSql);
  } catch (PDOException $e) {
    // Ignore duplicate column errors so schema migration remains idempotent.
  }
}

$admissionsPendingColumnsToEnsure = [
  "birth_certificate_number VARCHAR(80) NULL",
  "student_photo_path VARCHAR(255) NULL"
];
foreach ($admissionsPendingColumnsToEnsure as $columnSql) {
  try {
    $pdo->exec("ALTER TABLE admissions_pending ADD COLUMN " . $columnSql);
  } catch (PDOException $e) {
    // Ignore duplicate column errors so schema migration remains idempotent.
  }
}

$teacherDocumentColumnsToEnsure = [
  "hop_status ENUM('submitted','reviewed','needs_correction','approved') NOT NULL DEFAULT 'submitted'",
  "hop_comment TEXT NULL",
  "hop_reviewed_by INT NULL",
  "hop_reviewed_at DATETIME NULL"
];
foreach ($teacherDocumentColumnsToEnsure as $columnSql) {
  try {
    $pdo->exec("ALTER TABLE teacher_documents ADD COLUMN " . $columnSql);
  } catch (PDOException $e) {
    // Ignore duplicate column errors so schema migration remains idempotent.
  }
}

try {
  $pdo->exec("ALTER TABLE teacher_documents ADD CONSTRAINT fk_td_hop_reviewer FOREIGN KEY (hop_reviewed_by) REFERENCES users(id) ON DELETE SET NULL");
} catch (PDOException $e) {
  // Ignore if constraint already exists.
}

try {
  $pdo->exec("UPDATE learners
    SET reg_number = CONCAT('MAV', DATE_FORMAT(CURDATE(), '%y'), LPAD(id, 3, '0'))
    WHERE reg_number IS NULL OR reg_number = '' OR reg_number NOT REGEXP '^MAV[0-9]{2}[0-9]{3,6}$'");
} catch (PDOException $e) {
  // Ignore update errors caused by temporary schema differences.
}

try {
  $pdo->exec("ALTER TABLE learners MODIFY reg_number VARCHAR(30) NOT NULL");
} catch (PDOException $e) {
  // Keep going when already in desired shape.
}

try {
  $pdo->exec("ALTER TABLE learners DROP PRIMARY KEY, ADD PRIMARY KEY (reg_number), ADD UNIQUE KEY uq_learners_id (id)");
} catch (PDOException $e) {
  // Ignore when indexes are already present.
}

function generate_reg_number(PDO $pdo, int $classId): string {
  $yearCode = date('y');
  $prefix = 'MAV' . $yearCode;

  $nextRollStmt = $pdo->query("SELECT COALESCE(MAX(id), 0) FROM learners");
  $nextRoll = ((int)$nextRollStmt->fetchColumn()) + 1;

  return $prefix . str_pad((string)$nextRoll, 3, '0', STR_PAD_LEFT);
}

function get_teacher_document_types(): array {
  return [
    'schemebook' => 'Schemebook',
    'lesson_plan' => 'Lesson Plans',
    'irbm' => 'IRBM',
    'mark_list' => 'Mark Lists',
    'class_register' => 'Class Register',
    'inventory_book' => 'Inventory Book'
  ];
}

function inventory_category_label(string $category): string {
  $map = [
    'textbook' => 'Textbooks',
    'furniture' => 'Furniture',
    'equipment' => 'Equipment (Laptops, Projectors, etc.)',
    'other' => 'Other Teaching Materials'
  ];
  return $map[$category] ?? ucfirst(str_replace('_', ' ', $category));
}

function announcement_target_label(array $row): string {
  $className = trim((string)($row['target_class_name'] ?? ''));
  $learnerName = trim((string)($row['target_learner_name'] ?? ''));
  $regNumber = trim((string)($row['target_learner_reg_number'] ?? ''));

  if ($learnerName !== '') {
    $learnerPart = $regNumber !== '' ? ($learnerName . ' (' . $regNumber . ')') : $learnerName;
    if ($className !== '') {
      return 'Learner: ' . $learnerPart . ' - ' . $className;
    }
    return 'Learner: ' . $learnerPart;
  }

  if ($className !== '') {
    return 'Class: ' . $className;
  }

  return 'All';
}

function format_file_size($bytes): string {
  $size = (float)$bytes;
  if ($size <= 0) {
    return '0 B';
  }
  $units = ['B', 'KB', 'MB', 'GB', 'TB'];
  $power = min((int)floor(log($size, 1024)), count($units) - 1);
  $value = $size / pow(1024, $power);
  return number_format($value, $value >= 100 || $power === 0 ? 0 : 1) . ' ' . $units[$power];
}

// ========== LEARNER PROMOTION FUNCTIONS ==========

/**
 * Calculate learner balance for a specific class
 * Balance = Total Paid - Total Invoiced for that class
 */
function get_learner_balance_for_class($pdo, int $learner_id, int $class_id): float {
  try {
    $stmt = $pdo->prepare("
      SELECT 
        COALESCE(SUM(CASE WHEN fp.learner_id IS NOT NULL THEN fp.amount_paid_usd ELSE 0 END), 0) AS total_paid,
        COALESCE(SUM(CASE WHEN fi.learner_id IS NOT NULL THEN fi.amount_due ELSE 0 END), 0) AS total_invoiced
      FROM learners l
      LEFT JOIN fee_payments fp ON fp.learner_id = l.id AND l.class_id = ?
      LEFT JOIN fee_invoices fi ON fi.learner_id = l.id AND fi.class_id = ?
      WHERE l.id = ?
    ");
    $stmt->execute([$class_id, $class_id, $learner_id]);
    $result = $stmt->fetch(PDO::FETCH_ASSOC);
    
    $balance = floatval($result['total_paid']) - floatval($result['total_invoiced']);
    return max(0, $balance); // Return 0 or positive balance, never negative
  } catch (Exception $e) {
    return 0.0;
  }
}

/**
 * Get the next class for a learner (progression through forms)
 * Assumes class sequence: 1North -> 2North -> 3North -> 4North -> L6 -> U6
 */
function get_next_class($pdo, int $current_class_id) {
  $classSequence = ['1North', '2North', '3North', '4north', 'L6', 'U6'];
  
  try {
    $currentStmt = $pdo->prepare("SELECT name FROM classes WHERE id = ? LIMIT 1");
    $currentStmt->execute([$current_class_id]);
    $currentClass = $currentStmt->fetch(PDO::FETCH_ASSOC);
    
    if (!$currentClass) {
      return null;
    }
    
    $currentName = strtolower($currentClass['name']);
    $currentIndex = array_search($currentName, array_map('strtolower', $classSequence));
    
    if ($currentIndex === false || $currentIndex >= count($classSequence) - 1) {
      return null; // U6 is the last form, can't promote
    }
    
    $nextClassName = $classSequence[$currentIndex + 1];
    $nextStmt = $pdo->prepare("SELECT id FROM classes WHERE LOWER(name) = LOWER(?) LIMIT 1");
    $nextStmt->execute([$nextClassName]);
    $nextClass = $nextStmt->fetch(PDO::FETCH_ASSOC);
    
    return $nextClass ? $nextClass['id'] : null;
  } catch (Exception $e) {
    return null;
  }
}

/**
 * Get all pending learner promotions with financial data
 */
function get_pending_promotions($pdo) {
  try {
    $stmt = $pdo->prepare("
      SELECT 
        lp.id,
        lp.learner_id,
        lp.from_class_id,
        lp.to_class_id,
        lp.status,
        lp.balance_before,
        lp.balance_carried,
        lp.created_at,
        l.reg_number,
        l.full_name,
        l.guardian_name,
        l.guardian_phone,
        cf.name AS from_class_name,
        ct.name AS to_class_name,
        u.name AS created_by_name
      FROM learner_promotions lp
      JOIN learners l ON l.id = lp.learner_id
      JOIN classes cf ON cf.id = lp.from_class_id
      JOIN classes ct ON ct.id = lp.to_class_id
      LEFT JOIN users u ON u.id = lp.created_by
      WHERE lp.status = 'pending'
      ORDER BY lp.created_at DESC
    ");
    $stmt->execute();
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
  } catch (Exception $e) {
    return [];
  }
}

/**
 * Approve a single promotion and move learner to new class
 */
function approve_promotion($pdo, int $promotion_id, int $admin_id): bool {
  try {
    $pdo->beginTransaction();
    
    // Get promotion details
    $promStmt = $pdo->prepare("
      SELECT lp.*, l.id AS learner_id 
      FROM learner_promotions lp
      JOIN learners l ON l.id = lp.learner_id
      WHERE lp.id = ?
    ");
    $promStmt->execute([$promotion_id]);
    $promo = $promStmt->fetch(PDO::FETCH_ASSOC);
    
    if (!$promo || $promo['status'] !== 'pending') {
      $pdo->rollBack();
      return false;
    }
    
    // Update learner's class
    $updateLearner = $pdo->prepare("UPDATE learners SET class_id = ? WHERE id = ?");
    $updateLearner->execute([$promo['to_class_id'], $promo['learner_id']]);
    
    // Mark promotion as approved
    $updatePromo = $pdo->prepare("
      UPDATE learner_promotions 
      SET status = 'approved', approved_by = ?, approved_at = NOW()
      WHERE id = ?
    ");
    $updatePromo->execute([$admin_id, $promotion_id]);
    
    // Log in system log
    $logStmt = $pdo->prepare("
      INSERT INTO system_logs (actor_id, actor_role, action, details, entity_type, entity_id, ip_address, created_at)
      VALUES (?, 'admin', 'learner_promotion_approved', ?, 'learner_promotion', ?, ?, NOW())
    ");
    $logStmt->execute([
      $admin_id,
      "Learner ID {$promo['learner_id']} promoted from class {$promo['from_class_id']} to {$promo['to_class_id']}, balance carried: USD {$promo['balance_carried']}",
      $promotion_id,
      $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'
    ]);
    
    $pdo->commit();
    return true;
  } catch (Exception $e) {
    $pdo->rollBack();
    return false;
  }
}

/**
 * Approve all pending promotions (batch operation)
 */
function approve_all_promotions($pdo, int $admin_id): int {
  try {
    $pdo->beginTransaction();
    $approved_count = 0;
    
    $pendingStmt = $pdo->prepare("
      SELECT id FROM learner_promotions WHERE status = 'pending' ORDER BY id
    ");
    $pendingStmt->execute();
    $pendingPromos = $pendingStmt->fetchAll(PDO::FETCH_ASSOC);
    
    foreach ($pendingPromos as $promo) {
      if (approve_promotion($pdo, $promo['id'], $admin_id)) {
        $approved_count++;
      }
    }
    
    $pdo->commit();
    return $approved_count;
  } catch (Exception $e) {
    $pdo->rollBack();
    return 0;
  }
}

/**
 * Approve all pending learner admissions in one action.
 */
function approve_all_pending_admissions($pdo, int $admin_id): int {
  try {
    $pdo->beginTransaction();
    $approved_count = 0;

    $pendingStmt = $pdo->prepare("SELECT * FROM admissions_pending WHERE status = 'pending' ORDER BY created_at ASC FOR UPDATE");
    $pendingStmt->execute();
    $pendingAdmissions = $pendingStmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($pendingAdmissions as $pending) {
      $regNumber = generate_reg_number($pdo, (int)$pending['class_id']);
      $insertLearner = $pdo->prepare("INSERT INTO learners (
          reg_number,
          class_id,
          date_of_admission,
          surname,
          christian_names,
          full_name,
          date_of_birth_info,
          birth_certificate_number,
          religious_denomination,
          gender,
          guardian_name,
          guardian_national_id,
          guardian_address,
          guardian_phone,
          student_photo_path
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
      $insertLearner->execute([
        $regNumber,
        (int)$pending['class_id'],
        $pending['date_of_admission'] ?: null,
        $pending['surname'],
        $pending['christian_names'],
        $pending['full_name'],
        $pending['date_of_birth_info'],
        $pending['birth_certificate_number'],
        $pending['religious_denomination'],
        $pending['gender'],
        $pending['guardian_name'],
        $pending['guardian_national_id'],
        $pending['guardian_address'],
        $pending['guardian_phone'],
        $pending['student_photo_path'] ?? null
      ]);

      $approveStmt = $pdo->prepare("UPDATE admissions_pending
        SET status = 'approved', reviewed_by = ?, reviewed_at = NOW(), review_comment = ?
        WHERE id = ?");
      $approveStmt->execute([$admin_id > 0 ? $admin_id : null, 'Approved by admin', (int)$pending['id']]);
      $approved_count++;
    }

    $pdo->commit();
    return $approved_count;
  } catch (Exception $e) {
    if ($pdo->inTransaction()) {
      $pdo->rollBack();
    }
    return 0;
  }
}

/**
 * Create batch promotions for all eligible learners (typically run on Jan 1st)
 */
function create_batch_promotions($pdo, int $admin_id): int {
  try {
    $pdo->beginTransaction();
    $created_count = 0;
    $current_year = (int)date('Y');
    
    // Get all active learners (not frozen)
    $learnersStmt = $pdo->prepare("
      SELECT l.id, l.class_id, l.full_name 
      FROM learners l
      WHERE COALESCE(l.is_frozen, 0) = 0
      ORDER BY l.class_id, l.full_name
    ");
    $learnersStmt->execute();
    $learners = $learnersStmt->fetchAll(PDO::FETCH_ASSOC);
    
    foreach ($learners as $learner) {
      $nextClassId = get_next_class($pdo, $learner['class_id']);
      
      if ($nextClassId === null) {
        continue; // Can't promote (last form or invalid)
      }
      
      // Check if promotion for this year already exists
      $checkStmt = $pdo->prepare("
        SELECT id FROM learner_promotions 
        WHERE learner_id = ? AND promotion_year = ? AND (status = 'pending' OR status = 'approved')
        LIMIT 1
      ");
      $checkStmt->execute([$learner['id'], $current_year]);
      
      if ($checkStmt->fetch()) {
        continue; // Promotion already exists for this year
      }
      
      // Calculate balance for current class
      $balance = get_learner_balance_for_class($pdo, $learner['id'], $learner['class_id']);
      
      // Create promotion record
      $insertStmt = $pdo->prepare("
        INSERT INTO learner_promotions 
        (learner_id, from_class_id, to_class_id, promotion_year, status, balance_before, balance_carried, created_by, created_at)
        VALUES (?, ?, ?, ?, 'pending', ?, ?, ?, NOW())
      ");
      $insertStmt->execute([
        $learner['id'],
        $learner['class_id'],
        $nextClassId,
        $current_year,
        $balance,
        $balance, // Carried forward to next class
        $admin_id
      ]);
      
      $created_count++;
    }
    
    $pdo->commit();
    return $created_count;
  } catch (Exception $e) {
    $pdo->rollBack();
    return 0;
  }
}

// ========== END PROMOTION FUNCTIONS ==========

$alerts = [];
$activeAdminId = (int)($_SESSION['user_id'] ?? 0);
$initialAdminView = 'adminHomeView';
$operationsStepIds = [
  'operationsStepClassSubject',
  'operationsStepTeacher',
  'operationsStepHop',
  'operationsStepTeacherHopAssignment',
  'operationsStepClassTeacher',
  'operationsStepSubjectAllocation',
  'operationsStepAdmissionApprovals'
];
$initialOperationsStep = 'operationsStepClassSubject';

$adminProfileStmt = $pdo->prepare("SELECT id, name, email, role, password_hash FROM users WHERE id = ? AND role = 'admin' LIMIT 1");
$adminProfileStmt->execute([$activeAdminId]);
$adminProfile = $adminProfileStmt->fetch();

if (!$adminProfile) {
  logout_user();
  header('Location: index.php');
  exit;
}

$postedOperationsStep = trim((string)($_POST['admin_operations_step'] ?? $_GET['admin_operations_step'] ?? ''));
if (in_array($postedOperationsStep, $operationsStepIds, true)) {
  $initialOperationsStep = $postedOperationsStep;
}

$allowedAdminViews = [
  'adminHomeView',
  'adminSecurityView',
  'adminSystemLogView',
  'adminStaffDetailsView',
  'adminAncillaryStaffView',
  'adminOperationsView',
  'adminAdmissionView',
  'adminStudentIdsView',
  'adminApplicationsView',
  'adminTransfersView',
  'adminLearnerPromotionsView',
  'adminLeaveRequestsView',
  'adminWorkloadView',
  'adminRegistryView',
  'adminCoverageView',
  'adminParentsDeskView',
  'adminAnnouncementsView',
  'adminSchoolSettingsView',
  'adminWhatsappSettingsView',
  'adminTeacherDocumentsView',
  'adminAssetsRegisterView'
];

$admissionEditLearnerId = (int)($_GET['edit_admission_id'] ?? 0);
if ($admissionEditLearnerId > 0) {
  $initialAdminView = 'adminAdmissionView';
}

if (isset($_POST['save_admin_profile'])) {
  $initialAdminView = 'adminSecurityView';
  $profileName = trim((string)($_POST['profile_name'] ?? ''));
  $profileEmail = trim((string)($_POST['profile_email'] ?? ''));

  if ($profileName === '' || $profileEmail === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Profile name and email are required.'];
  } elseif (!filter_var($profileEmail, FILTER_VALIDATE_EMAIL)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please provide a valid profile email address.'];
  } else {
    $emailExistsStmt = $pdo->prepare("SELECT id FROM users WHERE LOWER(email) = LOWER(?) AND id <> ? LIMIT 1");
    $emailExistsStmt->execute([$profileEmail, $activeAdminId]);
    if ($emailExistsStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'That email is already used by another account.'];
    } else {
      $updateProfileStmt = $pdo->prepare("UPDATE users SET name = ?, email = ? WHERE id = ? AND role = 'admin' LIMIT 1");
      $updateProfileStmt->execute([$profileName, $profileEmail, $activeAdminId]);
      append_system_log($pdo, 'admin_profile_updated', 'Admin profile updated for ' . $profileEmail, $activeAdminId, 'admin', 'user', $activeAdminId, get_client_ip_address());
      $_SESSION['name'] = $profileName;
      $adminProfile['name'] = $profileName;
      $adminProfile['email'] = $profileEmail;
      $alerts[] = ['type' => 'success', 'text' => 'Admin profile updated successfully.'];
    }
  }
}

if (isset($_POST['change_admin_password'])) {
  $initialAdminView = 'adminSecurityView';
  $currentPassword = (string)($_POST['current_password'] ?? '');
  $newPassword = (string)($_POST['new_password'] ?? '');
  $confirmPassword = (string)($_POST['confirm_password'] ?? '');

  if ($currentPassword === '' || $newPassword === '' || $confirmPassword === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Current password, new password, and confirmation are required.'];
  } elseif (!password_verify($currentPassword, (string)$adminProfile['password_hash'])) {
    $alerts[] = ['type' => 'error', 'text' => 'Current password is incorrect.'];
  } elseif (!mavela_password_is_strong($newPassword)) {
    $alerts[] = ['type' => 'error', 'text' => 'Use at least 10 characters with uppercase, lowercase, and a number.'];
  } elseif ($newPassword !== $confirmPassword) {
    $alerts[] = ['type' => 'error', 'text' => 'New password and confirmation do not match.'];
  } else {
    $newHash = password_hash($newPassword, PASSWORD_DEFAULT);
    $updatePasswordStmt = $pdo->prepare("UPDATE users SET password_hash = ?, must_change_password = 0 WHERE id = ? AND role = 'admin' LIMIT 1");
    $updatePasswordStmt->execute([$newHash, $activeAdminId]);
    $_SESSION['must_change_password'] = false;
    append_system_log($pdo, 'admin_password_changed', 'Admin password changed for ' . $adminProfile['email'], $activeAdminId, 'admin', 'user', $activeAdminId, get_client_ip_address());
    $adminProfile['password_hash'] = $newHash;
    $alerts[] = ['type' => 'success', 'text' => 'Admin password changed successfully.'];
  }
}

if (isset($_POST['review_password_reset_request'])) {
  $initialAdminView = 'adminSecurityView';
  $requestId = (int)($_POST['reset_request_id'] ?? 0);
  $decision = trim((string)($_POST['reset_decision'] ?? ''));
  $adminNote = trim((string)($_POST['reset_admin_note'] ?? ''));

  if ($requestId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid password reset request selected.'];
  } elseif (!in_array($decision, ['approve', 'reject'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid password reset decision selected.'];
  } else {
    try {
      $pdo->beginTransaction();
      $resetRequestStmt = $pdo->prepare("SELECT id, user_id, email, requested_password_hash
        FROM password_reset_requests
        WHERE id = ? AND status = 'pending'
        LIMIT 1
        FOR UPDATE");
      $resetRequestStmt->execute([$requestId]);
      $resetRequest = $resetRequestStmt->fetch();

      if (!$resetRequest) {
        $pdo->rollBack();
        $alerts[] = ['type' => 'error', 'text' => 'Password reset request not found or already reviewed.'];
      } else {
        if ($decision === 'approve') {
          $applyPasswordStmt = $pdo->prepare("UPDATE users SET password_hash = ? WHERE id = ? LIMIT 1");
          $applyPasswordStmt->execute([
            (string)$resetRequest['requested_password_hash'],
            (int)$resetRequest['user_id']
          ]);

          $markResetStmt = $pdo->prepare("UPDATE password_reset_requests
            SET status = 'approved', admin_note = ?, reviewed_by = ?, reviewed_at = NOW()
            WHERE id = ? LIMIT 1");
          $markResetStmt->execute([
            $adminNote === '' ? 'Approved after physical verification by admin.' : $adminNote,
            $activeAdminId,
            $requestId
          ]);

          $alerts[] = ['type' => 'success', 'text' => 'Password reset approved and applied for ' . (string)$resetRequest['email'] . '.'];
        } else {
          $markResetStmt = $pdo->prepare("UPDATE password_reset_requests
            SET status = 'rejected', admin_note = ?, reviewed_by = ?, reviewed_at = NOW()
            WHERE id = ? LIMIT 1");
          $markResetStmt->execute([
            $adminNote === '' ? 'Rejected after verification checks.' : $adminNote,
            $activeAdminId,
            $requestId
          ]);

          $alerts[] = ['type' => 'success', 'text' => 'Password reset request rejected.'];
        }

        $pdo->commit();
      }
    } catch (Throwable $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      $alerts[] = ['type' => 'error', 'text' => 'Could not process password reset request: ' . mavela_exception_detail($e)];
    }
  }
}

if (isset($_POST['save_staff_details'])) {
  $initialAdminView = 'adminStaffDetailsView';
  $staffUserId = (int)($_POST['staff_user_id'] ?? 0);
  $staffFullName = trim((string)($_POST['staff_full_name'] ?? ''));
  $staffEmail = trim((string)($_POST['staff_email'] ?? ''));
  $staffSex = trim((string)($_POST['staff_sex'] ?? ''));
  $staffDob = trim((string)($_POST['staff_dob'] ?? ''));
  $staffEcNumber = trim((string)($_POST['staff_ec_number'] ?? ''));
  $staffNationalId = trim((string)($_POST['staff_national_id'] ?? ''));
  $staffQualifications = trim((string)($_POST['staff_qualifications'] ?? ''));
  $staffSubjectSpecialization = trim((string)($_POST['staff_subject_specialization'] ?? ''));
  $allowedSex = ['Male', 'Female', 'Other'];

  if ($staffUserId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose a teacher first.'];
  } elseif ($staffFullName === '' || $staffEmail === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Full name and email are required for staff details.'];
  } elseif (!filter_var($staffEmail, FILTER_VALIDATE_EMAIL)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please provide a valid staff email address.'];
  } elseif ($staffSex !== '' && !in_array($staffSex, $allowedSex, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid sex value selected.'];
  } elseif ($staffDob !== '' && normalize_person_dob_for_match($staffDob) === null) {
    $alerts[] = ['type' => 'error', 'text' => 'Date of birth must use YYYY-MM-DD format.'];
  } else {
    $staffExistsStmt = $pdo->prepare("SELECT id FROM users WHERE id = ? AND role = 'teacher' LIMIT 1");
    $staffExistsStmt->execute([$staffUserId]);
    if (!$staffExistsStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'Selected staff record does not exist.'];
    } else {
      $emailExistsStmt = $pdo->prepare("SELECT id FROM users WHERE LOWER(email) = LOWER(?) AND id <> ? LIMIT 1");
      $emailExistsStmt->execute([$staffEmail, $staffUserId]);
      if ($emailExistsStmt->fetch()) {
        $alerts[] = ['type' => 'error', 'text' => 'That email is already used by another account.'];
      } else {
        $duplicateStaff = find_duplicate_teacher_by_name_and_dob($pdo, $staffFullName, $staffDob, $staffUserId);
        if ($duplicateStaff) {
          $alerts[] = ['type' => 'error', 'text' => 'A teacher with the same name and date of birth already exists.'];
        } else {
          try {
            $pdo->beginTransaction();

            $updateUserStmt = $pdo->prepare("UPDATE users SET name = ?, email = ? WHERE id = ? LIMIT 1");
            $updateUserStmt->execute([$staffFullName, $staffEmail, $staffUserId]);

            $upsertStaffProfileStmt = $pdo->prepare("INSERT INTO staff_profiles
              (user_id, sex, date_of_birth, ec_number, national_id, qualifications, subject_specialization, updated_by)
              VALUES (?, ?, ?, ?, ?, ?, ?, ?)
              ON DUPLICATE KEY UPDATE
                sex = VALUES(sex),
                date_of_birth = VALUES(date_of_birth),
                ec_number = VALUES(ec_number),
                national_id = VALUES(national_id),
                qualifications = VALUES(qualifications),
                subject_specialization = VALUES(subject_specialization),
                updated_by = VALUES(updated_by)");
            $upsertStaffProfileStmt->execute([
              $staffUserId,
              $staffSex === '' ? null : $staffSex,
              $staffDob === '' ? null : $staffDob,
              $staffEcNumber === '' ? null : $staffEcNumber,
              $staffNationalId === '' ? null : $staffNationalId,
              $staffQualifications === '' ? null : $staffQualifications,
              $staffSubjectSpecialization === '' ? null : $staffSubjectSpecialization,
              $activeAdminId
            ]);

            $pdo->commit();
            $alerts[] = ['type' => 'success', 'text' => 'Staff details saved successfully.'];
          } catch (Throwable $e) {
            if ($pdo->inTransaction()) {
              $pdo->rollBack();
            }
            $alerts[] = ['type' => 'error', 'text' => 'Could not save staff details: ' . mavela_exception_detail($e)];
          }
        }
      }
    }
  }
}

if (isset($_POST['save_ancillary_staff_details'])) {
  $initialAdminView = 'adminAncillaryStaffView';
  $staffUserId = (int)($_POST['ancillary_user_id'] ?? 0);
  $staffFullName = trim((string)($_POST['ancillary_full_name'] ?? ''));
  $staffEmail = trim((string)($_POST['ancillary_email'] ?? ''));
  $staffSex = trim((string)($_POST['ancillary_sex'] ?? ''));
  $staffDob = trim((string)($_POST['ancillary_dob'] ?? ''));
  $staffEcNumber = trim((string)($_POST['ancillary_ec_number'] ?? ''));
  $staffNationalId = trim((string)($_POST['ancillary_national_id'] ?? ''));
  $staffWorkProfile = trim((string)($_POST['ancillary_work_profile'] ?? ''));
  $staffQualifications = trim((string)($_POST['ancillary_qualifications'] ?? ''));
  $allowedSex = ['Male', 'Female', 'Other'];

  if ($staffUserId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose an ancillary staff member first.'];
  } elseif ($staffFullName === '' || $staffEmail === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Full name and email are required for ancillary staff details.'];
  } elseif (!filter_var($staffEmail, FILTER_VALIDATE_EMAIL)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please provide a valid ancillary staff email address.'];
  } elseif ($staffSex !== '' && !in_array($staffSex, $allowedSex, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid sex value selected.'];
  } elseif ($staffDob !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $staffDob)) {
    $alerts[] = ['type' => 'error', 'text' => 'Date of birth must use YYYY-MM-DD format.'];
  } else {
    $staffExistsStmt = $pdo->prepare("SELECT id FROM users WHERE id = ? AND role = 'ancillary' LIMIT 1");
    $staffExistsStmt->execute([$staffUserId]);
    if (!$staffExistsStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'Selected ancillary staff record does not exist.'];
    } else {
      $emailExistsStmt = $pdo->prepare("SELECT id FROM users WHERE LOWER(email) = LOWER(?) AND id <> ? LIMIT 1");
      $emailExistsStmt->execute([$staffEmail, $staffUserId]);
      if ($emailExistsStmt->fetch()) {
        $alerts[] = ['type' => 'error', 'text' => 'That email is already used by another account.'];
      } else {
        try {
          $pdo->beginTransaction();

          $updateUserStmt = $pdo->prepare("UPDATE users SET name = ?, email = ? WHERE id = ? LIMIT 1");
          $updateUserStmt->execute([$staffFullName, $staffEmail, $staffUserId]);

          $upsertStaffProfileStmt = $pdo->prepare("INSERT INTO staff_profiles
            (user_id, sex, date_of_birth, ec_number, national_id, work_profile, qualifications, subject_specialization, updated_by)
            VALUES (?, ?, ?, ?, ?, ?, ?, NULL, ?)
            ON DUPLICATE KEY UPDATE
              sex = VALUES(sex),
              date_of_birth = VALUES(date_of_birth),
              ec_number = VALUES(ec_number),
              national_id = VALUES(national_id),
              work_profile = VALUES(work_profile),
              qualifications = VALUES(qualifications),
              updated_by = VALUES(updated_by)");
          $upsertStaffProfileStmt->execute([
            $staffUserId,
            $staffSex === '' ? null : $staffSex,
            $staffDob === '' ? null : $staffDob,
            $staffEcNumber === '' ? null : $staffEcNumber,
            $staffNationalId === '' ? null : $staffNationalId,
            $staffWorkProfile === '' ? null : $staffWorkProfile,
            $staffQualifications === '' ? null : $staffQualifications,
            $activeAdminId
          ]);

          $pdo->commit();
          $alerts[] = ['type' => 'success', 'text' => 'Ancillary staff details saved successfully.'];
        } catch (Throwable $e) {
          if ($pdo->inTransaction()) {
            $pdo->rollBack();
          }
          $alerts[] = ['type' => 'error', 'text' => 'Could not save ancillary staff details: ' . mavela_exception_detail($e)];
        }
      }
    }
  }
}

$defaultSchoolName = 'MAVELA GOVERNMENT HIGH SCHOOL';
$defaultSchoolAddress = 'P.O.Box 12 Tsholotsho';
$defaultSchoolContact = 'Phone: +263 77 000 0000 | Email: admin@mavelahigh.org';
$defaultSchoolMotto = 'Imfundo Yinsika Yesizwe';
$defaultSchoolLogoPath = 'Uploads/Mavela_Logo.png';

$themePresets = [
  'ocean' => [
    'label' => 'Ocean Blue',
    'bg_cream' => '#f6efe0',
    'bg_sand' => '#eadcc0',
    'ink' => '#0a2f63',
    'muted' => '#4f5f7a',
    'brand_navy' => '#0a3b79',
    'brand_navy_deep' => '#082e60',
    'brand_gold' => '#f8b400',
    'brand_gold_soft' => '#d9c39a',
    'brand_ice' => '#e8eef8',
    'patch_sky' => '#7cc9ff',
    'patch_sky_soft' => '#dff2ff',
    'patch_yellow' => '#ffd447',
    'patch_yellow_soft' => '#fff4be'
  ],
  'sunset' => [
    'label' => 'Sunset Orange',
    'bg_cream' => '#fff2e4',
    'bg_sand' => '#f7ddc6',
    'ink' => '#5d2b1f',
    'muted' => '#7b5a4e',
    'brand_navy' => '#b74f2a',
    'brand_navy_deep' => '#8a3518',
    'brand_gold' => '#f4a300',
    'brand_gold_soft' => '#efc48d',
    'brand_ice' => '#ffe7d4',
    'patch_sky' => '#ffb56b',
    'patch_sky_soft' => '#ffe2c4',
    'patch_yellow' => '#ffd15c',
    'patch_yellow_soft' => '#fff1bf'
  ],
  'forest' => [
    'label' => 'Forest Green',
    'bg_cream' => '#f7fbf7',
    'bg_sand' => '#e5f0e6',
    'ink' => '#173122',
    'muted' => '#4f6656',
    'brand_navy' => '#2e8b45',
    'brand_navy_deep' => '#1d6a33',
    'brand_gold' => '#1e1a1b',
    'brand_gold_soft' => '#d8ddd8',
    'brand_ice' => '#eef7ef',
    'patch_sky' => '#7cc9ff',
    'patch_sky_soft' => '#dff2ff',
    'patch_yellow' => '#7dc48a',
    'patch_yellow_soft' => '#f0f7f1'
  ]
];

$defaultThemePreset = 'forest';

$normalizeHexColor = static function (string $raw, string $fallback): string {
  $value = strtoupper(trim($raw));
  if (preg_match('/^#[0-9A-F]{6}$/', $value)) {
    return $value;
  }
  return strtoupper($fallback);
};

$schoolName = trim(get_app_setting($pdo, 'school_name', $defaultSchoolName));
$schoolAddress = trim(get_app_setting($pdo, 'school_address', $defaultSchoolAddress));
$schoolContact = trim(get_app_setting($pdo, 'school_contact', $defaultSchoolContact));
$schoolMotto = trim(get_app_setting($pdo, 'school_motto', $defaultSchoolMotto));
$schoolLogoPath = trim(get_app_setting($pdo, 'school_logo_path', $defaultSchoolLogoPath));

$schoolThemePreset = trim(get_app_setting($pdo, 'school_theme_preset', $defaultThemePreset));
if (!array_key_exists($schoolThemePreset, $themePresets)) {
  $schoolThemePreset = $defaultThemePreset;
}
$activeThemePalette = $themePresets[$schoolThemePreset];

$paletteBgCream = $normalizeHexColor(get_app_setting($pdo, 'palette_bg_cream', $activeThemePalette['bg_cream']), $activeThemePalette['bg_cream']);
$paletteBgSand = $normalizeHexColor(get_app_setting($pdo, 'palette_bg_sand', $activeThemePalette['bg_sand']), $activeThemePalette['bg_sand']);
$paletteInk = $normalizeHexColor(get_app_setting($pdo, 'palette_ink', $activeThemePalette['ink']), $activeThemePalette['ink']);
$paletteMuted = $normalizeHexColor(get_app_setting($pdo, 'palette_muted', $activeThemePalette['muted']), $activeThemePalette['muted']);
$paletteBrandNavy = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_navy', $activeThemePalette['brand_navy']), $activeThemePalette['brand_navy']);
$paletteBrandNavyDeep = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_navy_deep', $activeThemePalette['brand_navy_deep']), $activeThemePalette['brand_navy_deep']);
$paletteBrandGold = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_gold', $activeThemePalette['brand_gold']), $activeThemePalette['brand_gold']);
$paletteBrandGoldSoft = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_gold_soft', $activeThemePalette['brand_gold_soft']), $activeThemePalette['brand_gold_soft']);
$paletteBrandIce = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_ice', $activeThemePalette['brand_ice']), $activeThemePalette['brand_ice']);
$palettePatchSky = $normalizeHexColor(get_app_setting($pdo, 'palette_patch_sky', $activeThemePalette['patch_sky']), $activeThemePalette['patch_sky']);
$palettePatchSkySoft = $normalizeHexColor(get_app_setting($pdo, 'palette_patch_sky_soft', $activeThemePalette['patch_sky_soft']), $activeThemePalette['patch_sky_soft']);
$palettePatchYellow = $normalizeHexColor(get_app_setting($pdo, 'palette_patch_yellow', $activeThemePalette['patch_yellow']), $activeThemePalette['patch_yellow']);
$palettePatchYellowSoft = $normalizeHexColor(get_app_setting($pdo, 'palette_patch_yellow_soft', $activeThemePalette['patch_yellow_soft']), $activeThemePalette['patch_yellow_soft']);

if ($schoolName === '') {
  $schoolName = $defaultSchoolName;
}
if ($schoolAddress === '') {
  $schoolAddress = $defaultSchoolAddress;
}
if ($schoolContact === '') {
  $schoolContact = $defaultSchoolContact;
}
if ($schoolMotto === '') {
  $schoolMotto = $defaultSchoolMotto;
}

if ($schoolLogoPath === '') {
  $schoolLogoPath = $defaultSchoolLogoPath;
}

$resolvedSchoolLogoPath = $schoolLogoPath;
$resolvedSchoolLogoAbsolute = __DIR__ . '/' . ltrim($resolvedSchoolLogoPath, '/\\');
if (!is_file($resolvedSchoolLogoAbsolute)) {
  $fallbackLogoAbsolute = __DIR__ . '/' . ltrim($defaultSchoolLogoPath, '/\\');
  if (is_file($fallbackLogoAbsolute)) {
    $resolvedSchoolLogoPath = $defaultSchoolLogoPath;
    $resolvedSchoolLogoAbsolute = $fallbackLogoAbsolute;
  } else {
    $resolvedSchoolLogoPath = '';
    $resolvedSchoolLogoAbsolute = '';
  }
}

$postedActiveView = trim((string)($_POST['admin_active_view'] ?? ''));
if ($postedActiveView !== '' && in_array($postedActiveView, $allowedAdminViews, true)) {
  $initialAdminView = $postedActiveView;
}

if (isset($_POST['save_whatsapp_settings'])) {
  $initialAdminView = 'adminWhatsappSettingsView';
  $phoneNumberId = trim((string)($_POST['whatsapp_phone_number_id'] ?? ''));
  $apiVersion = trim((string)($_POST['whatsapp_api_version'] ?? 'v22.0'));
  $tokenInput = trim((string)($_POST['whatsapp_token'] ?? ''));
  $clearToken = isset($_POST['whatsapp_clear_token']);

  if ($phoneNumberId === '') {
    $alerts[] = ['type' => 'error', 'text' => 'WhatsApp Phone Number ID is required.'];
  } elseif (!preg_match('/^[0-9]{6,30}$/', $phoneNumberId)) {
    $alerts[] = ['type' => 'error', 'text' => 'WhatsApp Phone Number ID should contain digits only.'];
  } elseif ($apiVersion === '' || !preg_match('/^v[0-9]+\.[0-9]+$/', $apiVersion)) {
    $alerts[] = ['type' => 'error', 'text' => 'API version must look like v22.0'];
  } else {
    $savedPhoneId = set_app_setting($pdo, 'whatsapp_phone_number_id', $phoneNumberId, $activeAdminId > 0 ? $activeAdminId : null);
    $savedApiVersion = set_app_setting($pdo, 'whatsapp_api_version', $apiVersion, $activeAdminId > 0 ? $activeAdminId : null);

    $savedToken = true;
    if ($clearToken) {
      $savedToken = set_app_setting($pdo, 'whatsapp_token', '', $activeAdminId > 0 ? $activeAdminId : null);
    } elseif ($tokenInput !== '') {
      $savedToken = set_app_setting($pdo, 'whatsapp_token', $tokenInput, $activeAdminId > 0 ? $activeAdminId : null);
    }

    if ($savedPhoneId && $savedApiVersion && $savedToken) {
      $alerts[] = ['type' => 'success', 'text' => 'WhatsApp settings saved successfully.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Could not save WhatsApp settings. Please retry.'];
    }
  }
}

if (isset($_POST['save_school_profile_settings'])) {
  $initialAdminView = 'adminSchoolSettingsView';

  $postedSchoolName = trim((string)($_POST['school_name'] ?? ''));
  $postedSchoolAddress = trim((string)($_POST['school_address'] ?? ''));
  $postedSchoolContact = trim((string)($_POST['school_contact'] ?? ''));
  $postedSchoolMotto = trim((string)($_POST['school_motto'] ?? ''));
  $postedThemePreset = trim((string)($_POST['school_theme_preset'] ?? $schoolThemePreset));
  $applyThemePreset = isset($_POST['apply_theme_preset']);
  $clearSchoolLogo = isset($_POST['clear_school_logo']);

  if (!array_key_exists($postedThemePreset, $themePresets)) {
    $postedThemePreset = $defaultThemePreset;
  }

  $presetPalette = $themePresets[$postedThemePreset];
  $postedPalette = [
    'bg_cream' => $applyThemePreset
      ? $presetPalette['bg_cream']
      : $normalizeHexColor((string)($_POST['palette_bg_cream'] ?? $paletteBgCream), $presetPalette['bg_cream']),
    'bg_sand' => $applyThemePreset
      ? $presetPalette['bg_sand']
      : $normalizeHexColor((string)($_POST['palette_bg_sand'] ?? $paletteBgSand), $presetPalette['bg_sand']),
    'ink' => $applyThemePreset
      ? $presetPalette['ink']
      : $normalizeHexColor((string)($_POST['palette_ink'] ?? $paletteInk), $presetPalette['ink']),
    'muted' => $applyThemePreset
      ? $presetPalette['muted']
      : $normalizeHexColor((string)($_POST['palette_muted'] ?? $paletteMuted), $presetPalette['muted']),
    'brand_navy' => $applyThemePreset
      ? $presetPalette['brand_navy']
      : $normalizeHexColor((string)($_POST['palette_brand_navy'] ?? $paletteBrandNavy), $presetPalette['brand_navy']),
    'brand_navy_deep' => $applyThemePreset
      ? $presetPalette['brand_navy_deep']
      : $normalizeHexColor((string)($_POST['palette_brand_navy_deep'] ?? $paletteBrandNavyDeep), $presetPalette['brand_navy_deep']),
    'brand_gold' => $applyThemePreset
      ? $presetPalette['brand_gold']
      : $normalizeHexColor((string)($_POST['palette_brand_gold'] ?? $paletteBrandGold), $presetPalette['brand_gold']),
    'brand_gold_soft' => $applyThemePreset
      ? $presetPalette['brand_gold_soft']
      : $normalizeHexColor((string)($_POST['palette_brand_gold_soft'] ?? $paletteBrandGoldSoft), $presetPalette['brand_gold_soft']),
    'brand_ice' => $applyThemePreset
      ? $presetPalette['brand_ice']
      : $normalizeHexColor((string)($_POST['palette_brand_ice'] ?? $paletteBrandIce), $presetPalette['brand_ice']),
    'patch_sky' => $applyThemePreset
      ? $presetPalette['patch_sky']
      : $normalizeHexColor((string)($_POST['palette_patch_sky'] ?? $palettePatchSky), $presetPalette['patch_sky']),
    'patch_sky_soft' => $applyThemePreset
      ? $presetPalette['patch_sky_soft']
      : $normalizeHexColor((string)($_POST['palette_patch_sky_soft'] ?? $palettePatchSkySoft), $presetPalette['patch_sky_soft']),
    'patch_yellow' => $applyThemePreset
      ? $presetPalette['patch_yellow']
      : $normalizeHexColor((string)($_POST['palette_patch_yellow'] ?? $palettePatchYellow), $presetPalette['patch_yellow']),
    'patch_yellow_soft' => $applyThemePreset
      ? $presetPalette['patch_yellow_soft']
      : $normalizeHexColor((string)($_POST['palette_patch_yellow_soft'] ?? $palettePatchYellowSoft), $presetPalette['patch_yellow_soft'])
  ];

  if ($postedSchoolName === '') {
    $alerts[] = ['type' => 'error', 'text' => 'School name is required.'];
  } else {
    $saveOk = true;
    $saveOk = $saveOk && set_app_setting($pdo, 'school_name', $postedSchoolName, $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'school_address', $postedSchoolAddress, $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'school_contact', $postedSchoolContact, $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'school_motto', $postedSchoolMotto, $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'school_theme_preset', $postedThemePreset, $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_bg_cream', $postedPalette['bg_cream'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_bg_sand', $postedPalette['bg_sand'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_ink', $postedPalette['ink'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_muted', $postedPalette['muted'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_brand_navy', $postedPalette['brand_navy'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_brand_navy_deep', $postedPalette['brand_navy_deep'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_brand_gold', $postedPalette['brand_gold'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_brand_gold_soft', $postedPalette['brand_gold_soft'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_brand_ice', $postedPalette['brand_ice'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_patch_sky', $postedPalette['patch_sky'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_patch_sky_soft', $postedPalette['patch_sky_soft'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_patch_yellow', $postedPalette['patch_yellow'], $activeAdminId > 0 ? $activeAdminId : null);
    $saveOk = $saveOk && set_app_setting($pdo, 'palette_patch_yellow_soft', $postedPalette['patch_yellow_soft'], $activeAdminId > 0 ? $activeAdminId : null);

    $nextLogoPath = $resolvedSchoolLogoPath;
    if ($clearSchoolLogo) {
      $nextLogoPath = '';
      $saveOk = $saveOk && set_app_setting($pdo, 'school_logo_path', '', $activeAdminId > 0 ? $activeAdminId : null);
    }

    $logoUploadError = (int)($_FILES['school_logo']['error'] ?? UPLOAD_ERR_NO_FILE);
    if ($logoUploadError !== UPLOAD_ERR_NO_FILE) {
      if ($logoUploadError !== UPLOAD_ERR_OK) {
        $alerts[] = ['type' => 'error', 'text' => 'School logo upload failed. Please retry.'];
        $saveOk = false;
      } else {
        $logoOriginalName = (string)($_FILES['school_logo']['name'] ?? '');
        $logoTmpName = (string)($_FILES['school_logo']['tmp_name'] ?? '');
        $logoSize = (int)($_FILES['school_logo']['size'] ?? 0);
        $logoExt = strtolower(pathinfo($logoOriginalName, PATHINFO_EXTENSION));
        $allowedLogoExt = ['jpg', 'jpeg', 'png', 'webp'];

        if ($logoOriginalName === '' || $logoTmpName === '') {
          $alerts[] = ['type' => 'error', 'text' => 'Invalid school logo payload.'];
          $saveOk = false;
        } elseif ($logoSize <= 0 || $logoSize > 5 * 1024 * 1024) {
          $alerts[] = ['type' => 'error', 'text' => 'School logo must be between 1 byte and 5 MB.'];
          $saveOk = false;
        } elseif (!in_array($logoExt, $allowedLogoExt, true)) {
          $alerts[] = ['type' => 'error', 'text' => 'School logo must be JPG, PNG, or WEBP.'];
          $saveOk = false;
        } else {
          $logoFinfo = finfo_open(FILEINFO_MIME_TYPE);
          $logoMime = $logoFinfo ? (string)finfo_file($logoFinfo, $logoTmpName) : '';
          if ($logoFinfo) {
            finfo_close($logoFinfo);
          }
          if ($logoMime !== '' && strpos($logoMime, 'image/') !== 0) {
            $alerts[] = ['type' => 'error', 'text' => 'Uploaded school logo is not a valid image.'];
            $saveOk = false;
          } else {
            $logoUploadDir = __DIR__ . '/Uploads/school_branding';
            if (!is_dir($logoUploadDir) && !mkdir($logoUploadDir, 0775, true)) {
              $alerts[] = ['type' => 'error', 'text' => 'Could not prepare school branding upload folder.'];
              $saveOk = false;
            } else {
              $logoFileName = 'school_logo_' . date('Ymd_His') . '_' . bin2hex(random_bytes(3)) . '.' . $logoExt;
              $logoDestination = $logoUploadDir . '/' . $logoFileName;
              if (!move_uploaded_file($logoTmpName, $logoDestination)) {
                $alerts[] = ['type' => 'error', 'text' => 'Could not save uploaded school logo.'];
                $saveOk = false;
              } else {
                $nextLogoPath = 'Uploads/school_branding/' . $logoFileName;
                $saveOk = $saveOk && set_app_setting($pdo, 'school_logo_path', $nextLogoPath, $activeAdminId > 0 ? $activeAdminId : null);
              }
            }
          }
        }
      }
    }

    if ($saveOk) {
      $schoolName = $postedSchoolName;
      $schoolAddress = $postedSchoolAddress;
      $schoolContact = $postedSchoolContact;
      $schoolMotto = $postedSchoolMotto;
      $schoolThemePreset = $postedThemePreset;
      $paletteBgCream = $postedPalette['bg_cream'];
      $paletteBgSand = $postedPalette['bg_sand'];
      $paletteInk = $postedPalette['ink'];
      $paletteMuted = $postedPalette['muted'];
      $paletteBrandNavy = $postedPalette['brand_navy'];
      $paletteBrandNavyDeep = $postedPalette['brand_navy_deep'];
      $paletteBrandGold = $postedPalette['brand_gold'];
      $paletteBrandGoldSoft = $postedPalette['brand_gold_soft'];
      $paletteBrandIce = $postedPalette['brand_ice'];
      $palettePatchSky = $postedPalette['patch_sky'];
      $palettePatchSkySoft = $postedPalette['patch_sky_soft'];
      $palettePatchYellow = $postedPalette['patch_yellow'];
      $palettePatchYellowSoft = $postedPalette['patch_yellow_soft'];
      $resolvedSchoolLogoPath = $nextLogoPath;
      if ($resolvedSchoolLogoPath === '') {
        $fallbackLogoAbsolute = __DIR__ . '/' . ltrim($defaultSchoolLogoPath, '/\\');
        if (is_file($fallbackLogoAbsolute)) {
          $resolvedSchoolLogoPath = $defaultSchoolLogoPath;
        }
      }
      $resolvedSchoolLogoAbsolute = $resolvedSchoolLogoPath !== ''
        ? (__DIR__ . '/' . ltrim($resolvedSchoolLogoPath, '/\\'))
        : '';
      $alerts[] = ['type' => 'success', 'text' => 'School profile and color theme settings saved successfully.'];
    }
  }
}

if (isset($_POST['send_whatsapp_test_message'])) {
  $initialAdminView = 'adminWhatsappSettingsView';
  $testPhoneRaw = trim((string)($_POST['whatsapp_test_phone'] ?? ''));
  $testMessageRaw = trim((string)($_POST['whatsapp_test_message'] ?? ''));
  $testPhone = normalize_whatsapp_phone($testPhoneRaw);

  if (!whatsapp_notifications_enabled($pdo)) {
    $alerts[] = ['type' => 'error', 'text' => 'WhatsApp is not configured yet. Save WhatsApp settings first.'];
  } elseif ($testPhone === null) {
    $alerts[] = ['type' => 'error', 'text' => 'Enter a valid phone number, for example +26377XXXXXXX.'];
  } else {
    $testMessage = $testMessageRaw !== ''
      ? $testMessageRaw
      : 'MAVELA GOVERNMENT HIGH WhatsApp test successful. Admin integration is active.';

    $sendResult = send_whatsapp_message_to_phone($testPhone, $testMessage, $pdo);
    if (!empty($sendResult['ok'])) {
      $alerts[] = ['type' => 'success', 'text' => 'Test message sent successfully to ' . $testPhone . '.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Test message failed: ' . (string)($sendResult['error'] ?? 'send_failed')];
    }
  }
}

if (isset($_POST['add_teacher'])) {
  $initialAdminView = 'adminOperationsView';
  $teacherName = trim((string)($_POST['teacher_name'] ?? $_POST['name'] ?? ''));
  $teacherSurname = trim((string)($_POST['teacher_surname'] ?? ''));
  $teacherDob = trim((string)($_POST['teacher_dob'] ?? ''));
  $email = trim((string)($_POST['email'] ?? ''));
  $fullTeacherName = build_full_name_from_parts($teacherName, $teacherSurname);
  $normalizedTeacherDob = normalize_person_dob_for_match($teacherDob);

  if ($teacherName === '' || $teacherSurname === '' || $email === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Teacher name, surname, and email are required.'];
  } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please provide a valid email address.'];
  } elseif ($teacherDob !== '' && $normalizedTeacherDob === null) {
    $alerts[] = ['type' => 'error', 'text' => 'Date of birth must use YYYY-MM-DD format.'];
  } else {
    $duplicateTeacher = find_duplicate_teacher_by_name_and_dob($pdo, $fullTeacherName, $normalizedTeacherDob);
    if ($duplicateTeacher) {
      $alerts[] = ['type' => 'error', 'text' => 'A teacher with the same name and date of birth already exists.'];
    } else {
      try {
        $temporaryPassword = mavela_generate_temporary_password();
        $stmt = $pdo->prepare("INSERT INTO users (name, email, password_hash, must_change_password, role) VALUES (?, ?, ?, 1, 'teacher')");
        $stmt->execute([$fullTeacherName, $email, password_hash($temporaryPassword, PASSWORD_DEFAULT)]);
        $alerts[] = ['type' => 'success', 'text' => 'Teacher added. Temporary password (shown once): ' . $temporaryPassword];
      } catch (PDOException $e) {
        $message = mavela_exception_detail($e);
        if (stripos($message, 'Duplicate') !== false) {
          $alerts[] = ['type' => 'error', 'text' => 'This email already exists for another user.'];
        } else {
          $alerts[] = ['type' => 'error', 'text' => 'Could not add teacher: ' . $message];
        }
      }
    }
  }
}

if (isset($_POST['add_ancillary_staff_user'])) {
  $initialAdminView = 'adminAncillaryStaffView';
  $name = trim((string)($_POST['ancillary_new_name'] ?? ''));
  $email = trim((string)($_POST['ancillary_new_email'] ?? ''));
  $workProfile = trim((string)($_POST['ancillary_new_work_profile'] ?? ''));

  if ($name === '' || $email === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Ancillary staff name and email are required.'];
  } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please provide a valid ancillary staff email address.'];
  } else {
    try {
      $pdo->beginTransaction();

      $temporaryPassword = mavela_generate_temporary_password();
      $createStmt = $pdo->prepare("INSERT INTO users (name, email, password_hash, must_change_password, role) VALUES (?, ?, ?, 1, 'ancillary')");
      $createStmt->execute([$name, $email, password_hash($temporaryPassword, PASSWORD_DEFAULT)]);
      $newUserId = (int)$pdo->lastInsertId();

      if ($newUserId > 0) {
        $profileStmt = $pdo->prepare("INSERT INTO staff_profiles
          (user_id, work_profile, updated_by)
          VALUES (?, ?, ?)");
        $profileStmt->execute([
          $newUserId,
          $workProfile === '' ? null : $workProfile,
          $activeAdminId > 0 ? $activeAdminId : null
        ]);
      }

      $pdo->commit();
      $alerts[] = ['type' => 'success', 'text' => 'Ancillary staff user created. Temporary password (shown once): ' . $temporaryPassword];
    } catch (PDOException $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      $message = mavela_exception_detail($e);
      if (stripos($message, 'Duplicate') !== false) {
        $alerts[] = ['type' => 'error', 'text' => 'This email already exists for another user.'];
      } else {
        $alerts[] = ['type' => 'error', 'text' => 'Could not create ancillary staff user: ' . $message];
      }
    }
  }
}

if (isset($_POST['add_hop_profile'])) {
  $initialAdminView = 'adminOperationsView';
  $hopName = trim((string)($_POST['hop_name'] ?? ''));
  $hopEmail = trim((string)($_POST['hop_email'] ?? ''));
  $departmentName = trim((string)($_POST['hop_department_name'] ?? ''));

  if ($hopName === '' || $hopEmail === '' || $departmentName === '') {
    $alerts[] = ['type' => 'error', 'text' => 'HOP name, email, and department are required.'];
  } elseif (!filter_var($hopEmail, FILTER_VALIDATE_EMAIL)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please provide a valid HOP email address.'];
  } else {
    try {
      $pdo->beginTransaction();

      $temporaryPassword = mavela_generate_temporary_password();
      $createHopStmt = $pdo->prepare("INSERT INTO users (name, email, password_hash, must_change_password, role) VALUES (?, ?, ?, 1, 'hop')");
      $createHopStmt->execute([$hopName, $hopEmail, password_hash($temporaryPassword, PASSWORD_DEFAULT)]);
      $hopUserId = (int)$pdo->lastInsertId();

      $profileStmt = $pdo->prepare("INSERT INTO hop_profiles (user_id, department_name) VALUES (?, ?)");
      $profileStmt->execute([$hopUserId, $departmentName]);

      $pdo->commit();
      $alerts[] = ['type' => 'success', 'text' => 'HOP profile created. Temporary password (shown once): ' . $temporaryPassword];
    } catch (PDOException $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      $message = mavela_exception_detail($e);
      if (stripos($message, 'Duplicate') !== false) {
        $alerts[] = ['type' => 'error', 'text' => 'This email already exists for another user.'];
      } else {
        $alerts[] = ['type' => 'error', 'text' => 'Could not create HOP profile: ' . $message];
      }
    }
  }
}

if (isset($_POST['assign_teacher_to_hop'])) {
  $initialAdminView = 'adminOperationsView';
  $hopUserId = (int)($_POST['hop_user_id'] ?? 0);
  $teacherUserId = (int)($_POST['hop_teacher_id'] ?? 0);

  if ($hopUserId <= 0 || $teacherUserId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose both HOP and teacher.'];
  } else {
    $hopCheckStmt = $pdo->prepare("SELECT u.id
      FROM users u
      JOIN hop_profiles hp ON hp.user_id = u.id
      WHERE u.id = ? AND LOWER(TRIM(u.role)) = 'hop'
      LIMIT 1");
    $hopCheckStmt->execute([$hopUserId]);

    $teacherCheckStmt = $pdo->prepare("SELECT id FROM users WHERE id = ? AND LOWER(TRIM(role)) = 'teacher' LIMIT 1");
    $teacherCheckStmt->execute([$teacherUserId]);

    if (!$hopCheckStmt->fetch() || !$teacherCheckStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'Invalid HOP or teacher selection.'];
    } else {
      $assignStmt = $pdo->prepare("INSERT INTO teacher_hop_assignments (hop_user_id, teacher_id, assigned_by)
        VALUES (?, ?, ?)
        ON DUPLICATE KEY UPDATE hop_user_id = VALUES(hop_user_id), assigned_by = VALUES(assigned_by), updated_at = CURRENT_TIMESTAMP");
      $assignStmt->execute([
        $hopUserId,
        $teacherUserId,
        $activeAdminId > 0 ? $activeAdminId : null
      ]);
      $alerts[] = ['type' => 'success', 'text' => 'Teacher assigned to HOP successfully.'];
    }
  }
}

if (isset($_POST['add_class'])) {
  $initialAdminView = 'adminOperationsView';
  $className = trim((string)($_POST['class_name'] ?? ''));

  if ($className === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Class name is required.'];
  } else {
    $classExistsStmt = $pdo->prepare("SELECT COUNT(*) FROM classes WHERE LOWER(name) = LOWER(?)");
    $classExistsStmt->execute([$className]);

    if ((int)$classExistsStmt->fetchColumn() > 0) {
      $alerts[] = ['type' => 'error', 'text' => 'That class already exists.'];
    } else {
      try {
        $classInsertStmt = $pdo->prepare("INSERT INTO classes (name) VALUES (?)");
        $classInsertStmt->execute([$className]);
        $alerts[] = ['type' => 'success', 'text' => 'Class saved successfully.'];
      } catch (PDOException $e) {
        $alerts[] = ['type' => 'error', 'text' => 'Could not save class: ' . mavela_exception_detail($e)];
      }
    }
  }
}

if (isset($_POST['assign_class_teacher'])) {
  $initialAdminView = 'adminOperationsView';
  $classId = (int)($_POST['class_teacher_class_id'] ?? 0);
  $teacherId = (int)($_POST['class_teacher_teacher_id'] ?? 0);

  if ($classId <= 0 || $teacherId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose both class and teacher for class teacher allocation.'];
  } else {
    $classCheckStmt = $pdo->prepare("SELECT id FROM classes WHERE id = ? LIMIT 1");
    $classCheckStmt->execute([$classId]);

    $teacherCheckStmt = $pdo->prepare("SELECT id FROM users WHERE id = ? AND LOWER(TRIM(role)) = 'teacher' LIMIT 1");
    $teacherCheckStmt->execute([$teacherId]);

    if (!$classCheckStmt->fetch() || !$teacherCheckStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'Invalid class or teacher selected.'];
    } else {
      $assignStmt = $pdo->prepare("INSERT INTO class_teacher_assignments (class_id, teacher_id, assigned_by)
        VALUES (?, ?, ?)
        ON DUPLICATE KEY UPDATE teacher_id = VALUES(teacher_id), assigned_by = VALUES(assigned_by), updated_at = CURRENT_TIMESTAMP");
      $assignStmt->execute([
        $classId,
        $teacherId,
        $activeAdminId > 0 ? $activeAdminId : null
      ]);
      $alerts[] = ['type' => 'success', 'text' => 'Class teacher allocated successfully.'];
    }
  }
}

if (isset($_POST['add_subject'])) {
  $initialAdminView = 'adminOperationsView';
  $subjectName = trim((string)($_POST['subject_name'] ?? ''));

  if ($subjectName === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Subject name is required.'];
  } else {
    $subjectCheckStmt = $pdo->prepare("SELECT COUNT(*) FROM subjects WHERE class_id = ? AND LOWER(name) = LOWER(?)");
    $subjectInsertStmt = $pdo->prepare("INSERT INTO subjects (name, class_id) VALUES (?, ?)");

    try {
      $pdo->beginTransaction();
      $insertedCount = 0;
      $targetClassIds = $pdo->query("SELECT id FROM classes ORDER BY name")->fetchAll(PDO::FETCH_COLUMN);

      if (empty($targetClassIds)) {
        throw new PDOException('Add classes first before registering subjects.');
      }

      foreach ($targetClassIds as $targetClassId) {
        $targetClassId = (int)$targetClassId;
        if ($targetClassId <= 0) {
          continue;
        }

        $subjectCheckStmt->execute([$targetClassId, $subjectName]);
        if ((int)$subjectCheckStmt->fetchColumn() > 0) {
          continue;
        }

        $subjectInsertStmt->execute([$subjectName, $targetClassId]);
        $insertedCount++;
      }

      $pdo->commit();

      if ($insertedCount > 0) {
        $alerts[] = ['type' => 'success', 'text' => 'Subject saved and made available for ' . $insertedCount . ' classes.'];
      } else {
        $alerts[] = ['type' => 'error', 'text' => 'That subject already exists for all registered classes.'];
      }
    } catch (PDOException $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      $alerts[] = ['type' => 'error', 'text' => 'Could not save subject: ' . mavela_exception_detail($e)];
    }
  }
}

if (isset($_POST['assign'])) {
  $teacher_id = (int)($_POST['teacher_id'] ?? 0);
  $class_id = (int)($_POST['class_id'] ?? 0);
  $selected_subjects = $_POST['subjects'] ?? [];

  if ($teacher_id <= 0 || $class_id <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Please select both teacher and class.'];
  } else {
    try {
      $pdo->beginTransaction();
      $pdo->prepare("DELETE FROM teacher_subjects WHERE teacher_id = ? AND class_id = ?")
          ->execute([$teacher_id, $class_id]);

      if (!empty($selected_subjects)) {
        $stmt = $pdo->prepare("INSERT INTO teacher_subjects (teacher_id, subject_id, class_id) VALUES (?, ?, ?)");
        foreach ($selected_subjects as $subject_id) {
          $stmt->execute([$teacher_id, (int)$subject_id, $class_id]);
        }
      }

      $pdo->commit();
      $alerts[] = ['type' => 'success', 'text' => 'Assignment saved successfully.'];
    } catch (PDOException $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      $alerts[] = ['type' => 'error', 'text' => 'Assignment failed: ' . mavela_exception_detail($e)];
    }
  }
}

if (isset($_POST['add_learner_admin'])) {
  $learnerId = (int)($_POST['admission_learner_id'] ?? 0);
  $classId = (int)($_POST['admission_class_id'] ?? 0);
  $dateOfAdmission = trim($_POST['date_of_admission'] ?? '');
  $surname = trim($_POST['surname'] ?? '');
  $christianNames = trim($_POST['christian_names'] ?? '');
  $dateOfBirthInfo = trim($_POST['date_of_birth_info'] ?? '');
  $birthCertificateNumber = trim($_POST['birth_certificate_number'] ?? '');
  $religiousDenomination = trim($_POST['religious_denomination'] ?? '');
  $gender = trim($_POST['gender'] ?? 'Male');
  $guardianName = trim($_POST['guardian_name'] ?? '');
  $guardianNationalId = trim($_POST['guardian_national_id'] ?? '');
  $guardianAddress = trim($_POST['guardian_address'] ?? '');
  $guardianPhone = trim($_POST['guardian_phone'] ?? '');
  $studentPhotoPath = null;
  $existingLearner = null;
  $existingLearnerPhotoPath = null;

  if ($learnerId > 0) {
    $existingLearnerStmt = $pdo->prepare("SELECT id, student_photo_path, reg_number FROM learners WHERE id = ? LIMIT 1");
    $existingLearnerStmt->execute([$learnerId]);
    $existingLearner = $existingLearnerStmt->fetch();
    if ($existingLearner) {
      $existingLearnerPhotoPath = (string)($existingLearner['student_photo_path'] ?? '');
    }
  }

  if ($classId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a class for student admission.'];
  } elseif ($surname === '' || $christianNames === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Surname and Christian names are required.'];
  } elseif ($dateOfAdmission !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $dateOfAdmission)) {
    $alerts[] = ['type' => 'error', 'text' => 'Date of admission must be a valid date.'];
  } elseif ($dateOfBirthInfo !== '' && normalize_person_dob_for_match($dateOfBirthInfo) === null) {
    $alerts[] = ['type' => 'error', 'text' => 'Date of birth must use YYYY-MM-DD format.'];
  } elseif ($learnerId > 0 && !$existingLearner) {
    $alerts[] = ['type' => 'error', 'text' => 'Selected learner record was not found.'];
  } else {
    $studentPhotoError = (int)($_FILES['student_photo']['error'] ?? UPLOAD_ERR_NO_FILE);
    if ($studentPhotoError !== UPLOAD_ERR_NO_FILE) {
      if ($studentPhotoError !== UPLOAD_ERR_OK) {
        $alerts[] = ['type' => 'error', 'text' => 'Student photo upload failed. Please retry.'];
      } else {
        $photoOriginalName = (string)($_FILES['student_photo']['name'] ?? '');
        $photoTmpName = (string)($_FILES['student_photo']['tmp_name'] ?? '');
        $photoFileSize = (int)($_FILES['student_photo']['size'] ?? 0);
        $photoExtension = strtolower(pathinfo($photoOriginalName, PATHINFO_EXTENSION));
        $allowedPhotoExtensions = ['jpg', 'jpeg', 'png', 'webp'];

        if ($photoOriginalName === '' || $photoTmpName === '') {
          $alerts[] = ['type' => 'error', 'text' => 'Invalid student photo upload payload.'];
        } elseif ($photoFileSize <= 0 || $photoFileSize > 5 * 1024 * 1024) {
          $alerts[] = ['type' => 'error', 'text' => 'Student photo must be between 1 byte and 5 MB.'];
        } elseif (!in_array($photoExtension, $allowedPhotoExtensions, true)) {
          $alerts[] = ['type' => 'error', 'text' => 'Student photo must be JPG, PNG, or WEBP.'];
        } else {
          $photoFinfo = finfo_open(FILEINFO_MIME_TYPE);
          $detectedPhotoMime = $photoFinfo ? (string)finfo_file($photoFinfo, $photoTmpName) : '';
          if ($photoFinfo) {
            finfo_close($photoFinfo);
          }

          $allowedPhotoMimes = ['image/jpeg', 'image/png', 'image/webp'];
          if ($detectedPhotoMime !== '' && !in_array($detectedPhotoMime, $allowedPhotoMimes, true)) {
            $alerts[] = ['type' => 'error', 'text' => 'Uploaded file is not a valid image.'];
          } else {
            $photoBase = preg_replace('/[^A-Za-z0-9._-]/', '_', pathinfo($photoOriginalName, PATHINFO_FILENAME));
            $photoBase = trim((string)$photoBase, '._-');
            if ($photoBase === '') {
              $photoBase = 'student_photo';
            }

            $photoUploadDir = __DIR__ . '/Uploads/student_photos';
            if (!is_dir($photoUploadDir) && !mkdir($photoUploadDir, 0775, true)) {
              $alerts[] = ['type' => 'error', 'text' => 'Could not prepare student photo upload folder.'];
            } else {
              $photoFileName = 'admin_student_' . date('Ymd_His') . '_' . bin2hex(random_bytes(3)) . '_' . $photoBase . '.' . $photoExtension;
              $photoDestination = $photoUploadDir . '/' . $photoFileName;
              if (!move_uploaded_file($photoTmpName, $photoDestination)) {
                $alerts[] = ['type' => 'error', 'text' => 'Could not save uploaded student photo.'];
              } else {
                $studentPhotoPath = 'Uploads/student_photos/' . $photoFileName;
              }
            }
          }
        }
      }
    }

    $hasAdmissionError = false;
    foreach ($alerts as $alert) {
      if (($alert['type'] ?? '') === 'error') {
        $hasAdmissionError = true;
        break;
      }
    }

    if ($hasAdmissionError) {
      // Keep alert message already pushed above.
    } else {
      $duplicateLearner = find_duplicate_learner_by_name_and_dob($pdo, $surname, $christianNames, $dateOfBirthInfo, $learnerId);
      if ($duplicateLearner) {
        $alerts[] = ['type' => 'error', 'text' => 'A learner with the same surname, Christian names, and date of birth already exists.'];
      } else {
        try {
          $fullName = trim($surname . ' ' . $christianNames);
          $studentPhotoPathToSave = $studentPhotoPath;

      if ($learnerId > 0) {
        if ($studentPhotoPathToSave === null && $existingLearnerPhotoPath !== null && $existingLearnerPhotoPath !== '') {
          $studentPhotoPathToSave = $existingLearnerPhotoPath;
        }

        $updateLearner = $pdo->prepare("UPDATE learners SET
          class_id = ?,
          date_of_admission = ?,
          surname = ?,
          christian_names = ?,
          full_name = ?,
          date_of_birth_info = ?,
          birth_certificate_number = ?,
          religious_denomination = ?,
          gender = ?,
          guardian_name = ?,
          guardian_national_id = ?,
          guardian_address = ?,
          guardian_phone = ?,
          student_photo_path = ?
          WHERE id = ? LIMIT 1");
        $updateLearner->execute([
          $classId,
          $dateOfAdmission === '' ? null : $dateOfAdmission,
          $surname,
          $christianNames,
          $fullName,
          $dateOfBirthInfo === '' ? null : $dateOfBirthInfo,
          $birthCertificateNumber === '' ? null : $birthCertificateNumber,
          $religiousDenomination === '' ? null : $religiousDenomination,
          in_array($gender, ['Male', 'Female', 'Other'], true) ? $gender : 'Other',
          $guardianName === '' ? null : $guardianName,
          $guardianNationalId === '' ? null : $guardianNationalId,
          $guardianAddress === '' ? null : $guardianAddress,
          $guardianPhone === '' ? null : $guardianPhone,
          $studentPhotoPathToSave,
          $learnerId
        ]);

        if ($studentPhotoPath !== null && $existingLearnerPhotoPath !== null && $existingLearnerPhotoPath !== '' && $existingLearnerPhotoPath !== $studentPhotoPath) {
          @unlink(__DIR__ . '/' . $existingLearnerPhotoPath);
        }

        $alerts[] = ['type' => 'success', 'text' => 'Learner admission updated successfully.'];
      } else {
        $regNumber = generate_reg_number($pdo, $classId);

        $insertLearner = $pdo->prepare("INSERT INTO learners (
          reg_number,
          class_id,
          date_of_admission,
          surname,
          christian_names,
          full_name,
          date_of_birth_info,
          birth_certificate_number,
          religious_denomination,
          gender,
          guardian_name,
          guardian_national_id,
          guardian_address,
          guardian_phone,
          student_photo_path
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");

      $insertLearner->execute([
        $regNumber,
        $classId,
        $dateOfAdmission === '' ? null : $dateOfAdmission,
        $surname,
        $christianNames,
        $fullName,
        $dateOfBirthInfo === '' ? null : $dateOfBirthInfo,
        $birthCertificateNumber === '' ? null : $birthCertificateNumber,
        $religiousDenomination === '' ? null : $religiousDenomination,
        in_array($gender, ['Male', 'Female'], true) ? $gender : 'Male',
        $guardianName === '' ? null : $guardianName,
        $guardianNationalId === '' ? null : $guardianNationalId,
        $guardianAddress === '' ? null : $guardianAddress,
        $guardianPhone === '' ? null : $guardianPhone,
        $studentPhotoPath
      ]);

        $alerts[] = ['type' => 'success', 'text' => 'Learner admitted successfully. Reg Number: ' . $regNumber];
      }
    } catch (PDOException $e) {
      if ($studentPhotoPath !== null) {
        @unlink(__DIR__ . '/' . $studentPhotoPath);
      }
      $alerts[] = ['type' => 'error', 'text' => 'Could not admit learner: ' . mavela_exception_detail($e)];
    }
      }
    }
  }
}

if (isset($_POST['delete_admission_learner'])) {
  $learnerId = (int)($_POST['admission_learner_id'] ?? 0);
  $adminDeletePassword = (string)($_POST['admin_delete_password'] ?? '');
  if ($learnerId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid learner selected for deletion.'];
  } elseif ($adminDeletePassword === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Enter your admin password to delete this learner record.'];
  } else {
    try {
      $adminPasswordStmt = $pdo->prepare("SELECT password_hash FROM users WHERE id = ? AND role = 'admin' LIMIT 1");
      $adminPasswordStmt->execute([$activeAdminId]);
      $adminAccount = $adminPasswordStmt->fetch();

      if (!$adminAccount || !password_verify($adminDeletePassword, (string)$adminAccount['password_hash'])) {
        $alerts[] = ['type' => 'error', 'text' => 'Invalid admin password. Delete action was not completed.'];
      } else {
      $deleteLearnerStmt = $pdo->prepare("SELECT id, student_photo_path FROM learners WHERE id = ? LIMIT 1");
      $deleteLearnerStmt->execute([$learnerId]);
      $learnerToDelete = $deleteLearnerStmt->fetch();

      if (!$learnerToDelete) {
        $alerts[] = ['type' => 'error', 'text' => 'Learner record not found.'];
      } else {
        $removeLearnerStmt = $pdo->prepare("DELETE FROM learners WHERE id = ? LIMIT 1");
        $removeLearnerStmt->execute([$learnerId]);

        $photoPath = (string)($learnerToDelete['student_photo_path'] ?? '');
        if ($photoPath !== '') {
          @unlink(__DIR__ . '/' . $photoPath);
        }

        $alerts[] = ['type' => 'success', 'text' => 'Learner admission deleted successfully.'];
      }
      }
    } catch (PDOException $e) {
      $alerts[] = ['type' => 'error', 'text' => 'Could not delete learner admission: ' . mavela_exception_detail($e)];
    }
  }
}

if (isset($_POST['approve_pending_admission'])) {
  $pendingId = (int)($_POST['pending_id'] ?? 0);
  if ($pendingId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid pending admission selected.'];
  } else {
    try {
      $pdo->beginTransaction();

      $pendingStmt = $pdo->prepare("SELECT * FROM admissions_pending WHERE id = ? AND status = 'pending' LIMIT 1 FOR UPDATE");
      $pendingStmt->execute([$pendingId]);
      $pending = $pendingStmt->fetch();

      if (!$pending) {
        if ($pdo->inTransaction()) {
          $pdo->rollBack();
        }
        $alerts[] = ['type' => 'error', 'text' => 'Pending admission not found or already processed.'];
      } else {
        $regNumber = generate_reg_number($pdo, (int)$pending['class_id']);
        $insertLearner = $pdo->prepare("INSERT INTO learners (
            reg_number,
            class_id,
            date_of_admission,
            surname,
            christian_names,
            full_name,
            date_of_birth_info,
            birth_certificate_number,
            religious_denomination,
            gender,
            guardian_name,
            guardian_national_id,
            guardian_address,
            guardian_phone,
            student_photo_path
          ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
        $insertLearner->execute([
          $regNumber,
          (int)$pending['class_id'],
          $pending['date_of_admission'] ?: null,
          $pending['surname'],
          $pending['christian_names'],
          $pending['full_name'],
          $pending['date_of_birth_info'],
          $pending['birth_certificate_number'],
          $pending['religious_denomination'],
          $pending['gender'],
          $pending['guardian_name'],
          $pending['guardian_national_id'],
          $pending['guardian_address'],
          $pending['guardian_phone'],
          $pending['student_photo_path'] ?? null
        ]);

        $approveStmt = $pdo->prepare("UPDATE admissions_pending
          SET status = 'approved', reviewed_by = ?, reviewed_at = NOW(), review_comment = ?
          WHERE id = ?");
        $approveStmt->execute([$activeAdminId > 0 ? $activeAdminId : null, 'Approved by admin', $pendingId]);

        $pdo->commit();
        $alerts[] = ['type' => 'success', 'text' => 'Admission approved. Learner added to school database.'];
      }
    } catch (PDOException $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      $alerts[] = ['type' => 'error', 'text' => 'Could not approve admission: ' . mavela_exception_detail($e)];
    }
  }
}

if (isset($_POST['reject_pending_admission'])) {
  $pendingId = (int)($_POST['pending_id'] ?? 0);
  $reviewComment = trim($_POST['review_comment'] ?? '');

  if ($pendingId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid pending admission selected.'];
  } else {
    $rejectStmt = $pdo->prepare("UPDATE admissions_pending
      SET status = 'rejected', reviewed_by = ?, reviewed_at = NOW(), review_comment = ?
      WHERE id = ? AND status = 'pending'");
    $rejectStmt->execute([
      $activeAdminId > 0 ? $activeAdminId : null,
      $reviewComment === '' ? 'Rejected by admin' : $reviewComment,
      $pendingId
    ]);

    if ($rejectStmt->rowCount() > 0) {
      $alerts[] = ['type' => 'success', 'text' => 'Admission request rejected.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Pending admission not found or already processed.'];
    }
  }
}

if (isset($_POST['approve_all_pending_admissions'])) {
  $pendingAdmissionCount = (int)($pdo->query("SELECT COUNT(*) FROM admissions_pending WHERE status = 'pending'")->fetchColumn());

  if ($pendingAdmissionCount === 0) {
    $alerts[] = ['type' => 'info', 'text' => 'There are no pending admissions to approve.'];
  } else {
    $approved = approve_all_pending_admissions($pdo, $activeAdminId > 0 ? $activeAdminId : 1);

    if ($approved > 0) {
      $alerts[] = ['type' => 'success', 'text' => "Approved all $approved pending admissions. Learners were added to the school database."];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Could not approve the pending admissions. Please try again.'];
    }
  }
}

if (isset($_POST['review_teacher_document'])) {
  $documentId = (int)($_POST['teacher_document_id'] ?? 0);
  $documentStatus = trim((string)($_POST['teacher_document_status'] ?? 'reviewed'));
  $documentComment = trim((string)($_POST['teacher_document_comment'] ?? ''));

  if ($documentId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid teacher document selected.'];
  } elseif (!in_array($documentStatus, ['reviewed', 'needs_correction', 'approved'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid teacher document review status selected.'];
  } else {
    $docCheckStmt = $pdo->prepare("SELECT id FROM teacher_documents WHERE id = ? LIMIT 1");
    $docCheckStmt->execute([$documentId]);
    if (!$docCheckStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'Teacher document not found.'];
    } else {
      $reviewStmt = $pdo->prepare("UPDATE teacher_documents
        SET status = ?, admin_comment = ?, reviewed_by = ?, reviewed_at = NOW()
        WHERE id = ?");
      $reviewStmt->execute([
        $documentStatus,
        $documentComment === '' ? null : $documentComment,
        $activeAdminId > 0 ? $activeAdminId : null,
        $documentId
      ]);
      $alerts[] = ['type' => 'success', 'text' => 'Teacher document review saved and sent to teacher desk.'];
    }
  }
}

if (isset($_POST['add_parent_user'])) {
  $parentName = trim((string)($_POST['parent_name'] ?? ''));
  $parentEmail = trim((string)($_POST['parent_email'] ?? ''));
  $parentPassword = trim((string)($_POST['parent_password'] ?? ''));
  $parentLearnerId = (int)($_POST['parent_learner_id'] ?? 0);

  if ($parentName === '' || $parentEmail === '' || $parentLearnerId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Parent name, email, and learner selection are required.'];
  } elseif (!filter_var($parentEmail, FILTER_VALIDATE_EMAIL)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please provide a valid parent email address.'];
  } else {
    $passwordPlain = $parentPassword === '' ? 'parent123' : $parentPassword;

    try {
      $pdo->beginTransaction();

      $existingLearnerLinkStmt = $pdo->prepare("SELECT id FROM parent_learner_links WHERE learner_id = ? LIMIT 1");
      $existingLearnerLinkStmt->execute([$parentLearnerId]);
      if ($existingLearnerLinkStmt->fetch()) {
        $alerts[] = ['type' => 'error', 'text' => 'Selected learner already has a linked parent account.'];
      } else {
        $insertParentStmt = $pdo->prepare("INSERT INTO users (name, email, password_hash, role) VALUES (?, ?, ?, 'parent')");
        $insertParentStmt->execute([$parentName, $parentEmail, password_hash($passwordPlain, PASSWORD_DEFAULT)]);
        $parentUserId = (int)$pdo->lastInsertId();

        $linkParentStmt = $pdo->prepare("INSERT INTO parent_learner_links (parent_user_id, learner_id) VALUES (?, ?)");
        $linkParentStmt->execute([$parentUserId, $parentLearnerId]);

        $alerts[] = ['type' => 'success', 'text' => 'Parent account created and linked. Default password is parent123 unless custom password was entered.'];
      }

      if (!empty($alerts) && end($alerts)['type'] === 'error') {
        $pdo->rollBack();
      } else {
        $pdo->commit();
      }
    } catch (PDOException $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      if (stripos(mavela_exception_detail($e), 'Duplicate') !== false) {
        $alerts[] = ['type' => 'error', 'text' => 'This parent email already exists.'];
      } else {
        $alerts[] = ['type' => 'error', 'text' => 'Could not create parent account: ' . mavela_exception_detail($e)];
      }
    }
  }
}

if (isset($_POST['post_admin_announcement'])) {
  $announcementAudience = trim((string)($_POST['announcement_audience'] ?? ''));
  $announcementTargetType = trim((string)($_POST['announcement_target_type'] ?? 'all'));
  $announcementTargetClassId = (int)($_POST['announcement_target_class_id'] ?? 0);
  $announcementTargetLearnerId = (int)($_POST['announcement_target_learner_id'] ?? 0);
  $announcementTitle = trim((string)($_POST['announcement_title'] ?? ''));
  $announcementBody = trim((string)($_POST['announcement_body'] ?? ''));

  $resolvedTargetClassId = null;
  $resolvedTargetLearnerId = null;

  if (!in_array($announcementAudience, ['teacher', 'learner', 'parent'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid announcement audience.'];
  } elseif (!in_array($announcementTargetType, ['all', 'class', 'learner'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid announcement target scope.'];
  } elseif ($announcementAudience === 'teacher' && $announcementTargetType !== 'all') {
    $alerts[] = ['type' => 'error', 'text' => 'Teacher announcements currently support school-wide targeting only.'];
  } elseif ($announcementTitle === '' || $announcementBody === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Announcement title and message are required.'];
  } else {
    if (in_array($announcementAudience, ['learner', 'parent'], true)) {
      if ($announcementTargetType === 'class') {
        if ($announcementTargetClassId <= 0) {
          $alerts[] = ['type' => 'error', 'text' => 'Choose a valid class target for this announcement.'];
        } else {
          $classExistsStmt = $pdo->prepare("SELECT id FROM classes WHERE id = ? LIMIT 1");
          $classExistsStmt->execute([$announcementTargetClassId]);
          if (!$classExistsStmt->fetch()) {
            $alerts[] = ['type' => 'error', 'text' => 'Selected class target was not found.'];
          } else {
            $resolvedTargetClassId = $announcementTargetClassId;
          }
        }
      } elseif ($announcementTargetType === 'learner') {
        if ($announcementTargetLearnerId <= 0) {
          $alerts[] = ['type' => 'error', 'text' => 'Choose a valid learner target for this announcement.'];
        } else {
          $learnerTargetStmt = $pdo->prepare("SELECT id, class_id FROM learners WHERE id = ? AND COALESCE(is_frozen, 0) = 0 LIMIT 1");
          $learnerTargetStmt->execute([$announcementTargetLearnerId]);
          $learnerTargetRow = $learnerTargetStmt->fetch();
          if (!$learnerTargetRow) {
            $alerts[] = ['type' => 'error', 'text' => 'Selected learner target was not found.'];
          } else {
            $resolvedTargetLearnerId = (int)$learnerTargetRow['id'];
            $resolvedTargetClassId = (int)$learnerTargetRow['class_id'];
          }
        }
      }
    }

    if (!empty($alerts) && end($alerts)['type'] === 'error') {
      // Keep form errors and skip insert.
    } else {
    $insertAnnouncementStmt = $pdo->prepare("INSERT INTO announcements
      (sender_id, sender_role, audience, target_class_id, target_learner_id, title, body, status, published_at)
      VALUES (?, 'admin', ?, ?, ?, ?, ?, 'published', NOW())");
    $insertAnnouncementStmt->execute([
      $activeAdminId,
      $announcementAudience,
      $resolvedTargetClassId,
      $resolvedTargetLearnerId,
      $announcementTitle,
      $announcementBody
    ]);
    $alerts[] = ['type' => 'success', 'text' => 'Announcement published to ' . $announcementAudience . ' dashboard.'];

    if ($announcementAudience === 'parent') {
      if (whatsapp_notifications_enabled()) {
        $waStats = notify_parents_announcement_whatsapp(
          $pdo,
          $announcementTitle,
          $announcementBody,
          $resolvedTargetClassId,
          $resolvedTargetLearnerId
        );
        $alerts[] = ['type' => 'success', 'text' => 'WhatsApp dispatch: ' . $waStats['sent'] . ' sent, ' . $waStats['failed'] . ' failed, ' . $waStats['skipped'] . ' skipped.'];
      } else {
        $alerts[] = ['type' => 'success', 'text' => 'Announcement published. WhatsApp is not configured yet. Save the school WhatsApp credentials to enable parent alerts.'];
      }
    }
    }
  }
}

if (isset($_POST['review_teacher_parent_announcement'])) {
  $announcementId = (int)($_POST['teacher_announcement_id'] ?? 0);
  $reviewDecision = trim((string)($_POST['teacher_announcement_decision'] ?? 'approve'));
  $reviewComment = trim((string)($_POST['teacher_announcement_comment'] ?? ''));

  if ($announcementId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid teacher announcement selected for review.'];
  } elseif (!in_array($reviewDecision, ['approve', 'reject'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid announcement review decision.'];
  } else {
    $pendingAnnouncementStmt = $pdo->prepare("SELECT id, title, body, target_class_id, target_learner_id
      FROM announcements
      WHERE id = ? AND sender_role = 'teacher' AND audience = 'parent' AND status = 'pending_admin_review' LIMIT 1");
    $pendingAnnouncementStmt->execute([$announcementId]);
    $pendingAnnouncement = $pendingAnnouncementStmt->fetch();

    if (!$pendingAnnouncement) {
      $alerts[] = ['type' => 'error', 'text' => 'Teacher parent announcement not found or already reviewed.'];
    } else {
      if ($reviewDecision === 'approve') {
        $updateAnnouncementStmt = $pdo->prepare("UPDATE announcements
          SET status = 'published',
              admin_review_comment = ?,
              reviewed_by = ?,
              reviewed_at = NOW(),
              published_at = NOW()
          WHERE id = ?");
        $updateAnnouncementStmt->execute([
          $reviewComment === '' ? null : $reviewComment,
          $activeAdminId,
          $announcementId
        ]);
        $alerts[] = ['type' => 'success', 'text' => 'Teacher announcement approved and posted to parents dashboard.'];

        if (whatsapp_notifications_enabled()) {
          $waStats = notify_parents_announcement_whatsapp(
            $pdo,
            (string)$pendingAnnouncement['title'],
            (string)$pendingAnnouncement['body'],
            isset($pendingAnnouncement['target_class_id']) ? (int)$pendingAnnouncement['target_class_id'] : null,
            isset($pendingAnnouncement['target_learner_id']) ? (int)$pendingAnnouncement['target_learner_id'] : null
          );
          $alerts[] = ['type' => 'success', 'text' => 'WhatsApp dispatch: ' . $waStats['sent'] . ' sent, ' . $waStats['failed'] . ' failed, ' . $waStats['skipped'] . ' skipped.'];
        } else {
          $alerts[] = ['type' => 'success', 'text' => 'Announcement approved. WhatsApp is not configured yet. Save the school WhatsApp credentials to enable parent alerts.'];
        }
      } else {
        $updateAnnouncementStmt = $pdo->prepare("UPDATE announcements
          SET status = 'rejected',
              admin_review_comment = ?,
              reviewed_by = ?,
              reviewed_at = NOW()
          WHERE id = ?");
        $updateAnnouncementStmt->execute([
          $reviewComment === '' ? 'Rejected by admin.' : $reviewComment,
          $activeAdminId,
          $announcementId
        ]);
        $alerts[] = ['type' => 'success', 'text' => 'Teacher parent announcement rejected.'];
      }
    }
  }
}

if (isset($_POST['send_transfer_clearance'])) {
  $transferRequestId = (int)($_POST['transfer_request_id'] ?? 0);
  if ($transferRequestId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid transfer request selected.'];
  } else {
    $stmt = $pdo->prepare("UPDATE transfer_requests
      SET status = 'clearance_requested', reviewed_by_admin = ?, reviewed_at_admin = NOW(), admin_comment = ?
      WHERE id = ? AND status = 'pending_admin'");
    $stmt->execute([$activeAdminId > 0 ? $activeAdminId : null, 'Clearance requested from teacher and accountant.', $transferRequestId]);
    if ($stmt->rowCount() > 0) {
      $alerts[] = ['type' => 'success', 'text' => 'Clearance request sent to teacher and accountant.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Transfer request not found or already progressed.'];
    }
  }
}

if (isset($_POST['reject_transfer_request'])) {
  $transferRequestId = (int)($_POST['transfer_request_id'] ?? 0);
  $adminComment = trim((string)($_POST['transfer_admin_comment'] ?? ''));
  if ($transferRequestId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid transfer request selected.'];
  } else {
    $stmt = $pdo->prepare("UPDATE transfer_requests
      SET status = 'rejected', reviewed_by_admin = ?, reviewed_at_admin = NOW(), admin_comment = ?
      WHERE id = ? AND status IN ('pending_admin','clearance_requested','approved')");
    $stmt->execute([$activeAdminId > 0 ? $activeAdminId : null, $adminComment === '' ? 'Rejected by admin.' : $adminComment, $transferRequestId]);
    if ($stmt->rowCount() > 0) {
      $alerts[] = ['type' => 'success', 'text' => 'Transfer request rejected.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Transfer request could not be rejected at current stage.'];
    }
  }
}

if (isset($_POST['finalize_transfer_request'])) {
  $transferRequestId = (int)($_POST['transfer_request_id'] ?? 0);
  $adminComment = trim((string)($_POST['transfer_admin_comment'] ?? ''));

  if ($transferRequestId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid transfer request selected.'];
  } else {
    try {
      $pdo->beginTransaction();

      $requestStmt = $pdo->prepare("SELECT tr.*, l.full_name, l.reg_number, c.name AS class_name
        FROM transfer_requests tr
        JOIN learners l ON l.id = tr.learner_id
        JOIN classes c ON c.id = l.class_id
        WHERE tr.id = ?
        LIMIT 1
        FOR UPDATE");
      $requestStmt->execute([$transferRequestId]);
      $transferRow = $requestStmt->fetch();

      if (!$transferRow) {
        throw new RuntimeException('Transfer request not found.');
      }

      if ((string)$transferRow['teacher_status'] !== 'approved' || (string)$transferRow['accountant_status'] !== 'approved') {
        throw new RuntimeException('Transfer cannot be finalized before teacher and accountant approval.');
      }

      $letterHtml = build_transfer_letter_html(
        [
          'name' => $schoolName,
          'address' => $schoolAddress,
          'logo_path' => $resolvedSchoolLogoPath !== '' ? $resolvedSchoolLogoPath : $defaultSchoolLogoPath,
          'palette' => [
            'ink' => $paletteInk,
            'muted' => $paletteMuted,
            'brand_navy' => $paletteBrandNavy,
            'brand_navy_deep' => $paletteBrandNavyDeep,
            'brand_ice' => $paletteBrandIce,
            'patch_sky_soft' => $palettePatchSkySoft
          ]
        ],
        [
          'full_name' => (string)$transferRow['full_name'],
          'reg_number' => (string)$transferRow['reg_number'],
          'class_name' => (string)$transferRow['class_name']
        ],
        ['destination_school' => (string)$transferRow['destination_school'], 'reason' => (string)$transferRow['reason']]
      );

      $upsertLetter = $pdo->prepare("INSERT INTO transfer_letters (transfer_request_id, letter_html, generated_by, generated_at)
        VALUES (?, ?, ?, NOW())
        ON DUPLICATE KEY UPDATE letter_html = VALUES(letter_html), generated_by = VALUES(generated_by), generated_at = VALUES(generated_at)");
      $upsertLetter->execute([$transferRequestId, $letterHtml, $activeAdminId > 0 ? $activeAdminId : null]);

      $updateTransfer = $pdo->prepare("UPDATE transfer_requests
        SET status = 'completed', reviewed_by_admin = ?, reviewed_at_admin = NOW(), admin_comment = ?
        WHERE id = ?");
      $updateTransfer->execute([
        $activeAdminId > 0 ? $activeAdminId : null,
        $adminComment === '' ? 'Transfer finalized and letter generated.' : $adminComment,
        $transferRequestId
      ]);

      $freezeLearner = $pdo->prepare("UPDATE learners
        SET is_frozen = 1,
            frozen_reason = ?,
            frozen_at = NOW()
        WHERE id = ?");
      $freezeLearner->execute([
        'Transferred to ' . (string)$transferRow['destination_school'] . '. Record frozen for reference.',
        (int)$transferRow['learner_id']
      ]);

      $pdo->commit();
      $alerts[] = ['type' => 'success', 'text' => 'Transfer finalized. Learner has been frozen and retained in the database for future reference, and the transfer letter is available on the parent dashboard.'];
    } catch (Throwable $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      $alerts[] = ['type' => 'error', 'text' => 'Could not finalize transfer: ' . mavela_exception_detail($e)];
    }
  }
}

if (isset($_POST['review_teacher_leave_request'])) {
  $leaveRequestId = (int)($_POST['leave_request_id'] ?? 0);
  $decision = trim((string)($_POST['leave_decision'] ?? 'approve'));
  $comment = trim((string)($_POST['leave_admin_comment'] ?? ''));

  if ($leaveRequestId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid leave request selected.'];
  } elseif (!in_array($decision, ['approve', 'reject'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid leave decision selected.'];
  } else {
    $status = $decision === 'approve' ? 'approved' : 'rejected';
    $stmt = $pdo->prepare("UPDATE teacher_leave_requests
      SET status = ?, admin_comment = ?, reviewed_by = ?, reviewed_at = NOW()
      WHERE id = ? AND status = 'pending'");
    $stmt->execute([
      $status,
      $comment === '' ? ($status === 'approved' ? 'Approved by admin.' : 'Rejected by admin.') : $comment,
      $activeAdminId > 0 ? $activeAdminId : null,
      $leaveRequestId
    ]);
    if ($stmt->rowCount() > 0) {
      $alerts[] = ['type' => 'success', 'text' => 'Teacher leave request ' . $status . '.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Leave request not found or already reviewed.'];
    }
  }
}

if (isset($_POST['review_ancillary_leave_request'])) {
  $leaveRequestId = (int)($_POST['leave_request_id'] ?? 0);
  $decision = trim((string)($_POST['leave_decision'] ?? 'approve'));
  $comment = trim((string)($_POST['leave_admin_comment'] ?? ''));

  if ($leaveRequestId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid ancillary leave request selected.'];
  } elseif (!in_array($decision, ['approve', 'reject'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid leave decision selected.'];
  } else {
    $status = $decision === 'approve' ? 'approved' : 'rejected';
    $stmt = $pdo->prepare("UPDATE ancillary_leave_requests
      SET status = ?, admin_comment = ?, reviewed_by = ?, reviewed_at = NOW()
      WHERE id = ? AND status = 'pending'");
    $stmt->execute([
      $status,
      $comment === '' ? ($status === 'approved' ? 'Approved by admin.' : 'Rejected by admin.') : $comment,
      $activeAdminId > 0 ? $activeAdminId : null,
      $leaveRequestId
    ]);
    if ($stmt->rowCount() > 0) {
      $alerts[] = ['type' => 'success', 'text' => 'Ancillary leave request ' . $status . '.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Ancillary leave request not found or already reviewed.'];
    }
  }
}

if (isset($_POST['review_public_learner_application'])) {
  $applicationId = (int)($_POST['application_id'] ?? 0);
  $decision = trim((string)($_POST['application_decision'] ?? 'approve'));
  $assignedClassId = (int)($_POST['application_assigned_class_id'] ?? 0);
  $assignedTeacherId = (int)($_POST['application_assigned_teacher_id'] ?? 0);
  $adminComment = trim((string)($_POST['application_admin_comment'] ?? ''));

  if ($applicationId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid learner application selected.'];
  } elseif (!in_array($decision, ['approve', 'reject'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid learner application decision.'];
  } else {
    try {
      $pdo->beginTransaction();

      $appStmt = $pdo->prepare("SELECT * FROM learner_applications WHERE id = ? AND status = 'pending' LIMIT 1 FOR UPDATE");
      $appStmt->execute([$applicationId]);
      $appRow = $appStmt->fetch();

      if (!$appRow) {
        throw new RuntimeException('Learner application not found or already reviewed.');
      }

      if ($decision === 'reject') {
        $rejectStmt = $pdo->prepare("UPDATE learner_applications
          SET status = 'rejected', admin_comment = ?, reviewed_by = ?, reviewed_at = NOW()
          WHERE id = ?");
        $rejectStmt->execute([
          $adminComment === '' ? 'Rejected by admin.' : $adminComment,
          $activeAdminId > 0 ? $activeAdminId : null,
          $applicationId
        ]);
        $pdo->commit();
        $alerts[] = ['type' => 'success', 'text' => 'Learner application rejected.'];
      } else {
        $targetClassId = $assignedClassId > 0 ? $assignedClassId : (int)$appRow['preferred_class_id'];
        if ($targetClassId <= 0) {
          throw new RuntimeException('Assigned class is required for approval.');
        }

        $normalizedDob = normalize_person_dob_for_match((string)($appRow['date_of_birth_info'] ?? ''));
        $duplicateLearner = find_duplicate_learner_by_name_and_dob($pdo, (string)$appRow['surname'], (string)$appRow['christian_names'], $normalizedDob);
        if ($duplicateLearner) {
          throw new RuntimeException('A learner with the same surname, Christian names, and date of birth already exists.');
        }

        $regNumber = generate_reg_number($pdo, $targetClassId);
        $insertLearner = $pdo->prepare("INSERT INTO learners
          (reg_number, class_id, assigned_teacher_id, date_of_admission, surname, christian_names, full_name,
           date_of_birth_info, birth_certificate_number, religious_denomination, gender, guardian_name, guardian_national_id,
           guardian_address, guardian_phone, student_photo_path)
          VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
        $insertLearner->execute([
          $regNumber,
          $targetClassId,
          $assignedTeacherId > 0 ? $assignedTeacherId : null,
          $appRow['date_of_admission'] ?: null,
          $appRow['surname'],
          $appRow['christian_names'],
          $appRow['full_name'],
          $appRow['date_of_birth_info'],
          $appRow['birth_certificate_number'],
          $appRow['religious_denomination'],
          $appRow['gender'],
          $appRow['guardian_name'],
          $appRow['guardian_national_id'],
          $appRow['guardian_address'],
          $appRow['guardian_phone'],
          $appRow['student_photo_path']
        ]);

        $classNameStmt = $pdo->prepare("SELECT name FROM classes WHERE id = ? LIMIT 1");
        $classNameStmt->execute([$targetClassId]);
        $className = (string)($classNameStmt->fetchColumn() ?: 'Assigned Class');

        $offerText = build_offer_letter_text(
          ['name' => $schoolName],
          ['full_name' => (string)$appRow['full_name']],
          $className
        );

        $updateAppStmt = $pdo->prepare("UPDATE learner_applications
          SET status = 'approved', assigned_class_id = ?, assigned_teacher_id = ?, admin_comment = ?,
              reviewed_by = ?, reviewed_at = NOW(), offer_letter_html = ?, offer_sent_at = NOW()
          WHERE id = ?");
        $updateAppStmt->execute([
          $targetClassId,
          $assignedTeacherId > 0 ? $assignedTeacherId : null,
          $adminComment === '' ? 'Approved by admin.' : $adminComment,
          $activeAdminId > 0 ? $activeAdminId : null,
          nl2br(h($offerText)),
          $applicationId
        ]);

        $waPhone = trim((string)($appRow['parent_whatsapp_phone'] ?? ''));
        if ($waPhone !== '') {
          $normalizedPhone = normalize_whatsapp_phone($waPhone);
          if ($normalizedPhone !== null && whatsapp_notifications_enabled($pdo)) {
            send_whatsapp_message_to_phone($normalizedPhone, $offerText, $pdo);
          }
        }

        $pdo->commit();
        $alerts[] = ['type' => 'success', 'text' => 'Learner application approved, learner registered, and offer letter dispatched to parent WhatsApp where configured.'];
      }
    } catch (Throwable $e) {
      if ($pdo->inTransaction()) {
        $pdo->rollBack();
      }
      $alerts[] = ['type' => 'error', 'text' => 'Could not process learner application: ' . mavela_exception_detail($e)];
    }
  }
}

if (isset($_POST['upload_head_signature'])) {
  $initialAdminView = 'adminStudentIdsView';
  $signatureError = (int)($_FILES['head_signature_file']['error'] ?? UPLOAD_ERR_NO_FILE);

  if ($signatureError === UPLOAD_ERR_NO_FILE) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose a signature file to upload.'];
  } elseif ($signatureError !== UPLOAD_ERR_OK) {
    $alerts[] = ['type' => 'error', 'text' => 'Signature upload failed. Please retry.'];
  } else {
    $signatureTmp = (string)($_FILES['head_signature_file']['tmp_name'] ?? '');
    $signatureOriginalName = (string)($_FILES['head_signature_file']['name'] ?? '');
    $signatureSize = (int)($_FILES['head_signature_file']['size'] ?? 0);
    $signatureExt = strtolower(pathinfo($signatureOriginalName, PATHINFO_EXTENSION));
    $allowedSignatureExt = ['png', 'jpg', 'jpeg', 'webp'];

    if ($signatureTmp === '' || $signatureOriginalName === '') {
      $alerts[] = ['type' => 'error', 'text' => 'Invalid signature upload payload.'];
    } elseif ($signatureSize <= 0 || $signatureSize > 4 * 1024 * 1024) {
      $alerts[] = ['type' => 'error', 'text' => 'Signature file must be between 1 byte and 4 MB.'];
    } elseif (!in_array($signatureExt, $allowedSignatureExt, true)) {
      $alerts[] = ['type' => 'error', 'text' => 'Signature must be PNG, JPG, JPEG, or WEBP.'];
    } elseif (!function_exists('imagecreatetruecolor')) {
      $alerts[] = ['type' => 'error', 'text' => 'GD image library is required for background removal.'];
    } else {
      $finfo = finfo_open(FILEINFO_MIME_TYPE);
      $signatureMime = $finfo ? (string)finfo_file($finfo, $signatureTmp) : '';
      if ($finfo) {
        finfo_close($finfo);
      }

      $allowedSignatureMimes = ['image/png', 'image/jpeg', 'image/webp'];
      if ($signatureMime !== '' && !in_array($signatureMime, $allowedSignatureMimes, true)) {
        $alerts[] = ['type' => 'error', 'text' => 'Uploaded signature is not a valid image.'];
      } else {
        $sourceImage = null;
        if ($signatureMime === 'image/png' && function_exists('imagecreatefrompng')) {
          $sourceImage = @imagecreatefrompng($signatureTmp);
        } elseif ($signatureMime === 'image/webp' && function_exists('imagecreatefromwebp')) {
          $sourceImage = @imagecreatefromwebp($signatureTmp);
        } elseif ($signatureMime === 'image/jpeg' && function_exists('imagecreatefromjpeg')) {
          $sourceImage = @imagecreatefromjpeg($signatureTmp);
        }

        if (!$sourceImage) {
          $alerts[] = ['type' => 'error', 'text' => 'Could not read signature image.'];
        } else {
          $sourceWidth = imagesx($sourceImage);
          $sourceHeight = imagesy($sourceImage);
          if ($sourceWidth <= 0 || $sourceHeight <= 0) {
            imagedestroy($sourceImage);
            $alerts[] = ['type' => 'error', 'text' => 'Signature image dimensions are invalid.'];
          } else {
            $maxWidth = 1200;
            $maxHeight = 420;
            $scale = min(1.0, $maxWidth / $sourceWidth, $maxHeight / $sourceHeight);
            $targetWidth = max(1, (int)round($sourceWidth * $scale));
            $targetHeight = max(1, (int)round($sourceHeight * $scale));

            $resampledImage = imagecreatetruecolor($targetWidth, $targetHeight);
            imagesavealpha($resampledImage, true);
            $transparent = imagecolorallocatealpha($resampledImage, 0, 0, 0, 127);
            imagefill($resampledImage, 0, 0, $transparent);
            imagecopyresampled($resampledImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $sourceWidth, $sourceHeight);

            for ($y = 0; $y < $targetHeight; $y++) {
              for ($x = 0; $x < $targetWidth; $x++) {
                $rgba = imagecolorat($resampledImage, $x, $y);
                $a = ($rgba >> 24) & 0x7F;
                $r = ($rgba >> 16) & 0xFF;
                $g = ($rgba >> 8) & 0xFF;
                $b = $rgba & 0xFF;
                $avg = (int)round(($r + $g + $b) / 3);
                $isNearWhite = $r > 230 && $g > 230 && $b > 230;
                $isPaperTint = $avg > 220 && abs($r - $g) < 22 && abs($g - $b) < 22;

                if ($isNearWhite || $isPaperTint) {
                  $newColor = imagecolorallocatealpha($resampledImage, $r, $g, $b, 127);
                  imagesetpixel($resampledImage, $x, $y, $newColor);
                } else {
                  $newAlpha = min(127, max(0, $a));
                  $newColor = imagecolorallocatealpha($resampledImage, $r, $g, $b, $newAlpha);
                  imagesetpixel($resampledImage, $x, $y, $newColor);
                }
              }
            }

            $signatureDir = __DIR__ . '/Uploads/signatures';
            if (!is_dir($signatureDir) && !mkdir($signatureDir, 0775, true)) {
              $alerts[] = ['type' => 'error', 'text' => 'Could not prepare signature upload directory.'];
            } else {
              $signatureFileName = 'head_signature_' . date('Ymd_His') . '_' . bin2hex(random_bytes(3)) . '.png';
              $signaturePath = $signatureDir . '/' . $signatureFileName;
              $relativePath = 'Uploads/signatures/' . $signatureFileName;
              if (!imagepng($resampledImage, $signaturePath, 6)) {
                $alerts[] = ['type' => 'error', 'text' => 'Could not save processed signature image.'];
              } else {
                if (!set_app_setting($pdo, 'head_signature_path', $relativePath, $activeAdminId > 0 ? $activeAdminId : null)) {
                  @unlink($signaturePath);
                  $alerts[] = ['type' => 'error', 'text' => 'Signature image was processed but could not be linked to system settings.'];
                } else {
                  $alerts[] = ['type' => 'success', 'text' => 'Head signature uploaded, background cleaned, and applied to student IDs.'];
                }
              }
            }

            imagedestroy($resampledImage);
            imagedestroy($sourceImage);
          }
        }
      }
    }
  }
}

// ========== LEARNER PROMOTION HANDLERS ==========

if (isset($_POST['create_batch_promotions'])) {
  $created = create_batch_promotions($pdo, $activeAdminId > 0 ? $activeAdminId : 1);
  if ($created > 0) {
    $alerts[] = ['type' => 'success', 'text' => "Created $created pending learner promotions for this year."];
  } else {
    $alerts[] = ['type' => 'info', 'text' => 'No new promotions needed or all learners already have pending promotions.'];
  }
  $initialAdminView = 'adminLearnerPromotionsView';
}

if (isset($_POST['approve_promotion'])) {
  $promId = (int)($_POST['promotion_id'] ?? 0);
  if ($promId > 0) {
    if (approve_promotion($pdo, $promId, $activeAdminId > 0 ? $activeAdminId : 1)) {
      $alerts[] = ['type' => 'success', 'text' => 'Learner promotion approved successfully.'];
    } else {
      $alerts[] = ['type' => 'error', 'text' => 'Could not approve promotion.'];
    }
  }
  $initialAdminView = 'adminLearnerPromotionsView';
}

if (isset($_POST['approve_all_promotions'])) {
  $approved = approve_all_promotions($pdo, $activeAdminId > 0 ? $activeAdminId : 1);
  if ($approved > 0) {
    $alerts[] = ['type' => 'success', 'text' => "Batch approved $approved learner promotions."];
  } else {
    $alerts[] = ['type' => 'info', 'text' => 'No pending promotions to approve.'];
  }
  $initialAdminView = 'adminLearnerPromotionsView';
}

if (isset($_POST['reject_promotion'])) {
  $promId = (int)($_POST['promotion_id'] ?? 0);
  $reason = trim((string)($_POST['rejection_reason'] ?? ''));
  if ($promId > 0) {
    try {
      $stmt = $pdo->prepare("
        UPDATE learner_promotions 
        SET status = 'rejected', note = IF(note IS NOT NULL, CONCAT(note, ' | Rejected: ', ?), CONCAT('Rejected: ', ?))
        WHERE id = ? AND status = 'pending'
      ");
      if ($stmt->execute([$reason, $reason, $promId])) {
        $alerts[] = ['type' => 'success', 'text' => 'Promotion rejected successfully.'];
      } else {
        $alerts[] = ['type' => 'error', 'text' => 'Could not reject promotion.'];
      }
    } catch (Exception $e) {
      $alerts[] = ['type' => 'error', 'text' => 'Error rejecting promotion.'];
    }
  }
  $initialAdminView = 'adminLearnerPromotionsView';
}

// ========== END PROMOTION HANDLERS ==========

$teachers = $pdo->query("SELECT id, name, email FROM users WHERE LOWER(TRIM(role)) = 'teacher' ORDER BY name")->fetchAll();
$staffDirectory = $pdo->query("SELECT u.id, u.name, u.email, u.role,
    sp.sex, sp.date_of_birth, sp.ec_number, sp.national_id, sp.work_profile, sp.qualifications, sp.subject_specialization,
    updater.name AS updated_by_name, sp.updated_at
  FROM users u
  LEFT JOIN staff_profiles sp ON sp.user_id = u.id
  LEFT JOIN users updater ON updater.id = sp.updated_by
  WHERE LOWER(TRIM(u.role)) = 'teacher'
  ORDER BY u.name")->fetchAll();
$ancillaryStaffDirectory = $pdo->query("SELECT u.id, u.name, u.email, u.role,
    sp.sex, sp.date_of_birth, sp.ec_number, sp.national_id, sp.work_profile, sp.qualifications,
    updater.name AS updated_by_name, sp.updated_at
  FROM users u
  LEFT JOIN staff_profiles sp ON sp.user_id = u.id
  LEFT JOIN users updater ON updater.id = sp.updated_by
  WHERE LOWER(TRIM(u.role)) = 'ancillary'
  ORDER BY u.name")->fetchAll();
$hops = $pdo->query("SELECT u.id, u.name, u.email, hp.department_name
  FROM users u
  JOIN hop_profiles hp ON hp.user_id = u.id
  WHERE LOWER(TRIM(u.role)) = 'hop'
  ORDER BY hp.department_name, u.name")->fetchAll();
$classes = $pdo->query("SELECT id, name FROM classes ORDER BY id")->fetchAll();
$subjects = $pdo->query("SELECT id, name, class_id FROM subjects ORDER BY class_id, name")->fetchAll();
$parents = $pdo->query("SELECT id, name, email FROM users WHERE role = 'parent' ORDER BY name")->fetchAll();

$teacherHopAssignments = $pdo->query("SELECT tha.id, tha.teacher_id, tha.hop_user_id, tha.updated_at, tha.created_at,
    t.name AS teacher_name, t.email AS teacher_email,
    h.name AS hop_name, h.email AS hop_email,
    hp.department_name
  FROM teacher_hop_assignments tha
  JOIN users t ON t.id = tha.teacher_id
  JOIN users h ON h.id = tha.hop_user_id
  LEFT JOIN hop_profiles hp ON hp.user_id = tha.hop_user_id
  ORDER BY hp.department_name, h.name, t.name")->fetchAll();

$classTeacherAssignments = $pdo->query("SELECT cta.id, cta.class_id, cta.teacher_id, cta.created_at, cta.updated_at,
    c.name AS class_name,
    t.name AS teacher_name, t.email AS teacher_email
  FROM class_teacher_assignments cta
  JOIN classes c ON c.id = cta.class_id
  JOIN users t ON t.id = cta.teacher_id
  ORDER BY c.id")->fetchAll();

$parentLearnerChoices = $pdo->query("SELECT l.id, l.reg_number, l.full_name, c.name AS class_name
  FROM learners l
  JOIN classes c ON c.id = l.class_id
  WHERE COALESCE(l.is_frozen, 0) = 0
  ORDER BY c.id, l.surname, l.christian_names, l.full_name")->fetchAll();

$parentLinks = $pdo->query("SELECT pll.id, u.name AS parent_name, u.email AS parent_email,
    l.reg_number, l.full_name AS learner_name, c.name AS class_name
  FROM parent_learner_links pll
  JOIN users u ON u.id = pll.parent_user_id
  JOIN learners l ON l.id = pll.learner_id
  JOIN classes c ON c.id = l.class_id
  ORDER BY pll.created_at DESC")->fetchAll();

ensure_system_logs_table($pdo);

$pendingPasswordResetRequests = $pdo->query("SELECT prr.id, prr.email, prr.requester_note, prr.requested_at,
    u.name AS user_name, u.role AS user_role
  FROM password_reset_requests prr
  JOIN users u ON u.id = prr.user_id
  WHERE prr.status = 'pending'
  ORDER BY prr.requested_at ASC
  LIMIT 200")->fetchAll();

$systemLogRows = $pdo->query("SELECT sl.id, sl.created_at, sl.action, sl.details, sl.entity_type, sl.entity_id, sl.ip_address,
    u.name AS actor_name, u.email AS actor_email, u.role AS actor_role
  FROM system_logs sl
  LEFT JOIN users u ON u.id = sl.actor_id
  ORDER BY sl.created_at DESC
  LIMIT 250")->fetchAll();

if (empty($hops)) {
  $alerts[] = ['type' => 'error', 'text' => 'No HOP accounts with department profiles found. Create a HOP profile first, then assign teachers.'];
}

if (empty($teachers)) {
  $alerts[] = ['type' => 'error', 'text' => 'No teacher accounts found for allocation. Add teacher users first.'];
}

if (empty($classes)) {
  $alerts[] = ['type' => 'error', 'text' => 'No classes found for class-teacher allocation. Create classes first.'];
}

$recentPasswordResetRequests = $pdo->query("SELECT prr.id, prr.email, prr.status, prr.requested_at, prr.reviewed_at,
    prr.admin_note, u.name AS user_name, u.role AS user_role,
    reviewer.name AS reviewed_by_name
  FROM password_reset_requests prr
  JOIN users u ON u.id = prr.user_id
  LEFT JOIN users reviewer ON reviewer.id = prr.reviewed_by
  ORDER BY prr.requested_at DESC
  LIMIT 250")->fetchAll();

$teacherParentAnnouncementsPending = $pdo->query("SELECT a.id, a.title, a.body, a.created_at,
    a.target_class_id, a.target_learner_id,
    tc.name AS target_class_name,
    tl.full_name AS target_learner_name,
    tl.reg_number AS target_learner_reg_number,
    u.name AS teacher_name, u.email AS teacher_email
  FROM announcements a
  JOIN users u ON u.id = a.sender_id
  LEFT JOIN classes tc ON tc.id = a.target_class_id
  LEFT JOIN learners tl ON tl.id = a.target_learner_id
  WHERE a.sender_role = 'teacher' AND a.audience = 'parent' AND a.status = 'pending_admin_review'
  ORDER BY a.created_at ASC
  LIMIT 250")->fetchAll();

$adminAnnouncementRows = $pdo->query("SELECT a.id, a.title, a.body, a.audience, a.status, a.created_at, a.published_at,
    a.target_class_id, a.target_learner_id,
    tc.name AS target_class_name,
    tl.full_name AS target_learner_name,
    tl.reg_number AS target_learner_reg_number,
    u.name AS sender_name
  FROM announcements a
  JOIN users u ON u.id = a.sender_id
  LEFT JOIN classes tc ON tc.id = a.target_class_id
  LEFT JOIN learners tl ON tl.id = a.target_learner_id
  WHERE a.sender_role = 'admin'
  ORDER BY a.created_at DESC
  LIMIT 250")->fetchAll();

$assignments = $pdo->query("
  SELECT ts.id, u.name AS teacher, u.email, c.name AS class_name, s.name AS subject_name
  FROM teacher_subjects ts
  JOIN users u ON ts.teacher_id = u.id
  JOIN classes c ON ts.class_id = c.id
  JOIN subjects s ON ts.subject_id = s.id
  ORDER BY c.id, u.name, s.name
")->fetchAll();

$teacherLoads = $pdo->query("
  SELECT u.name, COUNT(ts.id) AS subject_count, COUNT(DISTINCT ts.class_id) AS class_count
  FROM users u
  LEFT JOIN teacher_subjects ts ON ts.teacher_id = u.id
  WHERE u.role = 'teacher'
  GROUP BY u.id, u.name
  ORDER BY subject_count DESC, u.name
")->fetchAll();

$classCoverage = $pdo->query("
  SELECT c.name,
         COUNT(ts.id) AS assigned_subjects,
         (SELECT COUNT(*) FROM subjects s2 WHERE s2.class_id = c.id) AS total_subjects
  FROM classes c
  LEFT JOIN teacher_subjects ts ON ts.class_id = c.id
  GROUP BY c.id, c.name
  ORDER BY c.id
")->fetchAll();

$enrolmentSummaryByGradeStmt = $pdo->query("SELECT c.id, c.name AS grade_name,
    SUM(CASE WHEN l.gender = 'Male' THEN 1 ELSE 0 END) AS boys_count,
    SUM(CASE WHEN l.gender = 'Female' THEN 1 ELSE 0 END) AS girls_count,
  SUM(CASE WHEN l.gender = 'Other' THEN 1 ELSE 0 END) AS other_count,
    COUNT(l.id) AS total_enrolment
  FROM classes c
  LEFT JOIN learners l ON l.class_id = c.id AND COALESCE(l.is_frozen, 0) = 0
  GROUP BY c.id, c.name
  ORDER BY c.id");
$enrolmentSummaryByGrade = $enrolmentSummaryByGradeStmt->fetchAll();

$overallEnrolmentTotals = [
  'boys' => 0,
  'girls' => 0,
  'other' => 0,
  'total' => 0
];
foreach ($enrolmentSummaryByGrade as $gradeRow) {
  $overallEnrolmentTotals['boys'] += (int)$gradeRow['boys_count'];
  $overallEnrolmentTotals['girls'] += (int)$gradeRow['girls_count'];
  $overallEnrolmentTotals['other'] += (int)$gradeRow['other_count'];
  $overallEnrolmentTotals['total'] += (int)$gradeRow['total_enrolment'];
}

$overallBoysPercent = $overallEnrolmentTotals['total'] > 0
  ? (int)round(($overallEnrolmentTotals['boys'] / $overallEnrolmentTotals['total']) * 100)
  : 0;
$overallGirlsPercent = $overallEnrolmentTotals['total'] > 0
  ? (int)round(($overallEnrolmentTotals['girls'] / $overallEnrolmentTotals['total']) * 100)
  : 0;
$overallOtherPercent = max(0, 100 - $overallBoysPercent - $overallGirlsPercent);

$todayAttendanceDate = date('Y-m-d');
$dailyAttendanceTotals = [
  'present' => 0,
  'absent' => 0,
  'late' => 0,
  'excused' => 0
];

$dailyAttendanceSummaryStmt = $pdo->prepare("SELECT status, COUNT(*) AS total
  FROM daily_attendance_register
  WHERE attendance_date = ?
  GROUP BY status");
$dailyAttendanceSummaryStmt->execute([$todayAttendanceDate]);
foreach ($dailyAttendanceSummaryStmt->fetchAll() as $row) {
  $statusKey = (string)$row['status'];
  if (array_key_exists($statusKey, $dailyAttendanceTotals)) {
    $dailyAttendanceTotals[$statusKey] = (int)$row['total'];
  }
}

$dailyAttendanceMarkedTotal = array_sum($dailyAttendanceTotals);

$dailyAttendanceByClassStmt = $pdo->prepare("SELECT c.name AS class_name,
  (SELECT COUNT(*) FROM learners l WHERE l.class_id = c.id AND COALESCE(l.is_frozen, 0) = 0) AS total_learners,
    (SELECT COUNT(DISTINCT dar1.learner_id) FROM daily_attendance_register dar1
      WHERE dar1.class_id = c.id AND dar1.attendance_date = ? AND dar1.status = 'present') AS present_count,
    (SELECT COUNT(DISTINCT dar2.learner_id) FROM daily_attendance_register dar2
      WHERE dar2.class_id = c.id AND dar2.attendance_date = ? AND dar2.status = 'absent') AS absent_marked_count,
    (SELECT COUNT(DISTINCT dar3.learner_id) FROM daily_attendance_register dar3
      WHERE dar3.class_id = c.id AND dar3.attendance_date = ? AND dar3.status = 'late') AS late_marked_count,
    (SELECT COUNT(DISTINCT dar4.learner_id) FROM daily_attendance_register dar4
      WHERE dar4.class_id = c.id AND dar4.attendance_date = ? AND dar4.status = 'excused') AS excused_marked_count,
    (SELECT COUNT(DISTINCT dar5.learner_id) FROM daily_attendance_register dar5
      WHERE dar5.class_id = c.id AND dar5.attendance_date = ?) AS marked_count
  FROM classes c
  ORDER BY c.id");
$dailyAttendanceByClassStmt->execute([
  $todayAttendanceDate,
  $todayAttendanceDate,
  $todayAttendanceDate,
  $todayAttendanceDate,
  $todayAttendanceDate
]);
$dailyAttendanceByClass = $dailyAttendanceByClassStmt->fetchAll();

$attendanceTrendStartDate = date('Y-m-d', strtotime('-6 days'));
$dailyAttendanceTrendStmt = $pdo->prepare("SELECT attendance_date,
    COUNT(*) AS marked_count,
    SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) AS present_count
  FROM daily_attendance_register
  WHERE attendance_date BETWEEN ? AND ?
  GROUP BY attendance_date
  ORDER BY attendance_date ASC");
$dailyAttendanceTrendStmt->execute([$attendanceTrendStartDate, $todayAttendanceDate]);

$dailyAttendanceTrendMap = [];
foreach ($dailyAttendanceTrendStmt->fetchAll() as $trendRow) {
  $dailyAttendanceTrendMap[(string)$trendRow['attendance_date']] = [
    'marked_count' => (int)$trendRow['marked_count'],
    'present_count' => (int)$trendRow['present_count']
  ];
}

$dailyAttendanceTrend = [];
for ($offset = 6; $offset >= 0; $offset--) {
  $trendDate = date('Y-m-d', strtotime('-' . $offset . ' days'));
  $trendEntry = $dailyAttendanceTrendMap[$trendDate] ?? ['marked_count' => 0, 'present_count' => 0];
  $dailyAttendanceTrend[] = [
    'attendance_date' => $trendDate,
    'marked_count' => (int)$trendEntry['marked_count'],
    'present_count' => (int)$trendEntry['present_count']
  ];
}

$dailyAttendanceTrendMax = 1;
foreach ($dailyAttendanceTrend as $trendEntry) {
  if ((int)$trendEntry['marked_count'] > $dailyAttendanceTrendMax) {
    $dailyAttendanceTrendMax = (int)$trendEntry['marked_count'];
  }
}

$pendingAdmissionsStmt = $pdo->query("SELECT ap.id, ap.created_at, ap.surname, ap.christian_names, ap.gender, ap.date_of_admission,
  ap.student_photo_path,
    ap.review_comment, c.name AS class_name, u.name AS teacher_name
  FROM admissions_pending ap
  JOIN classes c ON c.id = ap.class_id
  JOIN users u ON u.id = ap.teacher_id
  WHERE ap.status = 'pending'
  ORDER BY ap.created_at ASC");
$pendingAdmissions = $pendingAdmissionsStmt->fetchAll();

$admissionRegister = $pdo->query("SELECT l.id, l.created_at, l.reg_number, l.class_id, l.surname, l.christian_names, l.gender,
  l.birth_certificate_number,
  l.student_photo_path,
    l.date_of_admission, l.guardian_name, l.guardian_phone, c.name AS class_name
  FROM learners l
  JOIN classes c ON c.id = l.class_id
  ORDER BY l.created_at DESC
")->fetchAll();

$admissionEditLearner = null;
if ($admissionEditLearnerId > 0) {
  $admissionEditStmt = $pdo->prepare("SELECT id, reg_number, class_id, date_of_admission, surname, christian_names, date_of_birth_info,
    birth_certificate_number, religious_denomination, gender, guardian_name, guardian_national_id, guardian_address,
    guardian_phone, student_photo_path
    FROM learners
    WHERE id = ?
    LIMIT 1");
  $admissionEditStmt->execute([$admissionEditLearnerId]);
  $admissionEditLearner = $admissionEditStmt->fetch() ?: null;
}

$studentIdLearners = $pdo->query("SELECT l.id, l.reg_number, l.full_name, l.date_of_birth_info,
  l.birth_certificate_number, l.student_photo_path, l.guardian_name, l.guardian_phone, l.guardian_address, c.name AS class_name
  FROM learners l
  JOIN classes c ON c.id = l.class_id
  WHERE COALESCE(l.is_frozen, 0) = 0
  ORDER BY c.id, l.surname, l.christian_names, l.full_name")->fetchAll();

// Load pending promotions with all related data
$pendingPromotions = get_pending_promotions($pdo);

// Load promotion history
$promotionHistory = $pdo->query("
  SELECT 
    lp.id,
    lp.learner_id,
    lp.from_class_id,
    lp.to_class_id,
    lp.status,
    lp.balance_carried,
    lp.approved_at,
    l.reg_number,
    l.full_name,
    cf.name AS from_class_name,
    ct.name AS to_class_name,
    approver.name AS approved_by_name
  FROM learner_promotions lp
  JOIN learners l ON l.id = lp.learner_id
  JOIN classes cf ON cf.id = lp.from_class_id
  JOIN classes ct ON ct.id = lp.to_class_id
  LEFT JOIN users approver ON approver.id = lp.approved_by
  WHERE lp.status = 'approved' OR lp.status = 'rejected'
  ORDER BY lp.approved_at DESC
  LIMIT 100
")->fetchAll();

$teacherDocumentTypes = get_teacher_document_types();
$teacherDocumentsForAdmin = $pdo->query("SELECT td.id, td.document_type, td.title, td.description, td.original_name,
    td.file_path, td.file_size, td.status, td.admin_comment, td.reviewed_at, td.created_at,
    u.name AS teacher_name, u.email AS teacher_email, c.name AS class_name, s.name AS subject_name
  FROM teacher_documents td
  JOIN users u ON u.id = td.teacher_id
  JOIN classes c ON c.id = td.class_id
  LEFT JOIN subjects s ON s.id = td.subject_id
  ORDER BY td.created_at DESC
  LIMIT 400")->fetchAll();

$schoolAssetsRows = $pdo->query("SELECT sar.id, sar.source_inventory_id, sar.category, sar.item_name, sar.quantity,
    sar.item_condition, sar.inventory_note, sar.approved_at, sar.created_at,
    c.name AS class_name,
    t.name AS teacher_name, t.email AS teacher_email,
    approver.name AS approver_name
  FROM school_assets_register sar
  JOIN classes c ON c.id = sar.class_id
  JOIN users t ON t.id = sar.teacher_id
  LEFT JOIN users approver ON approver.id = sar.approved_by
  ORDER BY sar.approved_at DESC, sar.created_at DESC
  LIMIT 700")->fetchAll();

$transferRequests = $pdo->query("SELECT tr.id, tr.destination_school, tr.reason, tr.requested_at, tr.status,
    tr.teacher_status, tr.teacher_comment, tr.teacher_reviewed_at,
    tr.accountant_status, tr.accountant_comment, tr.accountant_reviewed_at,
    tr.admin_comment, tr.reviewed_at_admin,
    p.name AS parent_name, p.email AS parent_email,
    l.full_name AS learner_name, l.reg_number, c.name AS class_name,
    tl.id AS letter_id
  FROM transfer_requests tr
  JOIN users p ON p.id = tr.parent_user_id
  JOIN learners l ON l.id = tr.learner_id
  JOIN classes c ON c.id = l.class_id
  LEFT JOIN transfer_letters tl ON tl.transfer_request_id = tr.id
  ORDER BY tr.requested_at DESC
  LIMIT 500")->fetchAll();

$teacherLeaveRequests = $pdo->query("SELECT tlr.id, tlr.leave_type, tlr.start_date, tlr.end_date, tlr.reason,
  tlr.supporting_document_path, tlr.supporting_document_name, tlr.supporting_document_mime, tlr.supporting_document_size,
  tlr.status, tlr.admin_comment, tlr.reviewed_at, tlr.created_at,
    u.name AS teacher_name, u.email AS teacher_email
  FROM teacher_leave_requests tlr
  JOIN users u ON u.id = tlr.teacher_id
  ORDER BY FIELD(tlr.status, 'pending', 'approved', 'rejected'), tlr.created_at DESC
  LIMIT 500")->fetchAll();

$ancillaryLeaveRequests = $pdo->query("SELECT alr.id, alr.leave_type, alr.start_date, alr.end_date, alr.reason,
  alr.supporting_document_path, alr.supporting_document_name, alr.supporting_document_mime, alr.supporting_document_size,
  alr.status, alr.admin_comment, alr.reviewed_at, alr.created_at,
    u.name AS ancillary_name, u.email AS ancillary_email
  FROM ancillary_leave_requests alr
  JOIN users u ON u.id = alr.ancillary_id
  ORDER BY FIELD(alr.status, 'pending', 'approved', 'rejected'), alr.created_at DESC
  LIMIT 500")->fetchAll();

$publicLearnerApplications = $pdo->query("SELECT la.*, pc.name AS preferred_class_name,
    ac.name AS assigned_class_name, atch.name AS assigned_teacher_name
  FROM learner_applications la
  JOIN classes pc ON pc.id = la.preferred_class_id
  LEFT JOIN classes ac ON ac.id = la.assigned_class_id
  LEFT JOIN users atch ON atch.id = la.assigned_teacher_id
  ORDER BY FIELD(la.status, 'pending', 'approved', 'rejected'), la.created_at DESC
  LIMIT 500")->fetchAll();

$schoolAssetsCount = (int)$pdo->query("SELECT COUNT(*) FROM school_assets_register")->fetchColumn();

$totalTeachers = count($teachers);
$totalClasses = count($classes);
$totalSubjects = count($subjects);
$totalAssignments = count($assignments);
$classesWithNoAssignments = 0;
foreach ($classCoverage as $coverage) {
  if ((int)$coverage['assigned_subjects'] === 0) {
    $classesWithNoAssignments++;
  }
}

$schoolLogoDataUri = '';
$adminLogoPath = $resolvedSchoolLogoAbsolute;
if ($adminLogoPath !== '' && is_file($adminLogoPath)) {
  $adminLogoBytes = @file_get_contents($adminLogoPath);
  if ($adminLogoBytes !== false) {
    $schoolLogoDataUri = 'data:image/png;base64,' . base64_encode($adminLogoBytes);
  }
}

$headSignaturePath = trim(get_app_setting($pdo, 'head_signature_path', ''));
if ($headSignaturePath !== '' && !is_file(__DIR__ . '/' . ltrim($headSignaturePath, '/\\'))) {
  $headSignaturePath = '';
}

$whatsappConfig = get_whatsapp_config($pdo);
$whatsappConfigured = whatsapp_notifications_enabled($pdo);
$whatsappPhoneNumberId = (string)($whatsappConfig['phone_number_id'] ?? '');
$whatsappApiVersion = (string)($whatsappConfig['api_version'] ?? 'v22.0');
$whatsappToken = (string)($whatsappConfig['token'] ?? '');
$whatsappTokenMasked = $whatsappToken === ''
  ? 'Not saved'
  : str_repeat('*', max(0, strlen($whatsappToken) - 6)) . substr($whatsappToken, -6);
$whatsappConfigSource = (string)($whatsappConfig['source'] ?? 'environment');
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><?= h($schoolName) ?> Management</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
  <style>
    :root {
      --bg-cream: <?= h($paletteBgCream) ?>;
      --bg-sand: <?= h($paletteBgSand) ?>;
      --ink: <?= h($paletteInk) ?>;
      --muted: <?= h($paletteMuted) ?>;
      --brand-navy: <?= h($paletteBrandNavy) ?>;
      --brand-navy-deep: <?= h($paletteBrandNavyDeep) ?>;
      --brand-gold: <?= h($paletteBrandGold) ?>;
      --brand-gold-soft: <?= h($paletteBrandGoldSoft) ?>;
      --brand-ice: <?= h($paletteBrandIce) ?>;
      --patch-sky: <?= h($palettePatchSky) ?>;
      --patch-sky-soft: <?= h($palettePatchSkySoft) ?>;
      --patch-yellow: <?= h($palettePatchYellow) ?>;
      --patch-yellow-soft: <?= h($palettePatchYellowSoft) ?>;
      --panel: #ffffff;
      --line: #d9d5cb;
      --danger: #9f1239;
      --success: #166534;
      --shadow: 0 18px 45px rgba(10, 47, 99, 0.14);
      --radius-xl: 20px;
      --radius-lg: 14px;
    }

    * {
      box-sizing: border-box;
    }

    body {
      margin: 0;
      min-height: 100vh;
      font-family: 'Outfit', sans-serif;
      color: var(--ink);
      background:
        radial-gradient(circle at 5% 15%, rgba(248, 180, 0, 0.2) 0, rgba(248, 180, 0, 0) 42%),
        radial-gradient(circle at 18% 84%, rgba(124, 201, 255, 0.26) 0, rgba(124, 201, 255, 0) 44%),
        radial-gradient(circle at 85% 5%, rgba(10, 59, 121, 0.2) 0, rgba(10, 59, 121, 0) 40%),
        radial-gradient(circle at 88% 76%, rgba(255, 212, 71, 0.14) 0, rgba(255, 212, 71, 0) 42%),
        linear-gradient(170deg, var(--bg-cream) 0%, var(--bg-sand) 100%);
      padding: 22px;
    }

    .shell {
      max-width: 1240px;
      margin: 0 auto;
      display: grid;
      gap: 18px;
      animation: pageReveal 450ms ease-out;
    }

    @keyframes pageReveal {
      from {
        opacity: 0;
        transform: translateY(14px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    .header {
      border-radius: var(--radius-xl);
      padding: 22px;
      background: linear-gradient(125deg, var(--brand-navy-deep), var(--brand-navy) 55%, var(--patch-sky));
      box-shadow: var(--shadow);
      color: #f9fafb;
      position: relative;
      overflow: hidden;
    }

    .header::after {
      content: '';
      position: absolute;
      width: 230px;
      height: 230px;
      right: -68px;
      top: -108px;
      border-radius: 50%;
      background: rgba(248, 180, 0, 0.2);
      border: 1px solid rgba(248, 180, 0, 0.34);
    }

    .header::before {
      content: '';
      position: absolute;
      width: 280px;
      height: 180px;
      left: -70px;
      bottom: -90px;
      border-radius: 50%;
      background: rgba(124, 201, 255, 0.2);
      border: 1px solid rgba(124, 201, 255, 0.3);
    }

    .brand-row {
      display: flex;
      justify-content: space-between;
      gap: 12px;
      align-items: flex-start;
      flex-wrap: wrap;
      position: relative;
      z-index: 1;
    }

    .brand-left {
      display: flex;
      align-items: center;
      gap: 14px;
      flex-wrap: wrap;
    }

    .school-logo {
      width: 74px;
      height: 74px;
      object-fit: contain;
      border-radius: 14px;
      background: rgba(255, 255, 255, 0.1);
      border: 1px solid rgba(255, 255, 255, 0.26);
      padding: 8px;
    }

    .brand-title {
      margin: 0;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: clamp(1.45rem, 2.4vw, 2rem);
      font-weight: 800;
      letter-spacing: 0.01em;
    }

    .brand-subtitle {
      margin: 8px 0 0;
      color: rgba(243, 244, 246, 0.84);
      max-width: 700px;
      font-size: 0.98rem;
      line-height: 1.45;
    }

    .meta-chip {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      background: #ffd447;
      border: 1px solid #f8b400;
      color: #12386d;
      border-radius: 999px;
      font-size: 0.84rem;
      padding: 8px 14px;
      font-weight: 600;
      text-decoration: none;
      text-align: center;
    }

    .chips-grid {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 8px;
      align-items: center;
    }

    .cards {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 12px;
    }

    .metric {
      background: var(--panel);
      border: 1px solid rgba(10, 59, 121, 0.2);
      border-radius: var(--radius-lg);
      padding: 16px;
      box-shadow: 0 10px 26px rgba(10, 59, 121, 0.1);
      position: relative;
      overflow: hidden;
    }

    .metric::before {
      content: '';
      position: absolute;
      inset: 0 auto auto 0;
      width: 100%;
      height: 4px;
      background: linear-gradient(90deg, var(--patch-sky), var(--patch-yellow));
    }

    .metric::after {
      content: '';
      position: absolute;
      right: -14px;
      bottom: -18px;
      width: 56px;
      height: 56px;
      border-radius: 50%;
      background: radial-gradient(circle, rgba(255, 212, 71, 0.28), rgba(255, 212, 71, 0));
    }

    .metric .label {
      color: var(--muted);
      font-size: 0.82rem;
      text-transform: uppercase;
      letter-spacing: 0.08em;
      margin-bottom: 8px;
      font-weight: 600;
    }

    .metric .value {
      margin: 0;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.8rem;
      color: var(--ink);
      font-weight: 800;
      line-height: 1;
    }

    .metric .note {
      margin: 8px 0 0;
      font-size: 0.9rem;
      color: var(--muted);
    }

    .grid-two {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 14px;
    }

    .grouped-registers {
      grid-column: 1 / -1;
      display: grid;
      gap: 16px;
    }

    .grouped-register-grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 14px;
    }

    .grouped-register-card {
      border: 1px solid #ddd9cd;
      border-radius: 16px;
      padding: 18px;
      background: linear-gradient(180deg, #fffdfa 0%, #f8fbff 100%);
    }

    .grouped-register-card h3 {
      margin: 0;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.02rem;
      color: var(--brand-navy-deep);
    }

    .grouped-register-card .sub {
      margin-top: 8px;
    }

    .operations-step-nav {
      grid-column: 1 / -1;
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: 8px;
      background: #ffffff;
      border: 1px solid var(--line);
      border-radius: 16px;
      padding: 10px;
      box-shadow: 0 8px 24px rgba(10, 59, 121, 0.08);
    }

    .operations-step-btn {
      border: 1px solid #d8def0;
      background: #f8fbff;
      color: #12386d;
      border-radius: 10px;
      text-align: left;
      padding: 9px 10px;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 0.82rem;
      font-weight: 700;
      cursor: pointer;
      transition: background 140ms ease, color 140ms ease, transform 120ms ease;
    }

    .operations-step-btn:hover {
      transform: translateY(-1px);
    }

    .operations-step-btn.active {
      background: linear-gradient(115deg, var(--brand-navy), var(--brand-navy-deep));
      color: #fff;
      border-color: #0a3b79;
    }

    .operation-step {
      display: none !important;
    }

    .operation-step.active {
      display: block !important;
    }

    .operation-step.grouped-registers.active {
      display: grid !important;
    }

    .panel {
      background: var(--panel);
      border: 1px solid var(--line);
      border-radius: var(--radius-xl);
      box-shadow: var(--shadow);
      padding: 20px;
      position: relative;
      overflow: hidden;
    }

    .panel::before {
      content: '';
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 5px;
      background: linear-gradient(90deg, var(--patch-sky-soft), var(--patch-yellow-soft));
      pointer-events: none;
    }

    .panel h2 {
      margin: 0;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.15rem;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 10px;
    }

    .panel .sub {
      margin: 8px 0 18px;
      color: var(--muted);
      line-height: 1.4;
      font-size: 0.95rem;
    }

    .alert {
      border-radius: 12px;
      padding: 11px 14px;
      font-weight: 600;
      font-size: 0.92rem;
      margin-bottom: 10px;
      border: 1px solid;
      animation: alertSlide 320ms ease-out;
    }

    @keyframes alertSlide {
      from {
        opacity: 0;
        transform: translateY(-7px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    .alert.success {
      color: var(--success);
      background: #ecfdf3;
      border-color: #86efac;
    }

    .alert.error {
      color: var(--danger);
      background: #fff1f2;
      border-color: #fda4af;
    }

    .field {
      display: grid;
      gap: 6px;
      margin-bottom: 13px;
    }

    label {
      font-size: 0.85rem;
      font-weight: 600;
      color: var(--muted);
      text-transform: uppercase;
      letter-spacing: 0.05em;
    }

    input,
    select,
    textarea {
      border-radius: 10px;
      border: 1px solid #c5c2b8;
      background: #fff;
      padding: 10px 12px;
      font-size: 0.96rem;
      font-family: inherit;
      color: var(--ink);
      width: 100%;
      transition: border-color 180ms ease, box-shadow 180ms ease;
    }

    input:focus,
    select:focus,
    textarea:focus {
      outline: none;
      border-color: var(--brand-navy);
      box-shadow: 0 0 0 3px rgba(10, 59, 121, 0.18);
    }

    textarea {
      min-height: 88px;
      resize: vertical;
    }

    .subject-picker {
      min-height: 190px;
      max-height: 230px;
      overflow-y: auto;
      border: 1px dashed #b9b8ad;
      border-radius: 12px;
      padding: 12px;
      background: linear-gradient(180deg, #fcfbf7 0%, #f9fcff 100%);
      display: grid;
      align-content: start;
      gap: 8px;
    }

    .subject-item {
      background: #ffffff;
      border: 1px solid #ddd9cd;
      border-radius: 9px;
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 8px 10px;
      font-size: 0.93rem;
    }

    .subject-item input {
      width: auto;
      margin: 0;
    }

    .subject-hint {
      color: var(--muted);
      font-size: 0.92rem;
    }

    .button {
      border: 0;
      border-radius: 12px;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-weight: 700;
      cursor: pointer;
      padding: 11px 16px;
      transition: transform 140ms ease, filter 140ms ease;
      box-shadow: 0 0 0 2px rgba(124, 201, 255, 0.55), 0 0 0 4px rgba(255, 212, 71, 0.35);
    }

    .button:hover {
      background: #7cc9ff;
      color: #083b78;
      border-color: #5fb7e6;
      transform: translateY(-1px);
      box-shadow: 0 0 0 2px rgba(124, 201, 255, 0.85), 0 0 0 5px rgba(255, 212, 71, 0.55);
    }

    .button.primary {
      background: linear-gradient(115deg, var(--brand-navy), var(--brand-navy-deep));
      color: #fff;
      width: 100%;
    }

    .button.accent {
      background: linear-gradient(115deg, #ffc531, var(--brand-gold));
      color: #1f2937;
      width: 100%;
    }

    .button.thin {
      padding: 7px 11px;
      border-radius: 9px;
      font-size: 0.8rem;
      font-weight: 700;
      box-shadow: 0 0 0 1px rgba(124, 201, 255, 0.65), 0 0 0 3px rgba(255, 212, 71, 0.25);
    }

    .helper-inline {
      margin-top: 8px;
      color: var(--muted);
      font-size: 0.9rem;
      display: flex;
      justify-content: space-between;
      gap: 10px;
    }

    .table-wrap {
      border: 1px solid var(--line);
      border-radius: 14px;
      overflow-x: auto;
      overflow-y: hidden;
      background: linear-gradient(180deg, #fff 0%, #fffefa 100%);
    }

    .teacher-documents-table {
      min-width: 1280px;
    }

    table {
      width: 100%;
      border-collapse: collapse;
      font-size: 0.94rem;
    }

    thead th {
      text-align: left;
      background: linear-gradient(95deg, #eef3fb, #f8edd1);
      color: #173b70;
      font-size: 0.82rem;
      text-transform: uppercase;
      letter-spacing: 0.07em;
      padding: 12px;
    }

    tbody td {
      border-top: 1px solid #efebe1;
      padding: 11px 12px;
      color: #24303c;
    }

    tbody tr:nth-child(even) {
      background: linear-gradient(90deg, #fcfaf5 0%, #f4f9ff 100%);
    }

    .status-chip {
      border-radius: 999px;
      padding: 4px 10px;
      font-size: 0.8rem;
      font-weight: 700;
      display: inline-block;
      border: 1px solid transparent;
    }

    .status-ok {
      background: #eaf0fb;
      color: #1a4a8a;
      border-color: #bfd4f4;
    }

    .status-warn {
      background: #fff5dc;
      color: #8a6111;
      border-color: #f3d487;
    }

    .search-bar {
      margin-bottom: 14px;
      display: grid;
      grid-template-columns: 1fr;
      gap: 8px;
    }

    .search-bar.record-filter-bar {
      grid-template-columns: minmax(150px, 230px) minmax(0, 1fr);
      align-items: center;
    }

    input[type="search"] {
      background:
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23516f96' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") no-repeat 10px center,
        linear-gradient(90deg, #ffffff 0%, #f2f8ff 65%, #fff8df 100%);
      background-size: 15px 15px, auto;
      padding-left: 34px;
    }

    .panel-actions {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      margin-bottom: 12px;
    }

    .summary-card {
      border: 1px solid #d0d8e4;
      border-radius: 14px;
      overflow: hidden;
      background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
      box-shadow: 0 12px 28px rgba(10, 47, 99, 0.08);
    }

    .summary-head {
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 10px;
      flex-wrap: wrap;
      padding: 14px 16px;
      background: linear-gradient(120deg, #0f2f5c, #1b3f73);
      color: #f1f5f9;
    }

    .summary-head h3 {
      margin: 0;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.15rem;
      font-weight: 700;
    }

    .summary-body {
      padding: 0;
    }

    .summary-table {
      width: 100%;
      border-collapse: collapse;
    }

    .summary-table th {
      background: #c7d0dc;
      color: #1a355c;
      font-size: 0.86rem;
      text-transform: none;
      letter-spacing: 0;
      padding: 10px 12px;
      border-top: 1px solid #b8c4d3;
    }

    .summary-table td {
      padding: 11px 12px;
      border-top: 1px solid #d2d8e0;
      color: #203a5b;
      font-size: 0.95rem;
    }

    .summary-table tbody tr:nth-child(even) {
      background: #f6f8fb;
    }

    .summary-table .class-cell {
      font-weight: 700;
      color: #1a355c;
    }

    .summary-table .num-green {
      color: #1ea45b;
      font-weight: 700;
    }

    .summary-table .num-red {
      color: #cf3f35;
      font-weight: 700;
    }

    .summary-table .num-blue {
      color: #1e4a84;
      font-weight: 700;
    }

    .progress-track {
      width: 100%;
      height: 13px;
      background: #c4ccd8;
      border-radius: 999px;
      overflow: hidden;
      position: relative;
    }

    .progress-fill {
      position: absolute;
      top: 0;
      left: 0;
      height: 100%;
      background: linear-gradient(90deg, #2d84bc, #3d99d2);
      border-radius: 999px;
    }

    .split-track {
      width: 100%;
      height: 13px;
      background: #d7dde6;
      border-radius: 999px;
      overflow: hidden;
      display: flex;
    }

    .split-male {
      height: 100%;
      background: #2d84bc;
    }

    .split-female {
      height: 100%;
      background: #cf473d;
    }

    .split-other {
      height: 100%;
      background: #6b7280;
    }

    .split-label {
      margin-top: 4px;
      color: #6b7280;
      font-size: 0.82rem;
    }

    .view-toggle {
      display: none;
    }

    .view-toggle.active {
      display: block;
    }

    .foot-note {
      color: var(--muted);
      font-size: 0.86rem;
      margin-top: 10px;
      line-height: 1.35;
    }

    .desk-layout {
      display: grid;
      grid-template-columns: 250px minmax(0, 1fr);
      gap: 14px;
      align-items: start;
    }

    .desk-sidebar {
      position: sticky;
      top: 14px;
      background: #ffffff;
      border: 1px solid var(--line);
      border-radius: 16px;
      box-shadow: var(--shadow);
      padding: 12px;
    }

    .desk-sidebar h3 {
      margin: 0 0 8px;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 0.96rem;
      color: #163a6e;
    }

    .desk-nav {
      display: grid;
      gap: 6px;
      max-height: 600px;
      overflow-y: auto;
      padding-right: 6px;
    }

    /* Custom scrollbar styling */
    .desk-nav::-webkit-scrollbar {
      width: 8px;
    }

    .desk-nav::-webkit-scrollbar-track {
      background: #f8fbff;
      border-radius: 4px;
    }

    .desk-nav::-webkit-scrollbar-thumb {
      background: linear-gradient(180deg, #5c9dff, #0a3b79);
      border-radius: 4px;
      box-shadow: 0 0 0 1px rgba(10, 59, 121, 0.3);
    }

    .desk-nav::-webkit-scrollbar-thumb:hover {
      background: linear-gradient(180deg, #7bacff, #0a3b79);
      box-shadow: 0 0 4px rgba(92, 157, 255, 0.5);
    }

    /* Firefox scrollbar */
    .desk-nav {
      scrollbar-color: linear-gradient(180deg, #5c9dff, #0a3b79) #f8fbff;
      scrollbar-width: thin;
    }

    .desk-nav-btn {
      border: 1px solid #d8def0;
      background: #f8fbff;
      color: #12386d;
      border-radius: 10px;
      text-align: left;
      padding: 9px 10px;
      font-weight: 700;
      cursor: pointer;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 0.86rem;
      box-shadow: 0 0 0 1px rgba(124, 201, 255, 0.45), 0 0 0 3px rgba(255, 212, 71, 0.22);
    }

    .desk-nav-btn.active {
      background: linear-gradient(115deg, var(--brand-navy), var(--brand-navy-deep));
      color: #fff;
      border-color: #0a3b79;
    }

    .desk-nav-btn.active:hover {
      background: linear-gradient(115deg, var(--brand-navy), var(--brand-navy-deep)) !important;
      color: #fff !important;
      border-color: #0a3b79 !important;
    }

    .desk-nav-btn:hover {
      background: #dff4ff;
      color: #083b78;
      box-shadow: 0 0 0 2px rgba(124, 201, 255, 0.7), 0 0 0 5px rgba(223, 242, 255, 0.95);
    }

    .desk-nav-group-label {
      margin: 10px 4px 2px;
      font-size: 0.78rem;
      font-weight: 800;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: #54735e;
    }

    .desk-main {
      min-width: 0;
      display: grid;
      gap: 12px;
    }

    .desk-view {
      display: none !important;
      visibility: hidden;
      height: 0;
      overflow: hidden;
      animation: pageReveal 280ms ease-out;
    }

    .desk-view.active {
      display: block !important;
      visibility: visible;
      height: auto;
      overflow: visible;
    }

    .grid-two.desk-view.active {
      display: grid !important;
      visibility: visible;
      height: auto;
      overflow: visible;
    }

    .trend-bars {
      display: grid;
      gap: 8px;
      margin-top: 10px;
    }

    .trend-bar {
      background: #f8fbff;
      border: 1px solid #d8def0;
      border-radius: 10px;
      padding: 8px;
    }

    .trend-bar .head {
      display: flex;
      justify-content: space-between;
      font-size: 0.84rem;
      font-weight: 700;
      color: #163a6e;
      margin-bottom: 6px;
    }

    .trend-bar .meter {
      height: 8px;
      border-radius: 999px;
      background: #e8eef8;
      overflow: hidden;
    }

    .trend-bar .fill {
      height: 100%;
      border-radius: 999px;
      background: linear-gradient(90deg, #7cc9ff, #ffd447);
    }

    .student-id-canvas {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(85.60mm, 85.60mm));
      justify-content: center;
      gap: 14px;
      min-height: 130px;
    }

    .student-id-pair {
      display: grid;
      grid-template-columns: 1fr;
      gap: 10px;
      align-items: stretch;
    }

    .student-id-card {
      position: relative;
      overflow: hidden;
      width: 85.60mm;
      min-width: 85.60mm;
      max-width: 85.60mm;
      height: 53.98mm;
      min-height: 53.98mm;
      max-height: 53.98mm;
      border-radius: 3.2mm;
      border: 0.45mm solid var(--brand-navy-deep);
      background:
        radial-gradient(circle at 16% 16%, rgba(255, 210, 74, 0.56) 0 12%, transparent 13%),
        radial-gradient(circle at 86% 81%, rgba(255, 210, 74, 0.48) 0 10%, transparent 11%),
        linear-gradient(132deg, var(--brand-navy-deep) 0%, var(--brand-navy) 38%, var(--patch-sky) 72%, var(--patch-yellow) 100%);
      box-shadow: 0 12px 24px rgba(9, 39, 82, 0.2);
      padding: 2.4mm;
      display: grid;
      grid-template-rows: auto 1fr auto;
      gap: 1.2mm;
      color: #f6fbff;
    }

    .student-id-watermark {
      position: absolute;
      inset: 0;
      display: flex;
      align-items: center;
      justify-content: center;
      pointer-events: none;
      opacity: 0.08;
      z-index: 0;
    }

    .student-id-watermark img {
      width: 72%;
      max-height: 72%;
      object-fit: contain;
      filter: grayscale(10%) brightness(1.12);
      mix-blend-mode: multiply;
      background: transparent;
    }

    .student-id-head,
    .student-id-body,
    .student-id-foot {
      position: relative;
      z-index: 1;
    }

    .student-id-head {
      display: grid;
      grid-template-columns: auto 1fr;
      align-items: center;
      gap: 1.3mm;
      border-bottom: 0.35mm solid rgba(234, 245, 255, 0.56);
      padding-bottom: 1.1mm;
    }

    .student-id-head img {
      width: 8.8mm;
      height: 8.8mm;
      object-fit: contain;
      border-radius: 1.2mm;
      background: #fff;
      border: 0.3mm solid var(--patch-sky);
      padding: 0.6mm;
    }

    .student-id-school {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-weight: 800;
      font-size: 2.9mm;
      color: #f7fcff;
      letter-spacing: 0.2px;
      line-height: 1.1;
      text-shadow: 0 0.5px 0 rgba(5, 31, 73, 0.36);
    }

    .student-id-sub {
      font-size: 1.9mm;
      color: #e8f6ff;
      margin-top: 0.2mm;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.5px;
    }

    .student-id-body {
      display: grid;
      grid-template-columns: 14.4mm 1fr 12.5mm;
      gap: 1.2mm;
      align-items: center;
      min-height: 0;
    }

    .student-id-photo {
      width: 13.8mm;
      height: 17.8mm;
      border-radius: 1.2mm;
      border: 0.3mm solid var(--patch-sky);
      background: #f4f7fb;
      object-fit: cover;
      box-shadow: inset 0 0 0 0.25mm rgba(255, 255, 255, 0.74);
    }

    .student-id-photo-fallback {
      width: 13.8mm;
      height: 17.8mm;
      border-radius: 1.2mm;
      border: 0.3mm dashed var(--patch-sky);
      background: #f4f7fb;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #5f6f88;
      font-size: 1.8mm;
      font-weight: 700;
      text-align: center;
      padding: 1mm;
    }

    .student-id-fields {
      display: grid;
      gap: 0.45mm;
      min-width: 0;
    }

    .student-id-fields .line {
      font-size: 2.1mm;
      color: #f4fbff;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .student-id-fields .line strong {
      color: var(--brand-gold);
    }

    .student-id-qr {
      width: 12.2mm;
      height: 12.2mm;
      border-radius: 1mm;
      border: 0.3mm solid var(--patch-sky);
      background: #fff;
      padding: 0.6mm;
      object-fit: contain;
      justify-self: end;
    }

    .student-id-foot {
      border-top: 0.35mm solid rgba(233, 245, 255, 0.6);
      padding-top: 0.8mm;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 1.2mm;
    }

    .student-id-class {
      font-size: 2mm;
      color: var(--brand-gold);
      font-weight: 800;
      letter-spacing: 0.4px;
      text-transform: uppercase;
    }

    .student-id-verify {
      font-size: 1.7mm;
      color: #e7f6ff;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.6px;
    }

    .student-id-meta {
      display: grid;
      gap: 0.35mm;
      font-size: 1.68mm;
      color: #eaf6ff;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: 0.45px;
      text-align: right;
    }

    .student-id-card.back {
      background:
        radial-gradient(circle at 12% 82%, rgba(255, 214, 88, 0.5) 0 10%, transparent 11%),
        radial-gradient(circle at 82% 17%, rgba(255, 214, 88, 0.44) 0 12%, transparent 13%),
        linear-gradient(144deg, var(--brand-navy-deep) 0%, var(--brand-navy) 44%, var(--patch-sky) 76%, var(--patch-yellow) 100%);
    }

    .student-id-back-body {
      position: relative;
      z-index: 1;
      display: grid;
      gap: 0.45mm;
      font-size: 2.1mm;
      color: #ecf7ff;
      min-height: 0;
    }

    .student-id-back-title {
      font-size: 2mm;
      text-transform: uppercase;
      letter-spacing: 0.55px;
      color: var(--brand-gold);
      font-weight: 800;
      border-bottom: 0.3mm dashed rgba(233, 245, 255, 0.64);
      padding-bottom: 0.45mm;
      margin-bottom: 0.1mm;
    }

    .student-id-back-line {
      font-size: 1.85mm;
      line-height: 1.3;
      color: #f3fbff;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .student-id-signature {
      margin-top: 0.45mm;
      border-top: 0.3mm solid rgba(238, 247, 255, 0.64);
      padding-top: 0.45mm;
      font-size: 1.7mm;
      color: var(--brand-gold);
      text-transform: uppercase;
      letter-spacing: 0.5px;
      font-weight: 700;
    }

    .student-id-stamp {
      margin-top: 0.8mm;
      width: 17.8mm;
      height: 17.8mm;
      border-radius: 50%;
      border: 0.4mm dashed rgba(255, 236, 170, 0.95);
      display: flex;
      align-items: center;
      justify-content: center;
      text-align: center;
      font-size: 1.58mm;
      line-height: 1.2;
      color: #fff7d2;
      background: rgba(9, 38, 78, 0.2);
      margin-left: auto;
    }

    .student-id-card.front {
      padding: 0;
      display: grid;
      grid-template-rows: auto auto 1fr auto auto;
      gap: 0;
      background: var(--brand-ice);
      color: var(--ink);
    }

    .student-id-card.front .student-id-watermark {
      opacity: 0.11;
    }

    .student-id-front-head {
      position: relative;
      z-index: 1;
      display: grid;
      grid-template-columns: 10mm 1fr;
      gap: 1.2mm;
      align-items: center;
      background: linear-gradient(110deg, var(--brand-navy-deep) 0%, var(--brand-navy) 58%, var(--patch-sky) 100%);
      padding: 1.3mm 1.8mm 1.1mm;
      border-bottom: 0.28mm solid var(--patch-sky);
    }

    .student-id-front-logo {
      width: 8.8mm;
      height: 8.8mm;
      object-fit: contain;
      border-radius: 50%;
      border: 0.35mm solid rgba(240, 250, 255, 0.95);
      padding: 0.45mm;
      background: transparent;
      justify-self: center;
    }

    .student-id-front-school {
      font-family: 'Plus Jakarta Sans', sans-serif;
      color: #f6fbff;
      line-height: 1.1;
    }

    .student-id-front-school .name {
      font-size: 2.6mm;
      font-weight: 900;
      letter-spacing: 0.28px;
      text-transform: uppercase;
    }

    .student-id-front-school .sub {
      font-size: 1.45mm;
      opacity: 0.95;
      font-weight: 700;
      letter-spacing: 0.2px;
      margin-top: 0.1mm;
    }

    .student-id-front-title-row {
      position: relative;
      z-index: 1;
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 0.6mm 1.7mm;
      background: #f8fcff;
      border-bottom: 0.28mm solid var(--patch-sky);
      color: var(--brand-navy-deep);
      font-size: 2.2mm;
      font-weight: 900;
      letter-spacing: 0.22px;
      text-transform: uppercase;
    }

    .student-id-front-main {
      position: relative;
      z-index: 1;
      display: grid;
      grid-template-columns: 19mm 1fr 15.5mm;
      gap: 1mm;
      align-items: start;
      padding: 1.05mm 1.6mm;
      background: linear-gradient(180deg, rgba(236, 246, 255, 0.95) 0%, rgba(224, 238, 255, 0.95) 100%);
    }

    .student-id-front-photo-wrap {
      border: 0.36mm solid var(--patch-sky);
      border-radius: 2.2mm;
      background: #ffffff;
      padding: 0.6mm;
      box-shadow: 0 0 0 0.3mm rgba(255, 220, 108, 0.42);
    }

    .student-id-front-photo-wrap .student-id-photo,
    .student-id-front-photo-wrap .student-id-photo-fallback {
      width: 100%;
      height: 25mm;
      border-radius: 1.5mm;
      border: 0.24mm solid #b9c8e3;
    }

    .student-id-front-fields {
      display: grid;
      gap: 0.2mm;
      color: var(--ink);
      font-size: 1.78mm;
      line-height: 1.12;
      min-width: 0;
    }

    .student-id-front-fields .line {
      display: grid;
      grid-template-columns: 14.5mm 0.9mm 1fr;
      align-items: baseline;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .student-id-front-fields .k {
      font-weight: 900;
      color: var(--brand-navy-deep);
      text-transform: uppercase;
      letter-spacing: 0.12px;
    }

    .student-id-front-fields .v {
      color: var(--brand-navy);
      font-weight: 900;
      min-width: 0;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .student-id-front-fields .line.serial-line .v {
      font-size: 1.62mm;
      letter-spacing: 0;
    }

    .student-id-front-qr-wrap {
      display: flex;
      align-items: center;
      justify-content: center;
      align-self: stretch;
      min-height: 100%;
    }

    .student-id-front-main .student-id-qr {
      width: 13.8mm;
      height: 13.8mm;
      border: 0.3mm solid var(--brand-navy);
      border-radius: 1.15mm;
      background: #fff;
      padding: 0.45mm;
      object-fit: contain;
      box-shadow: 0 0 0 0.25mm rgba(255, 220, 108, 0.38);
    }

    .student-id-front-bottom {
      position: relative;
      z-index: 1;
      display: flex;
      justify-content: space-between;
      align-items: center;
      gap: 1.05mm;
      padding: 0.8mm 1.7mm 0.7mm;
      background: var(--brand-ice);
      border-top: 0.28mm solid var(--patch-sky);
      color: var(--brand-navy-deep);
    }

    .student-id-front-signature {
      font-size: 1.72mm;
      font-family: Georgia, 'Times New Roman', serif;
      font-style: italic;
      color: var(--brand-navy);
      font-weight: 600;
      line-height: 1.05;
      text-align: right;
      margin-left: auto;
    }

    .student-id-front-signature .label {
      display: block;
      font-size: 1.66mm;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-style: normal;
      font-weight: 800;
      color: var(--brand-navy-deep);
      letter-spacing: 0.14px;
      margin-bottom: 0.25mm;
      text-transform: none;
    }

    .student-id-front-signature .sig-img {
      display: block;
      margin-left: auto;
      max-height: 5.6mm;
      max-width: 20mm;
      object-fit: contain;
      mix-blend-mode: multiply;
      background: transparent;
    }

    .student-id-front-signature .sig-text {
      display: block;
      margin-top: 0.15mm;
    }

    .student-id-front-signature strong {
      display: block;
      margin-top: 0.35mm;
      font-size: 1.62mm;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-style: normal;
      text-transform: uppercase;
      color: var(--brand-navy-deep);
      letter-spacing: 0.16px;
      font-weight: 900;
    }

    .student-id-front-slogan {
      position: relative;
      z-index: 1;
      background: linear-gradient(90deg, var(--brand-navy-deep) 0%, var(--brand-navy) 55%, var(--brand-navy-deep) 100%);
      color: var(--brand-gold);
      font-size: 1.62mm;
      font-weight: 800;
      letter-spacing: 0.4px;
      text-transform: uppercase;
      text-align: center;
      padding: 0.65mm 1.2mm;
      border-top: 0.24mm solid rgba(255, 222, 127, 0.45);
    }

    a:hover,
    button:hover,
    input:hover,
    select:hover,
    textarea:hover,
    [role="button"]:hover,
    .button:hover,
    .btn:hover,
    .submit:hover,
    .chip:hover,
    .meta-chip:hover,
    .side-btn:hover,
    .desk-nav-btn:not(.active):hover,
    .menu button:hover,
    table tbody tr:hover td,
    table tbody tr:hover th,
    .card:hover,
    .panel:hover,
    .item:hover,
    .metric:hover,
    .stat:hover {
      background-color: #dff4ff !important;
      border-color: #7cc9ff !important;
      color: #083b78 !important;
    }

    @media (max-width: 1080px) {
      .cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
      }
    }

    @media (max-width: 880px) {
      body {
        padding: 14px;
      }

      .grid-two {
        grid-template-columns: 1fr;
      }

      .desk-layout {
        grid-template-columns: 1fr;
      }

      .desk-sidebar {
        position: static;
      }

      .student-id-canvas {
        grid-template-columns: 1fr;
      }

      .student-id-pair {
        grid-template-columns: 1fr;
      }
    }

    @media (max-width: 560px) {
      .cards {
        grid-template-columns: 1fr;
      }

      .brand-left {
        align-items: flex-start;
      }

      .school-logo {
        width: 60px;
        height: 60px;
      }

      .panel {
        padding: 15px;
      }

      thead th,
      tbody td {
        padding: 10px 8px;
      }

      input,
      select,
      textarea {
        font-size: 16px;
      }

      .button,
      .desk-nav-btn {
        min-height: 44px;
      }
    }
  </style>
</head>
<body>
  <div class="shell">
    <header class="header">
      <div class="brand-row">
        <div class="brand-left">
          <img class="school-logo" src="<?= h($resolvedSchoolLogoPath !== '' ? $resolvedSchoolLogoPath : $defaultSchoolLogoPath) ?>" alt="<?= h($schoolName) ?> logo">
          <div>
            <h1 class="brand-title"><?= h($schoolName) ?> MANAGEMENT SYSTEM</h1>
            <p class="brand-subtitle">
              <?= h($schoolAddress) ?> | <?= h($schoolContact) ?>
            </p>
          </div>
        </div>
        <div class="chips-grid">
          <span class="meta-chip" id="adminDeskProgressChip">Step 1 of 21</span>
          <a class="meta-chip" href="teacher.php?admin_view=1">Open Teacher Dashboard (View Only)</a>
          <a class="meta-chip" href="accountant.php?admin_view=1">Open Accountant Dashboard (View Only)</a>
          <a class="meta-chip" href="ancillary.php?admin_view=1">Open Ancillary Desk (View Only)</a>
          <a class="meta-chip" href="hop.php?admin_view=1">Open HOP Dashboard (View Only)</a>
          <a class="meta-chip" href="business_accounts.php">Business Accounts</a>
          <a class="meta-chip" href="logout.php">Logout</a>
          <span class="meta-chip">Academic Setup | <?= h(date('D, d M Y')) ?></span>
        </div>
      </div>
    </header>

    <?php if (!empty($alerts)): ?>
      <section>
        <?php foreach ($alerts as $alert): ?>
          <div class="alert <?= $alert['type'] === 'success' ? 'success' : 'error' ?>"><?= h($alert['text']) ?></div>
        <?php endforeach; ?>
      </section>
    <?php endif; ?>

    <div class="desk-layout">
      <aside class="desk-sidebar">
        <h3>Admin Menu</h3>
        <nav class="desk-nav" id="adminDeskNav">
          <button type="button" class="desk-nav-btn active" data-target="adminHomeView">Summary, Graphs and Trends</button>
          <button type="button" class="desk-nav-btn" data-target="adminSecurityView">Account &amp; Security</button>
          <h4 class="desk-nav-group-label">Staff</h4>
          <button type="button" class="desk-nav-btn" data-target="adminStaffDetailsView">Teaching Staff</button>
          <button type="button" class="desk-nav-btn" data-target="adminAncillaryStaffView">Ancillary Staff</button>
          <button type="button" class="desk-nav-btn" data-target="adminOperationsView">Teacher Onboarding and Allocation</button>
          <button type="button" class="desk-nav-btn" data-target="adminAdmissionView">Student Admission</button>
          <button type="button" class="desk-nav-btn" data-target="adminStudentIdsView">Student IDs</button>
          <button type="button" class="desk-nav-btn" data-target="adminApplicationsView">Public Learner Applications</button>
          <button type="button" class="desk-nav-btn" data-target="adminTransfersView">Student Transfers</button>
          <button type="button" class="desk-nav-btn" data-target="adminLearnerPromotionsView">Learner Promotions</button>
          <button type="button" class="desk-nav-btn" data-target="adminLeaveRequestsView">Staff Leave Requests</button>
          <button type="button" class="desk-nav-btn" data-target="adminWorkloadView">Teacher Workload Snapshot</button>
          <button type="button" class="desk-nav-btn" data-target="adminRegistryView">Assignment Registry</button>
          <button type="button" class="desk-nav-btn" data-target="adminCoverageView">Class Coverage Quality</button>
          <button type="button" class="desk-nav-btn" data-target="adminParentsDeskView">Parents Desk</button>
          <button type="button" class="desk-nav-btn" data-target="adminAnnouncementsView">Announcement Center</button>
          <button type="button" class="desk-nav-btn" data-target="adminSchoolSettingsView">School Settings</button>
          <button type="button" class="desk-nav-btn" data-target="adminWhatsappSettingsView">WhatsApp Settings</button>
          <button type="button" class="desk-nav-btn" data-target="adminSystemLogView">System Log</button>
          <button type="button" class="desk-nav-btn" data-target="adminTeacherDocumentsView">Documents from Teacher</button>
          <button type="button" class="desk-nav-btn" data-target="adminAssetsRegisterView">School Assets Register</button>
        </nav>
      </aside>

      <div class="desk-main">
    <section id="adminHomeView" class="desk-view active">
    <section class="cards">
      <article class="metric">
        <div class="label">Teachers</div>
        <p class="value"><?= h($totalTeachers) ?></p>
        <p class="note">Active teacher profiles available for assignment</p>
      </article>
      <article class="metric">
        <div class="label">Classes</div>
        <p class="value"><?= h($totalClasses) ?></p>
        <p class="note">Configured grades and streams</p>
      </article>
      <article class="metric">
        <div class="label">Subjects</div>
        <p class="value"><?= h($totalSubjects) ?></p>
        <p class="note">Curriculum subjects mapped to classes</p>
      </article>
      <article class="metric">
        <div class="label">Assignments</div>
        <p class="value"><?= h($totalAssignments) ?></p>
        <p class="note"><?= h($classesWithNoAssignments) ?> class(es) still need teacher allocation</p>
      </article>
      <article class="metric">
        <div class="label">School Assets Register</div>
        <p class="value"><?= h($schoolAssetsCount) ?></p>
        <p class="note">Approved assets automatically fed from verified teacher inventory</p>
      </article>
      <article class="metric">
        <div class="label">Today Attendance Marks</div>
        <p class="value"><?= h($dailyAttendanceMarkedTotal) ?></p>
        <p class="note"><?= h($todayAttendanceDate) ?> snapshot from teacher attendance registers</p>
      </article>
      <article class="metric">
        <div class="label">Total Enrolment</div>
        <p class="value"><?= h($overallEnrolmentTotals['total']) ?></p>
        <p class="note">Boys: <?= h($overallEnrolmentTotals['boys']) ?> | Girls: <?= h($overallEnrolmentTotals['girls']) ?> | Other: <?= h($overallEnrolmentTotals['other']) ?></p>
      </article>
    </section>

    <section class="panel">
      <h2>Coverage Trends <span class="meta-chip" style="color:#143a72;background:var(--brand-ice);border-color:#bfd4f4;">Summary</span></h2>
      <p class="sub">Central analytics space for quick trend checks before opening operation modules.</p>
      <?php $maxCoverageCount = max(1, ...array_map(fn($v) => (int)$v['assigned_subjects'], $classCoverage ?: [['assigned_subjects' => 0]])); ?>
      <div class="trend-bars">
        <?php foreach ($classCoverage as $coverage): ?>
          <?php $assigned = (int)$coverage['assigned_subjects']; $barWidth = (int)round(($assigned / $maxCoverageCount) * 100); ?>
          <div class="trend-bar">
            <div class="head">
              <span><?= h($coverage['name']) ?></span>
              <span><?= h($assigned) ?> assigned</span>
            </div>
            <div class="meter"><div class="fill" style="width: <?= h($barWidth) ?>%"></div></div>
          </div>
        <?php endforeach; ?>
      </div>
    </section>

    <section class="panel">
      <h2>Daily Attendance Statistics <span class="meta-chip" style="color:#143a72;background:var(--brand-ice);border-color:#bfd4f4;">Admin Dashboard</span></h2>
      <p class="sub">Live class-by-class attendance with rates for <?= h($todayAttendanceDate) ?>.</p>

      <div class="summary-card">
        <div class="summary-head">
          <h3>Student Attendance by Class — <?= h(date('d M Y', strtotime($todayAttendanceDate))) ?></h3>
          <button type="button" class="button primary" style="width:auto;" id="printDailyAttendanceSummaryBtn">Print Report</button>
        </div>
        <div class="summary-body">
          <table id="dailyAttendanceSummaryTable" class="summary-table">
            <thead>
              <tr>
                <th>Class</th>
                <th>Total</th>
                <th>Present</th>
                <th>Absent</th>
                <th>Present %</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($dailyAttendanceByClass)): ?>
                <tr><td colspan="5">No classes found for attendance statistics.</td></tr>
              <?php else: ?>
                <?php foreach ($dailyAttendanceByClass as $attendanceClassRow): ?>
                  <?php
                    $totalLearners = (int)$attendanceClassRow['total_learners'];
                    $presentCount = (int)$attendanceClassRow['present_count'];
                    $lateCount = (int)$attendanceClassRow['late_marked_count'];
                    $excusedCount = (int)$attendanceClassRow['excused_marked_count'];
                    $absentCount = max(0, $totalLearners - ($presentCount + $lateCount + $excusedCount));
                    $attendanceRate = $totalLearners > 0 ? (int)round(($presentCount / $totalLearners) * 100) : 0;
                  ?>
                  <tr>
                    <td class="class-cell"><?= h($attendanceClassRow['class_name']) ?></td>
                    <td><?= h($totalLearners) ?></td>
                    <td class="num-green"><?= h($presentCount) ?></td>
                    <td class="num-red"><?= h($absentCount) ?></td>
                    <td>
                      <div style="display:flex; align-items:center; gap:8px;">
                        <div class="progress-track"><div class="progress-fill" style="width: <?= h($attendanceRate) ?>%;"></div></div>
                        <span><?= h($attendanceRate) ?>%</span>
                      </div>
                    </td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </div>
    </section>

    <section class="panel">
      <h2>Student Enrolment Summary <span class="meta-chip" style="color:#143a72;background:var(--brand-ice);border-color:#bfd4f4;">All Grades</span></h2>
      <p class="sub">Boys, girls, and total enrolment with visual gender split for each grade.</p>

      <div class="summary-card">
        <div class="summary-head">
          <h3>Student Enrolment by Class & Gender</h3>
          <div style="display:flex; gap:8px; flex-wrap:wrap;">
            <button type="button" class="button primary" style="width:auto;" id="printEnrolmentSummaryBtn">Print Report</button>
            <button type="button" class="button accent" style="width:auto;" id="downloadEnrolmentSummaryPdfBtn">Download PDF</button>
          </div>
        </div>
        <div class="summary-body">
          <table id="enrolmentSummaryTable" class="summary-table">
            <thead>
              <tr>
                <th>Class</th>
                <th>Boys</th>
                <th>Girls</th>
                <th>Other</th>
                <th>Total</th>
                <th>Gender Split</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($enrolmentSummaryByGrade)): ?>
                <tr><td colspan="6">No grade enrolment data available.</td></tr>
              <?php else: ?>
                <?php foreach ($enrolmentSummaryByGrade as $gradeRow): ?>
                  <?php
                    $boysCount = (int)$gradeRow['boys_count'];
                    $girlsCount = (int)$gradeRow['girls_count'];
                    $otherCount = (int)$gradeRow['other_count'];
                    $totalCount = (int)$gradeRow['total_enrolment'];
                    $boysPercent = $totalCount > 0 ? (int)round(($boysCount / $totalCount) * 100) : 0;
                    $girlsPercent = $totalCount > 0 ? (int)round(($girlsCount / $totalCount) * 100) : 0;
                    $otherPercent = max(0, 100 - $boysPercent - $girlsPercent);
                  ?>
                  <tr>
                    <td class="class-cell"><?= h($gradeRow['grade_name']) ?></td>
                    <td class="num-blue"><?= h($boysCount) ?></td>
                    <td class="num-blue"><?= h($girlsCount) ?></td>
                    <td class="num-blue"><?= h($otherCount) ?></td>
                    <td class="num-blue"><?= h($totalCount) ?></td>
                    <td>
                      <?php if ($totalCount > 0): ?>
                        <div class="split-track">
                          <div class="split-male" style="width: <?= h($boysPercent) ?>%;"></div>
                          <div class="split-female" style="width: <?= h($girlsPercent) ?>%;"></div>
                          <div class="split-other" style="width: <?= h($otherPercent) ?>%;"></div>
                        </div>
                        <div class="split-label"><?= h($boysPercent) ?>% M / <?= h($girlsPercent) ?>% F / <?= h($otherPercent) ?>% O</div>
                      <?php else: ?>
                        <span class="split-label">No learners</span>
                      <?php endif; ?>
                    </td>
                  </tr>
                <?php endforeach; ?>
                <tr>
                  <td class="class-cell" style="font-weight:800;">GRAND TOTAL</td>
                  <td class="num-blue" style="font-weight:800;"><?= h($overallEnrolmentTotals['boys']) ?></td>
                  <td class="num-blue" style="font-weight:800;"><?= h($overallEnrolmentTotals['girls']) ?></td>
                  <td class="num-blue" style="font-weight:800;"><?= h($overallEnrolmentTotals['other']) ?></td>
                  <td class="num-blue" style="font-weight:800;"><?= h($overallEnrolmentTotals['total']) ?></td>
                  <td>
                    <div class="split-track">
                      <div class="split-male" style="width: <?= h($overallBoysPercent) ?>%;"></div>
                      <div class="split-female" style="width: <?= h($overallGirlsPercent) ?>%;"></div>
                      <div class="split-other" style="width: <?= h($overallOtherPercent) ?>%;"></div>
                    </div>
                    <div class="split-label"><?= h($overallBoysPercent) ?>% M / <?= h($overallGirlsPercent) ?>% F / <?= h($overallOtherPercent) ?>% O</div>
                  </td>
                </tr>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </div>
    </section>
    </section>

    <section id="adminSecurityView" class="desk-view">
    <section class="grid-two" style="margin-bottom:12px;">
      <article class="panel">
        <h2>My Admin Profile</h2>
        <p class="sub">Update your account details and login password.</p>
        <form method="POST" autocomplete="off" style="margin-bottom:10px;">
          <div class="field">
            <label for="admin_profile_name">Full Name</label>
            <input id="admin_profile_name" name="profile_name" value="<?= h((string)$adminProfile['name']) ?>" required>
          </div>
          <div class="field">
            <label for="admin_profile_email">Email Address</label>
            <input id="admin_profile_email" type="email" name="profile_email" value="<?= h((string)$adminProfile['email']) ?>" required>
          </div>
          <button class="button primary" type="submit" name="save_admin_profile">Save Profile</button>
        </form>

        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="admin_current_password">Current Password</label>
            <input id="admin_current_password" type="password" name="current_password" required>
          </div>
          <div class="field">
            <label for="admin_new_password">New Password</label>
            <input id="admin_new_password" type="password" name="new_password" minlength="10" autocomplete="new-password" required>
          </div>
          <div class="field">
            <label for="admin_confirm_password">Confirm New Password</label>
            <input id="admin_confirm_password" type="password" name="confirm_password" minlength="10" autocomplete="new-password" required>
          </div>
          <button class="button" type="submit" name="change_admin_password">Change Password</button>
        </form>
      </article>

      <article class="panel">
        <h2>Password Reset Approvals</h2>
        <p class="sub">Only approve after physical phone call or in-person verification.</p>

        <div class="table-wrap" style="margin-bottom:10px;">
          <table>
            <thead>
              <tr>
                <th>Requested</th>
                <th>User</th>
                <th>Email</th>
                <th>Role</th>
                <th>Requester Note</th>
                <th>Decision</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($pendingPasswordResetRequests)): ?>
                <tr><td colspan="6">No pending password reset requests.</td></tr>
              <?php else: ?>
                <?php foreach ($pendingPasswordResetRequests as $req): ?>
                  <tr>
                    <td><?= h((string)$req['requested_at']) ?></td>
                    <td><?= h((string)$req['user_name']) ?></td>
                    <td><?= h((string)$req['email']) ?></td>
                    <td><?= h(strtoupper((string)$req['user_role'])) ?></td>
                    <td><?= h((string)($req['requester_note'] ?? '-')) ?></td>
                    <td>
                      <form method="POST" style="display:grid; gap:6px; min-width:230px;">
                        <input type="hidden" name="reset_request_id" value="<?= h((string)$req['id']) ?>">
                        <select name="reset_decision" required>
                          <option value="approve">Approve</option>
                          <option value="reject">Reject</option>
                        </select>
                        <input name="reset_admin_note" placeholder="Verification note (optional)">
                        <button class="button primary" type="submit" name="review_password_reset_request">Submit Decision</button>
                      </form>
                    </td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>

        <h3 style="margin:8px 0 6px;">Recent Reset History</h3>
        <div class="table-wrap">
          <table>
            <thead>
              <tr>
                <th>Requested</th>
                <th>User</th>
                <th>Status</th>
                <th>Reviewed At</th>
                <th>Reviewed By</th>
                <th>Admin Note</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($recentPasswordResetRequests)): ?>
                <tr><td colspan="6">No reset history yet.</td></tr>
              <?php else: ?>
                <?php foreach ($recentPasswordResetRequests as $req): ?>
                  <tr>
                    <td><?= h((string)$req['requested_at']) ?></td>
                    <td><?= h((string)$req['user_name']) ?> (<?= h((string)$req['email']) ?>)</td>
                    <td><?= h(strtoupper((string)$req['status'])) ?></td>
                    <td><?= h((string)($req['reviewed_at'] ?? '-')) ?></td>
                    <td><?= h((string)($req['reviewed_by_name'] ?? '-')) ?></td>
                    <td><?= h((string)($req['admin_note'] ?? '-')) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>
    </section>

    <section id="adminStaffDetailsView" class="desk-view">
      <section class="grid-two">
        <article class="panel">
          <h2>Staff Details Panel</h2>
          <p class="sub">Capture and maintain teacher biodata, qualifications, and subject specialization. Accountant and other ancillary staff will be managed in a separate section.</p>

          <form method="POST" autocomplete="off" id="adminStaffDetailsForm">
            <div class="field">
              <label for="staff_user_id">Teacher</label>
              <select id="staff_user_id" name="staff_user_id" required>
                <option value="">Choose teacher</option>
                <?php foreach ($staffDirectory as $staffRow): ?>
                  <option
                    value="<?= h((string)$staffRow['id']) ?>"
                    data-full-name="<?= h((string)$staffRow['name']) ?>"
                    data-email="<?= h((string)$staffRow['email']) ?>"
                    data-sex="<?= h((string)($staffRow['sex'] ?? '')) ?>"
                    data-dob="<?= h((string)($staffRow['date_of_birth'] ?? '')) ?>"
                    data-ec="<?= h((string)($staffRow['ec_number'] ?? '')) ?>"
                    data-national-id="<?= h((string)($staffRow['national_id'] ?? '')) ?>"
                    data-qualifications="<?= h((string)($staffRow['qualifications'] ?? '')) ?>"
                    data-subject-specialization="<?= h((string)($staffRow['subject_specialization'] ?? '')) ?>"
                  >
                    <?= h((string)$staffRow['name']) ?>
                  </option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="field">
              <label for="staff_full_name">Full Name</label>
              <input id="staff_full_name" name="staff_full_name" required>
            </div>
            <div class="field">
              <label for="staff_email">Email Address</label>
              <input id="staff_email" type="email" name="staff_email" required>
            </div>
            <div class="field">
              <label for="staff_sex">Sex</label>
              <select id="staff_sex" name="staff_sex">
                <option value="">Choose sex</option>
                <option value="Male">Male</option>
                <option value="Female">Female</option>
                <option value="Other">Other</option>
              </select>
            </div>
            <div class="field">
              <label for="staff_dob">Date of Birth</label>
              <input id="staff_dob" type="date" name="staff_dob">
            </div>
            <div class="field">
              <label for="staff_ec_number">EC#</label>
              <input id="staff_ec_number" name="staff_ec_number">
            </div>
            <div class="field">
              <label for="staff_national_id">ID#</label>
              <input id="staff_national_id" name="staff_national_id">
            </div>
            <div class="field">
              <label for="staff_qualifications">Qualifications</label>
              <textarea id="staff_qualifications" name="staff_qualifications" rows="4"></textarea>
            </div>
            <div class="field">
              <label for="staff_subject_specialization">Subject Specialization</label>
              <input id="staff_subject_specialization" name="staff_subject_specialization" placeholder="e.g. Mathematics, Science, English Literature">
            </div>
            <button class="button primary" type="submit" name="save_staff_details">Save Staff Details</button>
          </form>
        </article>

        <article class="panel">
          <div style="display:flex; justify-content:space-between; gap:10px; align-items:center; flex-wrap:wrap;">
            <div>
              <h2 style="margin:0;">Printable Teacher Register</h2>
              <p class="sub" style="margin:6px 0 0;">Prepared to fit A3 landscape for complete teacher biodata reporting.</p>
            </div>
            <button type="button" class="button accent" style="width:auto;" id="printStaffDetailsReportBtn">Print A3 Report</button>
          </div>
          <div class="table-wrap" style="margin-top:10px;">
            <table id="adminStaffDetailsTable">
              <thead>
                <tr>
                  <th>Full Name</th>
                  <th>Role</th>
                  <th>Sex</th>
                  <th>DOB</th>
                  <th>EC#</th>
                  <th>ID#</th>
                  <th>Qualifications</th>
                  <th>Subject Specialization</th>
                  <th>Email</th>
                  <th>Last Updated</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($staffDirectory)): ?>
                  <tr><td colspan="10">No staff records found.</td></tr>
                <?php else: ?>
                  <?php foreach ($staffDirectory as $staffRow): ?>
                    <tr>
                      <td><?= h((string)$staffRow['name']) ?></td>
                      <td><?= h(strtoupper((string)$staffRow['role'])) ?></td>
                      <td><?= h((string)($staffRow['sex'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['date_of_birth'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['ec_number'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['national_id'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['qualifications'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['subject_specialization'] ?? '-')) ?></td>
                      <td><?= h((string)$staffRow['email']) ?></td>
                      <td><?= h(trim((string)($staffRow['updated_at'] ?? '')) !== '' ? (string)$staffRow['updated_at'] : '-') ?></td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </article>
      </section>
    </section>

    <section id="adminAncillaryStaffView" class="desk-view">
      <section class="grid-two">
        <article class="panel">
          <h2>Ancillary Staff Section</h2>
          <p class="sub">Capture and maintain ancillary staff biodata and work profile.</p>

          <form method="POST" autocomplete="off" style="margin-bottom:14px; border:1px solid #d7e2ef; border-radius:12px; padding:12px; background:#f8fbff;">
            <h3 style="margin:0 0 8px; color:#143a72;">Create Ancillary Staff Login</h3>
            <p class="sub" style="margin:0 0 10px;">A unique temporary password is shown once after creation. The staff member is prompted to replace it on first login.</p>
            <div class="field">
              <label for="ancillary_new_name">Full Name</label>
              <input id="ancillary_new_name" name="ancillary_new_name" required>
            </div>
            <div class="field">
              <label for="ancillary_new_email">Email Address</label>
              <input id="ancillary_new_email" name="ancillary_new_email" type="email" required>
            </div>
            <div class="field">
              <label for="ancillary_new_work_profile">Work Profile</label>
              <input id="ancillary_new_work_profile" name="ancillary_new_work_profile" placeholder="e.g. Security, Grounds, Transport, Office Support">
            </div>
            <button class="button primary" type="submit" name="add_ancillary_staff_user">Create Ancillary User</button>
          </form>

          <form method="POST" autocomplete="off" id="adminAncillaryStaffForm">
            <div class="field">
              <label for="ancillary_user_id">Ancillary Staff</label>
              <select id="ancillary_user_id" name="ancillary_user_id" required>
                <option value="">Choose ancillary staff</option>
                <?php foreach ($ancillaryStaffDirectory as $staffRow): ?>
                  <option
                    value="<?= h((string)$staffRow['id']) ?>"
                    data-full-name="<?= h((string)$staffRow['name']) ?>"
                    data-email="<?= h((string)$staffRow['email']) ?>"
                    data-sex="<?= h((string)($staffRow['sex'] ?? '')) ?>"
                    data-dob="<?= h((string)($staffRow['date_of_birth'] ?? '')) ?>"
                    data-ec="<?= h((string)($staffRow['ec_number'] ?? '')) ?>"
                    data-national-id="<?= h((string)($staffRow['national_id'] ?? '')) ?>"
                    data-work-profile="<?= h((string)($staffRow['work_profile'] ?? '')) ?>"
                    data-qualifications="<?= h((string)($staffRow['qualifications'] ?? '')) ?>"
                  >
                    <?= h((string)$staffRow['name']) ?>
                  </option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="field">
              <label for="ancillary_full_name">Full Name</label>
              <input id="ancillary_full_name" name="ancillary_full_name" required>
            </div>
            <div class="field">
              <label for="ancillary_email">Email Address</label>
              <input id="ancillary_email" type="email" name="ancillary_email" required>
            </div>
            <div class="field">
              <label for="ancillary_sex">Sex</label>
              <select id="ancillary_sex" name="ancillary_sex">
                <option value="">Choose sex</option>
                <option value="Male">Male</option>
                <option value="Female">Female</option>
                <option value="Other">Other</option>
              </select>
            </div>
            <div class="field">
              <label for="ancillary_dob">Date of Birth</label>
              <input id="ancillary_dob" type="date" name="ancillary_dob">
            </div>
            <div class="field">
              <label for="ancillary_ec_number">EC#</label>
              <input id="ancillary_ec_number" name="ancillary_ec_number">
            </div>
            <div class="field">
              <label for="ancillary_national_id">ID#</label>
              <input id="ancillary_national_id" name="ancillary_national_id">
            </div>
            <div class="field">
              <label for="ancillary_work_profile">Work Profile</label>
              <input id="ancillary_work_profile" name="ancillary_work_profile" placeholder="e.g. Accounts, Cash Office, School Bursary">
            </div>
            <div class="field">
              <label for="ancillary_qualifications">Qualifications</label>
              <textarea id="ancillary_qualifications" name="ancillary_qualifications" rows="4"></textarea>
            </div>
            <button class="button primary" type="submit" name="save_ancillary_staff_details">Save Ancillary Staff Details</button>
          </form>
        </article>

        <article class="panel">
          <div style="display:flex; justify-content:space-between; gap:10px; align-items:center; flex-wrap:wrap;">
            <div>
              <h2 style="margin:0;">Printable Ancillary Staff Register</h2>
              <p class="sub" style="margin:6px 0 0;">Prepared to fit A3 landscape for ancillary staff biodata and work profile reporting.</p>
            </div>
            <button type="button" class="button accent" style="width:auto;" id="printAncillaryStaffReportBtn">Print A3 Report</button>
          </div>
          <div class="table-wrap" style="margin-top:10px;">
            <table id="adminAncillaryStaffTable">
              <thead>
                <tr>
                  <th>Full Name</th>
                  <th>Role</th>
                  <th>Sex</th>
                  <th>DOB</th>
                  <th>EC#</th>
                  <th>ID#</th>
                  <th>Work Profile</th>
                  <th>Qualifications</th>
                  <th>Email</th>
                  <th>Last Updated</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($ancillaryStaffDirectory)): ?>
                  <tr><td colspan="10">No ancillary staff records found.</td></tr>
                <?php else: ?>
                  <?php foreach ($ancillaryStaffDirectory as $staffRow): ?>
                    <tr>
                      <td><?= h((string)$staffRow['name']) ?></td>
                      <td><?= h(strtoupper((string)$staffRow['role'])) ?></td>
                      <td><?= h((string)($staffRow['sex'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['date_of_birth'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['ec_number'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['national_id'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['work_profile'] ?? '-')) ?></td>
                      <td><?= h((string)($staffRow['qualifications'] ?? '-')) ?></td>
                      <td><?= h((string)$staffRow['email']) ?></td>
                      <td><?= h(trim((string)($staffRow['updated_at'] ?? '')) !== '' ? (string)$staffRow['updated_at'] : '-') ?></td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </article>
      </section>
    </section>

    <section id="adminParentsDeskView" class="grid-two desk-view">
      <article class="panel">
        <h2>
          Parent Onboarding
          <span class="status-chip status-ok">Access Setup</span>
        </h2>
        <p class="sub">Create parent accounts and link each account to one learner for view-only access to learner desk data.</p>

        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="parent-name">Parent Full Name</label>
            <input id="parent-name" name="parent_name" placeholder="e.g. Thandiwe Dube" required>
          </div>

          <div class="field">
            <label for="parent-email">Parent Email</label>
            <input id="parent-email" name="parent_email" type="email" placeholder="parent@mavela.gov.zw" required>
          </div>

          <div class="field">
            <label for="parent-password">Initial Password (optional)</label>
            <input id="parent-password" name="parent_password" placeholder="Leave blank to use parent123">
          </div>

          <div class="field">
            <label for="parent-learner">Link to Learner</label>
            <select id="parent-learner" name="parent_learner_id" required>
              <option value="">Choose learner</option>
              <?php foreach ($parentLearnerChoices as $learnerChoice): ?>
                <option value="<?= h($learnerChoice['id']) ?>">
                  <?= h($learnerChoice['reg_number']) ?> - <?= h($learnerChoice['full_name']) ?> (<?= h($learnerChoice['class_name']) ?>)
                </option>
              <?php endforeach; ?>
            </select>
          </div>

          <button class="button primary" type="submit" name="add_parent_user">Create Parent Account</button>
          <p class="foot-note">Each learner can be linked to one parent account in this version.</p>
        </form>
      </article>

      <article class="panel">
        <h2>
          Linked Parent Accounts
          <span class="status-chip status-warn">View</span>
        </h2>
        <p class="sub">Monitor active parent-to-learner mappings used by the Parents Desk.</p>

        <div class="search-bar record-filter-bar" data-table-id="parentLinksTable">
          <select class="record-filter-field" aria-label="Parent links filter field">
            <option value="all">All Columns</option>
            <option value="0">Parent</option>
            <option value="1">Email</option>
            <option value="2">Learner</option>
            <option value="3">Reg Number</option>
            <option value="4">Class</option>
          </select>
          <input class="record-filter-input" type="search" placeholder="Search parent links...">
        </div>

        <div class="table-wrap">
          <table id="parentLinksTable">
            <thead>
              <tr>
                <th>Parent</th>
                <th>Email</th>
                <th>Learner</th>
                <th>Reg Number</th>
                <th>Class</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($parentLinks)): ?>
                <tr><td colspan="5">No linked parent accounts yet.</td></tr>
              <?php else: ?>
                <?php foreach ($parentLinks as $link): ?>
                  <tr>
                    <td><?= h($link['parent_name']) ?></td>
                    <td><?= h($link['parent_email']) ?></td>
                    <td><?= h($link['learner_name']) ?></td>
                    <td><?= h($link['reg_number']) ?></td>
                    <td><?= h($link['class_name']) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>

    <section id="adminAnnouncementsView" class="grid-two desk-view">
      <article class="panel">
        <h2>
          Post Announcement
          <span class="status-chip status-ok">Admin Broadcast</span>
        </h2>
        <p class="sub">Publish announcements directly to teachers, learners, or parents.</p>

        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="announcement-audience">Audience</label>
            <select id="announcement-audience" name="announcement_audience" required>
              <option value="">Choose audience</option>
              <option value="teacher">Teachers</option>
              <option value="learner">Learners</option>
              <option value="parent">Parents</option>
            </select>
          </div>

          <div class="field">
            <label for="announcement-target-type">Target Scope</label>
            <select id="announcement-target-type" name="announcement_target_type" required>
              <option value="all">All</option>
              <option value="class">Specific Class</option>
              <option value="learner">Specific Learner</option>
            </select>
          </div>

          <div class="field" id="announcement-target-class-wrap">
            <label for="announcement-target-class">Target Class</label>
            <select id="announcement-target-class" name="announcement_target_class_id">
              <option value="">Choose class</option>
              <?php foreach ($classes as $class_item): ?>
                <option value="<?= h($class_item['id']) ?>"><?= h($class_item['name']) ?></option>
              <?php endforeach; ?>
            </select>
          </div>

          <div class="field" id="announcement-target-learner-wrap">
            <label for="announcement-target-learner">Target Learner</label>
            <select id="announcement-target-learner" name="announcement_target_learner_id">
              <option value="">Choose learner</option>
              <?php foreach ($parentLearnerChoices as $learnerChoice): ?>
                <option value="<?= h($learnerChoice['id']) ?>" data-class-name="<?= h($learnerChoice['class_name']) ?>">
                  <?= h($learnerChoice['reg_number']) ?> - <?= h($learnerChoice['full_name']) ?> (<?= h($learnerChoice['class_name']) ?>)
                </option>
              <?php endforeach; ?>
            </select>
          </div>

          <div class="field">
            <label for="announcement-title">Title</label>
            <input id="announcement-title" name="announcement_title" placeholder="Announcement title" required>
          </div>

          <div class="field">
            <label for="announcement-body">Message</label>
            <textarea id="announcement-body" name="announcement_body" placeholder="Type announcement message" required></textarea>
          </div>

          <button class="button primary" type="submit" name="post_admin_announcement">Publish Announcement</button>
        </form>
      </article>

      <article class="panel">
        <h2>
          Teacher to Parent Review Queue
          <span class="status-chip status-warn">Admin Verification</span>
        </h2>
        <p class="sub">Approve or reject teacher announcements targeted to parents before they are posted.</p>

        <div class="search-bar record-filter-bar" data-table-id="teacherParentReviewTable">
          <select class="record-filter-field" aria-label="Teacher parent review filter field">
            <option value="all">All Columns</option>
            <option value="0">Submitted</option>
            <option value="1">Teacher</option>
            <option value="2">Target</option>
            <option value="3">Title</option>
            <option value="4">Message</option>
          </select>
          <input class="record-filter-input" type="search" placeholder="Search teacher review queue...">
        </div>

        <div class="table-wrap">
          <table id="teacherParentReviewTable">
            <thead>
              <tr>
                <th>Submitted</th>
                <th>Teacher</th>
                <th>Target</th>
                <th>Title</th>
                <th>Message</th>
                <th>Decision</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($teacherParentAnnouncementsPending)): ?>
                <tr><td colspan="6">No pending teacher announcements for parents.</td></tr>
              <?php else: ?>
                <?php foreach ($teacherParentAnnouncementsPending as $pendingAnnouncement): ?>
                  <tr>
                    <td><?= h($pendingAnnouncement['created_at']) ?></td>
                    <td><?= h($pendingAnnouncement['teacher_name']) ?><br><small><?= h($pendingAnnouncement['teacher_email']) ?></small></td>
                    <td><?= h(announcement_target_label($pendingAnnouncement)) ?></td>
                    <td><?= h($pendingAnnouncement['title']) ?></td>
                    <td><?= nl2br(h($pendingAnnouncement['body'])) ?></td>
                    <td>
                      <form method="POST" style="display:grid; gap:6px; min-width:220px;">
                        <input type="hidden" name="teacher_announcement_id" value="<?= h($pendingAnnouncement['id']) ?>">
                        <select name="teacher_announcement_decision" required>
                          <option value="approve">Approve</option>
                          <option value="reject">Reject</option>
                        </select>
                        <textarea name="teacher_announcement_comment" placeholder="Admin review comment (optional)"></textarea>
                        <button class="button accent" type="submit" name="review_teacher_parent_announcement">Submit Review</button>
                      </form>
                    </td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>

      <article class="panel" style="grid-column:1 / -1;">
        <h2>
          Recent Admin Announcements
          <span class="status-chip status-ok">History</span>
        </h2>
        <div class="search-bar record-filter-bar" data-table-id="adminAnnouncementsTable">
          <select class="record-filter-field" aria-label="Admin announcements filter field">
            <option value="all">All Columns</option>
            <option value="0">Created</option>
            <option value="1">Audience</option>
            <option value="2">Target</option>
            <option value="3">Title</option>
            <option value="5">Status</option>
          </select>
          <input class="record-filter-input" type="search" placeholder="Search announcements history...">
        </div>
        <div class="table-wrap">
          <table id="adminAnnouncementsTable">
            <thead>
              <tr>
                <th>Created</th>
                <th>Audience</th>
                <th>Target</th>
                <th>Title</th>
                <th>Message</th>
                <th>Status</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($adminAnnouncementRows)): ?>
                <tr><td colspan="6">No admin announcements posted yet.</td></tr>
              <?php else: ?>
                <?php foreach ($adminAnnouncementRows as $row): ?>
                  <tr>
                    <td><?= h($row['created_at']) ?></td>
                    <td><?= h(ucfirst($row['audience'])) ?></td>
                    <td><?= h(announcement_target_label($row)) ?></td>
                    <td><?= h($row['title']) ?></td>
                    <td><?= nl2br(h($row['body'])) ?></td>
                    <td>
                      <span class="status-chip <?= $row['status'] === 'published' ? 'status-ok' : 'status-warn' ?>">
                        <?= h(ucfirst(str_replace('_', ' ', $row['status']))) ?>
                      </span>
                    </td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>

    <section id="adminSystemLogView" class="desk-view">
      <article class="panel">
        <h2>System Log</h2>
        <p class="sub">Administrative activity, login events, and system changes. Visible to admins only.</p>
        <div style="display:flex; gap:8px; flex-wrap:wrap; margin-bottom:12px;">
          <button type="button" class="button primary" style="width:auto;" id="printSystemLogBtn">Print Report</button>
          <button type="button" class="button accent" style="width:auto;" id="downloadSystemLogPdfBtn">Download PDF</button>
        </div>
        <div class="table-wrap">
          <table id="adminSystemLogTable">
            <thead>
              <tr>
                <th>Time</th>
                <th>Actor</th>
                <th>Role</th>
                <th>Action</th>
                <th>Details</th>
                <th>IP Address</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($systemLogRows)): ?>
                <tr><td colspan="6">No system activity recorded yet.</td></tr>
              <?php else: ?>
                <?php foreach ($systemLogRows as $logRow): ?>
                  <tr>
                    <td><?= h((string)($logRow['created_at'] ?? '')) ?></td>
                    <td><?= h((string)($logRow['actor_name'] ?? '-')) ?><br><small><?= h((string)($logRow['actor_email'] ?? '')) ?></small></td>
                    <td><?= h((string)($logRow['actor_role'] ?? '-')) ?></td>
                    <td><?= h((string)($logRow['action'] ?? '')) ?></td>
                    <td><?= h((string)($logRow['details'] ?? '')) ?></td>
                    <td><?= h((string)($logRow['ip_address'] ?? '-')) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>

    <section id="adminSchoolSettingsView" class="grid-two desk-view">
      <article class="panel">
        <h2>
          School Profile Settings
          <span class="status-chip status-ok">Global Branding</span>
        </h2>
        <p class="sub">Update school details and logo here so reports and admin outputs match your school identity.</p>

        <form method="POST" enctype="multipart/form-data" autocomplete="off">
          <div class="field">
            <label for="school-name">School Name</label>
            <input id="school-name" name="school_name" value="<?= h($schoolName) ?>" required>
          </div>

          <div class="field">
            <label for="school-address">School Address</label>
            <input id="school-address" name="school_address" value="<?= h($schoolAddress) ?>" placeholder="P.O Box, Town">
          </div>

          <div class="field">
            <label for="school-contact">School Contact</label>
            <input id="school-contact" name="school_contact" value="<?= h($schoolContact) ?>" placeholder="Phone and/or email">
          </div>

          <div class="field">
            <label for="school-motto">School Motto</label>
            <input id="school-motto" name="school_motto" value="<?= h($schoolMotto) ?>" placeholder="Education for all">
          </div>

          <div class="field">
            <label for="school-theme-preset">Color Theme Preset</label>
            <select id="school-theme-preset" name="school_theme_preset">
              <?php foreach ($themePresets as $presetKey => $presetMeta): ?>
                <option value="<?= h($presetKey) ?>" <?= $schoolThemePreset === $presetKey ? 'selected' : '' ?>><?= h($presetMeta['label']) ?></option>
              <?php endforeach; ?>
            </select>
          </div>

          <div class="field" style="margin-bottom:6px;">
            <label style="display:flex; align-items:center; gap:8px; text-transform:none; letter-spacing:0; font-size:0.92rem;">
              <input id="apply-theme-preset" type="checkbox" name="apply_theme_preset" value="1" style="width:auto; margin:0;"> Apply selected preset palette
            </label>
          </div>

          <div class="field" style="grid-column:1 / -1; margin-bottom:0;">
            <label style="margin-bottom:6px;">Custom Palette (optional)</label>
            <div style="display:grid; gap:10px; grid-template-columns:repeat(auto-fit,minmax(180px,1fr));">
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Background Cream
                <input id="palette-bg-cream" type="color" name="palette_bg_cream" value="<?= h($paletteBgCream) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Background Sand
                <input id="palette-bg-sand" type="color" name="palette_bg_sand" value="<?= h($paletteBgSand) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Ink
                <input id="palette-ink" type="color" name="palette_ink" value="<?= h($paletteInk) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Muted Text
                <input id="palette-muted" type="color" name="palette_muted" value="<?= h($paletteMuted) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Brand Primary
                <input id="palette-brand-navy" type="color" name="palette_brand_navy" value="<?= h($paletteBrandNavy) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Brand Deep
                <input id="palette-brand-navy-deep" type="color" name="palette_brand_navy_deep" value="<?= h($paletteBrandNavyDeep) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Gold Accent
                <input id="palette-brand-gold" type="color" name="palette_brand_gold" value="<?= h($paletteBrandGold) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Gold Soft
                <input id="palette-brand-gold-soft" type="color" name="palette_brand_gold_soft" value="<?= h($paletteBrandGoldSoft) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Ice Surface
                <input id="palette-brand-ice" type="color" name="palette_brand_ice" value="<?= h($paletteBrandIce) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Sky Accent
                <input id="palette-patch-sky" type="color" name="palette_patch_sky" value="<?= h($palettePatchSky) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Sky Soft
                <input id="palette-patch-sky-soft" type="color" name="palette_patch_sky_soft" value="<?= h($palettePatchSkySoft) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Yellow Accent
                <input id="palette-patch-yellow" type="color" name="palette_patch_yellow" value="<?= h($palettePatchYellow) ?>" style="height:40px; padding:4px;">
              </label>
              <label style="display:grid; gap:4px; font-size:12px; text-transform:uppercase; letter-spacing:.08em; color:#38557f;">Yellow Soft
                <input id="palette-patch-yellow-soft" type="color" name="palette_patch_yellow_soft" value="<?= h($palettePatchYellowSoft) ?>" style="height:40px; padding:4px;">
              </label>
            </div>
          </div>

          <div class="field">
            <label for="school-logo">School Logo (JPG, PNG, WEBP)</label>
            <input id="school-logo" name="school_logo" type="file" accept="image/jpeg,image/png,image/webp">
          </div>

          <div class="field" style="margin-bottom:14px;">
            <label style="display:flex; align-items:center; gap:8px; text-transform:none; letter-spacing:0; font-size:0.92rem;">
              <input type="checkbox" name="clear_school_logo" value="1" style="width:auto; margin:0;"> Clear saved logo and use default
            </label>
          </div>

          <button class="button primary" type="submit" name="save_school_profile_settings">Save School Settings</button>
        </form>
      </article>

      <article class="panel">
        <h2>
          Current School Branding
          <span class="status-chip status-warn">Preview</span>
        </h2>
        <p class="sub">This preview is used by admin report printouts and branding blocks.</p>

        <div style="display:grid; gap:12px;">
          <div style="display:flex; gap:12px; align-items:center;">
            <img src="<?= h($resolvedSchoolLogoPath !== '' ? $resolvedSchoolLogoPath : $defaultSchoolLogoPath) ?>" alt="<?= h($schoolName) ?> logo" style="width:88px; height:88px; object-fit:contain; border:1px solid #ccd7ea; border-radius:12px; background:#fff; padding:6px;">
            <div>
              <div style="font-weight:800; color:#0d3f79;"><?= h($schoolName) ?></div>
              <div class="foot-note" style="margin-top:4px;"><?= h($schoolAddress) ?></div>
              <div class="foot-note"><?= h($schoolContact) ?></div>
              <div class="foot-note" style="font-style:italic;"><?= h($schoolMotto) ?></div>
            </div>
          </div>
          <div class="table-wrap" style="margin:0;">
            <table>
              <tbody>
                <tr>
                  <th style="width:200px;">Logo Path</th>
                  <td><span class="mono"><?= h($resolvedSchoolLogoPath !== '' ? $resolvedSchoolLogoPath : 'Not set') ?></span></td>
                </tr>
                <tr>
                  <th>Theme</th>
                  <td><?= h($themePresets[$schoolThemePreset]['label'] ?? ucfirst($schoolThemePreset)) ?></td>
                </tr>
                <tr>
                  <th>Last Branding Target</th>
                  <td>Admin reports and printable outputs</td>
                </tr>
              </tbody>
            </table>
          </div>

          <div style="display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:8px;">
            <span title="Brand Primary" style="height:28px; border-radius:7px; border:1px solid #c8d3e6; background:<?= h($paletteBrandNavy) ?>;"></span>
            <span title="Brand Deep" style="height:28px; border-radius:7px; border:1px solid #c8d3e6; background:<?= h($paletteBrandNavyDeep) ?>;"></span>
            <span title="Gold" style="height:28px; border-radius:7px; border:1px solid #c8d3e6; background:<?= h($paletteBrandGold) ?>;"></span>
            <span title="Ice" style="height:28px; border-radius:7px; border:1px solid #c8d3e6; background:<?= h($paletteBrandIce) ?>;"></span>
            <span title="Sky" style="height:28px; border-radius:7px; border:1px solid #c8d3e6; background:<?= h($palettePatchSky) ?>;"></span>
            <span title="Yellow" style="height:28px; border-radius:7px; border:1px solid #c8d3e6; background:<?= h($palettePatchYellow) ?>;"></span>
          </div>
        </div>
      </article>
    </section>

    <section id="adminWhatsappSettingsView" class="grid-two desk-view">
      <article class="panel">
        <h2>
          WhatsApp Configuration
          <span class="status-chip <?= $whatsappConfigured ? 'status-ok' : 'status-warn' ?>"><?= $whatsappConfigured ? 'Configured' : 'Needs Setup' ?></span>
        </h2>
        <p class="sub">Save WhatsApp Cloud API credentials here. These settings are used for parent alerts on announcements, funds receipted, and total owed updates.</p>

        <div class="table-wrap" style="margin-bottom:12px;">
          <table>
            <tbody>
              <tr>
                <th style="width:220px;">Source</th>
                <td><?= h(ucfirst($whatsappConfigSource)) ?></td>
              </tr>
              <tr>
                <th>Saved Token</th>
                <td><span class="mono"><?= h($whatsappTokenMasked) ?></span></td>
              </tr>
              <tr>
                <th>Phone Number ID</th>
                <td><span class="mono"><?= h($whatsappPhoneNumberId !== '' ? $whatsappPhoneNumberId : 'Not saved') ?></span></td>
              </tr>
              <tr>
                <th>API Version</th>
                <td><span class="mono"><?= h($whatsappApiVersion) ?></span></td>
              </tr>
            </tbody>
          </table>
        </div>

        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="whatsapp-phone-number-id">WhatsApp Phone Number ID</label>
            <input id="whatsapp-phone-number-id" name="whatsapp_phone_number_id" value="<?= h($whatsappPhoneNumberId) ?>" placeholder="e.g. 123456789012345" required>
          </div>

          <div class="field">
            <label for="whatsapp-api-version">Meta Graph API Version</label>
            <input id="whatsapp-api-version" name="whatsapp_api_version" value="<?= h($whatsappApiVersion) ?>" placeholder="v22.0" required>
          </div>

          <div class="field">
            <label for="whatsapp-token">WhatsApp Access Token</label>
            <input id="whatsapp-token" name="whatsapp_token" type="password" placeholder="Paste a new token only when replacing current one">
          </div>

          <div class="field" style="margin-bottom:14px;">
            <label style="display:flex; align-items:center; gap:8px; text-transform:none; letter-spacing:0; font-size:0.92rem;">
              <input type="checkbox" name="whatsapp_clear_token" value="1" style="width:auto; margin:0;"> Clear saved token
            </label>
          </div>

          <button class="button primary" type="submit" name="save_whatsapp_settings">Save WhatsApp Settings</button>
          <p class="foot-note">Security note: token input is write-only in this form. Leave token blank to keep existing token.</p>
        </form>
      </article>

      <article class="panel">
        <h2>
          Send Test Message
          <span class="status-chip status-ok">Delivery Check</span>
        </h2>
        <p class="sub">Send an immediate WhatsApp test message from this dashboard to verify credentials and delivery.</p>

        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="whatsapp-test-phone">Destination Phone</label>
            <input id="whatsapp-test-phone" name="whatsapp_test_phone" placeholder="+26377XXXXXXX" required>
          </div>

          <div class="field">
            <label for="whatsapp-test-message">Message</label>
            <textarea id="whatsapp-test-message" name="whatsapp_test_message" placeholder="Leave blank to send default test message"></textarea>
          </div>

          <button class="button accent" type="submit" name="send_whatsapp_test_message">Send Test WhatsApp Message</button>
        </form>

        <p class="foot-note">If sending fails, check token validity, phone number ID, and that the test number is allowed in your WhatsApp Cloud API setup.</p>
      </article>
    </section>

    <section id="adminOperationsView" class="grid-two desk-view">
      <div class="operations-step-nav" id="adminOperationsStepNav">
        <button type="button" class="operations-step-btn" data-step-target="operationsStepClassSubject">Step 1 and 3: Class and Subject Register</button>
        <button type="button" class="operations-step-btn" data-step-target="operationsStepTeacher">Step 2: Teacher Onboarding</button>
        <button type="button" class="operations-step-btn" data-step-target="operationsStepHop">Step 2B: HOP Profile Setup</button>
        <button type="button" class="operations-step-btn" data-step-target="operationsStepTeacherHopAssignment">Step 2C: Teacher to HOP Assignment</button>
        <button type="button" class="operations-step-btn" data-step-target="operationsStepClassTeacher">Step 2D: Class Teacher Allocation</button>
        <button type="button" class="operations-step-btn" data-step-target="operationsStepSubjectAllocation">Step 4: Subject Allocation Studio</button>
        <button type="button" class="operations-step-btn" data-step-target="operationsStepAdmissionApprovals">Admin: Student Admission Approvals</button>
      </div>

      <article id="operationsStepClassSubject" class="panel grouped-registers operation-step<?= $initialOperationsStep === 'operationsStepClassSubject' ? ' active' : '' ?>">
        <h2>
          Class and Subject Register
          <span class="status-chip status-ok">Steps 1 and 3</span>
        </h2>
        <p class="sub">Set up classes and subjects together in one place before moving on to teacher allocation.</p>

        <div class="grouped-register-grid">
          <div class="grouped-register-card">
            <h3>Class Register</h3>
            <p class="sub">Enter classes manually before assigning learners, subjects, and teachers.</p>
            <form method="POST" autocomplete="off">
              <div class="field">
                <label for="class-name">Class Name</label>
                <input id="class-name" name="class_name" placeholder="e.g. Form 1A" required>
              </div>
              <button class="button primary" type="submit" name="add_class">Save Class</button>
            </form>
          </div>

          <div class="grouped-register-card">
            <h3>Subject Register</h3>
            <p class="sub">Enter subjects once and make them available for teacher allocation across all classes.</p>
            <form method="POST" autocomplete="off">
              <div class="field">
                <label for="subject-name">Subject Name</label>
                <input id="subject-name" name="subject_name" placeholder="e.g. Agriculture" required>
              </div>
              <button class="button primary" type="submit" name="add_subject">Save Subject</button>
            </form>
          </div>
        </div>
      </article>

      <article id="operationsStepTeacher" class="panel operation-step<?= $initialOperationsStep === 'operationsStepTeacher' ? ' active' : '' ?>">
        <h2>
          Teacher Onboarding
          <span class="status-chip status-ok">Step 2</span>
        </h2>
        <p class="sub">Register staff members with secure default access. They can be assigned immediately after creation.</p>
        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="teacher-name">Teacher First Name</label>
            <input id="teacher-name" name="teacher_name" placeholder="e.g. Nomsa" required>
          </div>
          <div class="field">
            <label for="teacher-surname">Teacher Surname</label>
            <input id="teacher-surname" name="teacher_surname" placeholder="e.g. Ndlovu" required>
          </div>
          <div class="field">
            <label for="teacher-email">Teacher Email</label>
            <input id="teacher-email" name="email" type="email" placeholder="teacher@mavela.gov.zw" required>
          </div>
          <div class="field">
            <label for="teacher-dob">Date of Birth</label>
            <input id="teacher-dob" name="teacher_dob" type="date">
          </div>
          <button class="button primary" type="submit" name="add_teacher">Create Teacher Profile</button>
          <p class="foot-note">A unique temporary password is generated for each teacher and shown once after creation.</p>
        </form>
      </article>

      <article id="operationsStepHop" class="panel operation-step<?= $initialOperationsStep === 'operationsStepHop' ? ' active' : '' ?>">
        <h2>
          HOP Profile Setup
          <span class="status-chip status-ok">Step 2B</span>
        </h2>
        <p class="sub">Create Head of Platform profiles by department. HOPs use the same login page and get redirected to their own dashboard.</p>
        <form method="POST" autocomplete="off">
          <div class="field">
            <label for="hop-name">HOP Full Name</label>
            <input id="hop-name" name="hop_name" placeholder="e.g. Sibongile Ncube" required>
          </div>
          <div class="field">
            <label for="hop-email">HOP Email</label>
            <input id="hop-email" name="hop_email" type="email" placeholder="hop@mavela.gov.zw" required>
          </div>
          <div class="field">
            <label for="hop-department-name">Department</label>
            <input id="hop-department-name" name="hop_department_name" placeholder="e.g. Science Department" required>
          </div>
          <button class="button primary" type="submit" name="add_hop_profile">Create HOP Profile</button>
          <p class="foot-note">A unique temporary password is generated for each HOP profile and shown once after creation.</p>
        </form>
      </article>

      <article id="operationsStepTeacherHopAssignment" class="panel operation-step<?= $initialOperationsStep === 'operationsStepTeacherHopAssignment' ? ' active' : '' ?>" style="grid-column: 1 / -1;">
        <h2>
          Teacher to HOP Assignment
          <span class="status-chip status-warn">Step 2C</span>
        </h2>
        <p class="sub">Link each teacher to one HOP. HOP can then assign classes and subjects for their assigned teachers.</p>

        <form method="POST" autocomplete="off" style="display:grid; gap:10px; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); align-items:end; margin-bottom:12px;">
          <div class="field" style="margin:0;">
            <label for="hop-user-id">Select HOP</label>
            <select id="hop-user-id" name="hop_user_id" required>
              <option value="">Choose HOP</option>
              <?php foreach ($hops as $hop): ?>
                <option value="<?= h($hop['id']) ?>"><?= h($hop['name']) ?> (<?= h($hop['department_name']) ?>)</option>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="field" style="margin:0;">
            <label for="hop-teacher-id">Select Teacher</label>
            <select id="hop-teacher-id" name="hop_teacher_id" required>
              <option value="">Choose teacher</option>
              <?php foreach ($teachers as $teacher): ?>
                <option value="<?= h($teacher['id']) ?>"><?= h($teacher['name']) ?> (<?= h($teacher['email']) ?>)</option>
              <?php endforeach; ?>
            </select>
          </div>
          <button class="button accent" type="submit" name="assign_teacher_to_hop">Assign Teacher to HOP</button>
        </form>

        <div class="search-bar record-filter-bar" data-table-id="teacherHopAssignmentsTable">
          <select class="record-filter-field" aria-label="Teacher to HOP assignments filter field">
            <option value="all">All Columns</option>
            <option value="0">Department</option>
            <option value="1">HOP</option>
            <option value="2">Teacher</option>
            <option value="3">Last Linked</option>
          </select>
          <input class="record-filter-input" type="search" placeholder="Search teacher to HOP assignments...">
        </div>

        <div class="table-wrap">
          <table id="teacherHopAssignmentsTable">
            <thead>
              <tr>
                <th>Department</th>
                <th>HOP</th>
                <th>Teacher</th>
                <th>Last Linked</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($teacherHopAssignments)): ?>
                <tr><td colspan="4">No teachers linked to HOPs yet.</td></tr>
              <?php else: ?>
                <?php foreach ($teacherHopAssignments as $mapping): ?>
                  <tr>
                    <td><?= h($mapping['department_name'] ?: '-') ?></td>
                    <td><?= h($mapping['hop_name']) ?><br><small><?= h($mapping['hop_email']) ?></small></td>
                    <td><?= h($mapping['teacher_name']) ?><br><small><?= h($mapping['teacher_email']) ?></small></td>
                    <td><?= h($mapping['updated_at'] ?: $mapping['created_at']) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>

      <article id="operationsStepClassTeacher" class="panel operation-step<?= $initialOperationsStep === 'operationsStepClassTeacher' ? ' active' : '' ?>" style="grid-column: 1 / -1;">
        <h2>
          Class Teacher Allocation
          <span class="status-chip status-warn">Step 2D</span>
        </h2>
        <p class="sub">After class setup, allocate one class teacher per class. Class teachers handle attendance, learner profile upkeep, parent liaison, and attendance reporting.</p>

        <form method="POST" autocomplete="off" style="display:grid; gap:10px; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); align-items:end; margin-bottom:12px;">
          <div class="field" style="margin:0;">
            <label for="class-teacher-class-id">Select Class</label>
            <select id="class-teacher-class-id" name="class_teacher_class_id" required>
              <option value="">Choose class</option>
              <?php foreach ($classes as $class_item): ?>
                <option value="<?= h($class_item['id']) ?>"><?= h($class_item['name']) ?></option>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="field" style="margin:0;">
            <label for="class-teacher-teacher-id">Select Class Teacher</label>
            <select id="class-teacher-teacher-id" name="class_teacher_teacher_id" required>
              <option value="">Choose teacher</option>
              <?php foreach ($teachers as $teacher): ?>
                <option value="<?= h($teacher['id']) ?>"><?= h($teacher['name']) ?> (<?= h($teacher['email']) ?>)</option>
              <?php endforeach; ?>
            </select>
          </div>
          <button class="button accent" type="submit" name="assign_class_teacher">Save Class Teacher</button>
        </form>

        <div class="search-bar record-filter-bar" data-table-id="classTeacherAssignmentsTable">
          <select class="record-filter-field" aria-label="Class teacher allocations filter field">
            <option value="all">All Columns</option>
            <option value="0">Class</option>
            <option value="1">Class Teacher</option>
            <option value="2">Last Updated</option>
          </select>
          <input class="record-filter-input" type="search" placeholder="Search class teacher allocations...">
        </div>

        <div class="table-wrap">
          <table id="classTeacherAssignmentsTable">
            <thead>
              <tr>
                <th>Class</th>
                <th>Class Teacher</th>
                <th>Last Updated</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($classTeacherAssignments)): ?>
                <tr><td colspan="3">No class teacher allocations yet.</td></tr>
              <?php else: ?>
                <?php foreach ($classTeacherAssignments as $allocation): ?>
                  <tr>
                    <td><?= h($allocation['class_name']) ?></td>
                    <td><?= h($allocation['teacher_name']) ?><br><small><?= h($allocation['teacher_email']) ?></small></td>
                    <td><?= h($allocation['updated_at'] ?: $allocation['created_at']) ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>

      <article id="operationsStepSubjectAllocation" class="panel operation-step<?= $initialOperationsStep === 'operationsStepSubjectAllocation' ? ' active' : '' ?>">
        <h2>
          Subject Allocation Studio
          <span class="status-chip status-warn">Step 4</span>
        </h2>
        <p class="sub">Assign a teacher to one class, then choose the specific subjects they are responsible for.</p>
        <form method="POST" id="assignForm">
          <div class="field">
            <label for="teacher-select">Select Teacher</label>
            <input id="teacherSelectSearch" type="search" placeholder="Search teacher name or email...">
            <select id="teacher-select" name="teacher_id" required>
              <option value="">Choose teacher</option>
              <?php foreach ($teachers as $teacher): ?>
                <option value="<?= h($teacher['id']) ?>"><?= h($teacher['name']) ?> (<?= h($teacher['email']) ?>)</option>
              <?php endforeach; ?>
            </select>
          </div>

          <div class="field">
            <label for="classSelect">Select Class</label>
            <input id="classSelectSearch" type="search" placeholder="Search class...">
            <select id="classSelect" name="class_id" required>
              <option value="">Choose class</option>
              <?php foreach ($classes as $class_item): ?>
                <option value="<?= h($class_item['id']) ?>"><?= h($class_item['name']) ?></option>
              <?php endforeach; ?>
            </select>
          </div>

          <div class="field">
            <label>Subjects for selected class</label>
            <input id="subjectSelectSearch" type="search" placeholder="Search subject...">
            <div id="subjectCheckboxes" class="subject-picker">
              <div class="subject-hint">Select a class to load subjects.</div>
            </div>
            <div class="helper-inline">
              <span id="selectedCount">0 selected</span>
              <span id="availableCount">0 available</span>
            </div>
          </div>

          <button class="button accent" type="submit" name="assign">Save Subject Assignment</button>
        </form>
      </article>

      <article id="operationsStepAdmissionApprovals" class="panel operation-step<?= $initialOperationsStep === 'operationsStepAdmissionApprovals' ? ' active' : '' ?>" style="grid-column: 1 / -1;">
        <h2>
          Student Admission Approvals
          <span class="status-chip status-warn">Admin Required</span>
        </h2>
        <p class="sub">Learners are added to the school database only after admin approval.</p>

        <form method="POST" style="display:flex; justify-content:flex-end; margin-bottom:12px;">
          <button class="button primary" type="submit" name="approve_all_pending_admissions" <?= empty($pendingAdmissions) ? 'disabled' : '' ?>>
            Approve All <?= count($pendingAdmissions) ?> Pending
          </button>
        </form>

        <div class="search-bar record-filter-bar" data-table-id="pendingAdmissionsTable">
          <select class="record-filter-field" aria-label="Pending admissions filter field">
            <option value="all">All Columns</option>
            <option value="0">Submitted On</option>
            <option value="2">Learner</option>
            <option value="3">Class</option>
            <option value="4">Gender</option>
            <option value="5">Submitted By</option>
          </select>
          <input class="record-filter-input" type="search" placeholder="Search pending admissions...">
        </div>

        <div class="table-wrap">
          <table id="pendingAdmissionsTable">
            <thead>
              <tr>
                <th>Submitted On</th>
                <th>Photo</th>
                <th>Learner</th>
                <th>Class</th>
                <th>Gender</th>
                <th>Submitted By</th>
                <th>Decision</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($pendingAdmissions)): ?>
                <tr><td colspan="7">No pending admission approvals at the moment.</td></tr>
              <?php else: ?>
                <?php foreach ($pendingAdmissions as $pending): ?>
                  <tr>
                    <td><?= h($pending['created_at']) ?></td>
                    <td>
                      <?php if (!empty($pending['student_photo_path'])): ?>
                        <a href="<?= h($pending['student_photo_path']) ?>" target="_blank" rel="noopener">
                          <img src="<?= h($pending['student_photo_path']) ?>" alt="Student photo" style="width:44px;height:44px;object-fit:cover;border-radius:8px;border:1px solid #d8def0;">
                        </a>
                      <?php else: ?>
                        <span class="status-chip status-warn">No Photo</span>
                      <?php endif; ?>
                    </td>
                    <td><?= h(trim($pending['christian_names'] . ' ' . $pending['surname'])) ?></td>
                    <td><?= h($pending['class_name']) ?></td>
                    <td><?= h($pending['gender']) ?></td>
                    <td><?= h($pending['teacher_name']) ?></td>
                    <td>
                      <form method="POST" style="display:grid; gap:6px; min-width:230px;">
                        <input type="hidden" name="pending_id" value="<?= h($pending['id']) ?>">
                        <input name="review_comment" placeholder="Comment (optional)">
                        <div style="display:flex; gap:6px;">
                          <button class="button primary" type="submit" name="approve_pending_admission">Approve</button>
                          <button class="button accent" type="submit" name="reject_pending_admission">Reject</button>
                        </div>
                      </form>
                    </td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </article>
    </section>

    <section id="adminAdmissionView" class="grid-two desk-view">
      <article class="panel">
        <h2>
          Student Admission Form
          <span class="status-chip status-ok">Admin Entry</span>
        </h2>
        <p class="sub">Capture learner and parent or guardian details and admit directly into the school register.</p>

        <?php if ($admissionEditLearner): ?>
          <div class="alert success" style="margin-bottom:14px;">Editing learner admission record. Reg Number: <?= h($admissionEditLearner['reg_number'] ?? '') ?></div>
        <?php endif; ?>

        <div class="panel-actions">
          <button type="button" class="button primary" style="width:auto;" id="toggleAdminAdmissionFormBtn">Show Student Admission Form</button>
          <?php if ($admissionEditLearner): ?>
            <a class="button accent" style="width:auto; text-decoration:none;" href="admin.php?admin_active_view=adminAdmissionView">Cancel Edit</a>
          <?php endif; ?>
        </div>

        <div id="adminAdmissionFormView" class="view-toggle">
          <form method="POST" autocomplete="off" enctype="multipart/form-data">
            <input type="hidden" name="admin_active_view" value="adminAdmissionView">
            <input type="hidden" name="admission_learner_id" value="<?= h((string)($admissionEditLearner['id'] ?? '')) ?>">
            <div class="field">
              <label for="admission_class_id">Class</label>
              <input type="search" id="admissionClassSearch" placeholder="Search class...">
              <select name="admission_class_id" id="admission_class_id" required>
                <option value="">Choose class</option>
                <?php foreach ($classes as $class_item): ?>
                  <option value="<?= h($class_item['id']) ?>" <?= (int)($admissionEditLearner['class_id'] ?? 0) === (int)$class_item['id'] ? 'selected' : '' ?>><?= h($class_item['name']) ?></option>
                <?php endforeach; ?>
              </select>
            </div>

            <p class="foot-note" style="margin-top:-4px;">Reg Number is auto-generated when you save this learner.</p>

            <div class="field">
              <label for="date_of_admission">Date of Admission</label>
              <input type="date" id="date_of_admission" name="date_of_admission" value="<?= h((string)($admissionEditLearner['date_of_admission'] ?? '')) ?>">
            </div>
            <div class="field">
              <label for="surname">Surname</label>
              <input id="surname" name="surname" placeholder="e.g. Moyo" value="<?= h((string)($admissionEditLearner['surname'] ?? '')) ?>" required>
            </div>
            <div class="field">
              <label for="christian_names">Christian Names</label>
              <input id="christian_names" name="christian_names" placeholder="e.g. Sipho Themba" value="<?= h((string)($admissionEditLearner['christian_names'] ?? '')) ?>" required>
            </div>
            <div class="field">
              <label for="date_of_birth_info">Date of Birth</label>
              <input type="date" id="date_of_birth_info" name="date_of_birth_info" value="<?= h((string)($admissionEditLearner['date_of_birth_info'] ?? '')) ?>">
            </div>
            <div class="field">
              <label for="birth_certificate_number">Birth Certificate Number</label>
              <input id="birth_certificate_number" name="birth_certificate_number" placeholder="Optional" value="<?= h((string)($admissionEditLearner['birth_certificate_number'] ?? '')) ?>">
            </div>
            <div class="field">
              <label for="religious_denomination">Religious Denomination</label>
              <input id="religious_denomination" name="religious_denomination" placeholder="Optional" value="<?= h((string)($admissionEditLearner['religious_denomination'] ?? '')) ?>">
            </div>
            <div class="field">
              <label for="gender">Gender</label>
              <select id="gender" name="gender" required>
                <option value="Male" <?= (string)($admissionEditLearner['gender'] ?? 'Male') === 'Male' ? 'selected' : '' ?>>Male</option>
                <option value="Female" <?= (string)($admissionEditLearner['gender'] ?? 'Male') === 'Female' ? 'selected' : '' ?>>Female</option>
              </select>
            </div>
            <div class="field">
              <label for="guardian_name">Parent/Guardian Surname and First Two Names (in full)</label>
              <input id="guardian_name" name="guardian_name" placeholder="e.g. Moyo Patricia Lindiwe" value="<?= h((string)($admissionEditLearner['guardian_name'] ?? '')) ?>">
            </div>
            <div class="field">
              <label for="guardian_national_id">Parent/Guardian National Registration Number</label>
              <input id="guardian_national_id" name="guardian_national_id" placeholder="Optional" value="<?= h((string)($admissionEditLearner['guardian_national_id'] ?? '')) ?>">
            </div>
            <div class="field">
              <label for="guardian_address">Parent/Guardian Address</label>
              <input id="guardian_address" name="guardian_address" placeholder="Optional" value="<?= h((string)($admissionEditLearner['guardian_address'] ?? '')) ?>">
            </div>
            <div class="field">
              <label for="guardian_phone">Guardian Phone</label>
              <input id="guardian_phone" name="guardian_phone" placeholder="Optional" value="<?= h((string)($admissionEditLearner['guardian_phone'] ?? '')) ?>">
            </div>
            <div class="field">
              <label for="student_photo">Student Photo (Optional)</label>
              <input type="file" id="student_photo" name="student_photo" accept=".jpg,.jpeg,.png,.webp,image/jpeg,image/png,image/webp">
              <span class="foot-note" style="margin-top:0;">Max 5MB, JPG/PNG/WEBP.</span>
              <?php if (!empty($admissionEditLearner['student_photo_path'])): ?>
                <span class="foot-note">Current photo: <a href="<?= h($admissionEditLearner['student_photo_path']) ?>" target="_blank" rel="noopener"><?= h($admissionEditLearner['student_photo_path']) ?></a></span>
              <?php endif; ?>
            </div>
            <button class="button accent" type="submit" name="add_learner_admin"><?= $admissionEditLearner ? 'Update Learner' : 'Save Learner' ?></button>
          </form>
        </div>
      </article>

      <article class="panel">
        <h2>
          Student Admission Register
          <span class="status-chip status-warn">PDF + Print</span>
        </h2>
        <p class="sub">Generate a formal admission register from admitted learners in print-ready and PDF-ready formats.</p>

        <div class="panel-actions">
          <button type="button" class="button primary" style="width:auto;" id="toggleAdminAdmissionRegisterBtn">Show Student Admission Register</button>
          <button type="button" class="button accent" style="width:auto;" id="printAdminAdmissionRegisterBtn" disabled>Print</button>
          <button type="button" class="button accent" style="width:auto;" id="downloadAdminAdmissionRegisterPdfBtn" disabled>Download PDF</button>
        </div>

        <div class="search-bar record-filter-bar" data-table-id="adminAdmissionRegisterTable">
          <select class="record-filter-field" aria-label="Admission register filter field">
            <option value="all">All Columns</option>
            <option value="0">Admitted On</option>
            <option value="1">Reg Number</option>
            <option value="3">Learner</option>
            <option value="4">Class</option>
            <option value="7">Gender</option>
            <option value="8">Guardian Name</option>
          </select>
          <input class="record-filter-input" type="search" placeholder="Search admitted learners...">
        </div>

        <div id="adminAdmissionRegisterView" class="view-toggle">
          <div class="table-wrap">
            <table id="adminAdmissionRegisterTable">
              <thead>
                <tr>
                  <th>Admitted On</th>
                  <th>Reg Number</th>
                  <th>Photo</th>
                  <th>Learner</th>
                  <th>Class</th>
                  <th>Date of Admission</th>
                  <th>Birth Certificate No.</th>
                  <th>Gender</th>
                  <th>Guardian Name</th>
                  <th>Guardian Phone</th>
                  <th>Actions</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($admissionRegister)): ?>
                    <tr><td colspan="11">No admitted learners found yet.</td></tr>
                <?php else: ?>
                  <?php foreach ($admissionRegister as $row): ?>
                    <tr>
                      <td><?= h($row['created_at']) ?></td>
                      <td><?= h($row['reg_number']) ?></td>
                      <td>
                        <?php if (!empty($row['student_photo_path'])): ?>
                          <a href="<?= h($row['student_photo_path']) ?>" target="_blank" rel="noopener">
                            <img src="<?= h($row['student_photo_path']) ?>" alt="Student photo" style="width:44px;height:44px;object-fit:cover;border-radius:8px;border:1px solid #d8def0;">
                          </a>
                        <?php else: ?>
                          <span class="status-chip status-warn">No Photo</span>
                        <?php endif; ?>
                      </td>
                      <td><?= h(trim($row['surname'] . ' ' . $row['christian_names'])) ?></td>
                      <td><?= h($row['class_name']) ?></td>
                      <td><?= h($row['date_of_admission'] ?? '-') ?></td>
                      <td><?= h($row['birth_certificate_number'] ?? '-') ?></td>
                      <td><?= h($row['gender']) ?></td>
                      <td><?= h($row['guardian_name'] ?? '-') ?></td>
                      <td><?= h($row['guardian_phone'] ?? '-') ?></td>
                      <td>
                        <div style="display:flex; gap:6px; flex-wrap:wrap;">
                          <a class="button primary thin" style="text-decoration:none; width:auto;" href="admin.php?admin_active_view=adminAdmissionView&edit_admission_id=<?= h($row['id']) ?>">Edit</a>
                          <form method="POST" class="admission-delete-form" style="display:inline; margin:0;">
                            <input type="hidden" name="admission_learner_id" value="<?= h($row['id']) ?>">
                            <input type="hidden" name="admin_active_view" value="adminAdmissionView">
                            <input type="hidden" name="admin_delete_password" value="">
                            <button class="button accent thin" type="submit" name="delete_admission_learner" style="width:auto;">Delete</button>
                          </form>
                        </div>
                      </td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </div>
      </article>
    </section>

    <section id="adminStudentIdsView" class="grid-two desk-view">
      <article class="panel">
        <h2>
          Student ID Creator
          <span class="status-chip status-ok">Admin Only</span>
        </h2>
        <p class="sub">Create stylish student ID cards with school branding, photo, QR code, and learner identity details.</p>

        <div class="field">
          <label for="studentIdClassFilter">Filter by Class</label>
          <select id="studentIdClassFilter">
            <option value="all">All active classes</option>
            <?php foreach ($classes as $class_item): ?>
              <option value="<?= h($class_item['name']) ?>"><?= h($class_item['name']) ?></option>
            <?php endforeach; ?>
          </select>
        </div>

        <div class="field">
          <label for="studentIdLearnerSelect">Select Learner</label>
          <input type="search" id="studentIdLearnerSearch" placeholder="Search learner by name, reg number, class...">
          <select id="studentIdLearnerSelect">
            <option value="">Choose learner</option>
            <?php foreach ($studentIdLearners as $learner): ?>
              <option value="<?= h($learner['id']) ?>" data-class-name="<?= h($learner['class_name']) ?>">
                <?= h($learner['reg_number']) ?> - <?= h($learner['full_name']) ?> (<?= h($learner['class_name']) ?>)
              </option>
            <?php endforeach; ?>
          </select>
        </div>

        <div class="field">
          <label for="studentIdSerialPrefix">ID Serial Prefix</label>
          <input type="text" id="studentIdSerialPrefix" value="MAV-ID" maxlength="20" placeholder="e.g. MAV-ID">
        </div>

        <div class="field">
          <label for="studentIdIssueDate">Issue Date</label>
          <input type="date" id="studentIdIssueDate" value="<?= h(date('Y-m-d')) ?>">
        </div>

        <div class="field">
          <label for="studentIdExpiryDate">Expiry Date</label>
          <input type="date" id="studentIdExpiryDate" value="<?= h(date('Y-m-d', strtotime('+1 year'))) ?>">
        </div>

        <div class="field">
          <label for="studentIdRenewalYear">Renewal Year</label>
          <input type="number" id="studentIdRenewalYear" min="2000" max="2100" value="<?= h((string)((int)date('Y') + 1)) ?>">
        </div>

        <form method="POST" enctype="multipart/form-data" style="display:grid; gap:8px; margin-top:4px;">
          <div class="field" style="margin:0;">
            <label for="head_signature_file">Upload Head Signature</label>
            <input type="file" id="head_signature_file" name="head_signature_file" accept=".png,.jpg,.jpeg,.webp,image/png,image/jpeg,image/webp" required>
            <span class="foot-note" style="margin-top:4px;">Background is removed automatically and applied to IDs.</span>
          </div>
          <div style="display:flex; align-items:center; gap:8px; flex-wrap:wrap;">
            <button type="submit" class="button accent" name="upload_head_signature">Upload Signature</button>
            <?php if ($headSignaturePath !== ''): ?>
              <img src="<?= h($headSignaturePath) ?>" alt="Current head signature" style="max-height:30px; max-width:120px; object-fit:contain; background:#fff; border:1px solid #c7dbf5; border-radius:6px; padding:3px;">
              <span class="foot-note" style="margin:0;">Current signature loaded</span>
            <?php else: ?>
              <span class="foot-note" style="margin:0;">No signature uploaded yet.</span>
            <?php endif; ?>
          </div>
        </form>

        <div style="display:flex; gap:8px; flex-wrap:wrap;">
          <button type="button" class="button primary" id="generateSingleStudentIdBtn">Generate Selected ID</button>
          <button type="button" class="button accent" id="generateClassStudentIdsBtn">Generate Class IDs</button>
          <button type="button" class="button primary" id="printStudentIdCardsBtn" disabled>Print IDs</button>
          <button type="button" class="button accent" id="downloadStudentIdCardsPdfBtn" disabled>Download PDF</button>
        </div>

        <p class="foot-note">IDs include Student Name, Reg Number, Date of Birth, Birth Certificate Number, School Logo, School Name, QR code, logo watermark, serial number, issue date, expiry date, renewal year, school stamp placeholder, and a backside with guardian and school verification details.</p>
      </article>

      <article class="panel">
        <h2>
          Student ID Preview Canvas
          <span class="status-chip status-warn">Graphical Output</span>
        </h2>
        <p class="sub">Preview generated cards before printing or downloading as PDF.</p>
        <div id="studentIdCardsCanvas" class="student-id-canvas">
          <div class="foot-note">No IDs generated yet. Choose a learner or class and click generate.</div>
        </div>
      </article>
    </section>

    <section id="adminApplicationsView" class="panel desk-view">
      <h2>Public Learner Applications <span class="meta-chip" style="color:#1f5f2f;background:#e8f7ee;border-color:#b8e4c6;">Admissions Pipeline</span></h2>
      <p class="sub">Review learner application forms submitted on the login page, assign class and teacher, then approve or reject.</p>
      <div class="table-wrap">
        <table>
          <thead>
            <tr>
              <th>Submitted</th>
              <th>Learner</th>
              <th>Preferred Class</th>
              <th>Parent / Guardian</th>
              <th>WhatsApp</th>
              <th>Status</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($publicLearnerApplications)): ?>
              <tr><td colspan="7">No learner applications submitted yet.</td></tr>
            <?php else: ?>
              <?php foreach ($publicLearnerApplications as $application): ?>
                <tr>
                  <td><?= h($application['created_at']) ?></td>
                  <td>
                    <strong><?= h($application['full_name']) ?></strong><br>
                    <span class="foot-note">Gender: <?= h($application['gender']) ?> | DOB: <?= h($application['date_of_birth_info'] ?: '-') ?></span>
                  </td>
                  <td><?= h($application['preferred_class_name']) ?></td>
                  <td>
                    <?= h($application['guardian_name'] ?: '-') ?><br>
                    <span class="foot-note"><?= h($application['guardian_phone'] ?: '-') ?></span>
                  </td>
                  <td><?= h($application['parent_whatsapp_phone'] ?: '-') ?></td>
                  <td>
                    <span class="status-chip <?= $application['status'] === 'approved' ? 'status-ok' : ($application['status'] === 'rejected' ? 'status-warn' : '') ?>"><?= h(ucfirst($application['status'])) ?></span>
                  </td>
                  <td>
                    <?php if ($application['status'] === 'pending'): ?>
                      <form method="POST" style="display:grid;gap:6px;min-width:280px;">
                        <input type="hidden" name="application_id" value="<?= h($application['id']) ?>">
                        <select name="application_assigned_class_id" required>
                          <option value="">Assign class</option>
                          <?php foreach ($classes as $classOption): ?>
                            <option value="<?= h($classOption['id']) ?>" <?= (int)$classOption['id'] === (int)$application['preferred_class_id'] ? 'selected' : '' ?>><?= h($classOption['name']) ?></option>
                          <?php endforeach; ?>
                        </select>
                        <select name="application_assigned_teacher_id">
                          <option value="">Assign teacher (optional)</option>
                          <?php foreach ($teachers as $teacherOption): ?>
                            <option value="<?= h($teacherOption['id']) ?>"><?= h($teacherOption['name']) ?> (<?= h($teacherOption['email']) ?>)</option>
                          <?php endforeach; ?>
                        </select>
                        <input type="text" name="application_admin_comment" placeholder="Comment (optional)">
                        <div style="display:flex;gap:6px;">
                          <button class="button primary" type="submit" name="review_public_learner_application" value="1" onclick="this.form.application_decision.value='approve'">Approve</button>
                          <button class="button accent" type="submit" name="review_public_learner_application" value="1" onclick="this.form.application_decision.value='reject'">Reject</button>
                        </div>
                        <input type="hidden" name="application_decision" value="approve">
                      </form>
                    <?php else: ?>
                      <span class="foot-note">Reviewed by admin</span>
                      <?php if (!empty($application['admin_comment'])): ?>
                        <br><span class="foot-note"><?= h($application['admin_comment']) ?></span>
                      <?php endif; ?>
                    <?php endif; ?>
                  </td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="adminTransfersView" class="panel desk-view">
      <h2>Learner Transfer Requests <span class="meta-chip" style="color:#5f3d17;background:#fff1de;border-color:#f2d4aa;">Clearance Workflow</span></h2>
      <p class="sub">Manage parent transfer requests, request inter-department clearances, and finalize printable transfer letters.</p>
      <div class="table-wrap">
        <table>
          <thead>
            <tr>
              <th>Requested</th>
              <th>Learner</th>
              <th>Parent</th>
              <th>Destination</th>
              <th>Teacher Clearance</th>
              <th>Accountant Clearance</th>
              <th>Status</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($transferRequests)): ?>
              <tr><td colspan="8">No transfer requests yet.</td></tr>
            <?php else: ?>
              <?php foreach ($transferRequests as $transfer): ?>
                <tr>
                  <td><?= h($transfer['requested_at']) ?></td>
                  <td>
                    <?= h($transfer['learner_name']) ?><br>
                    <span class="foot-note"><?= h($transfer['reg_number']) ?> | <?= h($transfer['class_name']) ?></span>
                  </td>
                  <td>
                    <?= h($transfer['parent_name']) ?><br>
                    <span class="foot-note"><?= h($transfer['parent_email']) ?></span>
                  </td>
                  <td>
                    <?= h($transfer['destination_school']) ?><br>
                    <span class="foot-note"><?= h($transfer['reason']) ?></span>
                  </td>
                  <td><span class="status-chip <?= $transfer['teacher_status'] === 'approved' ? 'status-ok' : ($transfer['teacher_status'] === 'rejected' ? 'status-warn' : '') ?>"><?= h(ucfirst($transfer['teacher_status'])) ?></span></td>
                  <td><span class="status-chip <?= $transfer['accountant_status'] === 'approved' ? 'status-ok' : ($transfer['accountant_status'] === 'rejected' ? 'status-warn' : '') ?>"><?= h(ucfirst($transfer['accountant_status'])) ?></span></td>
                  <td><span class="status-chip <?= $transfer['status'] === 'completed' ? 'status-ok' : ($transfer['status'] === 'rejected' ? 'status-warn' : '') ?>"><?= h(ucfirst(str_replace('_', ' ', $transfer['status']))) ?></span></td>
                  <td>
                    <form method="POST" style="display:grid;gap:6px;min-width:250px;">
                      <input type="hidden" name="transfer_request_id" value="<?= h($transfer['id']) ?>">
                      <input type="text" name="transfer_admin_comment" placeholder="Comment (optional)">
                      <?php if ($transfer['status'] === 'pending_admin'): ?>
                        <button class="button primary" type="submit" name="send_transfer_clearance">Request Clearance</button>
                        <button class="button accent" type="submit" name="reject_transfer_request">Reject</button>
                      <?php elseif ($transfer['teacher_status'] === 'approved' && $transfer['accountant_status'] === 'approved' && $transfer['status'] !== 'completed' && $transfer['status'] !== 'rejected'): ?>
                        <button class="button primary" type="submit" name="finalize_transfer_request">Finalize + Generate Letter</button>
                        <button class="button accent" type="submit" name="reject_transfer_request">Reject</button>
                      <?php else: ?>
                        <span class="foot-note">Waiting for department clearances or already finalized.</span>
                      <?php endif; ?>
                      <?php if (!empty($transfer['letter_id'])): ?>
                        <span class="status-chip status-ok">Transfer letter available on parent dashboard</span>
                      <?php endif; ?>
                    </form>
                  </td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="adminLearnerPromotionsView" class="panel desk-view">
      <h2>Learner Promotions <span class="meta-chip" style="color:#5f3d17;background:#fff1de;border-color:#f2d4aa;">Annual Progress</span></h2>
      <p class="sub">Batch approve learner form/level promotions. Balances carry forward automatically. Typically run on January 1st.</p>

      <div class="panel-actions" style="margin-bottom:12px; display:flex; gap:8px; flex-wrap:wrap;">
        <form method="POST" style="display:inline;">
          <button type="submit" name="create_batch_promotions" class="button primary" style="width:auto;">
            Create Batch Promotions (Jan 1st)
          </button>
        </form>
        <?php if (!empty($pendingPromotions)): ?>
          <form method="POST" style="display:inline;">
            <button type="submit" name="approve_all_promotions" class="button accent" style="width:auto;">
              Approve All <?= count($pendingPromotions) ?> Pending
            </button>
          </form>
        <?php endif; ?>
      </div>

      <div style="margin-bottom:20px;">
        <h3>Pending Promotions (Batch Approval Required)</h3>
        <?php if (empty($pendingPromotions)): ?>
          <p style="padding:12px; background:#f0f0f0; border-radius:4px; color:#666;">No pending promotions. Click "Create Batch Promotions" to generate promotion requests for all learners.</p>
        <?php else: ?>
          <div class="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>Student</th>
                  <th>Reg Number</th>
                  <th>From Class</th>
                  <th>To Class</th>
                  <th>Balance to Carry</th>
                  <th>Guardian Contact</th>
                  <th>Created</th>
                  <th>Action</th>
                </tr>
              </thead>
              <tbody>
                <?php foreach ($pendingPromotions as $promo): ?>
                  <tr>
                    <td><?= h($promo['full_name']) ?></td>
                    <td><?= h($promo['reg_number']) ?></td>
                    <td><?= h($promo['from_class_name']) ?></td>
                    <td><?= h($promo['to_class_name']) ?></td>
                    <td>
                      <span class="status-chip" style="background:#e8f5e9; border-color:#81c784;">
                        <?= $promo['balance_carried'] > 0 ? 'USD ' . number_format($promo['balance_carried'], 2) : 'No balance' ?>
                      </span>
                    </td>
                    <td>
                      <?= h($promo['guardian_name'] ?? 'N/A') ?><br>
                      <span class="foot-note"><?= h($promo['guardian_phone'] ?? '-') ?></span>
                    </td>
                    <td><?= h(substr($promo['created_at'], 0, 10)) ?></td>
                    <td>
                      <form method="POST" style="display:grid; gap:4px;">
                        <input type="hidden" name="promotion_id" value="<?= h($promo['id']) ?>">
                        <button type="submit" name="approve_promotion" class="button primary" style="width:auto; font-size:12px; padding:6px;">Approve</button>
                        <button type="button" class="button accent" style="width:auto; font-size:12px; padding:6px;" onclick="toggleRejectForm(this)">Reject</button>
                        <div style="display:none; flex-direction:column; gap:4px;" class="reject-form">
                          <textarea name="rejection_reason" placeholder="Reason..." style="font-size:12px; min-height:40px; padding:4px;"></textarea>
                          <button type="submit" name="reject_promotion" class="button accent" style="width:auto; font-size:12px; padding:4px;">Confirm Reject</button>
                        </div>
                      </form>
                    </td>
                  </tr>
                <?php endforeach; ?>
              </tbody>
            </table>
          </div>
        <?php endif; ?>
      </div>

      <div>
        <h3>Promotion History</h3>
        <?php if (empty($promotionHistory)): ?>
          <p style="padding:12px; background:#f0f0f0; border-radius:4px; color:#666;">No promotion history yet.</p>
        <?php else: ?>
          <div class="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>Student</th>
                  <th>Reg Number</th>
                  <th>From Class</th>
                  <th>To Class</th>
                  <th>Balance Carried</th>
                  <th>Status</th>
                  <th>Approved Date</th>
                  <th>Approved By</th>
                </tr>
              </thead>
              <tbody>
                <?php foreach ($promotionHistory as $hist): ?>
                  <tr style="background:<?= $hist['status'] === 'approved' ? '#f1f8f1' : '#fef5f1' ?>;">
                    <td><?= h($hist['full_name']) ?></td>
                    <td><?= h($hist['reg_number']) ?></td>
                    <td><?= h($hist['from_class_name']) ?></td>
                    <td><?= h($hist['to_class_name']) ?></td>
                    <td>
                      <span class="status-chip" style="background:<?= $hist['balance_carried'] > 0 ? '#e8f5e9' : '#fff3e0' ?>; border-color:<?= $hist['balance_carried'] > 0 ? '#81c784' : '#ffb74d' ?>;">
                        <?= $hist['balance_carried'] > 0 ? 'USD ' . number_format($hist['balance_carried'], 2) : 'No balance' ?>
                      </span>
                    </td>
                    <td>
                      <span class="status-chip <?= $hist['status'] === 'approved' ? 'status-ok' : 'status-warn' ?>">
                        <?= h(ucfirst($hist['status'])) ?>
                      </span>
                    </td>
                    <td><?= h($hist['approved_at'] ? substr($hist['approved_at'], 0, 10) : '-') ?></td>
                    <td><?= h($hist['approved_by_name'] ?? '-') ?></td>
                  </tr>
                <?php endforeach; ?>
              </tbody>
            </table>
          </div>
        <?php endif; ?>
      </div>
    </section>

    <section id="adminLeaveRequestsView" class="panel desk-view">
      <h2>Staff Leave Requests <span class="meta-chip" style="color:#203a63;background:#e8efff;border-color:#c4d3ff;">Head Approval Desk</span></h2>
      <p class="sub">Review teacher and ancillary staff leave forms, then approve or reject from head desk.</p>

      <div class="panel-actions" style="margin-bottom:10px;">
        <button type="button" class="button primary" style="width:auto;" id="leaveFilterPendingBtn">Pending</button>
        <button type="button" class="button accent" style="width:auto;" id="leaveFilterApprovedBtn">Approved</button>
        <button type="button" class="button accent" style="width:auto;" id="leaveFilterRejectedBtn">Rejected</button>
        <button type="button" class="button accent" style="width:auto;" id="leaveFilterAllBtn">Show All</button>
      </div>

      <div class="table-wrap">
        <table>
          <thead>
            <tr>
              <th>Submitted</th>
              <th>Staff Member</th>
              <th>Role</th>
              <th>Leave Type</th>
              <th>Period</th>
              <th>Reason</th>
              <th>Attachment</th>
              <th>Status</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($teacherLeaveRequests) && empty($ancillaryLeaveRequests)): ?>
              <tr><td colspan="9">No staff leave requests yet.</td></tr>
            <?php else: ?>
              <?php foreach ($teacherLeaveRequests as $leaveRequest): ?>
                <?php
                  $leaveDocumentPath = trim((string)($leaveRequest['supporting_document_path'] ?? ''));
                  $leaveDocumentAbsolute = $leaveDocumentPath !== '' ? (__DIR__ . '/' . ltrim($leaveDocumentPath, '/\\')) : '';
                  $hasLeaveDocument = $leaveDocumentPath !== '' && is_file($leaveDocumentAbsolute);
                  $leaveDocumentName = trim((string)($leaveRequest['supporting_document_name'] ?? ''));
                  if ($leaveDocumentName === '') {
                    $leaveDocumentName = $hasLeaveDocument ? basename($leaveDocumentPath) : 'No document';
                  }
                ?>
                <tr class="leave-request-row" data-status="<?= h(strtolower((string)$leaveRequest['status'])) ?>">
                  <td><?= h($leaveRequest['created_at']) ?></td>
                  <td>
                    <?= h($leaveRequest['teacher_name']) ?><br>
                    <span class="foot-note"><?= h($leaveRequest['teacher_email']) ?></span>
                  </td>
                  <td><span class="status-chip">TEACHER</span></td>
                  <td><?= h(ucfirst(str_replace('_', ' ', $leaveRequest['leave_type']))) ?></td>
                  <td><?= h($leaveRequest['start_date']) ?> to <?= h($leaveRequest['end_date']) ?></td>
                  <td><?= h($leaveRequest['reason']) ?></td>
                  <td>
                    <?php if ($hasLeaveDocument): ?>
                      <span class="foot-note" style="display:block; margin-bottom:6px;"><?= h($leaveDocumentName) ?></span>
                      <div style="display:flex; gap:6px; flex-wrap:wrap;">
                        <a class="button accent" style="width:auto;" href="<?= h($leaveDocumentPath) ?>" download="<?= h($leaveDocumentName) ?>">Download</a>
                        <a class="button primary" style="width:auto;" href="<?= h($leaveDocumentPath) ?>" target="_blank" rel="noopener">Open / Print</a>
                      </div>
                    <?php else: ?>
                      <span class="foot-note">No document uploaded</span>
                    <?php endif; ?>
                  </td>
                  <td>
                    <span class="status-chip <?= $leaveRequest['status'] === 'approved' ? 'status-ok' : ($leaveRequest['status'] === 'rejected' ? 'status-warn' : '') ?>"><?= h(ucfirst($leaveRequest['status'])) ?></span>
                    <?php if (!empty($leaveRequest['admin_comment'])): ?>
                      <br><span class="foot-note"><?= h($leaveRequest['admin_comment']) ?></span>
                    <?php endif; ?>
                  </td>
                  <td>
                    <?php if ($leaveRequest['status'] === 'pending'): ?>
                      <form method="POST" style="display:grid;gap:6px;min-width:240px;">
                        <input type="hidden" name="leave_request_id" value="<?= h($leaveRequest['id']) ?>">
                        <input type="text" name="leave_admin_comment" placeholder="Comment (optional)">
                        <input type="hidden" name="leave_decision" value="approve">
                        <div style="display:flex;gap:6px;">
                          <button class="button primary" type="submit" name="review_teacher_leave_request" onclick="this.form.leave_decision.value='approve'">Approve</button>
                          <button class="button accent" type="submit" name="review_teacher_leave_request" onclick="this.form.leave_decision.value='reject'">Reject</button>
                        </div>
                      </form>
                    <?php else: ?>
                      <span class="foot-note">Already reviewed</span>
                    <?php endif; ?>
                  </td>
                </tr>
              <?php endforeach; ?>

              <?php foreach ($ancillaryLeaveRequests as $leaveRequest): ?>
                <?php
                  $leaveDocumentPath = trim((string)($leaveRequest['supporting_document_path'] ?? ''));
                  $leaveDocumentAbsolute = $leaveDocumentPath !== '' ? (__DIR__ . '/' . ltrim($leaveDocumentPath, '/\\')) : '';
                  $hasLeaveDocument = $leaveDocumentPath !== '' && is_file($leaveDocumentAbsolute);
                  $leaveDocumentName = trim((string)($leaveRequest['supporting_document_name'] ?? ''));
                  if ($leaveDocumentName === '') {
                    $leaveDocumentName = $hasLeaveDocument ? basename($leaveDocumentPath) : 'No document';
                  }
                ?>
                <tr class="leave-request-row" data-status="<?= h(strtolower((string)$leaveRequest['status'])) ?>">
                  <td><?= h($leaveRequest['created_at']) ?></td>
                  <td>
                    <?= h($leaveRequest['ancillary_name']) ?><br>
                    <span class="foot-note"><?= h($leaveRequest['ancillary_email']) ?></span>
                  </td>
                  <td><span class="status-chip">ANCILLARY</span></td>
                  <td><?= h(ucfirst(str_replace('_', ' ', $leaveRequest['leave_type']))) ?></td>
                  <td><?= h($leaveRequest['start_date']) ?> to <?= h($leaveRequest['end_date']) ?></td>
                  <td><?= h($leaveRequest['reason']) ?></td>
                  <td>
                    <?php if ($hasLeaveDocument): ?>
                      <span class="foot-note" style="display:block; margin-bottom:6px;"><?= h($leaveDocumentName) ?></span>
                      <div style="display:flex; gap:6px; flex-wrap:wrap;">
                        <a class="button accent" style="width:auto;" href="<?= h($leaveDocumentPath) ?>" download="<?= h($leaveDocumentName) ?>">Download</a>
                        <a class="button primary" style="width:auto;" href="<?= h($leaveDocumentPath) ?>" target="_blank" rel="noopener">Open / Print</a>
                      </div>
                    <?php else: ?>
                      <span class="foot-note">No document uploaded</span>
                    <?php endif; ?>
                  </td>
                  <td>
                    <span class="status-chip <?= $leaveRequest['status'] === 'approved' ? 'status-ok' : ($leaveRequest['status'] === 'rejected' ? 'status-warn' : '') ?>"><?= h(ucfirst($leaveRequest['status'])) ?></span>
                    <?php if (!empty($leaveRequest['admin_comment'])): ?>
                      <br><span class="foot-note"><?= h($leaveRequest['admin_comment']) ?></span>
                    <?php endif; ?>
                  </td>
                  <td>
                    <?php if ($leaveRequest['status'] === 'pending'): ?>
                      <form method="POST" style="display:grid;gap:6px;min-width:240px;">
                        <input type="hidden" name="leave_request_id" value="<?= h($leaveRequest['id']) ?>">
                        <input type="text" name="leave_admin_comment" placeholder="Comment (optional)">
                        <input type="hidden" name="leave_decision" value="approve">
                        <div style="display:flex;gap:6px;">
                          <button class="button primary" type="submit" name="review_ancillary_leave_request" onclick="this.form.leave_decision.value='approve'">Approve</button>
                          <button class="button accent" type="submit" name="review_ancillary_leave_request" onclick="this.form.leave_decision.value='reject'">Reject</button>
                        </div>
                      </form>
                    <?php else: ?>
                      <span class="foot-note">Already reviewed</span>
                    <?php endif; ?>
                  </td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="adminWorkloadView" class="panel desk-view">
      <h2>Teacher Workload Snapshot <span class="meta-chip" style="color:#143a72;background:var(--brand-ice);border-color:#bfd4f4;">Live</span></h2>
      <p class="sub">Track distribution to avoid overloading one educator while others remain underutilized.</p>
      <div class="search-bar record-filter-bar" data-table-id="teacherLoadTable">
        <select class="record-filter-field" aria-label="Teacher load filter field">
          <option value="all">All Columns</option>
          <option value="0">Teacher</option>
          <option value="3">Load Status</option>
        </select>
        <input class="record-filter-input" type="search" placeholder="Search teacher workload...">
      </div>
      <div class="table-wrap">
        <table id="teacherLoadTable">
          <thead>
            <tr>
              <th>Teacher</th>
              <th>Classes Covered</th>
              <th>Subjects Assigned</th>
              <th>Load Status</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($teacherLoads)): ?>
              <tr><td colspan="4">No teachers found yet.</td></tr>
            <?php else: ?>
              <?php foreach ($teacherLoads as $row): ?>
                <?php
                  $subject_count = (int)$row['subject_count'];
                  $load_status = $subject_count >= 10 ? 'High' : ($subject_count >= 4 ? 'Balanced' : 'Light');
                ?>
                <tr>
                  <td><?= h($row['name']) ?></td>
                  <td><?= h($row['class_count']) ?></td>
                  <td><?= h($subject_count) ?></td>
                  <td>
                    <span class="status-chip <?= $load_status === 'Balanced' ? 'status-ok' : 'status-warn' ?>"><?= h($load_status) ?></span>
                  </td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="adminRegistryView" class="panel desk-view">
      <h2>Assignment Registry <span class="meta-chip" style="color:#7b5f17;background:#fff5dc;border-color:#f3d487;">Detailed View</span></h2>
      <p class="sub">Search across teacher, class, or subject to quickly verify current timetabling ownership.</p>
      <div class="search-bar record-filter-bar" data-table-id="assignmentTable">
        <select id="assignmentSearchField" class="record-filter-field" aria-label="Assignment registry filter field">
          <option value="all">All Columns</option>
          <option value="0">Teacher</option>
          <option value="1">Email</option>
          <option value="2">Class</option>
          <option value="3">Subject</option>
        </select>
        <input id="assignmentSearch" class="record-filter-input" type="search" placeholder="Search teacher, class, or subject...">
      </div>
      <div class="table-wrap">
        <table id="assignmentTable">
          <thead>
            <tr>
              <th>Teacher</th>
              <th>Email</th>
              <th>Class</th>
              <th>Subject</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($assignments)): ?>
              <tr><td colspan="4">No assignments have been saved yet.</td></tr>
            <?php else: ?>
              <?php foreach ($assignments as $assignment): ?>
                <tr>
                  <td><?= h($assignment['teacher']) ?></td>
                  <td><?= h($assignment['email']) ?></td>
                  <td><?= h($assignment['class_name']) ?></td>
                  <td><?= h($assignment['subject_name']) ?></td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
      <p class="foot-note">Tip: A complete setup should have at least one subject assignment for each class listed in the system.</p>
    </section>

    <section id="adminCoverageView" class="panel desk-view">
      <h2>Class Coverage Quality</h2>
      <p class="sub">Measure curriculum coverage by class to identify gaps before lesson plans are finalized.</p>
      <div class="table-wrap">
        <table>
          <thead>
            <tr>
              <th>Class</th>
              <th>Assigned Subjects</th>
              <th>Total Subjects</th>
              <th>Coverage</th>
            </tr>
          </thead>
          <tbody>
            <?php foreach ($classCoverage as $coverage): ?>
              <?php
                $assigned = (int)$coverage['assigned_subjects'];
                $total = max((int)$coverage['total_subjects'], 1);
                $coverage_percent = (int)round(($assigned / $total) * 100);
              ?>
              <tr>
                <td><?= h($coverage['name']) ?></td>
                <td><?= h($assigned) ?></td>
                <td><?= h($total) ?></td>
                <td>
                  <span class="status-chip <?= $coverage_percent >= 60 ? 'status-ok' : 'status-warn' ?>"><?= h($coverage_percent) ?>%</span>
                </td>
              </tr>
            <?php endforeach; ?>
          </tbody>
        </table>
      </div>
    </section>

    <section id="adminTeacherDocumentsView" class="panel desk-view">
      <h2>Documents from Teacher <span class="meta-chip" style="color:#143a72;background:var(--brand-ice);border-color:#bfd4f4;">Review Desk</span></h2>
      <p class="sub">Download, open for printing, or send correction comments back to teachers. Items marked <strong>Needs correction</strong> are highlighted on teacher desk.</p>

      <div class="panel-actions">
        <button type="button" class="button primary" style="width:auto;" id="toggleAdminTeacherDocumentsBtn">Show Documents from Teacher</button>
      </div>

      <div class="search-bar record-filter-bar" data-table-id="teacherDocumentsTable">
        <select id="teacherDocumentSearchField" class="record-filter-field" aria-label="Teacher documents filter field">
          <option value="all">All Columns</option>
          <option value="0">Submitted</option>
          <option value="1">Teacher</option>
          <option value="2">Class</option>
          <option value="3">Type</option>
          <option value="4">Title</option>
          <option value="6">Status</option>
        </select>
        <input id="teacherDocumentSearch" class="record-filter-input" type="search" placeholder="Search teacher, class, document type, title, or status...">
      </div>

      <div id="adminTeacherDocumentsTableView" class="view-toggle">
      <div class="table-wrap">
        <table id="teacherDocumentsTable" class="teacher-documents-table">
          <thead>
            <tr>
              <th>Submitted</th>
              <th>Teacher</th>
              <th>Class</th>
              <th>Type</th>
              <th>Title</th>
              <th>File</th>
              <th>Status</th>
              <th>Admin Review</th>
            </tr>
          </thead>
          <tbody>
            <?php if (empty($teacherDocumentsForAdmin)): ?>
              <tr><td colspan="8">No teacher documents submitted yet.</td></tr>
            <?php else: ?>
              <?php foreach ($teacherDocumentsForAdmin as $doc): ?>
                <tr>
                  <td><?= h($doc['created_at']) ?></td>
                  <td><?= h($doc['teacher_name']) ?><br><small><?= h($doc['teacher_email']) ?></small></td>
                  <td><?= h($doc['class_name']) ?><?= !empty($doc['subject_name']) ? ' / ' . h($doc['subject_name']) : '' ?></td>
                  <td><?= h($teacherDocumentTypes[$doc['document_type']] ?? $doc['document_type']) ?></td>
                  <td>
                    <strong><?= h($doc['title']) ?></strong>
                    <?php if (!empty($doc['description'])): ?><br><small><?= h($doc['description']) ?></small><?php endif; ?>
                  </td>
                  <td>
                    <a href="<?= h($doc['file_path']) ?>" download>Download</a><br>
                    <a href="<?= h($doc['file_path']) ?>" target="_blank" rel="noopener">Open / Print</a><br>
                    <small><?= h($doc['original_name']) ?> (<?= h(format_file_size($doc['file_size'])) ?>)</small>
                  </td>
                  <td>
                    <span class="status-chip <?= in_array($doc['status'], ['approved', 'reviewed'], true) ? 'status-ok' : 'status-warn' ?>">
                      <?= h(ucfirst(str_replace('_', ' ', $doc['status']))) ?>
                    </span>
                    <?php if (!empty($doc['reviewed_at'])): ?><br><small>Reviewed: <?= h($doc['reviewed_at']) ?></small><?php endif; ?>
                  </td>
                  <td>
                    <form method="POST" style="display:grid; gap:6px; min-width:220px;">
                      <input type="hidden" name="teacher_document_id" value="<?= h($doc['id']) ?>">
                      <select name="teacher_document_status" required>
                        <option value="reviewed" <?= $doc['status'] === 'reviewed' ? 'selected' : '' ?>>Reviewed</option>
                        <option value="needs_correction" <?= $doc['status'] === 'needs_correction' ? 'selected' : '' ?>>Needs Correction</option>
                        <option value="approved" <?= $doc['status'] === 'approved' ? 'selected' : '' ?>>Approved</option>
                      </select>
                      <textarea name="teacher_document_comment" placeholder="Comment to teacher..."><?= h($doc['admin_comment']) ?></textarea>
                      <button class="button accent" type="submit" name="review_teacher_document">Send to Teacher</button>
                    </form>
                  </td>
                </tr>
              <?php endforeach; ?>
            <?php endif; ?>
          </tbody>
        </table>
      </div>
      </div>
    </section>

    <section id="adminAssetsRegisterView" class="panel desk-view">
      <h2>School Assets Register <span class="meta-chip" style="color:#143a72;background:var(--brand-ice);border-color:#bfd4f4;">Shared with Accountant Desk</span></h2>
      <p class="sub">Official register of approved assets. Records are fed automatically from teacher inventory after accountant verification.</p>

      <div class="panel-actions">
        <button type="button" class="button primary" style="width:auto;" id="toggleAdminAssetsRegisterBtn">Show School Assets Register</button>
        <button type="button" class="button accent" style="width:auto;" id="printAdminAssetsRegisterBtn" disabled>Print</button>
        <button type="button" class="button accent" style="width:auto;" id="downloadAdminAssetsRegisterPdfBtn" disabled>Download PDF</button>
      </div>

      <div id="adminAssetsRegisterTableView" class="view-toggle">
        <div class="table-wrap">
          <table id="adminAssetsRegisterTable">
            <thead>
              <tr>
                <th>Approved On</th>
                <th>Teacher</th>
                <th>Class</th>
                <th>Category</th>
                <th>Asset Item</th>
                <th>Quantity</th>
                <th>Condition</th>
                <th>Source Record</th>
                <th>Approved By</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($schoolAssetsRows)): ?>
                <tr><td colspan="9">No approved assets are in the register yet.</td></tr>
              <?php else: ?>
                <?php foreach ($schoolAssetsRows as $asset): ?>
                  <tr>
                    <td><?= h($asset['approved_at'] ?: $asset['created_at']) ?></td>
                    <td><?= h($asset['teacher_name']) ?><br><small><?= h($asset['teacher_email']) ?></small></td>
                    <td><?= h($asset['class_name']) ?></td>
                    <td><?= h(inventory_category_label((string)$asset['category'])) ?></td>
                    <td>
                      <strong><?= h($asset['item_name']) ?></strong>
                      <?php if (!empty($asset['inventory_note'])): ?><br><small><?= h($asset['inventory_note']) ?></small><?php endif; ?>
                    </td>
                    <td><?= h((int)$asset['quantity']) ?></td>
                    <td><?= h($asset['item_condition'] ?: '-') ?></td>
                    <td>#<?= h((int)$asset['source_inventory_id']) ?></td>
                    <td><?= h($asset['approver_name'] ?: '-') ?></td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </div>
    </section>
    </div>
    </div>
  </div>

  <script>
    const subjects = <?= json_encode($subjects, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;
    const classSelect = document.getElementById('classSelect');
    const classSelectSearch = document.getElementById('classSelectSearch');
    const teacherSelect = document.getElementById('teacher-select');
    const teacherSelectSearch = document.getElementById('teacherSelectSearch');
    const subjectSelectSearch = document.getElementById('subjectSelectSearch');
    const subjectBox = document.getElementById('subjectCheckboxes');
    const selectedCount = document.getElementById('selectedCount');
    const availableCount = document.getElementById('availableCount');
    const assignmentSearch = document.getElementById('assignmentSearch');
    const assignmentRows = Array.from(document.querySelectorAll('#assignmentTable tbody tr'));
    const teacherDocumentSearch = document.getElementById('teacherDocumentSearch');
    const teacherDocumentRows = Array.from(document.querySelectorAll('#teacherDocumentsTable tbody tr'));
    const leaveFilterPendingBtn = document.getElementById('leaveFilterPendingBtn');
    const leaveFilterApprovedBtn = document.getElementById('leaveFilterApprovedBtn');
    const leaveFilterRejectedBtn = document.getElementById('leaveFilterRejectedBtn');
    const leaveFilterAllBtn = document.getElementById('leaveFilterAllBtn');
    const leaveRequestRows = Array.from(document.querySelectorAll('.leave-request-row'));
    const parentSelect = document.getElementById('parent-learner');
    const announcementAudience = document.getElementById('announcement-audience');
    const announcementTargetType = document.getElementById('announcement-target-type');
    const announcementTargetClassWrap = document.getElementById('announcement-target-class-wrap');
    const announcementTargetLearnerWrap = document.getElementById('announcement-target-learner-wrap');
    const announcementTargetClass = document.getElementById('announcement-target-class');
    const announcementTargetLearner = document.getElementById('announcement-target-learner');
    const adminTeacherDocumentsTableView = document.getElementById('adminTeacherDocumentsTableView');
    const toggleAdminTeacherDocumentsBtn = document.getElementById('toggleAdminTeacherDocumentsBtn');
    const adminAssetsRegisterTableView = document.getElementById('adminAssetsRegisterTableView');
    const toggleAdminAssetsRegisterBtn = document.getElementById('toggleAdminAssetsRegisterBtn');
    const printAdminAssetsRegisterBtn = document.getElementById('printAdminAssetsRegisterBtn');
    const printStaffDetailsReportBtn = document.getElementById('printStaffDetailsReportBtn');
    const printAncillaryStaffReportBtn = document.getElementById('printAncillaryStaffReportBtn');
    const downloadAdminAssetsRegisterPdfBtn = document.getElementById('downloadAdminAssetsRegisterPdfBtn');
    const adminAssetsRegisterTable = document.getElementById('adminAssetsRegisterTable');
    const admissionClassSelect = document.getElementById('admission_class_id');
    const admissionClassSearch = document.getElementById('admissionClassSearch');
    const adminAdmissionFormView = document.getElementById('adminAdmissionFormView');
    const toggleAdminAdmissionFormBtn = document.getElementById('toggleAdminAdmissionFormBtn');
    const adminAdmissionRegisterView = document.getElementById('adminAdmissionRegisterView');
    const toggleAdminAdmissionRegisterBtn = document.getElementById('toggleAdminAdmissionRegisterBtn');
    const printAdminAdmissionRegisterBtn = document.getElementById('printAdminAdmissionRegisterBtn');
    const downloadAdminAdmissionRegisterPdfBtn = document.getElementById('downloadAdminAdmissionRegisterPdfBtn');
    const adminAdmissionRegisterTable = document.getElementById('adminAdmissionRegisterTable');
    const printDailyAttendanceSummaryBtn = document.getElementById('printDailyAttendanceSummaryBtn');
    const dailyAttendanceSummaryTable = document.getElementById('dailyAttendanceSummaryTable');
    const printEnrolmentSummaryBtn = document.getElementById('printEnrolmentSummaryBtn');
    const downloadEnrolmentSummaryPdfBtn = document.getElementById('downloadEnrolmentSummaryPdfBtn');
    const enrolmentSummaryTable = document.getElementById('enrolmentSummaryTable');
    const printSystemLogBtn = document.getElementById('printSystemLogBtn');
    const downloadSystemLogPdfBtn = document.getElementById('downloadSystemLogPdfBtn');
    const adminSystemLogTable = document.getElementById('adminSystemLogTable');
    const studentIdClassFilter = document.getElementById('studentIdClassFilter');
    const studentIdLearnerSearch = document.getElementById('studentIdLearnerSearch');
    const studentIdLearnerSelect = document.getElementById('studentIdLearnerSelect');
    const generateSingleStudentIdBtn = document.getElementById('generateSingleStudentIdBtn');
    const generateClassStudentIdsBtn = document.getElementById('generateClassStudentIdsBtn');
    const printStudentIdCardsBtn = document.getElementById('printStudentIdCardsBtn');
    const downloadStudentIdCardsPdfBtn = document.getElementById('downloadStudentIdCardsPdfBtn');
    const studentIdCardsCanvas = document.getElementById('studentIdCardsCanvas');
    const studentIdSerialPrefix = document.getElementById('studentIdSerialPrefix');
    const studentIdIssueDate = document.getElementById('studentIdIssueDate');
    const studentIdExpiryDate = document.getElementById('studentIdExpiryDate');
    const studentIdRenewalYear = document.getElementById('studentIdRenewalYear');
    const staffUserSelect = document.getElementById('staff_user_id');
    const ancillaryUserSelect = document.getElementById('ancillary_user_id');
    const staffFullNameInput = document.getElementById('staff_full_name');
    const staffEmailInput = document.getElementById('staff_email');
    const staffSexInput = document.getElementById('staff_sex');
    const staffDobInput = document.getElementById('staff_dob');
    const staffEcInput = document.getElementById('staff_ec_number');
    const staffNationalIdInput = document.getElementById('staff_national_id');
    const staffQualificationsInput = document.getElementById('staff_qualifications');
    const staffSubjectSpecializationInput = document.getElementById('staff_subject_specialization');
    const adminStaffDetailsTable = document.getElementById('adminStaffDetailsTable');
    const ancillaryFullNameInput = document.getElementById('ancillary_full_name');
    const ancillaryEmailInput = document.getElementById('ancillary_email');
    const ancillarySexInput = document.getElementById('ancillary_sex');
    const ancillaryDobInput = document.getElementById('ancillary_dob');
    const ancillaryEcInput = document.getElementById('ancillary_ec_number');
    const ancillaryNationalIdInput = document.getElementById('ancillary_national_id');
    const ancillaryWorkProfileInput = document.getElementById('ancillary_work_profile');
    const ancillaryQualificationsInput = document.getElementById('ancillary_qualifications');
    const adminAncillaryStaffTable = document.getElementById('adminAncillaryStaffTable');
    const studentIdLearners = <?= json_encode($studentIdLearners, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;

    const reportMeta = {
      schoolName: <?= json_encode($schoolName, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      schoolAddress: <?= json_encode($schoolAddress, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      schoolContact: <?= json_encode($schoolContact, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      schoolMotto: <?= json_encode($schoolMotto, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      palette: {
        ink: <?= json_encode($paletteInk, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        muted: <?= json_encode($paletteMuted, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        brandNavy: <?= json_encode($paletteBrandNavy, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        brandNavyDeep: <?= json_encode($paletteBrandNavyDeep, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        brandGold: <?= json_encode($paletteBrandGold, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        brandIce: <?= json_encode($paletteBrandIce, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        patchSky: <?= json_encode($palettePatchSky, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        patchYellow: <?= json_encode($palettePatchYellow, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>
      },
      preparedBy: 'Admin Desk',
      logoDataUri: <?= json_encode($schoolLogoDataUri, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      logoPath: <?= json_encode($resolvedSchoolLogoPath !== '' ? $resolvedSchoolLogoPath : $defaultSchoolLogoPath, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
      headSignaturePath: <?= json_encode($headSignaturePath, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>
    };

    const schoolThemePresets = <?= json_encode($themePresets, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;

    let renderedStudentIdCards = [];

    function wireSelectSearch(searchEl, selectEl, labels) {
      if (!searchEl || !selectEl) {
        return;
      }

      function applyFilter() {
        const term = searchEl.value.trim().toLowerCase();
        let hasAny = false;
        const visibleOptions = [];
        let changedSelection = false;

        Array.from(selectEl.options).forEach((option, idx) => {
          if (idx === 0) {
            option.style.display = '';
            return;
          }
          const matches = term === '' || option.textContent.toLowerCase().includes(term);
          option.style.display = matches ? '' : 'none';
          if (!matches && option.selected) {
            selectEl.value = String(selectEl.options[0]?.value || '');
            changedSelection = true;
          }
          if (matches) {
            hasAny = true;
            visibleOptions.push(option);
          }
        });

        if (selectEl.options[0]) {
          selectEl.options[0].text = hasAny ? labels.defaultLabel : labels.emptyLabel;
        }

        // Auto-pick the closest visible match when the user types a search term.
        if (term !== '') {
          const currentVisible = visibleOptions.some(option => option.value === selectEl.value);
          if (!currentVisible) {
            const startsWithMatch = visibleOptions.find(option => option.textContent.toLowerCase().startsWith(term));
            const nextOption = startsWithMatch || visibleOptions[0] || null;
            if (nextOption && selectEl.value !== nextOption.value) {
              selectEl.value = nextOption.value;
              changedSelection = true;
            }
          }
        }

        if (changedSelection) {
          selectEl.dispatchEvent(new Event('change', { bubbles: true }));
        }
      }

      searchEl.addEventListener('input', applyFilter);
      applyFilter();
    }

    function filterSubjectCheckboxes() {
      if (!subjectSelectSearch) {
        return;
      }
      const term = subjectSelectSearch.value.trim().toLowerCase();
      const items = Array.from(subjectBox.querySelectorAll('.subject-item'));
      items.forEach(item => {
        const text = item.textContent.toLowerCase();
        item.style.display = term === '' || text.includes(term) ? '' : 'none';
      });
    }

    function updateSelectionCount() {
      const selected = subjectBox.querySelectorAll('input[type="checkbox"]:checked').length;
      selectedCount.textContent = `${selected} selected`;
    }

    function renderSubjectsForClass() {
      const classId = Number(classSelect.value);
      subjectBox.innerHTML = '';

      if (!classId) {
        subjectBox.innerHTML = '<div class="subject-hint">Select a class to load subjects.</div>';
        availableCount.textContent = '0 available';
        selectedCount.textContent = '0 selected';
        return;
      }

      const filtered = subjects.filter(subject => Number(subject.class_id) === classId);
      availableCount.textContent = `${filtered.length} available`;

      if (!filtered.length) {
        subjectBox.innerHTML = '<div class="subject-hint">No subjects were found for this class.</div>';
        selectedCount.textContent = '0 selected';
        return;
      }

      const html = filtered.map(subject => {
        return `
          <label class="subject-item">
            <input type="checkbox" name="subjects[]" value="${subject.id}">
            <span>${subject.name}</span>
          </label>
        `;
      }).join('');

      subjectBox.innerHTML = html;
      subjectBox.querySelectorAll('input[type="checkbox"]').forEach(box => {
        box.addEventListener('change', updateSelectionCount);
      });
      updateSelectionCount();
      filterSubjectCheckboxes();
    }

    function getVisibleTableDataset(tableEl) {
      if (!tableEl) {
        return { headers: [], rows: [] };
      }
      const headers = Array.from(tableEl.querySelectorAll('thead th')).map(th => th.textContent.trim());
      const rows = Array.from(tableEl.querySelectorAll('tbody tr'))
        .filter(row => row.style.display !== 'none')
        .map(row => Array.from(row.querySelectorAll('td')).map(td => td.textContent.trim()));
      return { headers, rows };
    }

    function openReportPreview(modeLabel, tableEl) {
      const dataset = getVisibleTableDataset(tableEl);
      if (!dataset.rows.length) {
        window.alert('No visible data to export.');
        return;
      }

      const reportWindow = window.open('', '_blank');
      if (!reportWindow) {
        window.alert('Popup blocked. Please allow popups and try again.');
        return;
      }

      const generatedAt = new Date().toLocaleString();
      const headerHtml = dataset.headers.map(h => `<th>${h}</th>`).join('');
      const bodyHtml = dataset.rows.map(row => `<tr>${row.map(col => `<td>${col}</td>`).join('')}</tr>`).join('');
      const logoSrc = reportMeta.logoDataUri && reportMeta.logoDataUri !== '' ? reportMeta.logoDataUri : reportMeta.logoPath;

      reportWindow.document.write(`
        <html>
          <head>
            <title>${reportMeta.schoolName} - ${modeLabel}</title>
            <style>
              body { font-family: Arial, sans-serif; padding: 18px; color: ${reportMeta.palette.ink}; }
              .head { display:flex; gap:12px; align-items:center; margin-bottom:12px; }
              .logo { width:74px; height:74px; object-fit:contain; border:1px solid #d7d7d7; border-radius:10px; padding:4px; }
              h1 { margin:0; font-size: 20px; color:${reportMeta.palette.brandNavy}; }
              .meta { margin: 3px 0; font-size: 13px; }
              .motto { margin-top: 4px; color:${reportMeta.palette.muted}; font-style: italic; }
              .gen { margin: 10px 0 14px; font-size: 12px; }
              table { width: 100%; border-collapse: collapse; font-size: 12px; }
              th, td { border: 1px solid #cfcfcf; padding: 8px; text-align: left; }
              th { background: ${reportMeta.palette.brandIce}; color: ${reportMeta.palette.brandNavy}; }
            </style>
          </head>
          <body>
            <div class="head">
              <img class="logo" src="${logoSrc}" alt="School logo">
              <div>
                <h1>${reportMeta.schoolName}</h1>
                <div class="meta">${reportMeta.schoolAddress}</div>
                <div class="meta">${reportMeta.schoolContact}</div>
                <div class="motto">${reportMeta.schoolMotto}</div>
              </div>
            </div>
            <div class="gen">Report: ${modeLabel} | Prepared By: ${reportMeta.preparedBy} | Generated: ${generatedAt}</div>
            <table>
              <thead><tr>${headerHtml}</tr></thead>
              <tbody>${bodyHtml}</tbody>
            </table>
          </body>
        </html>
      `);
      reportWindow.document.close();
      reportWindow.focus();
      reportWindow.print();
    }

    function openA3ReportPreview(modeLabel, tableEl) {
      const dataset = getVisibleTableDataset(tableEl);
      if (!dataset.rows.length) {
        window.alert('No visible data to export.');
        return;
      }

      const reportWindow = window.open('', '_blank');
      if (!reportWindow) {
        window.alert('Popup blocked. Please allow popups and try again.');
        return;
      }

      const generatedAt = new Date().toLocaleString();
      const headerHtml = dataset.headers.map(h => `<th>${h}</th>`).join('');
      const bodyHtml = dataset.rows.map(row => `<tr>${row.map(col => `<td>${col}</td>`).join('')}</tr>`).join('');
      const logoSrc = reportMeta.logoDataUri && reportMeta.logoDataUri !== '' ? reportMeta.logoDataUri : reportMeta.logoPath;

      reportWindow.document.write(`
        <html>
          <head>
            <title>${reportMeta.schoolName} - ${modeLabel}</title>
            <style>
              @page { size: A3 landscape; margin: 12mm; }
              body { font-family: Arial, sans-serif; padding: 12px; color: ${reportMeta.palette.ink}; }
              .head { display:flex; gap:12px; align-items:center; margin-bottom:12px; }
              .logo { width:80px; height:80px; object-fit:contain; border:1px solid #d7d7d7; border-radius:10px; padding:4px; }
              h1 { margin:0; font-size: 22px; color:${reportMeta.palette.brandNavy}; }
              .meta { margin: 3px 0; font-size: 13px; }
              .motto { margin-top: 4px; color:${reportMeta.palette.muted}; font-style: italic; }
              .gen { margin: 10px 0 14px; font-size: 12px; }
              table { width: 100%; border-collapse: collapse; font-size: 10px; table-layout: fixed; }
              th, td { border: 1px solid #cfcfcf; padding: 6px; text-align: left; vertical-align: top; word-wrap: break-word; }
              th { background: ${reportMeta.palette.brandIce}; color: ${reportMeta.palette.brandNavy}; }
            </style>
          </head>
          <body>
            <div class="head">
              <img class="logo" src="${logoSrc}" alt="School logo">
              <div>
                <h1>${reportMeta.schoolName}</h1>
                <div class="meta">${reportMeta.schoolAddress}</div>
                <div class="meta">${reportMeta.schoolContact}</div>
                <div class="motto">${reportMeta.schoolMotto}</div>
              </div>
            </div>
            <div class="gen">Report: ${modeLabel} | Prepared By: ${reportMeta.preparedBy} | Generated: ${generatedAt}</div>
            <table>
              <thead><tr>${headerHtml}</tr></thead>
              <tbody>${bodyHtml}</tbody>
            </table>
          </body>
        </html>
      `);
      reportWindow.document.close();
      reportWindow.focus();
      reportWindow.print();
    }

    function populateStaffDetailsForm() {
      if (!staffUserSelect) {
        return;
      }
      if (staffUserSelect.value === '' && staffUserSelect.options.length > 1) {
        staffUserSelect.selectedIndex = 1;
      }
      const selectedOption = staffUserSelect.options[staffUserSelect.selectedIndex];
      if (!selectedOption || selectedOption.value === '') {
        if (staffFullNameInput) staffFullNameInput.value = '';
        if (staffEmailInput) staffEmailInput.value = '';
        if (staffSexInput) staffSexInput.value = '';
        if (staffDobInput) staffDobInput.value = '';
        if (staffEcInput) staffEcInput.value = '';
        if (staffNationalIdInput) staffNationalIdInput.value = '';
        if (staffQualificationsInput) staffQualificationsInput.value = '';
        if (staffSubjectSpecializationInput) staffSubjectSpecializationInput.value = '';
        return;
      }
      if (staffFullNameInput) staffFullNameInput.value = selectedOption.getAttribute('data-full-name') || '';
      if (staffEmailInput) staffEmailInput.value = selectedOption.getAttribute('data-email') || '';
      if (staffSexInput) staffSexInput.value = selectedOption.getAttribute('data-sex') || '';
      if (staffDobInput) staffDobInput.value = selectedOption.getAttribute('data-dob') || '';
      if (staffEcInput) staffEcInput.value = selectedOption.getAttribute('data-ec') || '';
      if (staffNationalIdInput) staffNationalIdInput.value = selectedOption.getAttribute('data-national-id') || '';
      if (staffQualificationsInput) staffQualificationsInput.value = selectedOption.getAttribute('data-qualifications') || '';
      if (staffSubjectSpecializationInput) staffSubjectSpecializationInput.value = selectedOption.getAttribute('data-subject-specialization') || '';
    }

    function populateAncillaryStaffForm() {
      if (!ancillaryUserSelect) {
        return;
      }
      if (ancillaryUserSelect.value === '' && ancillaryUserSelect.options.length > 1) {
        ancillaryUserSelect.selectedIndex = 1;
      }
      const selectedOption = ancillaryUserSelect.options[ancillaryUserSelect.selectedIndex];
      if (!selectedOption || selectedOption.value === '') {
        if (ancillaryFullNameInput) ancillaryFullNameInput.value = '';
        if (ancillaryEmailInput) ancillaryEmailInput.value = '';
        if (ancillarySexInput) ancillarySexInput.value = '';
        if (ancillaryDobInput) ancillaryDobInput.value = '';
        if (ancillaryEcInput) ancillaryEcInput.value = '';
        if (ancillaryNationalIdInput) ancillaryNationalIdInput.value = '';
        if (ancillaryWorkProfileInput) ancillaryWorkProfileInput.value = '';
        if (ancillaryQualificationsInput) ancillaryQualificationsInput.value = '';
        return;
      }
      if (ancillaryFullNameInput) ancillaryFullNameInput.value = selectedOption.getAttribute('data-full-name') || '';
      if (ancillaryEmailInput) ancillaryEmailInput.value = selectedOption.getAttribute('data-email') || '';
      if (ancillarySexInput) ancillarySexInput.value = selectedOption.getAttribute('data-sex') || '';
      if (ancillaryDobInput) ancillaryDobInput.value = selectedOption.getAttribute('data-dob') || '';
      if (ancillaryEcInput) ancillaryEcInput.value = selectedOption.getAttribute('data-ec') || '';
      if (ancillaryNationalIdInput) ancillaryNationalIdInput.value = selectedOption.getAttribute('data-national-id') || '';
      if (ancillaryWorkProfileInput) ancillaryWorkProfileInput.value = selectedOption.getAttribute('data-work-profile') || '';
      if (ancillaryQualificationsInput) ancillaryQualificationsInput.value = selectedOption.getAttribute('data-qualifications') || '';
    }

    const adminTogglePanelRegistry = [];

    function closeOtherAdminTogglePanels(activeCfg) {
      if (!activeCfg || !activeCfg.viewEl) {
        return;
      }

      const activeScope = activeCfg.viewEl.closest('.desk-view') || activeCfg.viewEl.parentElement;
      if (!activeScope) {
        return;
      }

      adminTogglePanelRegistry.forEach(cfg => {
        if (!cfg || cfg === activeCfg || !cfg.viewEl) {
          return;
        }

        const scope = cfg.viewEl.closest('.desk-view') || cfg.viewEl.parentElement;
        if (scope !== activeScope) {
          return;
        }

        cfg.viewEl.classList.remove('active');
        if (cfg.toggleBtn) {
          cfg.toggleBtn.textContent = cfg.showLabel;
        }
        (cfg.actionButtons || []).forEach(btn => {
          if (btn) {
            btn.disabled = true;
          }
        });
      });
    }

    function wireToggleAndActions(cfg) {
      if (!cfg.viewEl || !cfg.toggleBtn) {
        return;
      }

      adminTogglePanelRegistry.push(cfg);

      cfg.toggleBtn.addEventListener('click', function () {
        const show = !cfg.viewEl.classList.contains('active');
        if (show) {
          closeOtherAdminTogglePanels(cfg);
        }
        cfg.viewEl.classList.toggle('active', show);
        cfg.toggleBtn.textContent = show ? cfg.hideLabel : cfg.showLabel;
        (cfg.actionButtons || []).forEach(btn => {
          if (btn) {
            btn.disabled = !show;
          }
        });
      });

      if (cfg.printBtn) {
        cfg.printBtn.addEventListener('click', function () {
          openReportPreview(cfg.printTitle, cfg.tableEl);
        });
      }

      if (cfg.pdfBtn) {
        cfg.pdfBtn.addEventListener('click', function () {
          openReportPreview(cfg.pdfTitle, cfg.tableEl);
        });
      }
    }

    function wireRecordFilterBar(bar) {
      const tableId = String(bar?.dataset?.tableId || '').trim();
      const fieldSelect = bar ? bar.querySelector('.record-filter-field') : null;
      const searchInput = bar ? bar.querySelector('.record-filter-input') : null;
      const tableEl = tableId !== '' ? document.getElementById(tableId) : null;

      if (!fieldSelect || !searchInput || !tableEl) {
        return;
      }

      const tbody = tableEl.querySelector('tbody');
      if (!tbody) {
        return;
      }

      const applyFilter = function () {
        const term = searchInput.value.trim().toLowerCase();
        const selectedField = String(fieldSelect.value || 'all');
        const selectedColumnIndex = selectedField === 'all' ? -1 : Number(selectedField);
        const rows = Array.from(tbody.querySelectorAll('tr'));

        rows.forEach(function (row) {
          const cells = Array.from(row.querySelectorAll('td'));
          if (!cells.length) {
            row.style.display = '';
            return;
          }

          const isEmptyStateRow = cells.length === 1 && cells[0].hasAttribute('colspan');
          if (isEmptyStateRow) {
            row.style.display = '';
            return;
          }

          let haystack = '';
          if (selectedColumnIndex >= 0 && cells[selectedColumnIndex]) {
            haystack = cells[selectedColumnIndex].textContent || '';
          } else {
            haystack = row.textContent || '';
          }

          const matches = term === '' || haystack.toLowerCase().includes(term);
          row.style.display = matches ? '' : 'none';
        });
      };

      fieldSelect.addEventListener('change', applyFilter);
      searchInput.addEventListener('input', applyFilter);
      applyFilter();
    }

    function escapeStudentIdHtml(value) {
      return String(value ?? '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
    }

    function studentIdQrPayload(learner) {
      return [
        `School: ${reportMeta.schoolName}`,
        `Student: ${learner.full_name || ''}`,
        `Reg Number: ${learner.reg_number || ''}`,
        `DOB: ${learner.date_of_birth_info || 'N/A'}`,
        `Birth Certificate: ${learner.birth_certificate_number || 'N/A'}`,
        `Class: ${learner.class_name || ''}`,
        `Serial: ${learner.id_serial || ''}`,
        `Issued: ${learner.id_issue_date || ''}`,
        `Expiry: ${learner.id_expiry_date || ''}`,
        `Renewal Year: ${learner.id_renewal_year || ''}`
      ].join('\n');
    }

    function studentIdQrUrl(learner) {
      return `https://quickchart.io/qr?size=160&text=${encodeURIComponent(studentIdQrPayload(learner))}`;
    }

    function normalizeIssueDate(rawDate) {
      const value = String(rawDate || '').trim();
      if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
        return value;
      }
      return new Date().toISOString().slice(0, 10);
    }

    function issueDateLabel(issueDate) {
      const normalized = normalizeIssueDate(issueDate);
      const parsed = new Date(normalized + 'T00:00:00');
      if (Number.isNaN(parsed.getTime())) {
        return normalized;
      }
      return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: '2-digit' });
    }

    function normalizeExpiryDate(rawDate, issueDate) {
      const value = String(rawDate || '').trim();
      if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
        return value;
      }

      const fallbackIssue = normalizeIssueDate(issueDate);
      const dateObj = new Date(fallbackIssue + 'T00:00:00');
      dateObj.setFullYear(dateObj.getFullYear() + 1);
      return dateObj.toISOString().slice(0, 10);
    }

    function expiryDateLabel(expiryDate, issueDate) {
      const normalized = normalizeExpiryDate(expiryDate, issueDate);
      const parsed = new Date(normalized + 'T00:00:00');
      if (Number.isNaN(parsed.getTime())) {
        return normalized;
      }
      return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: '2-digit' });
    }

    function normalizeRenewalYear(rawYear, expiryDate) {
      const yearNum = Number(rawYear);
      if (Number.isInteger(yearNum) && yearNum >= 2000 && yearNum <= 2100) {
        return String(yearNum);
      }

      const normalizedExpiry = normalizeExpiryDate(expiryDate, normalizeIssueDate(studentIdIssueDate?.value || ''));
      return normalizedExpiry.slice(0, 4);
    }

    function serialPrefixValue() {
      const raw = String(studentIdSerialPrefix?.value || '').trim().toUpperCase();
      const cleaned = raw.replace(/[^A-Z0-9-]/g, '');
      return cleaned !== '' ? cleaned : 'MAV-ID';
    }

    function buildIdSerial(learner, issueDate, index) {
      const prefix = serialPrefixValue();
      const reg = String(learner.reg_number || 'UNKNOWN').toUpperCase().replace(/[^A-Z0-9]/g, '');
      const issueKey = normalizeIssueDate(issueDate).replace(/-/g, '');
      const seq = String(index + 1).padStart(3, '0');
      return `${prefix}-${issueKey}-${reg}-${seq}`;
    }

    function prepareStudentIdDataset(learners) {
      const issueDate = normalizeIssueDate(studentIdIssueDate?.value || '');
      const expiryDate = normalizeExpiryDate(studentIdExpiryDate?.value || '', issueDate);
      const renewalYear = normalizeRenewalYear(studentIdRenewalYear?.value || '', expiryDate);

      if (studentIdExpiryDate && studentIdExpiryDate.value !== expiryDate) {
        studentIdExpiryDate.value = expiryDate;
      }
      if (studentIdRenewalYear && studentIdRenewalYear.value !== renewalYear) {
        studentIdRenewalYear.value = renewalYear;
      }

      return (Array.isArray(learners) ? learners : []).map((learner, idx) => ({
        ...learner,
        id_issue_date: issueDate,
        id_expiry_date: expiryDate,
        id_renewal_year: renewalYear,
        id_serial: buildIdSerial(learner, issueDate, idx)
      }));
    }

    function buildStudentIdCardHtml(learner) {
      const logoSrc = reportMeta.logoDataUri && reportMeta.logoDataUri !== '' ? reportMeta.logoDataUri : reportMeta.logoPath;
      const photoSrc = String(learner.student_photo_path || '').trim();
      const photoHtml = photoSrc !== ''
        ? `<img class="student-id-photo" src="${escapeStudentIdHtml(photoSrc)}" alt="Student photo">`
        : `<div class="student-id-photo-fallback">NO PHOTO</div>`;
      const guardianName = String(learner.guardian_name || '').trim() || 'N/A';
      const guardianPhone = String(learner.guardian_phone || '').trim() || 'N/A';
      const guardianAddress = String(learner.guardian_address || '').trim() || 'N/A';
      const issuedLabel = issueDateLabel(learner.id_issue_date || '');
      const expiryLabel = expiryDateLabel(learner.id_expiry_date || '', learner.id_issue_date || '');
      const serialLabel = String(learner.id_serial || '').trim() || 'N/A';
      const renewalLabel = String(learner.id_renewal_year || '').trim() || 'N/A';
      const signatureSrc = String(reportMeta.headSignaturePath || '').trim();
      const signatureHtml = signatureSrc !== ''
        ? `<img class="sig-img" src="${escapeStudentIdHtml(signatureSrc)}" alt="Head signature">`
        : `<span class="sig-text">Signature Here</span>`;

      return `
        <div class="student-id-pair">
          <article class="student-id-card front">
            <div class="student-id-watermark"><img src="${escapeStudentIdHtml(logoSrc)}" alt="Logo watermark"></div>
            <header class="student-id-front-head">
              <img class="student-id-front-logo" src="${escapeStudentIdHtml(logoSrc)}" alt="School logo">
              <div class="student-id-front-school">
                <div class="name">${escapeStudentIdHtml(reportMeta.schoolName)}</div>
                <div class="sub">${escapeStudentIdHtml(reportMeta.schoolAddress || 'Education for all')}</div>
              </div>
            </header>
            <div class="student-id-front-title-row">
              <span>Identity Card</span>
              <span>${escapeStudentIdHtml(renewalLabel)}</span>
            </div>
            <section class="student-id-front-main">
              <div class="student-id-front-photo-wrap">${photoHtml}</div>
              <div class="student-id-front-fields">
                <div class="line"><span class="k">Student ID</span><span>:</span><span class="v">${escapeStudentIdHtml(learner.reg_number || 'N/A')}</span></div>
                <div class="line"><span class="k">Student Name</span><span>:</span><span class="v">${escapeStudentIdHtml(learner.full_name || 'N/A')}</span></div>
                <div class="line"><span class="k">Guardian</span><span>:</span><span class="v">${escapeStudentIdHtml(guardianName)}</span></div>
                <div class="line"><span class="k">Class</span><span>:</span><span class="v">${escapeStudentIdHtml(learner.class_name || 'N/A')}</span></div>
                <div class="line"><span class="k">Date of Birth</span><span>:</span><span class="v">${escapeStudentIdHtml(learner.date_of_birth_info || 'N/A')}</span></div>
                <div class="line"><span class="k">Birth Cert No</span><span>:</span><span class="v">${escapeStudentIdHtml(learner.birth_certificate_number || 'N/A')}</span></div>
                <div class="line"><span class="k">Issued</span><span>:</span><span class="v">${escapeStudentIdHtml(issuedLabel)}</span></div>
                <div class="line"><span class="k">Expires</span><span>:</span><span class="v">${escapeStudentIdHtml(expiryLabel)}</span></div>
                <div class="line"><span class="k">Renewal</span><span>:</span><span class="v">${escapeStudentIdHtml(renewalLabel)}</span></div>
                <div class="line serial-line"><span class="k">Serial</span><span>:</span><span class="v">${escapeStudentIdHtml(serialLabel)}</span></div>
              </div>
              <div class="student-id-front-qr-wrap">
                <img class="student-id-qr" src="${escapeStudentIdHtml(studentIdQrUrl(learner))}" alt="Student ID QR Code">
              </div>
            </section>
            <footer class="student-id-front-bottom">
              <div class="student-id-front-signature">
                <span class="label">Head's Signature</span>
                ${signatureHtml}
                <strong>HEAD'S SIGNATURE</strong>
              </div>
            </footer>
            <div class="student-id-front-slogan">${escapeStudentIdHtml(reportMeta.schoolMotto || 'Education for all')} • ${escapeStudentIdHtml(reportMeta.schoolMotto || 'Education for all')}</div>
          </article>
        </div>
      `;
    }

    function filteredStudentIdLearners() {
      const classFilter = String(studentIdClassFilter?.value || 'all');
      return studentIdLearners.filter(learner => {
        if (classFilter === 'all') {
          return true;
        }
        return String(learner.class_name || '') === classFilter;
      });
    }

    function renderStudentIdCards(learners) {
      renderedStudentIdCards = prepareStudentIdDataset(learners);
      if (!studentIdCardsCanvas) {
        return;
      }

      if (!renderedStudentIdCards.length) {
        studentIdCardsCanvas.innerHTML = '<div class="foot-note">No matching learners found for ID generation.</div>';
        if (printStudentIdCardsBtn) {
          printStudentIdCardsBtn.disabled = true;
        }
        if (downloadStudentIdCardsPdfBtn) {
          downloadStudentIdCardsPdfBtn.disabled = true;
        }
        return;
      }

      studentIdCardsCanvas.innerHTML = renderedStudentIdCards.map(buildStudentIdCardHtml).join('');
      if (printStudentIdCardsBtn) {
        printStudentIdCardsBtn.disabled = false;
      }
      if (downloadStudentIdCardsPdfBtn) {
        downloadStudentIdCardsPdfBtn.disabled = false;
      }
    }

    function refreshStudentIdLearnerSelect() {
      if (!studentIdLearnerSelect) {
        return;
      }

      const classFilter = String(studentIdClassFilter?.value || 'all');
      const searchTerm = String(studentIdLearnerSearch?.value || '').trim().toLowerCase();
      let visibleCount = 0;
      const visibleOptions = [];
      let changedSelection = false;

      Array.from(studentIdLearnerSelect.options).forEach((option, idx) => {
        if (idx === 0) {
          option.style.display = '';
          option.text = 'Choose learner';
          return;
        }

        const optionClass = String(option.dataset.className || '');
        const classMatches = classFilter === 'all' || optionClass === classFilter;
        const textMatches = searchTerm === '' || option.textContent.toLowerCase().includes(searchTerm);
        const show = classMatches && textMatches;
        option.style.display = show ? '' : 'none';
        if (!show && option.selected) {
          studentIdLearnerSelect.value = String(studentIdLearnerSelect.options[0]?.value || '');
          changedSelection = true;
        }
        if (show) {
          visibleCount++;
          visibleOptions.push(option);
        }
      });

      if (studentIdLearnerSelect.options[0]) {
        studentIdLearnerSelect.options[0].text = visibleCount > 0 ? 'Choose learner' : 'No matching learners';
      }

      if (searchTerm !== '' && visibleOptions.length > 0) {
        const currentVisible = visibleOptions.some(option => option.value === studentIdLearnerSelect.value);
        if (!currentVisible) {
          const startsWithMatch = visibleOptions.find(option => option.textContent.toLowerCase().startsWith(searchTerm));
          const nextOption = startsWithMatch || visibleOptions[0];
          if (nextOption && studentIdLearnerSelect.value !== nextOption.value) {
            studentIdLearnerSelect.value = nextOption.value;
            changedSelection = true;
          }
        }
      }

      if (changedSelection) {
        studentIdLearnerSelect.dispatchEvent(new Event('change', { bubbles: true }));
      }
    }

    function openStudentIdPrintWindow(modeLabel) {
      if (!renderedStudentIdCards.length) {
        window.alert('Generate at least one student ID card first.');
        return;
      }

      const printWin = window.open('', '_blank');
      if (!printWin) {
        window.alert('Popup blocked. Please allow popups and try again.');
        return;
      }

      const cardsHtml = renderedStudentIdCards.map(buildStudentIdCardHtml).join('');
      const t = {
        ink: reportMeta.palette.ink || '#102746',
        muted: reportMeta.palette.muted || '#4f5f7a',
        brandNavy: reportMeta.palette.brandNavy || '#0f3872',
        brandNavyDeep: reportMeta.palette.brandNavyDeep || reportMeta.palette.brandNavy || '#0d346a',
        brandGold: reportMeta.palette.brandGold || '#f8b400',
        brandIce: reportMeta.palette.brandIce || '#ecf5ff',
        patchSky: reportMeta.palette.patchSky || '#7cc9ff',
        patchYellow: reportMeta.palette.patchYellow || '#ffd447'
      };
      printWin.document.write(`
        <html>
          <head>
            <title>${escapeStudentIdHtml(reportMeta.schoolName)} - ${escapeStudentIdHtml(modeLabel)}</title>
            <style>
              @page { size: A4 portrait; margin: 10mm; }
              body { font-family: Arial, sans-serif; margin: 0; background: #fff; color: ${t.ink}; }
              .sheet { max-width: 190mm; margin: 0 auto; }
              .head { margin-bottom: 10px; display:flex; gap:10px; align-items:center; justify-content:center; }
              .head .logo { width: 54px; height: 54px; object-fit: contain; border: 1px solid #dbe4f3; border-radius: 10px; background:#fff; padding: 4px; }
              .head h1 { margin: 0; font-size: 18px; color: ${t.brandNavy}; }
              .head p { margin: 4px 0 0; font-size: 12px; color: ${t.muted}; }
              .cards { display: grid; grid-template-columns: repeat(2, 85.60mm); justify-content: center; gap: 4mm; }
              .student-id-pair { display: grid; grid-template-columns: 1fr; gap: 3mm; align-items: stretch; }
              .student-id-card {
                position: relative;
                overflow: hidden;
                width: 85.60mm;
                min-width: 85.60mm;
                max-width: 85.60mm;
                height: 53.98mm;
                min-height: 53.98mm;
                max-height: 53.98mm;
                border-radius: 3.2mm;
                border: 0.45mm solid ${t.brandNavyDeep};
                background:
                  radial-gradient(circle at 16% 16%, rgba(255, 210, 74, 0.56) 0 12%, transparent 13%),
                  radial-gradient(circle at 86% 81%, rgba(255, 210, 74, 0.48) 0 10%, transparent 11%),
                  linear-gradient(132deg, ${t.brandNavyDeep} 0%, ${t.brandNavy} 38%, ${t.patchSky} 72%, ${t.patchYellow} 100%);
                box-shadow: 0 7px 14px rgba(14, 42, 84, 0.14);
                padding: 2.4mm;
                display: grid;
                grid-template-rows: auto 1fr auto;
                gap: 1.2mm;
                color: #f6fbff;
              }
              .student-id-card.back {
                background:
                  radial-gradient(circle at 12% 82%, rgba(255, 214, 88, 0.5) 0 10%, transparent 11%),
                  radial-gradient(circle at 82% 17%, rgba(255, 214, 88, 0.44) 0 12%, transparent 13%),
                  linear-gradient(144deg, ${t.brandNavyDeep} 0%, ${t.brandNavy} 44%, ${t.patchSky} 76%, ${t.patchYellow} 100%);
              }
              .student-id-watermark { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; opacity: 0.08; z-index: 0; }
              .student-id-watermark img { width: 70%; max-height: 70%; object-fit: contain; mix-blend-mode: multiply; background: transparent; }
              .student-id-head, .student-id-body, .student-id-foot { position: relative; z-index: 1; }
              .student-id-head { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 1.3mm; border-bottom: 0.35mm solid rgba(234, 245, 255, 0.56); padding-bottom: 1.1mm; }
              .student-id-head img { width: 8.8mm; height: 8.8mm; object-fit: contain; border-radius: 1.2mm; background: #fff; border: 0.3mm solid #a5bfe7; padding: 0.6mm; }
              .student-id-school { font-weight: 800; font-size: 2.9mm; color: #f7fcff; line-height: 1.1; }
              .student-id-sub { font-size: 1.9mm; color: #e8f6ff; margin-top: 0.2mm; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; }
              .student-id-body { display: grid; grid-template-columns: 14.4mm 1fr 12.5mm; gap: 1.2mm; align-items: center; }
              .student-id-photo, .student-id-photo-fallback { width: 13.8mm; height: 17.8mm; border-radius: 1.2mm; border: 0.3mm solid #b9c8e3; }
              .student-id-photo { object-fit: cover; background: #f4f7fb; }
              .student-id-photo-fallback { background: #f4f7fb; display: flex; align-items: center; justify-content: center; color: #5f6f88; font-size: 1.8mm; font-weight: 700; text-align: center; }
              .student-id-fields { display: grid; gap: 0.45mm; min-width: 0; }
              .student-id-fields .line { font-size: 2.1mm; color: #f4fbff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
              .student-id-fields .line strong { color: #ffe38a; }
              .student-id-qr { width: 12.2mm; height: 12.2mm; border-radius: 1mm; border: 0.3mm solid #cae2ff; background: #fff; padding: 0.6mm; object-fit: contain; justify-self: end; }
              .student-id-foot { border-top: 0.35mm solid rgba(233, 245, 255, 0.6); padding-top: 0.8mm; display: flex; align-items: center; justify-content: space-between; gap: 1.2mm; }
              .student-id-class { font-size: 2mm; color: ${t.brandGold}; font-weight: 800; letter-spacing: 0.4px; text-transform: uppercase; }
              .student-id-verify { font-size: 1.7mm; color: #e7f6ff; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; }
              .student-id-meta { display: grid; gap: 0.35mm; font-size: 1.68mm; color: #eaf6ff; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; text-align: right; }
              .student-id-back-body { position: relative; z-index: 1; display: grid; gap: 0.45mm; font-size: 2.1mm; color: #ecf7ff; min-height: 0; }
              .student-id-back-title { font-size: 2mm; text-transform: uppercase; letter-spacing: 0.5px; color: ${t.brandGold}; font-weight: 800; border-bottom: 0.3mm dashed rgba(233, 245, 255, 0.64); padding-bottom: 0.45mm; }
              .student-id-back-line { font-size: 1.85mm; line-height: 1.3; color: #f3fbff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
              .student-id-signature { margin-top: 0.45mm; border-top: 0.3mm solid rgba(238, 247, 255, 0.64); padding-top: 0.45mm; font-size: 1.7mm; color: ${t.brandGold}; text-transform: uppercase; letter-spacing: 0.5px; font-weight: 700; }
              .student-id-stamp { margin-top: 0.8mm; width: 17.8mm; height: 17.8mm; border-radius: 50%; border: 0.4mm dashed rgba(255, 236, 170, 0.95); display: flex; align-items: center; justify-content: center; text-align: center; font-size: 1.58mm; line-height: 1.2; color: #fff7d2; background: rgba(9, 38, 78, 0.2); margin-left: auto; }
              .student-id-card.front { padding: 0; display: grid; grid-template-rows: auto auto 1fr auto auto; gap: 0; background: ${t.brandIce}; color: ${t.ink}; }
              .student-id-card.front .student-id-watermark { opacity: 0.11; }
              .student-id-front-head { position: relative; z-index: 1; display: grid; grid-template-columns: 10mm 1fr; gap: 1.2mm; align-items: center; background: linear-gradient(110deg, ${t.brandNavyDeep} 0%, ${t.brandNavy} 58%, ${t.patchSky} 100%); padding: 1.3mm 1.8mm 1.1mm; border-bottom: 0.28mm solid ${t.patchSky}; }
              .student-id-front-logo { width: 8.8mm; height: 8.8mm; object-fit: contain; border-radius: 50%; border: 0.35mm solid rgba(240, 250, 255, 0.95); padding: 0.45mm; background: transparent; justify-self: center; }
              .student-id-front-school { color: #f6fbff; line-height: 1.1; }
              .student-id-front-school .name { font-size: 2.6mm; font-weight: 900; letter-spacing: 0.28px; text-transform: uppercase; }
              .student-id-front-school .sub { font-size: 1.45mm; opacity: 0.95; font-weight: 700; letter-spacing: 0.2px; margin-top: 0.1mm; }
              .student-id-front-title-row { position: relative; z-index: 1; display: flex; justify-content: space-between; align-items: center; padding: 0.6mm 1.7mm; background: #f8fcff; border-bottom: 0.28mm solid ${t.patchSky}; color: ${t.brandNavyDeep}; font-size: 2.2mm; font-weight: 900; letter-spacing: 0.22px; text-transform: uppercase; }
              .student-id-front-main { position: relative; z-index: 1; display: grid; grid-template-columns: 19mm 1fr 15.5mm; gap: 1mm; align-items: start; padding: 1.05mm 1.6mm; background: linear-gradient(180deg, rgba(236, 246, 255, 0.95) 0%, rgba(224, 238, 255, 0.95) 100%); }
              .student-id-front-photo-wrap { border: 0.36mm solid ${t.patchSky}; border-radius: 2.2mm; background: #ffffff; padding: 0.6mm; box-shadow: 0 0 0 0.3mm rgba(255, 220, 108, 0.42); }
              .student-id-front-photo-wrap .student-id-photo, .student-id-front-photo-wrap .student-id-photo-fallback { width: 100%; height: 25mm; border-radius: 1.5mm; border: 0.24mm solid #b9c8e3; }
              .student-id-front-fields { display: grid; gap: 0.2mm; color: ${t.ink}; font-size: 1.78mm; line-height: 1.12; min-width: 0; }
              .student-id-front-fields .line { display: grid; grid-template-columns: 14.5mm 0.9mm 1fr; align-items: baseline; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
              .student-id-front-fields .k { font-weight: 900; color: ${t.brandNavyDeep}; text-transform: uppercase; letter-spacing: 0.12px; }
              .student-id-front-fields .v { color: ${t.brandNavy}; font-weight: 900; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
              .student-id-front-fields .line.serial-line .v { font-size: 1.62mm; letter-spacing: 0; }
              .student-id-front-qr-wrap { display: flex; align-items: center; justify-content: center; align-self: stretch; min-height: 100%; }
              .student-id-front-main .student-id-qr { width: 13.8mm; height: 13.8mm; border: 0.3mm solid ${t.brandNavy}; border-radius: 1.15mm; background: #fff; padding: 0.45mm; object-fit: contain; box-shadow: 0 0 0 0.25mm rgba(255, 220, 108, 0.38); }
              .student-id-front-bottom { position: relative; z-index: 1; display: flex; justify-content: space-between; align-items: center; gap: 1.05mm; padding: 0.8mm 1.7mm 0.7mm; background: ${t.brandIce}; border-top: 0.28mm solid ${t.patchSky}; color: ${t.brandNavyDeep}; }
              .student-id-front-signature { font-size: 1.72mm; font-family: Georgia, 'Times New Roman', serif; font-style: italic; color: ${t.brandNavy}; font-weight: 600; line-height: 1.05; text-align: right; margin-left: auto; }
              .student-id-front-signature .label { display: block; font-size: 1.66mm; font-family: 'Plus Jakarta Sans', sans-serif; font-style: normal; font-weight: 800; color: ${t.brandNavyDeep}; letter-spacing: 0.14px; margin-bottom: 0.25mm; text-transform: none; }
              .student-id-front-signature .sig-img { display: block; margin-left: auto; max-height: 5.6mm; max-width: 20mm; object-fit: contain; mix-blend-mode: multiply; background: transparent; }
              .student-id-front-signature .sig-text { display: block; margin-top: 0.15mm; }
              .student-id-front-signature strong { display: block; margin-top: 0.35mm; font-size: 1.62mm; font-family: 'Plus Jakarta Sans', sans-serif; font-style: normal; text-transform: uppercase; color: ${t.brandNavyDeep}; letter-spacing: 0.16px; font-weight: 900; }
              .student-id-front-slogan { position: relative; z-index: 1; background: linear-gradient(90deg, ${t.brandNavyDeep} 0%, ${t.brandNavy} 55%, ${t.brandNavyDeep} 100%); color: ${t.brandGold}; font-size: 1.62mm; font-weight: 800; letter-spacing: 0.4px; text-transform: uppercase; text-align: center; padding: 0.65mm 1.2mm; border-top: 0.24mm solid rgba(255, 222, 127, 0.45); }
              @media print {
                .cards { grid-template-columns: repeat(2, 85.60mm); }
                .student-id-pair { grid-template-columns: 1fr; }
              }
            </style>
          </head>
          <body>
            <section class="sheet">
              <div class="head">
                <img class="logo" src="${escapeStudentIdHtml(reportMeta.logoDataUri && reportMeta.logoDataUri !== '' ? reportMeta.logoDataUri : reportMeta.logoPath)}" alt="School logo">
                <div style="text-align:center;">
                  <h1>${escapeStudentIdHtml(reportMeta.schoolName)} - Student IDs</h1>
                  <p>${escapeStudentIdHtml(modeLabel)} | Generated: ${escapeStudentIdHtml(new Date().toLocaleString())}</p>
                </div>
              </div>
              <div class="cards">${cardsHtml}</div>
            </section>
            <script>window.onload = function(){ window.print(); };<\/script>
          </body>
        </html>
      `);
      printWin.document.close();
    }

    classSelect.addEventListener('change', renderSubjectsForClass);
    if (subjectSelectSearch) {
      subjectSelectSearch.addEventListener('input', filterSubjectCheckboxes);
    }

    wireSelectSearch(classSelectSearch, classSelect, {
      defaultLabel: 'Choose class',
      emptyLabel: 'No matching classes'
    });

    wireSelectSearch(teacherSelectSearch, teacherSelect, {
      defaultLabel: 'Choose teacher',
      emptyLabel: 'No matching teachers'
    });

    wireSelectSearch(admissionClassSearch, admissionClassSelect, {
      defaultLabel: 'Choose class',
      emptyLabel: 'No matching classes'
    });

    if (parentSelect) {
      const parentSearch = document.createElement('input');
      parentSearch.type = 'search';
      parentSearch.placeholder = 'Search learner by name, class, or reg number...';
      parentSearch.style.marginBottom = '8px';
      parentSelect.parentNode.insertBefore(parentSearch, parentSelect);
      wireSelectSearch(parentSearch, parentSelect, {
        defaultLabel: 'Choose learner',
        emptyLabel: 'No matching learners'
      });
    }

    function syncAnnouncementTargetFields() {
      if (!announcementAudience || !announcementTargetType || !announcementTargetClassWrap || !announcementTargetLearnerWrap) {
        return;
      }

      const audience = announcementAudience.value;
      const targetType = announcementTargetType.value;
      const audienceSupportsTargeting = audience === 'learner' || audience === 'parent';

      if (!audienceSupportsTargeting && targetType !== 'all') {
        announcementTargetType.value = 'all';
      }

      const effectiveType = announcementTargetType.value;
      announcementTargetType.disabled = !audienceSupportsTargeting;

      const showClass = audienceSupportsTargeting && effectiveType === 'class';
      const showLearner = audienceSupportsTargeting && effectiveType === 'learner';

      announcementTargetClassWrap.style.display = showClass ? '' : 'none';
      announcementTargetLearnerWrap.style.display = showLearner ? '' : 'none';

      if (announcementTargetClass) {
        announcementTargetClass.required = showClass;
        if (!showClass) {
          announcementTargetClass.value = '';
        }
      }
      if (announcementTargetLearner) {
        announcementTargetLearner.required = showLearner;
        if (!showLearner) {
          announcementTargetLearner.value = '';
        }
      }
    }

    if (announcementAudience) {
      announcementAudience.addEventListener('change', syncAnnouncementTargetFields);
    }
    if (announcementTargetType) {
      announcementTargetType.addEventListener('change', syncAnnouncementTargetFields);
    }
    syncAnnouncementTargetFields();

    if (assignmentSearch) {
      const assignmentSearchField = document.getElementById('assignmentSearchField');
      assignmentSearch.addEventListener('input', function () {
        const keyword = this.value.trim().toLowerCase();
        const selectedField = String(assignmentSearchField?.value || 'all');
        const selectedColumnIndex = selectedField === 'all' ? -1 : Number(selectedField);

        assignmentRows.forEach(function (row) {
          const cells = Array.from(row.querySelectorAll('td'));
          let haystack = '';

          if (selectedColumnIndex >= 0 && cells[selectedColumnIndex]) {
            haystack = cells[selectedColumnIndex].textContent || '';
          } else {
            haystack = row.textContent || '';
          }

          row.style.display = haystack.toLowerCase().includes(keyword) ? '' : 'none';
        });
      });
      if (assignmentSearchField) {
        assignmentSearchField.addEventListener('change', function () {
          assignmentSearch.dispatchEvent(new Event('input'));
        });
      }
    }

    if (teacherDocumentSearch) {
      const teacherDocumentSearchField = document.getElementById('teacherDocumentSearchField');
      teacherDocumentSearch.addEventListener('input', function () {
        const keyword = this.value.trim().toLowerCase();
        const selectedField = String(teacherDocumentSearchField?.value || 'all');
        const selectedColumnIndex = selectedField === 'all' ? -1 : Number(selectedField);

        teacherDocumentRows.forEach(function (row) {
          const cells = Array.from(row.querySelectorAll('td'));
          let haystack = '';

          if (selectedColumnIndex >= 0 && cells[selectedColumnIndex]) {
            haystack = cells[selectedColumnIndex].textContent || '';
          } else {
            haystack = row.textContent || '';
          }

          row.style.display = haystack.toLowerCase().includes(keyword) ? '' : 'none';
        });
      });
      if (teacherDocumentSearchField) {
        teacherDocumentSearchField.addEventListener('change', function () {
          teacherDocumentSearch.dispatchEvent(new Event('input'));
        });
      }
    }

    document.querySelectorAll('.record-filter-bar').forEach(wireRecordFilterBar);

    function filterLeaveRequestsByStatus(status) {
      if (!leaveRequestRows.length) {
        return;
      }
      leaveRequestRows.forEach(row => {
        const rowStatus = String(row.dataset.status || '').toLowerCase();
        const show = status === 'all' || rowStatus === status;
        row.style.display = show ? '' : 'none';
      });
    }

    if (leaveFilterPendingBtn) {
      leaveFilterPendingBtn.addEventListener('click', function () {
        filterLeaveRequestsByStatus('pending');
      });
    }
    if (leaveFilterApprovedBtn) {
      leaveFilterApprovedBtn.addEventListener('click', function () {
        filterLeaveRequestsByStatus('approved');
      });
    }
    if (leaveFilterRejectedBtn) {
      leaveFilterRejectedBtn.addEventListener('click', function () {
        filterLeaveRequestsByStatus('rejected');
      });
    }
    if (leaveFilterAllBtn) {
      leaveFilterAllBtn.addEventListener('click', function () {
        filterLeaveRequestsByStatus('all');
      });
    }
    filterLeaveRequestsByStatus('pending');

    wireToggleAndActions({
      viewEl: adminAdmissionFormView,
      tableEl: null,
      toggleBtn: toggleAdminAdmissionFormBtn,
      actionButtons: [],
      showLabel: 'Show Student Admission Form',
      hideLabel: 'Hide Student Admission Form'
    });

    wireToggleAndActions({
      viewEl: adminAdmissionRegisterView,
      tableEl: adminAdmissionRegisterTable,
      toggleBtn: toggleAdminAdmissionRegisterBtn,
      printBtn: printAdminAdmissionRegisterBtn,
      pdfBtn: downloadAdminAdmissionRegisterPdfBtn,
      actionButtons: [printAdminAdmissionRegisterBtn, downloadAdminAdmissionRegisterPdfBtn],
      showLabel: 'Show Student Admission Register',
      hideLabel: 'Hide Student Admission Register',
      printTitle: 'Student Admission Register Print Report',
      pdfTitle: 'Student Admission Register PDF Report'
    });

    wireToggleAndActions({
      viewEl: adminTeacherDocumentsTableView,
      tableEl: null,
      toggleBtn: toggleAdminTeacherDocumentsBtn,
      actionButtons: [],
      showLabel: 'Show Documents from Teacher',
      hideLabel: 'Hide Documents from Teacher'
    });

    wireToggleAndActions({
      viewEl: adminAssetsRegisterTableView,
      tableEl: adminAssetsRegisterTable,
      toggleBtn: toggleAdminAssetsRegisterBtn,
      printBtn: printAdminAssetsRegisterBtn,
      pdfBtn: downloadAdminAssetsRegisterPdfBtn,
      actionButtons: [printAdminAssetsRegisterBtn, downloadAdminAssetsRegisterPdfBtn],
      showLabel: 'Show School Assets Register',
      hideLabel: 'Hide School Assets Register',
      printTitle: 'School Assets Register Print Report',
      pdfTitle: 'School Assets Register PDF Report'
    });

    if (printDailyAttendanceSummaryBtn && dailyAttendanceSummaryTable) {
      printDailyAttendanceSummaryBtn.addEventListener('click', function () {
        openReportPreview('Daily Attendance by Class', dailyAttendanceSummaryTable);
      });
    }

    if (printEnrolmentSummaryBtn && enrolmentSummaryTable) {
      printEnrolmentSummaryBtn.addEventListener('click', function () {
        openReportPreview('Student Enrolment by Class and Gender', enrolmentSummaryTable);
      });
    }

    if (downloadEnrolmentSummaryPdfBtn && enrolmentSummaryTable) {
      downloadEnrolmentSummaryPdfBtn.addEventListener('click', function () {
        openReportPreview('Student Enrolment by Class and Gender PDF Report', enrolmentSummaryTable);
      });
    }

    if (printSystemLogBtn && adminSystemLogTable) {
      printSystemLogBtn.addEventListener('click', function () {
        openReportPreview('System Log Report', adminSystemLogTable);
      });
    }

    if (downloadSystemLogPdfBtn && adminSystemLogTable) {
      downloadSystemLogPdfBtn.addEventListener('click', function () {
        openReportPreview('System Log PDF Report', adminSystemLogTable);
      });
    }

    if (staffUserSelect) {
      staffUserSelect.addEventListener('change', populateStaffDetailsForm);
      populateStaffDetailsForm();
    }

    if (ancillaryUserSelect) {
      ancillaryUserSelect.addEventListener('change', populateAncillaryStaffForm);
      populateAncillaryStaffForm();
    }

    if (printStaffDetailsReportBtn && adminStaffDetailsTable) {
      printStaffDetailsReportBtn.addEventListener('click', function () {
        openA3ReportPreview('Teacher Details A3 Report', adminStaffDetailsTable);
      });
    }

    if (printAncillaryStaffReportBtn && adminAncillaryStaffTable) {
      printAncillaryStaffReportBtn.addEventListener('click', function () {
        openA3ReportPreview('Ancillary Staff Details A3 Report', adminAncillaryStaffTable);
      });
    }

    const admissionDeleteForms = Array.from(document.querySelectorAll('.admission-delete-form'));
    admissionDeleteForms.forEach(function (form) {
      form.addEventListener('submit', function (event) {
        event.preventDefault();

        const confirmed = window.confirm('Delete this learner admission record?');
        if (!confirmed) {
          return;
        }

        const password = window.prompt('Enter admin password to continue deletion:');
        if (password === null) {
          return;
        }

        const trimmedPassword = password.trim();
        if (trimmedPassword === '') {
          window.alert('Admin password is required to delete this learner record.');
          return;
        }

        const passwordInput = form.querySelector('input[name="admin_delete_password"]');
        if (!passwordInput) {
          window.alert('Password field missing. Please refresh and try again.');
          return;
        }

        passwordInput.value = trimmedPassword;
        form.submit();
      });
    });

    if (studentIdClassFilter) {
      studentIdClassFilter.addEventListener('change', refreshStudentIdLearnerSelect);
    }
    if (studentIdLearnerSearch) {
      studentIdLearnerSearch.addEventListener('input', refreshStudentIdLearnerSelect);
    }

    if (generateSingleStudentIdBtn) {
      generateSingleStudentIdBtn.addEventListener('click', function () {
        const learnerId = Number(studentIdLearnerSelect?.value || 0);
        if (learnerId <= 0) {
          window.alert('Select a learner first.');
          return;
        }
        const learner = studentIdLearners.find(item => Number(item.id || 0) === learnerId);
        if (!learner) {
          window.alert('Selected learner record not found.');
          return;
        }
        renderStudentIdCards([learner]);
      });
    }

    if (generateClassStudentIdsBtn) {
      generateClassStudentIdsBtn.addEventListener('click', function () {
        const filtered = filteredStudentIdLearners();
        renderStudentIdCards(filtered);
      });
    }

    if (studentIdSerialPrefix) {
      studentIdSerialPrefix.addEventListener('input', function () {
        if (renderedStudentIdCards.length) {
          renderStudentIdCards(renderedStudentIdCards);
        }
      });
    }

    if (studentIdIssueDate) {
      studentIdIssueDate.addEventListener('change', function () {
        if (renderedStudentIdCards.length) {
          renderStudentIdCards(renderedStudentIdCards);
        }
      });
    }

    if (studentIdExpiryDate) {
      studentIdExpiryDate.addEventListener('change', function () {
        if (renderedStudentIdCards.length) {
          renderStudentIdCards(renderedStudentIdCards);
        }
      });
    }

    if (studentIdRenewalYear) {
      studentIdRenewalYear.addEventListener('input', function () {
        if (renderedStudentIdCards.length) {
          renderStudentIdCards(renderedStudentIdCards);
        }
      });
    }

    if (printStudentIdCardsBtn) {
      printStudentIdCardsBtn.addEventListener('click', function () {
        openStudentIdPrintWindow('Print Student ID Cards');
      });
    }

    if (downloadStudentIdCardsPdfBtn) {
      downloadStudentIdCardsPdfBtn.addEventListener('click', function () {
        openStudentIdPrintWindow('PDF Student ID Cards');
      });
    }

    const schoolThemePresetSelect = document.getElementById('school-theme-preset');
    const applyThemePresetCheckbox = document.getElementById('apply-theme-preset');
    const paletteFieldMap = {
      bg_cream: document.getElementById('palette-bg-cream'),
      bg_sand: document.getElementById('palette-bg-sand'),
      ink: document.getElementById('palette-ink'),
      muted: document.getElementById('palette-muted'),
      brand_navy: document.getElementById('palette-brand-navy'),
      brand_navy_deep: document.getElementById('palette-brand-navy-deep'),
      brand_gold: document.getElementById('palette-brand-gold'),
      brand_gold_soft: document.getElementById('palette-brand-gold-soft'),
      brand_ice: document.getElementById('palette-brand-ice'),
      patch_sky: document.getElementById('palette-patch-sky'),
      patch_sky_soft: document.getElementById('palette-patch-sky-soft'),
      patch_yellow: document.getElementById('palette-patch-yellow'),
      patch_yellow_soft: document.getElementById('palette-patch-yellow-soft')
    };

    function applySelectedThemePresetToPalette() {
      if (!schoolThemePresetSelect || !applyThemePresetCheckbox || !applyThemePresetCheckbox.checked) {
        return;
      }
      const selectedPreset = schoolThemePresets[String(schoolThemePresetSelect.value || '')];
      if (!selectedPreset) {
        return;
      }
      Object.keys(paletteFieldMap).forEach(key => {
        const field = paletteFieldMap[key];
        if (field && selectedPreset[key]) {
          field.value = String(selectedPreset[key]).toUpperCase();
        }
      });
    }

    if (schoolThemePresetSelect) {
      schoolThemePresetSelect.addEventListener('change', applySelectedThemePresetToPalette);
    }
    if (applyThemePresetCheckbox) {
      applyThemePresetCheckbox.addEventListener('change', applySelectedThemePresetToPalette);
    }

    refreshStudentIdLearnerSelect();

    const adminDeskNavBtns = Array.from(document.querySelectorAll('#adminDeskNav .desk-nav-btn'));
    const adminDeskViews = Array.from(document.querySelectorAll('.desk-main .desk-view'));
    const adminDeskProgressChip = document.getElementById('adminDeskProgressChip');
    let currentAdminDeskViewId = 'adminHomeView';
    const initialOperationsStepId = <?= json_encode($initialOperationsStep, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;
    const operationsStepButtons = Array.from(document.querySelectorAll('#adminOperationsStepNav .operations-step-btn'));
    const operationsStepPanels = Array.from(document.querySelectorAll('#adminOperationsView .operation-step'));
    let currentOperationsStepId = initialOperationsStepId;

    function openOperationsStep(stepId) {
      if (!operationsStepPanels.length) {
        return;
      }

      const targetId = operationsStepPanels.some(panel => panel.id === stepId)
        ? stepId
        : operationsStepPanels[0].id;

      operationsStepPanels.forEach(panel => {
        panel.classList.toggle('active', panel.id === targetId);
      });

      operationsStepButtons.forEach(btn => {
        btn.classList.toggle('active', String(btn.dataset.stepTarget || '') === targetId);
      });

      currentOperationsStepId = targetId;
    }

    function openAdminDeskView(viewId) {
      const targetView = document.getElementById(viewId);
      
      // Explicitly remove active class from ALL views
      adminDeskViews.forEach(view => {
        view.classList.remove('active');
      });
      
      // Explicitly add active class only to target view
      if (targetView) {
        targetView.classList.add('active');
        currentAdminDeskViewId = viewId;
      }
      
      // Explicitly remove active class from ALL buttons
      adminDeskNavBtns.forEach(btn => {
        btn.classList.remove('active');
      });
      
      // Explicitly add active class only to matching button
      if (viewId) {
        const matchingBtn = adminDeskNavBtns.find(btn => btn.dataset.target === viewId);
        if (matchingBtn) {
          matchingBtn.classList.add('active');
        }
      }

      if (viewId === 'adminOperationsView') {
        openOperationsStep(currentOperationsStepId || initialOperationsStepId);
      }

      const activeIndex = adminDeskNavBtns.findIndex(btn => (btn.dataset.target || '') === viewId);
      if (adminDeskProgressChip && activeIndex >= 0) {
        const activeBtn = adminDeskNavBtns[activeIndex] || null;
        const activeLabel = String(activeBtn?.childNodes?.[0]?.textContent || activeBtn?.textContent || 'Current Section').trim().replace(/\s+/g, ' ');
        adminDeskProgressChip.textContent = `Step ${activeIndex + 1} of ${adminDeskNavBtns.length} | ${activeLabel}`;
      }
    }

    adminDeskNavBtns.forEach(btn => {
      btn.addEventListener('click', function () {
        if (this.dataset.target) {
          openAdminDeskView(this.dataset.target);
        }
      });
    });

    operationsStepButtons.forEach(btn => {
      btn.addEventListener('click', function () {
        const targetId = String(this.dataset.stepTarget || '').trim();
        if (targetId !== '') {
          openOperationsStep(targetId);
        }
      });
    });

    Array.from(document.querySelectorAll('form[method="POST"], form[method="post"]')).forEach(form => {
      form.addEventListener('submit', function () {
        let activeViewInput = form.querySelector('input[name="admin_active_view"]');
        if (!activeViewInput) {
          activeViewInput = document.createElement('input');
          activeViewInput.type = 'hidden';
          activeViewInput.name = 'admin_active_view';
          form.appendChild(activeViewInput);
        }
        activeViewInput.value = currentAdminDeskViewId;

        if (form.closest('#adminOperationsView')) {
          let activeStepInput = form.querySelector('input[name="admin_operations_step"]');
          if (!activeStepInput) {
            activeStepInput = document.createElement('input');
            activeStepInput.type = 'hidden';
            activeStepInput.name = 'admin_operations_step';
            form.appendChild(activeStepInput);
          }
          activeStepInput.value = currentOperationsStepId || initialOperationsStepId;
        }
      });
    });

    // Learner Promotions - Toggle reject form
    function toggleRejectForm(btn) {
      const form = btn.closest('form');
      const rejectDiv = form.querySelector('.reject-form');
      if (rejectDiv) {
        if (rejectDiv.style.display === 'none') {
          rejectDiv.style.display = 'flex';
          btn.textContent = 'Cancel Reject';
          btn.classList.remove('accent');
          btn.classList.add('warn');
        } else {
          rejectDiv.style.display = 'none';
          btn.textContent = 'Reject';
          btn.classList.add('accent');
          btn.classList.remove('warn');
        }
      }
    }

    openAdminDeskView(<?= json_encode($initialAdminView, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>);
  </script>
  <?php output_auto_capitalize_script(); ?>
  <?php output_select_search_script(); ?>
  <footer style="text-align:center;padding:14px 0 10px;font-size:0.8rem;color:#8a9ab0;opacity:0.7;">Developed by Ngwenya Jonas &copy; 2026</footer>
</body>
</html>
