/* ==========================================================================
   Shree Khadgakali Secondary School — Marks Entry App
   Design tokens: deep indigo (#1B2A4A) + marigold accent (#E8A33D)
   on warm cream (#FAF7F2). Display: Poppins. Body: Inter. Data: Roboto Mono.
   ========================================================================== */

@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@600;700;800&family=Inter:wght@400;500;600&family=Roboto+Mono:wght@500;600&family=Noto+Sans+Devanagari:wght@400;500;600;700;800&display=swap");

/* Kalimati — the standard Unicode Devanagari font used on official Nepali
   government/school documents (gradesheets, ledgers). Not on Google Fonts,
   so it's loaded from jsDelivr's GitHub CDN instead. Used as the *primary*
   Nepali typeface everywhere (see the "Kalimati", "Noto Sans Devanagari"
   font stacks below); Noto Sans Devanagari stays as the fallback for any
   glyph Kalimati doesn't cover, and for the brief moment before Kalimati
   itself finishes loading. */
@font-face {
  font-family: "Kalimati";
  src: url("https://cdn.jsdelivr.net/gh/mhnpd/nepali-font@master/fonts/Kalimati.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --ink: #1b2a4a;
  --ink-light: #2f4270;
  --gold: #e8a33d;
  --gold-dark: #c8811f;
  --cream: #faf7f2;
  --card: #ffffff;
  --text: #2b2b2b;
  --muted: #6b7280;
  --success: #3f7a5c;
  --error: #c1443c;
  --border: #e6e0d4;
  /* Mark-type color coding — used across the admin print ledger AND the
     marks-entry number-entry table/print view (see .mk-* and the
     data-field selectors under "Mark-type coloring" below). */
  --external: #1f6b3a;   /* dark green — external exam marks */
  --internal: #1a3d7c;   /* dark blue  — internal/formative marks */
  --total-mark: #cc1f1f; /* red        — computed totals */
}

* { box-sizing: border-box; }

body {
  background: var(--cream);
  color: var(--text);
  font-family: "Inter", "Kalimati", "Noto Sans Devanagari", system-ui, sans-serif;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, .display {
  font-family: "Poppins", "Kalimati", "Noto Sans Devanagari", sans-serif;
}

.font-mono-data {
  font-family: "Roboto Mono", "Kalimati", "Noto Sans Devanagari", monospace;
}

/* ---- Header / brand bar ---- */
.brand-header {
  background: linear-gradient(135deg, var(--ink) 0%, var(--ink-light) 100%);
  position: relative;
}
.brand-header::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--gold-dark), var(--gold), var(--gold-dark));
}

/* ---- Cards ---- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 1px 3px rgba(27, 42, 74, 0.06);
}

/* ---- Buttons ---- */
.btn-primary {
  background: var(--ink);
  color: #fff;
  font-weight: 600;
  border-radius: 12px;
  transition: transform 0.12s ease, background 0.12s ease;
}
.btn-primary:hover { background: var(--ink-light); }
.btn-primary:active { transform: scale(0.98); }
.btn-primary:disabled { opacity: 0.5; }

.btn-gold {
  background: var(--gold);
  color: var(--ink);
  font-weight: 700;
  border-radius: 12px;
  transition: transform 0.12s ease, background 0.12s ease;
}
.btn-gold:hover { background: var(--gold-dark); }
.btn-gold:active { transform: scale(0.98); }

/* ---- Inputs ---- */
.input-field {
  border: 1.5px solid var(--border);
  border-radius: 10px;
  padding: 0.65rem 0.85rem;
  font-size: 1rem;
  background: #fff;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
  width: 100%;
}
.input-field:focus {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(232, 163, 61, 0.25);
}
.input-field.invalid {
  border-color: var(--error);
  box-shadow: 0 0 0 3px rgba(193, 68, 60, 0.15);
}

:focus-visible {
  outline: 2px solid var(--gold-dark);
  outline-offset: 2px;
}

/* ---- Ledger-style marks table (the app's signature element) ---- */
.ledger {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
}
.ledger thead th {
  background: var(--ink);
  color: #f3ede0;
  font-family: "Poppins", "Kalimati", "Noto Sans Devanagari", sans-serif;
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 0.6rem 0.5rem;
  position: sticky;
  top: 0;
  z-index: 5;
  border: 1px solid var(--gold-dark);
  border-bottom: 2px solid var(--gold);
  white-space: nowrap;
}
/* Allotted-marks note shown under a column label, e.g. "Written (50)" —
   same small, tight-width bracket convention everywhere a column has a
   fixed full-marks value: Nursery/KG, Breakdown (classes 6-10), the LO
   ledger's Full Marks column, and the matching headers on the Marks
   Entry page and its print/preview. Deliberately lighter and smaller
   than the label above it, and never wraps onto its own second line. */
.fm-note {
  display: inline-block;
  font-weight: 400;
  font-size: 0.85em;
  letter-spacing: normal;
  text-transform: none;
  opacity: 0.7;
  white-space: nowrap;
}
.ledger tbody tr {
  background: #fff;
  border-bottom: 1px solid var(--border);
}
.ledger tbody tr:nth-child(even) { background: #fbf9f4; }
.ledger tbody tr:hover { background: #fdf3e2; }
.ledger td {
  padding: 0.5rem;
  vertical-align: middle;
  border: 1px solid var(--border);
}
/* Centered by default everywhere in the ledger — high enough
   specificity to beat Tailwind's .text-left utility used on a few
   header/data cells. Student-name cells are the one exception, set
   to right-aligned via .ledger-name-col below. */
.ledger th,
.ledger td {
  text-align: center;
}
.ledger td.ledger-name-col {
  text-align: right;
}
.ledger .mark-input {
  width: 100%;
  min-width: 3.5rem;
  text-align: center;
  font-family: "Roboto Mono", "Kalimati", "Noto Sans Devanagari", monospace;
  font-weight: 600;
  padding: 0.4rem 0.3rem;
  border: 1.5px solid var(--border);
  border-radius: 8px;
}
.ledger .mark-input:focus {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(232, 163, 61, 0.25);
}
.ledger .mark-input.invalid { border-color: var(--error); }
.ledger .row-total {
  font-family: "Roboto Mono", "Kalimati", "Noto Sans Devanagari", monospace;
  font-weight: 700;
  color: var(--ink);
}

/* ---- Mark-type coloring (marks-entry number-entry table) ----
   Internal/formative fields -> dark blue, the external-exam field ->
   dark green, computed totals -> red. Selected by the same data-field
   attributes marks-entry.js already puts on each input, so no extra
   markup is needed here. */
.ledger .mark-input[data-field="participation"],
.ledger .mark-input[data-field="practical"],
.ledger .mark-input[data-field="firstTerm"],
.ledger .mark-input[data-field="written"],
.ledger .mark-input[data-field="oral"],
.ledger .mark-input[data-field="obtainedLO"] {
  color: var(--internal);
}
.ledger .mark-input[data-field="external"] {
  color: var(--external);
}
.ledger .row-total,
.ledger td.mk-total {
  color: var(--total-mark) !important;
}
.ledger td.mk-internal { color: var(--internal) !important; }
.ledger td.mk-external { color: var(--external) !important; }

/* Grade Ledger — NG subject cells get a soft red background so a failed
   subject stands out at a glance; the GPA column is bold so it reads as
   the row's headline number. */
.ledger td.grade-ng {
  background: #fbe4e2;
  color: var(--error) !important;
  font-weight: 600;
}
.ledger td.gpa-cell {
  font-weight: 700;
}

.table-scroll {
  overflow-x: auto;
  border-radius: 16px;
  border: 1px solid var(--border);
}

/* ---- Audit trail ---- */
.audit-line {
  font-size: 0.72rem;
  color: var(--muted);
  font-family: "Roboto Mono", "Kalimati", "Noto Sans Devanagari", monospace;
}

/* ---- Sticky save bar (thumb-reach on mobile) ---- */
.save-bar {
  position: sticky;
  bottom: 0;
  background: rgba(250, 247, 242, 0.92);
  backdrop-filter: blur(6px);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom);
}

/* ---- Tab pills (in-page tabs: Print Ledger, Settings) ---- */
.admin-nav {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  padding-bottom: 0.25rem;
  -ms-overflow-style: none;
  scrollbar-width: none;
}
.admin-nav::-webkit-scrollbar { display: none; }
.admin-nav-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.55rem 1rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  white-space: nowrap;
  background: #fff;
  border: 1.5px solid var(--border);
  color: var(--ink);
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
  flex-shrink: 0;
}
.admin-nav-pill:hover { background: var(--cream); border-color: var(--gold); }
.admin-nav-pill[aria-current="page"] {
  background: var(--ink);
  color: #fff;
  border-color: var(--ink);
}

/* ---- Mobile admin menu: hamburger opens a full left-side drawer (not a
   floating button widget) so the whole nav is reachable in one place, same
   as the always-visible desktop sidebar below. ---- */
.admin-menu-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 0.6rem;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #fff;
  font-size: 1.2rem;
  line-height: 1;
  flex-shrink: 0;
  transition: background 0.12s ease;
}
.admin-menu-toggle svg { width: 1.15rem; height: 1.15rem; display: block; }
.admin-menu-toggle:hover { background: rgba(255, 255, 255, 0.18); }
.admin-menu-toggle[aria-expanded="true"] { background: var(--gold); border-color: var(--gold); color: var(--ink); }

/* Dimmed backdrop behind the open drawer — click to close. */
.admin-drawer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 20, 35, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 70;
}
.admin-drawer-overlay.open { opacity: 1; pointer-events: auto; }

/* The drawer itself — full-height panel pinned to the left edge, slides in
   over the page instead of a small button-style dropdown. */
.admin-drawer {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: min(80vw, 300px);
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, var(--ink) 0%, var(--ink-light) 100%);
  transform: translateX(-105%);
  transition: transform 0.25s ease;
  z-index: 71;
  box-shadow: 10px 0 30px rgba(10, 14, 28, 0.35);
}
.admin-drawer.open { transform: translateX(0); }
.admin-drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 1.1rem 1rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  flex-shrink: 0;
}
.admin-drawer-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 0.5rem;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #fff;
  flex-shrink: 0;
}
.admin-drawer-close svg { width: 1rem; height: 1rem; display: block; }
.admin-drawer-close:hover { background: rgba(255, 255, 255, 0.18); }
.admin-drawer-nav {
  flex: 1;
  overflow-y: auto;
  padding: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

/* ---- Desktop admin sidebar — always visible, full nav list, not a
   collapsed dropdown of action buttons. ---- */
.admin-sidebar {
  background: linear-gradient(180deg, var(--ink) 0%, var(--ink-light) 100%);
}
.admin-sidebar-nav {
  flex: 1;
  overflow-y: auto;
  padding: 0.9rem;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.sidebar-link {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.65rem 0.85rem;
  border-radius: 10px;
  font-size: 0.85rem;
  font-weight: 600;
  color: rgba(255,255,255,0.75);
  transition: background 0.12s ease, color 0.12s ease;
}
.sidebar-link:hover { background: rgba(255,255,255,0.08); color: #fff; }
.sidebar-link[aria-current="page"] {
  background: var(--gold);
  color: var(--ink);
}
.sidebar-link .admin-menu-icon { font-size: 1rem; width: 1.4rem; text-align: center; flex-shrink: 0; }


/* Round avatar-style icon used on the logout buttons (sidebar + mobile
   header) in renderAdminShell() — see js/utils.js. */
.user-circle {
  width: 30px;
  height: 30px;
  background-color: #e0e0e0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  flex-shrink: 0;
}

/* Desktop's account icon button — top-right of the page header (see
   renderAdminShell() in js/utils.js), just the circle icon with no extra
   chrome since the white header bar already provides the contrast. */
.account-trigger-btn {
  background: transparent;
  border: none;
  padding: 0;
  line-height: 0;
  cursor: pointer;
}

/* Account popover — opens under the 👤 logout icon (see
   setupAccountPopover() in js/utils.js). Shows who's signed in and holds
   the actual "Log out" action, so a click on the icon itself never signs
   anyone out by accident. */
.account-popover {
  position: absolute;
  z-index: 40;
  min-width: 200px;
  background: #fff;
  color: var(--ink);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.18);
  padding: 0.75rem;
}
/* Both the desktop header's account icon and the mobile header's sit at
   the top of the page (top-right corner), so both popovers open
   downward, right-aligned under the icon. account-popover-up is kept for
   any future spot where the trigger sits at the bottom of the screen. */
.account-popover-up { bottom: calc(100% + 8px); left: 0; }
.account-popover-down { top: calc(100% + 8px); right: 0; }
.account-popover-name {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 0.5rem;
  word-break: break-word;
}
.account-popover-logout {
  width: 100%;
  padding: 0.5rem 0.75rem;
  border-radius: 8px;
  background: var(--error, #c0392b);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 600;
}
.account-popover-logout:hover { opacity: 0.9; }

/* "Switch to Teacher View" / "Switch back to Admin View" — lives inside
   the account popover (see renderImpersonationControls() in js/utils.js),
   right between the "Signed in as…" line and Log out, so both account
   actions open from the same profile-circle click on both breakpoints.
   The popover itself is white on both breakpoints, so one style covers
   desktop and mobile. Given its own gradient + icon chip (rather than the
   plain gold-outline look) so it reads as a distinct, inviting action
   next to the plain white popover and the solid red Log out button. */
.account-popover-switch {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.6rem 0.75rem;
  border-radius: 10px;
  border: none;
  background: linear-gradient(135deg, var(--gold) 0%, var(--gold-dark) 100%);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 700;
  margin-bottom: 0.5rem;
  text-align: center;
  box-shadow: 0 3px 10px rgba(200, 129, 31, 0.35);
  transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s ease;
}
.account-popover-switch:hover { filter: brightness(1.06); box-shadow: 0 5px 14px rgba(200, 129, 31, 0.45); transform: translateY(-1px); }
.account-popover-switch:active { transform: translateY(0); box-shadow: 0 2px 6px rgba(200, 129, 31, 0.35); }
.account-popover-switch-icon { font-size: 0.95rem; line-height: 1; }
/* "Switch back to Admin View" — a cooler blue gradient so leaving Teacher
   View reads visually distinct from entering it. */
.account-popover-switch--admin {
  background: linear-gradient(135deg, var(--ink-light) 0%, var(--ink) 100%);
  box-shadow: 0 3px 10px rgba(27, 42, 74, 0.35);
}
.account-popover-switch--admin:hover { box-shadow: 0 5px 14px rgba(27, 42, 74, 0.45); }
.account-popover-switch--admin:active { box-shadow: 0 2px 6px rgba(27, 42, 74, 0.35); }

/* Persistent banner shown across the top of every page while an admin is
   previewing the Teacher view — a constant visual reminder they haven't
   actually left their admin session (see renderImpersonationControls()). */
.impersonation-banner {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--gold-dark);
  color: #fff;
  text-align: center;
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.45rem 0.75rem;
}
.impersonation-banner-link {
  text-decoration: underline;
  font-weight: 700;
  color: #fff;
}

/* ---- Logout confirmation modal ("Confirm Logout") ----
   Opened by the account popover's "Log out" button instead of signing out
   immediately — see ensureLogoutConfirmModal()/openLogoutConfirmModal()
   in js/utils.js. Same overlay+box convention as .pdf-progress-overlay
   above. */
.confirm-modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(27, 42, 74, 0.55);
  z-index: 10001;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.confirm-modal-overlay.open { display: flex; }
.confirm-modal-box {
  background: #fff;
  border-radius: 0.75rem;
  padding: 1.5rem;
  max-width: 22rem;
  width: 100%;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
}
.confirm-modal-title {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--ink);
  margin-bottom: 0.5rem;
}
.confirm-modal-message {
  font-size: 0.88rem;
  color: var(--muted);
  margin-bottom: 1.25rem;
}
.confirm-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
}
.btn-cancel {
  padding: 0.5rem 1rem;
  border-radius: 8px;
  border: 1.5px solid var(--border);
  background: #fff;
  color: var(--ink);
  font-size: 0.8rem;
  font-weight: 600;
}
.btn-cancel:hover { background: var(--cream, #fbf9f4); border-color: var(--gold); }

/* ---- Grade Summary card — a small, compact table (Class / Graded / NG /
   NG %) that sits inline in the page content (see admin.html, just below
   the Marks Entry Status card), not a large full-width ledger-style
   table. ---- */
.gradesum-scroll {
  max-width: 100%;
  overflow-x: auto;
}
.gradesum-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.72rem;
  background: #0F172A; /* charcoal slate — enterprise dark theme */
}
/* Full grid borders on every cell — matches the Marks Entry Status
   matrix table (.ledger) just above this card, instead of the old
   bottom-border-only rule rows used to have. */
.gradesum-table th, .gradesum-table td {
  padding: 0.35rem 0.5rem;
  text-align: center;
  border: 1px solid #1E293B;
  white-space: nowrap;
  color: #F8FAFC;
}
.gradesum-table th:first-child, .gradesum-table td:first-child {
  text-align: left;
  font-weight: 600;
  color: #F8FAFC;
  position: sticky;
  left: 0;
  background: #1E293B;
}
.gradesum-table th {
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: #94A3B8;
  font-weight: 700;
  background: #1E293B;
}
.gradesum-table th:first-child { background: #1E293B; }

/* Graded/Graded % rows banded emerald, Non Graded/NG % rows banded amber —
   each pair reads as one group at a glance instead of four look-alike
   rows. The :first-child rules win over the sticky label column's own
   background above by matching on the same (higher-specificity)
   selector, so the label cell is tinted too. */
.gradesum-table tr.gsum-row-graded td { background: rgba(16, 185, 129, 0.16); color: #34D399; font-weight: 700; }
.gradesum-table tr.gsum-row-graded td:first-child { background: rgba(16, 185, 129, 0.22); color: #34D399; }
.gradesum-table tr.gsum-row-ng td { background: rgba(245, 158, 11, 0.16); color: #FBBF24; font-weight: 700; }
.gradesum-table tr.gsum-row-ng td:first-child { background: rgba(245, 158, 11, 0.22); color: #FBBF24; }

.gradesum-table tbody tr:hover td { background: #1E293B; }
.gradesum-table tbody tr:hover td:first-child { background: #29374d; }

/* ---- Completion status matrix ---- */
.status-cell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 8px;
  font-size: 0.9rem;
  font-weight: 700;
}
.status-complete { background: rgba(63,122,92,0.15); color: var(--success); }
.status-partial { background: rgba(232,163,61,0.18); color: var(--gold-dark); }
.status-empty { background: rgba(193,68,60,0.12); color: var(--error); }
.status-na { background: transparent; color: var(--border); }

.stat-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.1rem 1.3rem;
}
.stat-card .stat-number {
  font-family: "Poppins", "Kalimati", "Noto Sans Devanagari", sans-serif;
  font-size: 1.7rem;
  font-weight: 700;
  color: var(--ink);
}
.stat-card .stat-label {
  font-size: 0.75rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* ---- Print — Mark Ledger ---- */
.print-only { display: none; }

/* These render both in the on-screen print-preview modal AND in the
   actual printed page, so they're normal (non-@media) rules. */
.print-header-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  border-bottom: 2px solid #000;
  padding-bottom: 0.15rem;
  margin-bottom: 0.2rem;
}
.print-school-name {
  font-family: "Poppins", "Kalimati", "Noto Sans Devanagari", sans-serif;
  font-weight: 700;
  font-size: 1.05rem;
  color: #000;
  line-height: 1.15;
}
.print-subtitle { font-size: 0.72rem; color: #333; line-height: 1.15; }
.print-exam-period {
  font-family: "Poppins", "Kalimati", "Noto Sans Devanagari", sans-serif;
  font-weight: 700;
  font-size: 0.88rem;
  color: #000;
  margin-top: 0.15rem;
  line-height: 1.15;
}
/* Class (left) / Subject, underlined (center) / Printed date (right) —
   one row, three even columns via flex so the center item is truly
   centered on the page no matter how wide the left/right text is. */
.print-meta-row {
  display: flex;
  align-items: baseline;
  margin-bottom: 0.2rem;
}
.print-ledger-type {
  font-family: "Poppins", "Kalimati", "Noto Sans Devanagari", sans-serif;
  font-weight: 700;
  font-size: 0.88rem;
  color: #000;
  margin-top: 0.15rem;
  line-height: 1.15;
}
.print-class-line,
.print-subject-line,
.print-date {
  flex: 1;
  margin: 0;
}
.print-class-line {
  font-weight: 700;
  font-size: 0.88rem;
  color: #000;
  text-align: left;
}
.print-subject-line {
  font-weight: 700;
  font-size: 0.88rem;
  color: #000;
  text-align: center;
}
.print-subject-line span {
  display: inline-block;
  border-bottom: 1px solid #000;
  padding: 0 0.15rem 0.1rem;
}
.print-date {
  font-size: 0.75rem;
  color: #333;
  text-align: right;
}
.print-signature-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.4rem 1.5rem;
  margin-top: 0.6rem;
  font-size: 0.78rem;
  color: #000;
}
/* Each signatory: signature mark, then their name (auto-filled from
   School Settings when saved there), then their post in parentheses — a
   standard three-line signature block instead of a single inline
   "Label: ____" row. */
.print-signature-block {
  text-align: center;
  min-width: 8rem;
}
.print-signature-block .sig-name {
  margin: 0;
  font-weight: 700;
  min-height: 1em;
}
.print-signature-block .sig-post {
  margin: 0.05rem 0 0;
  color: var(--muted);
  font-size: 0.72rem;
}

/* ---- Shared signature mark — used everywhere a person signs off on a
   printed document (Mark/Grade Ledger, Aptitude/Marks Entry, and the
   Gradesheet's Class Teacher / Prepared by / Exam Coordinator /
   Headmaster blocks). The dotted line is always drawn as the base "sign
   here" mark; when a digital signature image is on file it's layered
   over it rather than replacing it, so the printed page still shows
   where to sign by hand even with a digital signature attached. No
   image on file → dots only.

   The box is taller than the dotted line alone needs, and the dotted
   line sits partway down it (not at the very bottom) — this used to be
   a gradesheet-only override, but every signature field in the portal
   gets the same treatment now so an attached signature photo can
   render at a real, legible size and is free to cross over the dotted
   line above and below it, the way an actual pen signature does,
   instead of being squeezed flat on top of the line. */
.sig-mark {
  position: relative;
  width: 7rem;
  height: 2.1rem;
  margin: 0 auto 0.15rem;
}
.sig-mark-dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.55rem;
  border-bottom: 1px dotted #000;
}
.sig-mark-img {
  position: absolute;
  left: 50%;
  bottom: 0.1rem;
  transform: translateX(-50%);
  max-height: 1.9rem;
  max-width: 6.8rem;
  object-fit: contain;
}

/* ---- Print — LO / Breakdown Mark Ledger: grouped subject headers ----
   NOTE: table-layout:fixed/width:100% used to be forced here to squeeze
   every column onto one screen without scrolling — but on a narrow
   mobile screen that just crushes/overlaps the text instead, since the
   table can never grow past 100% to fit its content. Grade Ledger (no
   ledger-lo) doesn't have this problem: in normal table-layout:auto, a
   table's declared width is only a *preference* — the browser still lets
   it grow past that to fit its content, and .table-scroll's
   overflow-x:auto then makes that overflow horizontally scrollable
   instead of squashed. Dropping table-layout:fixed here gives the Mark
   Ledger the same scrollable behavior. */
.ledger-lo { width: 100%; }
.ledger-lo th, .ledger-lo td {
  text-align: center;
  vertical-align: middle;
}
.ledger-lo .ledger-sn-col { width: 1.5rem; }
/* No forced width/wrap here anymore — a fixed 6rem column forced most
   student names onto 2-3 lines, which is exactly the "unnecessary
   height" the Grade Ledger doesn't have (its name column just sizes
   itself to the content). Letting this column size naturally, on one
   line, matches that same look; .ledger-lo's table-layout:auto (see
   note above) lets the column grow without upsetting the other
   columns, and .table-scroll's horizontal scroll covers the rare
   very-long name. */
.ledger-lo .ledger-name-col {
  white-space: nowrap;
  font-weight: 600;
}
.ledger-lo tbody td { color: var(--ink); font-weight: 600; }
.ledger-lo thead tr:first-child th {
  white-space: normal;
  word-break: break-word;
  line-height: 1.2;
  padding: 0.3rem 0.2rem;
}
.ledger-lo thead tr:last-child th {
  font-size: 0.68rem;
  padding: 0 0.15rem;
  /* Fixed height that comfortably fits the longest rotated label
     ("Obtained Learning Achievement" / "No. Of Learning Achievement")
     at this font-size. A rotate() transform never reflows layout height
     (unlike writing-mode), so leaving this height to "whatever the
     content needs" — the old approach — let long labels visually spill
     out of a too-short cell and overlap the subject-name row above.
     .rot-wrap below fills this fixed height and centers the rotated
     label inside it, so every column's label sits fully contained
     regardless of how long its text is. */
  height: 128px;
  vertical-align: bottom;
  text-align: center;
  line-height: 1.3;
  overflow: visible;
}
/* Fills the th's fixed height and centers the (still-unrotated, from a
   layout point of view) label both ways — a plain <div>, not the th
   itself, so flex centering never fights the table layout model the way
   display:flex directly on a <th> can. Rotating .rot-label in place after
   it's already centered keeps its visual footprint centered too, so a
   short label ("Total") and a long one ("Obtained Learning Achievement")
   both sit safely inside the same fixed-height cell without touching the
   row above or below. */
.ledger-lo thead tr:last-child th .rot-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  width: 100%;
}
/* The actual bottom-to-top rotated label. Used to be writing-mode:
   vertical-rl + transform: rotate(180deg) directly on the <th> — visually
   fine on-screen, but html2canvas (the screenshot engine both the Page
   PDF and print-preview PDF export are built on) has long-standing bugs
   rendering vertical writing modes, which is what made these headers
   come out sideways/garbled/blank in an exported PDF while looking
   correct on the live page. A plain rotate transform on normal
   horizontal text is something html2canvas *does* render correctly, and
   looks identical: horizontal text rotated -90° reads bottom-to-top,
   same as the old vertical-rl+180° combo did. See loSubHeaderCells(),
   breakdownSubHeaderCells(), and buildWrittenOralLedgerTable() in
   admin-print-ledger.js, which wrap each subheader's text in this span. */
.ledger-lo thead tr:last-child th .rot-label {
  display: inline-block;
  white-space: nowrap;
  transform: rotate(-90deg);
  transform-origin: center;
}
/* S.N and Student Name stay upright even though they share the rotated
   header row structurally (rowspan across both header rows) — they never
   get a .rot-label span, so no override is needed here anymore. */
.ledger-lo thead .ledger-sn-col,
.ledger-lo thead .ledger-name-col {
  height: auto;
  vertical-align: middle;
  font-size: 0.68rem;
}

/* ---- Internal Form (Detailed) — rotated rubric-criterion headers ----
   Bottom-to-top rotated label for each individual evaluation criterion
   (Attendance, Creativity, Documentation, ...), so it reads in the same
   direction as the school's paper form while keeping columns narrow
   enough for every criterion to fit on one printed page. Applies to any
   header cell carrying .rot-th — both the leaf criterion row AND the
   rowspan-2 standalone columns (Practical & Project Total, Term Exam,
   Grand Total) that sit in the same row as the upright group headers —
   see renderDetailedTheadHtml() in js/internal-form-detailed.js.

   Uses writing-mode: vertical-rl (+ rotate(180deg) to read bottom-to-top
   instead of top-to-bottom), NOT transform: rotate() on horizontal text
   like .ledger-lo above. Two real, empirically-confirmed reasons this
   table needs the different technique despite .ledger-lo's long comment
   preferring rotate():
     1. .ledger-lo's rotate() approach relies on giving the (unrotated)
        label a fixed CSS width so wrapping keeps the rotated column
        narrow. But an element's `width` sizes it regardless of whatever
        transform is later applied to it — a fixed-width label sitting
        in NORMAL FLOW forces every one of this table's many rotated
        columns to reserve that same width in the table's auto-layout,
        which (confirmed by actually rendering it) starves the
        neighboring Roll/Student Name/Student ID columns down to almost
        nothing once enough rotated columns add up. Pulling the label
        out of flow with position:absolute avoids that — but:
     2. position:absolute inside a <th> turned out to not reliably use
        that <th> as its containing block during real Chromium print/PDF
        rendering (confirmed by actually printing it): every rotated
        label detached from its own cell and piled up in one spot near
        the middle of the page, completely different from the on-screen
        preview. This is exactly the "prints different from preview"
        failure — .ledger-lo's shorter, single-line labels never
        exercised this path, which is presumably why it wasn't caught
        there.
   writing-mode sidesteps both: it's real CSS layout (not a purely
   visual transform), so a wrapped vertical label's natural width really
   is just its wrapped-line thickness — no fixed width needed, nothing
   to pull out of flow, nothing that can detach from its cell. */
.ledger-rubric th.rot-th {
  height: 138px;
  vertical-align: bottom;
  text-align: center;
  padding: 0.1rem 0.05rem;
  overflow: hidden;
}
.ledger-rubric th.rot-th .rot-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  width: 100%;
}
.ledger-rubric th.rot-th .rot-label {
  display: inline-block;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: normal;
  overflow-wrap: anywhere;
  /* max-height, not max-width: in vertical-rl the INLINE axis (the one
     a wrap boundary applies to) runs top-to-bottom, which maps to the
     physical height property, not width — this is what bounds how far
     down a single line runs before wrapping to a new one, turning a
     long label into more (horizontally stacked) lines rather than one
     line that runs off the bottom of the column. */
  max-height: 8rem;
  text-align: center;
  font-size: 0.66rem;
  line-height: 1.15;
}
/* Group headers (सहभागिता, प्रयोगात्मक र परियोजना कार्य, ...) span
   several leaf columns via colspan — letting a long group name wrap
   (rather than the base .ledger thead th's nowrap) means it simply
   flows onto 2-3 lines within whatever total width its own leaf columns
   already add up to, instead of forcing every one of them wider just to
   fit the group name on a single line. */
.ledger-rubric th.rubric-group-th {
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.2;
}

/* Roll / Student Name / Student ID carry no rotated content and (unlike
   every rotated column) no explicit width of their own — without a
   floor, table auto-layout can squeeze them down to almost nothing once
   the rotated columns' own widths add up, especially under a print
   page's fixed width (there's no .table-scroll horizontal-scroll escape
   hatch there like there is on screen), wrapping the student's name one
   letter per line. min-width, not width, so they still grow to use any
   spare room rather than staying pinned this narrow.
   Kept tight — these three are read-only roster labels, not rubric data
   competing for space, so every rem they don't need goes to the rotated
   criterion columns instead. */
.ledger-rubric .ledger-sn-col { min-width: 2.1rem; }
.ledger-rubric .ledger-name-col { min-width: 5.5rem; }
.ledger-rubric td.font-mono-data,
.ledger-rubric th.ledger-id-col { min-width: 4.2rem; }

/* Roll/Student Name/Student ID headers (see detailedRowLabels() in
   internal-form-detailed.js) are Nepali on every subject but English,
   and run longer than their English counterparts — letting them wrap
   onto their own rowspan=3 header, instead of .ledger thead th's
   default nowrap forcing a single wide line, is what keeps the tight
   min-widths above from getting overridden by the header text itself. */
.ledger-rubric thead th.ledger-sn-col,
.ledger-rubric thead th.ledger-name-col,
.ledger-rubric thead th.ledger-id-col {
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.15;
  padding-left: 0.35rem;
  padding-right: 0.35rem;
}

/* Row 3 — the plain, upright max-mark for every leaf/standalone column
   (see renderDetailedTheadHtml()'s row3 in internal-form-detailed.js).
   Sits directly under the rotated labels, exactly like the school's
   paper form, instead of being crammed as a second line inside the
   rotated label itself. */
.ledger-rubric .ledger-maxrow th {
  font-size: 0.72rem;
  font-weight: 700;
  padding: 0.25rem 0.1rem;
  text-align: center;
  color: var(--ink);
}

/* Accent colors for the rubric's running-total columns — a group's own
   subtotal (any leaf column whose label says "जम्मा"/"Total", detected
   by content in isSubtotalLabel() since not every group ends in one),
   and the 3 fixed-role standalone columns (practical/project grand
   total, exam total, grand total — always in that order, see
   RUBRIC_TEMPLATES' header comment). Applied to both the rotated label
   and its row-3 mark so the whole column reads as one accented unit,
   matching the school's own color-coded paper form. */
/* The maxrow-cell color rules need !important: the print stylesheet
   (@media print .ledger thead th) forces color:#000 !important on every
   header cell including these, so a plain (non-!important) color here
   would be overridden and every total column would print black. The
   .rot-label rules don't need it — that span never has its own color
   set by the print rule (which targets the th, not its child), so an
   explicit child color always beats an inherited one regardless of
   !important on the parent. */
.ledger-rubric .rot-accent-subtotal .rot-label {
  color: #b45309;
}
.ledger-rubric th.ledger-maxrow-cell.rot-accent-subtotal {
  color: #b45309 !important;
}
.ledger-rubric .rot-accent-practical .rot-label {
  color: #15803d;
}
.ledger-rubric th.ledger-maxrow-cell.rot-accent-practical {
  color: #15803d !important;
}
.ledger-rubric .rot-accent-exam .rot-label {
  color: #7c3aed;
}
.ledger-rubric th.ledger-maxrow-cell.rot-accent-exam {
  color: #7c3aed !important;
}
.ledger-rubric .rot-accent-grand .rot-label {
  color: #b91c1c;
}
.ledger-rubric th.ledger-maxrow-cell.rot-accent-grand {
  color: #b91c1c !important;
  font-size: 0.8rem;
}

/* Wide ledgers (many subjects × sub-columns) print landscape and shrink
   to fit one A4 page. This USED to be done by assigning a named @page
   (`page: wideLedgerPage`) to the .wide-ledger wrapper — but putting a
   named page on an element forces Chrome to switch page "contexts" from
   the default page into the named one and back again, and Chrome pads
   both of those context switches with a genuinely blank page (blank
   page before the content, blank page after). That's what was showing
   up here. Since the print-preview modal only ever shows ONE document
   at a time (its whole innerHTML is replaced per document — see
   showPrintPreview() in utils.js), there's never actually a need for
   two page contexts to coexist in the same print job. showPrintPreview()
   now swaps the single default @page's size/margin (landscape 6mm vs
   portrait 8mm) via a small injected <style> tag instead, so the whole
   print job stays on one page context throughout and no blank padding
   pages get inserted. See setPrintPageSetup() in utils.js.             */

/* ---- Print — Gradesheet (individual student certificate) ----
   One .gradesheet-page per student — a bordered A4 portrait sheet
   modelled on the school's official gradesheet layout (see the sample
   images used to build this feature). Renders both in the on-screen
   preview and the actual print, same as the ledger rules above.

   Every font-size/padding/margin below is in em, not rem, ON PURPOSE:
   .gradesheet-page's own font-size is the single dial fitGradesheetsToOnePage()
   (utils.js) turns to make one gradesheet fill exactly one A4 page —
   shrinking it for content-heavy classes (9-10's Theory/Internal rows)
   and growing it for lighter ones (Nursery-5's shorter LO table) so the
   full page is used either way, with no second overflow page and no
   blank trailing page. Because everything here scales off that one
   font-size via em (not a fixed rem tied to the document root), the
   whole certificate — text AND spacing — grows or shrinks together as
   one unit. The em numbers look oddly precise (e.g. 1.4634em) because
   each was back-solved from the original rem-based design size so the
   default, unscaled appearance is unchanged from before this change.

   Each .gradesheet-page sits inside a .gs-page-frame wrapper (added by
   wrapGradesheetPagesForPrint() in utils.js) — the frame is what carries
   the fixed one-page height and page-break-after below. */
.gs-page-frame { margin: 0 auto 1rem; }
.gradesheet-page {
  position: relative;
  border: 2px solid #000;
  padding: 0.7927em 1.2195em;
  margin: 0 auto;
  width: 190mm; /* matches the @page gradesheetPage printable width below — fitGradesheetsToOnePage() only ever changes font-size, never width, so this stays put */
  box-sizing: border-box;
  color: #000;
  font-size: 0.82rem; /* the scalable base — overridden inline (in px) by fitGradesheetsToOnePage() */
  font-family: "Inter", "Kalimati", "Noto Sans Devanagari", system-ui, sans-serif;
  background: #fff;
  text-align: justify;
}
.gs-header { text-align: center; margin-bottom: 0.4268em; }
.gs-school-name {
  font-family: "Poppins", "Kalimati", "Noto Sans Devanagari", sans-serif;
  font-weight: 800;
  font-size: 1.4634em;
  color: #8b1a1a;
  letter-spacing: 0.02em;
  line-height: 1.2;
}
.gs-school-address {
  font-weight: 700;
  font-size: 0.9756em;
  color: #8b1a1a;
  margin-top: 0.0625em;
  line-height: 1.2;
}
/* "Grade: <label>" ribbon — a centered banner sitting just above the
   "Grade Sheet" title, folded-banner style. .gs-grade-ribbon-wrap centers
   it; the ribbon itself stays position:relative so its ::before/::after
   fold triangles below still anchor to its own box. */
.gs-grade-ribbon-wrap { text-align: center; margin-bottom: 0.3659em; }
.gs-grade-ribbon {
  position: relative;
  display: inline-block;
  background: #8b1a1a;
  color: #fff;
  font-weight: 700;
  font-size: 0.9146em;
  letter-spacing: 0.03em;
  padding: 0.2667em 1.0667em;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.gs-grade-ribbon::before, .gs-grade-ribbon::after {
  content: "";
  position: absolute;
  top: 100%;
  border-style: solid;
  border-width: 5px 5px 0 5px;
  border-color: #5c1010 transparent transparent transparent;
}
.gs-grade-ribbon::before { left: 0; }
.gs-grade-ribbon::after { right: 0; }
.gs-title {
  text-align: center;
  font-weight: 700;
  font-size: 1.1585em;
  margin: 0.3158em 0 0.4211em;
}
/* The certifying paragraph sits inside its own outline (border box)
   rather than floating free in the page — a tab-space indent opens the
   first line, like a formal certificate. */
.gs-meta-outline {
  border: 1px solid #000;
  padding: 0.4878em 0.7317em 0.4268em;
  margin: 0.122em 0 0.4878em;
}
.gs-meta-text {
  font-size: 1em;
  line-height: 1.35;
  text-align: justify;
  margin: 0;
  text-indent: 2.4em;
}
.gs-meta-text strong { font-weight: 700; }
/* Dotted "fill-in-the-blank" underline for actual data values (name,
   symbol no., roll no., school name, EMIS code, exam type, etc.) inside
   the meta paragraph — reads like a formal certificate. */
.gs-data {
  border-bottom: 1px dotted #000;
  padding: 0 0.1829em;
}
.gs-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 1em;
  margin-bottom: 0.1829em;
}
.gs-table th, .gs-table td {
  border: 1px solid #000;
  padding: 0.3659em 0.5488em;
  text-align: center;
}
.gs-table th { font-weight: 700; background: #f2f2f2; }
.gs-table td.gs-subject-col, .gs-table th.gs-subject-col { text-align: center; }
.gs-table tfoot td { font-weight: 700; }
/* Only the "Grade Point Average = X" sentence cell (the one spanning
   multiple columns) reads as a left-aligned line of text — the row's
   other two cells (the Subjects-column label and the total Credit
   Hour/Grade Point number) stay centered like every other cell in the
   table, matching the rest of the columns above them. */
.gs-table tfoot td[colspan] { text-align: left; }
.gs-footnotes { font-size: 0.8537em; margin: 0.3571em 0 0.5em; text-align: justify; line-height: 1.25; }
.gs-details-title {
  text-align: center;
  font-weight: 700;
  border: 1px solid #000;
  border-bottom: none;
  padding: 0.2308em;
  font-size: 0.9512em;
}
.gs-details-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8537em;
  margin-bottom: 0.7143em;
}
.gs-details-table th, .gs-details-table td {
  border: 1px solid #000;
  padding: 0.3143em 0.5714em;
  text-align: center;
}
.gs-details-table th { font-weight: 700; background: #f2f2f2; }
.gs-signature-row {
  display: flex;
  justify-content: space-between;
  margin-top: 0.55rem;
  font-size: 0.7rem; /* fixed (rem), not em on purpose — see note below */
}
.gs-signature-block { text-align: center; min-width: 7.5rem; font-weight: 700; }
.gs-prepared-block { align-self: flex-end; }
/* Signature mark itself (dotted line + optional image) is the shared
   .sig-mark component in the print-signature-block rules above — same
   taller box, with the dotted line partway down it, as every other
   signature field in the portal now uses (see that section for why). */
.gs-signature-name { display: block; font-weight: 700; }

/* The gradesheet's Class Teacher / Prepared by / Exam Coordinator /
   Headmaster row uses the shared .sig-mark box as-is (see "Shared
   signature mark", styles.css, print-signature-block section) — the
   taller box with the dotted line sitting partway down it, so an
   attached signature photo can render at a real, legible size and is
   free to cross over the dotted line above and below it, is now the
   one rule for every signature field in the portal, not a gradesheet-
   only override. Only the width is trimmed slightly here, to keep the
   signature comfortably inside .gs-signature-block's narrower
   min-width without widening the row. */
.gs-signature-block .sig-mark {
  width: 6.5rem;
}
.gs-signature-block .sig-mark-img {
  max-width: 6.3rem;
}

@media print {
  @page gradesheetPage { size: A4; margin: 8mm 10mm; }
  .gs-page-frame {
    page: gradesheetPage;
    break-after: page;
    page-break-after: always;
    margin: 0 !important;
  }
  .gs-page-frame:last-child { break-after: auto; page-break-after: auto; }
  .gradesheet-page {
    border: 2px solid #000 !important;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
    /* Belt-and-braces alongside fitGradesheetsToOnePage()'s sizing: even
       if a page still measured a hair too tall, this stops the browser
       from slicing the box mid-content and re-drawing its border around
       just the leftover bit (e.g. the signature row alone spilling onto
       a near-blank second sheet with its own border) — the box moves as
       one whole unit instead of fragmenting across the page break. */
    break-inside: avoid;
    page-break-inside: avoid;
  }
  .gs-school-name, .gs-school-address { color: #8b1a1a !important; }
  .gs-grade-ribbon {
    background: #8b1a1a !important;
    color: #fff !important;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .gs-table th, .gs-details-table th { background: #f2f2f2 !important; }
}

/* ---- Save PDF — shared off-screen render holder ----
   Used by both admin-gradesheet.js (per-student canvas capture, then
   composited into the PDF with jsPDF) and any future html2canvas-based
   export. Pinned at the real viewport origin (not pushed thousands of
   pixels off-screen) and hidden purely with a negative z-index — never
   opacity/visibility, since html2canvas can render those as a blank
   capture. Content inside renders at its normal, untransformed size;
   any shrinking to fit multiple gradesheets per page happens afterward,
   on the already-rendered image, not via CSS transform. */
.pdf-export-holder {
  position: fixed;
  top: 0;
  left: 0;
  z-index: -9999;
  pointer-events: none;
}

/* ---- Save PDF — progress overlay ----
   Shown for the whole render (admin-gradesheet.js's Save PDF buttons and
   the shared "📄 Page PDF" button in utils.js/showPrintPreview) so a
   multi-second render never looks like an unresponsive click. */
.pdf-progress-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(27, 42, 74, 0.55);
  z-index: 10000;
  align-items: center;
  justify-content: center;
}
.pdf-progress-overlay.open { display: flex; }
.pdf-progress-box {
  background: #fff;
  border-radius: 0.75rem;
  padding: 1.5rem 2rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  min-width: 14rem;
}
.pdf-progress-spinner {
  width: 2rem;
  height: 2rem;
  border: 3px solid var(--border, #ddd);
  border-top-color: var(--gold, #E8A33D);
  border-radius: 50%;
  animation: pdfSpin 0.8s linear infinite;
}
.pdf-progress-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink, #1B2A4A);
  text-align: center;
}
@keyframes pdfSpin { to { transform: rotate(360deg); } }

/* ---- Print preview modal — shows print content on-screen first ---- */
.print-preview-modal {
  display: none;
  position: fixed;
  inset: 0;
  background: #fff;
  z-index: 9999;
  overflow-y: auto;
}
.print-preview-modal.open { display: block; }
.print-preview-toolbar {
  position: sticky;
  top: 0;
  background: #fff;
  border-bottom: 1px solid var(--border);
  padding: 0.75rem 1rem;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
  z-index: 1;
}
/* The in-modal class switcher (Print Ledger page) sits on the left,
   Close/Print stay pinned right — lets a person flip between classes
   without closing the preview and reopening it. */
.print-preview-toolbar .ppm-switcher {
  margin-right: auto;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.print-preview-toolbar .ppm-switcher select {
  max-width: 9rem;
}
.print-preview-body {
  /* Fills the whole modal width instead of a narrow centered column —
     a fixed max-width here left large white gutters on either side of
     the sheet, which made the preview read as a small embedded frame
     floating in the middle of the screen instead of a true full-page
     print preview. The generous side padding keeps long lines from
     running edge-to-edge on very wide monitors. */
  padding: 1.25rem clamp(1rem, 4vw, 3rem) 3rem;
  max-width: 100%;
  width: 100%;
  margin: 0;
  color: #000;
  font-family: "Inter", "Kalimati", "Noto Sans Devanagari", system-ui, sans-serif;
}
.print-preview-body .ledger { width: 100%; font-size: 0.8rem; }
.print-preview-body .ledger td {
  border: 1px solid #ccc;
}
.print-preview-body .ledger thead th {
  background: #e9e9e9;
  color: #000;
  border: 1px solid #999;
}
.print-preview-body .ledger tbody tr:nth-child(even) { background: #f7f7f7; }
.print-preview-body.wide-ledger { max-width: 100%; padding-left: 1rem; padding-right: 1rem; overflow-x: auto; }

/* Subject-group divider — marks the FIRST sub-column of every subject
   (group header, sub-header, and every data row) with a heavier left
   border, so each subject's block of sub-columns reads as one visual
   group instead of every column blurring into the next. Was applied as
   a class in the markup (loSubHeaderCells(), breakdownSubHeaderCells(),
   buildWrittenOralLedgerTable(), and their matching data-row builders in
   admin-print-ledger.js) but never actually had a rule. */
.ledger .subj-div {
  border-left: 2px solid #9ca3ab;
}
.print-preview-body .ledger thead .subj-div,
.ledger thead .subj-div {
  border-left: 2px solid var(--gold-dark);
}

/* Classes 6-10 (Breakdown A/B ledgers) have the most columns of any
   ledger — up to 7 subjects × 5 sub-columns each — so the standard
   ledger-lo sizing is too large and the header/data text overlaps.
   Shrink further specifically for these, both in the on-screen print
   preview and the actual printed page. */
.print-preview-body .ledger-breakdown { font-size: 0.62rem; }
.print-preview-body .ledger-breakdown th,
.print-preview-body .ledger-breakdown td { padding: 0.2rem; }
.print-preview-body .ledger-breakdown thead tr:last-child th { font-size: 0.6rem; height: 112px; }

/* Single-subject mark sheet print (marks-entry.html) — center every
   column so the printed page reads clean and even, not just the
   grouped ledgers. Scoped to the print table only; the live editable
   ledger on-screen keeps its normal left-aligned layout. */
.ledger-print th,
.ledger-print td {
  text-align: center;
}
.ledger-print tbody td { color: var(--ink); font-weight: 600; }

/* Header colour now matches the Grade Ledger exactly — both just use
   the base .ledger thead th styling (single dark-ink tone on screen,
   plain light gray when printed). The old two-tone treatment (dark
   first row / light-blue second row, here and in the print block
   below) was the one difference between how the two ledgers looked. */
.ledger-lo tbody tr:nth-child(even) td { background: #f7f9fc; }

@media print {
  @page { margin: 8mm 8mm; }

  body { background: #fff !important; }
  .no-print { display: none !important; }
  .print-only { display: block !important; }
  /* The "Viewing as Teacher" admin-impersonation ribbon (see
     renderImpersonationControls() in utils.js) is a persistent on-screen
     reminder, not part of any printed document — it was never tagged
     .no-print, so it was bleeding into every print/PDF output (including
     both Print Internal Form sheets) whenever an admin previewed the
     Teacher view. */
  .impersonation-banner { display: none !important; }

  main { max-width: 100% !important; padding: 0 !important; margin: 0 !important; }

  /* When actually printing, only the open preview modal's body should
     appear — everything else on the page (including the modal's own
     toolbar) is hidden via .no-print. */
  .print-preview-modal { position: static !important; overflow: visible !important; }
  .print-preview-body { max-width: 100% !important; padding: 0 !important; }
  /* .print-preview-body.wide-ledger carries overflow-x:auto (see the
     base rule, styles.css) so a wide Mark/Grade Ledger can be scrolled
     sideways on-screen — but that same rule was never reset for actual
     printing, so hitting Print (or Ctrl+P) clipped the table to
     whatever fit in the on-screen scroll viewport, baked the scrollbar
     itself into the output, and cut off everything past the visible
     edge. Printing (unlike a browser tab) has no scroll position, so
     the full, untruncated table must render at its natural width here —
     the wideLedgerPage landscape @page + the .wide-ledger font-size
     shrinking already in this file is what keeps that natural width
     within one A4 landscape sheet. */
  .print-preview-body.wide-ledger {
    overflow: visible !important;
    padding: 0 !important;
  }

  .table-scroll { overflow: visible !important; }
  .ledger {
    width: 100%;
    font-size: 0.72rem;
  }
  .ledger thead th {
    position: static !important;
    background: #e9e9e9 !important;
    color: #000 !important;
    border: 1px solid #999 !important;
    padding: 0.2rem 0.3rem !important;
    white-space: normal !important;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .ledger tbody tr { break-inside: avoid; }
  .ledger tbody tr:nth-child(even) { background: #f7f7f7 !important; }
  .ledger td {
    border: 1px solid #ccc !important;
    padding: 0.16rem 0.25rem !important;
  }
  .ledger .subj-div {
    border-left: 2px solid #888 !important;
  }

  /* Marks/inputs render as plain values, not editable-looking boxes */
  .ledger input, .save-bar input {
    border: none !important;
    background: transparent !important;
    -webkit-appearance: none;
    appearance: none;
    padding: 0.08rem !important;
    font-weight: 600;
    color: #000 !important;
  }

  /* Signature footer must never split onto — or land entirely on — a
     second page by itself: keep it as one block and let the browser's
     page-fit decide, rather than the table's own break spilling one
     extra row's worth of height past the footer. Paired with the
     tighter header/table/footer spacing above, this is what keeps a
     normal-size class on a single printed page. */
  .print-signature-row, .gs-signature-row {
    break-inside: avoid;
    page-break-inside: avoid;
  }

  /* Every wide grouped ledger (LO / Breakdown A-B / Written-Oral / Grade
     Ledger / Internal Form Detailed's rubric) MUST land at exactly 100% of
     the printable page width — never more (clipped past the page edge,
     silently, since print has no horizontal scroll) and never less
     (whitespace down the right side instead of a full-bleed printout).
     table-layout:auto (the default, kept for the on-screen preview so
     .table-scroll can scroll sideways without squashing text — see the
     note by .ledger-lo above) only ever treats a declared width as a
     *preference*; the browser still lets the table grow past it to fit
     content — worse, any column with no declared width at all (just a
     min-width) is treated as fully flexible and absorbs 100% of whatever
     page width the other columns don't use, which is exactly what used to
     blow the Roll/Student Name/Student ID columns in the rubric table out
     into huge blank gaps. table-layout:fixed makes width 100% a hard rule
     instead, with EVERY column's share coming only from the <colgroup>
     the JS now emits — never from any cell's own width — so a column
     with no <col> entry can no longer silently claim the leftovers.
     See ledgerColgroupHtml() in admin-print-ledger.js for LO/Breakdown/
     Written-Oral/Grade Ledger, and renderDetailedColgroupHtml() in
     internal-form-detailed.js for the rubric table; changing a column's
     print share now only happens at those call sites. */
  .wide-ledger .ledger-lo,
  .wide-ledger .ledger-breakdown,
  .wide-ledger .ledger-rubric {
    table-layout: fixed !important;
    width: 100% !important;
  }

  /* Wide grouped ledgers (LO / Breakdown A / Breakdown B): compact
     everything so the full subject×sub-column grid fits one landscape
     A4 page. Header colour is intentionally left alone here now — it
     just inherits the plain light-gray .ledger thead th print style
     that the Grade Ledger also uses, instead of a separate dark/light
     two-tone treatment. */
  .wide-ledger .ledger-lo {
    font-size: 0.62rem;
  }
  .wide-ledger .ledger-lo td,
  .wide-ledger .ledger-lo thead tr:first-child th {
    padding: 0.18rem 0.1rem !important;
    border: 1px solid #bbb !important;
  }
  /* Fixed height (see the matching on-screen rule for why "let it size
     itself" doesn't work with a rotate() transform) — comfortably fits
     the longest rotated label at this print font-size without spilling
     into the subject-name row above. */
  .wide-ledger .ledger-lo thead tr:last-child th {
    padding: 0.35rem 0.25rem !important;
    border: 1px solid #bbb !important;
    font-size: 0.68rem !important;
    height: 118px !important;
  }
  .ledger-lo tbody td {
    color: var(--ink) !important;
  }
  .ledger-lo tbody tr:nth-child(even) td {
    background: #f7f9fc !important;
  }

  /* Classes 6-10 (Breakdown A/B): the widest ledgers on the page (up to
     7 subjects × 5 sub-columns = 35+ data columns). The general
     .wide-ledger .ledger-lo sizing above still overlaps at that width,
     so shrink text and padding further just for these. */
  .wide-ledger .ledger-breakdown {
    font-size: 0.52rem;
  }
  .wide-ledger .ledger-breakdown td,
  .wide-ledger .ledger-breakdown thead tr:first-child th {
    padding: 0.12rem 0.06rem !important;
  }
  .wide-ledger .ledger-breakdown thead tr:last-child th {
    font-size: 0.58rem !important;
    padding: 0.25rem 0.15rem !important;
    height: 98px !important;
  }
  /* Student ID cell (Grade Ledger only) carries Tailwind's .text-xs
     (0.75rem) for on-screen legibility — nearly double the Grade Ledger's
     compressed 0.52rem print size, and wide enough on its own to spill
     into the next column since a long numeric ID has no natural break
     point for word-wrap. Force it down to match the surrounding print
     size (the colgroup above already gives this column extra width on
     top of that), and add break-all purely as a safety net so an
     ID longer than expected wraps onto a second line instead of
     overlapping — it should never actually need to at this size. */
  .wide-ledger .ledger-breakdown td.font-mono-data {
    font-size: 0.5rem !important;
    line-height: 1.15 !important;
    letter-spacing: -0.01em;
    white-space: normal !important;
    word-break: break-all;
  }

  /* Internal Form (Detailed): one subject's full rubric only (not a
     multi-subject grid like Breakdown A/B above), but Nepali criterion
     names run long — compact print sizing so every rotated column still
     fits one landscape page, same idea as .ledger-lo/.ledger-breakdown
     above. */
  .wide-ledger .ledger-rubric {
    font-size: 0.62rem;
  }
  .wide-ledger .ledger-rubric td,
  .wide-ledger .ledger-rubric thead tr:first-child th {
    padding: 0.15rem 0.1rem !important;
  }
  /* Height only — NOT width/min-width here. Each column's width is set
     inline per-label by rotColumnWidthRem() in internal-form-detailed.js
     (narrow for a short criterion name, wider for a long one); a blanket
     width override here would force every column back to the same size
     and reintroduce the overflow this was built to avoid. */
  .wide-ledger .ledger-rubric th.rot-th {
    height: 112px !important;
  }
  /* Targets the label span directly, not just the th — the span carries
     its own explicit font-size and max-height (see the base
     .ledger-rubric th.rot-th .rot-label rule), neither of which the
     th's own font-size/height alone would override. The shorter
     max-height keeps the rotated label's wrap point under the shorter
     112px print row above (max-height, not max-width, for the same
     vertical-rl axis-mapping reason as the base rule — see its
     comment). */
  .wide-ledger .ledger-rubric th.rot-th .rot-label {
    max-height: 6.6rem !important;
    font-size: 0.58rem !important;
  }
  .wide-ledger .ledger-rubric .ledger-maxrow th {
    font-size: 0.66rem !important;
    padding: 0.18rem 0.08rem !important;
  }
  .wide-ledger .ledger-rubric th.ledger-maxrow-cell.rot-accent-grand {
    font-size: 0.74rem !important;
  }
  .wide-ledger .ledger-rubric td.font-mono-data {
    font-size: 0.52rem !important;
    word-break: break-all;
  }


  /* Long student names still need somewhere to go now that every column's
     print width is fixed by the <colgroup> rather than by content —
     without this they'd overflow their cell sideways instead of wrapping
     to a second line, since fixed-layout cells no longer grow to fit
     unbroken text (that's the on-screen ledger-lo behaviour, deliberately
     kept only there — see the note above). */
  .wide-ledger .ledger-name-col {
    white-space: normal !important;
    word-break: break-word;
    overflow-wrap: break-word;
  }
  /* Roll/Student ID headers get the same print wrap treatment as
     Student Name above — needed here specifically because their Nepali
     labels (रोल नं. / विद्यार्थीको इमिज आइडी) are longer than the
     plain "Roll"/"Student ID" this used to say. */
  .wide-ledger .ledger-rubric thead th.ledger-sn-col,
  .wide-ledger .ledger-rubric thead th.ledger-id-col {
    white-space: normal !important;
    overflow-wrap: anywhere;
  }
}

/* ---- Toasts ---- */
.toast {
  position: fixed;
  left: 50%;
  bottom: 5.5rem;
  transform: translate(-50%, 12px);
  padding: 0.65rem 1.1rem;
  border-radius: 10px;
  font-size: 0.9rem;
  font-weight: 600;
  color: #fff;
  opacity: 0;
  transition: opacity 0.25s ease, transform 0.25s ease;
  z-index: 50;
  box-shadow: 0 6px 18px rgba(0,0,0,0.18);
}
.toast-success { background: var(--success); }
.toast-error { background: var(--error); }
.toast-show { opacity: 1; transform: translate(-50%, 0); }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ---- Login page background flourish ---- */
.login-bg {
  background:
    radial-gradient(circle at 15% 10%, rgba(232,163,61,0.12), transparent 40%),
    radial-gradient(circle at 85% 90%, rgba(27,42,74,0.10), transparent 45%),
    var(--cream);
}
