/* =============================================================================
   parts.css — the remaining component styles used by the JavaScript layer.
   Loaded last so it can extend or alias anything declared earlier.
   ========================================================================== */

/* ------------------------------------------------------------- utility --- */

.grid-cols-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.grid-cols-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
.grid-cols-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); }
.ta-right { text-align: right; }
.ta-center { text-align: center; }
.p-4 { padding: var(--space-4); }
.help { font-size: var(--text-xs); color: var(--text-soft); line-height: 1.5; }
.input-wrap { position: relative; display: flex; flex-direction: column; gap: 0.35rem; }
.input-wrap .password-toggle { top: 22px; }
.btn-row { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.btn-row-tight { gap: 0.5rem; }
.row-actions { display: inline-flex; flex-wrap: wrap; gap: 0.4rem; justify-content: flex-end; }
.avatar-xl { width: 76px; height: 76px; font-size: var(--text-xl); }
.select-sm { min-height: 38px; padding-block: 0.4rem; width: auto; }
.fee-value { font-family: var(--font-display); font-size: var(--text-xl); color: var(--green-800); }
/* Sticky save bar. The old transparent-to-opaque gradient let the fields
   underneath show through the bar as it scrolled; use an opaque surface with a
   hairline so the bar always reads as a separate layer. */
.sticky-actions {
  position: sticky; bottom: 0; z-index: 3;
  display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center;
  margin-top: var(--space-5); padding: var(--space-4) var(--space-4);
  background: var(--bg); border-top: 1px solid var(--border);
  box-shadow: 0 -8px 20px -14px rgba(4, 35, 26, 0.35);
}

/* -------------------------------------------------------------- charts --- */

.chart { width: 100%; height: auto; display: block; }
.ch-grid { stroke: var(--chart-grid); stroke-width: 1; }
.ch-axis { fill: var(--text-soft); font-size: 11px; font-family: var(--font-body); font-weight: 600; }
.ch-area { stroke: none; }
.ch-line { fill: none; stroke: var(--chart-line); stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.ch-dot { fill: var(--surface); stroke: var(--chart-line); stroke-width: 2; }
.ch-dot:hover { fill: var(--gold-500); stroke: var(--gold-700); }
.ch-bar { fill: var(--green-700); transition: fill var(--dur-fast) var(--ease); }
.ch-bar:hover { fill: var(--green-900); }
.ch-bar-gold { fill: var(--gold-600); }
.ch-bar-danger { fill: var(--red-600); }
.ch-arc { transition: opacity var(--dur-fast) var(--ease); }
.ch-arc:hover { opacity: 0.82; }
.ch-center-value { font-family: var(--font-display); font-size: 26px; font-weight: 600; fill: var(--green-900); }
.ch-center-label { font-size: 11px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; fill: var(--text-muted); }
.chart-legend { list-style: none; padding: 0; }
.chart-legend li { display: inline-flex; align-items: center; gap: 0.4rem; }
.chart-legend strong { color: var(--text); font-variant-numeric: tabular-nums; }
.chart-legend .dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.donut-empty {
  padding: var(--space-7) var(--space-4); text-align: center;
  color: var(--text-muted); font-size: var(--text-sm);
  border: 1px dashed var(--border); border-radius: var(--radius-md);
}
.hbars { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.hbar-head { display: flex; justify-content: space-between; gap: var(--space-4); font-size: var(--text-sm); margin-bottom: 0.35rem; }
.hbar-head strong { font-variant-numeric: tabular-nums; }
.hbar-track { height: 9px; border-radius: var(--radius-pill); background: var(--chart-track); overflow: hidden; }
.hbar-fill { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--green-600), var(--green-800)); }
.spark { width: 96px; height: 28px; }
.spark path { fill: none; stroke: var(--gold-600); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* --------------------------------------------------------- panels/rows --- */

.panel-wide { grid-column: 1 / -1; }
.stat-grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.list-row-stack { align-items: flex-start; flex-wrap: wrap; }
.row-main { flex: 1 1 220px; min-width: 0; display: flex; flex-direction: column; gap: 0.15rem; }
.row-main .tiny { color: var(--text-muted); }
.row-date {
  flex: none; width: 76px; display: flex; flex-direction: column; gap: 0.1rem;
  padding-right: var(--space-3); border-right: 1px solid var(--border);
}
.row-date strong { font-size: var(--text-sm); }
.row-date small { font-size: var(--text-xs); color: var(--text-muted); }
.cell-user { display: flex; align-items: center; gap: 0.6rem; min-width: 0; }
.cell-user strong { display: block; }
.cell-user .tiny { color: var(--text-muted); }
.detail-head { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.detail-head h3 { font-family: var(--font-display); font-size: var(--text-xl); }
.kv-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); }
.kv-3 > div { display: flex; flex-direction: column; gap: 0.1rem; }
.kv-3 dt { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.08em; }
.kv-tight { gap: 0.3rem 0.9rem; font-size: var(--text-sm); }
.tl-dot {
  position: absolute; left: -21px; top: 6px; width: 9px; height: 9px; border-radius: 50%;
  background: var(--green-600); box-shadow: 0 0 0 3px var(--green-100);
}
.timeline li { position: relative; }
.next-class {
  display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; justify-content: space-between;
  padding: var(--space-4) var(--space-5); border-radius: var(--radius-md);
  background: linear-gradient(135deg, var(--green-900), var(--green-700)); color: var(--text-invert);
}
.next-class strong { display: block; font-family: var(--font-display); font-size: var(--text-lg); }
.next-class .tiny, .next-class .muted { color: rgba(255, 255, 255, 0.76); }
.day-group + .day-group { margin-top: var(--space-5); }
.day-heading {
  font-size: var(--text-xs); font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-muted); padding: 0.55rem var(--space-5); background: var(--bg-alt);
  border-bottom: 1px solid var(--border);
}
.chip-row { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.6rem; }
.chip-row .chip { cursor: default; font-size: var(--text-xs); padding: 0.25rem 0.65rem; }
.pill-count {
  flex: none; min-width: 20px; height: 20px; padding: 0 0.35rem; border-radius: var(--radius-pill);
  background: var(--gold-600); color: #22190a; font-size: 0.68rem; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center;
}
.stat-pill {
  display: flex; flex-direction: column; gap: 0.2rem; align-items: center; text-align: center;
  padding: var(--space-4) var(--space-5); border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.14);
}
.icon-badge.is-ok { background: var(--success-100); border-color: #b6e3ca; color: var(--success-700); }
.icon-badge.is-missing { background: var(--warning-100); border-color: var(--gold-300); color: var(--warning-700); }

/* ----------------------------------------------------- notifications ----- */

.notif-list { list-style: none; padding: 0; margin: 0; }
.notif {
  display: flex; gap: 0.7rem; align-items: flex-start;
  padding: 0.8rem var(--space-4); border-bottom: 1px solid var(--border);
}
.notif:last-child { border-bottom: 0; }
.notif.is-unread { background: var(--green-50); }
.notif strong { display: block; font-size: var(--text-base); }
.notif p { font-size: var(--text-sm); color: var(--text-muted); line-height: 1.5; }
.notif .when { display: block; font-size: var(--text-xs); color: var(--text-soft); margin-top: 0.2rem; }
.notif-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; margin-top: 0.45rem; background: var(--green-600); }
.notif-warning { background: var(--gold-600); }
.notif-danger { background: var(--red-600); }
.notif-info { background: var(--blue-500); }
.notif-success { background: var(--success-700); }
.notif-empty { padding: var(--space-6) var(--space-4); text-align: center; color: var(--text-muted); font-size: var(--text-sm); list-style: none; }
.notif-page .notif { padding: var(--space-4) var(--space-5); }

/* ---------------------------------------------------------- admin bits --- */

.student-card { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-4); }
.student-card-head { display: flex; gap: var(--space-4); align-items: center; }
.student-card-head strong { display: block; font-family: var(--font-display); font-size: var(--text-lg); }
.review-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); gap: var(--space-5); }
@media (max-width: 820px) { .review-grid { grid-template-columns: 1fr; } }
.proof-pane {
  border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden;
  background: var(--bg-alt); display: flex; flex-direction: column;
}
.proof-pane img { width: 100%; height: auto; display: block; background: #fff; }
.proof-pane figcaption, .proof-pane .empty-state { padding: var(--space-4); font-size: var(--text-sm); color: var(--text-muted); }
.admin-tile {
  border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden;
  background: var(--surface); box-shadow: var(--shadow-xs); display: flex; flex-direction: column;
}
.admin-tile img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block; }
.admin-tile figcaption { padding: var(--space-3) var(--space-4); display: flex; flex-direction: column; gap: 0.4rem; font-size: var(--text-sm); }
.config-list { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.config-row { display: flex; gap: var(--space-4); align-items: flex-start; }
.config-row .icon-badge { width: 34px; height: 34px; border-radius: var(--radius-sm); }
.config-row .icon-badge svg { width: 17px; height: 17px; }
.config-row strong { display: block; font-size: var(--text-base); }
.config-row .tiny { color: var(--text-muted); }

/* --------------------------------------------------- switches/segments --- */

.switch { display: inline-flex; align-items: center; gap: 0.6rem; cursor: pointer; font-size: var(--text-sm); font-weight: 650; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
/* Only the span immediately after the checkbox is the track. The selector used
   to be `.switch > span`, which also matched the "Enabled"/"Disabled" caption
   span and drew the pill and knob on top of that text. */
.switch > input + span {
  position: relative; flex: none; width: 44px; height: 24px; border-radius: var(--radius-pill);
  background: var(--line-strong); transition: background-color var(--dur) var(--ease);
}
.switch > input + span::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%;
  background: #fff; box-shadow: var(--shadow-xs); transition: transform var(--dur) var(--ease);
}
.switch input:checked + span { background: var(--green-700); }
.switch input:checked + span::after { transform: translateX(20px); }
.switch input:focus-visible + span { box-shadow: var(--ring); }
.switch > input + span + span { font-weight: 500; color: var(--text-muted); }

.segmented { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.segmented .seg {
  flex: 1 1 auto; display: inline-flex; align-items: center; justify-content: center; gap: 0.35rem;
  min-height: 42px; padding: 0.5rem 0.85rem; cursor: pointer; text-align: center;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface);
  font-size: var(--text-sm); font-weight: 650; transition: all var(--dur-fast) var(--ease);
}
.segmented .seg input { position: absolute; opacity: 0; width: 0; height: 0; }
.segmented .seg:hover { border-color: var(--green-200); background: var(--green-50); }
.segmented .seg:has(input:checked) { background: var(--green-800); border-color: var(--green-800); color: #fff; }
.segmented .seg:has(input:focus-visible) { box-shadow: var(--ring); }

.check-chip {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.5rem 0.9rem; border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface); font-size: var(--text-sm); font-weight: 600; cursor: pointer;
  transition: all var(--dur-fast) var(--ease);
}
.check-chip:hover { border-color: var(--green-200); background: var(--green-50); }
.check-chip:has(input:checked) { background: var(--green-800); border-color: var(--green-800); color: #fff; }
.check-chip:has(input:focus-visible) { box-shadow: var(--ring); }
.check-chip input { accent-color: var(--gold-600); }

/* ------------------------------------------------------- payment cards --- */

.method-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); gap: var(--space-4); }
.method-card {
  border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5);
  background: var(--surface); display: flex; flex-direction: column; gap: 0.5rem;
}
.method-card h3 { font-size: var(--text-md); }
.method-card .copy-field { margin-top: auto; }
.method-row {
  border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5);
  background: var(--surface); display: flex; flex-direction: column; gap: var(--space-4);
}
.method-row + .method-row { margin-top: var(--space-4); }
.method-row-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; }
.method-row-head strong { font-family: var(--font-display); font-size: var(--text-lg); }

/* ------------------------------------------------------------ receipts --- */

.receipt-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: var(--space-4) var(--space-5); margin-top: var(--space-5); }
.receipt-grid > div { display: flex; flex-direction: column; gap: 0.15rem; }
.receipt-grid dt { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); font-weight: 700; }
.receipt-grid dd { font-weight: 650; overflow-wrap: anywhere; }

@media print {
  body.printing-receipt > *:not(.modal-backdrop) { display: none !important; }
  body.printing-receipt .modal-backdrop { position: static; background: none; padding: 0; display: block; }
  body.printing-receipt .modal { box-shadow: none; border: 0; max-width: none; width: auto; }
  body.printing-receipt .modal-head, body.printing-receipt .modal-foot,
  body.printing-receipt .modal-close, body.printing-receipt .no-print { display: none !important; }
  body.printing-receipt .receipt { border: 0; max-width: none; padding: 0; }
}

/* --------------------------------------------------------- classroom ----- */

.meet-head { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-start; justify-content: space-between; margin-bottom: var(--space-4); }
.meet-head h2 { font-family: var(--font-display); font-size: var(--text-xl); }
.meet-frame-wrap { border-radius: var(--radius-md); overflow: hidden; background: #0c1512; box-shadow: var(--shadow-md); }
.meet-notes { margin-top: var(--space-5); display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }
.meet-loading { padding: var(--space-6) 0; display: flex; flex-direction: column; gap: var(--space-4); }

/* -------------------------------------------------------------- chat ----- */

.chat-contact {
  display: flex; gap: 0.65rem; align-items: center; width: 100%; text-align: left;
  padding: 0.7rem 1rem; border: 0; border-bottom: 1px solid var(--border);
  background: none; cursor: pointer; font: inherit; color: inherit;
}
.chat-contact:hover { background: var(--green-50); }
.chat-contact.is-active { background: var(--green-100); box-shadow: inset 2px 0 0 var(--green-700); }
.chat-contact-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.chat-contact-main strong { font-size: var(--text-base); }
.chat-contact-main .tiny { color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-form { padding: 0.75rem 1rem; border-top: 1px solid var(--border); display: flex; gap: 0.6rem; align-items: flex-end; background: var(--surface); }
.chat-form .textarea, .chat-form .input { min-height: 44px; max-height: 140px; resize: none; }
.bubble.is-me { margin-left: auto; background: var(--green-800); color: #fff; border-color: var(--green-800); }
.bubble.is-me .when, .bubble.is-me .tiny { color: rgba(255, 255, 255, 0.62); }
.bubble.is-them { margin-right: auto; }

/* ------------------------------------------------------- public extras --- */

.section-inner { margin-top: var(--space-8); }
.section-title { font-family: var(--font-display); font-size: var(--text-2xl); margin-bottom: var(--space-5); }
.course-media { display: block; overflow: hidden; aspect-ratio: 3 / 2; background: var(--green-50); }
.course-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform var(--dur-slow) var(--ease-out); }
.course-card:hover .course-media img { transform: scale(1.04); }
.course-body { padding: var(--space-5); display: flex; flex-direction: column; gap: 0.6rem; flex: 1 1 auto; }
.course-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; margin-top: auto; padding-top: var(--space-3); }
.course-detail { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: clamp(1.5rem, 1rem + 3vw, 3.5rem); align-items: start; }
@media (max-width: 880px) { .course-detail { grid-template-columns: 1fr; } }
.course-detail-media img { width: 100%; height: auto; border-radius: var(--radius-lg); box-shadow: var(--shadow-md); display: block; }
.course-detail-body { display: flex; flex-direction: column; gap: var(--space-4); }
.course-detail-body h1 { font-family: var(--font-display); font-size: var(--text-3xl); line-height: var(--leading-tight); }
.form-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: clamp(1.35rem, 1rem + 2vw, 2.5rem); box-shadow: var(--shadow-sm);
}
.gallery-tile {
  position: relative; display: block; width: 100%; padding: 0; border: 0; cursor: pointer;
  border-radius: var(--radius-md); overflow: hidden; background: var(--green-50); box-shadow: var(--shadow-xs);
}
.gallery-tile img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block; transition: transform var(--dur-slow) var(--ease-out); }
.gallery-tile:hover img { transform: scale(1.05); }
.gallery-tile:focus-visible { box-shadow: var(--ring); }
.gallery-cap {
  position: absolute; inset: auto 0 0 0; padding: 1.6rem 0.9rem 0.7rem; text-align: left;
  color: #fff; font-size: var(--text-sm); font-weight: 650;
  background: linear-gradient(180deg, rgba(4, 35, 26, 0), rgba(4, 35, 26, 0.82));
}
.teacher-avatar { display: flex; justify-content: center; margin-bottom: var(--space-4); }
.teacher-qual { font-size: var(--text-sm); color: var(--text-muted); }
.testimonial {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--space-5) var(--space-6); box-shadow: var(--shadow-xs);
  display: flex; flex-direction: column; gap: var(--space-4);
}
.testimonial blockquote { font-size: var(--text-md); line-height: var(--leading-normal); color: var(--ink-700); }
.testimonial figcaption { display: flex; flex-direction: column; gap: 0.1rem; margin-top: auto; }
.testimonial figcaption strong { font-weight: 700; }
.star { display: inline-flex; color: var(--line-strong); }
.star svg { width: 15px; height: 15px; }
.star.is-on { color: var(--gold-600); }

/* ---------------------------------------------------------- lightbox ----- */

.lightbox {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center;
  padding: clamp(1rem, 4vw, 3rem); background: rgba(4, 35, 26, 0.92);
}
.lightbox-figure { max-width: min(1000px, 100%); display: flex; flex-direction: column; gap: var(--space-4); }
.lightbox-figure img { max-width: 100%; max-height: 74vh; width: auto; border-radius: var(--radius-md); box-shadow: var(--shadow-lg); }
.lightbox-cap { color: rgba(255, 255, 255, 0.86); font-size: var(--text-sm); text-align: center; display: flex; flex-direction: column; gap: 0.2rem; }
.lightbox-close, .lightbox-nav {
  position: absolute; display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: var(--radius-pill); cursor: pointer;
  background: rgba(255, 255, 255, 0.12); border: 1px solid rgba(255, 255, 255, 0.24);
  color: #fff; font-size: 1.7rem; line-height: 1;
}
.lightbox-close { top: clamp(0.75rem, 3vw, 1.75rem); right: clamp(0.75rem, 3vw, 1.75rem); font-size: 1rem; }
.lightbox-close svg { width: 20px; height: 20px; }
.lightbox-nav.prev { left: clamp(0.5rem, 2vw, 1.5rem); }
.lightbox-nav.next { right: clamp(0.5rem, 2vw, 1.5rem); }
.lightbox-close:hover, .lightbox-nav:hover { background: rgba(255, 255, 255, 0.24); }
.lightbox-close:focus-visible, .lightbox-nav:focus-visible { box-shadow: var(--ring); }
@media (max-width: 620px) {
  .lightbox-nav { top: auto; bottom: clamp(0.75rem, 3vw, 1.5rem); }
}


/* ------------------------------------------- fee banner tones (JS names) -- */

.fee-banner.fee-success { border-color: rgba(15, 122, 79, 0.3); background: var(--success-100); }
.fee-banner.fee-info { border-color: rgba(26, 86, 196, 0.24); background: var(--info-100); }
.fee-banner.fee-warning { border-color: rgba(163, 90, 6, 0.3); background: var(--warning-100); }
.fee-banner.fee-danger { border-color: rgba(179, 38, 30, 0.3); background: var(--danger-100); }
.fee-banner.fee-success .icon-badge { background: #fff; color: var(--success-700); border-color: rgba(15, 122, 79, 0.28); }
.fee-banner.fee-warning .icon-badge { background: #fff; color: var(--warning-700); border-color: rgba(163, 90, 6, 0.28); }
.fee-banner.fee-danger .icon-badge { background: #fff; color: var(--danger-700); border-color: rgba(179, 38, 30, 0.28); }

/* ----------------------------------------- role-aware portal navigation -- */

body[data-role='student'] [data-role-only='teacher'],
body[data-role='teacher'] [data-role-only='student'] { display: none; }

/* =============================================================================
   QA fixes — found during Playwright review of the generated pages.
   ========================================================================== */

/* The header renders its Student/Teacher CTAs twice: once inside .main-nav (so
   they appear in the mobile drawer) and once in .header-actions. Hide the
   drawer copies on desktop so the pair is never duplicated. */
@media (min-width: 1041px) {
  .main-nav .nav-cta { display: none; }
}
.main-nav a { white-space: nowrap; }
/* Keep the tagline on one line; drop it entirely when the nav needs the room. */
.brand-tag { white-space: nowrap; }
@media (max-width: 1279px) { .brand-tag { display: none; } }

/* Stacked number/label and title/sub pairs are spans, so they need to break. */
.hero-proof-num,
.hero-proof-label,
.hero-float-title,
.hero-float-sub { display: block; }
.hero-float-sub { margin-top: 0.1rem; }

/* The hero headline is long; cap it a little below --text-hero on wide screens
   so it settles in four lines instead of five. */
@media (min-width: 1200px) {
  .hero h1 { font-size: clamp(3.1rem, 1.9rem + 2.2vw, 3.7rem); }
}

/* The fee sits inside .course-media, which is clipped to a 3/2 box, so it has
   to be an overlay badge rather than flow content. */
.course-media { position: relative; }
.course-fee {
  position: absolute;
  right: 0.7rem;
  bottom: 0.7rem;
  z-index: 1;
  display: inline-flex;
  align-items: baseline;
  gap: 0.18rem;
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(6px);
  box-shadow: var(--shadow-sm);
  font-size: var(--text-md);
  line-height: 1.2;
}

/* Public stat pills sit on a dark band — give the figure real presence. */
.stat-pill strong,
.stat-pill .num { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: 600; }

/* A .section-head that wraps its copy in a <div> and follows it with a link or
   button becomes a two-column header: copy left, action right. Without this the
   action stacks awkwardly under the intro paragraph. */
.section-head:has(> div + a),
.section-head:has(> div + .btn) {
  max-width: none;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
}
.section-head:has(> div + a) > div,
.section-head:has(> div + .btn) > div { max-width: 62ch; }
.section-head:has(> div + a) > a,
.section-head:has(> div + .btn) > .btn { flex: none; }
@media (max-width: 760px) {
  .section-head:has(> div + a),
  .section-head:has(> div + .btn) { flex-direction: column; align-items: flex-start; gap: var(--space-4); }
}

/* .card-quiet paints itself with --bg-alt, which makes it disappear inside a
   .section-alt band. Give it a real surface there instead. */
.section-alt .card-quiet,
.section-deep .card-quiet { background: var(--surface); border-color: var(--border); }
.section-deep .card-quiet { background: rgba(255, 255, 255, 0.07); border-color: rgba(255, 255, 255, 0.16); color: #fff; }

/* Headings run straight into a following lead paragraph without this. */
h1 + .lead, h2 + .lead, h3 + .lead { margin-top: var(--space-4); }

/* Small-but-readable body copy. --text-xs (.tiny) is for table meta, not prose. */
.sm { font-size: var(--text-sm); line-height: 1.6; }

/* A display-font card heading that should not compete with the section h2. */
h3.h5, h4.h5 { font-size: var(--text-lg); }

/* Card titles sat flush against their body copy. */
.card h3 + p, .card h4 + p, .card h3 + .sm, .card h4 + .sm { margin-top: 0.4rem; }

/* The home strip always shows six photographs; three columns fill two clean
   rows, where the auto-fill grid used on the gallery page leaves a ragged one. */
@media (min-width: 861px) { .gallery-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* Some photographs are bright at the bottom edge, so the caption needs a
   stronger scrim than the gallery page default. */
.gallery-cap {
  padding-top: 2.2rem;
  background: linear-gradient(180deg, rgba(4, 35, 26, 0), rgba(4, 35, 26, 0.55) 45%, rgba(4, 35, 26, 0.9));
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}

/* .toolbar is designed to sit flush inside a portal panel. On a public page it
   stands alone, so it needs its own frame and a select that does not stretch
   across the whole row. */
.toolbar-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-alt);
}
.toolbar-card .select { flex: 0 1 220px; }

/* Stacked label/description pairs are authored as sibling <span>s, which render
   on one line by default ("StudentWho is enrolling"). */
.step-label, .step-desc { display: block; }
.step-desc { margin-top: 0.1rem; }

/* ---------------------------------------------------------------------------
   Portal: label / value / meta groups
   These groups are rendered as sibling inline elements (<small><strong><span>),
   which run together on one line unless they are made block-level.
   --------------------------------------------------------------------------- */
.stat-card > div > small,
.stat-card > div > strong,
.stat-card > div > span,
.side-user .who > .name,
.side-user .who > .role,
.chat-head > div > strong,
.chat-head > div > span { display: block; }

.stat-card > div > small { font-size: var(--text-xs); color: var(--text-muted); letter-spacing: 0.02em; }
.stat-card > div > strong { font-family: var(--font-display); font-size: var(--text-2xl); font-weight: 600; line-height: 1.15; margin-top: 0.15rem; }
.stat-card > div > span { margin-top: 0.15rem; }
.side-user .who > .role { margin-top: 0.05rem; }

/* "September 2026" broke mid-word inside the 76px date gutter. */
.row-date { width: 112px; }
.row-date strong { overflow-wrap: normal; word-break: keep-all; }

/* Keep the "Mark read" action pinned to the right of a notification row. */
.notif > div { flex: 1 1 auto; min-width: 0; }
.notif > button { flex: none; margin-left: auto; align-self: flex-start; }

/* `.fee-banner` uses justify-content:space-between, which pushed the message
   block to the far right when it was the only sibling of the icon. */
.fee-banner > div { flex: 1 1 auto; min-width: 0; }
.fee-banner > div > strong { display: block; }
.fee-banner > div > p { margin-top: 0.15rem; font-size: var(--text-sm); line-height: 1.55; }
.fee-banner > .btn, .fee-banner > a.btn { flex: none; }

/* ---------------------------------------------------------------------------
   Base size for inline icons.
   There was no rule for `.icon` itself — icons were only ever sized by an
   ancestor (`.icon-badge svg`, `.icon-btn svg`, `.btn svg`...). A bare
   `<svg class="icon">` therefore stretched to the full width of its container,
   which blew the payment-method icons up to ~200px. Specificity here is 0,1,0
   so every existing ancestor rule still wins.
   --------------------------------------------------------------------------- */
.icon { width: 1.15em; height: 1.15em; flex: none; }

/* Payment method cards: icon + heading on one row, then label/value pairs. */
.method-card > header { display: flex; align-items: center; gap: 0.55rem; }
.method-card > header .icon { width: 20px; height: 20px; color: var(--primary); }
.method-card dl { display: flex; flex-direction: column; gap: 0.7rem; margin: 0; }
.method-card dl > div { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.method-card dt { font-size: var(--text-xs); color: var(--text-muted); letter-spacing: 0.02em; }
.method-card dd {
  margin: 0; display: flex; align-items: center; gap: 0.45rem; flex-wrap: wrap;
  font-size: var(--text-sm); font-weight: 600; overflow-wrap: anywhere;
}
.method-card dd.muted { font-weight: 400; }
.method-card dd .copy-btn { flex: none; font-weight: 500; }
.method-card > .btn { margin-top: auto; align-self: flex-start; }

/* Icon size variant that was used in markup but never defined. */
.icon-xs { width: 0.95em; height: 0.95em; flex: none; }

/* ---------------------------------------------------------------------------
   Utility classes that were referenced in markup but never defined.
   --------------------------------------------------------------------------- */
.block { display: block; }

/* Attendance / progress donuts are drawn by charts.js at a fixed size. */
.donut { display: block; width: 148px; height: 148px; }

/* Compact inputs used by the admin filter toolbars. */
.input-sm { padding: 0.42rem 0.65rem; font-size: var(--text-sm); }

/* The admission form marks the guardian block required when the student is a
   minor; give it a visible cue rather than relying on the asterisk alone. */
.is-required > label { font-weight: 650; }
.is-required .req { color: var(--danger-700); }

/* Table action buttons: keep them on one line where there is room, and aligned
   to the middle of the row rather than sitting on separate lines. */
.row-actions { align-items: center; }
td .row-actions { flex-wrap: nowrap; }
@media (max-width: 900px) { td .row-actions { flex-wrap: wrap; } }

/* "18:00" + day list read as one word without a line break between them. */
td .block { margin-top: 0.15rem; }

/* ---------------------------------------------------------------------------
   Admin "Recent activity" feed.
   `.timeline` (site.css) is built for the marketing page's `.timeline-item`
   grid; the console uses a plain <ul><li> with an absolutely-positioned dot,
   so it inherited gap:0 and had no padding, guide line or separation.
   --------------------------------------------------------------------------- */
ul.timeline { list-style: none; margin: 0; padding-left: var(--space-5); gap: 0; }
ul.timeline > li { padding: 0.7rem 0; border-bottom: 1px solid var(--border); }
ul.timeline > li:first-child { padding-top: 0; }
ul.timeline > li:first-child .tl-dot { top: 5px; }
ul.timeline > li:last-child { border-bottom: 0; padding-bottom: 0; }
ul.timeline > li > div > strong { display: block; font-size: var(--text-base); text-transform: capitalize; }
ul.timeline > li > div > p { margin-top: 0.2rem; line-height: 1.5; overflow-wrap: anywhere; }
ul.timeline > li.muted { border-bottom: 0; }

/* Charts with a single data point: make the lone marker readable. */
.chart-single-note { font-size: var(--text-xs); color: var(--text-muted); margin-top: var(--space-3); }

/* Give empty chart placeholders a soft surface so a panel with no data reads as
   deliberate rather than as a rendering failure. */
.donut-empty { background: var(--ivory-2); border-color: var(--line-strong); }

/* ---------------------------------------------------------------------------
   Mobile header overflow.
   `.brand` is `flex: 0 0 auto`, so at 375px the 257px brand block plus the
   177px action group forced a 101px horizontal scroll. Let the brand shrink and
   clamp the academy name instead.
   --------------------------------------------------------------------------- */
@media (max-width: 720px) {
  .header-inner { gap: var(--space-3); }
  .brand { flex: 0 1 auto; min-width: 0; }
  .brand-text { min-width: 0; }
  .brand-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .header-actions { min-width: 0; }
  .header-actions .btn { white-space: nowrap; }
}
@media (max-width: 430px) {
  /* The login CTA is repeated inside the drawer as `.nav-cta`, so the header
     only needs the brand and the menu button at the narrowest sizes. */
  .header-actions .btn { display: none; }
}

/* Portal topbar on phones: the page CTA buttons ("Verify payments",
   "Admissions", "My students") pushed `.topbar-actions` past the viewport.
   Every one of them is also reachable from the sidebar, so drop the text
   buttons and keep the icon actions. */
@media (max-width: 720px) {
  .topbar-actions { min-width: 0; flex-wrap: nowrap; justify-content: flex-end; }
  .topbar-actions > .btn { display: none; }
  /* With the CTA hidden the three icon actions fit on one line; let the page
     title take the remaining space instead of being squeezed by them. */
  .portal-topbar { gap: var(--space-3); }
  .portal-topbar > div:first-of-type, .topbar-title { min-width: 0; flex: 1 1 auto; }
  .portal-topbar h1 { font-size: var(--text-xl); }
}

/* Homepage proof band. loadStats() only renders counters whose value is real,
   so the row can legitimately hold two or three cards instead of four. Centre
   the partial row rather than leaving a hole on the right. */
[data-stats][data-stats-count='2'],
[data-stats][data-stats-count='3'] {
  grid-template-columns: repeat(var(--stats-cols, 2), minmax(0, 220px));
  justify-content: center;
}
[data-stats][data-stats-count='3'] { --stats-cols: 3; }
@media (max-width: 700px) {
  [data-stats][data-stats-count='2'],
  [data-stats][data-stats-count='3'] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Contact and social links ship without an href: applyPublicSettings() sets the
   real target once the academy's details are loaded, or leaves the element
   hidden if that detail is not configured. Restore the affordances the browser
   only gives to a real <a href>. */
a.btn:not([href]),
a.social-btn:not([href]),
a[data-academy]:not([href]),
a[data-whatsapp-link]:not([href]) { cursor: pointer; }
