:root {
  --primary: #2f5da3;
  --primary-dark: #234a82;
  --bg: #f4f6f9;
  --card-bg: #ffffff;
  --border: #dfe3e8;
  --text: #232a34;
  --text-muted: #6b7684;
  --success: #2e9e5b;
  --danger: #d64545;
  --warning: #a3781f;
  --radius: 8px;
  --input-bg: #ffffff;
  --table-header-bg: #f8f9fb;
  --row-hover-bg: #fafbfd;
  --sidebar-bg: #ffffff;
  --shadow: 0 12px 40px rgba(0,0,0,0.25);
  /* Chart identity colors (dashboard only) - kept distinct from
     --success/--warning/--danger above, which are reserved for STATUS
     (paid/pending/unpaid, approved/rejected, etc.) so a chart never lets
     an identity color (e.g. "which class") get mistaken for a status. */
  --chart-aqua: #1baf7a;
  --chart-violet: #4a3aa7;
  --chart-magenta: #e87ba4;
  /* R,G,B triplets (no #, no rgb()) of the identity colors above - lets
     rgba(var(--x-rgb), alpha) build a translucent tint of a variable
     color, which plain hex custom properties can't do on their own. Used
     by the admin sidebar's grouped-menu tint (see .sidebar a.nav-* below). */
  --primary-rgb: 47,93,163;
  --primary-dark-rgb: 35,74,130;
  --warning-rgb: 163,120,31;
  --chart-aqua-rgb: 27,175,122;
  --chart-violet-rgb: 74,58,167;
  --chart-magenta-rgb: 232,123,164;
}

/* ---------------------------------------------------------------------
   Dark mode - toggled by adding data-theme="dark" to <html> (see
   includes/header.php / login.php + the themeToggle handler in
   assets/js/app.js). Overriding the CSS variables above is enough to
   re-skin nearly everything; a handful of components below still had
   hardcoded pastel colors (badges, alerts, attendance dots) that need
   their own dark-mode overrides since they were never wired to variables.
   ------------------------------------------------------------------- */
[data-theme="dark"] {
  --primary: #4d7fd1;
  --primary-dark: #6a97e0;
  --bg: #171b23;
  --card-bg: #232833;
  --border: #333c4a;
  --text: #e7ebf1;
  --text-muted: #a2acbb;
  --success: #46c07f;
  --danger: #e2685f;
  --warning: #e0bb63;
  --chart-aqua: #199e70;
  --chart-violet: #9085e9;
  --chart-magenta: #d55181;
  --primary-rgb: 77,127,209;
  --primary-dark-rgb: 106,151,224;
  --warning-rgb: 224,187,99;
  --chart-aqua-rgb: 25,158,112;
  --chart-violet-rgb: 144,133,233;
  --chart-magenta-rgb: 213,81,129;
  --input-bg: #1c212b;
  --table-header-bg: #1c212b;
  --row-hover-bg: #262c38;
  --sidebar-bg: #1c212b;
  --shadow: 0 12px 40px rgba(0,0,0,0.6);
}
[data-theme="dark"] body { background: var(--bg); color: var(--text); }
[data-theme="dark"] table { background: var(--card-bg); color: var(--text); }
[data-theme="dark"] .badge-admin { background: rgba(122,62,214,0.22); color: #b592f2; }
[data-theme="dark"] .badge-teacher,
[data-theme="dark"] .badge-success { background: rgba(70,192,127,0.18); color: #6fdb9f; }
[data-theme="dark"] .badge-danger { background: rgba(226,104,95,0.2); color: #f0968e; }
[data-theme="dark"] .badge-warning { background: rgba(197,152,45,0.22); color: #e0bb63; }
[data-theme="dark"] .badge-neutral { background: rgba(255,255,255,0.08); color: var(--text-muted); }
[data-theme="dark"] .badge-student { background: rgba(77,127,209,0.2); color: #9dbdec; }
[data-theme="dark"] .alert-success { background: rgba(70,192,127,0.15); border-color: rgba(70,192,127,0.35); }
[data-theme="dark"] .alert-danger { background: rgba(226,104,95,0.15); border-color: rgba(226,104,95,0.35); }
[data-theme="dark"] .alert-info { background: rgba(77,127,209,0.18); border-color: rgba(77,127,209,0.4); }
[data-theme="dark"] .notice-item { background: var(--row-hover-bg); }
[data-theme="dark"] .notice-badge { background: rgba(77,127,209,0.2); color: #9dbdec; }
[data-theme="dark"] .att-present { background: rgba(70,192,127,0.18); color: #6fdb9f; }
[data-theme="dark"] .att-absent { background: rgba(226,104,95,0.2); color: #f0968e; }
[data-theme="dark"] .att-leave { background: rgba(197,152,45,0.22); color: #e0bb63; }
[data-theme="dark"] .att-none { background: rgba(255,255,255,0.08); color: var(--text-muted); }
[data-theme="dark"] .login-wrapper { background: linear-gradient(135deg, #1c2c4a, #0e1626); }
[data-theme="dark"] ::placeholder { color: var(--text-muted); opacity: 0.7; }

* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
}

.topbar {
  background: var(--primary);
  color: #fff;
  display: flex;
  align-items: center;
  padding: 12px 24px;
  gap: 12px;
  /* Stays put at the top of the viewport while the page scrolls. Sticky
     (not fixed) so it still occupies its normal spot in the document flow
     - no compensating top-padding needed anywhere else. */
  position: sticky;
  top: 0;
  z-index: 30;
}
.topbar-brand { font-weight: 700; font-size: 1.15rem; margin-right: auto; display: flex; align-items: center; gap: 10px; }
.brand-logo { width: 30px; height: 30px; flex-shrink: 0; display: block; }
.topbar-nav { display: flex; align-items: center; gap: 14px; }
.user-badge { font-size: 0.9rem; opacity: 0.95; }

/* Theme toggle + language switcher, shown in the topbar (all roles) and
   in their own small bar on the login page (see .login-top-controls). */
.topbar-controls { display: flex; align-items: center; gap: 8px; }
.icon-btn {
  background: transparent;
  border: 1px solid rgba(255,255,255,0.5);
  color: #fff;
  border-radius: 6px;
  font-size: 1rem;
  line-height: 1;
  padding: 7px 9px;
  cursor: pointer;
}
.icon-btn:hover { background: rgba(255,255,255,0.15); }
.lang-switch {
  width: auto;
  padding: 6px 8px;
  font-size: 0.85rem;
  border: 1px solid rgba(255,255,255,0.5);
  border-radius: 6px;
  background: rgba(255,255,255,0.12);
  color: #fff;
}
.lang-switch option { color: #232a34; }

.login-top-controls {
  position: absolute;
  top: 16px;
  right: 20px;
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 5;
}
.login-top-controls .icon-btn,
.login-top-controls .lang-switch {
  border-color: rgba(255,255,255,0.6);
}

@media (max-width: 480px) {
  .lang-switch { padding: 5px 4px; font-size: 0.78rem; }
  .icon-btn { padding: 5px 7px; }
}

/* Hamburger button - only shown on mobile (see media query below) */
.menu-toggle {
  display: none;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.5);
  color: #fff;
  border-radius: 6px;
  font-size: 1.1rem;
  line-height: 1;
  padding: 7px 11px;
  cursor: pointer;
}

.layout { display: flex; min-height: calc(100vh - 54px); position: relative; }

.sidebar {
  width: 210px;
  flex-shrink: 0;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  padding: 18px 0;
  display: flex;
  flex-direction: column;
  /* Stays in view alongside the content while a long page scrolls, right
     below the sticky topbar (54px - the topbar's own height, also assumed
     by .layout's min-height below). Sticky rather than fixed so it keeps
     stretching to the page's full height (and its own background/border
     keep spanning that height) - it just stops scrolling with the page
     once its top edge reaches the topbar. */
  position: sticky;
  top: 54px;
  align-self: flex-start;
  max-height: calc(100vh - 54px);
  overflow-y: auto;
  z-index: 15;
}
.sidebar a {
  padding: 11px 22px;
  border-left: 3px solid transparent;
  color: var(--text);
  text-decoration: none;
  font-size: 0.95rem;
}
.sidebar a:hover { background: var(--bg); color: var(--primary); }
.sidebar a.active {
  background: var(--bg);
  border-left-color: var(--primary);
  color: var(--primary);
  font-weight: 600;
}

/* Admin sidebar menu grouping (includes/header.php) - related links
   (e.g. Fee Structure/Fees/Fees Report) get a small uppercase section
   label above them and a left-border tint in that group's identity color,
   so the menu itself communicates "these belong together" instead of
   reading as one long flat list. Each section label's colored dot and
   each link's border use the SAME --primary/--chart-*/--warning/
   --primary-dark variables the dashboard charts already use, so the menu,
   the charts, and dark mode all stay visually consistent for free. The
   subtle default tint (via the *-rgb triplets above) becomes a solid,
   full-color border on hover/active so the current section is still
   obvious at a glance. */
.sidebar-group-label {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 14px 22px 4px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.sidebar-group-label::before { content: ''; width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.sidebar-group-academic::before  { background: var(--primary); }
.sidebar-group-reports::before   { background: var(--chart-violet); }
.sidebar-group-fees::before      { background: var(--chart-aqua); }
.sidebar-group-transport::before { background: var(--chart-magenta); }
.sidebar-group-leave::before     { background: var(--warning); }
.sidebar-group-admin::before     { background: var(--primary-dark); }

.sidebar a.nav-academic  { border-left-color: rgba(var(--primary-rgb), 0.35); }
.sidebar a.nav-reports   { border-left-color: rgba(var(--chart-violet-rgb), 0.35); }
.sidebar a.nav-fees      { border-left-color: rgba(var(--chart-aqua-rgb), 0.35); }
.sidebar a.nav-transport { border-left-color: rgba(var(--chart-magenta-rgb), 0.35); }
.sidebar a.nav-leave     { border-left-color: rgba(var(--warning-rgb), 0.35); }
.sidebar a.nav-admin     { border-left-color: rgba(var(--primary-dark-rgb), 0.35); }

.sidebar a.nav-academic:hover,  .sidebar a.nav-academic.active  { border-left-color: var(--primary); color: var(--primary); }
.sidebar a.nav-reports:hover,   .sidebar a.nav-reports.active   { border-left-color: var(--chart-violet); color: var(--chart-violet); }
.sidebar a.nav-fees:hover,      .sidebar a.nav-fees.active      { border-left-color: var(--chart-aqua); color: var(--chart-aqua); }
.sidebar a.nav-transport:hover, .sidebar a.nav-transport.active { border-left-color: var(--chart-magenta); color: var(--chart-magenta); }
.sidebar a.nav-leave:hover,     .sidebar a.nav-leave.active     { border-left-color: var(--warning); color: var(--warning); }
.sidebar a.nav-admin:hover,     .sidebar a.nav-admin.active     { border-left-color: var(--primary-dark); color: var(--primary-dark); }

.content { flex: 1; padding: 26px 32px; min-width: 0; }

/* ---------------------------------------------------------------------
   Mobile layout (phones/tablets)
   ------------------------------------------------------------------- */
@media (max-width: 860px) {
  .menu-toggle { display: inline-block; }
  .topbar-brand { font-size: 1rem; }
  .user-badge { display: none; } /* saves space on narrow screens; most pages already greet the user by name */

  .layout { display: block; }

  .sidebar {
    display: none; /* toggled open via JS (adds .sidebar-open on .layout) */
    width: 100%;
    border-right: none;
    border-bottom: 1px solid var(--border);
    padding: 8px 0;
    position: relative;
    z-index: 20;
  }
  .layout.sidebar-open .sidebar {
    display: flex;
  }
  .sidebar a { padding: 13px 20px; border-bottom: 1px solid var(--bg); }

  .content { padding: 16px; }
}

@media (max-width: 480px) {
  .topbar { padding: 10px 14px; }
  .topbar-brand { white-space: nowrap; }
  .brand-text { display: none; } /* keep the topbar on one line; the logo mark alone is enough branding here */
  .brand-logo { width: 26px; height: 26px; }
  .content { padding: 12px; }
  .card { padding: 14px 16px; }
}

h1, h2, h3 { color: var(--text); }
h1 { font-size: 1.5rem; margin-top: 0; }

.card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 24px;
  margin-bottom: 20px;
}

.stat-grid { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 24px; }
.stat-card {
  flex: 1; min-width: 160px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
}
.stat-card .num { font-size: 2rem; font-weight: 700; color: var(--primary); }
.stat-card .label { color: var(--text-muted); font-size: 0.9rem; }

/* Dashboard chart grid: two columns on wide screens, one on narrow -
   each .chart-card holds a title, a fixed-height canvas wrapper (Chart.js
   needs a sized parent to avoid runaway resize loops), and an optional
   note/legend line below. */
.dashboard-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
.chart-card h3 { margin-top: 0; }
.chart-canvas-wrap { position: relative; height: 260px; }
.chart-canvas-wrap.chart-canvas-wrap-sm { height: 200px; }
.chart-empty { color: var(--text-muted); text-align: center; padding: 40px 0; }

/* Meter: a same-ramp progress track for a single ratio against a limit
   (e.g. "how many students have a transport assignment") - deliberately
   not a 2-slice donut, see includes/dashboard.php callers. */
.meter-row { margin-bottom: 16px; }
.meter-row:last-child { margin-bottom: 0; }
.meter-label { display: flex; justify-content: space-between; font-size: 0.9rem; margin-bottom: 6px; }
.meter-label .meter-name { color: var(--text); font-weight: 600; }
.meter-label .meter-value { color: var(--text-muted); }
.meter-track { background: var(--border); border-radius: 999px; height: 10px; overflow: hidden; }
.meter-fill { background: var(--primary); height: 100%; border-radius: 999px; }

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

table { width: 100%; border-collapse: collapse; background: var(--card-bg); }
table th, table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  font-size: 0.92rem;
  color: var(--text);
}
table th { background: var(--table-header-bg); color: var(--text-muted); font-weight: 600; }
table tr:hover { background: var(--row-hover-bg); }

/* Wide/grid-shaped tables (timetables, anything with many columns that
   genuinely need to stay a grid): scroll horizontally instead of squeezing
   or reflowing, with momentum scrolling on iOS. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0 -1px; /* let the border touch the scroll edges cleanly */
}
.table-scroll table { min-width: 560px; }

/* Key/value tables (e.g. a profile detail table with <th> row-labels
   instead of a header row) - shrink the label column on small screens
   so values have more room to wrap. */
.kv-table th { width: 200px; }
@media (max-width: 480px) {
  .kv-table th { width: 40%; }
}

/* Listing tables: collapse into stacked "cards" on narrow screens instead
   of squeezing columns or forcing horizontal scroll. assets/js/app.js reads
   each <thead th> once on load and stamps the matching data-label onto every
   <tbody td> automatically, so no per-row markup is needed for this to work. */
@media (max-width: 720px) {
  table.table-stack thead { display: none; }
  table.table-stack, table.table-stack tbody, table.table-stack tr, table.table-stack td {
    display: block;
    width: 100%;
  }
  table.table-stack tr {
    margin-bottom: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 4px 12px;
  }
  table.table-stack tr:last-child { margin-bottom: 0; }
  table.table-stack td {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 4px 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--bg);
    text-align: right;
  }
  table.table-stack td:last-child { border-bottom: none; }
  table.table-stack td::before {
    content: attr(data-label);
    font-weight: 600;
    color: var(--text-muted);
    text-align: left;
    margin-right: auto;
  }
  /* A row with no columns (e.g. "No students found." placeholder rows) shouldn't
     get card chrome or try to show a label. */
  table.table-stack td[colspan] {
    display: block;
    text-align: left;
    border: none;
  }
  table.table-stack td[colspan]::before { content: none; }
}

form.form-box { max-width: 560px; }
.form-row { margin-bottom: 14px; }
label { display: block; margin-bottom: 5px; font-size: 0.88rem; font-weight: 600; color: var(--text-muted); }
input[type=text], input[type=password], input[type=email], input[type=date],
input[type=tel], input[type=file], select, textarea {
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.94rem;
  background: var(--input-bg);
  color: var(--text);
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--primary); }

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

/* Pager for any report/list table (Fees/Attendance/Marks Report, ...) -
   "Showing X-Y of Z" summary + Prev/page-numbers/Next controls. Shared
   across pages so a future report page gets a consistent look for free. */
.report-pager { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-top: 16px; }
.report-pager-controls { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.report-pager-ellipsis { color: var(--text-muted); padding: 0 4px; }

.checkbox-list {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 10px 12px;
  max-height: 220px;
  overflow-y: auto;
  background: var(--input-bg);
}
.checkbox-list-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.92rem;
  font-weight: normal;
  color: var(--text);
  margin: 0 0 8px 0;
}
.checkbox-list-item:last-child { margin-bottom: 0; }
.checkbox-list-item input[type=checkbox] { width: auto; }

.btn {
  display: inline-block;
  padding: 9px 18px;
  border-radius: 6px;
  border: none;
  background: var(--primary);
  color: #fff;
  cursor: pointer;
  font-size: 0.92rem;
  text-decoration: none;
}
.btn:hover { background: var(--primary-dark); }
.btn-sm { padding: 5px 11px; font-size: 0.82rem; }
.btn-outline { background: transparent; border: 1px solid #fff; }
.btn-outline:hover { background: rgba(255,255,255,0.15); }
.btn-danger { background: var(--danger); }
.btn-danger:hover { background: #b53838; }
.btn-secondary { background: #6b7684; }

@media (max-width: 640px) {
  form.form-box { max-width: 100%; }
  .form-grid { grid-template-columns: 1fr; }
  .actions-row { flex-wrap: wrap; }

  /* Keep inputs at 16px+ on mobile so iOS Safari doesn't auto-zoom on focus. */
  input[type=text], input[type=password], input[type=email], input[type=date],
  input[type=tel], input[type=number], input[type=file], select, textarea {
    font-size: 16px;
  }

  /* Comfortably tappable buttons/links. */
  .btn { padding: 10px 16px; min-height: 40px; }
  .btn-sm { min-height: 34px; display: inline-flex; align-items: center; }
}

.alert { padding: 12px 16px; border-radius: 6px; margin-bottom: 16px; font-size: 0.92rem; }
.alert-success { background: #e5f6ec; color: var(--success); border: 1px solid #bfe6cc; }
.alert-danger { background: #fdeaea; color: var(--danger); border: 1px solid #f6c6c6; }
.alert-info { background: #eaf1fb; color: var(--primary); border: 1px solid #cfe0f6; }

.login-wrapper {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #2f5da3, #1c3a66);
}
.login-card {
  background: var(--card-bg);
  padding: 36px 34px;
  border-radius: 12px;
  width: 100%;
  max-width: 380px;
  box-shadow: var(--shadow);
}
.login-logo { width: 56px; height: 56px; display: block; margin: 0 auto 12px; }
.login-card h1 { text-align: center; font-size: 1.3rem; margin-bottom: 4px; }
.login-card p.sub { text-align: center; color: var(--text-muted); margin-top: 0; margin-bottom: 22px; font-size: 0.88rem; }
.login-card .btn { width: 100%; padding: 11px; font-size: 1rem; margin-top: 6px; }

@media (max-width: 480px) {
  .login-wrapper { padding: 16px; }
  .login-card { padding: 26px 22px; }
  .login-card input[type=text], .login-card input[type=password] { font-size: 16px; }
}

.badge { padding: 3px 9px; border-radius: 20px; font-size: 0.78rem; font-weight: 600; }
.badge-admin { background: #f0e6fb; color: #7a3ed6; }
.badge-teacher { background: #e5f6ec; color: var(--success); }
.badge-student { background: #eaf1fb; color: var(--primary); }
/* Status badges - kept as classes (not inline styles) so dark mode can
   override their colors; used for account status, attendance status, etc. */
.badge-success { background: #e5f6ec; color: var(--success); }
.badge-danger  { background: #fdeaea; color: var(--danger); }
.badge-warning { background: #fff6e0; color: #a3781f; }
.badge-neutral { background: #f4f6f9; color: var(--text-muted); }

.text-muted { color: var(--text-muted); }
.text-success { color: var(--success); font-weight: 600; }
.text-danger { color: var(--danger); font-weight: 600; }
.mt-0 { margin-top: 0; }
.actions-row { display: flex; gap: 8px; margin-bottom: 18px; }

.avatar { border-radius: 50%; object-fit: cover; background: #dfe3e8; display: inline-block; }
.avatar-sm { width: 34px; height: 34px; }
.avatar-md { width: 56px; height: 56px; }
.avatar-lg { width: 96px; height: 96px; }
.profile-head { display: flex; align-items: center; gap: 18px; margin-bottom: 8px; flex-wrap: wrap; }
.profile-head .info h3 { margin: 0 0 4px 0; }

@media (max-width: 480px) {
  .stat-grid { gap: 10px; }
  .stat-card { min-width: 130px; padding: 14px 16px; }
  .stat-card .num { font-size: 1.6rem; }
  .avatar-lg { width: 76px; height: 76px; }
}

.notice-item { border-left: 3px solid var(--primary); padding: 10px 14px; margin-bottom: 12px; background: var(--row-hover-bg); border-radius: 0 6px 6px 0; }
.notice-item .notice-meta { font-size: 0.78rem; color: var(--text-muted); margin-top: 4px; }
.notice-badge { font-size: 0.72rem; padding: 2px 8px; border-radius: 10px; background: #eaf1fb; color: var(--primary); margin-left: 8px; }

.attendance-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(70px,1fr)); gap: 6px; }
.att-day { text-align: center; padding: 6px 2px; border-radius: 6px; font-size: 0.78rem; }
.att-present { background: #e5f6ec; color: var(--success); }
.att-absent { background: #fdeaea; color: var(--danger); }
.att-leave { background: #fff6e0; color: #a3781f; }
.att-none { background: #f4f6f9; color: var(--text-muted); }

/* Fee receipt (admin/fee_receipt.php, student/fee_receipt.php) */
.receipt-card { max-width: 560px; }
.receipt-header { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; padding-bottom: 16px; border-bottom: 1px dashed var(--border); }
.receipt-logo { width: 44px; height: 44px; flex-shrink: 0; }
.receipt-meta { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 14px; font-size: 0.92rem; flex-wrap: wrap; }
.receipt-card table { margin-bottom: 16px; }
.receipt-signature { text-align: right; margin-top: 28px; padding-top: 34px; border-top: 1px solid var(--border); max-width: 220px; margin-left: auto; font-size: 0.85rem; color: var(--text-muted); }

/* Transport route timeline (includes/transport.php render_transport_timeline())
   - a plain-CSS step-by-step route diagram, no map/JS involved. Stops flow
   left-to-right on desktop, connected by a line, ending at a distinct
   "School" node; one stop can be highlighted as the viewer's own boarding
   point. Below the 720px breakpoint (matching table-stack) it stacks into a
   vertical list instead, since a horizontal line of 6+ stops does not fit a
   phone screen. */
.route-timeline { display: flex; align-items: flex-start; overflow-x: auto; padding: 12px 4px 20px; -webkit-overflow-scrolling: touch; }
.route-stop { display: flex; flex-direction: column; align-items: center; text-align: center; flex-shrink: 0; width: 120px; }
.route-dot { width: 16px; height: 16px; border-radius: 50%; background: var(--primary); border: 3px solid var(--card-bg); box-shadow: 0 0 0 2px var(--primary); margin-bottom: 8px; }
.route-dot-school { width: 30px; height: 30px; background: var(--success); box-shadow: 0 0 0 2px var(--success); display: flex; align-items: center; justify-content: center; font-size: 15px; line-height: 1; }
.route-connector { flex: 1; height: 3px; background: var(--border); margin-top: 16px; min-width: 24px; }
.route-time { font-weight: 700; font-size: 0.85rem; color: var(--text); }
.route-name { font-size: 0.8rem; color: var(--text-muted); margin-top: 2px; word-break: break-word; }
.route-stop-highlight .route-dot { width: 22px; height: 22px; background: #c5981f; box-shadow: 0 0 0 3px #ffe6a3; margin-bottom: 5px; }
.route-badge { margin-top: 4px; font-size: 0.7rem; font-weight: 700; background: #fff6e0; color: #a3781f; padding: 2px 8px; border-radius: 10px; white-space: nowrap; }
[data-theme="dark"] .route-badge { background: rgba(197,152,45,0.22); color: #e0bb63; }
[data-theme="dark"] .route-stop-highlight .route-dot { background: #e0bb63; box-shadow: 0 0 0 3px rgba(224,187,99,0.35); }
@media (max-width: 720px) {
  .route-timeline { flex-direction: column; align-items: flex-start; overflow-x: visible; padding: 4px; }
  .route-stop { flex-direction: row; align-items: center; text-align: left; width: auto; gap: 10px; padding: 6px 0; }
  .route-dot { margin-bottom: 0; flex-shrink: 0; }
  .route-connector { display: none; }
  .route-info { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
  .route-name { margin-top: 0; }
}

/* Printing: keep only the page's own content (e.g. a receipt) on paper -
   the topbar, sidebar, and any .no-print controls (Print/Back buttons)
   are all app chrome that means nothing on a printed page. */
@media print {
  .topbar, .sidebar, .menu-toggle, .no-print { display: none !important; }
  .layout { display: block; }
  .content { padding: 0; }
  body { background: #fff; color: #000; }
  .card { border: none; box-shadow: none; padding: 0; }
}
