/* ============================================================
   SchSys — Design System v5
   Palette: "Thunderbird" — a single red scale carried end‑to‑end
   (sidebar, actions, accents, status) plus a warm stone neutral
   and a navy "information" accent — the classic red + navy school
   pairing. Font: DM Sans | Icons: Remixicon
   ============================================================ */

:root {
    /* ---- Thunderbird — the brand scale, used everywhere ---- */
    --thunder-50:  #FFF0F0;
    --thunder-100: #FFDDDD;
    --thunder-200: #FFC1C1;
    --thunder-300: #FF9595;
    --thunder-400: #FF5959;
    --thunder-500: #FF2626;
    --thunder-600: #FC0606;
    --thunder-700: #DB0000;
    --thunder-800: #AF0505;
    --thunder-900: #900C0C;
    --thunder-950: #500000;

    /* ---- Legacy aliases — kept so any older inline var(--wine-*) /
       var(--army-*) reference still resolves to a sensible spot on
       the new scale, without having to hunt down every usage. ---- */
    --wine-950: var(--thunder-950); --wine-900: var(--thunder-900); --wine-800: var(--thunder-800);
    --wine-700: var(--thunder-700); --wine-600: var(--thunder-600); --wine-500: var(--thunder-500);
    --wine-400: var(--thunder-400); --wine-300: var(--thunder-300); --wine-200: var(--thunder-200);
    --wine-100: var(--thunder-100); --wine-50:  var(--thunder-50);
    --army-950: var(--thunder-950); --army-900: var(--thunder-900); --army-800: var(--thunder-800);
    --army-700: var(--thunder-700); --army-600: var(--thunder-600); --army-500: var(--thunder-500);
    --army-400: var(--thunder-400); --army-300: var(--thunder-300); --army-200: var(--thunder-200);
    --army-100: var(--thunder-100); --army-50:  var(--thunder-50);

    /* ---- Warm stone neutral — text, borders, canvas. Slightly warm
       (not blue-gray) so it sits comfortably next to a red brand
       instead of fighting it. ---- */
    --stone-950: #201413;
    --stone-800: #3B2B29;
    --stone-600: #6E5A57;
    --stone-400: #9C8985;
    --stone-200: #E7DEDC;
    --stone-100: #F1EAE8;
    --stone-50:  #FAF7F6;

    /* ---- Navy — reserved strictly for neutral "information" accents,
       never for actions. Red + navy is the traditional school-colors
       pairing, so it reads as intentional rather than a random 3rd hue. ---- */
    --navy-800: #14294A;
    --navy-700: #1E3A5F;
    --navy-600: #2C5282;
    --navy-100: #E7EDF5;

    --sch-primary:          var(--thunder-800);
    --sch-primary-hover:    var(--thunder-900);
    --sch-dark-bg:          var(--thunder-950);
    --sch-accent:           var(--thunder-600);
    --sch-accent-hover:     var(--thunder-700);
    --sch-accent-muted:     var(--thunder-100);
    --sch-text-on-primary:  #FDF9F8;
    --sch-text-on-accent:   #FFFFFF;

    /* Semantic status colors kept true to meaning, not palette-ified --
       success stays a distinctly cooler green and warning a distinctly
       cooler amber, so an "Active" badge never reads as just another
       brand-red chip. Danger intentionally *does* share the brand's red
       family (there's only one red to work with), so it's differentiated
       by finish instead of hue: primary actions are glossy/gradient,
       destructive actions are flat and a touch brighter/hotter. */
    --sch-success:          #15803D;
    --sch-success-bg:       #F0FDF4;
    --sch-warning:          #B45309;
    --sch-warning-bg:       #FFFBEB;
    --sch-danger:           var(--thunder-700);
    --sch-danger-bg:        var(--thunder-50);
    --sch-info:             var(--navy-700);
    --sch-info-bg:          var(--navy-100);
    --sch-card-border:      var(--stone-200);
    --sch-card-header-bg:   #FBF8F7;

    --color-bg:              #F7F3F2;
    --color-primary-50:      var(--thunder-50);
    --color-primary-100:     var(--thunder-100);
    --color-text-primary:    var(--stone-950);
    --color-text-secondary:  var(--stone-600);
    --color-text-muted:      var(--stone-400);
    --color-border:          var(--stone-200);
    --color-border-subtle:   var(--stone-100);

    --shadow-sm: 0 1px 2px 0 rgb(80 0 0 / 0.05);
    --shadow-md: 0 10px 22px -8px rgb(80 0 0 / 0.14), 0 2px 6px -2px rgb(80 0 0 / 0.08);
    --shadow-lg: 0 22px 44px -16px rgb(80 0 0 / 0.38);
    --shadow-hero: 0 18px 34px -10px rgba(144, 12, 12, 0.4), 0 4px 12px -4px rgba(144, 12, 12, 0.28);

    --sidebar-width: 232px;
    --sidebar-collapsed: 64px;
    --header-height: 60px;
    --radius: 13px;
    --radius-sm: 9px;
    --radius-full: 9999px;
    --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
    --transition-normal: 220ms cubic-bezier(0.4, 0, 0.2, 1);
    --font-sans: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
body { font-family: var(--font-sans); background: var(--color-bg); color: var(--color-text-primary); line-height: 1.55; font-size: 1rem; letter-spacing: -0.006em; overflow-x: hidden; }
a { color: var(--sch-primary); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4, h5 { letter-spacing: -0.015em; }

/* ══ CUSTOM SCROLLBARS ══
   Applies everywhere by default (page body, tables that scroll
   horizontally on mobile, dropdown option panels, any overflow:auto
   card) so nothing falls back to the OS's boxy default. The dark
   .sidebar-nav gets its own slimmer, light-on-dark variant further
   down -- that rule is more specific than this one so it still wins
   there; this is just the sane default for every light-background
   scroll container. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--stone-400) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background-color: var(--stone-400);
    border-radius: var(--radius-full);
    border: 2.5px solid var(--color-bg);
    background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background-color: var(--thunder-400); }
*::-webkit-scrollbar-corner { background: transparent; }

/* APP SHELL */
.app-container { display: flex; min-height: 100vh; }

/* SIDEBAR */
.sidebar {
    width: var(--sidebar-width);
    background: linear-gradient(180deg, var(--thunder-950) 0%, var(--thunder-900) 48%, var(--thunder-800) 100%);
    display: flex; flex-direction: column; position: fixed;
    height: 100vh; z-index: 220;
    transition: width var(--transition-normal), transform var(--transition-normal);
    overflow: hidden;
    box-shadow: 2px 0 24px -8px rgba(80, 0, 0, 0.35);
}
.sidebar::before {
    /* soft top sheen for depth -- a flat gradient alone reads flat/cheap;
       this faint radial highlight is what makes a dark panel feel premium
       rather than just "a dark rectangle". */
    content: ''; position: absolute; top: -30%; left: -10%; width: 70%; height: 45%;
    background: radial-gradient(circle, rgba(255,255,255,0.07), transparent 70%);
    pointer-events: none;
}
.sidebar.collapsed { width: var(--sidebar-collapsed); }

.sidebar-header {
    height: var(--header-height); display: flex; align-items: center;
    padding: 0 1.125rem; gap: 0.75rem;
    border-bottom: 1px solid rgba(255,255,255,0.08);
    flex-shrink: 0; overflow: hidden; position: relative; z-index: 1;
}
.sidebar.collapsed .sidebar-header { padding: 0; justify-content: center; gap: 0; }
.logo-icon { width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; color: var(--thunder-800); background: #FFFFFF; border-radius: 6px; font-size: 0.95rem; }
.logo-text { font-weight: 700; font-size: 0.85rem; color: white; white-space: nowrap; letter-spacing: -0.01em; transition: opacity var(--transition-fast), width var(--transition-normal); }
.sidebar.collapsed .logo-text { opacity: 0; width: 0; pointer-events: none; }

.school-badge {
    background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.09);
    border-radius: var(--radius-sm); padding: 7px 12px; margin: 12px 10px 6px;
    display: flex; align-items: center; gap: 6px; overflow: hidden; position: relative; z-index: 1;
}
.sidebar.collapsed .school-badge { display: none; }
.school-badge-name { font-size: 0.6875rem; font-weight: 700; color: var(--thunder-300); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; letter-spacing: -0.005em; }
.school-badge-role { font-size: 0.6rem; color: rgba(255,255,255,0.75); font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; }

/* Nav */
.sidebar-nav { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 0.5rem 0; display: flex; flex-direction: column; position: relative; z-index: 1; }
.sidebar-nav::-webkit-scrollbar { width: 3px; }
.sidebar-nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.15); }

.nav-section-label { font-size: 0.5625rem; font-weight: 700; letter-spacing: 0.09em; color: rgba(255,255,255,0.75); text-transform: uppercase; padding: 0.25rem 1.125rem; white-space: nowrap; margin-top: 0.5rem; }
.nav-divider { height: 1px; background: rgba(255,255,255,0.35); margin: 0.5rem 1.125rem; }
.sidebar.collapsed .nav-divider { margin: 0.5rem 0.6rem; }
.sidebar.collapsed .nav-section-label { display: none; }

.nav-item {
    display: flex; align-items: center; padding: 0.5rem 1.125rem; cursor: pointer;
    transition: all var(--transition-fast); text-decoration: none !important;
    /* The sidebar background is a gradient from thunder-950 (near-black
       maroon) at the top down to thunder-800 (a much brighter, saturated
       red) at the bottom. Text opacity was set once and applied everywhere,
       but the same rgba(255,255,255,0.6) that reads at ~6:1 contrast near
       the top drops to ~3.3:1 by the time the gradient reaches thunder-800
       -- below the 4.5:1 WCAG AA floor for this text's size, which is why
       Reports/Attendance/School Profile/Settings read as noticeably
       fainter than Dashboard. 0.82 keeps at least ~5.2:1 at the gradient's
       brightest point, so every item is legible regardless of its
       position down the sidebar. */
    color: rgba(255,255,255,0.82); font-size: 0.75rem; font-weight: 500;
    position: relative; white-space: nowrap; gap: 0.7rem;
    border-left: 2px solid transparent; margin: 1px 0;
}
.nav-item:hover { background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.95); }
.nav-item.active { background: rgba(255,38,38,0.18); color: white; font-weight: 700; border-left: 3px solid var(--thunder-500); }
.nav-item i { font-size: 0.95rem; flex-shrink: 0; width: 18px; text-align: center; display: inline-flex; align-items: center; justify-content: center; }
.nav-item-text { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.sidebar.collapsed .nav-item-text, .sidebar.collapsed .nav-badge { display: none; }
.sidebar.collapsed .nav-item { justify-content: center; padding: 0.6rem 0; gap: 0; border-left: none; }
.sidebar.collapsed .nav-item.active { border-left: none; border-right: 3px solid var(--thunder-500); }
.sidebar.collapsed .nav-item i { width: 100%; font-size: 1.1rem; }

.nav-badge { background: var(--thunder-500); color: #fff; font-size: 0.6rem; font-weight: 700; padding: 1px 6px; border-radius: 10px; min-width: 18px; text-align: center; flex-shrink: 0; }

.sidebar-collapse-btn { width: 100%; height: 44px; border: none; border-top: 1px solid rgba(255,255,255,0.07); background: rgba(255,255,255,0.02); cursor: pointer; display: flex; align-items: center; justify-content: flex-end; padding: 0 1.125rem; gap: 0.5rem; color: rgba(255,255,255,0.75); font-size: 0.6875rem; font-weight: 500; font-family: var(--font-sans); transition: all var(--transition-fast); flex-shrink: 0; position: relative; z-index: 1; }
.sidebar-collapse-btn i { font-size: 1rem; transition: transform var(--transition-fast); }
.sidebar-collapse-btn:hover { background: rgba(255,255,255,0.07); color: rgba(255,255,255,0.85); }
.sidebar.collapsed .sidebar-collapse-btn { justify-content: center; padding: 0; }
.sidebar.collapsed .sidebar-collapse-btn .collapse-label { display: none; }
.sidebar.collapsed .sidebar-collapse-btn i { transform: rotate(180deg); }

.sidebar-overlay { display: none; position: fixed; inset: 0; background: rgba(64,0,0,0.55); backdrop-filter: blur(2px); z-index: 210; }
.sidebar-overlay.show { display: block; }

/* MAIN */
.main-content { margin-left: var(--sidebar-width); flex: 1; display: flex; flex-direction: column; min-height: 100vh; min-width: 0; transition: margin-left var(--transition-normal); }
.sidebar.collapsed ~ .main-content { margin-left: var(--sidebar-collapsed); }

/* HEADER */
.header { height: var(--header-height); background: rgba(255,255,255,0.86); backdrop-filter: saturate(180%) blur(10px); border-bottom: 1px solid var(--color-border); display: flex; align-items: center; justify-content: space-between; padding: 0 1.5rem; position: sticky; top: 0; z-index: 50; gap: 1rem; }
.header-left { display: flex; align-items: center; gap: 0.875rem; flex: 1; min-width: 0; }
.menu-toggle { display: none; align-items: center; justify-content: center; width: 36px; height: 36px; border: none; background: none; cursor: pointer; color: var(--color-text-primary); font-size: 1.25rem; border-radius: var(--radius-sm); }
.menu-toggle:hover { background: var(--color-bg); }
.page-title-group { display: flex; flex-direction: column; min-width: 0; justify-content: center; gap: 1px; }
.page-title-school {
    font-size: 0.625rem; font-weight: 700; color: var(--sch-primary); opacity: 0.72;
    text-transform: uppercase; letter-spacing: 0.05em; line-height: 1.1;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.page-title { font-size: 1.0625rem; font-weight: 700; color: var(--color-text-primary); letter-spacing: -0.015em; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.header-right { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
.header-sep { width: 1px; height: 24px; background: var(--color-border); margin: 0 2px; }

/* MOBILE TAB BAR — the native-app-style bottom nav for the pages that
   opt in via the .mobile-tabbar element (see .has-mobile-tabbar above).
   Hidden entirely above the mobile breakpoint; the desktop sidebar is
   the only nav there. */
.mobile-tabbar { display: none; }


/* User Profile Dropdown */
.user-profile-wrapper { position: relative; }
.user-profile-btn { display: flex; align-items: center; gap: 0.5rem; padding: 0.375rem 0.625rem; border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: white; cursor: pointer; transition: all var(--transition-fast); font-family: var(--font-sans); }
.user-profile-btn:hover { background: var(--color-bg); border-color: var(--thunder-300); }
.user-profile-avatar { width: 30px; height: 30px; border-radius: var(--radius-sm); background: linear-gradient(135deg, var(--thunder-800), var(--thunder-600)); color: #FFFFFF; font-size: 0.75rem; font-weight: 700; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.user-profile-name { font-size: 0.875rem; font-weight: 600; color: var(--color-text-primary); white-space: nowrap; }
.user-profile-role { font-size: 0.7rem; color: var(--color-text-muted); white-space: nowrap; }
.user-profile-chevron { color: var(--color-text-muted); transition: transform var(--transition-fast); font-size: 1rem; }
.user-profile-wrapper.open .user-profile-chevron { transform: rotate(180deg); }
.user-dropdown-menu { position: absolute; top: calc(100% + 8px); right: 0; background: white; border: 1px solid var(--color-border); border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); padding: 4px; min-width: 200px; display: none; z-index: 200; }
.user-dropdown-menu.show { display: block; animation: slideDown 0.15s ease; }
@keyframes slideDown { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
@keyframes slideUpPanel { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.user-dropdown-item { display: flex; align-items: center; gap: 0.625rem; padding: 9px 12px; border-radius: var(--radius-sm); cursor: pointer; transition: all var(--transition-fast); font-size: 0.875rem; color: var(--color-text-secondary); font-weight: 500; text-decoration: none; width: 100%; text-align: left; background: none; border: none; font-family: inherit; }
.user-dropdown-item:hover { background: var(--color-bg); color: var(--sch-primary); text-decoration: none; }
.user-dropdown-item i { font-size: 1rem; width: 18px; text-align: center; color: var(--color-text-muted); }
.user-dropdown-item.danger { color: var(--sch-danger); }
.user-dropdown-item.danger:hover { background: var(--sch-danger-bg); text-decoration: none; }
.user-dropdown-divider { height: 1px; background: var(--color-border); margin: 4px 0; }
.user-dropdown-info { padding: 8px 12px; font-size: 0.75rem; color: var(--color-text-muted); border-bottom: 1px solid var(--color-border); margin-bottom: 4px; }
.user-dropdown-info strong { display: block; font-size: 0.875rem; color: var(--color-text-primary); margin-bottom: 2px; }

/* CONTENT */
.content { padding: 1.5rem 2rem; flex: 1; min-width: 0; }

/* CARDS */
.card { background: white; border-radius: var(--radius); box-shadow: var(--shadow-sm); border: 1px solid var(--sch-card-border); margin-bottom: 1.25rem; animation: fadeInUp 0.3s ease both; }
.card-header { padding: 0.9375rem 1.125rem; border-bottom: 1px solid var(--color-border); display: flex; justify-content: space-between; align-items: center; background: var(--sch-card-header-bg); border-radius: var(--radius) var(--radius) 0 0; }
.card-title { font-size: 0.9375rem; font-weight: 700; color: var(--color-text-primary); display: flex; align-items: center; gap: 0.5rem; margin: 0; letter-spacing: -0.01em; }
.card-title i { color: var(--sch-primary); font-size: 1.05rem; }
.card-body { padding: 1.125rem; }
.card > h2:first-child, .card > h3:first-child, .card > h4:first-child { padding: 1.125rem 1.125rem 0; }
.card form, .card p, .card details { margin: 0 1.125rem 1.125rem; }
.card table { margin: 0 0 1.125rem; }
.card > h3 + form, .card > h3 + p, .card > h3 + table, .card > h4 + form { margin-top: 0.75rem; }
.card > h3, .card > h4 { padding: 1.125rem 1.125rem 0; margin-bottom: 0; }
.card > h3 + *, .card > h4 + * { margin-top: 0.625rem !important; }
.card > .alert { margin: 1.125rem; }
.card-header + p, .card-header + table, .card-header + form, .card-header + details, .card-header + div { margin-top: 0 !important; }
.card-header + p { padding: 1.125rem 1.125rem 0; }
.card table:not(:first-child), .card form:not(:first-child), .card p:not(:first-child), .card details:not(:first-child) { padding: 0; }
.card .card-header ~ p, .card .card-header ~ form, .card .card-header ~ h4, .card .card-header ~ details, .card .card-header ~ div:not(.form-row):not(.alert) {
    padding-left: 1.125rem; padding-right: 1.125rem;
}
.card .card-header ~ table { padding: 0; }
.card .card-header ~ p:last-child, .card .card-header ~ form:last-child, .card .card-header ~ details:last-child { padding-bottom: 1.125rem; }
.card .card-header ~ h4 { margin-top: 1.125rem; font-size: 0.875rem; color: var(--color-text-secondary); text-transform: uppercase; letter-spacing: 0.04em; }
/* NOTE: the "to" state below is deliberately transform: none rather than
   translateY(0) -- both render identically, but translateY(0) still
   counts as "a transform" once the animation's fill-mode:both holds it
   forever, which makes every element using this animation a containing
   block for any position:fixed descendant (e.g. an open custom-select
   dropdown), silently breaking its viewport-relative positioning. none
   avoids that with no visual difference. */
@keyframes fadeInUp { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* COLLAPSIBLE CARD — a native <details>/<summary> wearing the same .card
   shell, for a block of information that's useful but doesn't need to be
   open by default (e.g. a child's full admission record on the parent
   portal). Native <details> means the open/close behavior and keyboard/
   screen-reader accessibility come for free, no JS required. */
details.card { padding: 0; }
details.card > summary.card-header {
    cursor: pointer;
    list-style: none;
    user-select: none;
    gap: 0.75rem;
}
details.card > summary.card-header::-webkit-details-marker { display: none; }
details.card > summary.card-header::marker { content: ''; }
details.card > summary.card-header:hover { background: var(--thunder-50); }
/* Nothing renders below the summary while closed, so let it round out on
   all four corners instead of just the top two. */
details.card:not([open]) > summary.card-header { border-radius: var(--radius); }
.card-toggle-chevron { font-size: 1.15rem; color: var(--color-text-muted); transition: transform var(--transition-fast); flex-shrink: 0; }
details.card[open] > summary.card-header .card-toggle-chevron { transform: rotate(180deg); }

/* GRID / STATS */
.grid { display: grid; gap: 1.25rem; min-width: 0; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.25rem; min-width: 0; }
.stats-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.25rem; min-width: 0; }
.stat-card { position: relative; overflow: hidden; background: white; border-radius: var(--radius); padding: 1.25rem; box-shadow: var(--shadow-sm); border: 1px solid var(--sch-card-border); display: flex; flex-direction: column; gap: 0.75rem; transition: box-shadow var(--transition-normal), transform var(--transition-normal); animation: fadeInUp 0.35s ease both; min-width: 0; }
.stat-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
/* Thin top accent stripe -- a quiet, premium way to color-code a card at
   a glance without tinting the whole surface. The hero (.primary) card
   below is fully colored instead, so it doesn't need this. */
.stat-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--stone-200); }
.stat-card.success::before { background: var(--sch-success); }
.stat-card.info::before { background: var(--sch-info); }
.stat-card.warning::before { background: var(--sch-warning); }
.stat-card.danger::before { background: var(--sch-danger); }
.stat-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; }
.stat-icon { width: 40px; height: 40px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; font-size: 1.2rem; flex-shrink: 0; }
.stat-card.success .stat-icon { background: var(--sch-success-bg); color: var(--sch-success); }
.stat-card.info .stat-icon { background: var(--sch-info-bg); color: var(--sch-info); }
.stat-card.warning .stat-icon { background: var(--sch-warning-bg); color: var(--sch-warning); }
.stat-card.danger .stat-icon { background: var(--sch-danger-bg); color: var(--sch-danger); }
.stat-label { font-size: 0.75rem; color: var(--color-text-secondary); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; }
.stat-number { font-size: 1.85rem; font-weight: 700; color: var(--color-text-primary); line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.stat-card .value { font-size: 1.85rem; font-weight: 700; color: var(--sch-primary); line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.stat-card .label { font-size: 0.75rem; color: var(--color-text-secondary); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; margin-top: 4px; }
.stat-change { display: inline-flex; align-items: center; gap: 0.1875rem; font-size: 0.75rem; font-weight: 600; margin-top: 0; }
.stat-change i { font-size: 0.85rem; }
.stat-change.positive { color: var(--sch-success); }
.stat-change.negative { color: var(--sch-danger); }

/* HERO STAT CARD — the page's single headline metric (.stat-card.primary)
   gets the full gradient "Thunderbird" treatment: a glossy red panel with
   a soft radial highlight, mirroring the reference kit's featured card.
   Every dashboard/list page already marks exactly one card `primary`, so
   this reads as a consistent, deliberate signature rather than noise. */
.stat-card.primary {
    background: linear-gradient(135deg, var(--thunder-800) 0%, var(--thunder-600) 70%, var(--thunder-500) 100%);
    border: none; color: #fff; box-shadow: var(--shadow-hero);
}
.stat-card.primary::before { display: none; }
.stat-card.primary::after {
    content: ''; position: absolute; top: -45%; right: -15%; width: 220px; height: 220px;
    background: radial-gradient(circle, rgba(255,255,255,0.22), transparent 70%); pointer-events: none;
}
.stat-card.primary:hover { box-shadow: 0 24px 44px -12px rgba(144,12,12,0.5), 0 6px 16px -4px rgba(144,12,12,0.32); }
.stat-card.primary .stat-label { color: rgba(255,255,255,0.8); }
.stat-card.primary .stat-number, .stat-card.primary .value { color: #fff; }
.stat-card.primary .label { color: rgba(255,255,255,0.8); }
.stat-card.primary .stat-icon { background: rgba(255,255,255,0.18); color: #fff; backdrop-filter: blur(4px); }
.stat-card.primary .stat-change.positive { color: #C8FFD9; }
.stat-card.primary .stat-change.negative { color: #FFD3D3; }

.chart-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; min-width: 0; }
.chart-grid > * { min-width: 0; }
.chart-grid-wide { display: grid; grid-template-columns: 2.1fr 1fr; gap: 1rem; align-items: start; min-width: 0; }
.chart-grid-wide > * { min-width: 0; }
canvas { max-width: 100%; }

/* ══════════════════════════════════════════════════════════
   TEACHER DASHBOARD — greeting bar + class card grid.
   Replaces a single wide table row that had to cram five
   same-weight buttons into one line (unreadable past 2-3
   classes, and every action fought for equal attention).
   One clear primary action per class ("Enter Scores") plus a
   compact icon-button row for the rest reads as an actual
   hierarchy of controls instead of a button soup.
   ══════════════════════════════════════════════════════════ */
.th-dash-header { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 16px; margin-bottom: 1.5rem; }
.th-dash-greeting { font-size: 1.375rem; font-weight: 800; letter-spacing: -0.02em; }
.th-dash-term { margin-top: 6px; }

.term-pill { display: inline-flex; align-items: center; gap: 7px; padding: 5px 12px 5px 10px; border-radius: var(--radius-full); font-size: 0.75rem; font-weight: 600; background: var(--sch-card-header-bg); border: 1px solid var(--color-border); color: var(--color-text-secondary); }
.term-pill-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.term-pill.is-open { background: var(--sch-success-bg); border-color: #BBF0CE; color: #14532D; }
.term-pill.is-open .term-pill-dot { background: var(--sch-success); box-shadow: 0 0 0 3px rgba(21,128,61,0.15); }
.term-pill.is-locked { background: var(--sch-danger-bg); border-color: var(--thunder-200); color: var(--thunder-800); }
.term-pill.is-locked .term-pill-dot { background: var(--sch-danger); box-shadow: 0 0 0 3px rgba(219,0,0,0.13); }

.th-section-heading { display: flex; align-items: center; gap: 8px; margin: 0 0 0.875rem; font-size: 0.9375rem; font-weight: 700; color: var(--color-text-primary); letter-spacing: -0.01em; }
.th-section-heading i { color: var(--sch-primary); font-size: 1.05rem; }

.class-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 1rem; min-width: 0; }

.class-card {
    display: flex; flex-direction: column; gap: 1rem;
    background: white; border: 1px solid var(--sch-card-border); border-radius: var(--radius);
    padding: 1.125rem; box-shadow: var(--shadow-sm);
    transition: box-shadow var(--transition-normal), transform var(--transition-normal);
    animation: fadeInUp 0.3s ease both; min-width: 0;
}
.class-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.class-card-link { text-decoration: none; color: inherit; cursor: pointer; }
.class-card-link:hover { text-decoration: none; color: inherit; }
.class-card-link .class-card-actions .btn { background: var(--sch-card-header-bg); color: var(--sch-primary); border-color: var(--color-border); box-shadow: none; }
.class-card-link:hover .class-card-actions .btn { background: linear-gradient(135deg, var(--thunder-800) 0%, var(--thunder-600) 100%); color: #fff; border-color: var(--thunder-700); }

.class-card-top { display: flex; align-items: flex-start; gap: 0.75rem; min-width: 0; }
.class-card-id {
    width: 42px; height: 42px; border-radius: var(--radius-sm); flex-shrink: 0;
    background: linear-gradient(135deg, var(--thunder-800) 0%, var(--thunder-600) 100%);
    color: #fff; font-weight: 700; font-size: 0.8rem;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 4px 10px -3px rgba(144,12,12,0.45);
}
.class-card-titles { min-width: 0; }
.class-card-name { font-weight: 700; font-size: 0.9375rem; color: var(--color-text-primary); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; letter-spacing: -0.01em; }
.class-card-subject { font-size: 0.8125rem; color: var(--color-text-secondary); margin-top: 2px; }
.class-card-code { color: var(--color-text-muted); }

.class-card-meta { display: flex; gap: 1rem; flex-wrap: wrap; padding-top: 0.875rem; border-top: 1px solid var(--color-border-subtle); }
.class-card-meta-item { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: var(--color-text-secondary); }
.class-card-meta-item i { color: var(--sch-primary); font-size: 0.95rem; }
.class-card-meta-item strong { color: var(--color-text-primary); font-weight: 700; }

.class-card-actions { display: flex; align-items: center; gap: 0.5rem; margin-top: auto; }
.class-card-actions .btn { margin-top: 0; flex: 1; justify-content: center; }

.icon-btn-group { display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0; }
.icon-btn {
    width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm); background: var(--sch-card-header-bg); border: 1px solid var(--color-border);
    color: var(--color-text-secondary); font-size: 0.9rem; cursor: pointer; flex-shrink: 0;
    transition: all var(--transition-fast); text-decoration: none;
}
.icon-btn:hover { background: var(--thunder-50); border-color: var(--thunder-300); color: var(--sch-primary); text-decoration: none; transform: translateY(-1px); }
.icon-btn-warning:hover { background: var(--sch-warning-bg); border-color: #FDE4B8; color: var(--sch-warning); }

/* Secondary class-card actions -- labeled tiles rather than icon-only
   buttons. An unlabeled icon relies on the person already knowing what
   it means, or hovering to reveal a tooltip; a visible word next to it
   removes that guesswork entirely, which matters more here than the
   extra width it costs. */
.class-card-action-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
.action-tile {
    display: flex; align-items: center; gap: 7px; padding: 7px 10px;
    border-radius: var(--radius-sm); background: var(--sch-card-header-bg); border: 1px solid var(--color-border);
    color: var(--color-text-secondary); font-size: 0.75rem; font-weight: 600;
    text-decoration: none; cursor: pointer; transition: all var(--transition-fast); min-width: 0;
}
.action-tile i { font-size: 0.95rem; color: var(--sch-primary); flex-shrink: 0; }
.action-tile span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.action-tile:hover { background: var(--thunder-50); border-color: var(--thunder-300); color: var(--sch-primary); text-decoration: none; }
.action-tile.is-warning:hover { background: var(--sch-warning-bg); border-color: #FDE4B8; color: var(--sch-warning); }
.action-tile.is-warning:hover i { color: var(--sch-warning); }

.class-card-locked { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: var(--color-text-muted); margin-top: auto; }

.th-empty-state { text-align: center; padding: 3rem 1.5rem; }
.th-empty-icon { width: 56px; height: 56px; border-radius: var(--radius); background: var(--thunder-50); color: var(--sch-primary); display: flex; align-items: center; justify-content: center; font-size: 1.5rem; margin: 0 auto 1rem; }
.th-empty-state h3 { font-size: 1rem; font-weight: 700; margin-bottom: 4px; }
.th-empty-state p { color: var(--color-text-secondary); font-size: 0.875rem; max-width: 340px; margin: 0 auto; }

/* Attendance page info bar -- two matched chips (today's date, PTA dues
   progress) instead of one badge stretched into a sentence plus an
   unrelated plain-text line below it. Same weight, same shape, so the
   two pieces of context read as a pair rather than two different UI
   patterns bolted together. */
/* margin-top here would get zeroed by the shared ".card-header + div
   { margin-top: 0 !important; }" rule (this element is a div directly
   after .card-header), so padding-top is used instead -- a different
   property entirely, so it isn't affected by that rule at all. */
.attendance-meta { display: flex; gap: 0.875rem; flex-wrap: wrap; padding-top: 0.9375rem; margin-bottom: 0.625rem; }
.attendance-meta-item { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border-radius: var(--radius-sm); border: 1px solid var(--color-border); background: var(--sch-card-header-bg); flex: 1 1 240px; min-width: 240px; }
.attendance-meta-item i { font-size: 1.15rem; flex-shrink: 0; }
.attendance-meta-item strong { display: block; font-size: 0.8125rem; font-weight: 700; color: var(--color-text-primary); letter-spacing: -0.005em; margin-bottom: 2px; }
.attendance-meta-item span { font-size: 0.75rem; color: var(--color-text-secondary); }
.attendance-meta-item.is-info { background: var(--sch-info-bg); border-color: #D7E3F5; }
.attendance-meta-item.is-info i { color: var(--sch-info); }
.attendance-meta-item.is-success { background: var(--sch-success-bg); border-color: #BBF0CE; }
.attendance-meta-item.is-success i { color: var(--sch-success); }

@media (max-width: 480px) {
    .class-card-grid { grid-template-columns: 1fr; }
    .class-card-action-grid { grid-template-columns: 1fr; }
}

/* Table group header rows (e.g. students grouped by class) */
.group-header-row td {
    text-align: left !important;
    padding: 0.75rem 1.125rem !important;
    background: var(--thunder-50) !important;
    border-top: 1px solid var(--thunder-100);
    border-bottom: 1px solid var(--thunder-100);
}
.group-header-row:hover td { background: var(--thunder-100) !important; }
.group-header-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.group-header-left { display: flex; align-items: center; gap: 9px; }
.group-header-chevron { font-size: 1.1rem; color: var(--sch-primary); transition: transform 0.15s ease; flex-shrink: 0; }
.group-header-icon { width: 24px; height: 24px; border-radius: 6px; background: var(--thunder-100); color: var(--sch-primary); display: flex; align-items: center; justify-content: center; font-size: 0.8rem; flex-shrink: 0; }
.group-header-label { font-weight: 700; font-size: 0.8125rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--sch-primary); }

/* BUTTONS
   Three families, matching the reference kit:
   - .btn (default) = "Bezel": glossy gradient, the primary/high-emphasis action.
   - .btn-outline    = bordered, transparent fill, secondary emphasis.
   - .btn-flat       = solid flat fill, no gradient/shadow, for dense UI.
   .btn-secondary keeps its established meaning (a bordered neutral button)
   and is now just an alias built on the outline treatment. */
.btn { display: inline-flex; align-items: center; vertical-align: middle; gap: 0.45rem; padding: 0.75rem 1.375rem; border-radius: var(--radius-sm); border: 1px solid var(--thunder-700); background: linear-gradient(135deg, var(--thunder-800) 0%, var(--thunder-600) 100%); color: #fff; font-size: 0.875rem; font-weight: 600; cursor: pointer; margin-top: 0.875rem; font-family: inherit; transition: all var(--transition-fast); text-decoration: none; line-height: 1.3; box-shadow: 0 3px 10px rgba(144,12,12,0.32); letter-spacing: -0.005em; }
.btn:hover { background: linear-gradient(135deg, var(--thunder-900) 0%, var(--thunder-700) 100%); border-color: var(--thunder-900); text-decoration: none; transform: translateY(-1px); box-shadow: 0 6px 16px rgba(144,12,12,0.4); }
.btn:active { transform: translateY(0); }
.btn:disabled, .btn[disabled] { background: var(--thunder-100); border-color: var(--thunder-100); color: var(--thunder-300); cursor: not-allowed; box-shadow: none; transform: none; }
.btn i { font-size: 1.05rem; }

/* .btn-sm: the small row-action buttons used side-by-side in tables
   (Edit / Configure / Lock / Deactivate etc). These must always render
   at an identical, predictable height regardless of color variant --
   height + box-sizing + line-height are all pinned here so no variant
   can drift. Colored variants (btn-warning/btn-danger/btn-success) were
   previously carrying their own box-shadow, which visually "bled" past
   their edges and made them look bigger/heavier than a flat neutral
   button sitting right next to them in the same row, even though the
   actual box was pixel-identical -- that's what read as "misaligned".
   Small buttons are flat by design now; shadow is reserved for the
   one full-size primary .btn per page. */
.btn-sm { padding: 0 0.9rem; font-size: 0.8125rem; margin-top: 0; height: 38px; line-height: 1; box-sizing: border-box; box-shadow: none; }
.btn-sm:hover { box-shadow: none; transform: none; }
summary.btn-sm { list-style: none; }
summary.btn-sm::-webkit-details-marker { display: none; }
summary.btn-sm::marker { content: ''; }

/* Flat destructive action: same red family as the brand (there's only
   one red), but a flat solid fill with no gradient/gloss -- so next to a
   .btn primary action it never gets mistaken for "the main thing to
   click", even at a glance. */
.btn-danger { background: var(--thunder-700); border-color: var(--thunder-700); color: #fff; box-shadow: 0 1px 2px rgba(219,0,0,0.22); }
.btn-danger:hover { background: var(--thunder-800); border-color: var(--thunder-800); }
.btn-warning { background: linear-gradient(135deg, #92400E 0%, var(--sch-warning) 100%); border-color: #92400E; color: #fff; box-shadow: 0 2px 8px rgba(180,83,9,0.3); }
.btn-warning:hover { background: linear-gradient(135deg, #78350F 0%, #92400E 100%); }
.btn-secondary, .btn-outline { background: white; border-color: var(--color-border); color: var(--color-text-secondary); box-shadow: none; }
.btn-secondary:hover, .btn-outline:hover { background: var(--thunder-50); border-color: var(--thunder-300); color: var(--sch-primary); }
.btn-outline { border-color: var(--thunder-700); color: var(--thunder-800); }
.btn-outline:hover { background: var(--thunder-50); border-color: var(--thunder-800); }
.btn-success { background: var(--sch-success); border-color: var(--sch-success); box-shadow: 0 1px 2px rgba(21,128,61,0.22); }
.btn-success:hover { background: #14532D; border-color: #14532D; }
/* Solid flat fill, no gradient -- the third of the three reference
   button families, for dense toolbars where a glossy button is too loud. */
.btn-flat { background: var(--thunder-600); border-color: var(--thunder-600); color: #fff; box-shadow: none; }
.btn-flat:hover { background: var(--thunder-700); border-color: var(--thunder-700); transform: none; }
.btn-flat:active { background: var(--thunder-800); border-color: var(--thunder-800); }

/* Higher specificity (two classes) so this reliably wins over the
   single-class shadow declared on each color variant above, regardless
   of source order -- this is what actually makes .btn-sm's "flat, no
   shadow" rule stick for colored small buttons like Deactivate/Lock. */
.btn-sm.btn-danger, .btn-sm.btn-warning, .btn-sm.btn-success { box-shadow: none; }
.btn-sm.btn-danger:hover, .btn-sm.btn-warning:hover, .btn-sm.btn-success:hover { box-shadow: none; }

/* FORMS */
label { display: block; font-size: 0.8125rem; font-weight: 600; color: var(--color-text-secondary); margin-bottom: 4px; margin-top: 12px; }
input, select, textarea {
    width: 100%; padding: 0.75rem 0.875rem; border: 1px solid var(--color-border); border-radius: var(--radius-sm);
    font-size: 0.9375rem; font-family: inherit; color: var(--color-text-primary); background: white;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--thunder-700); box-shadow: 0 0 0 3px rgba(219,0,0,0.12); }
input[type="checkbox"], input[type="radio"] { width: auto; accent-color: var(--thunder-700); }
.form-row { display: flex; gap: 12px; flex-wrap: wrap; }
.form-row > div { flex: 1; min-width: 160px; }

/* TABLES */
table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
th, td { text-align: left; padding: 0.75rem 0.625rem; border-bottom: 1px solid var(--color-border-subtle); }
th:first-child, td:first-child { padding-left: 1.125rem; }
th:last-child, td:last-child { padding-right: 1.125rem; text-align: right; }
th { background: var(--sch-card-header-bg); font-weight: 600; color: var(--color-text-secondary); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; white-space: normal; padding-top: 0.875rem; padding-bottom: 0.875rem; border-bottom: 2px solid var(--color-border); }
tr:hover td { background: var(--color-primary-50); }
table input, table select { padding: 0.5rem 0.625rem; font-size: 0.875rem; }

/* A row whose Total/Grade were just recomputed client-side (see
   schRecomputeTotal in grading.php) but not yet persisted by a Save --
   the badges already show the correct live values, this just keeps a
   teacher from mistaking "looks right on screen" for "saved". Clears
   itself on the next page load once the save actually lands. */
tr.row-unsaved td:first-child { border-left: 3px solid var(--sch-warning); }

/* BADGES / STATUS. Green/amber stay off-brand on purpose (see note
   above .sch-success); blue borrows the navy "information" accent so it
   never collides visually with brand-red actions/links; red intentionally
   shares the brand hue since it *is* the brand's danger color. */
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px; border-radius: var(--radius-full); font-size: 0.75rem; font-weight: 600; }
.badge::before { content: ''; width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; }
.badge-green { background: var(--sch-success-bg); color: #166534; }
.badge-green::before { background: var(--sch-success); }
.badge-red { background: var(--sch-danger-bg); color: var(--thunder-800); }
.badge-red::before { background: var(--sch-danger); }
.badge-gray { background: var(--stone-100); color: var(--stone-600); }
.badge-gray::before { background: var(--stone-400); }
.badge-yellow { background: var(--sch-warning-bg); color: #92400e; }
.badge-yellow::before { background: var(--sch-warning); }
.badge-blue { background: var(--sch-info-bg); color: var(--sch-info); }
.badge-blue::before { background: var(--navy-600); }

/* A badge that is *also* a real interactive control (e.g. "unlink child"
   in the parents table). Plain badges are informational only, so a
   clickable one needs its own hover/focus affordance -- otherwise it's
   indistinguishable from a static badge like "Class 3: Mathematics". */
.badge-removable { cursor: pointer; transition: all var(--transition-fast); }
.badge-removable:hover, .badge-removable:focus-visible { background: var(--sch-danger-bg); color: var(--sch-danger); outline: none; }
.badge-removable:hover::before, .badge-removable:focus-visible::before { background: var(--sch-danger); }

/* AVATAR TILES — one consistent "person identity" thumbnail used in every
   list row (teachers, students, parents) and person card header, whether
   showing a photo or initials. Previously each table hand-rolled its own
   inline styles with two different color treatments (solid navy vs. light
   tint) and inconsistent sizing. */
.avatar-tile {
    display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
    border-radius: var(--radius-sm); background: var(--color-primary-100); color: var(--sch-primary);
    font-weight: 700; font-size: 0.72rem; letter-spacing: 0; overflow: hidden;
}
.avatar-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-tile-sm { width: 30px; height: 30px; font-size: 0.68rem; }
.avatar-tile-md { width: 32px; height: 32px; }

/* Row identity cell: avatar + name, used as a link to the edit page.
   Consistent underline affordance signals "this is clickable" -- the
   same treatment must appear on every row across every dashboard table. */
.row-identity { display: flex; align-items: center; gap: 8px; text-decoration: none; color: inherit; }
.row-identity-name { text-decoration: underline; text-decoration-color: var(--color-border); text-underline-offset: 3px; }
.row-identity:hover .row-identity-name { text-decoration-color: var(--sch-primary); }

/* ALERTS / FLASH */
.alert { display: flex; align-items: flex-start; gap: 0.625rem; padding: 0.75rem 1rem; border-radius: var(--radius-sm); margin-bottom: 1rem; font-size: 0.875rem; font-weight: 500; }
.alert-success { background: var(--sch-success-bg); color: #166534; border: 1px solid #bbf7d0; }
.alert-error { background: var(--sch-danger-bg); color: #7A0000; border: 1px solid var(--thunder-200); }

/* INFO BOXES — quiet callouts for tips/notices (two weights, matching the
   reference kit: a light wash for passive hints, a deeper tint for a
   notice that deserves a bit more attention). */
.info-box { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.875rem 1.125rem; border-radius: var(--radius); font-size: 0.8438rem; line-height: 1.5; margin-bottom: 1rem; }
.info-box-icon { width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.95rem; flex-shrink: 0; color: #fff; }
.info-box-1 { background: var(--thunder-50); color: var(--thunder-900); }
.info-box-1 .info-box-icon { background: var(--thunder-600); }
.info-box-2 { background: var(--thunder-200); color: var(--thunder-950); }
.info-box-2 .info-box-icon { background: var(--thunder-800); }
.info-box strong { font-weight: 700; }

/* READ-ONLY DETAIL GRID — label/value pairs for "view" pages showing data
   entered elsewhere (a child's admission record, a family's address on
   file, etc.) rather than an editable form -- e.g. the parent portal's
   child-details and home-address displays. */
.detail-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem 1.5rem; }
.detail-item { min-width: 0; }
.detail-label { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted); margin-bottom: 3px; }
.detail-value { font-size: 0.9375rem; font-weight: 600; color: var(--color-text-primary); word-break: break-word; }
.detail-value.muted { font-weight: 500; color: var(--color-text-muted); font-style: italic; }

/* MISC */
.help-text { font-size: 0.75rem; color: var(--color-text-muted); margin-top: 4px; }
.text-right { text-align: right; }
.mt-0 { margin-top: 0; }

.btn-back {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 16px 8px 12px;
    background: white; border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    color: var(--color-text-secondary);
    font-size: 0.85rem; font-weight: 600;
    text-decoration: none !important;
    margin-bottom: 16px;
    transition: all var(--transition-fast);
    box-shadow: var(--shadow-sm);
}
.btn-back i { font-size: 1rem; color: var(--sch-primary); transition: transform var(--transition-fast); }
.btn-back:hover { background: var(--thunder-50); border-color: var(--thunder-200); color: var(--sch-primary); box-shadow: var(--shadow-md); }
.btn-back:hover i { transform: translateX(-2px); }

/* MODAL */
dialog.modal { border: none; border-radius: var(--radius); padding: 0; max-width: 600px; width: 92vw; box-shadow: var(--shadow-lg); overflow: visible; position: fixed; top: 50%; left: 50%; margin: 0; transform: translate(-50%, -50%); }
dialog.modal::backdrop { background: rgba(64,0,0,0.6); backdrop-filter: blur(2px); }
dialog.modal[open] { animation: modalIn 0.2s cubic-bezier(0.4,0,0.2,1) both; }
@keyframes modalIn {
  from { opacity: 0; transform: translate(-50%, -50%) translateY(-12px) scale(0.98); }
  to   { opacity: 1; transform: translate(-50%, -50%) translateY(0) scale(1); }
}
.modal-header { display: flex; justify-content: space-between; align-items: center; padding: 1rem 1.25rem; border-bottom: 1px solid var(--color-border); background: var(--sch-card-header-bg); border-radius: var(--radius) var(--radius) 0 0; }
.modal-header h3 { font-size: 1rem; font-weight: 700; display: flex; align-items: center; gap: 8px; margin: 0; color: var(--color-text-primary); }
.modal-close-btn { background: none; border: none; font-size: 1.3rem; cursor: pointer; color: var(--color-text-muted); width: 32px; height: 32px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; transition: all var(--transition-fast); flex-shrink: 0; }
.modal-close-btn:hover { background: var(--sch-danger-bg); color: var(--sch-danger); }
.modal-body { padding: 1.25rem; }
.modal-body .form-row { display: block; }
.modal-body .form-row > div { margin-bottom: 0; }
.row-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
/* .btn carries margin-top: 0.875rem so a standalone submit button (e.g.
   "Add Year") sits away from the form field above it. Row-action buttons
   reuse .btn/.btn-sm but live inside a flex row, not below a form -- and
   because that margin only exists on the top side, align-items: center
   centers the button's margin box, not its visible face, so every action
   button (Configure/Activate/Lock/Unlock, and the same on Teachers,
   Students, Parents, Subjects) renders a few pixels below true center.
   Zeroing it here, scoped to .row-actions only, restores true vertical
   centering without touching the spacing standalone submit buttons need. */
.row-actions .btn { margin-top: 0; }
/* Row-action buttons (Edit/Move, Configure/Lock, Deactivate, etc.) sit in
   dense repeated columns down a table, so their width needs to come from
   a shared floor rather than each button's own label+icon -- otherwise
   "Edit" and "Move" end up very slightly different widths from row to
   row-adjacent columns and the whole list reads as not-quite-aligned even
   though every row's markup is identical. min-width plus centered content
   makes every short-label action button the same size, so the columns
   line up cleanly top to bottom. */
.row-actions .btn-sm { min-width: 74px; justify-content: center; }

/* Status-toggle action buttons (Activate/Deactivate, Lock/Unlock) show a
   different label depending on the row's current state, so their natural
   width changes from row to row -- "Deactivate" is noticeably wider than
   "Activate", "Unlock" wider than "Lock". Because these sit as the last
   button in a right-aligned .row-actions group, that width change drags
   every button before it (Edit, Reset PW, etc.) sideways too, so the whole
   column reads as jittery even though each row's markup is identical.
   Giving both states of each toggle one shared, wider floor keeps the
   button -- and everything left of it -- pinned to the same spot down
   the table regardless of which state the row happens to be in. */
.row-actions .btn-status-toggle { min-width: 104px; }
.row-actions .btn-lock-toggle { min-width: 92px; }

/* Buttons that need to POST (Deactivate, Lock/Unlock, Remove, etc.) are
   necessarily wrapped in their own <form>, and the dropdown-style actions
   (Reset PW, Move, Link Another Child) are wrapped in <details> so their
   panel can open below the button. Both wrappers are block-level boxes
   with a single inline-flex button inside them, and a block box sizes
   its inline content using ordinary line-box metrics -- which reserves
   extra leading (half the body's line-height) above and below that
   button. A bare <a class="btn"> sitting directly in .row-actions has no
   such wrapper and no such leading, so it doesn't get that extra space.
   The result: wrapped buttons render a few pixels higher/shorter inside
   their own box than unwrapped ones, even though every button is the
   same 30px tall -- so "Edit" lines up but "Reset PW"/"Deactivate"/"Lock"
   look like they're floating slightly off the row's true center.
   Zeroing the wrapper's line-height collapses that invisible leading so
   the button's own box is all that's left, matching a plain <a>. Forms
   never need the popover behavior details relies on, so they can also be
   switched to inline-flex directly for a same effect via a different
   route. */
/* `!important` here is deliberate, not a shortcut: several row-action
   forms across the app still carry a leftover inline style="display:inline"
   attribute from before .row-actions existed, and an inline style attribute
   always outranks any stylesheet rule (specificity or source order can't
   touch it) except one marked !important. Without it, that legacy inline
   style silently wins, the form never becomes a flex item the way this
   rule intends, and it falls back to being blockified with the unscoped
   ".card form" rule's 18px margin -- which is the actual mechanism behind
   the Lock/Unlock/Activate button sitting lower than a plain-link button
   like Configure in the same row. Resetting margin to 0 here (it wins
   .card form's margin on source order/specificity alone, no !important
   needed for that half) removes the extra height the sibling button was
   being measured against. */
.row-actions > form { display: inline-flex !important; align-items: center; margin: 0; }
/* Same bleed-through as the form fix above, different element: .card
   form, .card p, .card details all share one rule for standalone card
   spacing, and that rule's 18px margin-bottom lands on the Move/Reset PW
   <details> popovers too since they're descendants of .card. Zeroing it
   here is what actually made Edit and Move sit level -- line-height: 0
   alone only fixes the *content* box (the closed summary's own height),
   it doesn't touch the margin .card details adds around that box. */
.row-actions details { line-height: 0; margin: 0; }
/* The line-height reset above only exists to fix the summary button's
   position; without restoring it, every input/label inside the revealed
   popover panel (Reset PW's password field, Move's class/status selects)
   would inherit line-height: 0 too and collapse into unreadable text. */
.row-actions details form { line-height: 1.55; }

/* SECTIONED FULL-PAGE FORMS (Add/Edit Teacher, Add/Edit Student) */
.form-page-grid { display: grid; grid-template-columns: 1fr 300px; gap: 1.25rem; align-items: start; }
@media (max-width: 900px) { .form-page-grid { grid-template-columns: 1fr; } }

.form-section-header { display: flex; align-items: center; gap: 8px; margin-bottom: 1rem; padding-bottom: 8px; border-bottom: 2px solid var(--thunder-100); }
.form-section-header i { color: var(--sch-primary); font-size: 1.1rem; }
.form-section-header span { font-weight: 700; font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--sch-primary); }
.form-section-header .section-hint { text-transform: none; font-weight: 500; color: var(--color-text-muted); font-size: 0.75rem; letter-spacing: 0; margin-left: 2px; }
label .required-mark { color: var(--sch-danger); margin-left: 2px; }
label .optional-mark { color: var(--color-text-muted); font-weight: 500; text-transform: none; letter-spacing: 0; font-size: 0.7rem; margin-left: 3px; }

.photo-dropzone { aspect-ratio: 1; border: 2px dashed var(--color-border); border-radius: var(--radius); display: flex; align-items: center; justify-content: center; cursor: pointer; background: var(--thunder-50); transition: all var(--transition-fast); overflow: hidden; margin-bottom: 10px; }
.photo-dropzone:hover { border-color: var(--thunder-300); background: var(--thunder-100); }
.photo-dropzone img { width: 100%; height: 100%; object-fit: cover; display: none; }
.photo-dropzone-content { display: flex; flex-direction: column; align-items: center; gap: 8px; color: var(--sch-primary); text-align: center; padding: 20px; }
.photo-dropzone-content i { font-size: 2rem; }
.photo-dropzone-content span { font-size: 0.8125rem; font-weight: 600; line-height: 1.4; }
.photo-dropzone-caption { text-align: center; font-size: 0.7rem; color: var(--color-text-muted); margin-bottom: 12px; }

/* ══════════════════════════════════════════════════════════
   LOGIN — split screen (structure adapted from CampusCore ref)
   ══════════════════════════════════════════════════════════ */
.login-wrap {
    min-height: 100vh; display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg, var(--thunder-900) 0%, var(--thunder-950) 100%);
    padding: 20px;
}
/* legacy single-box variant kept for any page still using it */
.login-box { background: #fff; padding: 2.5rem; border-radius: 14px; width: 100%; max-width: 380px; box-shadow: var(--shadow-lg); }
.login-box .login-icon { width: 52px; height: 52px; border-radius: var(--radius-sm); background: var(--thunder-800); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 1.6rem; margin-bottom: 1.125rem; }
.login-box h1 { font-size: 1.25rem; font-weight: 700; margin-bottom: 4px; color: var(--color-text-primary); letter-spacing: -0.02em; }
.login-box p.sub { color: var(--color-text-muted); font-size: 0.8125rem; margin: 0 0 1.375rem; }

.login-wrapper { display: flex; width: 100%; max-width: 1160px; min-height: 100vh; align-items: center; justify-content: flex-start; gap: 64px; padding: 48px 60px; }

.login-left { flex: 0 0 480px; width: 480px; min-width: 0; color: #fff; }
.login-left .brand { font-size: 1.75rem; font-weight: 800; letter-spacing: -0.4px; display: inline-flex; align-items: center; gap: 10px; margin-bottom: 56px; }
.login-left .brand-icon { width: 34px; height: 34px; border-radius: 8px; background: #fff; color: var(--thunder-800); display: flex; align-items: center; justify-content: center; font-size: 1.15rem; }

.login-slogan { position: relative; min-height: 200px; }
.login-slide { position: absolute; inset: 0; opacity: 0; transition: opacity 0.6s cubic-bezier(0.4,0,0.2,1); pointer-events: none; }
.login-slide.active { opacity: 1; position: relative; pointer-events: auto; }
.login-slide h1 { font-size: clamp(1.9rem, 2.6vw, 2.6rem); font-weight: 800; line-height: 1.15; letter-spacing: -0.5px; margin-bottom: 16px; }
.login-slide p { font-size: 1rem; color: rgba(255,255,255,0.72); line-height: 1.65; max-width: 440px; }

.login-dots { display: flex; gap: 9px; align-items: center; margin-top: 36px; }
.login-dots .dot { width: 9px; height: 9px; border-radius: 50%; background: rgba(255,255,255,0.28); border: none; cursor: pointer; padding: 0; transition: all var(--transition-normal); }
.login-dots .dot:hover { background: rgba(255,255,255,0.55); }
.login-dots .dot.active { width: 30px; border-radius: 5px; background: var(--thunder-500); }

.login-right { display: flex; justify-content: center; flex-shrink: 0; margin-left: auto; }
.login-card { width: 380px; background: #fff; border-radius: 16px; padding: 2.75rem 2.25rem 2.25rem; box-shadow: var(--shadow-lg); animation: cardIn 0.4s cubic-bezier(0.4,0,0.2,1) both; }
@keyframes cardIn { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
.login-card .card-header { background: none; padding: 0; border: none; text-align: center; margin-bottom: 30px; display: block; }
.login-card .card-header h2 { font-size: 1.5rem; font-weight: 800; color: var(--color-text-primary); letter-spacing: -0.5px; margin-bottom: 4px; }
.login-card .card-header p { font-size: 0.8438rem; font-weight: 500; color: var(--color-text-secondary); }

.form-group { margin-bottom: 18px; }
.form-group label { font-size: 0.75rem; font-weight: 700; color: var(--color-text-primary); letter-spacing: 0.04em; text-transform: uppercase; margin-top: 0; margin-bottom: 7px; }
.input-wrapper { position: relative; display: flex; align-items: center; }
.input-wrapper > i { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); font-size: 1.15rem; color: var(--color-border); pointer-events: none; z-index: 2; transition: color var(--transition-fast); }
.input-wrapper input { padding: 0.85rem 2.5rem 0.85rem 2.5rem; }
.input-wrapper:focus-within > i { color: var(--thunder-700); }
/* The login card intentionally keeps the dark Thunderbird gradient theme
   (it mirrors the sidebar), so its own inputs keep that same red-toned
   focus ring rather than anything else. */
.login-card input:focus, .login-box input:focus { border-color: var(--thunder-600); box-shadow: 0 0 0 3px rgba(252,6,6,0.14); }
.toggle-password { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 36px; height: 36px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; background: transparent; border: none; border-radius: var(--radius-sm); cursor: pointer; color: var(--color-text-muted); z-index: 3; transition: all var(--transition-fast); }
.toggle-password:hover { color: var(--thunder-700); background: var(--thunder-50); }

.signin-btn { position: relative; overflow: hidden; width: 100%; padding: 0.8rem 1.25rem; margin-top: 6px; background: linear-gradient(135deg, var(--thunder-800) 0%, var(--thunder-600) 100%); color: #fff; font-family: inherit; font-size: 0.9375rem; font-weight: 700; letter-spacing: 0.01em; border: none; border-radius: var(--radius-sm); cursor: pointer; box-shadow: 0 4px 14px rgba(144,12,12,0.36); transition: transform var(--transition-fast), box-shadow var(--transition-fast); display: flex; align-items: center; justify-content: center; gap: 8px; }
.signin-btn::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg,transparent,rgba(255,255,255,0.2),transparent); transition: left 0.5s ease; }
.signin-btn:hover::before { left: 100%; }
.signin-btn:hover { transform: translateY(-2px); box-shadow: 0 8px 22px rgba(144,12,12,0.46); }
.signin-btn:active { transform: translateY(0); }

.login-forgot { text-align: center; margin-top: 14px; }
.login-forgot a { color: var(--color-text-muted); font-size: 0.8125rem; text-decoration: none; }
.login-forgot a:hover { color: var(--thunder-700); }
.login-help { text-align: center; margin-top: 18px; font-size: 0.75rem; color: var(--color-text-muted); }

/* ══ RESPONSIVE ══ */
@media (max-width: 1280px) {
    .stats-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
    .login-wrapper { flex-direction: column; justify-content: center; gap: 32px; padding: 32px 20px; }
    .login-left { flex: none; width: 100%; text-align: center; }
    .login-left .brand { justify-content: center; margin-bottom: 28px; }
    .login-slogan { min-height: 140px; }
    .login-slide p { margin: 0 auto; }
    .login-dots { justify-content: center; }
    .login-right { margin-left: 0; width: 100%; }
    .login-card { width: 100%; max-width: 380px; }
}
@media (max-width: 768px) {
    .sidebar { transform: translateX(-100%); width: var(--sidebar-width) !important; }
    .sidebar.open { transform: translateX(0); box-shadow: var(--shadow-lg); }
    .main-content { margin-left: 0 !important; }
    .content { padding: 1rem; }
    .user-profile-name, .user-profile-role { display: none; }
    .menu-toggle { display: flex; }
    .stats-grid { grid-template-columns: 1fr 1fr; gap: 0.75rem; }
    .stats-grid-3 { grid-template-columns: 1fr; gap: 0.75rem; }
    .stat-number, .stat-card .value { font-size: 1.4rem; }
    .chart-grid { grid-template-columns: 1fr; }
    .chart-grid-wide { grid-template-columns: 1fr; }
    .header { padding: 0 1rem; }
    .page-title { font-size: 0.9375rem; }

    table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; white-space: nowrap; }

    .card-header { flex-wrap: wrap; gap: 8px; }
    .form-row > div { min-width: 100%; }

    /* Pages with a bottom tab bar (see .mobile-tabbar below) get the
       full native-app treatment: the header hamburger disappears since
       "More" in the tab bar reaches the same drawer, the drawer itself
       drops the destinations already pinned to the tab bar so it reads
       as an overflow menu rather than a duplicate of it, and page
       content gets enough bottom clearance to never sit under the bar. */
    .has-mobile-tabbar .menu-toggle { display: none; }
    .has-mobile-tabbar .sidebar-collapse-btn { display: none; }
    .has-mobile-tabbar .sidebar .nav-item-primary,
    .has-mobile-tabbar .sidebar .nav-section-label-primary { display: none; }
    .has-mobile-tabbar .content { padding-bottom: calc(4.75rem + env(safe-area-inset-bottom)); }

    /* The subject picker, profile menu, and multiselect panels all pop
       up with z-index:200 -- comfortably above ordinary page content,
       but that used to also put them above the fixed tab bar (90),
       so an open dropdown near the bottom of a long page could cover
       the nav entirely. The tab bar now outranks every popover here
       (see z-index below), and panels get a viewport-relative height
       cap so they scroll internally instead of trying to occupy the
       space the bar needs. */
    .has-mobile-tabbar .qe-select-panel,
    .has-mobile-tabbar .multiselect-menu,
    .has-mobile-tabbar .user-dropdown-menu {
        max-height: min(280px, 45vh);
    }

    .mobile-tabbar {
        display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 205;
        background: rgba(255,255,255,0.96); backdrop-filter: saturate(180%) blur(14px);
        border-top: 1px solid var(--color-border);
        box-shadow: 0 -6px 20px -6px rgba(80,0,0,0.14);
        padding: 0.375rem 0.25rem calc(0.375rem + env(safe-area-inset-bottom));
    }
    .mobile-tabbar-item {
        flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
        gap: 3px; padding: 0.3rem 0.15rem; border: none; background: none; cursor: pointer;
        font-family: var(--font-sans); color: var(--stone-400); text-decoration: none !important;
        border-radius: var(--radius-sm); transition: color var(--transition-fast);
        position: relative;
    }
    .mobile-tabbar-item i { font-size: 1.2rem; line-height: 1; position: relative; z-index: 1; }
    .mobile-tabbar-item span { font-size: 0.625rem; font-weight: 600; letter-spacing: -0.01em; white-space: nowrap; }
    .mobile-tabbar-item:active { color: var(--sch-primary); }
    .mobile-tabbar-item.active { color: var(--sch-primary); }
    .mobile-tabbar-item.active::before {
        /* small filled pill behind the active icon, the way iOS/Android
           tab bars mark the current destination instead of just tinting
           the icon a different color. */
        content: ''; position: absolute; top: 1px; left: 50%; transform: translateX(-50%);
        width: 34px; height: 20px; background: var(--thunder-100); border-radius: var(--radius-full);
    }
}
@media (max-width: 480px) {
    .stats-grid { grid-template-columns: 1fr; }
    .card-title { font-size: 0.875rem; }
}
/* MULTISELECT (checkbox dropdown) — e.g. Assign Subject to Teacher */
.multiselect { position: relative; }
.multiselect-toggle {
    width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px;
    padding: 0.75rem 0.875rem; border: 1px solid var(--color-border); border-radius: var(--radius-sm);
    font-size: 0.9375rem; font-family: inherit; color: var(--color-text-primary); background: white;
    cursor: pointer; text-align: left; transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.multiselect-toggle:hover { border-color: var(--thunder-400); }
.multiselect-toggle span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.multiselect-toggle i { color: var(--color-text-muted); flex-shrink: 0; }
.multiselect-menu {
    /* position:fixed for the same reason as .qe-select-panel above --
       escapes the stacking context .card's entrance animation creates,
       so this can't get painted over by the next card in the page. */
    display: none; position: fixed; z-index: 200;
    background: white; border: 1px solid var(--color-border); border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg); max-height: 240px; overflow-y: auto; padding: 4px;
}
.multiselect-menu.show { display: block; animation: slideDown 0.15s ease; }
.multiselect-option {
    display: flex; align-items: center; gap: 8px; padding: 10px 10px; border-radius: var(--radius-sm);
    font-size: 0.9rem; font-weight: 500; cursor: pointer; margin: 0;
}
.multiselect-option:hover { background: var(--color-bg); }
.multiselect-option input[type="checkbox"] { width: auto; margin: 0; }
.multiselect-option-all { color: var(--sch-primary, var(--thunder-700)); }
.multiselect-divider { height: 1px; background: var(--color-border); margin: 4px 0; }

/* STAT CARD gender breakdown line (e.g. "32 Boys / 25 Girls" at a glance) */
.stat-breakdown { display: flex; gap: 14px; padding-top: 2px; }
.stat-breakdown-item { display: inline-flex; align-items: center; gap: 4px; font-size: 0.8rem; font-weight: 600; color: var(--color-text-secondary); }
.stat-breakdown-item i { font-size: 0.95rem; color: var(--color-text-muted); }

/* ============================================================
   SUBJECT COLOR CODING — 8 curated accents, deliberately outside
   the brand red / status green / status amber / info navy, so a
   subject tag never gets mistaken for a status. Picked from
   different points on the wheel (indigo -> teal -> plum -> cobalt
   -> terracotta -> olive -> cocoa -> steel) so 8 subjects sit next
   to each other without any two reading as "the same color".
   ============================================================ */
:root {
    --subj-1: #4338CA; --subj-1-bg: #EEF0FD; /* indigo */
    --subj-2: #0F766E; --subj-2-bg: #E6F5F3; /* teal */
    --subj-3: #A21CAF; --subj-3-bg: #FAE8FB; /* plum */
    --subj-4: #1D4ED8; --subj-4-bg: #E8F0FE; /* cobalt */
    --subj-5: #C2410C; --subj-5-bg: #FDEEE6; /* terracotta */
    --subj-6: #4D7C0F; --subj-6-bg: #F1F8E8; /* olive */
    --subj-7: #78350F; --subj-7-bg: #FBF3EA; /* cocoa */
    --subj-8: #475569; --subj-8-bg: #EEF2F6; /* steel */
}

/* Shared small "icon + label" pill used inside the score-entry preview
   below (Assignments / Attendance / Students / Remarks) and colored per
   the active subject via --subj-accent, set on an ancestor. */
.row-icon-btn {
    display: flex; align-items: center; gap: 5px; height: 38px; padding: 0 12px; border-radius: var(--radius-sm);
    background: var(--sch-card-header-bg); border: 1px solid var(--color-border); color: var(--color-text-secondary);
    font-size: 0.8125rem; font-weight: 600; white-space: nowrap; transition: all var(--transition-fast);
}
.row-icon-btn:hover { background: var(--subj-accent-bg); border-color: var(--subj-accent); color: var(--subj-accent); text-decoration: none; }
.row-icon-btn i { font-size: 1rem; flex-shrink: 0; }

.subject-row-locked { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: var(--color-text-muted); }

/* ============================================================
   SCORE-ENTRY PICKER (teacher "My Classes") — cascading Class ->
   Subject dropdowns that reveal one subject's actions at a time,
   replacing a full-detail row per subject/class combination.
   ============================================================ */
.qe-card { background: white; border: 1px solid var(--sch-card-border); border-radius: var(--radius); padding: 1.125rem; box-shadow: var(--shadow-sm); margin-bottom: 1.5rem; }
.qe-locked-banner { display: flex; align-items: center; gap: 8px; padding: 0.625rem 0.875rem; border-radius: var(--radius-sm); background: var(--sch-warning-bg); color: var(--sch-warning); font-size: 0.8125rem; font-weight: 600; margin-bottom: 0.875rem; }
.qe-locked-banner i { font-size: 1rem; flex-shrink: 0; }
.qe-intro { font-size: 0.8125rem; color: var(--color-text-secondary); margin-bottom: 0.875rem; }

.qe-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 0.875rem; }
.qe-field { min-width: 0; }
.qe-label { display: block; font-size: 0.75rem; font-weight: 700; color: var(--color-text-secondary); letter-spacing: 0.04em; text-transform: uppercase; margin-bottom: 6px; }

.qe-select { position: relative; }
/* When this wraps a real <select> (see custom-select.js, which
   auto-enhances every plain dropdown in the app), hide the native
   control -- it stays in the DOM as the actual source of truth for the
   field's value/name/required state, the custom trigger+panel below is
   just its on-brand skin. Hand-built pickers (score entry, etc.) have
   no <select> inside them, so this rule is a no-op there. */
.qe-select select { display: none; }
.qe-select-error-text { display: none; color: var(--sch-danger); font-size: 0.75rem; font-weight: 600; margin-top: 5px; }
.qe-select-invalid .qe-select-trigger { border-color: var(--sch-danger); box-shadow: 0 0 0 3px var(--thunder-100); }
.qe-select-invalid .qe-select-error-text { display: block; }
.qe-select-trigger {
    width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px;
    padding: 0.75rem 0.875rem; border: 1.5px solid var(--color-border); border-radius: var(--radius-sm);
    font-size: 0.9375rem; font-weight: 600; font-family: inherit; color: var(--color-text-primary); background: white;
    cursor: pointer; text-align: left; transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.qe-select-trigger:hover { border-color: var(--thunder-400); }
.qe-select.open .qe-select-trigger { border-color: var(--sch-primary); box-shadow: 0 0 0 3px var(--thunder-100); }
.qe-select-trigger:focus-visible { border-color: var(--thunder-700); box-shadow: 0 0 0 3px rgba(219,0,0,0.12); outline: none; }
.qe-select-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qe-select-value.is-placeholder { color: var(--color-text-muted); font-weight: 500; }
.qe-select-chevron { color: var(--color-text-muted); flex-shrink: 0; transition: transform var(--transition-fast); }
.qe-select.open .qe-select-chevron { transform: rotate(180deg); color: var(--sch-primary); }
.qe-select.is-disabled .qe-select-trigger { cursor: not-allowed; background: var(--sch-card-header-bg); color: var(--color-text-muted); }

.qe-select-panel {
    /* position:fixed (not absolute) so the panel escapes the local
       stacking context entirely -- .card and a few other containers
       play a one-time entrance animation with fill-mode:both, and per
       spec that gives the element its own stacking context for as long
       as the animation's end state is held (i.e. forever), which would
       otherwise trap this panel's z-index:200 *inside* that card and
       let the very next card in the DOM paint over it. Fixed
       positioning is anchored to the viewport, not any ancestor, so
       that trap doesn't apply. JS sets left/top (or bottom)/width per
       open, since fixed positioning has no relationship to the trigger
       without it. */
    display: none; position: fixed; z-index: 200;
    background: white; border: 1px solid var(--color-border); border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg); max-height: 280px; overflow-y: auto; padding: 5px;
}
.qe-select.open .qe-select-panel { display: block; animation: slideDown 0.15s ease; }
.qe-select.open .qe-select-panel.opens-up { animation: slideUpPanel 0.15s ease; }
.qe-select-option {
    width: 100%; display: flex; align-items: center; gap: 9px; padding: 10px 10px; border-radius: var(--radius-sm);
    font-size: 0.85rem; font-weight: 600; color: var(--color-text-primary); text-align: left;
    background: none; border: none; font-family: inherit; cursor: pointer; margin: 0;
}
.qe-select-option:hover { background: var(--color-bg); }
.qe-select-option:focus { background: var(--color-bg); outline: none; box-shadow: inset 0 0 0 2px var(--thunder-200); }
.qe-select-option.is-active { background: var(--sch-card-header-bg); }
.qe-option-tag {
    width: 26px; height: 26px; border-radius: 7px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 0.6875rem;
}
.qe-option-text { flex: 1; min-width: 0; }
.qe-option-code { font-weight: 600; font-size: 0.7rem; color: var(--color-text-muted); margin-left: 2px; }
.qe-option-meta { font-size: 0.7rem; color: var(--color-text-muted); font-weight: 500; flex-shrink: 0; }
.qe-option-check { color: var(--sch-primary); font-size: 1rem; flex-shrink: 0; }

/* Preview panel — revealed once both dropdowns above are answered.
   Mirrors the color-tag treatment used across the app for subjects. */
.qe-preview {
    display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-top: 1rem;
    padding: 0.875rem 1rem; border-radius: var(--radius-sm); border: 1px solid var(--sch-card-border);
    border-left: 4px solid var(--subj-accent); background: var(--sch-card-header-bg);
    animation: fadeInUp 0.2s ease both;
}
.qe-preview-tag {
    width: 40px; height: 40px; border-radius: var(--radius-sm); flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 0.8125rem; letter-spacing: 0.02em;
    background: var(--subj-accent-bg); color: var(--subj-accent);
}
.qe-preview-info { min-width: 180px; flex: 1 1 220px; }
.qe-preview-title { font-weight: 700; font-size: 0.9375rem; color: var(--color-text-primary); letter-spacing: -0.01em; }
.qe-preview-code { font-weight: 600; font-size: 0.75rem; color: var(--subj-accent); margin-left: 2px; }
.qe-preview-class { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: var(--color-text-secondary); margin-top: 2px; }
.qe-preview-count { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: var(--color-text-secondary); flex: 0 0 auto; white-space: nowrap; }
.qe-preview-count i { color: var(--subj-accent); font-size: 1rem; }
.qe-preview-count strong { color: var(--color-text-primary); font-weight: 700; }
.qe-preview-actions { display: flex; align-items: center; gap: 0.5rem; margin-left: auto; flex-shrink: 0; flex-wrap: wrap; }
.qe-preview-cta { margin-top: 0; white-space: nowrap; }
.qe-preview-icons { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* Compact reference grid below the picker — every class/subject combo as
   a small chip so nothing that was reachable before is lost, it's just
   no longer the primary (space-hungry) interaction. */
.qe-heading { margin-top: 0.25rem; }
.subject-chip-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 0.625rem; margin-bottom: 1.75rem; }
.subject-chip {
    display: flex; align-items: center; gap: 10px; padding: 0.625rem 0.75rem;
    background: white; border: 1px solid var(--sch-card-border); border-radius: var(--radius-sm);
    cursor: pointer; text-align: left; font-family: inherit; transition: all var(--transition-fast);
}
.subject-chip:hover { border-color: var(--subj-accent); box-shadow: var(--shadow-sm); transform: translateY(-1px); }
.subject-chip-tag {
    width: 32px; height: 32px; border-radius: 8px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 0.6875rem; background: var(--subj-accent-bg); color: var(--subj-accent);
}
.subject-chip-info { min-width: 0; }
.subject-chip-name { display: block; font-size: 0.8125rem; font-weight: 700; color: var(--color-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.subject-chip-class { display: block; font-size: 0.7rem; color: var(--color-text-secondary); font-weight: 500; }

@media (max-width: 640px) {
    .qe-fields { grid-template-columns: 1fr; }
    .qe-preview-actions, .qe-preview-count { margin-left: 0; width: 100%; }
    .qe-preview-count { padding: 0.375rem 0; border-top: 1px solid var(--color-border-subtle); border-bottom: 1px solid var(--color-border-subtle); }
    .qe-preview-actions { flex-direction: column; align-items: stretch; gap: 0.375rem; }
    .qe-preview-cta { font-size: 0.85rem; padding: 0.7rem 0.9rem; justify-content: center; }
    .qe-preview-icons { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; width: 100%; }
    .row-icon-btn { justify-content: center; height: 36px; font-size: 0.75rem; }
    .subject-chip-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 420px) {
    .subject-chip-grid { grid-template-columns: 1fr; }
}
/* ── Parent/Teacher Chat ─────────────────────────────────────── */
.chat-list-item {
    display: flex; align-items: center; gap: 12px; padding: 0.875rem 1.125rem;
    text-decoration: none; color: inherit; border-bottom: 1px solid var(--color-border-subtle);
    transition: background var(--transition-fast);
}
.chat-list-item:hover { background: var(--thunder-50); text-decoration: none; }
.chat-list-item:last-child { border-bottom: none; }
.chat-list-item-info { min-width: 0; flex: 1; }
.chat-list-item-name { font-weight: 700; font-size: 0.9rem; color: var(--color-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-list-item-meta { font-size: 0.78rem; color: var(--color-text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; }
.chat-list-item-preview { font-size: 0.8125rem; color: var(--color-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; }
.chat-unread-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--sch-danger); flex-shrink: 0; }
.chat-unread-count { background: var(--sch-danger); color: #fff; font-size: 0.7rem; font-weight: 700; border-radius: var(--radius-full); min-width: 20px; height: 20px; display: inline-flex; align-items: center; justify-content: center; padding: 0 5px; flex-shrink: 0; }

.chat-thread-wrap { display: flex; flex-direction: column; height: calc(100vh - 220px); min-height: 420px; background: white; border: 1px solid var(--sch-card-border); border-radius: var(--radius); overflow: hidden; }
.chat-thread-header { padding: 0.875rem 1.125rem; border-bottom: 1px solid var(--color-border); background: var(--sch-card-header-bg); display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.chat-thread-messages { flex: 1; overflow-y: auto; padding: 1rem; display: flex; flex-direction: column; gap: 8px; background: var(--stone-50, #fafaf9); }

.chat-bubble-row { display: flex; }
.chat-bubble-row.mine { justify-content: flex-end; }
.chat-bubble { max-width: 72%; padding: 0.55rem 0.8rem; border-radius: 14px; font-size: 0.875rem; line-height: 1.4; box-shadow: var(--shadow-sm); }
.chat-bubble-row:not(.mine) .chat-bubble { background: white; border: 1px solid var(--sch-card-border); border-bottom-left-radius: 4px; }
.chat-bubble-row.mine .chat-bubble { background: linear-gradient(135deg, var(--thunder-800) 0%, var(--thunder-600) 100%); color: #fff; border-bottom-right-radius: 4px; }
.chat-bubble-time { display: block; font-size: 0.68rem; margin-top: 3px; opacity: 0.7; }
.chat-bubble audio { width: 220px; max-width: 60vw; height: 34px; }

.chat-composer { display: flex; align-items: center; gap: 8px; padding: 0.75rem 1rem; border-top: 1px solid var(--color-border); background: white; flex-shrink: 0; }
.chat-composer input[type="text"] { flex: 1; margin: 0; }
.chat-composer .btn, .chat-composer .btn-sm { margin-top: 0; }
.chat-record-btn { width: 42px; height: 42px; border-radius: 50%; border: 1px solid var(--thunder-700); background: white; color: var(--thunder-800); display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; transition: all var(--transition-fast); }
.chat-record-btn:hover { background: var(--thunder-50); }
.chat-record-btn.recording { background: var(--sch-danger); border-color: var(--sch-danger); color: #fff; animation: pulseRecord 1s infinite; }
@keyframes pulseRecord { 0%, 100% { box-shadow: 0 0 0 0 rgba(220,38,38,0.4); } 50% { box-shadow: 0 0 0 8px rgba(220,38,38,0); } }
.chat-recording-indicator { font-size: 0.78rem; color: var(--sch-danger); font-weight: 700; display: flex; align-items: center; gap: 6px; }

@media (max-width: 640px) {
    .chat-thread-wrap { height: calc(100vh - 170px); }
    .chat-bubble { max-width: 85%; }
}
