<?php
require_once __DIR__ . '/Includes.php';

$sessionRole = (string)($_SESSION['role'] ?? '');
$isAdminReadOnlyView = $sessionRole === 'admin' && (string)($_GET['admin_view'] ?? '') === '1';
if ($sessionRole === 'admin' && !$isAdminReadOnlyView) {
  header('Location: admin.php');
  exit;
}
check_login(['teacher', 'admin']);

// Keep schema creation here so the page works even if opened directly first.
$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', '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,
  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 users MODIFY role ENUM('admin', 'teacher', 'hop', 'accountant', '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 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)
)");

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 this remains safe for existing databases.
  }
}

$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 this remains safe for existing databases.
  }
}

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.
}

$pdo->exec("CREATE TABLE IF NOT EXISTS learner_notes (
  id INT AUTO_INCREMENT PRIMARY KEY,
  learner_id INT NOT NULL,
  teacher_id INT NOT NULL,
  note_text TEXT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_notes_learner FOREIGN KEY (learner_id) REFERENCES learners(id) ON DELETE CASCADE,
  CONSTRAINT fk_notes_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS learner_marks (
  id INT AUTO_INCREMENT PRIMARY KEY,
  learner_id INT NOT NULL,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  subject_id INT NOT NULL,
  assessment_type ENUM(
    'daily_exercise',
    'weekly_test',
    'end_of_month_test',
    'end_of_term_exam',
    'midyear_exam',
    'end_of_year_exam'
  ) NOT NULL,
  term_name VARCHAR(30) NOT NULL,
  assessment_date DATE NOT NULL,
  score DECIMAL(6,2) NOT NULL,
  max_score DECIMAL(6,2) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_marks_learner FOREIGN KEY (learner_id) REFERENCES learners(id) ON DELETE CASCADE,
  CONSTRAINT fk_marks_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_marks_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_marks_subject FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE CASCADE,
  INDEX idx_marks_teacher_date (teacher_id, assessment_date),
  INDEX idx_marks_type (assessment_type)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS elearning_posts (
  id INT AUTO_INCREMENT PRIMARY KEY,
  teacher_id INT NOT NULL,
  class_id INT NOT NULL,
  subject_id INT NULL,
  content_type ENUM('assignment','exercise','note','video') NOT NULL DEFAULT 'assignment',
  title VARCHAR(180) NOT NULL,
  instructions TEXT NULL,
  resource_url VARCHAR(255) NULL,
  due_date DATE NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_ep_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_ep_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_ep_subject FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE SET NULL,
  INDEX idx_ep_teacher_created (teacher_id, created_at),
  INDEX idx_ep_class (class_id)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS elearning_submissions (
  id INT AUTO_INCREMENT PRIMARY KEY,
  post_id INT NOT NULL,
  learner_id INT NOT NULL,
  response_text TEXT NULL,
  response_link VARCHAR(255) NULL,
  attachment_name VARCHAR(255) NULL,
  attachment_path VARCHAR(255) NULL,
  attachment_type VARCHAR(120) NULL,
  attachment_size INT NULL,
  submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  status ENUM('submitted','graded','returned') NOT NULL DEFAULT 'submitted',
  score DECIMAL(6,2) NULL,
  teacher_comment TEXT NULL,
  graded_at DATETIME NULL,
  CONSTRAINT fk_es_post FOREIGN KEY (post_id) REFERENCES elearning_posts(id) ON DELETE CASCADE,
  CONSTRAINT fk_es_learner FOREIGN KEY (learner_id) REFERENCES learners(id) ON DELETE CASCADE,
  UNIQUE KEY uq_es_post_learner (post_id, learner_id),
  INDEX idx_es_post (post_id),
  INDEX idx_es_learner (learner_id)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS library_resources (
  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 DEFAULT 'other',
  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,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  is_active TINYINT(1) NOT NULL DEFAULT 1,
  CONSTRAINT fk_lr_teacher FOREIGN KEY (teacher_id) REFERENCES users(id) ON DELETE CASCADE,
  CONSTRAINT fk_lr_class FOREIGN KEY (class_id) REFERENCES classes(id) ON DELETE CASCADE,
  CONSTRAINT fk_lr_subject FOREIGN KEY (subject_id) REFERENCES subjects(id) ON DELETE SET NULL,
  INDEX idx_lr_teacher_created (teacher_id, created_at),
  INDEX idx_lr_class (class_id)
)");

$pdo->exec("CREATE TABLE IF NOT EXISTS library_access_logs (
  id INT AUTO_INCREMENT PRIMARY KEY,
  resource_id INT NOT NULL,
  learner_id INT NOT NULL,
  action ENUM('view','download') NOT NULL,
  accessed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_lal_resource FOREIGN KEY (resource_id) REFERENCES library_resources(id) ON DELETE CASCADE,
  CONSTRAINT fk_lal_learner FOREIGN KEY (learner_id) REFERENCES learners(id) ON DELETE CASCADE,
  INDEX idx_lal_resource_time (resource_id, accessed_at),
  INDEX idx_lal_learner_time (learner_id, accessed_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 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 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 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_sender_created (sender_id, created_at),
  INDEX idx_ann_audience_status_created (audience, status, created_at)
)");

$submissionColumnsToEnsure = [
  "attachment_name VARCHAR(255) NULL",
  "attachment_path VARCHAR(255) NULL",
  "attachment_type VARCHAR(120) NULL",
  "attachment_size INT NULL"
];
foreach ($submissionColumnsToEnsure as $columnSql) {
  try {
    $pdo->exec("ALTER TABLE elearning_submissions ADD COLUMN " . $columnSql);
  } catch (PDOException $e) {
    // Ignore duplicate column errors so migration remains idempotent.
  }
}

$libraryResourceColumnsToEnsure = [
  "document_type VARCHAR(40) NOT NULL DEFAULT 'other'"
];
foreach ($libraryResourceColumnsToEnsure as $columnSql) {
  try {
    $pdo->exec("ALTER TABLE library_resources ADD COLUMN " . $columnSql);
  } catch (PDOException $e) {
    // Ignore duplicate column errors so 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 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.
}

$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 migration remains idempotent.
  }
}

$alerts = [];
$assessmentTypes = [
  'daily_exercise' => 'Daily Exercise',
  'weekly_test' => 'Weekly Test',
  'end_of_month_test' => 'End of Month Test',
  'end_of_term_exam' => 'End of Term Exam',
  'midyear_exam' => 'Midyear Exam',
  'end_of_year_exam' => 'End of Year Exam'
];

$attendanceStatuses = [
  'present' => 'Present',
  'absent' => 'Absent',
  'late' => 'Late',
  'excused' => 'Excused'
];

if ($isAdminReadOnlyView && ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
  $_POST = [];
  $_FILES = [];
  $alerts[] = ['type' => 'error', 'text' => 'Admin view is read-only. Changes are not allowed in teacher dashboard preview mode.'];
}

function build_mark_context_key($classId, $subjectId, $assessmentType, $termName, $assessmentDate, $learnerId) {
  return (int)$classId . '|' . (int)$subjectId . '|' . (string)$assessmentType . '|' . (string)$termName . '|' . (string)$assessmentDate . '|' . (int)$learnerId;
}

function learner_display_name($fullName, $className) {
  $name = (string)$fullName;
  $suffix = ' (' . (string)$className . ')';
  if ($className !== '' && substr($name, -strlen($suffix)) === $suffix) {
    return substr($name, 0, -strlen($suffix));
  }
  return $name;
}

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];
}

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

function get_core_learning_platforms(): array {
  return [
    [
      'name' => 'Learning Passport Zimbabwe',
      'url' => 'https://mopsezw.learningpassport.org/',
      'description' => 'National digital learning platform with curriculum-aligned resources.'
    ],
    [
      'name' => 'Khan Academy',
      'url' => 'https://www.khanacademy.org/',
      'description' => 'Free practice exercises and instructional videos across core subjects.'
    ],
    [
      'name' => 'Akello Smart Learning',
      'url' => 'https://smartlearning.akello.co/',
      'description' => 'Smart digital learning platform with structured learning pathways.'
    ],
    [
      'name' => 'Dzidzo',
      'url' => 'https://www.dzidzo.co.zw/',
      'description' => 'Local education platform supporting schools with digital content.'
    ],
    [
      'name' => 'Stellar Learning',
      'url' => 'https://stellarlearning.app/',
      'description' => 'Digital learning platform for guided lessons and learner progress tracking.'
    ]
  ];
}

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 get_inventory_categories(): array {
  return [
    'textbook' => 'Textbooks',
    'furniture' => 'Furniture',
    'equipment' => 'Equipment (Laptops, Projectors, etc.)',
    'other' => 'Other Teaching Materials'
  ];
}

function build_subject_library_resources(string $subjectName): array {
  $subject = strtolower(trim($subjectName));
  $resources = [];

  if (strpos($subject, 'math') !== false) {
    $resources[] = ['title' => 'Khan Academy Math', 'url' => 'https://www.khanacademy.org/math', 'type' => 'Practice + Video'];
    $resources[] = ['title' => 'Math is Fun', 'url' => 'https://www.mathsisfun.com/', 'type' => 'Explanations'];
  }
  if (strpos($subject, 'english') !== false) {
    $resources[] = ['title' => 'Khan Academy Grammar', 'url' => 'https://www.khanacademy.org/humanities/grammar', 'type' => 'Language'];
    $resources[] = ['title' => 'British Council LearnEnglish', 'url' => 'https://learnenglish.britishcouncil.org/', 'type' => 'Reading + Writing'];
  }
  if (strpos($subject, 'science') !== false) {
    $resources[] = ['title' => 'Khan Academy Science', 'url' => 'https://www.khanacademy.org/science', 'type' => 'Concept Videos'];
    $resources[] = ['title' => 'National Geographic Education', 'url' => 'https://education.nationalgeographic.org/', 'type' => 'Exploration'];
  }
  if (strpos($subject, 'shona') !== false || strpos($subject, 'ndebele') !== false || strpos($subject, 'language') !== false) {
    $resources[] = ['title' => 'Learning Passport Zimbabwe Languages', 'url' => 'https://mopsezw.learningpassport.org/', 'type' => 'Local Language Content'];
  }
  if (strpos($subject, 'computer') !== false || strpos($subject, 'ict') !== false) {
    $resources[] = ['title' => 'Code.org', 'url' => 'https://code.org/', 'type' => 'Digital Skills'];
    $resources[] = ['title' => 'Khan Academy Computing', 'url' => 'https://www.khanacademy.org/computing', 'type' => 'Computing Basics'];
  }
  if (strpos($subject, 'history') !== false || strpos($subject, 'geography') !== false || strpos($subject, 'social') !== false) {
    $resources[] = ['title' => 'Khan Academy Humanities', 'url' => 'https://www.khanacademy.org/humanities', 'type' => 'Social Sciences'];
  }

  if (empty($resources)) {
    $resources[] = ['title' => 'Learning Passport Zimbabwe', 'url' => 'https://mopsezw.learningpassport.org/', 'type' => 'Curriculum Support'];
    $resources[] = ['title' => 'Khan Academy', 'url' => 'https://www.khanacademy.org/', 'type' => 'General Learning'];
  }

  return $resources;
}

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

$activeTeacherId = 0;
$activeTeacher = null;

$teacherViewOptions = [];

if ($isAdminReadOnlyView) {
  $teacherViewOptions = $pdo->query("SELECT id, name, email FROM users WHERE role = 'teacher' ORDER BY name")->fetchAll();
  $requestedTeacherId = (int)($_GET['teacher_id'] ?? 0);

  if ($requestedTeacherId > 0) {
    $activeTeacherId = $requestedTeacherId;
  } elseif (!empty($teacherViewOptions)) {
    $activeTeacherId = (int)$teacherViewOptions[0]['id'];
  }
} else {
  $activeTeacherId = (int)($_SESSION['user_id'] ?? 0);
}

if ($activeTeacherId > 0) {
  $teacherStmt = $pdo->prepare("SELECT u.id, u.name, u.email, u.password_hash,
      sp.sex, sp.date_of_birth, sp.ec_number, sp.national_id, sp.qualifications, sp.subject_specialization
    FROM users u
    LEFT JOIN staff_profiles sp ON sp.user_id = u.id
    WHERE u.id = ? AND u.role = 'teacher'
    LIMIT 1");
  $teacherStmt->execute([$activeTeacherId]);
  $activeTeacher = $teacherStmt->fetch();
}

if (!$activeTeacher) {
  if ($isAdminReadOnlyView) {
    $alerts[] = ['type' => 'error', 'text' => 'No teacher profile available to preview yet.'];
  } else {
    logout_user();
    header('Location: index.php');
    exit;
  }
}

if ($isAdminReadOnlyView && $activeTeacher) {
  $alerts[] = ['type' => 'success', 'text' => 'Admin read-only preview mode is active for teacher dashboard.'];
}

if (!$activeTeacher && !$isAdminReadOnlyView) {
  exit;
}

if ($activeTeacher && !$isAdminReadOnlyView && isset($_POST['save_teacher_profile'])) {
  $profileName = trim((string)($_POST['profile_name'] ?? ''));
  $profileEmail = trim((string)($_POST['profile_email'] ?? ''));
  $teacherSex = trim((string)($_POST['teacher_sex'] ?? ''));
  $teacherDob = trim((string)($_POST['teacher_dob'] ?? ''));
  $teacherEcNumber = trim((string)($_POST['teacher_ec_number'] ?? ''));
  $teacherNationalId = trim((string)($_POST['teacher_national_id'] ?? ''));
  $teacherQualifications = trim((string)($_POST['teacher_qualifications'] ?? ''));
  $teacherSubjectSpecialization = trim((string)($_POST['teacher_subject_specialization'] ?? ''));
  $allowedSex = ['Male', 'Female', 'Other'];

  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 email address.'];
  } elseif ($teacherSex !== '' && !in_array($teacherSex, $allowedSex, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid sex value selected.'];
  } elseif ($teacherDob !== '' && normalize_person_dob_for_match($teacherDob) === null) {
    $alerts[] = ['type' => 'error', 'text' => 'Date of birth must use YYYY-MM-DD format.'];
  } else {
    $emailExistsStmt = $pdo->prepare("SELECT id FROM users WHERE LOWER(email) = LOWER(?) AND id <> ? LIMIT 1");
    $emailExistsStmt->execute([$profileEmail, $activeTeacherId]);
    if ($emailExistsStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'That email is already used by another account.'];
    } else {
      $duplicateTeacher = find_duplicate_teacher_by_name_and_dob($pdo, $profileName, $teacherDob, $activeTeacherId);
      if ($duplicateTeacher) {
        $alerts[] = ['type' => 'error', 'text' => 'A teacher with the same name and date of birth already exists.'];
      } else {
      try {
        $pdo->beginTransaction();

        $updateProfileStmt = $pdo->prepare("UPDATE users SET name = ?, email = ? WHERE id = ? AND role = 'teacher' LIMIT 1");
        $updateProfileStmt->execute([$profileName, $profileEmail, $activeTeacherId]);

        $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([
          $activeTeacherId,
          $teacherSex === '' ? null : $teacherSex,
          $teacherDob === '' ? null : $teacherDob,
          $teacherEcNumber === '' ? null : $teacherEcNumber,
          $teacherNationalId === '' ? null : $teacherNationalId,
          $teacherQualifications === '' ? null : $teacherQualifications,
          $teacherSubjectSpecialization === '' ? null : $teacherSubjectSpecialization,
          $activeTeacherId
        ]);

        $pdo->commit();
        $_SESSION['name'] = $profileName;
        $activeTeacher['name'] = $profileName;
        $activeTeacher['email'] = $profileEmail;
        $activeTeacher['sex'] = $teacherSex;
        $activeTeacher['date_of_birth'] = $teacherDob;
        $activeTeacher['ec_number'] = $teacherEcNumber;
        $activeTeacher['national_id'] = $teacherNationalId;
        $activeTeacher['qualifications'] = $teacherQualifications;
        $activeTeacher['subject_specialization'] = $teacherSubjectSpecialization;
        $alerts[] = ['type' => 'success', 'text' => 'Teacher profile updated successfully.'];
      } catch (Throwable $e) {
        if ($pdo->inTransaction()) {
          $pdo->rollBack();
        }
        $alerts[] = ['type' => 'error', 'text' => 'Could not update teacher profile: ' . mavela_exception_detail($e)];
      }
      }
    }
  }
}

if ($activeTeacher && !$isAdminReadOnlyView && isset($_POST['change_teacher_password'])) {
  $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)$activeTeacher['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 = 'teacher' LIMIT 1");
    $updatePasswordStmt->execute([$newHash, $activeTeacherId]);
    $_SESSION['must_change_password'] = false;
    $activeTeacher['password_hash'] = $newHash;
    $alerts[] = ['type' => 'success', 'text' => 'Teacher password changed successfully.'];
  }
}

$allowedClasses = [];
$allowedClassIds = [];
$classTeacherClasses = [];
$classTeacherClassIds = [];
$managedClasses = [];
$managedClassIds = [];
$subjectsByClass = [];
$assignedSubjects = [];
$teacherLibraryBySubject = [];
$attendanceSelectedClassId = isset($_POST['attendance_class_id']) ? (int)($_POST['attendance_class_id']) : 0;
$attendanceSelectedDate = trim((string)($_POST['attendance_date'] ?? date('Y-m-d')));
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $attendanceSelectedDate)) {
  $attendanceSelectedDate = date('Y-m-d');
}
$coreLearningPlatforms = get_core_learning_platforms();
$libraryDocumentTypes = get_library_document_types();
$teacherDocumentTypes = get_teacher_document_types();
$inventoryCategories = get_inventory_categories();

if ($activeTeacherId > 0) {
  $classStmt = $pdo->prepare("SELECT DISTINCT c.id, c.name
    FROM teacher_subjects ts
    JOIN classes c ON c.id = ts.class_id
    WHERE ts.teacher_id = ?
    ORDER BY c.id");
  $classStmt->execute([$activeTeacherId]);
  $allowedClasses = $classStmt->fetchAll();
  $allowedClassIds = array_map(function ($row) {
    return (int)$row['id'];
  }, $allowedClasses);

  $subjectStmt = $pdo->prepare("SELECT c.id AS class_id, c.name AS class_name, s.id AS subject_id, s.name AS subject_name
    FROM teacher_subjects ts
    JOIN classes c ON c.id = ts.class_id
    JOIN subjects s ON s.id = ts.subject_id
    WHERE ts.teacher_id = ?
    ORDER BY c.id, s.name");
  $subjectStmt->execute([$activeTeacherId]);
  $subjectRows = $subjectStmt->fetchAll();

  foreach ($subjectRows as $subjectRow) {
    $className = $subjectRow['class_name'];
    $subjectName = (string)$subjectRow['subject_name'];
    if (!isset($subjectsByClass[$className])) {
      $subjectsByClass[$className] = [];
    }
    $subjectsByClass[$className][] = $subjectName;
    $assignedSubjects[] = [
      'class_id' => (int)$subjectRow['class_id'],
      'class_name' => $subjectRow['class_name'],
      'subject_id' => (int)$subjectRow['subject_id'],
      'subject_name' => $subjectName
    ];

    if (!isset($teacherLibraryBySubject[$subjectName])) {
      $teacherLibraryBySubject[$subjectName] = build_subject_library_resources($subjectName);
    }
  }

  if (!empty($teacherLibraryBySubject)) {
    ksort($teacherLibraryBySubject);
  }

  $classTeacherStmt = $pdo->prepare("SELECT c.id, c.name
    FROM class_teacher_assignments cta
    JOIN classes c ON c.id = cta.class_id
    WHERE cta.teacher_id = ?
    ORDER BY c.id");
  $classTeacherStmt->execute([$activeTeacherId]);
  $classTeacherClasses = $classTeacherStmt->fetchAll();
  $classTeacherClassIds = array_map(static function ($row) {
    return (int)$row['id'];
  }, $classTeacherClasses);

  $managedClassRows = [];
  foreach ($allowedClasses as $classRow) {
    $managedClassRows[(int)$classRow['id']] = [
      'id' => (int)$classRow['id'],
      'name' => (string)$classRow['name']
    ];
  }
  foreach ($classTeacherClasses as $classRow) {
    $managedClassRows[(int)$classRow['id']] = [
      'id' => (int)$classRow['id'],
      'name' => (string)$classRow['name']
    ];
  }
  ksort($managedClassRows);
  $managedClasses = array_values($managedClassRows);
  $managedClassIds = array_map(static function ($row) {
    return (int)$row['id'];
  }, $managedClasses);
}

if ($activeTeacherId > 0 && isset($_POST['add_learner'])) {
  $classId = (int)($_POST['class_id'] ?? 0);
  $dateOfAdmission = trim($_POST['date_of_admission'] ?? '');
  $surname = trim($_POST['surname'] ?? '');
  $christianNames = trim($_POST['christian_names'] ?? '');
  $fullName = trim($surname . ' ' . $christianNames);
  $dateOfBirthInfo = trim($_POST['date_of_birth_info'] ?? '');
  $birthCertificateNumber = trim($_POST['birth_certificate_number'] ?? '');
  $religiousDenomination = trim($_POST['religious_denomination'] ?? '');
  $gender = trim($_POST['gender'] ?? 'Other');
  $guardianName = trim($_POST['guardian_name'] ?? '');
  $guardianNationalId = trim($_POST['guardian_national_id'] ?? '');
  $guardianAddress = trim($_POST['guardian_address'] ?? '');
  $guardianPhone = trim($_POST['guardian_phone'] ?? '');

  if (!in_array($classId, $classTeacherClassIds, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'You can only add learners to classes where you are the allocated class teacher.'];
  } 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 (!in_array($gender, ['Male', 'Female', 'Other'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid gender option.'];
  } else {
    $studentPhotoPath = null;
    $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 = 'student_' . $activeTeacherId . '_' . 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 {
    try {
      $insertPending = $pdo->prepare("INSERT INTO admissions_pending (
          teacher_id,
          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,
          status
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')");
      $insertPending->execute([
        $activeTeacherId,
        $classId,
        $dateOfAdmission === '' ? null : $dateOfAdmission,
        $surname,
        $christianNames,
        $fullName,
        $dateOfBirthInfo,
        $birthCertificateNumber === '' ? null : $birthCertificateNumber,
        $religiousDenomination,
        $gender,
        $guardianName,
        $guardianNationalId,
        $guardianAddress,
        $guardianPhone,
        $studentPhotoPath
      ]);
      $alerts[] = ['type' => 'success', 'text' => 'Admission submitted. Admin approval is required before learner enters the school database.'];
    } catch (PDOException $e) {
      $alerts[] = ['type' => 'error', 'text' => 'Could not submit admission request: ' . mavela_exception_detail($e)];
      if ($studentPhotoPath !== null) {
        @unlink(__DIR__ . '/' . $studentPhotoPath);
      }
    }
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['add_note'])) {
  $learnerId = (int)($_POST['learner_id'] ?? 0);
  $noteText = trim($_POST['note_text'] ?? '');

  if ($learnerId <= 0 || $noteText === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Choose a learner and write a note.'];
  } else {
    $allowedLearnerStmt = $pdo->prepare("SELECT l.id
      FROM learners l
      JOIN class_teacher_assignments cta ON cta.class_id = l.class_id
      WHERE l.id = ? AND cta.teacher_id = ? AND COALESCE(l.is_frozen, 0) = 0
      LIMIT 1");
    $allowedLearnerStmt->execute([$learnerId, $activeTeacherId]);
    $allowedLearner = $allowedLearnerStmt->fetch();

    if (!$allowedLearner) {
      $alerts[] = ['type' => 'error', 'text' => 'You can only write notes for learners in classes where you are class teacher.'];
    } else {
      $noteStmt = $pdo->prepare("INSERT INTO learner_notes (learner_id, teacher_id, note_text) VALUES (?, ?, ?)");
      $noteStmt->execute([$learnerId, $activeTeacherId, $noteText]);
      $alerts[] = ['type' => 'success', 'text' => 'Learner note saved.'];
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['save_marks_bulk'])) {
  $classId = (int)($_POST['mark_class_id'] ?? 0);
  $subjectId = (int)($_POST['mark_subject_id'] ?? 0);
  $assessmentType = trim($_POST['assessment_type'] ?? '');
  $termName = trim($_POST['term_name'] ?? 'Term 1');
  $assessmentDate = trim($_POST['assessment_date'] ?? '');
  $maxScore = $_POST['max_score'] ?? '';
  $markScores = $_POST['mark_scores'] ?? [];

  if (!in_array($classId, $allowedClassIds, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'You can only record marks for your assigned classes.'];
  } elseif (!array_key_exists($assessmentType, $assessmentTypes)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid assessment type.'];
  } elseif ($assessmentDate === '' || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $assessmentDate)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid assessment date.'];
  } elseif (!is_numeric($maxScore)) {
    $alerts[] = ['type' => 'error', 'text' => 'Maximum score must be numeric.'];
  } elseif (!is_array($markScores) || empty($markScores)) {
    $alerts[] = ['type' => 'error', 'text' => 'No learner marks were submitted.'];
  } else {
    $maxScoreValue = (float)$maxScore;
    if ($maxScoreValue <= 0) {
      $alerts[] = ['type' => 'error', 'text' => 'Maximum score must be greater than 0.'];
    } else {
      $subjectPermissionStmt = $pdo->prepare("SELECT 1
        FROM teacher_subjects
        WHERE teacher_id = ? AND class_id = ? AND subject_id = ?
        LIMIT 1");
      $subjectPermissionStmt->execute([$activeTeacherId, $classId, $subjectId]);
      $canTeachSubject = $subjectPermissionStmt->fetchColumn();

      if (!$canTeachSubject) {
        $alerts[] = ['type' => 'error', 'text' => 'You can only capture marks for subjects assigned to you in this class.'];
      } else {
        $validLearnersStmt = $pdo->prepare("SELECT l.id
          FROM learners l
          WHERE l.class_id = ? AND COALESCE(l.is_frozen, 0) = 0
          ORDER BY l.id");
        $validLearnersStmt->execute([$classId]);
        $validLearnerIds = [];
        foreach ($validLearnersStmt->fetchAll() as $row) {
          $validLearnerIds[(int)$row['id']] = true;
        }

        $rowsToInsert = [];
        foreach ($markScores as $learnerIdKey => $scoreRaw) {
          $learnerId = (int)$learnerIdKey;
          $scoreText = str_replace(',', '.', trim((string)$scoreRaw));

          if ($scoreText === '') {
            continue;
          }

          if (!isset($validLearnerIds[$learnerId])) {
            $alerts[] = ['type' => 'error', 'text' => 'One or more learners are outside your selected class.'];
            $rowsToInsert = [];
            break;
          }

          if (!is_numeric($scoreText)) {
            $alerts[] = ['type' => 'error', 'text' => 'All entered scores must be numeric.'];
            $rowsToInsert = [];
            break;
          }

          $scoreValue = (float)$scoreText;
          if ($scoreValue < 0 || $scoreValue > $maxScoreValue) {
            $alerts[] = ['type' => 'error', 'text' => 'Each score must be between 0 and the maximum score.'];
            $rowsToInsert = [];
            break;
          }

          $rowsToInsert[] = [$learnerId, $scoreValue];
        }

        if (empty($alerts)) {
          if (empty($rowsToInsert)) {
            $alerts[] = ['type' => 'error', 'text' => 'Enter at least one learner mark before saving.'];
          } else {
            try {
              $pdo->beginTransaction();
              $learnerIds = array_map(function ($row) {
                return (int)$row[0];
              }, $rowsToInsert);
              $existingByLearner = [];

              if (!empty($learnerIds)) {
                $inPlaceholders = implode(',', array_fill(0, count($learnerIds), '?'));
                $existingStmt = $pdo->prepare("SELECT id, learner_id
                  FROM learner_marks
                  WHERE teacher_id = ?
                    AND class_id = ?
                    AND subject_id = ?
                    AND assessment_type = ?
                    AND term_name = ?
                    AND assessment_date = ?
                    AND learner_id IN ($inPlaceholders)");
                $existingStmt->execute(array_merge([
                  $activeTeacherId,
                  $classId,
                  $subjectId,
                  $assessmentType,
                  $termName === '' ? 'Term 1' : $termName,
                  $assessmentDate
                ], $learnerIds));
                foreach ($existingStmt->fetchAll() as $existingRow) {
                  $existingByLearner[(int)$existingRow['learner_id']] = (int)$existingRow['id'];
                }
              }

              $markStmt = $pdo->prepare("INSERT INTO learner_marks (
                learner_id, teacher_id, class_id, subject_id, assessment_type, term_name, assessment_date, score, max_score
              ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
              $updateStmt = $pdo->prepare("UPDATE learner_marks
                SET score = ?, max_score = ?
                WHERE id = ? AND teacher_id = ?");

              $insertedCount = 0;
              $updatedCount = 0;

              foreach ($rowsToInsert as $row) {
                $learnerId = (int)$row[0];
                $scoreValue = (float)$row[1];

                if (isset($existingByLearner[$learnerId])) {
                  $updateStmt->execute([$scoreValue, $maxScoreValue, $existingByLearner[$learnerId], $activeTeacherId]);
                  $updatedCount++;
                } else {
                  $markStmt->execute([
                    $learnerId,
                    $activeTeacherId,
                    $classId,
                    $subjectId,
                    $assessmentType,
                    $termName === '' ? 'Term 1' : $termName,
                    $assessmentDate,
                    $scoreValue,
                    $maxScoreValue
                  ]);
                  $insertedCount++;
                }
              }
              $pdo->commit();
              $alerts[] = ['type' => 'success', 'text' => 'Marks saved. Added: ' . $insertedCount . ', Updated: ' . $updatedCount . '.'];
            } catch (PDOException $e) {
              if ($pdo->inTransaction()) {
                $pdo->rollBack();
              }
              $alerts[] = ['type' => 'error', 'text' => 'Could not save marks: ' . mavela_exception_detail($e)];
            }
          }
        }
      }
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['save_daily_attendance'])) {
  $attendanceClassId = (int)($_POST['attendance_class_id'] ?? 0);
  $attendanceDate = trim((string)($_POST['attendance_date'] ?? ''));
  $submittedAttendanceStatuses = $_POST['attendance_status'] ?? [];

  $attendanceSelectedClassId = $attendanceClassId;
  if ($attendanceDate !== '') {
    $attendanceSelectedDate = $attendanceDate;
  }

  if (!in_array($attendanceClassId, $classTeacherClassIds, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'You can only capture attendance for classes where you are class teacher.'];
  } elseif ($attendanceDate === '' || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $attendanceDate)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid attendance date.'];
  } elseif (!is_array($submittedAttendanceStatuses) || empty($submittedAttendanceStatuses)) {
    $alerts[] = ['type' => 'error', 'text' => 'No attendance entries were submitted.'];
  } else {
    $classLearnersStmt = $pdo->prepare("SELECT id FROM learners WHERE class_id = ? AND COALESCE(is_frozen, 0) = 0");
    $classLearnersStmt->execute([$attendanceClassId]);
    $validLearnerIds = [];
    foreach ($classLearnersStmt->fetchAll() as $row) {
      $validLearnerIds[(int)$row['id']] = true;
    }

    if (empty($validLearnerIds)) {
      $alerts[] = ['type' => 'error', 'text' => 'There are no learners in the selected class yet.'];
    } else {
      $rowsToSave = [];
      foreach ($submittedAttendanceStatuses as $learnerIdKey => $statusRaw) {
        $learnerId = (int)$learnerIdKey;
        $status = strtolower(trim((string)$statusRaw));

        if (!isset($validLearnerIds[$learnerId])) {
          continue;
        }

        if (!array_key_exists($status, $attendanceStatuses)) {
          $alerts[] = ['type' => 'error', 'text' => 'One or more attendance statuses are invalid.'];
          $rowsToSave = [];
          break;
        }

        $rowsToSave[] = [$learnerId, $status];
      }

      if (empty($alerts)) {
        if (empty($rowsToSave)) {
          $alerts[] = ['type' => 'error', 'text' => 'No valid attendance rows were found to save.'];
        } else {
          try {
            $pdo->beginTransaction();
            $attendanceStmt = $pdo->prepare("INSERT INTO daily_attendance_register
              (teacher_id, class_id, learner_id, attendance_date, status)
              VALUES (?, ?, ?, ?, ?)
              ON DUPLICATE KEY UPDATE status = VALUES(status), updated_at = NOW()");

            $savedCount = 0;
            foreach ($rowsToSave as $row) {
              $attendanceStmt->execute([
                $activeTeacherId,
                $attendanceClassId,
                (int)$row[0],
                $attendanceDate,
                $row[1]
              ]);
              $savedCount++;
            }

            $pdo->commit();
            $alerts[] = ['type' => 'success', 'text' => 'Daily attendance saved for ' . $savedCount . ' learners.'];
          } catch (PDOException $e) {
            if ($pdo->inTransaction()) {
              $pdo->rollBack();
            }
            $alerts[] = ['type' => 'error', 'text' => 'Could not save daily attendance: ' . mavela_exception_detail($e)];
          }
        }
      }
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['create_hub_post'])) {
  $hubClassId = (int)($_POST['hub_class_id'] ?? 0);
  $hubSubjectId = (int)($_POST['hub_subject_id'] ?? 0);
  $hubType = trim($_POST['hub_content_type'] ?? 'assignment');
  $hubTitle = trim($_POST['hub_title'] ?? '');
  $hubInstructions = trim($_POST['hub_instructions'] ?? '');
  $hubResourceUrl = trim($_POST['hub_resource_url'] ?? '');
  $hubDueDate = trim($_POST['hub_due_date'] ?? '');

  if (!in_array($hubClassId, $allowedClassIds, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'You can only post e-learning content to your assigned classes.'];
  } elseif (!in_array($hubType, ['assignment', 'exercise', 'note', 'video'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose a valid e-learning content type.'];
  } elseif ($hubTitle === '') {
    $alerts[] = ['type' => 'error', 'text' => 'E-learning title is required.'];
  } elseif ($hubDueDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $hubDueDate)) {
    $alerts[] = ['type' => 'error', 'text' => 'Due date must be a valid date.'];
  } else {
    if ($hubSubjectId > 0) {
      $subjectPermissionStmt = $pdo->prepare("SELECT 1 FROM teacher_subjects WHERE teacher_id = ? AND class_id = ? AND subject_id = ? LIMIT 1");
      $subjectPermissionStmt->execute([$activeTeacherId, $hubClassId, $hubSubjectId]);
      if (!$subjectPermissionStmt->fetchColumn()) {
        $alerts[] = ['type' => 'error', 'text' => 'You can only post for subjects assigned to you in that class.'];
      }
    }
  }

  if (empty($alerts) || end($alerts)['type'] !== 'error') {
    try {
      $hubInsert = $pdo->prepare("INSERT INTO elearning_posts
        (teacher_id, class_id, subject_id, content_type, title, instructions, resource_url, due_date)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
      $hubInsert->execute([
        $activeTeacherId,
        $hubClassId,
        $hubSubjectId > 0 ? $hubSubjectId : null,
        $hubType,
        $hubTitle,
        $hubInstructions,
        $hubResourceUrl === '' ? null : $hubResourceUrl,
        $hubDueDate === '' ? null : $hubDueDate
      ]);
      $alerts[] = ['type' => 'success', 'text' => 'E-learning content posted for learners.'];
    } catch (PDOException $e) {
      $alerts[] = ['type' => 'error', 'text' => 'Could not post e-learning content: ' . mavela_exception_detail($e)];
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['upload_library_resource'])) {
  $libraryClassId = (int)($_POST['library_class_id'] ?? 0);
  $librarySubjectId = (int)($_POST['library_subject_id'] ?? 0);
  $libraryDocumentType = 'other';
  $libraryTitle = trim($_POST['library_title'] ?? '');
  $libraryDescription = trim($_POST['library_description'] ?? '');

  if (!in_array($libraryClassId, $allowedClassIds, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'You can only upload library files to your assigned classes.'];
  } elseif ($libraryTitle === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Library title is required.'];
  } elseif (!isset($_FILES['library_file']) || (int)($_FILES['library_file']['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose a file to upload to the library.'];
  } else {
    if ($librarySubjectId > 0) {
      $subjectPermissionStmt = $pdo->prepare("SELECT 1 FROM teacher_subjects WHERE teacher_id = ? AND class_id = ? AND subject_id = ? LIMIT 1");
      $subjectPermissionStmt->execute([$activeTeacherId, $libraryClassId, $librarySubjectId]);
      if (!$subjectPermissionStmt->fetchColumn()) {
        $alerts[] = ['type' => 'error', 'text' => 'You can only attach subjects assigned to you in that class.'];
      }
    }
  }

  if (empty($alerts) || end($alerts)['type'] !== 'error') {
    $fileError = (int)($_FILES['library_file']['error'] ?? UPLOAD_ERR_NO_FILE);
    if ($fileError !== UPLOAD_ERR_OK) {
      $alerts[] = ['type' => 'error', 'text' => 'File upload failed. Please retry.'];
    } else {
      $originalName = (string)($_FILES['library_file']['name'] ?? '');
      $tmpName = (string)($_FILES['library_file']['tmp_name'] ?? '');
      $fileSize = (int)($_FILES['library_file']['size'] ?? 0);
      $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));

      $allowedExtensions = [
        'pdf', 'epub', 'mobi', 'txt',
        'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'csv',
        'jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp',
        'mp4', 'mov', 'avi', 'mkv', 'webm', 'mp3', 'wav',
        'zip', 'rar', '7z', 'rtf'
      ];

      if ($originalName === '' || $tmpName === '') {
        $alerts[] = ['type' => 'error', 'text' => 'Invalid file upload payload.'];
      } elseif ($fileSize <= 0 || $fileSize > 200 * 1024 * 1024) {
        $alerts[] = ['type' => 'error', 'text' => 'File must be between 1 byte and 200 MB.'];
      } elseif ($extension !== '' && !in_array($extension, $allowedExtensions, true)) {
        $alerts[] = ['type' => 'error', 'text' => 'Unsupported file type. Upload books, documents, pictures, videos, or common archive formats.'];
      } else {
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $detectedMime = $finfo ? (string)finfo_file($finfo, $tmpName) : '';
        if ($finfo) {
          finfo_close($finfo);
        }

        $safeBase = preg_replace('/[^A-Za-z0-9._-]/', '_', pathinfo($originalName, PATHINFO_FILENAME));
        $safeBase = trim((string)$safeBase, '._-');
        if ($safeBase === '') {
          $safeBase = 'library_file';
        }

        $uploadDirAbsolute = __DIR__ . '/Uploads/library';
        if (!is_dir($uploadDirAbsolute) && !mkdir($uploadDirAbsolute, 0775, true)) {
          $alerts[] = ['type' => 'error', 'text' => 'Could not prepare library upload folder.'];
        } else {
          $generatedName = 'library_' . $activeTeacherId . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(3));
          $newFileName = $generatedName . '_' . $safeBase . ($extension !== '' ? ('.' . $extension) : '');
          $destinationAbsolute = $uploadDirAbsolute . '/' . $newFileName;

          if (!move_uploaded_file($tmpName, $destinationAbsolute)) {
            $alerts[] = ['type' => 'error', 'text' => 'Could not save uploaded library file on server.'];
          } else {
            $relativePath = 'Uploads/library/' . $newFileName;
            try {
              $insertResource = $pdo->prepare("INSERT INTO library_resources
                (teacher_id, class_id, subject_id, document_type, title, description, original_name, file_path, mime_type, file_size)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
              $insertResource->execute([
                $activeTeacherId,
                $libraryClassId,
                $librarySubjectId > 0 ? $librarySubjectId : null,
                $libraryDocumentType,
                $libraryTitle,
                $libraryDescription === '' ? null : $libraryDescription,
                $originalName,
                $relativePath,
                $detectedMime === '' ? null : $detectedMime,
                $fileSize
              ]);
              $alerts[] = ['type' => 'success', 'text' => 'Library file uploaded and available to learners.'];
            } catch (PDOException $e) {
              @unlink($destinationAbsolute);
              $alerts[] = ['type' => 'error', 'text' => 'Could not save library record: ' . mavela_exception_detail($e)];
            }
          }
        }
      }
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['upload_teacher_document'])) {
  $documentClassId = (int)($_POST['teacher_document_class_id'] ?? 0);
  $documentSubjectId = (int)($_POST['teacher_document_subject_id'] ?? 0);
  $documentType = trim((string)($_POST['teacher_document_type'] ?? ''));
  $documentTitle = trim($_POST['teacher_document_title'] ?? '');
  $documentDescription = trim($_POST['teacher_document_description'] ?? '');

  if (!in_array($documentClassId, $allowedClassIds, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'You can only upload teacher documents for your assigned classes.'];
  } elseif (!array_key_exists($documentType, $teacherDocumentTypes)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid teacher document type.'];
  } elseif ($documentTitle === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Document title is required.'];
  } elseif (!isset($_FILES['teacher_document_file']) || (int)($_FILES['teacher_document_file']['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
    $alerts[] = ['type' => 'error', 'text' => 'Choose a file for teacher document upload.'];
  } else {
    if ($documentSubjectId > 0) {
      $subjectPermissionStmt = $pdo->prepare("SELECT 1 FROM teacher_subjects WHERE teacher_id = ? AND class_id = ? AND subject_id = ? LIMIT 1");
      $subjectPermissionStmt->execute([$activeTeacherId, $documentClassId, $documentSubjectId]);
      if (!$subjectPermissionStmt->fetchColumn()) {
        $alerts[] = ['type' => 'error', 'text' => 'You can only attach subjects assigned to you in that class.'];
      }
    }
  }

  if (empty($alerts) || end($alerts)['type'] !== 'error') {
    $fileError = (int)($_FILES['teacher_document_file']['error'] ?? UPLOAD_ERR_NO_FILE);
    if ($fileError !== UPLOAD_ERR_OK) {
      $alerts[] = ['type' => 'error', 'text' => 'Teacher document upload failed. Please retry.'];
    } else {
      $originalName = (string)($_FILES['teacher_document_file']['name'] ?? '');
      $tmpName = (string)($_FILES['teacher_document_file']['tmp_name'] ?? '');
      $fileSize = (int)($_FILES['teacher_document_file']['size'] ?? 0);
      $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
      $allowedExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'rtf', 'txt', 'jpg', 'jpeg', 'png', 'webp'];

      if ($originalName === '' || $tmpName === '') {
        $alerts[] = ['type' => 'error', 'text' => 'Invalid teacher document upload payload.'];
      } elseif ($fileSize <= 0 || $fileSize > 100 * 1024 * 1024) {
        $alerts[] = ['type' => 'error', 'text' => 'Teacher document file must be between 1 byte and 100 MB.'];
      } elseif ($extension !== '' && !in_array($extension, $allowedExtensions, true)) {
        $alerts[] = ['type' => 'error', 'text' => 'Unsupported file type for teacher documents.'];
      } else {
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $detectedMime = $finfo ? (string)finfo_file($finfo, $tmpName) : '';
        if ($finfo) {
          finfo_close($finfo);
        }

        $allowedDocumentMimes = [
          'application/pdf', 'application/msword',
          'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
          'application/vnd.ms-excel',
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
          'application/rtf', 'application/zip', 'text/rtf', 'text/plain', 'text/csv',
          'image/jpeg', 'image/png', 'image/webp'
        ];
        if ($detectedMime === '' || !in_array($detectedMime, $allowedDocumentMimes, true)) {
          $alerts[] = ['type' => 'error', 'text' => 'The uploaded file content does not match an allowed document type.'];
        } else {
          $safeBase = preg_replace('/[^A-Za-z0-9._-]/', '_', pathinfo($originalName, PATHINFO_FILENAME));
          $safeBase = trim((string)$safeBase, '._-');
          if ($safeBase === '') {
            $safeBase = 'teacher_document';
          }

          $uploadDirAbsolute = __DIR__ . '/Uploads/teacher_documents';
          if (!is_dir($uploadDirAbsolute) && !mkdir($uploadDirAbsolute, 0775, true)) {
            $alerts[] = ['type' => 'error', 'text' => 'Could not prepare teacher documents folder.'];
          } else {
            $newFileName = 'teacher_doc_' . $activeTeacherId . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(3)) . '_' . $safeBase . ($extension !== '' ? ('.' . $extension) : '');
            $destinationAbsolute = $uploadDirAbsolute . '/' . $newFileName;
            if (!move_uploaded_file($tmpName, $destinationAbsolute)) {
              $alerts[] = ['type' => 'error', 'text' => 'Could not save teacher document on server.'];
            } else {
              try {
                $insertTeacherDoc = $pdo->prepare("INSERT INTO teacher_documents
                  (teacher_id, class_id, subject_id, document_type, title, description, original_name, file_path, mime_type, file_size, status, hop_status)
                  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'submitted', 'submitted')");
                $insertTeacherDoc->execute([
                  $activeTeacherId,
                  $documentClassId,
                  $documentSubjectId > 0 ? $documentSubjectId : null,
                  $documentType,
                  $documentTitle,
                  $documentDescription === '' ? null : $documentDescription,
                  $originalName,
                  'Uploads/teacher_documents/' . $newFileName,
                  $detectedMime,
                  $fileSize
                ]);
                $alerts[] = ['type' => 'success', 'text' => 'Teacher document sent to Admin and HOP desks for review.'];
              } catch (PDOException $e) {
                @unlink($destinationAbsolute);
                $alerts[] = ['type' => 'error', 'text' => 'Could not save teacher document record: ' . mavela_exception_detail($e)];
              }
            }
          }
        }
      }
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['add_inventory_record'])) {
  $inventoryClassId = (int)($_POST['inventory_class_id'] ?? 0);
  $inventoryCategory = trim((string)($_POST['inventory_category'] ?? 'other'));
  $inventoryItemName = trim((string)($_POST['inventory_item_name'] ?? ''));
  $inventoryQuantityRaw = trim((string)($_POST['inventory_quantity'] ?? ''));
  $inventoryCondition = trim((string)($_POST['inventory_condition'] ?? ''));
  $inventoryNote = trim((string)($_POST['inventory_note'] ?? ''));

  if (!in_array($inventoryClassId, $allowedClassIds, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'You can only record inventory for your assigned classes.'];
  } elseif (!array_key_exists($inventoryCategory, $inventoryCategories)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid inventory category.'];
  } elseif ($inventoryItemName === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Inventory item name is required.'];
  } elseif ($inventoryQuantityRaw === '' || !ctype_digit($inventoryQuantityRaw)) {
    $alerts[] = ['type' => 'error', 'text' => 'Recorded quantity must be a whole number (0 or more).'];
  } else {
    $inventoryInsertStmt = $pdo->prepare("INSERT INTO inventory_records
      (teacher_id, class_id, category, item_name, quantity_recorded, item_condition, inventory_note, status)
      VALUES (?, ?, ?, ?, ?, ?, ?, 'submitted')");
    $inventoryInsertStmt->execute([
      $activeTeacherId,
      $inventoryClassId,
      $inventoryCategory,
      $inventoryItemName,
      (int)$inventoryQuantityRaw,
      $inventoryCondition === '' ? null : $inventoryCondition,
      $inventoryNote === '' ? null : $inventoryNote
    ]);
    $alerts[] = ['type' => 'success', 'text' => 'Inventory record sent to accountant desk for stock-take verification.'];
  }
}

if ($activeTeacherId > 0 && isset($_POST['update_inventory_record'])) {
  $inventoryRecordId = (int)($_POST['inventory_record_id'] ?? 0);
  $inventoryClassId = (int)($_POST['inventory_class_id'] ?? 0);
  $inventoryCategory = trim((string)($_POST['inventory_category'] ?? 'other'));
  $inventoryItemName = trim((string)($_POST['inventory_item_name'] ?? ''));
  $inventoryQuantityRaw = trim((string)($_POST['inventory_quantity'] ?? ''));
  $inventoryCondition = trim((string)($_POST['inventory_condition'] ?? ''));
  $inventoryNote = trim((string)($_POST['inventory_note'] ?? ''));

  if ($inventoryRecordId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid inventory record selected for update.'];
  } elseif (!in_array($inventoryClassId, $allowedClassIds, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'You can only update inventory for your assigned classes.'];
  } elseif (!array_key_exists($inventoryCategory, $inventoryCategories)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid inventory category.'];
  } elseif ($inventoryItemName === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Inventory item name is required.'];
  } elseif ($inventoryQuantityRaw === '' || !ctype_digit($inventoryQuantityRaw)) {
    $alerts[] = ['type' => 'error', 'text' => 'Recorded quantity must be a whole number (0 or more).'];
  } else {
    $inventoryOwnerStmt = $pdo->prepare("SELECT id FROM inventory_records WHERE id = ? AND teacher_id = ? LIMIT 1");
    $inventoryOwnerStmt->execute([$inventoryRecordId, $activeTeacherId]);
    if (!$inventoryOwnerStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'Inventory record not found for this teacher.'];
    } else {
      $inventoryUpdateStmt = $pdo->prepare("UPDATE inventory_records
        SET class_id = ?,
            category = ?,
            item_name = ?,
            quantity_recorded = ?,
            item_condition = ?,
            inventory_note = ?,
            status = 'submitted',
            stock_take_quantity = NULL,
            accountant_review = NULL,
            reviewed_by = NULL,
            reviewed_at = NULL
        WHERE id = ? AND teacher_id = ?");
      $inventoryUpdateStmt->execute([
        $inventoryClassId,
        $inventoryCategory,
        $inventoryItemName,
        (int)$inventoryQuantityRaw,
        $inventoryCondition === '' ? null : $inventoryCondition,
        $inventoryNote === '' ? null : $inventoryNote,
        $inventoryRecordId,
        $activeTeacherId
      ]);

      try {
        $removeAssetStmt = $pdo->prepare("DELETE FROM school_assets_register WHERE source_inventory_id = ?");
        $removeAssetStmt->execute([$inventoryRecordId]);
      } catch (PDOException $e) {
        // Ignore when asset register table is not yet created in this runtime path.
      }

      $alerts[] = ['type' => 'success', 'text' => 'Inventory record updated and resubmitted for accountant verification.'];
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['grade_hub_submission'])) {
  $submissionId = (int)($_POST['submission_id'] ?? 0);
  $scoreRaw = trim((string)($_POST['submission_score'] ?? ''));
  $teacherComment = trim($_POST['submission_comment'] ?? '');
  $submissionStatus = trim($_POST['submission_status'] ?? 'graded');

  if ($submissionId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid submission selected for marking.'];
  } elseif (!in_array($submissionStatus, ['graded', 'returned'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid marking status selected.'];
  } elseif ($scoreRaw !== '' && !is_numeric(str_replace(',', '.', $scoreRaw))) {
    $alerts[] = ['type' => 'error', 'text' => 'Submission score must be numeric if provided.'];
  } else {
    $ownerStmt = $pdo->prepare("SELECT es.id
      FROM elearning_submissions es
      JOIN elearning_posts ep ON ep.id = es.post_id
      WHERE es.id = ? AND ep.teacher_id = ?
      LIMIT 1");
    $ownerStmt->execute([$submissionId, $activeTeacherId]);

    if (!$ownerStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'You can only mark submissions from your own e-learning posts.'];
    } else {
      $scoreValue = $scoreRaw === '' ? null : (float)str_replace(',', '.', $scoreRaw);
      $gradeStmt = $pdo->prepare("UPDATE elearning_submissions
        SET score = ?, teacher_comment = ?, status = ?, graded_at = NOW()
        WHERE id = ?");
      $gradeStmt->execute([$scoreValue, $teacherComment, $submissionStatus, $submissionId]);
      $alerts[] = ['type' => 'success', 'text' => 'Submission marked and feedback sent to learner desk.'];
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['post_teacher_announcement'])) {
  $announcementAudience = trim((string)($_POST['teacher_announcement_audience'] ?? ''));
  $announcementTargetType = trim((string)($_POST['teacher_announcement_target_type'] ?? 'all'));
  $announcementTargetClassId = (int)($_POST['teacher_announcement_target_class_id'] ?? 0);
  $announcementTargetLearnerId = (int)($_POST['teacher_announcement_target_learner_id'] ?? 0);
  $announcementTitle = trim((string)($_POST['teacher_announcement_title'] ?? ''));
  $announcementBody = trim((string)($_POST['teacher_announcement_body'] ?? ''));

  $resolvedTargetClassId = null;
  $resolvedTargetLearnerId = null;

  if (!in_array($announcementAudience, ['learner', 'parent'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Teacher announcements can only be sent to learners or parents.'];
  } elseif (!in_array($announcementTargetType, ['all', 'class', 'learner'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid target scope.'];
  } elseif ($announcementTitle === '' || $announcementBody === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Announcement title and message are required.'];
  } else {
    if ($announcementTargetType === 'class') {
      if (!in_array($announcementTargetClassId, $managedClassIds, true)) {
        $alerts[] = ['type' => 'error', 'text' => 'You can only target your assigned classes.'];
      } else {
        $resolvedTargetClassId = $announcementTargetClassId;
      }
    } elseif ($announcementTargetType === 'learner') {
      if ($announcementTargetLearnerId <= 0) {
        $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid learner target.'];
      } 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 {
          $targetClassId = (int)$learnerTargetRow['class_id'];
          if (!in_array($targetClassId, $managedClassIds, true)) {
            $alerts[] = ['type' => 'error', 'text' => 'You can only target learners in your assigned classes.'];
          } else {
            $resolvedTargetLearnerId = (int)$learnerTargetRow['id'];
            $resolvedTargetClassId = $targetClassId;
          }
        }
      }
    }

    if (!empty($alerts) && end($alerts)['type'] === 'error') {
      // Keep form errors and skip insert.
    } else {
    $announcementStatus = $announcementAudience === 'parent' ? 'pending_admin_review' : 'published';
    $publishedAt = $announcementStatus === 'published' ? date('Y-m-d H:i:s') : null;

    $insertAnnouncementStmt = $pdo->prepare("INSERT INTO announcements
      (sender_id, sender_role, audience, target_class_id, target_learner_id, title, body, status, published_at)
      VALUES (?, 'teacher', ?, ?, ?, ?, ?, ?, ?)");
    $insertAnnouncementStmt->execute([
      $activeTeacherId,
      $announcementAudience,
      $resolvedTargetClassId,
      $resolvedTargetLearnerId,
      $announcementTitle,
      $announcementBody,
      $announcementStatus,
      $publishedAt
    ]);

    if ($announcementStatus === 'pending_admin_review') {
      $alerts[] = ['type' => 'success', 'text' => 'Announcement sent to admin for verification before posting to parents.'];
    } else {
      $alerts[] = ['type' => 'success', 'text' => 'Announcement posted directly to learners.'];
    }
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['review_transfer_clearance_teacher'])) {
  $transferRequestId = (int)($_POST['transfer_request_id'] ?? 0);
  $decision = trim((string)($_POST['teacher_transfer_decision'] ?? 'approve'));
  $comment = trim((string)($_POST['teacher_transfer_comment'] ?? ''));

  if ($transferRequestId <= 0) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid transfer request selected.'];
  } elseif (!in_array($decision, ['approve', 'reject'], true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Invalid transfer clearance decision.'];
  } else {
    $status = $decision === 'approve' ? 'approved' : 'rejected';
    $verifyStmt = $pdo->prepare("SELECT tr.id
      FROM transfer_requests tr
      JOIN learners l ON l.id = tr.learner_id
      WHERE tr.id = ?
        AND tr.status = 'clearance_requested'
        AND tr.teacher_status = 'pending'
        AND (
          EXISTS (
            SELECT 1 FROM teacher_subjects ts
            WHERE ts.teacher_id = ? AND ts.class_id = l.class_id
          )
          OR EXISTS (
            SELECT 1 FROM class_teacher_assignments cta
            WHERE cta.teacher_id = ? AND cta.class_id = l.class_id
          )
        )
      LIMIT 1");
    $verifyStmt->execute([$transferRequestId, $activeTeacherId, $activeTeacherId]);

    if (!$verifyStmt->fetch()) {
      $alerts[] = ['type' => 'error', 'text' => 'Transfer request not found in your classes or already reviewed.'];
    } else {
      $updateStmt = $pdo->prepare("UPDATE transfer_requests
        SET teacher_status = ?, teacher_comment = ?, teacher_reviewed_at = NOW(),
            status = CASE WHEN ? = 'rejected' THEN 'rejected' ELSE status END
        WHERE id = ?");
      $updateStmt->execute([
        $status,
        $comment === '' ? ($status === 'approved' ? 'Teacher clearance approved.' : 'Teacher clearance rejected.') : $comment,
        $status,
        $transferRequestId
      ]);
      $alerts[] = ['type' => 'success', 'text' => 'Transfer clearance ' . $status . ' successfully.'];
    }
  }
}

if ($activeTeacherId > 0 && isset($_POST['submit_teacher_leave_request'])) {
  $leaveType = trim((string)($_POST['leave_type'] ?? ''));
  $startDate = trim((string)($_POST['leave_start_date'] ?? ''));
  $endDate = trim((string)($_POST['leave_end_date'] ?? ''));
  $leaveReason = trim((string)($_POST['leave_reason'] ?? ''));

  $allowedLeaveTypes = ['sick', 'annual', 'maternity', 'compassionate', 'unpaid', 'other'];

  if (!in_array($leaveType, $allowedLeaveTypes, true)) {
    $alerts[] = ['type' => 'error', 'text' => 'Please choose a valid leave type.'];
  } elseif ($startDate === '' || $endDate === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Leave start and end dates are required.'];
  } elseif ($leaveReason === '') {
    $alerts[] = ['type' => 'error', 'text' => 'Please provide a reason for leave.'];
  } elseif (strtotime($endDate) < strtotime($startDate)) {
    $alerts[] = ['type' => 'error', 'text' => 'Leave end date cannot be earlier than start date.'];
  } else {
    $documentError = (int)($_FILES['leave_document']['error'] ?? UPLOAD_ERR_NO_FILE);
    $documentPath = null;
    $documentName = null;
    $documentMime = null;
    $documentSize = null;

    if ($documentError === UPLOAD_ERR_NO_FILE) {
      $alerts[] = ['type' => 'error', 'text' => 'Please attach your leave form document (PDF or image).'];
    } elseif ($documentError !== UPLOAD_ERR_OK) {
      $alerts[] = ['type' => 'error', 'text' => 'Leave form upload failed. Please retry.'];
    } else {
      $docOriginalName = (string)($_FILES['leave_document']['name'] ?? '');
      $docTmpName = (string)($_FILES['leave_document']['tmp_name'] ?? '');
      $docSize = (int)($_FILES['leave_document']['size'] ?? 0);
      $docExt = strtolower(pathinfo($docOriginalName, PATHINFO_EXTENSION));
      $allowedDocExt = ['pdf', 'jpg', 'jpeg', 'png', 'webp'];

      if ($docOriginalName === '' || $docTmpName === '') {
        $alerts[] = ['type' => 'error', 'text' => 'Invalid leave form payload.'];
      } elseif ($docSize <= 0 || $docSize > 10 * 1024 * 1024) {
        $alerts[] = ['type' => 'error', 'text' => 'Leave form must be between 1 byte and 10 MB.'];
      } elseif (!in_array($docExt, $allowedDocExt, true)) {
        $alerts[] = ['type' => 'error', 'text' => 'Leave form must be PDF, JPG, PNG, or WEBP.'];
      } else {
        $docFinfo = finfo_open(FILEINFO_MIME_TYPE);
        $detectedDocMime = $docFinfo ? (string)finfo_file($docFinfo, $docTmpName) : '';
        if ($docFinfo) {
          finfo_close($docFinfo);
        }

        $allowedDocMimes = ['application/pdf', 'image/jpeg', 'image/png', 'image/webp'];
        if ($detectedDocMime !== '' && !in_array($detectedDocMime, $allowedDocMimes, true)) {
          $alerts[] = ['type' => 'error', 'text' => 'Uploaded leave form is not a valid PDF or image file.'];
        } else {
          $uploadDir = __DIR__ . '/Uploads/leave_forms';
          if (!is_dir($uploadDir) && !mkdir($uploadDir, 0775, true)) {
            $alerts[] = ['type' => 'error', 'text' => 'Could not prepare leave forms upload folder.'];
          } else {
            $baseName = preg_replace('/[^A-Za-z0-9._-]/', '_', pathinfo($docOriginalName, PATHINFO_FILENAME));
            $baseName = trim((string)$baseName, '._-');
            if ($baseName === '') {
              $baseName = 'leave_form';
            }

            $docFileName = 'leave_form_' . date('Ymd_His') . '_' . bin2hex(random_bytes(3)) . '_' . $baseName . '.' . $docExt;
            $destination = $uploadDir . '/' . $docFileName;
            if (!move_uploaded_file($docTmpName, $destination)) {
              $alerts[] = ['type' => 'error', 'text' => 'Could not save uploaded leave form document.'];
            } else {
              $documentPath = 'Uploads/leave_forms/' . $docFileName;
              $documentName = $docOriginalName;
              $documentMime = $detectedDocMime !== '' ? $detectedDocMime : null;
              $documentSize = $docSize;
            }
          }
        }
      }
    }

    if ($documentPath !== null) {
      $insertStmt = $pdo->prepare("INSERT INTO teacher_leave_requests
        (teacher_id, leave_type, start_date, end_date, reason, supporting_document_path, supporting_document_name, supporting_document_mime, supporting_document_size, status)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')");
      $insertStmt->execute([
        $activeTeacherId,
        $leaveType,
        $startDate,
        $endDate,
        $leaveReason,
        $documentPath,
        $documentName,
        $documentMime,
        $documentSize
      ]);
      $alerts[] = ['type' => 'success', 'text' => 'Leave request submitted to head desk for approval.'];
    }
  }
}

$learners = [];
$recentNotes = [];
$recentMarks = [];
$marksByType = [];
$existingMarksLookup = [];
$hubPosts = [];
$hubSubmissions = [];
$libraryResources = [];
$libraryAccessLogs = [];
$libraryTotalAccesses = 0;
$teacherDocuments = [];
$teacherDocumentsNeedsCorrection = 0;
$teacherInventoryRecords = [];
$inventoryNeedsAction = 0;
$teacherAnnouncementRows = [];
$teacherAnnouncementPendingCount = 0;
$teacherTransferRequests = [];
$teacherLeaveRequests = [];
$activeLearners = [];
$classTeacherLearners = [];
$attendanceStatusLookup = [];
$attendanceSummary = [
  'present' => 0,
  'absent' => 0,
  'late' => 0,
  'excused' => 0
];
$recentAttendanceRows = [];
$majorExamReportCards = [];
$majorExamMarkRows = [];
$totalLearners = 0;
$totalNotes = 0;
$totalMarks = 0;
$totalClasses = count($managedClassIds);

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

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

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 = '';
  }
}

$paletteBgCream = $normalizeHexColor(get_app_setting($pdo, 'palette_bg_cream', '#f6efe0'), '#f6efe0');
$paletteBgSand = $normalizeHexColor(get_app_setting($pdo, 'palette_bg_sand', '#eadcc0'), '#eadcc0');
$paletteInk = $normalizeHexColor(get_app_setting($pdo, 'palette_ink', '#0a2f63'), '#0a2f63');
$paletteMuted = $normalizeHexColor(get_app_setting($pdo, 'palette_muted', '#4f5f7a'), '#4f5f7a');
$paletteBrandNavy = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_navy', '#0a3b79'), '#0a3b79');
$paletteBrandNavyDeep = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_navy_deep', '#082e60'), '#082e60');
$paletteBrandGold = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_gold', '#f8b400'), '#f8b400');
$paletteBrandIce = $normalizeHexColor(get_app_setting($pdo, 'palette_brand_ice', '#e8eef8'), '#e8eef8');
$palettePatchSky = $normalizeHexColor(get_app_setting($pdo, 'palette_patch_sky', '#7cc9ff'), '#7cc9ff');
$palettePatchYellow = $normalizeHexColor(get_app_setting($pdo, 'palette_patch_yellow', '#ffd447'), '#ffd447');

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

if ($activeTeacherId > 0 && !empty($managedClassIds)) {
  $placeholders = implode(',', array_fill(0, count($managedClassIds), '?'));

  $learnerStmt = $pdo->prepare("SELECT l.id, l.class_id, l.reg_number, l.date_of_admission, l.surname, l.christian_names,
      l.full_name, l.date_of_birth_info, l.birth_certificate_number, l.religious_denomination, l.gender, l.guardian_name,
      l.guardian_national_id, l.guardian_address, l.guardian_phone, l.student_photo_path, l.is_frozen, c.name AS class_name
    FROM learners l
    JOIN classes c ON c.id = l.class_id
    WHERE l.class_id IN ($placeholders)
    ORDER BY c.id, l.surname, l.christian_names, l.full_name");
  $learnerStmt->execute($managedClassIds);
  $learners = $learnerStmt->fetchAll();
  $activeLearners = array_values(array_filter($learners, static function (array $learnerRow): bool {
    return (int)($learnerRow['is_frozen'] ?? 0) === 0;
  }));
  $classTeacherLearners = array_values(array_filter($activeLearners, static function (array $learnerRow) use ($classTeacherClassIds): bool {
    return in_array((int)$learnerRow['class_id'], $classTeacherClassIds, true);
  }));
  $totalLearners = count($activeLearners);

  $noteStmt = $pdo->prepare("SELECT ln.note_text, ln.created_at, l.full_name, l.student_photo_path, c.name AS class_name
    FROM learner_notes ln
    JOIN learners l ON l.id = ln.learner_id
    JOIN classes c ON c.id = l.class_id
    WHERE ln.teacher_id = ?
    ORDER BY ln.created_at DESC
    LIMIT 12");
  $noteStmt->execute([$activeTeacherId]);
  $recentNotes = $noteStmt->fetchAll();

  $countStmt = $pdo->prepare("SELECT COUNT(*)
    FROM learner_notes ln
    JOIN learners l ON l.id = ln.learner_id
    JOIN class_teacher_assignments cta ON cta.class_id = l.class_id
    WHERE ln.teacher_id = ? AND cta.teacher_id = ?");
  $countStmt->execute([$activeTeacherId, $activeTeacherId]);
  $totalNotes = (int)$countStmt->fetchColumn();

  $marksStmt = $pdo->prepare("SELECT lm.assessment_date, lm.assessment_type, lm.term_name, lm.score, lm.max_score,
      l.id AS learner_id, l.reg_number, l.full_name AS learner_name, l.student_photo_path, c.name AS class_name, s.name AS subject_name
    FROM learner_marks lm
    JOIN learners l ON l.id = lm.learner_id
    JOIN classes c ON c.id = lm.class_id
    JOIN subjects s ON s.id = lm.subject_id
    WHERE lm.teacher_id = ?
    ORDER BY lm.assessment_date DESC, lm.created_at DESC
    LIMIT 40");
  $marksStmt->execute([$activeTeacherId]);
  $recentMarks = $marksStmt->fetchAll();

  if (!empty($allowedClassIds)) {
    $subjectPlaceholders = implode(',', array_fill(0, count($allowedClassIds), '?'));

    $majorExamReportStmt = $pdo->prepare("SELECT l.id AS learner_id, l.reg_number, l.full_name AS learner_name,
      l.student_photo_path, c.name AS class_name,
      AVG(CASE
        WHEN lm.assessment_type = 'end_of_term_exam' AND LOWER(TRIM(lm.term_name)) = 'term 1'
        THEN (lm.score / NULLIF(lm.max_score, 0)) * 100
        ELSE NULL
      END) AS term1_percent,
      AVG(CASE
        WHEN lm.assessment_type = 'midyear_exam'
        THEN (lm.score / NULLIF(lm.max_score, 0)) * 100
        ELSE NULL
      END) AS midyear_percent,
      AVG(CASE
        WHEN lm.assessment_type = 'end_of_year_exam'
        THEN (lm.score / NULLIF(lm.max_score, 0)) * 100
        ELSE NULL
      END) AS endyear_percent
    FROM learners l
    JOIN classes c ON c.id = l.class_id
    LEFT JOIN learner_marks lm ON lm.learner_id = l.id AND lm.class_id = l.class_id AND lm.teacher_id = ?
    WHERE l.class_id IN ($subjectPlaceholders)
    GROUP BY l.id, l.reg_number, l.full_name, l.student_photo_path, c.id, c.name
    ORDER BY c.id, l.surname, l.christian_names, l.full_name");
    $majorExamReportStmt->execute(array_merge([$activeTeacherId], $allowedClassIds));
    $majorExamReportCards = $majorExamReportStmt->fetchAll();

    $majorExamMarksStmt = $pdo->prepare("SELECT lm.learner_id, lm.assessment_type, lm.term_name, lm.assessment_date,
      lm.score, lm.max_score,
      l.reg_number, l.full_name AS learner_name, l.gender, l.date_of_birth_info, l.date_of_admission,
      l.student_photo_path,
      c.name AS class_name, s.name AS subject_name
    FROM learner_marks lm
    JOIN learners l ON l.id = lm.learner_id
    JOIN classes c ON c.id = lm.class_id
    JOIN subjects s ON s.id = lm.subject_id
    WHERE lm.teacher_id = ?
      AND lm.class_id IN ($subjectPlaceholders)
      AND lm.assessment_type IN ('end_of_term_exam', 'midyear_exam', 'end_of_year_exam')
    ORDER BY c.id, l.surname, l.christian_names, l.full_name, s.name, lm.assessment_date");
    $majorExamMarksStmt->execute(array_merge([$activeTeacherId], $allowedClassIds));
    $majorExamMarkRows = $majorExamMarksStmt->fetchAll();
  }

  $totalMarksStmt = $pdo->prepare("SELECT COUNT(*) FROM learner_marks WHERE teacher_id = ?");
  $totalMarksStmt->execute([$activeTeacherId]);
  $totalMarks = (int)$totalMarksStmt->fetchColumn();

  $marksTypeStmt = $pdo->prepare("SELECT assessment_type, COUNT(*) AS total
    FROM learner_marks
    WHERE teacher_id = ?
    GROUP BY assessment_type");
  $marksTypeStmt->execute([$activeTeacherId]);
  foreach ($marksTypeStmt->fetchAll() as $row) {
    $marksByType[$row['assessment_type']] = (int)$row['total'];
  }

  $existingMarksStmt = $pdo->prepare("SELECT class_id, subject_id, assessment_type, term_name, assessment_date, learner_id, score
    FROM learner_marks
    WHERE teacher_id = ?");
  $existingMarksStmt->execute([$activeTeacherId]);
  foreach ($existingMarksStmt->fetchAll() as $markRow) {
    $lookupKey = build_mark_context_key(
      $markRow['class_id'],
      $markRow['subject_id'],
      $markRow['assessment_type'],
      $markRow['term_name'],
      $markRow['assessment_date'],
      $markRow['learner_id']
    );
    $existingMarksLookup[$lookupKey] = (float)$markRow['score'];
  }

  $hubPostsStmt = $pdo->prepare("SELECT ep.id, ep.content_type, ep.title, ep.instructions, ep.resource_url, ep.due_date, ep.created_at,
      c.name AS class_name, s.name AS subject_name,
      (SELECT COUNT(*) FROM elearning_submissions es WHERE es.post_id = ep.id) AS submission_count,
      (SELECT COUNT(*) FROM elearning_submissions es WHERE es.post_id = ep.id AND es.status IN ('graded','returned')) AS graded_count
    FROM elearning_posts ep
    JOIN classes c ON c.id = ep.class_id
    LEFT JOIN subjects s ON s.id = ep.subject_id
    WHERE ep.teacher_id = ?
    ORDER BY ep.created_at DESC
    LIMIT 50");
  $hubPostsStmt->execute([$activeTeacherId]);
  $hubPosts = $hubPostsStmt->fetchAll();

  $hubSubmissionStmt = $pdo->prepare("SELECT es.id, es.response_text, es.response_link, es.attachment_name, es.attachment_path, es.attachment_type, es.attachment_size,
      es.submitted_at, es.status, es.score, es.teacher_comment,
      ep.title AS post_title, ep.content_type, c.name AS class_name,
      l.reg_number, l.full_name AS learner_name
    FROM elearning_submissions es
    JOIN elearning_posts ep ON ep.id = es.post_id
    JOIN learners l ON l.id = es.learner_id
    JOIN classes c ON c.id = ep.class_id
    WHERE ep.teacher_id = ?
    ORDER BY es.submitted_at DESC
    LIMIT 120");
  $hubSubmissionStmt->execute([$activeTeacherId]);
  $hubSubmissions = $hubSubmissionStmt->fetchAll();

  $libraryResourceStmt = $pdo->prepare("SELECT lr.id, lr.title, lr.description, lr.original_name, lr.file_path, lr.mime_type, lr.file_size,
      lr.document_type, lr.created_at, c.name AS class_name, s.name AS subject_name,
      (SELECT COUNT(*) FROM library_access_logs lal WHERE lal.resource_id = lr.id) AS access_count
    FROM library_resources lr
    JOIN classes c ON c.id = lr.class_id
    LEFT JOIN subjects s ON s.id = lr.subject_id
    WHERE lr.teacher_id = ? AND lr.is_active = 1
    ORDER BY lr.created_at DESC
    LIMIT 200");
  $libraryResourceStmt->execute([$activeTeacherId]);
  $libraryResources = $libraryResourceStmt->fetchAll();

  $libraryAccessLogStmt = $pdo->prepare("SELECT lal.accessed_at, lal.action,
      lr.title AS resource_title, lr.original_name,
      l.reg_number, l.full_name AS learner_name, c.name AS class_name
    FROM library_access_logs lal
    JOIN library_resources lr ON lr.id = lal.resource_id
    JOIN learners l ON l.id = lal.learner_id
    JOIN classes c ON c.id = l.class_id
    WHERE lr.teacher_id = ?
    ORDER BY lal.accessed_at DESC
    LIMIT 400");
  $libraryAccessLogStmt->execute([$activeTeacherId]);
  $libraryAccessLogs = $libraryAccessLogStmt->fetchAll();

  $libraryAccessCountStmt = $pdo->prepare("SELECT COUNT(*)
    FROM library_access_logs lal
    JOIN library_resources lr ON lr.id = lal.resource_id
    WHERE lr.teacher_id = ?");
  $libraryAccessCountStmt->execute([$activeTeacherId]);
  $libraryTotalAccesses = (int)$libraryAccessCountStmt->fetchColumn();

  $teacherDocumentsStmt = $pdo->prepare("SELECT td.id, td.document_type, td.title, td.description, td.original_name,
      td.file_path, td.mime_type, td.file_size, td.status, td.admin_comment, td.reviewed_at,
      td.hop_status, td.hop_comment, td.hop_reviewed_at, td.created_at,
      c.name AS class_name, s.name AS subject_name
    FROM teacher_documents td
    JOIN classes c ON c.id = td.class_id
    LEFT JOIN subjects s ON s.id = td.subject_id
    WHERE td.teacher_id = ?
    ORDER BY td.created_at DESC
    LIMIT 250");
  $teacherDocumentsStmt->execute([$activeTeacherId]);
  $teacherDocuments = $teacherDocumentsStmt->fetchAll();
  foreach ($teacherDocuments as $docRow) {
    if (($docRow['status'] ?? '') === 'needs_correction' || ($docRow['hop_status'] ?? '') === 'needs_correction') {
      $teacherDocumentsNeedsCorrection++;
    }
  }

  $teacherInventoryStmt = $pdo->prepare("SELECT ir.id, ir.category, ir.item_name, ir.quantity_recorded,
      ir.item_condition, ir.inventory_note, ir.status, ir.stock_take_quantity,
      ir.accountant_review, ir.reviewed_at, ir.created_at,
      c.name AS class_name, reviewer.name AS reviewer_name
    FROM inventory_records ir
    JOIN classes c ON c.id = ir.class_id
    LEFT JOIN users reviewer ON reviewer.id = ir.reviewed_by
    WHERE ir.teacher_id = ?
    ORDER BY ir.created_at DESC
    LIMIT 300");
  $teacherInventoryStmt->execute([$activeTeacherId]);
  $teacherInventoryRecords = $teacherInventoryStmt->fetchAll();
  foreach ($teacherInventoryRecords as $inventoryRow) {
    if (($inventoryRow['status'] ?? '') === 'discrepancy') {
      $inventoryNeedsAction++;
    }
  }

  $teacherAnnouncementsStmt = $pdo->prepare("SELECT a.id, a.audience, a.title, a.body, a.status,
      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,
      a.admin_review_comment, a.reviewed_at, a.published_at, a.created_at,
      reviewer.name AS reviewer_name
    FROM announcements a
    LEFT JOIN users reviewer ON reviewer.id = a.reviewed_by
    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_id = ? AND a.sender_role = 'teacher'
    ORDER BY a.created_at DESC
    LIMIT 250");
  $teacherAnnouncementsStmt->execute([$activeTeacherId]);
  $teacherAnnouncementRows = $teacherAnnouncementsStmt->fetchAll();
  foreach ($teacherAnnouncementRows as $announcementRow) {
    if (($announcementRow['status'] ?? '') === 'pending_admin_review') {
      $teacherAnnouncementPendingCount++;
    }
  }

  $teacherTransferStmt = $pdo->prepare("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,
      p.name AS parent_name,
      l.full_name AS learner_name, l.reg_number, c.name AS class_name
    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
    WHERE EXISTS (
      SELECT 1 FROM teacher_subjects ts
      WHERE ts.teacher_id = ? AND ts.class_id = l.class_id
    ) OR EXISTS (
      SELECT 1 FROM class_teacher_assignments cta
      WHERE cta.teacher_id = ? AND cta.class_id = l.class_id
    )
    GROUP BY 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, p.name, l.full_name, l.reg_number, c.name
    ORDER BY tr.requested_at DESC
    LIMIT 300");
  $teacherTransferStmt->execute([$activeTeacherId, $activeTeacherId]);
  $teacherTransferRequests = $teacherTransferStmt->fetchAll();

  $teacherLeaveStmt = $pdo->prepare("SELECT tlr.id, tlr.leave_type, tlr.start_date, tlr.end_date, tlr.reason,
      tlr.supporting_document_path, tlr.supporting_document_name,
      tlr.status, tlr.admin_comment, tlr.reviewed_at, tlr.created_at
    FROM teacher_leave_requests tlr
    WHERE tlr.teacher_id = ?
    ORDER BY tlr.created_at DESC
    LIMIT 120");
  $teacherLeaveStmt->execute([$activeTeacherId]);
  $teacherLeaveRequests = $teacherLeaveStmt->fetchAll();

  $attendanceLookupStmt = $pdo->prepare("SELECT class_id, learner_id, attendance_date, status
    FROM daily_attendance_register
    WHERE teacher_id = ?");
  $attendanceLookupStmt->execute([$activeTeacherId]);
  foreach ($attendanceLookupStmt->fetchAll() as $attendanceRow) {
    $lookupKey = (int)$attendanceRow['class_id'] . '|' . (string)$attendanceRow['attendance_date'] . '|' . (int)$attendanceRow['learner_id'];
    $attendanceStatusLookup[$lookupKey] = (string)$attendanceRow['status'];
  }

  if ($attendanceSelectedClassId > 0 && in_array($attendanceSelectedClassId, $classTeacherClassIds, true)) {
    $attendanceSummaryStmt = $pdo->prepare("SELECT status, COUNT(*) AS total
      FROM daily_attendance_register
      WHERE teacher_id = ? AND class_id = ? AND attendance_date = ?
      GROUP BY status");
    $attendanceSummaryStmt->execute([$activeTeacherId, $attendanceSelectedClassId, $attendanceSelectedDate]);
  } else {
    $attendanceSummaryStmt = $pdo->prepare("SELECT status, COUNT(*) AS total
      FROM daily_attendance_register
      WHERE teacher_id = ? AND attendance_date = ?
      GROUP BY status");
    $attendanceSummaryStmt->execute([$activeTeacherId, $attendanceSelectedDate]);
  }
  foreach ($attendanceSummaryStmt->fetchAll() as $summaryRow) {
    $statusKey = (string)$summaryRow['status'];
    if (array_key_exists($statusKey, $attendanceSummary)) {
      $attendanceSummary[$statusKey] = (int)$summaryRow['total'];
    }
  }

  $recentAttendanceStmt = $pdo->prepare("SELECT dar.attendance_date, dar.status, l.reg_number, l.full_name AS learner_name,
      c.name AS class_name, dar.updated_at, dar.created_at
    FROM daily_attendance_register dar
    JOIN learners l ON l.id = dar.learner_id
    JOIN classes c ON c.id = dar.class_id
    WHERE dar.teacher_id = ?
    ORDER BY dar.attendance_date DESC, c.name, l.surname, l.christian_names, l.full_name
    LIMIT 250");
  $recentAttendanceStmt->execute([$activeTeacherId]);
  $recentAttendanceRows = $recentAttendanceStmt->fetchAll();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Teacher Dashboard | <?= h($schoolName) ?></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@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-ice: <?= h($paletteBrandIce) ?>;
      --patch-sky: <?= h($palettePatchSky) ?>;
      --patch-yellow: <?= h($palettePatchYellow) ?>;
      --panel: #ffffff;
      --line: #d6d3cb;
      --success: #166534;
      --danger: #9f1239;
      --shadow: 0 18px 45px rgba(10, 47, 99, 0.14);
      --radius-xl: 20px;
      --radius-lg: 14px;
    }

    * { box-sizing: border-box; }

    body {
      margin: 0;
      font-family: 'Outfit', sans-serif;
      min-height: 100vh;
      color: var(--ink);
      background:
        radial-gradient(circle at 10% 15%, rgba(248, 180, 0, 0.2) 0, rgba(248, 180, 0, 0) 42%),
        radial-gradient(circle at 82% 12%, rgba(124, 201, 255, 0.24) 0, rgba(124, 201, 255, 0) 38%),
        linear-gradient(170deg, var(--bg-cream) 0%, var(--bg-sand) 100%);
      padding: 20px;
    }

    .shell {
      max-width: 1240px;
      margin: 0 auto;
      display: grid;
      gap: 16px;
      animation: rise 420ms ease-out;
    }

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

    .header {
      background: linear-gradient(122deg, var(--brand-navy-deep), var(--brand-navy) 55%, var(--patch-sky));
      color: #fff;
      border-radius: var(--radius-xl);
      padding: 20px;
      box-shadow: var(--shadow);
      display: grid;
      gap: 14px;
      position: relative;
      overflow: hidden;
    }

    .header::after {
      content: '';
      position: absolute;
      width: 230px;
      height: 230px;
      right: -65px;
      top: -90px;
      border-radius: 50%;
      background: rgba(255, 212, 71, 0.2);
      border: 1px solid rgba(255, 212, 71, 0.34);
    }

    .top-row {
      display: flex;
      justify-content: space-between;
      gap: 10px;
      align-items: center;
      flex-wrap: wrap;
      position: relative;
      z-index: 1;
    }

    .brand {
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .logo {
      width: 64px;
      height: 64px;
      object-fit: contain;
      border-radius: 12px;
      border: 1px solid rgba(255, 255, 255, 0.3);
      background: rgba(255, 255, 255, 0.1);
      padding: 6px;
    }

    .title {
      margin: 0;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: clamp(1.3rem, 2.3vw, 1.9rem);
      font-weight: 800;
    }

    .subtitle {
      margin: 5px 0 0;
      opacity: 0.9;
      font-size: 0.96rem;
    }

    .chip {
      border-radius: 999px;
      padding: 7px 12px;
      font-size: 0.82rem;
      font-weight: 700;
      background: #ffd447;
      border: 1px solid #f8b400;
      color: #12386d;
      text-decoration: none;
      display: inline-flex;
      align-items: center;
      gap: 8px;
    }

    .stats {
      display: grid;
      grid-template-columns: repeat(4, minmax(0, 1fr));
      gap: 12px;
      position: relative;
      z-index: 1;
    }

    .stat {
      background: #fff;
      color: var(--ink);
      border-radius: var(--radius-lg);
      border: 1px solid rgba(10, 59, 121, 0.2);
      box-shadow: 0 8px 24px rgba(10, 59, 121, 0.08);
      padding: 14px;
      position: relative;
      overflow: hidden;
    }

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

    .stat small {
      text-transform: uppercase;
      letter-spacing: 0.07em;
      color: var(--muted);
      font-size: 0.78rem;
      font-weight: 700;
      display: block;
      margin-bottom: 7px;
    }

    .stat strong {
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.5rem;
    }

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

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

    .panel::before {
      content: '';
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 5px;
      background: linear-gradient(90deg, rgba(124, 201, 255, 0.5), rgba(255, 212, 71, 0.5));
    }

    .panel h2 {
      margin: 0;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 1.1rem;
    }

    .sub {
      color: var(--muted);
      margin: 8px 0 14px;
      font-size: 0.93rem;
    }

    .field {
      display: grid;
      gap: 5px;
      margin-bottom: 11px;
    }

    label {
      font-size: 0.82rem;
      text-transform: uppercase;
      letter-spacing: 0.06em;
      color: var(--muted);
      font-weight: 700;
    }

    input, select, textarea {
      width: 100%;
      font-family: inherit;
      font-size: 0.95rem;
      border: 1px solid #c8c8be;
      border-radius: 10px;
      padding: 10px 11px;
      color: var(--ink);
      background: #fff;
    }

    select option {
      color: var(--ink);
      background: #fff;
    }

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

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

    .btn {
      border: 0;
      border-radius: 11px;
      padding: 10px 14px;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-weight: 700;
      cursor: pointer;
      transition: background 160ms ease, color 160ms ease, transform 120ms ease;
      box-shadow: 0 0 0 2px rgba(124, 201, 255, 0.55), 0 0 0 4px rgba(255, 212, 71, 0.35);
    }

    .btn:hover {
      background: #7cc9ff;
      color: #083b78;
      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);
    }

    .btn:focus-visible {
      outline: none;
      box-shadow: 0 0 0 2px rgba(124, 201, 255, 0.95), 0 0 0 6px rgba(255, 212, 71, 0.65);
    }

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

    .btn.gold {
      background: linear-gradient(115deg, #ffd447, #f8b400);
      color: #17253f;
      width: 100%;
    }

    .btn.ghost {
      background: rgba(255, 255, 255, 0.15);
      color: #fff;
      border: 1px solid rgba(255, 255, 255, 0.35);
    }

    .alert {
      padding: 10px 12px;
      border-radius: 11px;
      border: 1px solid;
      font-size: 0.92rem;
      font-weight: 600;
      margin-bottom: 10px;
    }

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

    .table-wrap {
      border-radius: 14px;
      border: 1px solid var(--line);
      overflow-x: auto;
      overflow-y: hidden;
      background: #fff;
    }

    .full-width-stack {
      display: grid;
      gap: 12px;
    }

    .teacher-docs-table {
      min-width: 1180px;
    }

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

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

    td {
      border-top: 1px solid #eeebe3;
      padding: 10px 11px;
      color: #1f3359;
    }

    tr:nth-child(even) td {
      background: #fbfdff;
    }

    .badge {
      border-radius: 999px;
      padding: 3px 10px;
      font-size: 0.77rem;
      font-weight: 700;
      background: #eaf0fb;
      color: #1a4a8a;
      border: 1px solid #bfd4f4;
      display: inline-block;
    }

    .teacher-select {
      display: flex;
      gap: 10px;
      flex-wrap: wrap;
      align-items: end;
    }

    .teacher-select .field {
      margin: 0;
      flex: 1;
      min-width: 230px;
    }

    .no-access {
      background: #fffdf7;
      border: 1px dashed #d7c8a8;
      padding: 14px;
      border-radius: 12px;
      color: #7c5f19;
      font-weight: 600;
    }

    .subject-list {
      display: grid;
      gap: 7px;
      grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    }

    .subject-item {
      border: 1px solid #d8def0;
      background: #f8fbff;
      border-radius: 10px;
      padding: 10px;
    }

    .subject-item strong {
      display: block;
      margin-bottom: 5px;
      color: #0f3d7e;
    }

    .type-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
      gap: 8px;
      margin-top: 8px;
    }

    .type-chip {
      border: 1px solid #d8def0;
      background: #f8fbff;
      border-radius: 10px;
      padding: 9px;
      font-size: 0.88rem;
      color: #173b70;
      display: flex;
      justify-content: space-between;
      gap: 10px;
      font-weight: 600;
    }

    .mark-sheet-wrap {
      border: 1px solid #d8def0;
      border-radius: 12px;
      overflow: hidden;
      margin-bottom: 11px;
      background: #fff;
    }

    .mark-sheet-wrap table {
      font-size: 0.9rem;
    }

    .mark-sheet-wrap th,
    .mark-sheet-wrap td {
      padding: 8px;
    }

    .score-input {
      min-width: 90px;
    }

    .bulk-learner-row.missing-mark td {
      background: #fff1f2 !important;
    }

    .bulk-learner-row.missing-mark .score-input {
      border-color: #e11d48;
      box-shadow: 0 0 0 2px rgba(225, 29, 72, 0.15);
    }

    .search {
      margin-bottom: 10px;
    }

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

    .marks-actions {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      margin-bottom: 10px;
      align-items: center;
    }

    .btn.small {
      width: auto;
      padding: 8px 12px;
      font-size: 0.85rem;
      border-radius: 9px;
    }

    .btn.outline {
      background: #fff;
      color: var(--brand-navy);
      border: 1px solid #bfd4f4;
    }

    .btn.outline:hover {
      background: #7cc9ff;
      color: #083b78;
      border-color: #5fb7e6;
    }

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

    .marks-view {
      display: none;
      animation: rise 220ms ease-out;
    }

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

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

    .desk-sidebar {
      position: sticky;
      top: 14px;
      max-height: calc(100vh - 24px);
      overflow: auto;
      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;
    }

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

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

    .nav-alert-count {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      min-width: 20px;
      height: 20px;
      margin-left: 8px;
      padding: 0 6px;
      border-radius: 999px;
      background: #be123c;
      color: #fff;
      font-size: 0.72rem;
      font-weight: 800;
      line-height: 1;
      vertical-align: middle;
    }

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

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

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

    .panel-grid.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;
    }

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

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

    .library-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
      gap: 10px;
      margin-top: 8px;
    }

    .resource-card {
      border: 1px solid #d8def0;
      border-radius: 12px;
      padding: 10px;
      background: #f8fbff;
    }

    .resource-card h4 {
      margin: 0 0 8px;
      color: #0f3d7e;
      font-family: 'Plus Jakarta Sans', sans-serif;
      font-size: 0.95rem;
    }

    .resource-list {
      margin: 0;
      padding-left: 16px;
      display: grid;
      gap: 6px;
    }

    .resource-list li {
      color: #1f3359;
      font-size: 0.9rem;
    }

    .platform-links {
      margin: 0;
      padding-left: 16px;
      display: grid;
      gap: 8px;
    }

    .platform-links li {
      color: #1f3359;
      font-size: 0.9rem;
    }

    .meta-ai-box {
      border: 1px solid #bfd4f4;
      border-radius: 12px;
      background: #f2f8ff;
      padding: 12px;
      margin-bottom: 12px;
    }

    .mono {
      font-family: 'Courier New', monospace;
      font-size: 0.82rem;
      color: #304a71;
    }

    .tiny {
      font-size: 0.8rem;
      color: var(--muted);
    }

    .doc-correction {
      background: #fff1f2 !important;
    }

    .doc-correction td {
      border-top-color: #fda4af;
    }

    @media (max-width: 980px) {
      .stats { grid-template-columns: 1fr; }
      .panel-grid { grid-template-columns: 1fr; }
      .desk-layout { grid-template-columns: 1fr; }
      .desk-sidebar { position: static; }
    }

    @media (max-width: 560px) {
      body { padding: 12px; }
      .logo { width: 56px; height: 56px; }
      .panel { padding: 14px; }
      th, td { padding: 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="top-row">
        <div class="brand">
          <img class="logo" src="<?= h($resolvedSchoolLogoPath !== '' ? $resolvedSchoolLogoPath : $defaultSchoolLogoPath) ?>" alt="<?= h($schoolName) ?> logo">
          <div>
            <h1 class="title">Teacher Dashboard</h1>
            <?php if ($isAdminReadOnlyView): ?>
              <p class="subtitle">Admin read-only preview for teacher: <?= h($activeTeacher['name']) ?>. All update actions are disabled in this mode.</p>
            <?php else: ?>
              <p class="subtitle">Signed in as <?= h($activeTeacher['name']) ?>. You can only work with your assigned classes and learners.</p>
            <?php endif; ?>
          </div>
        </div>
        <div style="display:flex; gap:8px; flex-wrap:wrap;">
          <span class="chip" id="teacherDeskProgressChip">Step 1 of 14</span>
          <?php if ($isAdminReadOnlyView): ?>
            <a class="chip" href="admin.php">Back to Admin Portal</a>
          <?php endif; ?>
          <a class="chip" href="logout.php">Logout</a>
          <span class="chip"><?= h(date('D, d M Y')) ?></span>
        </div>
      </div>

      <?php if ($isAdminReadOnlyView): ?>
        <form method="GET" style="margin-top:10px; display:flex; gap:8px; flex-wrap:wrap; align-items:end;">
          <input type="hidden" name="admin_view" value="1">
          <div class="field" style="margin:0; min-width:320px;">
            <label for="admin_teacher_preview_id" style="color:#e2e8f0;">Preview Teacher</label>
            <select id="admin_teacher_preview_id" name="teacher_id" required>
              <?php foreach ($teacherViewOptions as $teacherOption): ?>
                <option value="<?= h($teacherOption['id']) ?>" <?= (int)$teacherOption['id'] === (int)$activeTeacher['id'] ? 'selected' : '' ?>>
                  <?= h($teacherOption['name']) ?> (<?= h($teacherOption['email']) ?>)
                </option>
              <?php endforeach; ?>
            </select>
          </div>
          <button class="btn outline small" type="submit">Open Teacher Preview</button>
        </form>
      <?php endif; ?>
    </header>

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

    <?php if ($activeTeacher): ?>
      <div class="desk-layout">
        <aside class="desk-sidebar">
          <h3>Teacher Menu</h3>
          <nav class="desk-nav" id="teacherDeskNav">
            <button type="button" class="desk-nav-btn active" data-target="teacherHomeView">Summary, Graphs and Trends</button>
            <button type="button" class="desk-nav-btn" data-target="teacherProfileView">My Profile</button>
            <button type="button" class="desk-nav-btn" data-targets="teacherScopeView,teacherAdmissionNotesView,teacherRegisterView">Student Records</button>
            <button type="button" class="desk-nav-btn" data-targets="teacherCaptureCoverageView,teacherRecentMarksView,teacherIndividualView">Student Marks</button>
            <button type="button" class="desk-nav-btn" data-target="teacherAttendanceView">Daily Attendance Register</button>
            <button type="button" class="desk-nav-btn" data-target="teacherMajorExamReportCardsView">Student Report Cards</button>
            <button type="button" class="desk-nav-btn" data-target="teacherElearningView">E-learning Hub</button>
            <button type="button" class="desk-nav-btn" data-target="teacherELibraryView">E-Library</button>
            <button type="button" class="desk-nav-btn" data-target="teacherUploadsView">Teacher Uploads<?php if ($teacherDocumentsNeedsCorrection > 0): ?><span class="nav-alert-count"><?= h($teacherDocumentsNeedsCorrection) ?></span><?php endif; ?></button>
            <button type="button" class="desk-nav-btn" data-target="teacherInventoryView">Inventory<?php if ($inventoryNeedsAction > 0): ?><span class="nav-alert-count"><?= h($inventoryNeedsAction) ?></span><?php endif; ?></button>
            <button type="button" class="desk-nav-btn" data-target="teacherTransferClearanceView">Transfer Clearances</button>
            <button type="button" class="desk-nav-btn" data-target="teacherLeaveRequestsView">Leave Requests</button>
            <button type="button" class="desk-nav-btn" data-target="teacherAnnouncementsView">Announcements<?php if ($teacherAnnouncementPendingCount > 0): ?><span class="nav-alert-count"><?= h($teacherAnnouncementPendingCount) ?></span><?php endif; ?></button>
            <button type="button" class="desk-nav-btn" data-target="teacherRecentNotesView">Recent Notes</button>
          </nav>
        </aside>

        <div class="desk-main">
      <section id="teacherHomeView" class="desk-view active">
      <section class="stats">
        <article class="stat">
          <small>Active Teacher</small>
          <strong><?= h($activeTeacher['name']) ?></strong>
        </article>
        <article class="stat">
          <small>Assigned Classes</small>
          <strong><?= h($totalClasses) ?></strong>
        </article>
        <article class="stat">
          <small>Learners in My Classes</small>
          <strong><?= h($totalLearners) ?></strong>
        </article>
        <article class="stat">
          <small>Total Marks Captured</small>
          <strong><?= h($totalMarks) ?></strong>
        </article>
      </section>

      <section class="panel">
        <h2>Assessment Trends</h2>
        <p class="sub">Quick trend bars showing how often each assessment type is being captured.</p>
        <?php
          $trendValues = array_values(array_map(fn($v) => (int)$v, $marksByType));
          $maxTypeCount = max(1, ...($trendValues ?: [0]));
        ?>
        <div class="trend-bars">
          <?php foreach ($assessmentTypes as $typeKey => $typeLabel): ?>
            <?php $typeCount = (int)($marksByType[$typeKey] ?? 0); $typeWidth = (int)round(($typeCount / $maxTypeCount) * 100); ?>
            <div class="trend-bar">
              <div class="head">
                <span><?= h($typeLabel) ?></span>
                <span><?= h($typeCount) ?></span>
              </div>
              <div class="meter"><div class="fill" style="width: <?= h($typeWidth) ?>%"></div></div>
            </div>
          <?php endforeach; ?>
        </div>
      </section>
      </section>

      <section id="teacherProfileView" class="panel-grid desk-view">
        <article class="panel">
          <h2>My Teacher Profile</h2>
          <?php if ($isAdminReadOnlyView): ?>
            <p class="sub">Profile editing is disabled in admin read-only preview mode.</p>
          <?php else: ?>
            <p class="sub">Update your personal details and password for secure access.</p>
            <form method="POST" autocomplete="off" style="margin-bottom:12px;">
              <div class="field">
                <label for="teacher_profile_name">Full Name</label>
                <input id="teacher_profile_name" name="profile_name" value="<?= h((string)$activeTeacher['name']) ?>" required>
              </div>
              <div class="field">
                <label for="teacher_profile_email">Email Address</label>
                <input id="teacher_profile_email" type="email" name="profile_email" value="<?= h((string)$activeTeacher['email']) ?>" required>
              </div>
              <div class="field">
                <label for="teacher_sex">Sex</label>
                <select id="teacher_sex" name="teacher_sex">
                  <option value="">Choose sex</option>
                  <option value="Male" <?= (string)($activeTeacher['sex'] ?? '') === 'Male' ? 'selected' : '' ?>>Male</option>
                  <option value="Female" <?= (string)($activeTeacher['sex'] ?? '') === 'Female' ? 'selected' : '' ?>>Female</option>
                  <option value="Other" <?= (string)($activeTeacher['sex'] ?? '') === 'Other' ? 'selected' : '' ?>>Other</option>
                </select>
              </div>
              <div class="field">
                <label for="teacher_dob">Date of Birth</label>
                <input id="teacher_dob" type="date" name="teacher_dob" value="<?= h((string)($activeTeacher['date_of_birth'] ?? '')) ?>">
              </div>
              <div class="field">
                <label for="teacher_ec_number">EC#</label>
                <input id="teacher_ec_number" name="teacher_ec_number" value="<?= h((string)($activeTeacher['ec_number'] ?? '')) ?>">
              </div>
              <div class="field">
                <label for="teacher_national_id">ID#</label>
                <input id="teacher_national_id" name="teacher_national_id" value="<?= h((string)($activeTeacher['national_id'] ?? '')) ?>">
              </div>
              <div class="field">
                <label for="teacher_qualifications">Qualifications</label>
                <textarea id="teacher_qualifications" name="teacher_qualifications" rows="4"><?= h((string)($activeTeacher['qualifications'] ?? '')) ?></textarea>
              </div>
              <div class="field">
                <label for="teacher_subject_specialization">Subject Specialization</label>
                <input id="teacher_subject_specialization" name="teacher_subject_specialization" value="<?= h((string)($activeTeacher['subject_specialization'] ?? '')) ?>" placeholder="e.g. Mathematics, Biology, English Literature">
              </div>
              <button class="btn primary" type="submit" name="save_teacher_profile">Save Profile</button>
            </form>

            <form method="POST" autocomplete="off">
              <div class="field">
                <label for="teacher_current_password">Current Password</label>
                <input id="teacher_current_password" type="password" name="current_password" required>
              </div>
              <div class="field">
                <label for="teacher_new_password">New Password</label>
                <input id="teacher_new_password" type="password" name="new_password" minlength="10" autocomplete="new-password" required>
              </div>
              <div class="field">
                <label for="teacher_confirm_password">Confirm New Password</label>
                <input id="teacher_confirm_password" type="password" name="confirm_password" minlength="10" autocomplete="new-password" required>
              </div>
              <button class="btn" type="submit" name="change_teacher_password">Change Password</button>
            </form>
          <?php endif; ?>
        </article>
      </section>

      <section id="teacherScopeView" class="panel desk-view">
        <h2>My Class and Subject Scope</h2>
        <p class="sub">Subject teaching scope and class-teacher duty scope are shown separately.</p>

        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleScopeBtn">Show Class and Subject Scope</button>
        </div>

        <div id="scopeView" class="marks-view">
          <?php if (empty($allowedClasses) && empty($classTeacherClasses)): ?>
            <div class="no-access">No scope has been assigned yet. Ask admin to assign subjects and class teacher duties.</div>
          <?php else: ?>
            <h3 style="margin:0 0 8px;">Subject Teaching Scope</h3>
            <?php if (empty($allowedClasses)): ?>
              <div class="no-access" style="margin-bottom:10px;">No subject-teaching classes assigned yet.</div>
            <?php else: ?>
            <div class="subject-list">
              <?php foreach ($subjectsByClass as $className => $subjectNames): ?>
                <div class="subject-item">
                  <strong><?= h($className) ?></strong>
                  <span><?= h(implode(', ', $subjectNames)) ?></span>
                </div>
              <?php endforeach; ?>
            </div>
            <?php endif; ?>

            <h3 style="margin:14px 0 8px;">Class Teacher Duty Scope</h3>
            <?php if (empty($classTeacherClasses)): ?>
              <div class="no-access">No class-teacher allocation yet.</div>
            <?php else: ?>
              <div class="subject-list">
                <?php foreach ($classTeacherClasses as $classRow): ?>
                  <div class="subject-item">
                    <strong><?= h($classRow['name']) ?></strong>
                    <span>Attendance, learner records, parent liaison, and class tracking enabled.</span>
                  </div>
                <?php endforeach; ?>
              </div>
            <?php endif; ?>
          <?php endif; ?>
        </div>
      </section>

      <section id="teacherAdmissionNotesView" class="panel-grid desk-view">
        <article class="panel">
          <h2>Student Admission Form</h2>
          <p class="sub">Capture learner and parent or guardian details in the same structure as the admission register.</p>

          <div class="marks-actions">
            <button type="button" class="btn primary small" id="toggleAdmissionFormBtn">Show Student Admission Form</button>
          </div>

          <div id="admissionFormView" class="marks-view">
            <form method="POST" enctype="multipart/form-data">
            <div class="field">
              <label for="class_id">Class</label>
              <div class="search" style="margin-bottom:8px;">
                <input type="search" id="admissionClassSearch" placeholder="Search class...">
              </div>
              <select name="class_id" id="class_id" required>
                <option value="">Choose class</option>
                <?php foreach ($classTeacherClasses as $classRow): ?>
                  <option value="<?= h($classRow['id']) ?>"><?= h($classRow['name']) ?></option>
                <?php endforeach; ?>
              </select>
            </div>
            <?php if (empty($classTeacherClasses)): ?>
              <div class="no-access" style="margin-bottom:10px;">No class-teacher class allocated yet. Ask admin to allocate your class.</div>
            <?php endif; ?>
            <p class="sub" 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">
            </div>
            <div class="field">
              <label for="surname">Surname</label>
              <input id="surname" name="surname" placeholder="e.g. Moyo" required>
            </div>
            <div class="field">
              <label for="christian_names">Christian Names</label>
              <input id="christian_names" name="christian_names" placeholder="e.g. Sipho Themba" required>
            </div>
            <div class="field">
              <label for="date_of_birth_info">Date of Birth (or Year if exact date unknown)</label>
              <input id="date_of_birth_info" name="date_of_birth_info" placeholder="e.g. 2015-04-12 or 2015">
            </div>
            <div class="field">
              <label for="birth_certificate_number">Birth Certificate Number</label>
              <input id="birth_certificate_number" name="birth_certificate_number" placeholder="Optional">
            </div>
            <div class="field">
              <label for="religious_denomination">Religious Denomination</label>
              <input id="religious_denomination" name="religious_denomination" placeholder="Optional">
            </div>
            <div class="field">
              <label for="gender">Gender</label>
              <select id="gender" name="gender" required>
                <option value="Male">Male</option>
                <option value="Female">Female</option>
                <option value="Other" selected>Other</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">
            </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">
            </div>
            <div class="field">
              <label for="guardian_address">Parent/Guardian Address</label>
              <input id="guardian_address" name="guardian_address" placeholder="Optional">
            </div>
            <div class="field">
              <label for="guardian_phone">Guardian Phone</label>
              <input id="guardian_phone" name="guardian_phone" placeholder="Optional">
            </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">
              <small class="tiny">Recommended: clear headshot, max 5MB, JPG/PNG/WEBP.</small>
            </div>
            <button class="btn primary" type="submit" name="add_learner">Save Learner</button>
            </form>
          </div>
        </article>

        <article class="panel">
          <h2>Class Learner Notes</h2>
          <p class="sub">Write progress or behavior notes only for learners in your own class list.</p>

          <div class="marks-actions">
            <button type="button" class="btn primary small" id="toggleClassNotesFormBtn">Show Class Learner Notes</button>
          </div>

          <div id="classNotesFormView" class="marks-view">

          <form method="POST">
            <div class="field">
              <label for="learner_id">Learner</label>
              <div class="search" style="margin-bottom:8px;">
                <input type="search" id="learnerPickerSearch" placeholder="Search learner name...">
              </div>
              <select name="learner_id" id="learner_id" required>
                <option value="">Choose learner</option>
                <?php foreach ($classTeacherLearners as $learner): ?>
                  <option value="<?= h($learner['id']) ?>"><?= h(learner_display_name($learner['full_name'], $learner['class_name'])) ?> - <?= h($learner['class_name']) ?></option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="field">
              <label for="note_text">Note</label>
              <textarea name="note_text" id="note_text" placeholder="Write learner update..." required></textarea>
            </div>
            <button class="btn gold" type="submit" name="add_note">Save Note</button>
          </form>

          <div style="margin-top:14px;">
            <span class="badge"><?= h($totalNotes) ?> notes recorded by this teacher</span>
          </div>
          </div>
        </article>
      </section>

      <section id="teacherCaptureCoverageView" class="panel-grid desk-view">
        <article class="panel">
          <h2>Capture Learner Marks</h2>
          <p class="sub">Choose class, subject, and test once. Learners populate in one sheet. Existing marks for the same test are auto-loaded for quick editing.</p>

          <div class="marks-actions">
            <button type="button" class="btn primary small" id="toggleCaptureMarksBtn">Show Capture Learner Marks</button>
          </div>

          <div id="captureMarksView" class="marks-view">
            <form method="POST" id="marksForm">
            <div class="field">
              <label for="mark_class_id">Class</label>
              <div class="search" style="margin-bottom:8px;">
                <input type="search" id="markClassSearch" placeholder="Search class...">
              </div>
              <select name="mark_class_id" id="mark_class_id" required>
                <option value="">Choose class</option>
                <?php foreach ($allowedClasses as $classRow): ?>
                  <option value="<?= h($classRow['id']) ?>"><?= h($classRow['name']) ?></option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="field">
              <label for="mark_subject_id">Subject</label>
              <div class="search" style="margin-bottom:8px;">
                <input type="search" id="markSubjectSearch" placeholder="Search subject...">
              </div>
              <select name="mark_subject_id" id="mark_subject_id" required>
                <option value="">Choose class first</option>
                <?php foreach ($assignedSubjects as $subject): ?>
                  <option value="<?= h($subject['subject_id']) ?>" data-class="<?= h($subject['class_id']) ?>" style="display:none;">
                    <?= h($subject['subject_name']) ?> (<?= h($subject['class_name']) ?>)
                  </option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="field">
              <label>Learners for selected class</label>
              <div class="mark-sheet-wrap">
                <table id="bulkMarkTable">
                  <thead>
                    <tr>
                      <th>Reg #</th>
                      <th>Learner</th>
                      <th>Score</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr id="markSheetHint"><td colspan="3">Choose class and subject to load learners.</td></tr>
                    <?php if (!empty($activeLearners)): ?>
                      <?php foreach ($activeLearners as $learner): ?>
                        <tr class="bulk-learner-row" data-class="<?= h($learner['class_id']) ?>" style="display:none;">
                          <td><?= h($learner['reg_number']) ?></td>
                          <td><?= h(learner_display_name($learner['full_name'], $learner['class_name'])) ?></td>
                          <td>
                            <input class="score-input" type="number" step="0.01" min="0" name="mark_scores[<?= h($learner['id']) ?>]" data-learner-id="<?= h($learner['id']) ?>" placeholder="Score">
                          </td>
                        </tr>
                      <?php endforeach; ?>
                    <?php endif; ?>
                  </tbody>
                </table>
              </div>
            </div>
            <div class="field">
              <label for="assessment_type">Assessment Type</label>
              <select name="assessment_type" id="assessment_type" required>
                <?php foreach ($assessmentTypes as $typeKey => $typeLabel): ?>
                  <option value="<?= h($typeKey) ?>"><?= h($typeLabel) ?></option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="field">
              <label for="term_name">Term</label>
              <select name="term_name" id="term_name" required>
                <option value="Term 1">Term 1</option>
                <option value="Term 2">Term 2</option>
                <option value="Term 3">Term 3</option>
              </select>
            </div>
            <div class="field">
              <label for="assessment_date">Assessment Date</label>
              <input type="date" name="assessment_date" id="assessment_date" required>
            </div>
            <div class="field">
              <label for="max_score">Maximum Score</label>
              <input type="number" step="0.01" min="1" name="max_score" id="max_score" placeholder="e.g. 20" required>
            </div>
            <button class="btn primary" type="submit" name="save_marks_bulk">Save All Entered Marks</button>
            <p id="markEntryStatus" class="sub" style="margin-top:8px;">Choose class and subject to begin entering marks.</p>
            </form>
          </div>
        </article>

        <article class="panel">
          <h2>Assessment Coverage Summary</h2>
          <p class="sub">Quick view of marks loaded by this teacher per assessment type.</p>

          <div class="marks-actions">
            <button type="button" class="btn primary small" id="toggleCoverageBtn">Show Assessment Coverage Summary</button>
            <button type="button" class="btn outline small" id="printCoverageBtn" disabled>Print</button>
            <button type="button" class="btn outline small" id="downloadCoveragePdfBtn" disabled>Download PDF</button>
            <button type="button" class="btn outline small" id="downloadCoverageCsvBtn" disabled>Download CSV</button>
          </div>

          <div id="coverageView" class="marks-view">
            <div class="type-grid">
              <?php foreach ($assessmentTypes as $typeKey => $typeLabel): ?>
                <div class="type-chip">
                  <span><?= h($typeLabel) ?></span>
                  <span><?= h($marksByType[$typeKey] ?? 0) ?></span>
                </div>
              <?php endforeach; ?>
            </div>
            <div style="margin-top:14px;">
              <span class="badge">All captured marks remain restricted to this teacher and assigned class scope.</span>
            </div>

            <div class="table-wrap" style="margin-top:12px;">
              <table id="coverageTable">
                <thead>
                  <tr>
                    <th>Assessment Type</th>
                    <th>Total Records</th>
                  </tr>
                </thead>
                <tbody>
                  <?php foreach ($assessmentTypes as $typeKey => $typeLabel): ?>
                    <tr>
                      <td><?= h($typeLabel) ?></td>
                      <td><?= h($marksByType[$typeKey] ?? 0) ?></td>
                    </tr>
                  <?php endforeach; ?>
                </tbody>
              </table>
            </div>
          </div>
        </article>
      </section>

      <section id="teacherRecentMarksView" class="panel desk-view">
        <h2>Recent Marks Captured</h2>
        <p class="sub">History of marks entered by this teacher only.</p>

        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleMarksBtn">Show Marks</button>
          <button type="button" class="btn outline small" id="printMarksBtn" disabled>Print</button>
          <button type="button" class="btn outline small" id="downloadPdfBtn" disabled>Download PDF</button>
          <button type="button" class="btn outline small" id="downloadCsvBtn" disabled>Download CSV</button>
        </div>

        <div id="marksView" class="marks-view">
          <div class="search">
            <input type="search" id="markSearch" placeholder="Search by learner, class, subject, assessment type...">
          </div>
          <div class="table-wrap">
            <table id="markTable">
              <thead>
                <tr>
                  <th>Date</th>
                  <th>Photo</th>
                  <th>Learner</th>
                  <th>Class</th>
                  <th>Subject</th>
                  <th>Assessment</th>
                  <th>Term</th>
                  <th>Score</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($recentMarks)): ?>
                  <tr><td colspan="8">No marks captured yet.</td></tr>
                <?php else: ?>
                  <?php foreach ($recentMarks as $mark): ?>
                    <?php $percent = $mark['max_score'] > 0 ? round(((float)$mark['score'] / (float)$mark['max_score']) * 100, 1) : 0; ?>
                    <tr>
                      <td><?= h($mark['assessment_date']) ?></td>
                      <td>
                        <?php if (!empty($mark['student_photo_path'])): ?>
                          <a href="<?= h($mark['student_photo_path']) ?>" target="_blank" rel="noopener">
                            <img src="<?= h($mark['student_photo_path']) ?>" alt="Learner photo" style="width:40px;height:40px;object-fit:cover;border-radius:8px;border:1px solid #d8def0;">
                          </a>
                        <?php else: ?>
                          <span class="tiny">No Photo</span>
                        <?php endif; ?>
                      </td>
                      <td><?= h(learner_display_name($mark['learner_name'], $mark['class_name'])) ?></td>
                      <td><?= h($mark['class_name']) ?></td>
                      <td><?= h($mark['subject_name']) ?></td>
                      <td><?= h($assessmentTypes[$mark['assessment_type']] ?? $mark['assessment_type']) ?></td>
                      <td><?= h($mark['term_name']) ?></td>
                      <td><?= h($mark['score']) ?>/<?= h($mark['max_score']) ?> (<?= h($percent) ?>%)</td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </div>
      </section>

      <section id="teacherRegisterView" class="panel desk-view">
        <h2>My Learner Register</h2>
        <p class="sub">This list is restricted to the active teacher's assigned classes only.</p>
        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleLearnersBtn">Show Learner Register</button>
          <button type="button" class="btn outline small" id="printLearnersBtn" disabled>Print</button>
          <button type="button" class="btn outline small" id="downloadLearnersPdfBtn" disabled>Download PDF</button>
          <button type="button" class="btn outline small" id="downloadLearnersCsvBtn" disabled>Download CSV</button>
        </div>
        <div id="learnerView" class="marks-view">
          <div class="search">
            <input type="search" id="learnerSearch" placeholder="Search learner by name, reg number, class...">
          </div>
          <div class="table-wrap">
            <table id="learnerTable">
              <thead>
                <tr>
                  <th>Photo</th>
                  <th>Reg number</th>
                  <th>Date of admission</th>
                  <th>Surname</th>
                  <th>Christian names</th>
                  <th>Date of Birth (Give year if date not known)</th>
                  <th>Birth Certificate No.</th>
                  <th>Religious denomination</th>
                  <th>Surname Give all first two names in full</th>
                  <th>National registration number</th>
                  <th>Address</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($learners)): ?>
                  <tr><td colspan="11">No learners found yet in your classes.</td></tr>
                <?php else: ?>
                  <?php foreach ($learners as $learner): ?>
                    <tr>
                      <td>
                        <?php if (!empty($learner['student_photo_path'])): ?>
                          <a href="<?= h($learner['student_photo_path']) ?>" target="_blank" rel="noopener">
                            <img src="<?= h($learner['student_photo_path']) ?>" alt="Learner photo" style="width:40px;height:40px;object-fit:cover;border-radius:8px;border:1px solid #d8def0;">
                          </a>
                        <?php else: ?>
                          <span class="tiny">No Photo</span>
                        <?php endif; ?>
                      </td>
                      <td><?= h($learner['reg_number']) ?></td>
                      <td><?= h($learner['date_of_admission']) ?></td>
                      <td><?= h($learner['surname']) ?></td>
                      <td><?= h($learner['christian_names']) ?></td>
                      <td><?= h($learner['date_of_birth_info']) ?></td>
                      <td><?= h($learner['birth_certificate_number'] ?: '-') ?></td>
                      <td><?= h($learner['religious_denomination']) ?></td>
                      <td><?= h($learner['guardian_name']) ?></td>
                      <td><?= h($learner['guardian_national_id']) ?></td>
                      <td><?= h($learner['guardian_address']) ?></td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </div>
      </section>

      <section id="teacherAttendanceView" class="panel desk-view">
        <h2>Daily Attendance Register</h2>
        <p class="sub">Capture daily attendance for classes where you are allocated as class teacher. Existing attendance for a selected class and date is auto-loaded for editing.</p>

        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleAttendanceRegisterBtn">Show Daily Attendance Register</button>
        </div>

        <div id="attendanceRegisterView" class="marks-view">
          <form method="POST" id="attendanceForm">
            <div class="field">
              <label for="attendance_class_id">Class</label>
              <div class="search" style="margin-bottom:8px;">
                <input type="search" id="attendanceClassSearch" placeholder="Search class...">
              </div>
              <select name="attendance_class_id" id="attendance_class_id" required>
                <option value="">Choose class</option>
                <?php foreach ($classTeacherClasses as $classRow): ?>
                  <option value="<?= h($classRow['id']) ?>" <?= $attendanceSelectedClassId === (int)$classRow['id'] ? 'selected' : '' ?>><?= h($classRow['name']) ?></option>
                <?php endforeach; ?>
              </select>
            </div>

            <div class="field">
              <label for="attendance_date">Attendance Date</label>
              <input type="date" name="attendance_date" id="attendance_date" value="<?= h($attendanceSelectedDate) ?>" required>
            </div>

            <div class="table-wrap">
              <table id="attendanceTable">
                <thead>
                  <tr>
                    <th>Reg #</th>
                    <th>Learner</th>
                    <th>Class</th>
                    <th>Status</th>
                  </tr>
                </thead>
                <tbody>
                  <tr id="attendanceEmptyHint"><td colspan="4">Choose class to mark daily attendance.</td></tr>
                  <?php foreach ($classTeacherLearners as $learner): ?>
                    <?php
                      $attendanceKey = (int)$learner['class_id'] . '|' . $attendanceSelectedDate . '|' . (int)$learner['id'];
                      $savedAttendanceStatus = $attendanceStatusLookup[$attendanceKey] ?? 'present';
                    ?>
                    <tr class="attendance-row" data-class="<?= h($learner['class_id']) ?>" style="display:none;">
                      <td><?= h($learner['reg_number']) ?></td>
                      <td><?= h(learner_display_name($learner['full_name'], $learner['class_name'])) ?></td>
                      <td><?= h($learner['class_name']) ?></td>
                      <td>
                        <select name="attendance_status[<?= h($learner['id']) ?>]" data-learner-id="<?= h($learner['id']) ?>" class="attendance-status-select">
                          <?php foreach ($attendanceStatuses as $attendanceStatusKey => $attendanceStatusLabel): ?>
                            <option value="<?= h($attendanceStatusKey) ?>" <?= $savedAttendanceStatus === $attendanceStatusKey ? 'selected' : '' ?>><?= h($attendanceStatusLabel) ?></option>
                          <?php endforeach; ?>
                        </select>
                      </td>
                    </tr>
                  <?php endforeach; ?>
                </tbody>
              </table>
            </div>

            <button class="btn primary" type="submit" name="save_daily_attendance" style="margin-top:10px;">Save Daily Attendance</button>
          </form>

          <div style="margin-top:12px; display:flex; gap:8px; flex-wrap:wrap;">
            <span class="badge">Present: <?= h($attendanceSummary['present']) ?></span>
            <span class="badge">Absent: <?= h($attendanceSummary['absent']) ?></span>
            <span class="badge">Late: <?= h($attendanceSummary['late']) ?></span>
            <span class="badge">Excused: <?= h($attendanceSummary['excused']) ?></span>
          </div>

          <div class="table-wrap" style="margin-top:12px;">
            <table id="attendanceRecentTable">
              <thead>
                <tr>
                  <th>Date</th>
                  <th>Learner</th>
                  <th>Class</th>
                  <th>Status</th>
                  <th>Last Updated</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($recentAttendanceRows)): ?>
                  <tr><td colspan="5">No attendance records saved yet.</td></tr>
                <?php else: ?>
                  <?php foreach ($recentAttendanceRows as $attendanceRow): ?>
                    <tr>
                      <td><?= h($attendanceRow['attendance_date']) ?></td>
                      <td>
                        <strong><?= h(learner_display_name($attendanceRow['learner_name'], $attendanceRow['class_name'])) ?></strong><br>
                        <small><?= h($attendanceRow['reg_number']) ?></small>
                      </td>
                      <td><?= h($attendanceRow['class_name']) ?></td>
                      <td><span class="badge"><?= h(ucfirst($attendanceRow['status'])) ?></span></td>
                      <td><?= h($attendanceRow['updated_at'] ?: $attendanceRow['created_at']) ?></td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </div>
      </section>

      <section id="teacherMajorExamReportCardsView" class="panel desk-view">
        <h2>Student Report Cards for Major Exams</h2>
        <p class="sub">Consolidated learner performance for End of Term 1, Midyear, and End of Year exams.</p>
        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleMajorExamReportCardsBtn">Show Student Report Cards</button>
          <button type="button" class="btn outline small" id="printMajorExamReportCardsBtn" disabled>Print</button>
          <button type="button" class="btn outline small" id="downloadMajorExamReportCardsPdfBtn" disabled>Download PDF</button>
          <button type="button" class="btn outline small" id="downloadMajorExamReportCardsCsvBtn" disabled>Download CSV</button>
        </div>

        <div id="majorExamReportCardsView" class="marks-view">
          <div class="panel" style="margin-bottom:12px;">
            <h2 style="margin-top:0;">Generate Card Like Official Format</h2>
            <p class="sub">Select learner and exam period, then generate a printable report card layout similar to the sample.</p>
            <div class="panel-grid">
              <div class="field">
                <label for="reportCardExamType">Exam Period</label>
                <select id="reportCardExamType">
                  <option value="end_of_term_exam_term1">End of Term 1</option>
                  <option value="midyear_exam">Midyear</option>
                  <option value="end_of_year_exam">End of Year</option>
                </select>
              </div>
              <div class="field">
                <label for="reportCardLearnerId">Learner</label>
                <div class="search" style="margin-bottom:8px;">
                  <input type="search" id="reportCardLearnerSearch" placeholder="Search learner name...">
                </div>
                <select id="reportCardLearnerId">
                  <option value="">Choose learner</option>
                  <?php foreach ($learners as $learner): ?>
                    <option value="<?= h($learner['id']) ?>"><?= h(learner_display_name($learner['full_name'], $learner['class_name'])) ?> - <?= h($learner['class_name']) ?> - <?= h($learner['reg_number']) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
            </div>
            <div class="marks-actions" style="margin-top:10px;">
              <button type="button" class="btn gold small" id="generateStudentReportCardBtn">Generate Printable Report Card</button>
            </div>
          </div>

          <div class="table-wrap">
            <table id="majorExamReportCardsTable">
              <thead>
                <tr>
                  <th>Photo</th>
                  <th>Reg #</th>
                  <th>Learner</th>
                  <th>Class</th>
                  <th>End of Term 1 (%)</th>
                  <th>Midyear (%)</th>
                  <th>End of Year (%)</th>
                  <th>Overall Major Exams (%)</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($majorExamReportCards)): ?>
                  <tr><td colspan="8">No learner report card data available yet.</td></tr>
                <?php else: ?>
                  <?php foreach ($majorExamReportCards as $reportRow): ?>
                    <?php
                      $term1Percent = $reportRow['term1_percent'] !== null ? round((float)$reportRow['term1_percent'], 1) : null;
                      $midyearPercent = $reportRow['midyear_percent'] !== null ? round((float)$reportRow['midyear_percent'], 1) : null;
                      $endyearPercent = $reportRow['endyear_percent'] !== null ? round((float)$reportRow['endyear_percent'], 1) : null;
                      $majorExamScores = array_values(array_filter([$term1Percent, $midyearPercent, $endyearPercent], static fn($v) => $v !== null));
                      $overallMajorExamPercent = !empty($majorExamScores)
                        ? round(array_sum($majorExamScores) / count($majorExamScores), 1)
                        : null;
                    ?>
                    <tr>
                      <td>
                        <?php if (!empty($reportRow['student_photo_path'])): ?>
                          <a href="<?= h($reportRow['student_photo_path']) ?>" target="_blank" rel="noopener">
                            <img src="<?= h($reportRow['student_photo_path']) ?>" alt="Learner photo" style="width:40px;height:40px;object-fit:cover;border-radius:8px;border:1px solid #d8def0;">
                          </a>
                        <?php else: ?>
                          <span class="tiny">No Photo</span>
                        <?php endif; ?>
                      </td>
                      <td><?= h($reportRow['reg_number']) ?></td>
                      <td><?= h(learner_display_name($reportRow['learner_name'], $reportRow['class_name'])) ?></td>
                      <td><?= h($reportRow['class_name']) ?></td>
                      <td><?= h($term1Percent !== null ? number_format($term1Percent, 1) . '%' : '-') ?></td>
                      <td><?= h($midyearPercent !== null ? number_format($midyearPercent, 1) . '%' : '-') ?></td>
                      <td><?= h($endyearPercent !== null ? number_format($endyearPercent, 1) . '%' : '-') ?></td>
                      <td><strong><?= h($overallMajorExamPercent !== null ? number_format($overallMajorExamPercent, 1) . '%' : '-') ?></strong></td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </div>
      </section>

      <section id="teacherRecentNotesView" class="panel desk-view">
        <h2>Recent Notes by This Teacher</h2>
        <p class="sub">Only notes written by the active teacher account are shown here.</p>
        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleNotesBtn">Show Notes</button>
          <button type="button" class="btn outline small" id="printNotesBtn" disabled>Print</button>
          <button type="button" class="btn outline small" id="downloadNotesPdfBtn" disabled>Download PDF</button>
          <button type="button" class="btn outline small" id="downloadNotesCsvBtn" disabled>Download CSV</button>
        </div>
        <div id="notesView" class="marks-view">
          <div class="table-wrap">
            <table id="notesTable">
              <thead>
                <tr>
                  <th>Date</th>
                  <th>Photo</th>
                  <th>Learner</th>
                  <th>Class</th>
                  <th>Note</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($recentNotes)): ?>
                  <tr><td colspan="5">No notes yet.</td></tr>
                <?php else: ?>
                  <?php foreach ($recentNotes as $note): ?>
                    <tr>
                      <td><?= h($note['created_at']) ?></td>
                      <td>
                        <?php if (!empty($note['student_photo_path'])): ?>
                          <a href="<?= h($note['student_photo_path']) ?>" target="_blank" rel="noopener">
                            <img src="<?= h($note['student_photo_path']) ?>" alt="Learner photo" style="width:40px;height:40px;object-fit:cover;border-radius:8px;border:1px solid #d8def0;">
                          </a>
                        <?php else: ?>
                          <span class="tiny">No Photo</span>
                        <?php endif; ?>
                      </td>
                      <td><?= h(learner_display_name($note['full_name'], $note['class_name'])) ?></td>
                      <td><?= h($note['class_name']) ?></td>
                      <td><?= h($note['note_text']) ?></td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </div>
      </section>

      <section id="teacherIndividualView" class="panel desk-view">
        <h2>Individual Learner Reports</h2>
        <p class="sub">Choose one learner and export only that learner's marks report.</p>
        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleIndividualReportBtn">Show Individual Learner Report</button>
          <button type="button" class="btn outline small" id="printIndividualReportBtn" disabled>Print</button>
          <button type="button" class="btn outline small" id="downloadIndividualPdfBtn" disabled>Download PDF</button>
          <button type="button" class="btn outline small" id="downloadIndividualCsvBtn" disabled>Download CSV</button>
        </div>
        <div id="individualReportView" class="marks-view">
          <div class="field">
            <label for="individualLearnerId">Learner</label>
            <div class="search" style="margin-bottom:8px;">
              <input type="search" id="individualLearnerSearch" placeholder="Search learner name...">
            </div>
            <select id="individualLearnerId">
              <option value="">Choose learner</option>
              <?php foreach ($learners as $learner): ?>
                <option value="<?= h($learner['id']) ?>"><?= h(learner_display_name($learner['full_name'], $learner['class_name'])) ?> - <?= h($learner['class_name']) ?> - <?= h($learner['reg_number']) ?></option>
              <?php endforeach; ?>
            </select>
          </div>
          <div class="table-wrap">
            <table id="individualReportTable">
              <thead>
                <tr>
                  <th>Date</th>
                  <th>Photo</th>
                  <th>Reg #</th>
                  <th>Learner</th>
                  <th>Class</th>
                  <th>Subject</th>
                  <th>Assessment</th>
                  <th>Term</th>
                  <th>Score</th>
                </tr>
              </thead>
              <tbody>
                <tr id="individualReportEmptyRow"><td colspan="9">Choose a learner to view an individual report.</td></tr>
                <?php foreach ($recentMarks as $mark): ?>
                  <?php $percent = $mark['max_score'] > 0 ? round(((float)$mark['score'] / (float)$mark['max_score']) * 100, 1) : 0; ?>
                  <tr data-learner-id="<?= h($mark['learner_id']) ?>" style="display:none;">
                    <td><?= h($mark['assessment_date']) ?></td>
                    <td>
                      <?php if (!empty($mark['student_photo_path'])): ?>
                        <a href="<?= h($mark['student_photo_path']) ?>" target="_blank" rel="noopener">
                          <img src="<?= h($mark['student_photo_path']) ?>" alt="Learner photo" style="width:40px;height:40px;object-fit:cover;border-radius:8px;border:1px solid #d8def0;">
                        </a>
                      <?php else: ?>
                        <span class="tiny">No Photo</span>
                      <?php endif; ?>
                    </td>
                    <td><?= h($mark['reg_number']) ?></td>
                    <td><?= h(learner_display_name($mark['learner_name'], $mark['class_name'])) ?></td>
                    <td><?= h($mark['class_name']) ?></td>
                    <td><?= h($mark['subject_name']) ?></td>
                    <td><?= h($assessmentTypes[$mark['assessment_type']] ?? $mark['assessment_type']) ?></td>
                    <td><?= h($mark['term_name']) ?></td>
                    <td><?= h($mark['score']) ?>/<?= h($mark['max_score']) ?> (<?= h($percent) ?>%)</td>
                  </tr>
                <?php endforeach; ?>
              </tbody>
            </table>
          </div>
        </div>
      </section>

      <section id="teacherElearningView" class="panel desk-view">
        <h2>E-learning Hub</h2>
        <p class="sub">Post assignments, exercises, notes and teaching videos to learners. Learners submit from their desk, then mark and return feedback here.</p>

        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleTeacherElearningContentBtn">Show E-learning Hub</button>
        </div>

        <div id="teacherElearningContentView" class="marks-view">

        <section class="panel-grid">
          <article class="panel">
            <h2>Post Learning Content</h2>
            <form method="POST">
              <div class="field">
                <label for="hub_class_id">Class</label>
                <select id="hub_class_id" name="hub_class_id" required>
                  <option value="">Choose class</option>
                  <?php foreach ($allowedClasses as $classRow): ?>
                    <option value="<?= h($classRow['id']) ?>"><?= h($classRow['name']) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="hub_subject_id">Subject</label>
                <select id="hub_subject_id" name="hub_subject_id">
                  <option value="0">General / not subject specific</option>
                  <?php foreach ($assignedSubjects as $subject): ?>
                    <option value="<?= h($subject['subject_id']) ?>"><?= h($subject['subject_name']) ?> (<?= h($subject['class_name']) ?>)</option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="hub_content_type">Type</label>
                <select id="hub_content_type" name="hub_content_type" required>
                  <option value="assignment">Assignment</option>
                  <option value="exercise">Exercise</option>
                  <option value="note">Note</option>
                  <option value="video">Teaching Video</option>
                </select>
              </div>
              <div class="field">
                <label for="hub_title">Title</label>
                <input id="hub_title" name="hub_title" required>
              </div>
              <div class="field">
                <label for="hub_instructions">Instructions</label>
                <textarea id="hub_instructions" name="hub_instructions" placeholder="Give learner instructions..."></textarea>
              </div>
              <div class="field">
                <label for="hub_resource_url">Resource URL (video/file/link)</label>
                <input id="hub_resource_url" name="hub_resource_url" placeholder="https://...">
              </div>
              <div class="field">
                <label for="hub_due_date">Due Date</label>
                <input type="date" id="hub_due_date" name="hub_due_date">
              </div>
              <button class="btn primary" type="submit" name="create_hub_post">Publish to Learners</button>
            </form>
          </article>

          <article class="panel">
            <h2>My Published Content</h2>
            <div class="table-wrap">
              <table>
                <thead>
                  <tr>
                    <th>Type</th>
                    <th>Title</th>
                    <th>Class</th>
                    <th>Due</th>
                    <th>Submitted</th>
                    <th>Marked</th>
                  </tr>
                </thead>
                <tbody>
                  <?php if (empty($hubPosts)): ?>
                    <tr><td colspan="6">No e-learning content posted yet.</td></tr>
                  <?php else: ?>
                    <?php foreach ($hubPosts as $post): ?>
                      <tr>
                        <td><?= h(ucfirst($post['content_type'])) ?></td>
                        <td><?= h($post['title']) ?></td>
                        <td><?= h($post['class_name']) ?></td>
                        <td><?= h($post['due_date'] ?: '-') ?></td>
                        <td><?= h($post['submission_count']) ?></td>
                        <td><?= h($post['graded_count']) ?></td>
                      </tr>
                    <?php endforeach; ?>
                  <?php endif; ?>
                </tbody>
              </table>
            </div>
          </article>
        </section>

        <article class="panel" style="margin-top:12px;">
          <h2>Learner Submissions for Marking</h2>
          <div class="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>Learner</th>
                  <th>Post</th>
                  <th>Class</th>
                  <th>Submitted</th>
                  <th>Status</th>
                  <th>Mark and Comment</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($hubSubmissions)): ?>
                  <tr><td colspan="6">No learner submissions yet.</td></tr>
                <?php else: ?>
                  <?php foreach ($hubSubmissions as $submission): ?>
                    <tr>
                      <td>
                        <strong><?= h(learner_display_name($submission['learner_name'], $submission['class_name'])) ?></strong><br>
                        <small><?= h($submission['reg_number']) ?></small>
                      </td>
                      <td>
                        <strong><?= h($submission['post_title']) ?></strong><br>
                        <small><?= h(ucfirst($submission['content_type'])) ?></small>
                      </td>
                      <td><?= h($submission['class_name']) ?></td>
                      <td><?= h($submission['submitted_at']) ?></td>
                      <td><span class="badge"><?= h(ucfirst($submission['status'])) ?></span></td>
                      <td>
                        <div style="margin-bottom:6px;"><small><?= h($submission['response_text']) ?></small></div>
                        <?php if (!empty($submission['response_link'])): ?>
                          <div style="margin-bottom:6px;"><a href="<?= h($submission['response_link']) ?>" target="_blank" rel="noopener">Open submission link</a></div>
                        <?php endif; ?>
                        <?php if (!empty($submission['attachment_path'])): ?>
                          <div style="margin-bottom:6px;">
                            <a href="<?= h($submission['attachment_path']) ?>" target="_blank" rel="noopener">
                              Open uploaded file<?= !empty($submission['attachment_name']) ? ': ' . h($submission['attachment_name']) : '' ?>
                            </a>
                          </div>
                        <?php endif; ?>
                        <form method="POST" style="display:grid; gap:6px;">
                          <input type="hidden" name="submission_id" value="<?= h($submission['id']) ?>">
                          <input name="submission_score" placeholder="Score" value="<?= h($submission['score']) ?>">
                          <textarea name="submission_comment" placeholder="Comment to learner"><?= h($submission['teacher_comment']) ?></textarea>
                          <select name="submission_status">
                            <option value="graded" <?= $submission['status'] === 'graded' ? 'selected' : '' ?>>Graded</option>
                            <option value="returned" <?= $submission['status'] === 'returned' ? 'selected' : '' ?>>Returned</option>
                          </select>
                          <button class="btn gold" type="submit" name="grade_hub_submission">Save Feedback</button>
                        </form>
                      </td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </article>
        </div>
      </section>

      <section id="teacherELibraryView" class="panel desk-view">
        <h2>Teacher E-Library</h2>
        <p class="sub">Upload learning resources for learners. Administrative teaching files are managed separately in the Teacher Uploads tab.</p>

        <div class="marks-actions">
          <button type="button" class="btn primary small" id="toggleTeacherELibraryContentBtn">Show E-Library</button>
        </div>

        <div id="teacherELibraryContentView" class="marks-view">

        <section class="panel-grid">
          <article class="panel">
            <h2>Upload Library Resource</h2>
            <form method="POST" enctype="multipart/form-data">
              <div class="field">
                <label for="library_class_id">Class</label>
                <select id="library_class_id" name="library_class_id" required>
                  <option value="">Choose class</option>
                  <?php foreach ($allowedClasses as $classRow): ?>
                    <option value="<?= h($classRow['id']) ?>"><?= h($classRow['name']) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="library_subject_id">Subject (Optional)</label>
                <select id="library_subject_id" name="library_subject_id">
                  <option value="0">General / not subject specific</option>
                  <?php foreach ($assignedSubjects as $subject): ?>
                    <option value="<?= h($subject['subject_id']) ?>" data-class="<?= h($subject['class_id']) ?>" style="display:none;">
                      <?= h($subject['subject_name']) ?> (<?= h($subject['class_name']) ?>)
                    </option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="library_title">Title</label>
                <input id="library_title" name="library_title" required placeholder="e.g. Grade 6 Science Revision Book">
              </div>
              <div class="field">
                <label for="library_description">Description (Optional)</label>
                <textarea id="library_description" name="library_description" placeholder="Short note for learners..."></textarea>
              </div>
              <div class="field">
                <label for="library_file">Upload File</label>
                <input type="file" id="library_file" name="library_file" required accept=".pdf,.epub,.mobi,.txt,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.csv,.jpg,.jpeg,.png,.gif,.webp,.bmp,.mp4,.mov,.avi,.mkv,.webm,.mp3,.wav,.zip,.rar,.7z,.rtf">
                <small class="tiny">Max 200MB. Supports books, documents, pictures, videos, and common archive formats.</small>
              </div>
              <button class="btn primary" type="submit" name="upload_library_resource">Upload to E-Library</button>
            </form>

            <h2 style="margin-top:14px;">My Uploaded Library Files</h2>
            <div class="table-wrap">
              <table id="teacherLibraryTable">
                <thead>
                  <tr>
                    <th>Title</th>
                    <th>Class</th>
                    <th>Subject</th>
                    <th>File</th>
                    <th>Size</th>
                    <th>Access Count</th>
                  </tr>
                </thead>
                <tbody>
                  <?php if (empty($libraryResources)): ?>
                    <tr><td colspan="6">No e-library files uploaded yet.</td></tr>
                  <?php else: ?>
                    <?php foreach ($libraryResources as $resource): ?>
                      <tr>
                        <td>
                          <strong><?= h($resource['title']) ?></strong>
                          <?php if (!empty($resource['description'])): ?><br><small><?= h($resource['description']) ?></small><?php endif; ?>
                        </td>
                        <td><?= h($resource['class_name']) ?></td>
                        <td><?= h($resource['subject_name'] ?: 'General') ?></td>
                        <td>
                          <a href="<?= h($resource['file_path']) ?>" target="_blank" rel="noopener"><?= h($resource['original_name']) ?></a><br>
                          <span class="mono"><?= h($resource['mime_type'] ?: 'unknown') ?></span>
                        </td>
                        <td><?= h(format_file_size($resource['file_size'])) ?></td>
                        <td><?= h((int)$resource['access_count']) ?></td>
                      </tr>
                    <?php endforeach; ?>
                  <?php endif; ?>
                </tbody>
              </table>
            </div>
          </article>

          <article class="panel">
            <h2>Subject Resource Shelf</h2>
            <?php if (empty($teacherLibraryBySubject)): ?>
              <p class="sub">No subjects assigned yet. Ask admin to assign subjects so this library can auto-populate.</p>
            <?php else: ?>
              <div class="library-grid">
                <?php foreach ($teacherLibraryBySubject as $subjectName => $resources): ?>
                  <article class="resource-card">
                    <h4><?= h($subjectName) ?></h4>
                    <ul class="resource-list">
                      <?php foreach ($resources as $resource): ?>
                        <li>
                          <a href="<?= h($resource['url']) ?>" target="_blank" rel="noopener"><?= h($resource['title']) ?></a>
                          <span class="muted">(<?= h($resource['type']) ?>)</span>
                        </li>
                      <?php endforeach; ?>
                    </ul>
                  </article>
                <?php endforeach; ?>
              </div>
            <?php endif; ?>
          </article>

          <article class="panel">
            <h2>Meta AI Lesson Assistant</h2>
            <div class="meta-ai-box">
              <div class="field">
                <label for="teacherMetaSubject">Subject for Prompt</label>
                <select id="teacherMetaSubject">
                  <?php if (empty($teacherLibraryBySubject)): ?>
                    <option value="General">General</option>
                  <?php else: ?>
                    <?php foreach (array_keys($teacherLibraryBySubject) as $subjectName): ?>
                      <option value="<?= h($subjectName) ?>"><?= h($subjectName) ?></option>
                    <?php endforeach; ?>
                  <?php endif; ?>
                </select>
              </div>
              <div class="field">
                <label for="teacherMetaPrompt">Ready Prompt</label>
                <textarea id="teacherMetaPrompt">Create a 40-minute lesson plan for General for Zimbabwe primary learners. Include lesson objectives, starter activity, main activity, assessment, homework, and one low-bandwidth digital resource.</textarea>
              </div>
              <div class="marks-actions" style="margin-bottom:0;">
                <a class="btn gold small" href="https://www.meta.ai/" target="_blank" rel="noopener">Open Meta AI</a>
                <button type="button" class="btn outline small" id="copyTeacherMetaPromptBtn">Copy Prompt</button>
              </div>
            </div>

            <h2>Zimbabwe and Global Learning Platforms</h2>
            <ul class="platform-links">
              <?php foreach ($coreLearningPlatforms as $platform): ?>
                <li>
                  <a href="<?= h($platform['url']) ?>" target="_blank" rel="noopener"><?= h($platform['name']) ?></a>
                  <span class="muted"> - <?= h($platform['description']) ?></span>
                </li>
              <?php endforeach; ?>
            </ul>
          </article>
        </section>

        <article class="panel" style="margin-top:12px;">
          <h2>E-Library Access Log</h2>
          <p class="sub">Track learner frequency of library access. Total accesses recorded: <strong><?= h($libraryTotalAccesses) ?></strong>.</p>
          <div class="marks-actions">
            <button type="button" class="btn primary small" id="toggleLibraryLogBtn">Show Access Log</button>
            <button type="button" class="btn outline small" id="printLibraryLogBtn" disabled>Print</button>
            <button type="button" class="btn outline small" id="downloadLibraryLogPdfBtn" disabled>Download PDF</button>
            <button type="button" class="btn outline small" id="downloadLibraryLogCsvBtn" disabled>Download CSV</button>
          </div>

          <div id="libraryLogView" class="marks-view">
            <div class="table-wrap">
              <table id="libraryLogTable">
                <thead>
                  <tr>
                    <th>Date</th>
                    <th>Learner</th>
                    <th>Class</th>
                    <th>Action</th>
                    <th>Resource</th>
                    <th>File</th>
                  </tr>
                </thead>
                <tbody>
                  <?php if (empty($libraryAccessLogs)): ?>
                    <tr><td colspan="6">No learner e-library access has been recorded yet.</td></tr>
                  <?php else: ?>
                    <?php foreach ($libraryAccessLogs as $log): ?>
                      <tr>
                        <td><?= h($log['accessed_at']) ?></td>
                        <td><?= h(learner_display_name($log['learner_name'], $log['class_name'])) ?> (<?= h($log['reg_number']) ?>)</td>
                        <td><?= h($log['class_name']) ?></td>
                        <td><span class="badge"><?= h(ucfirst($log['action'])) ?></span></td>
                        <td><?= h($log['resource_title']) ?></td>
                        <td><?= h($log['original_name']) ?></td>
                      </tr>
                    <?php endforeach; ?>
                  <?php endif; ?>
                </tbody>
              </table>
            </div>
          </div>
        </article>
      </section>

      <section id="teacherUploadsView" class="panel desk-view">
        <h2>Teacher Uploads</h2>
        <p class="sub">Submit professional documents for Admin and HOP review. Both desks can return corrections, and those items are highlighted below.</p>

        <div class="full-width-stack">
          <article class="panel">
            <h2>Upload Document to Admin and HOP Desks</h2>
            <div class="marks-actions">
              <button type="button" class="btn primary small" id="toggleTeacherDocumentUploadFormBtn">Show Upload Form</button>
            </div>

            <div id="teacherDocumentUploadFormView" class="marks-view">
            <form method="POST" enctype="multipart/form-data">
              <div class="field">
                <label for="teacher_document_class_id">Class</label>
                <select id="teacher_document_class_id" name="teacher_document_class_id" required>
                  <option value="">Choose class</option>
                  <?php foreach ($allowedClasses as $classRow): ?>
                    <option value="<?= h($classRow['id']) ?>"><?= h($classRow['name']) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="teacher_document_subject_id">Subject (Optional)</label>
                <select id="teacher_document_subject_id" name="teacher_document_subject_id">
                  <option value="0">General / not subject specific</option>
                  <?php foreach ($assignedSubjects as $subject): ?>
                    <option value="<?= h($subject['subject_id']) ?>" data-class="<?= h($subject['class_id']) ?>" style="display:none;">
                      <?= h($subject['subject_name']) ?> (<?= h($subject['class_name']) ?>)
                    </option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="teacher_document_type">Document Type</label>
                <select id="teacher_document_type" name="teacher_document_type" required>
                  <option value="">Choose document type</option>
                  <?php foreach ($teacherDocumentTypes as $docKey => $docLabel): ?>
                    <option value="<?= h($docKey) ?>"><?= h($docLabel) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="teacher_document_title">Title</label>
                <input id="teacher_document_title" name="teacher_document_title" placeholder="e.g. Term 2 Grade 5 Schemebook" required>
              </div>
              <div class="field">
                <label for="teacher_document_description">Description (Optional)</label>
                <textarea id="teacher_document_description" name="teacher_document_description" placeholder="Extra context for admin review..."></textarea>
              </div>
              <div class="field">
                <label for="teacher_document_file">Upload Document</label>
                <input type="file" id="teacher_document_file" name="teacher_document_file" required accept=".pdf,.doc,.docx,.xls,.xlsx,.csv,.rtf,.txt,.jpg,.jpeg,.png,.webp">
                <small class="tiny">Allowed types: PDF, Word, Excel, CSV, RTF, TXT, and images. Max 100MB.</small>
              </div>
              <button class="btn primary" type="submit" name="upload_teacher_document">Send to Admin and HOP</button>
            </form>
            </div>
          </article>

          <article class="panel">
            <h2>My Submitted Documents</h2>
            <div class="marks-actions">
              <button type="button" class="btn primary small" id="toggleTeacherSubmittedDocumentsBtn">Show Submitted Documents</button>
            </div>

            <div id="teacherSubmittedDocumentsView" class="marks-view">
            <div class="table-wrap">
              <table class="teacher-docs-table">
                <thead>
                  <tr>
                    <th>Submitted</th>
                    <th>Type</th>
                    <th>Title</th>
                    <th>Class</th>
                    <th>Admin Status</th>
                    <th>HOP Status</th>
                    <th>Admin Feedback</th>
                    <th>HOP Feedback</th>
                    <th>File</th>
                  </tr>
                </thead>
                <tbody>
                  <?php if (empty($teacherDocuments)): ?>
                    <tr><td colspan="9">No teacher documents submitted yet.</td></tr>
                  <?php else: ?>
                    <?php foreach ($teacherDocuments as $doc): ?>
                      <tr class="<?= ($doc['status'] === 'needs_correction' || $doc['hop_status'] === 'needs_correction') ? 'doc-correction' : '' ?>">
                        <td><?= h($doc['created_at']) ?></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><?= h($doc['class_name']) ?><?= !empty($doc['subject_name']) ? ' / ' . h($doc['subject_name']) : '' ?></td>
                        <td><span class="badge"><?= h(str_replace('_', ' ', ucfirst($doc['status']))) ?></span></td>
                        <td><span class="badge"><?= h(str_replace('_', ' ', ucfirst($doc['hop_status'] ?? 'submitted'))) ?></span></td>
                        <td>
                          <?php if (!empty($doc['admin_comment'])): ?>
                            <strong><?= h($doc['status'] === 'needs_correction' ? 'Correction Required:' : 'Admin Note:') ?></strong>
                            <div><?= nl2br(h($doc['admin_comment'])) ?></div>
                            <?php if (!empty($doc['reviewed_at'])): ?><small class="tiny">Reviewed: <?= h($doc['reviewed_at']) ?></small><?php endif; ?>
                          <?php else: ?>
                            <span class="tiny">No feedback yet.</span>
                          <?php endif; ?>
                        </td>
                        <td>
                          <?php if (!empty($doc['hop_comment'])): ?>
                            <strong><?= h(($doc['hop_status'] ?? '') === 'needs_correction' ? 'Correction Required:' : 'HOP Note:') ?></strong>
                            <div><?= nl2br(h($doc['hop_comment'])) ?></div>
                            <?php if (!empty($doc['hop_reviewed_at'])): ?><small class="tiny">Reviewed: <?= h($doc['hop_reviewed_at']) ?></small><?php endif; ?>
                          <?php else: ?>
                            <span class="tiny">No HOP feedback yet.</span>
                          <?php endif; ?>
                        </td>
                        <td>
                          <a href="<?= h($doc['file_path']) ?>" target="_blank" rel="noopener"><?= h($doc['original_name']) ?></a><br>
                          <span class="mono"><?= h(format_file_size($doc['file_size'])) ?></span>
                        </td>
                      </tr>
                    <?php endforeach; ?>
                  <?php endif; ?>
                </tbody>
              </table>
            </div>
            </div>
          </article>
        </div>
      </section>

      <section id="teacherInventoryView" class="panel-grid desk-view">
        <article class="panel">
          <h2>Teacher Inventory Register</h2>
          <p class="sub">Record textbooks, furniture, and all teaching materials used in class. Entries are sent directly to the accountant for physical stock-take.</p>

          <div class="marks-actions">
            <button type="button" class="btn primary small" id="toggleTeacherInventoryFormBtn">Show Inventory Form</button>
          </div>

          <div id="teacherInventoryFormView" class="marks-view">
            <form method="POST" autocomplete="off">
              <div class="field">
                <label for="inventory_class_id">Class</label>
                <select id="inventory_class_id" name="inventory_class_id" required>
                  <option value="">Choose class</option>
                  <?php foreach ($allowedClasses as $classRow): ?>
                    <option value="<?= h($classRow['id']) ?>"><?= h($classRow['name']) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="inventory_category">Category</label>
                <select id="inventory_category" name="inventory_category" required>
                  <?php foreach ($inventoryCategories as $categoryKey => $categoryLabel): ?>
                    <option value="<?= h($categoryKey) ?>"><?= h($categoryLabel) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="field">
                <label for="inventory_item_name">Item Name</label>
                <input id="inventory_item_name" name="inventory_item_name" placeholder="e.g. Grade 6 Mathematics Textbook" required>
              </div>
              <div class="field">
                <label for="inventory_quantity">Quantity Recorded</label>
                <input id="inventory_quantity" name="inventory_quantity" type="number" min="0" step="1" required>
              </div>
              <div class="field">
                <label for="inventory_condition">Condition (Optional)</label>
                <input id="inventory_condition" name="inventory_condition" placeholder="e.g. Good, Fair, Needs repair">
              </div>
              <div class="field">
                <label for="inventory_note">Notes (Optional)</label>
                <textarea id="inventory_note" name="inventory_note" placeholder="Any extra details for accountant stock take"></textarea>
              </div>
              <button class="btn primary" type="submit" name="add_inventory_record">Submit Inventory Record</button>
            </form>
          </div>
        </article>

        <article class="panel">
          <h2>Accountant Inventory Reviews</h2>
          <p class="sub">Track stock-take verification and read review feedback returned from accountant desk.</p>

          <div class="marks-actions">
            <button type="button" class="btn primary small" id="toggleTeacherInventoryTableBtn">Show Inventory Reviews</button>
            <button type="button" class="btn outline small" id="printTeacherInventoryBtn" disabled>Print</button>
            <button type="button" class="btn outline small" id="downloadTeacherInventoryPdfBtn" disabled>Download PDF</button>
            <button type="button" class="btn outline small" id="downloadTeacherInventoryCsvBtn" disabled>Download CSV</button>
          </div>

          <div id="teacherInventoryTableView" class="marks-view">
            <div class="table-wrap">
              <table id="teacherInventoryTable">
                <thead>
                  <tr>
                    <th>Submitted</th>
                    <th>Class</th>
                    <th>Category</th>
                    <th>Item</th>
                    <th>Recorded Qty</th>
                    <th>Stock-Take Qty</th>
                    <th>Status</th>
                    <th>Accountant Review</th>
                    <th>Update</th>
                  </tr>
                </thead>
                <tbody>
                  <?php if (empty($teacherInventoryRecords)): ?>
                    <tr><td colspan="9">No inventory records submitted yet.</td></tr>
                  <?php else: ?>
                    <?php foreach ($teacherInventoryRecords as $inventoryRow): ?>
                      <tr>
                        <td><?= h($inventoryRow['created_at']) ?></td>
                        <td><?= h($inventoryRow['class_name']) ?></td>
                        <td><?= h($inventoryCategories[$inventoryRow['category']] ?? $inventoryRow['category']) ?></td>
                        <td>
                          <strong><?= h($inventoryRow['item_name']) ?></strong>
                          <?php if (!empty($inventoryRow['item_condition'])): ?><br><small>Condition: <?= h($inventoryRow['item_condition']) ?></small><?php endif; ?>
                          <?php if (!empty($inventoryRow['inventory_note'])): ?><br><small><?= h($inventoryRow['inventory_note']) ?></small><?php endif; ?>
                        </td>
                        <td><?= h((int)$inventoryRow['quantity_recorded']) ?></td>
                        <td><?= h($inventoryRow['stock_take_quantity'] !== null ? (int)$inventoryRow['stock_take_quantity'] : '-') ?></td>
                        <td><span class="badge"><?= h(str_replace('_', ' ', ucfirst((string)$inventoryRow['status']))) ?></span></td>
                        <td>
                          <?php if (!empty($inventoryRow['accountant_review'])): ?>
                            <?= nl2br(h($inventoryRow['accountant_review'])) ?>
                            <?php if (!empty($inventoryRow['reviewed_at'])): ?><br><small>Reviewed: <?= h($inventoryRow['reviewed_at']) ?></small><?php endif; ?>
                            <?php if (!empty($inventoryRow['reviewer_name'])): ?><br><small>By: <?= h($inventoryRow['reviewer_name']) ?></small><?php endif; ?>
                          <?php else: ?>
                            <span class="tiny">Awaiting accountant review.</span>
                          <?php endif; ?>
                        </td>
                        <td>
                          <form method="POST" style="display:grid; gap:6px; min-width:220px;">
                            <input type="hidden" name="inventory_record_id" value="<?= h($inventoryRow['id']) ?>">
                            <select name="inventory_class_id" required>
                              <?php foreach ($allowedClasses as $classRow): ?>
                                <option value="<?= h($classRow['id']) ?>" <?= $inventoryRow['class_name'] === $classRow['name'] ? 'selected' : '' ?>><?= h($classRow['name']) ?></option>
                              <?php endforeach; ?>
                            </select>
                            <select name="inventory_category" required>
                              <?php foreach ($inventoryCategories as $categoryKey => $categoryLabel): ?>
                                <option value="<?= h($categoryKey) ?>" <?= (string)$inventoryRow['category'] === $categoryKey ? 'selected' : '' ?>><?= h($categoryLabel) ?></option>
                              <?php endforeach; ?>
                            </select>
                            <input name="inventory_item_name" value="<?= h($inventoryRow['item_name']) ?>" required>
                            <input name="inventory_quantity" type="number" min="0" step="1" value="<?= h((int)$inventoryRow['quantity_recorded']) ?>" required>
                            <input name="inventory_condition" value="<?= h((string)($inventoryRow['item_condition'] ?? '')) ?>" placeholder="Condition (optional)">
                            <textarea name="inventory_note" placeholder="Notes (optional)"><?= h((string)($inventoryRow['inventory_note'] ?? '')) ?></textarea>
                            <button class="btn gold" type="submit" name="update_inventory_record">Update and Resubmit</button>
                          </form>
                        </td>
                      </tr>
                    <?php endforeach; ?>
                  <?php endif; ?>
                </tbody>
              </table>
            </div>
          </div>
        </article>
      </section>

      <section id="teacherAnnouncementsView" class="panel-grid desk-view">
        <article class="panel">
          <h2>Post Announcement</h2>
          <p class="sub">Send to learners directly, or send to parents through admin verification.</p>

          <form method="POST" autocomplete="off">
            <div class="field">
              <label for="teacher_announcement_audience">Audience</label>
              <select id="teacher_announcement_audience" name="teacher_announcement_audience" required>
                <option value="">Choose audience</option>
                <option value="learner">Learners (direct post)</option>
                <option value="parent">Parents (admin verification required)</option>
              </select>
            </div>
            <div class="field">
              <label for="teacher_announcement_target_type">Target Scope</label>
              <select id="teacher_announcement_target_type" name="teacher_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="teacherAnnouncementTargetClassWrap">
              <label for="teacher_announcement_target_class_id">Target Class</label>
              <select id="teacher_announcement_target_class_id" name="teacher_announcement_target_class_id">
                <option value="">Choose class</option>
                <?php foreach ($managedClasses as $classRow): ?>
                  <option value="<?= h($classRow['id']) ?>"><?= h($classRow['name']) ?></option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="field" id="teacherAnnouncementTargetLearnerWrap">
              <label for="teacher_announcement_target_learner_id">Target Learner</label>
              <select id="teacher_announcement_target_learner_id" name="teacher_announcement_target_learner_id">
                <option value="">Choose learner</option>
                <?php foreach ($activeLearners as $learner): ?>
                  <option value="<?= h($learner['id']) ?>" data-class-id="<?= h($learner['class_id']) ?>">
                    <?= h($learner['reg_number']) ?> - <?= h(learner_display_name($learner['full_name'], $learner['class_name'])) ?> (<?= h($learner['class_name']) ?>)
                  </option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="field">
              <label for="teacher_announcement_title">Title</label>
              <input id="teacher_announcement_title" name="teacher_announcement_title" placeholder="Announcement title" required>
            </div>
            <div class="field">
              <label for="teacher_announcement_body">Message</label>
              <textarea id="teacher_announcement_body" name="teacher_announcement_body" placeholder="Type your message" required></textarea>
            </div>
            <button class="btn primary" type="submit" name="post_teacher_announcement">Send Announcement</button>
          </form>
        </article>

        <article class="panel">
          <h2>My Announcement Status</h2>
          <p class="sub">Track whether each announcement is published, pending admin review, or rejected.</p>

          <div class="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>Created</th>
                  <th>Audience</th>
                  <th>Target</th>
                  <th>Title</th>
                  <th>Message</th>
                  <th>Status</th>
                  <th>Admin Review</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($teacherAnnouncementRows)): ?>
                  <tr><td colspan="7">No announcements sent yet.</td></tr>
                <?php else: ?>
                  <?php foreach ($teacherAnnouncementRows as $announcementRow): ?>
                    <tr>
                      <td><?= h($announcementRow['created_at']) ?></td>
                      <td><?= h(ucfirst((string)$announcementRow['audience'])) ?></td>
                      <td><?= h(announcement_target_label($announcementRow)) ?></td>
                      <td><?= h($announcementRow['title']) ?></td>
                      <td><?= nl2br(h($announcementRow['body'])) ?></td>
                      <td><span class="badge"><?= h(ucfirst(str_replace('_', ' ', (string)$announcementRow['status']))) ?></span></td>
                      <td>
                        <?php if (!empty($announcementRow['admin_review_comment'])): ?>
                          <?= nl2br(h($announcementRow['admin_review_comment'])) ?>
                          <?php if (!empty($announcementRow['reviewed_at'])): ?><br><small>Reviewed: <?= h($announcementRow['reviewed_at']) ?></small><?php endif; ?>
                          <?php if (!empty($announcementRow['reviewer_name'])): ?><br><small>By: <?= h($announcementRow['reviewer_name']) ?></small><?php endif; ?>
                        <?php else: ?>
                          <span class="tiny">No admin comment yet.</span>
                        <?php endif; ?>
                      </td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </article>
      </section>

      <section id="teacherTransferClearanceView" class="panel desk-view">
        <h2>Learner Transfer Clearance Requests</h2>
        <p class="sub">Review parent transfer requests for your classes and submit your clearance decision.</p>
        <div class="table-wrap">
          <table>
            <thead>
              <tr>
                <th>Requested</th>
                <th>Learner</th>
                <th>Parent</th>
                <th>Destination</th>
                <th>Status</th>
                <th>Your Clearance</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($teacherTransferRequests)): ?>
                <tr><td colspan="7">No transfer requests assigned to your classes.</td></tr>
              <?php else: ?>
                <?php foreach ($teacherTransferRequests as $transfer): ?>
                  <tr>
                    <td><?= h($transfer['requested_at']) ?></td>
                    <td><?= h($transfer['learner_name']) ?><br><small><?= h($transfer['reg_number']) ?> | <?= h($transfer['class_name']) ?></small></td>
                    <td><?= h($transfer['parent_name']) ?></td>
                    <td><?= h($transfer['destination_school']) ?><br><small><?= h($transfer['reason']) ?></small></td>
                    <td><span class="status-chip"><?= h(ucfirst(str_replace('_', ' ', (string)$transfer['status']))) ?></span></td>
                    <td>
                      <span class="status-chip <?= $transfer['teacher_status'] === 'approved' ? 'status-ok' : (($transfer['teacher_status'] === 'rejected') ? 'status-warn' : '') ?>"><?= h(ucfirst((string)$transfer['teacher_status'])) ?></span>
                      <?php if (!empty($transfer['teacher_comment'])): ?><br><small><?= h($transfer['teacher_comment']) ?></small><?php endif; ?>
                    </td>
                    <td>
                      <?php if ($transfer['status'] === 'clearance_requested' && $transfer['teacher_status'] === 'pending'): ?>
                        <form method="POST" style="display:grid;gap:6px;min-width:240px;">
                          <input type="hidden" name="transfer_request_id" value="<?= h($transfer['id']) ?>">
                          <input type="text" name="teacher_transfer_comment" placeholder="Comment (optional)">
                          <input type="hidden" name="teacher_transfer_decision" value="approve">
                          <div style="display:flex;gap:6px;">
                            <button class="button primary" type="submit" name="review_transfer_clearance_teacher" onclick="this.form.teacher_transfer_decision.value='approve'">Approve</button>
                            <button class="button accent" type="submit" name="review_transfer_clearance_teacher" onclick="this.form.teacher_transfer_decision.value='reject'">Reject</button>
                          </div>
                        </form>
                      <?php else: ?>
                        <small>No action required.</small>
                      <?php endif; ?>
                    </td>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </section>

      <section id="teacherLeaveRequestsView" class="panel-grid desk-view">
        <article class="panel">
          <h2>Submit Leave Request</h2>
          <p class="sub">Upload your leave form here and track head approval directly from your desk.</p>
          <form method="POST" enctype="multipart/form-data">
            <div class="field">
              <label for="leave_type">Leave Type</label>
              <select id="leave_type" name="leave_type" required>
                <option value="">Choose leave type</option>
                <option value="sick">Sick Leave</option>
                <option value="annual">Annual Leave</option>
                <option value="maternity">Maternity Leave</option>
                <option value="compassionate">Compassionate Leave</option>
                <option value="unpaid">Unpaid Leave</option>
                <option value="other">Other</option>
              </select>
            </div>
            <div class="field">
              <label for="leave_start_date">Start Date</label>
              <input type="date" id="leave_start_date" name="leave_start_date" required>
            </div>
            <div class="field">
              <label for="leave_end_date">End Date</label>
              <input type="date" id="leave_end_date" name="leave_end_date" required>
            </div>
            <div class="field">
              <label for="leave_reason">Reason</label>
              <textarea id="leave_reason" name="leave_reason" required placeholder="Provide details about this leave request"></textarea>
            </div>
            <div class="field">
              <label for="leave_document">Leave Form Document (PDF, JPG, PNG, WEBP)</label>
              <input id="leave_document" name="leave_document" type="file" accept="application/pdf,image/jpeg,image/png,image/webp" required>
            </div>
            <button type="submit" class="button primary" name="submit_teacher_leave_request">Submit Leave Request</button>
          </form>
        </article>

        <article class="panel">
          <h2>My Leave Requests</h2>
          <div class="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>Submitted</th>
                  <th>Leave Type</th>
                  <th>Period</th>
                  <th>Reason</th>
                  <th>Attachment</th>
                  <th>Status</th>
                  <th>Head Feedback</th>
                </tr>
              </thead>
              <tbody>
                <?php if (empty($teacherLeaveRequests)): ?>
                  <tr><td colspan="7">No leave requests submitted 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>
                      <td><?= h($leaveRequest['created_at']) ?></td>
                      <td><?= h(ucfirst(str_replace('_', ' ', (string)$leaveRequest['leave_type']))) ?></td>
                      <td><?= h($leaveRequest['start_date']) ?> to <?= h($leaveRequest['end_date']) ?></td>
                      <td><?= h($leaveRequest['reason']) ?></td>
                      <td>
                        <?php if ($hasLeaveDocument): ?>
                          <a class="button accent" style="width:auto;" href="<?= h($leaveDocumentPath) ?>" target="_blank" rel="noopener">Open</a>
                        <?php else: ?>
                          <span class="foot-note">No attachment</span>
                        <?php endif; ?>
                      </td>
                      <td><span class="status-chip <?= $leaveRequest['status'] === 'approved' ? 'status-ok' : (($leaveRequest['status'] === 'rejected') ? 'status-warn' : '') ?>"><?= h(ucfirst((string)$leaveRequest['status'])) ?></span></td>
                      <td>
                        <?= h($leaveRequest['admin_comment'] ?: '-') ?>
                        <?php if (!empty($leaveRequest['reviewed_at'])): ?><br><small><?= h($leaveRequest['reviewed_at']) ?></small><?php endif; ?>
                      </td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </article>
      </section>
      </div>
      </div>
    <?php endif; ?>
  </div>

  <script>
    const isAdminReadOnlyView = <?= $isAdminReadOnlyView ? 'true' : 'false' ?>;

    if (isAdminReadOnlyView) {
      Array.from(document.querySelectorAll('form[method="POST"], form[method="post"]')).forEach(form => {
        form.addEventListener('submit', function (event) {
          event.preventDefault();
          window.alert('Admin preview mode is read-only.');
        });

        Array.from(form.querySelectorAll('button[type="submit"], input[type="submit"]')).forEach(btn => {
          btn.disabled = true;
          btn.title = 'Disabled in admin read-only preview mode';
        });
      });
    }

    const existingMarksLookup = <?= json_encode($existingMarksLookup, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;
    const attendanceStatusLookup = <?= json_encode($attendanceStatusLookup, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;
    const learnerDirectory = <?= json_encode($learners, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;
    const majorExamMarkRows = <?= json_encode($majorExamMarkRows, 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) ?>,
        brandIce: <?= json_encode($paletteBrandIce, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>,
        line: <?= json_encode($palettePatchSky, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>
      },
      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) ?>,
      teacherName: <?= json_encode($activeTeacher['name'], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>
    };
    const schoolFilePrefix = String(reportMeta.schoolName || 'school')
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '_')
      .replace(/^_+|_+$/g, '') || 'school';

    const searchInput = document.getElementById('learnerSearch');
    if (searchInput) {
      const rows = Array.from(document.querySelectorAll('#learnerTable tbody tr'));
      searchInput.addEventListener('input', function () {
        const term = this.value.trim().toLowerCase();
        rows.forEach(row => {
          const text = row.textContent.toLowerCase();
          row.style.display = text.includes(term) ? '' : 'none';
        });
      });
    }

    const markClassSelect = document.getElementById('mark_class_id');
    const markClassSearch = document.getElementById('markClassSearch');
    const admissionClassSearch = document.getElementById('admissionClassSearch');
    const admissionClassSelect = document.getElementById('class_id');
    const markSubjectSelect = document.getElementById('mark_subject_id');
    const markSubjectSearch = document.getElementById('markSubjectSearch');
    const learnerPickerSearch = document.getElementById('learnerPickerSearch');
    const learnerPickerSelect = document.getElementById('learner_id');
    const markTypeSelect = document.getElementById('assessment_type');
    const markTermSelect = document.getElementById('term_name');
    const markDateInput = document.getElementById('assessment_date');
    const teacherAnnouncementAudience = document.getElementById('teacher_announcement_audience');
    const teacherAnnouncementTargetType = document.getElementById('teacher_announcement_target_type');
    const teacherAnnouncementTargetClassWrap = document.getElementById('teacherAnnouncementTargetClassWrap');
    const teacherAnnouncementTargetLearnerWrap = document.getElementById('teacherAnnouncementTargetLearnerWrap');
    const teacherAnnouncementTargetClassSelect = document.getElementById('teacher_announcement_target_class_id');
    const teacherAnnouncementTargetLearnerSelect = document.getElementById('teacher_announcement_target_learner_id');
    const attendanceClassSearch = document.getElementById('attendanceClassSearch');
    const attendanceClassSelect = document.getElementById('attendance_class_id');
    const attendanceDateInput = document.getElementById('attendance_date');
    const attendanceRows = Array.from(document.querySelectorAll('.attendance-row'));
    const attendanceEmptyHint = document.getElementById('attendanceEmptyHint');
    const marksForm = document.getElementById('marksForm');
    const saveBulkBtn = marksForm ? marksForm.querySelector('button[name="save_marks_bulk"]') : null;
    const markEntryStatus = document.getElementById('markEntryStatus');
    const bulkLearnerRows = Array.from(document.querySelectorAll('.bulk-learner-row'));

    function buildMarkKey(classId, subjectId, assessmentType, termName, assessmentDate, learnerId) {
      return `${classId}|${subjectId}|${assessmentType}|${termName}|${assessmentDate}|${learnerId}`;
    }

    function buildAttendanceKey(classId, attendanceDate, learnerId) {
      return `${classId}|${attendanceDate}|${learnerId}`;
    }

    function applyExistingMarksToVisibleRows() {
      const classId = Number(markClassSelect?.value || 0);
      const subjectId = Number(markSubjectSelect?.value || 0);
      const assessmentType = String(markTypeSelect?.value || '');
      const termName = String(markTermSelect?.value || '');
      const assessmentDate = String(markDateInput?.value || '');
      const ready = classId > 0 && subjectId > 0 && assessmentType !== '' && termName !== '' && assessmentDate !== '';

      bulkLearnerRows.forEach(row => {
        const input = row.querySelector('input[data-learner-id]');
        if (!input || row.style.display === 'none') {
          return;
        }

        if (!ready) {
          input.value = '';
          return;
        }

        const learnerId = Number(input.dataset.learnerId || 0);
        const key = buildMarkKey(classId, subjectId, assessmentType, termName, assessmentDate, learnerId);
        input.value = Object.prototype.hasOwnProperty.call(existingMarksLookup, key) ? existingMarksLookup[key] : '';
      });

      updateMarkEntryState();
    }

    function filterAttendanceRowsByClass(classId) {
      let visibleCount = 0;

      attendanceRows.forEach(row => {
        const rowClass = Number(row.dataset.class || 0);
        const show = classId > 0 && rowClass === classId;
        row.style.display = show ? '' : 'none';
        if (show) {
          visibleCount++;
        }
      });

      if (attendanceEmptyHint) {
        attendanceEmptyHint.style.display = visibleCount === 0 ? '' : 'none';
        if (visibleCount === 0) {
          attendanceEmptyHint.cells[0].textContent = classId > 0
            ? 'No learners found in the selected class.'
            : 'Choose class to mark daily attendance.';
        }
      }
    }

    function applyExistingAttendanceToVisibleRows() {
      const classId = Number(attendanceClassSelect?.value || 0);
      const attendanceDate = String(attendanceDateInput?.value || '');
      const ready = classId > 0 && attendanceDate !== '';

      attendanceRows.forEach(row => {
        if (row.style.display === 'none') {
          return;
        }
        const selectEl = row.querySelector('select[data-learner-id]');
        if (!selectEl) {
          return;
        }

        if (!ready) {
          selectEl.value = 'present';
          return;
        }

        const learnerId = Number(selectEl.dataset.learnerId || 0);
        const key = buildAttendanceKey(classId, attendanceDate, learnerId);
        selectEl.value = Object.prototype.hasOwnProperty.call(attendanceStatusLookup, key)
          ? String(attendanceStatusLookup[key])
          : 'present';
      });
    }

    function filterOptionsByClass(selectEl, classId) {
      if (!selectEl) {
        return;
      }

      let hasAny = false;
      Array.from(selectEl.options).forEach((option, idx) => {
        if (idx === 0) {
          option.style.display = '';
          return;
        }

        const optionClass = Number(option.dataset.class || 0);
        const show = classId > 0 && optionClass === classId;
        option.dataset.classVisible = show ? '1' : '0';
        option.style.display = show ? '' : 'none';
        if (show) {
          hasAny = true;
        }
      });

      selectEl.value = '';
      applySelectSearch(markSubjectSearch, selectEl, {
        defaultLabel: hasAny ? 'Choose option' : 'No options for selected class',
        emptyLabel: 'No matching options'
      });
    }

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

      const term = searchEl ? 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 classVisible = option.dataset.classVisible ? option.dataset.classVisible === '1' : true;
        const matches = term === '' || option.textContent.toLowerCase().includes(term);
        const show = classVisible && matches;
        option.style.display = show ? '' : 'none';
        if (!show && option.selected) {
          selectEl.value = String(selectEl.options[0]?.value || '');
          changedSelection = true;
        }
        if (show) {
          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 }));
      }
    }

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

      searchEl.addEventListener('input', function () {
        applySelectSearch(searchEl, selectEl, labels);
      });
      applySelectSearch(searchEl, selectEl, labels);
    }

    function filterLearnerRowsByClass(classId, subjectId) {
      const ready = classId > 0 && subjectId > 0;
      let visibleCount = 0;
      bulkLearnerRows.forEach(row => {
        const rowClass = Number(row.dataset.class || 0);
        const show = ready && rowClass === classId;
        row.style.display = show ? '' : 'none';
        if (!show) {
          const input = row.querySelector('input');
          if (input) {
            input.value = '';
          }
        }
        if (show) {
          visibleCount++;
        }
      });

      const emptyState = document.getElementById('markSheetHint');
      if (emptyState) {
        emptyState.style.display = visibleCount === 0 ? '' : 'none';
      }

      updateMarkEntryState();
    }

    function updateMarkEntryState() {
      let visibleCount = 0;
      let enteredCount = 0;

      bulkLearnerRows.forEach(row => {
        if (row.style.display === 'none') {
          return;
        }

        visibleCount++;
        const input = row.querySelector('input[data-learner-id]');
        row.classList.remove('missing-mark');
        if (input && String(input.value).trim() !== '') {
          enteredCount++;
        }
      });

      if (markEntryStatus) {
        if (visibleCount === 0) {
          markEntryStatus.textContent = 'Choose class and subject to begin entering marks.';
        } else {
          markEntryStatus.textContent = enteredCount + ' of ' + visibleCount + ' learner marks entered.';
        }
      }

      if (saveBulkBtn) {
        saveBulkBtn.disabled = visibleCount === 0 || enteredCount === 0;
        saveBulkBtn.style.opacity = saveBulkBtn.disabled ? '0.6' : '1';
        saveBulkBtn.style.cursor = saveBulkBtn.disabled ? 'not-allowed' : 'pointer';
      }
    }

    if (markClassSelect) {
      markClassSelect.addEventListener('change', function () {
        const classId = Number(this.value || 0);
        filterOptionsByClass(markSubjectSelect, classId);
        filterLearnerRowsByClass(classId, Number(markSubjectSelect?.value || 0));
        applyExistingMarksToVisibleRows();
      });
    }

    if (markSubjectSelect) {
      markSubjectSelect.addEventListener('change', function () {
        const classId = Number(markClassSelect?.value || 0);
        filterLearnerRowsByClass(classId, Number(this.value || 0));
        applyExistingMarksToVisibleRows();
      });
    }

    wireSelectSearch(learnerPickerSearch, learnerPickerSelect, {
      defaultLabel: 'Choose learner',
      emptyLabel: 'No matching learners'
    });

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

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

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

    wireSelectSearch(markSubjectSearch, markSubjectSelect, {
      defaultLabel: 'Choose option',
      emptyLabel: 'No matching options'
    });

    if (markTypeSelect) {
      markTypeSelect.addEventListener('change', applyExistingMarksToVisibleRows);
    }

    if (markTermSelect) {
      markTermSelect.addEventListener('change', applyExistingMarksToVisibleRows);
    }

    if (markDateInput) {
      markDateInput.addEventListener('change', applyExistingMarksToVisibleRows);
    }

    if (attendanceClassSelect) {
      attendanceClassSelect.addEventListener('change', function () {
        const classId = Number(this.value || 0);
        filterAttendanceRowsByClass(classId);
        applyExistingAttendanceToVisibleRows();
      });
      filterAttendanceRowsByClass(Number(attendanceClassSelect.value || 0));
      applyExistingAttendanceToVisibleRows();
    }

    if (attendanceDateInput) {
      attendanceDateInput.addEventListener('change', applyExistingAttendanceToVisibleRows);
    }

    bulkLearnerRows.forEach(row => {
      const input = row.querySelector('input[data-learner-id]');
      if (input) {
        input.addEventListener('input', updateMarkEntryState);
      }
    });

    if (marksForm) {
      marksForm.addEventListener('submit', function (event) {
        let hasEntry = false;
        let firstMissingInput = null;
        bulkLearnerRows.forEach(row => {
          if (row.style.display === 'none') {
            return;
          }

          const input = row.querySelector('input[data-learner-id]');
          if (!input) {
            return;
          }

          if (String(input.value).trim() !== '') {
            hasEntry = true;
            row.classList.remove('missing-mark');
          } else {
            row.classList.add('missing-mark');
            if (!firstMissingInput) {
              firstMissingInput = input;
            }
          }
        });

        if (!hasEntry) {
          event.preventDefault();
          if (markEntryStatus) {
            markEntryStatus.textContent = 'Enter at least one learner mark before saving.';
          }
          if (firstMissingInput) {
            firstMissingInput.focus();
          }
          return;
        }

        // If some rows are still empty, guide teacher to complete them quickly.
        if (firstMissingInput) {
          event.preventDefault();
          if (markEntryStatus) {
            markEntryStatus.textContent = 'Fill all highlighted rows, or remove learners from this sheet before saving.';
          }
          firstMissingInput.focus();
        }
      });
    }

    updateMarkEntryState();

    const markSearchInput = document.getElementById('markSearch');
    if (markSearchInput) {
      const markRows = Array.from(document.querySelectorAll('#markTable tbody tr'));
      markSearchInput.addEventListener('input', function () {
        const term = this.value.trim().toLowerCase();
        markRows.forEach(row => {
          const text = row.textContent.toLowerCase();
          row.style.display = text.includes(term) ? '' : 'none';
        });
      });
    }

    const marksView = document.getElementById('marksView');
    const toggleMarksBtn = document.getElementById('toggleMarksBtn');
    const printMarksBtn = document.getElementById('printMarksBtn');
    const downloadPdfBtn = document.getElementById('downloadPdfBtn');
    const downloadCsvBtn = document.getElementById('downloadCsvBtn');
    const markTable = document.getElementById('markTable');

    const learnerView = document.getElementById('learnerView');
    const toggleLearnersBtn = document.getElementById('toggleLearnersBtn');
    const printLearnersBtn = document.getElementById('printLearnersBtn');
    const downloadLearnersPdfBtn = document.getElementById('downloadLearnersPdfBtn');
    const downloadLearnersCsvBtn = document.getElementById('downloadLearnersCsvBtn');
    const learnerTable = document.getElementById('learnerTable');

    const notesView = document.getElementById('notesView');
    const toggleNotesBtn = document.getElementById('toggleNotesBtn');
    const printNotesBtn = document.getElementById('printNotesBtn');
    const downloadNotesPdfBtn = document.getElementById('downloadNotesPdfBtn');
    const downloadNotesCsvBtn = document.getElementById('downloadNotesCsvBtn');
    const notesTable = document.getElementById('notesTable');

    const individualReportView = document.getElementById('individualReportView');
    const toggleIndividualReportBtn = document.getElementById('toggleIndividualReportBtn');
    const printIndividualReportBtn = document.getElementById('printIndividualReportBtn');
    const downloadIndividualPdfBtn = document.getElementById('downloadIndividualPdfBtn');
    const downloadIndividualCsvBtn = document.getElementById('downloadIndividualCsvBtn');
    const individualReportTable = document.getElementById('individualReportTable');
    const individualLearnerSearch = document.getElementById('individualLearnerSearch');
    const individualLearnerId = document.getElementById('individualLearnerId');
    const individualReportEmptyRow = document.getElementById('individualReportEmptyRow');

    const scopeView = document.getElementById('scopeView');
    const toggleScopeBtn = document.getElementById('toggleScopeBtn');
    const admissionFormView = document.getElementById('admissionFormView');
    const toggleAdmissionFormBtn = document.getElementById('toggleAdmissionFormBtn');
    const captureMarksView = document.getElementById('captureMarksView');
    const toggleCaptureMarksBtn = document.getElementById('toggleCaptureMarksBtn');
    const coverageView = document.getElementById('coverageView');
    const toggleCoverageBtn = document.getElementById('toggleCoverageBtn');
    const printCoverageBtn = document.getElementById('printCoverageBtn');
    const downloadCoveragePdfBtn = document.getElementById('downloadCoveragePdfBtn');
    const downloadCoverageCsvBtn = document.getElementById('downloadCoverageCsvBtn');
    const coverageTable = document.getElementById('coverageTable');
    const classNotesFormView = document.getElementById('classNotesFormView');
    const toggleClassNotesFormBtn = document.getElementById('toggleClassNotesFormBtn');
    const libraryClassSelect = document.getElementById('library_class_id');
    const librarySubjectSelect = document.getElementById('library_subject_id');
    const teacherDocumentClassSelect = document.getElementById('teacher_document_class_id');
    const teacherDocumentSubjectSelect = document.getElementById('teacher_document_subject_id');
    const teacherDocumentUploadFormView = document.getElementById('teacherDocumentUploadFormView');
    const toggleTeacherDocumentUploadFormBtn = document.getElementById('toggleTeacherDocumentUploadFormBtn');
    const teacherSubmittedDocumentsView = document.getElementById('teacherSubmittedDocumentsView');
    const toggleTeacherSubmittedDocumentsBtn = document.getElementById('toggleTeacherSubmittedDocumentsBtn');
    const teacherInventoryFormView = document.getElementById('teacherInventoryFormView');
    const toggleTeacherInventoryFormBtn = document.getElementById('toggleTeacherInventoryFormBtn');
    const teacherInventoryTableView = document.getElementById('teacherInventoryTableView');
    const toggleTeacherInventoryTableBtn = document.getElementById('toggleTeacherInventoryTableBtn');
    const printTeacherInventoryBtn = document.getElementById('printTeacherInventoryBtn');
    const downloadTeacherInventoryPdfBtn = document.getElementById('downloadTeacherInventoryPdfBtn');
    const downloadTeacherInventoryCsvBtn = document.getElementById('downloadTeacherInventoryCsvBtn');
    const teacherInventoryTable = document.getElementById('teacherInventoryTable');
    const attendanceRegisterView = document.getElementById('attendanceRegisterView');
    const toggleAttendanceRegisterBtn = document.getElementById('toggleAttendanceRegisterBtn');
    const majorExamReportCardsView = document.getElementById('majorExamReportCardsView');
    const toggleMajorExamReportCardsBtn = document.getElementById('toggleMajorExamReportCardsBtn');
    const printMajorExamReportCardsBtn = document.getElementById('printMajorExamReportCardsBtn');
    const downloadMajorExamReportCardsPdfBtn = document.getElementById('downloadMajorExamReportCardsPdfBtn');
    const downloadMajorExamReportCardsCsvBtn = document.getElementById('downloadMajorExamReportCardsCsvBtn');
    const majorExamReportCardsTable = document.getElementById('majorExamReportCardsTable');
    const reportCardExamType = document.getElementById('reportCardExamType');
    const reportCardLearnerSearch = document.getElementById('reportCardLearnerSearch');
    const reportCardLearnerId = document.getElementById('reportCardLearnerId');
    const generateStudentReportCardBtn = document.getElementById('generateStudentReportCardBtn');
    const teacherElearningContentView = document.getElementById('teacherElearningContentView');
    const toggleTeacherElearningContentBtn = document.getElementById('toggleTeacherElearningContentBtn');
    const teacherELibraryContentView = document.getElementById('teacherELibraryContentView');
    const toggleTeacherELibraryContentBtn = document.getElementById('toggleTeacherELibraryContentBtn');
    const libraryLogView = document.getElementById('libraryLogView');
    const toggleLibraryLogBtn = document.getElementById('toggleLibraryLogBtn');
    const printLibraryLogBtn = document.getElementById('printLibraryLogBtn');
    const downloadLibraryLogPdfBtn = document.getElementById('downloadLibraryLogPdfBtn');
    const downloadLibraryLogCsvBtn = document.getElementById('downloadLibraryLogCsvBtn');
    const libraryLogTable = document.getElementById('libraryLogTable');
    const teacherLibraryFilterBtns = Array.from(document.querySelectorAll('#teacherLibraryFilterBar [data-doc-filter]'));
    const teacherLibraryRows = Array.from(document.querySelectorAll('#teacherLibraryTable tbody tr[data-doc-type]'));
    const teacherMetaSubject = document.getElementById('teacherMetaSubject');
    const teacherMetaPrompt = document.getElementById('teacherMetaPrompt');
    const copyTeacherMetaPromptBtn = document.getElementById('copyTeacherMetaPromptBtn');

    function applyTeacherLibraryFilter(filterType) {
      if (!teacherLibraryRows.length) {
        return;
      }

      teacherLibraryRows.forEach(row => {
        const rowType = String(row.dataset.docType || 'other');
        const show = filterType === 'all' || rowType === filterType;
        row.style.display = show ? '' : 'none';
      });

      teacherLibraryFilterBtns.forEach(btn => {
        btn.classList.toggle('active', btn.dataset.docFilter === filterType);
      });
    }

    teacherLibraryFilterBtns.forEach(btn => {
      btn.addEventListener('click', function () {
        applyTeacherLibraryFilter(String(this.dataset.docFilter || 'all'));
      });
    });

    applyTeacherLibraryFilter('all');

    function updateTeacherMetaPrompt() {
      if (!teacherMetaPrompt) {
        return;
      }
      const selectedSubject = String(teacherMetaSubject?.value || 'General').trim() || 'General';
      teacherMetaPrompt.value = `Create a 40-minute lesson plan for ${selectedSubject} for Zimbabwe primary learners. Include lesson objectives, starter activity, main activity, assessment, homework, and one low-bandwidth digital resource.`;
    }

    if (teacherMetaSubject) {
      teacherMetaSubject.addEventListener('change', updateTeacherMetaPrompt);
    }

    if (copyTeacherMetaPromptBtn && teacherMetaPrompt) {
      copyTeacherMetaPromptBtn.addEventListener('click', function () {
        teacherMetaPrompt.select();
        teacherMetaPrompt.setSelectionRange(0, teacherMetaPrompt.value.length);
        const copied = document.execCommand('copy');
        if (copied) {
          copyTeacherMetaPromptBtn.textContent = 'Copied';
          setTimeout(() => {
            copyTeacherMetaPromptBtn.textContent = 'Copy Prompt';
          }, 1200);
        }
      });
    }

    function filterLibrarySubjectsByClass(classId) {
      if (!librarySubjectSelect) {
        return;
      }

      let visibleCount = 0;
      Array.from(librarySubjectSelect.options).forEach((option, idx) => {
        if (idx === 0) {
          option.style.display = '';
          return;
        }

        const optionClass = Number(option.dataset.class || 0);
        const show = classId > 0 && optionClass === classId;
        option.style.display = show ? '' : 'none';
        if (show) {
          visibleCount++;
        }
      });

      if (librarySubjectSelect.options[0]) {
        librarySubjectSelect.options[0].text = visibleCount > 0
          ? 'General / not subject specific'
          : 'General / no class subject found';
      }

      librarySubjectSelect.value = '0';
    }

    if (libraryClassSelect) {
      libraryClassSelect.addEventListener('change', function () {
        filterLibrarySubjectsByClass(Number(this.value || 0));
      });
      filterLibrarySubjectsByClass(Number(libraryClassSelect.value || 0));
    }

    function filterTeacherDocumentSubjectsByClass(classId) {
      if (!teacherDocumentSubjectSelect) {
        return;
      }

      let visibleCount = 0;
      Array.from(teacherDocumentSubjectSelect.options).forEach((option, idx) => {
        if (idx === 0) {
          option.style.display = '';
          return;
        }

        const optionClass = Number(option.dataset.class || 0);
        const show = classId > 0 && optionClass === classId;
        option.style.display = show ? '' : 'none';
        if (show) {
          visibleCount++;
        }
      });

      if (teacherDocumentSubjectSelect.options[0]) {
        teacherDocumentSubjectSelect.options[0].text = visibleCount > 0
          ? 'General / not subject specific'
          : 'General / no class subject found';
      }

      teacherDocumentSubjectSelect.value = '0';
    }

    if (teacherDocumentClassSelect) {
      teacherDocumentClassSelect.addEventListener('change', function () {
        filterTeacherDocumentSubjectsByClass(Number(this.value || 0));
      });
      filterTeacherDocumentSubjectsByClass(Number(teacherDocumentClassSelect.value || 0));
    }

    function getVisibleTableRows(tableEl) {
      if (!tableEl) {
        return [];
      }
      return Array.from(tableEl.querySelectorAll('tbody tr')).filter(row => row.style.display !== 'none');
    }

    function getVisibleTableDataset(tableEl) {
      if (!tableEl) {
        return { headers: [], rows: [] };
      }

      const headers = Array.from(tableEl.querySelectorAll('thead th')).map(th => th.textContent.trim());
      const rows = getVisibleTableRows(tableEl).map(row => Array.from(row.querySelectorAll('td')).map(td => {
        const text = td.textContent.trim();
        const imageEl = td.querySelector('img');
        const imageSrc = imageEl && imageEl.getAttribute('src') ? String(imageEl.getAttribute('src')) : '';
        return {
          text,
          imageSrc
        };
      }));
      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 qrPayload = [
        `School: ${reportMeta.schoolName}`,
        `Report: ${modeLabel}`,
        `Teacher: ${reportMeta.teacherName}`,
        `Generated: ${generatedAt}`,
        `Rows: ${dataset.rows.length}`
      ].join(' | ');
      const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=${encodeURIComponent(qrPayload)}`;
      const palette = {
        ink: String(reportMeta?.palette?.ink || '#173122'),
        muted: String(reportMeta?.palette?.muted || '#4F6656'),
        brandNavyDeep: String(reportMeta?.palette?.brandNavyDeep || '#1D6A33'),
        brandIce: String(reportMeta?.palette?.brandIce || '#EEF7EF'),
        line: String(reportMeta?.palette?.line || '#D6EEFF')
      };

      const logoSrc = reportMeta.logoDataUri && reportMeta.logoDataUri !== '' ? reportMeta.logoDataUri : reportMeta.logoPath;
      const logoHtml = `<img src="${logoSrc}" alt="School logo" style="width:74px;height:74px;object-fit:contain;border:1px solid ${palette.line};border-radius:10px;padding:4px;">`;
      const qrHtml = `<div class="qr-box"><img src="${qrUrl}" alt="Report QR code"><div class="qr-label">Verify Report</div></div>`;
      const headerHtml = dataset.headers.map(h => `<th>${h}</th>`).join('');
      const escapeHtml = (value) => String(value ?? '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
      const bodyHtml = dataset.rows.map(row => `<tr>${row.map(cell => {
        if (cell.imageSrc) {
          return `<td class="photo-cell"><img src="${escapeHtml(cell.imageSrc)}" alt="Learner photo"></td>`;
        }
        return `<td>${escapeHtml(cell.text)}</td>`;
      }).join('')}</tr>`).join('');

      reportWindow.document.write(`
        <html>
          <head>
            <title>${reportMeta.schoolName} - ${modeLabel}</title>
            <style>
              body { font-family: Arial, sans-serif; padding: 18px; color: ${palette.ink}; }
              .head { display:flex; gap:12px; align-items:center; justify-content:space-between; margin-bottom:12px; }
              .head-left { display:flex; gap:12px; align-items:center; }
              h1 { margin:0; font-size: 20px; color:${palette.brandNavyDeep}; }
              .meta { margin: 3px 0; font-size: 13px; }
              .motto { margin-top: 4px; color:${palette.muted}; font-style: italic; }
              .gen { margin: 10px 0 14px; font-size: 12px; }
              .qr-box { text-align:center; }
              .qr-box img { width:120px; height:120px; border:1px solid ${palette.line}; border-radius:10px; padding:4px; }
              .qr-label { margin-top: 4px; font-size: 11px; color:${palette.muted}; }
              table { width: 100%; border-collapse: collapse; font-size: 12px; }
              th, td { border: 1px solid ${palette.line}; padding: 8px; text-align: left; }
              th { background: ${palette.brandIce}; color: ${palette.brandNavyDeep}; }
              .photo-cell { width: 62px; text-align: center; }
              .photo-cell img { width: 44px; height: 44px; object-fit: cover; border: 1px solid ${palette.line}; border-radius: 8px; display: inline-block; }
            </style>
          </head>
          <body>
            <div class="head">
              <div class="head-left">
                ${logoHtml}
                <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>
              ${qrHtml}
            </div>
            <div class="gen">Report: ${modeLabel} | Prepared By: ${reportMeta.teacherName} | Generated: ${generatedAt}</div>
            <table>
              <thead><tr>${headerHtml}</tr></thead>
              <tbody>${bodyHtml}</tbody>
        </div>
            </table>
          </body>
        </html>
      `);
      reportWindow.document.close();
      reportWindow.focus();
      reportWindow.print();
    }

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

      const esc = (text) => `"${String(text ?? '').replace(/\s+/g, ' ').trim().replace(/"/g, '""')}"`;
      const now = new Date().toLocaleString();
      const lines = [];

      lines.push('sep=,');
      lines.push(esc(sectionTitle));
      lines.push('');
      lines.push([esc('School Name'), esc(reportMeta.schoolName)].join(','));
      lines.push([esc('Address'), esc(reportMeta.schoolAddress)].join(','));
      lines.push([esc('Contact'), esc(reportMeta.schoolContact)].join(','));
      lines.push([esc('Motto'), esc(reportMeta.schoolMotto)].join(','));
      lines.push([esc('Logo File'), esc(reportMeta.logoPath)].join(','));
      lines.push('');
      lines.push([esc('Prepared By'), esc(reportMeta.teacherName)].join(','));
      lines.push([esc('Generated On'), esc(now)].join(','));
      lines.push([esc('Record Count'), esc(dataset.rows.length)].join(','));
      lines.push('');
      lines.push(esc('DATA TABLE'));
      lines.push(dataset.headers.map(esc).join(','));
      dataset.rows.forEach(row => lines.push(row.map(cell => esc(cell.text)).join(',')));

      const csv = '\uFEFF' + lines.join('\n');
      const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
      const link = document.createElement('a');
      link.href = URL.createObjectURL(blob);
      link.download = fileName;
      link.style.display = 'none';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }

    const teacherToggleRegistry = [];

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

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

      teacherToggleRegistry.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.toggleBtn || !cfg.viewEl) {
        return;
      }

      teacherToggleRegistry.push(cfg);

      cfg.toggleBtn.addEventListener('click', function () {
        const show = !cfg.viewEl.classList.contains('active');
        if (show) {
          closeSiblingFocusPanels(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);
        });
      }

      if (cfg.csvBtn) {
        cfg.csvBtn.addEventListener('click', function () {
          downloadCsvForTable(cfg.tableEl, cfg.csvName, cfg.csvTitle);
        });
      }
    }

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

      cfg.actionButtons = cfg.actionButtons || [];
      teacherToggleRegistry.push(cfg);

      cfg.toggleBtn.addEventListener('click', function () {
        const show = !cfg.viewEl.classList.contains('active');
        if (show) {
          closeSiblingFocusPanels(cfg);
        }
        cfg.viewEl.classList.toggle('active', show);
        cfg.toggleBtn.textContent = show ? cfg.hideLabel : cfg.showLabel;
      });
    }

    function updateIndividualReportRows() {
      if (!individualReportTable) {
        return;
      }

      const selectedLearnerId = Number(individualLearnerId?.value || 0);
      const rows = Array.from(individualReportTable.querySelectorAll('tbody tr[data-learner-id]'));
      let visibleCount = 0;

      rows.forEach(row => {
        const rowLearnerId = Number(row.dataset.learnerId || 0);
        const show = selectedLearnerId > 0 && rowLearnerId === selectedLearnerId;
        row.style.display = show ? '' : 'none';
        if (show) {
          visibleCount++;
        }
      });

      if (individualReportEmptyRow) {
        individualReportEmptyRow.style.display = visibleCount === 0 ? '' : 'none';
        if (visibleCount === 0) {
          individualReportEmptyRow.cells[0].textContent = selectedLearnerId > 0
            ? 'No marks found for selected learner.'
            : 'Choose a learner to view an individual report.';
        }
      }

      const isOpen = individualReportView && individualReportView.classList.contains('active');
      const canExport = isOpen && visibleCount > 0;
      [printIndividualReportBtn, downloadIndividualPdfBtn, downloadIndividualCsvBtn].forEach(btn => {
        if (btn) {
          btn.disabled = !canExport;
        }
      });
    }

    function reportCardExamMatches(row, examTypeKey) {
      const type = String(row.assessment_type || '').toLowerCase();
      const term = String(row.term_name || '').trim().toLowerCase();
      if (examTypeKey === 'end_of_term_exam_term1') {
        return type === 'end_of_term_exam' && term === 'term 1';
      }
      if (examTypeKey === 'midyear_exam') {
        return type === 'midyear_exam';
      }
      if (examTypeKey === 'end_of_year_exam') {
        return type === 'end_of_year_exam';
      }
      return false;
    }

    function percentageGrade(percent) {
      if (!Number.isFinite(percent)) {
        return { grade: 'U', status: 'FAIL' };
      }
      if (percent >= 80) return { grade: 'A', status: 'PASS' };
      if (percent >= 70) return { grade: 'B', status: 'PASS' };
      if (percent >= 60) return { grade: 'C', status: 'PASS' };
      if (percent >= 50) return { grade: 'D', status: 'PASS' };
      if (percent >= 40) return { grade: 'E', status: 'FAIL' };
      return { grade: 'U', status: 'FAIL' };
    }

    function generateStudentReportCard() {
      const learnerId = Number(reportCardLearnerId?.value || 0);
      const examTypeKey = String(reportCardExamType?.value || 'end_of_term_exam_term1');
      if (learnerId <= 0) {
        window.alert('Please choose a learner first.');
        return;
      }

      const examLabelMap = {
        end_of_term_exam_term1: 'END OF TERM 1',
        midyear_exam: 'MIDYEAR',
        end_of_year_exam: 'END OF YEAR'
      };

      const learnerInfo = (learnerDirectory || []).find(item => Number(item.id || 0) === learnerId) || null;
      const learnerRows = (majorExamMarkRows || []).filter(row => Number(row.learner_id || 0) === learnerId && reportCardExamMatches(row, examTypeKey));

      const subjectMap = new Map();
      learnerRows.forEach(row => {
        const subject = String(row.subject_name || 'Subject');
        const score = Number(row.score || 0);
        const maxScore = Number(row.max_score || 0);
        if (!subjectMap.has(subject)) {
          subjectMap.set(subject, { obtained: 0, total: 0 });
        }
        const bucket = subjectMap.get(subject);
        bucket.obtained += score;
        bucket.total += maxScore;
      });

      const subjectRows = Array.from(subjectMap.entries()).map(([subjectName, totals]) => {
        const percent = totals.total > 0 ? (totals.obtained / totals.total) * 100 : 0;
        const result = percentageGrade(percent);
        return {
          subjectName,
          obtained: totals.obtained,
          total: totals.total,
          percent,
          grade: result.grade,
          status: result.status
        };
      });

      const totalObtained = subjectRows.reduce((sum, row) => sum + row.obtained, 0);
      const totalPossible = subjectRows.reduce((sum, row) => sum + row.total, 0);
      const overallPercent = totalPossible > 0 ? (totalObtained / totalPossible) * 100 : 0;
      const overallResult = percentageGrade(overallPercent);

      const className = learnerInfo ? String(learnerInfo.class_name || '') : (learnerRows[0]?.class_name || '');
      const examClassRows = (majorExamMarkRows || []).filter(row => String(row.class_name || '') === className && reportCardExamMatches(row, examTypeKey));
      const learnerExamTotals = new Map();
      examClassRows.forEach(row => {
        const id = Number(row.learner_id || 0);
        if (!learnerExamTotals.has(id)) {
          learnerExamTotals.set(id, { obtained: 0, total: 0 });
        }
        const bucket = learnerExamTotals.get(id);
        bucket.obtained += Number(row.score || 0);
        bucket.total += Number(row.max_score || 0);
      });

      const ranked = Array.from(learnerExamTotals.entries()).map(([id, totals]) => ({
        learnerId: Number(id),
        percent: totals.total > 0 ? (totals.obtained / totals.total) * 100 : 0
      })).sort((a, b) => b.percent - a.percent);

      let studentPosition = '-';
      for (let idx = 0; idx < ranked.length; idx++) {
        if (ranked[idx].learnerId === learnerId) {
          studentPosition = String(idx + 1);
          break;
        }
      }

      const classAverage = ranked.length > 0 ? ranked.reduce((sum, row) => sum + row.percent, 0) / ranked.length : 0;
      const classMax = ranked.length > 0 ? ranked[0].percent : 0;
      const classMin = ranked.length > 0 ? ranked[ranked.length - 1].percent : 0;
      const learnerName = learnerInfo ? String(learnerInfo.full_name || '') : String(learnerRows[0]?.learner_name || '');
      const regNumber = learnerInfo ? String(learnerInfo.reg_number || '') : String(learnerRows[0]?.reg_number || '');
      const learnerGender = learnerInfo ? String(learnerInfo.gender || '') : String(learnerRows[0]?.gender || '');
      const dob = learnerInfo ? String(learnerInfo.date_of_birth_info || 'N/A') : 'N/A';
      const birthCertificateNo = learnerInfo ? String(learnerInfo.birth_certificate_number || 'N/A') : 'N/A';
      const admissionDate = learnerInfo ? String(learnerInfo.date_of_admission || 'N/A') : 'N/A';
      const photoPath = learnerInfo ? String(learnerInfo.student_photo_path || '') : String(learnerRows[0]?.student_photo_path || '');

      const esc = (value) => String(value ?? '')
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');

      const photoHtml = photoPath
        ? `<img src="${esc(photoPath)}" alt="Learner photo" style="width:54px;height:54px;object-fit:cover;border-radius:50%;border:1px solid #b6b6b6;">`
        : `<div style="width:54px;height:54px;border-radius:50%;border:1px solid #b6b6b6;background:#ededed;display:flex;align-items:center;justify-content:center;font-size:10px;color:#666;">NO PHOTO</div>`;

      const rowsHtml = subjectRows.length > 0
        ? subjectRows.map(row => `
          <tr>
            <td>${esc(row.subjectName.toUpperCase())}</td>
            <td>${esc(row.obtained.toFixed(0))}</td>
            <td>${esc(row.total.toFixed(0))}</td>
            <td>${esc(row.percent.toFixed(0))}%</td>
            <td>${esc(row.grade)}</td>
            <td>${esc(row.status)}</td>
            <td></td>
          </tr>
        `).join('')
        : `<tr><td colspan="7">No marks have been recorded for this examination.</td></tr>`;

      const logoSrc = reportMeta.logoDataUri && reportMeta.logoDataUri !== ''
        ? reportMeta.logoDataUri
        : reportMeta.logoPath;
      const palette = {
        ink: String(reportMeta?.palette?.ink || '#173122'),
        muted: String(reportMeta?.palette?.muted || '#4F6656'),
        brandNavyDeep: String(reportMeta?.palette?.brandNavyDeep || '#1D6A33'),
        brandIce: String(reportMeta?.palette?.brandIce || '#EEF7EF'),
        line: String(reportMeta?.palette?.line || '#D6EEFF')
      };

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

      reportWindow.document.write(`
        <html>
          <head>
            <title>${esc(reportMeta.schoolName)} Student Report Card</title>
            <style>
              @page { size: A4 portrait; margin: 8mm; }
              body { font-family: Arial, sans-serif; background:#fff; margin:0; padding:0; color:${palette.ink}; }
              .card { max-width: 194mm; width: 194mm; margin:0 auto; background:#fff; border:1px solid ${palette.line}; border-radius:14px; padding:8mm; }
              .center { text-align:center; }
              .school { font-size:20px; font-weight:700; color:${palette.brandNavyDeep}; }
              .sub { font-size:12px; color:${palette.muted}; }
              .title { font-size:18px; font-weight:700; margin-top:3px; }
              .box { border:1px solid ${palette.line}; border-radius:12px; margin-top:10px; overflow:hidden; }
              .box-head { background:${palette.brandIce}; border-bottom:1px solid ${palette.line}; font-size:12px; font-weight:700; padding:4px 8px; color:${palette.brandNavyDeep}; }
              .identity { display:grid; grid-template-columns:80px 1fr 1fr 1fr; gap:8px; padding:8px; font-size:12px; align-items:center; }
              .identity .kv { line-height:1.5; }
              .table { width:100%; border-collapse:collapse; font-size:12px; }
              .table th,.table td { border:1px solid ${palette.line}; padding:4px 6px; text-align:left; }
              .table th { background:${palette.brandIce}; color:${palette.brandNavyDeep}; }
              .line-box { border:1px solid ${palette.line}; border-radius:12px; margin-top:10px; padding:8px; min-height:70px; }
              .line { border-bottom:1px solid #bbb; height:18px; }
              .footer { margin-top:12px; display:grid; grid-template-columns:repeat(4,1fr); gap:10px; font-size:11px; text-align:center; }
              .footer .sigline { border-top:1px solid ${palette.line}; padding-top:4px; }
              @media print {
                body { background:#fff; padding:0; }
                .card { border:none; border-radius:0; page-break-inside: avoid; }
              }
            </style>
          </head>
          <body>
            <div class="card">
              <div class="center">
                <div style="margin-bottom:2px;"><img src="${esc(logoSrc)}" alt="School logo" style="width:22mm;height:22mm;object-fit:contain;"></div>
                <div class="school">${esc(reportMeta.schoolName)}</div>
                <div class="sub">Educational for Self Reliance</div>
                <div class="sub">Zimbabwe</div>
                <div class="title">Student Report Card</div>
              </div>

              <div class="box">
                <div class="identity">
                  <div>${photoHtml}</div>
                  <div class="kv">
                    <strong>REGISTRATION:</strong> ${esc(regNumber || 'N/A')}<br>
                    <strong>NAME:</strong> ${esc(learnerName || 'N/A')}<br>
                    <strong>CLASS:</strong> ${esc(className || 'N/A')}
                  </div>
                  <div class="kv">
                    <strong>DATE OF BIRTH:</strong> ${esc(dob || 'N/A')}<br>
                    <strong>BIRTH CERTIFICATE NO:</strong> ${esc(birthCertificateNo || 'N/A')}<br>
                    <strong>GENDER:</strong> ${esc(learnerGender || 'N/A')}<br>
                    <strong>ADMISSION DATE:</strong> ${esc(admissionDate || 'N/A')}
                  </div>
                  <div class="kv">
                    <strong>EXAM:</strong> ${esc(examLabelMap[examTypeKey] || 'MAJOR EXAM')}<br>
                    <strong>ATTENDANCE:</strong> 0%<br>
                    <strong>ABSENTS:</strong> 0
                  </div>
                </div>
              </div>

              <div class="box">
                <div class="box-head">COGNITIVE DOMAIN - ${esc(String(examLabelMap[examTypeKey] || 'MAJOR EXAM').toUpperCase())}</div>
                <table class="table">
                  <thead>
                    <tr>
                      <th>ASSESSMENTS / SUBJECT</th>
                      <th>OBTAINED</th>
                      <th>TOTAL</th>
                      <th>%</th>
                      <th>GRADE</th>
                      <th>STATUS</th>
                      <th>TEACHER'S COMMENT</th>
                    </tr>
                  </thead>
                  <tbody>
                    ${rowsHtml}
                  </tbody>
                </table>
                <table class="table">
                  <tbody>
                    <tr>
                      <td><strong>TOTAL MARKS</strong><br>${esc(totalObtained.toFixed(0))}</td>
                      <td><strong>TOTAL SCORE</strong><br>${esc(totalObtained.toFixed(0))} / ${esc(totalPossible.toFixed(0))}</td>
                      <td><strong>PERCENTAGE</strong><br>${esc(overallPercent.toFixed(1))}%</td>
                      <td><strong>GRADE</strong><br>${esc(overallResult.grade)}</td>
                      <td><strong>STATUS</strong><br>${esc(overallResult.status)}</td>
                    </tr>
                  </tbody>
                </table>
                <table class="table" style="margin-top:4px;">
                  <tbody>
                    <tr>
                      <td>COMPARISON WITH CLASS</td>
                      <td>CLASS STRENGTH<br><strong>${esc(String(ranked.length || 0))} STUDENTS</strong></td>
                      <td>CLASS AVERAGE<br><strong>${esc(classAverage.toFixed(1))}%</strong></td>
                      <td>CLASS MAX AVERAGE<br><strong>${esc(classMax.toFixed(1))}%</strong></td>
                      <td>CLASS MIN AVERAGE<br><strong>${esc(classMin.toFixed(1))}%</strong></td>
                      <td>STUDENT POSITION<br><strong>${esc(studentPosition)}</strong></td>
                    </tr>
                  </tbody>
                </table>
              </div>

              <div class="line-box">
                <strong>CLASS TEACHER'S OVERALL OBSERVATION</strong>
                <div class="line"></div>
                <div class="line"></div>
                <div class="line"></div>
              </div>

              <div class="line-box">
                <strong>HEAD TEACHER'S COMMENT</strong>
                <div class="line"></div>
                <div class="line"></div>
                <div class="line"></div>
              </div>

              <div class="box" style="margin-top:10px;">
                <div class="box-head">NEXT TERM INFORMATION</div>
                <div style="padding:6px 8px; font-size:12px;"><strong>Next Term Opens:</strong> __ / __ / ____ &nbsp;&nbsp; <strong>Promotion Status:</strong> PROMOTED / REPEAT &nbsp;&nbsp; <strong>Next Class:</strong> __________</div>
              </div>

              <div class="footer">
                <div><div class="sigline">DATE</div></div>
                <div><div class="sigline">SIGNATURE</div></div>
                <div><div class="sigline">STAMP</div></div>
                <div><div class="sigline">${esc(examLabelMap[examTypeKey] || 'TERM')}</div></div>
              </div>
            </div>
            <script>window.onload = function(){ window.print(); }<\/script>
          </body>
        </html>
      `);
      reportWindow.document.close();
    }

    wireToggleAndActions({
      viewEl: marksView,
      tableEl: markTable,
      toggleBtn: toggleMarksBtn,
      printBtn: printMarksBtn,
      pdfBtn: downloadPdfBtn,
      csvBtn: downloadCsvBtn,
      actionButtons: [printMarksBtn, downloadPdfBtn, downloadCsvBtn],
      showLabel: 'Show Marks',
      hideLabel: 'Hide Marks',
      printTitle: 'Marks Print Report',
      pdfTitle: 'Marks PDF Report',
      csvTitle: 'MARKS REPORT',
      csvName: `${schoolFilePrefix}_marks_report.csv`
    });

    wireToggleAndActions({
      viewEl: learnerView,
      tableEl: learnerTable,
      toggleBtn: toggleLearnersBtn,
      printBtn: printLearnersBtn,
      pdfBtn: downloadLearnersPdfBtn,
      csvBtn: downloadLearnersCsvBtn,
      actionButtons: [printLearnersBtn, downloadLearnersPdfBtn, downloadLearnersCsvBtn],
      showLabel: 'Show Learner Register',
      hideLabel: 'Hide Learner Register',
      printTitle: 'Learner Register Print Report',
      pdfTitle: 'Learner Register PDF Report',
      csvTitle: 'LEARNER REGISTER REPORT',
      csvName: `${schoolFilePrefix}_learner_register.csv`
    });

    wireToggleAndActions({
      viewEl: notesView,
      tableEl: notesTable,
      toggleBtn: toggleNotesBtn,
      printBtn: printNotesBtn,
      pdfBtn: downloadNotesPdfBtn,
      csvBtn: downloadNotesCsvBtn,
      actionButtons: [printNotesBtn, downloadNotesPdfBtn, downloadNotesCsvBtn],
      showLabel: 'Show Notes',
      hideLabel: 'Hide Notes',
      printTitle: 'Teacher Notes Print Report',
      pdfTitle: 'Teacher Notes PDF Report',
      csvTitle: 'TEACHER NOTES REPORT',
      csvName: `${schoolFilePrefix}_teacher_notes.csv`
    });

    wireToggleAndActions({
      viewEl: individualReportView,
      tableEl: individualReportTable,
      toggleBtn: toggleIndividualReportBtn,
      printBtn: printIndividualReportBtn,
      pdfBtn: downloadIndividualPdfBtn,
      csvBtn: downloadIndividualCsvBtn,
      actionButtons: [printIndividualReportBtn, downloadIndividualPdfBtn, downloadIndividualCsvBtn],
      showLabel: 'Show Individual Learner Report',
      hideLabel: 'Hide Individual Learner Report',
      printTitle: 'Individual Learner Print Report',
      pdfTitle: 'Individual Learner PDF Report',
      csvTitle: 'INDIVIDUAL LEARNER REPORT',
      csvName: `${schoolFilePrefix}_individual_learner_report.csv`
    });

    wireToggleOnly({
      viewEl: scopeView,
      toggleBtn: toggleScopeBtn,
      showLabel: 'Show Class and Subject Scope',
      hideLabel: 'Hide Class and Subject Scope'
    });

    function focusAdmissionFormAfterSuccessfulSave() {
      const successAlert = Array.from(document.querySelectorAll('.alert.success')).find(function (alertEl) {
        return (alertEl.textContent || '').toLowerCase().includes('admission submitted') ||
          (alertEl.textContent || '').toLowerCase().includes('learner');
      });

      if (!successAlert || !admissionFormView || !toggleAdmissionFormBtn) {
        return;
      }

      const targetSection = document.getElementById('teacherAdmissionNotesView');
      if (targetSection) {
        targetSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
      }

      const formIsVisible = admissionFormView.classList.contains('active');
      if (!formIsVisible) {
        admissionFormView.classList.add('active');
        toggleAdmissionFormBtn.textContent = 'Hide Student Admission Form';
      }

      const firstField = document.getElementById('class_id');
      if (firstField) {
        setTimeout(function () {
          firstField.focus();
          firstField.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }, 120);
      }
    }

    wireToggleOnly({
      viewEl: admissionFormView,
      toggleBtn: toggleAdmissionFormBtn,
      showLabel: 'Show Student Admission Form',
      hideLabel: 'Hide Student Admission Form'
    });

    focusAdmissionFormAfterSuccessfulSave();

    wireToggleOnly({
      viewEl: captureMarksView,
      toggleBtn: toggleCaptureMarksBtn,
      showLabel: 'Show Capture Learner Marks',
      hideLabel: 'Hide Capture Learner Marks'
    });

    wireToggleOnly({
      viewEl: classNotesFormView,
      toggleBtn: toggleClassNotesFormBtn,
      showLabel: 'Show Class Learner Notes',
      hideLabel: 'Hide Class Learner Notes'
    });

    wireToggleOnly({
      viewEl: teacherDocumentUploadFormView,
      toggleBtn: toggleTeacherDocumentUploadFormBtn,
      showLabel: 'Show Upload Form',
      hideLabel: 'Hide Upload Form'
    });

    wireToggleOnly({
      viewEl: teacherSubmittedDocumentsView,
      toggleBtn: toggleTeacherSubmittedDocumentsBtn,
      showLabel: 'Show Submitted Documents',
      hideLabel: 'Hide Submitted Documents'
    });

    wireToggleOnly({
      viewEl: teacherInventoryFormView,
      toggleBtn: toggleTeacherInventoryFormBtn,
      showLabel: 'Show Inventory Form',
      hideLabel: 'Hide Inventory Form'
    });

    wireToggleAndActions({
      viewEl: teacherInventoryTableView,
      tableEl: teacherInventoryTable,
      toggleBtn: toggleTeacherInventoryTableBtn,
      printBtn: printTeacherInventoryBtn,
      pdfBtn: downloadTeacherInventoryPdfBtn,
      csvBtn: downloadTeacherInventoryCsvBtn,
      actionButtons: [printTeacherInventoryBtn, downloadTeacherInventoryPdfBtn, downloadTeacherInventoryCsvBtn],
      showLabel: 'Show Inventory Reviews',
      hideLabel: 'Hide Inventory Reviews',
      printTitle: 'Teacher Inventory Reviews Print Report',
      pdfTitle: 'Teacher Inventory Reviews PDF Report',
      csvTitle: 'TEACHER INVENTORY REVIEWS',
      csvName: `${schoolFilePrefix}_teacher_inventory_reviews.csv`
    });

    wireToggleOnly({
      viewEl: attendanceRegisterView,
      toggleBtn: toggleAttendanceRegisterBtn,
      showLabel: 'Show Daily Attendance Register',
      hideLabel: 'Hide Daily Attendance Register'
    });

    wireToggleAndActions({
      viewEl: majorExamReportCardsView,
      tableEl: majorExamReportCardsTable,
      toggleBtn: toggleMajorExamReportCardsBtn,
      printBtn: printMajorExamReportCardsBtn,
      pdfBtn: downloadMajorExamReportCardsPdfBtn,
      csvBtn: downloadMajorExamReportCardsCsvBtn,
      actionButtons: [printMajorExamReportCardsBtn, downloadMajorExamReportCardsPdfBtn, downloadMajorExamReportCardsCsvBtn],
      showLabel: 'Show Student Report Cards',
      hideLabel: 'Hide Student Report Cards',
      printTitle: 'Student Report Cards - Major Exams Print Report',
      pdfTitle: 'Student Report Cards - Major Exams PDF Report',
      csvTitle: 'STUDENT REPORT CARDS - MAJOR EXAMS',
      csvName: `${schoolFilePrefix}_student_report_cards_major_exams.csv`
    });

    wireToggleOnly({
      viewEl: teacherElearningContentView,
      toggleBtn: toggleTeacherElearningContentBtn,
      showLabel: 'Show E-learning Hub',
      hideLabel: 'Hide E-learning Hub'
    });

    wireToggleOnly({
      viewEl: teacherELibraryContentView,
      toggleBtn: toggleTeacherELibraryContentBtn,
      showLabel: 'Show E-Library',
      hideLabel: 'Hide E-Library'
    });

    wireToggleAndActions({
      viewEl: coverageView,
      tableEl: coverageTable,
      toggleBtn: toggleCoverageBtn,
      printBtn: printCoverageBtn,
      pdfBtn: downloadCoveragePdfBtn,
      csvBtn: downloadCoverageCsvBtn,
      actionButtons: [printCoverageBtn, downloadCoveragePdfBtn, downloadCoverageCsvBtn],
      showLabel: 'Show Assessment Coverage Summary',
      hideLabel: 'Hide Assessment Coverage Summary',
      printTitle: 'Assessment Coverage Print Report',
      pdfTitle: 'Assessment Coverage PDF Report',
      csvTitle: 'ASSESSMENT COVERAGE REPORT',
      csvName: `${schoolFilePrefix}_assessment_coverage_report.csv`
    });

    wireToggleAndActions({
      viewEl: libraryLogView,
      tableEl: libraryLogTable,
      toggleBtn: toggleLibraryLogBtn,
      printBtn: printLibraryLogBtn,
      pdfBtn: downloadLibraryLogPdfBtn,
      csvBtn: downloadLibraryLogCsvBtn,
      actionButtons: [printLibraryLogBtn, downloadLibraryLogPdfBtn, downloadLibraryLogCsvBtn],
      showLabel: 'Show Access Log',
      hideLabel: 'Hide Access Log',
      printTitle: 'E-Library Access Log Print Report',
      pdfTitle: 'E-Library Access Log PDF Report',
      csvTitle: 'E-LIBRARY ACCESS LOG REPORT',
      csvName: `${schoolFilePrefix}_elibrary_access_log.csv`
    });

    const teacherDeskNavBtns = Array.from(document.querySelectorAll('#teacherDeskNav .desk-nav-btn'));
    const teacherDeskViews = Array.from(document.querySelectorAll('.desk-main > .desk-view'));
    const teacherDeskProgressChip = document.getElementById('teacherDeskProgressChip');

    function getTeacherBtnTargets(btn) {
      if (!btn) {
        return [];
      }
      if (btn.dataset.targets) {
        return btn.dataset.targets.split(',').map(x => x.trim()).filter(Boolean);
      }
      return btn.dataset.target ? [btn.dataset.target] : [];
    }

    function openTeacherDeskView(viewIdOrList) {
      const viewIds = Array.isArray(viewIdOrList) ? viewIdOrList : [viewIdOrList];
      
      // Explicitly remove active class from ALL views
      teacherDeskViews.forEach(view => {
        view.classList.remove('active');
      });
      
      // Explicitly add active class to target views
      viewIds.forEach(viewId => {
        const view = document.getElementById(viewId);
        if (view) {
          view.classList.add('active');
        }
      });
      
      // Explicitly remove active class from ALL buttons
      teacherDeskNavBtns.forEach(btn => {
        btn.classList.remove('active');
      });
      
      // Explicitly add active class to matching buttons
      teacherDeskNavBtns.forEach(btn => {
        const targets = getTeacherBtnTargets(btn);
        const isActive = targets.length > 0 && targets.every(target => viewIds.includes(target));
        if (isActive) {
          btn.classList.add('active');
        }
      });

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

    teacherDeskNavBtns.forEach(btn => {
      btn.addEventListener('click', function () {
        const targets = getTeacherBtnTargets(this);
        if (targets.length > 0) {
          openTeacherDeskView(targets);
        }
      });
    });

    openTeacherDeskView('teacherHomeView');

    wireSelectSearch(individualLearnerSearch, individualLearnerId, {
      defaultLabel: 'Choose learner',
      emptyLabel: 'No matching learners'
    });

    wireSelectSearch(reportCardLearnerSearch, reportCardLearnerId, {
      defaultLabel: 'Choose learner',
      emptyLabel: 'No matching learners'
    });

    function syncTeacherAnnouncementTargetFields() {
      if (!teacherAnnouncementTargetType || !teacherAnnouncementTargetClassWrap || !teacherAnnouncementTargetLearnerWrap) {
        return;
      }

      const targetType = teacherAnnouncementTargetType.value;
      const showClass = targetType === 'class';
      const showLearner = targetType === 'learner';

      teacherAnnouncementTargetClassWrap.style.display = showClass ? '' : 'none';
      teacherAnnouncementTargetLearnerWrap.style.display = showLearner ? '' : 'none';

      if (teacherAnnouncementTargetClassSelect) {
        teacherAnnouncementTargetClassSelect.required = showClass;
        if (!showClass) {
          teacherAnnouncementTargetClassSelect.value = '';
        }
      }
      if (teacherAnnouncementTargetLearnerSelect) {
        teacherAnnouncementTargetLearnerSelect.required = showLearner;
        if (!showLearner) {
          teacherAnnouncementTargetLearnerSelect.value = '';
        }
      }
    }

    if (teacherAnnouncementTargetType) {
      teacherAnnouncementTargetType.addEventListener('change', syncTeacherAnnouncementTargetFields);
    }
    syncTeacherAnnouncementTargetFields();

    if (generateStudentReportCardBtn) {
      generateStudentReportCardBtn.addEventListener('click', generateStudentReportCard);
    }

    if (individualLearnerId) {
      individualLearnerId.addEventListener('change', updateIndividualReportRows);
    }

    if (toggleIndividualReportBtn) {
      toggleIndividualReportBtn.addEventListener('click', updateIndividualReportRows);
    }

    updateIndividualReportRows();
  </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>
