/* ============================================================================
   Seven Hills Driving Academy — Shared Stylesheet
   Mobile-first. Navy + amber "driving school" palette. Poppins + Material
   Symbols. Designed to feel like a native app on phones/tablets.
   ============================================================================ */

:root {
    --shda-navy: #0f1f3d;
    --shda-navy-dark: #0a1529;
    --shda-navy-light: #1c2f57;
    --shda-amber: #f5a623;
    --shda-amber-dark: #d68c0f;
    --shda-amber-soft: #fef3e2;
    --shda-bg: #f4f6fb;
    --shda-card-bg: #ffffff;
    --shda-border: #e5e8f0;
    --shda-input-border: #adb5c4;
    --shda-text: #1c2333;
    --shda-text-muted: #6b7280;
    --shda-danger: #d64545;
    --shda-danger-soft: #fdecec;
    --shda-success: #1f9d55;
    --shda-success-soft: #e9f8ef;
    --shda-info: #2f7fd6;
    --shda-info-soft: #eaf3fd;

    --shda-header-navy: #0e2862;
    --shda-btn-primary: #ff6a20;
    --shda-btn-primary-dark: #cc551a;

    --shda-radius-sm: 0.5rem;
    --shda-control-radius: 5px;
    --shda-radius: 0.9rem;
    --shda-radius-lg: 1.25rem;

    --shda-shadow-sm: 0 1px 2px rgba(15, 31, 61, 0.05), 0 1px 3px rgba(15, 31, 61, 0.06);
    --shda-shadow: 0 4px 10px rgba(15, 31, 61, 0.06), 0 2px 4px rgba(15, 31, 61, 0.05);
    --shda-shadow-lg: 0 12px 32px rgba(15, 31, 61, 0.14);

    --shda-transition: 160ms cubic-bezier(0.4, 0, 0.2, 1);
    --shda-bottom-tabbar-height: 64px;
    /* Base navbar height (0.65rem padding top+bottom + its content) plus
       whatever the iOS status bar/notch actually needs — env() resolves to
       0 on Android, desktop, and regular (non-PWA) Safari, so this is
       exactly 64px everywhere except an installed iOS home-screen app on a
       device with a status bar to clear. Consumers that position something
       just below the navbar (search modal, chat panel) read this instead
       of a hardcoded 64px so they stay correctly placed on notched phones
       too — see .shda-navbar's own padding-top below for the actual fix. */
    --shda-navbar-height: calc(64px + env(safe-area-inset-top));
}

* {
    -webkit-tap-highlight-color: transparent;
}

/* Bootstrap's display utilities (.d-flex, .d-block, .d-grid, ...) carry
   !important, which silently wins over the plain [hidden] { display: none }
   the browser applies by default — so any element toggled with the HTML
   `hidden` attribute while also carrying one of those classes (e.g.
   index.php's #customRangeFields, "d-flex ... hidden") stays visible
   regardless of the hidden attribute. Confirmed live via headless Chromium:
   the Dashboard's Custom Range Start/End fields showed even when Period
   wasn't "Custom Range", pushing Apply off the right edge of the screen on
   a real 393px-wide viewport. This app-wide rule makes `hidden` win again,
   the same fix already applied once before for Schedule Session's
   hidden-vs-required fields (see project memory) — same underlying cascade
   gotcha, different symptom. */
[hidden] {
    display: none !important;
}

html, body {
    height: 100%;
}

html {
    /* Defensive safety net: nothing in this app should legitimately need
       to scroll sideways, so a stray over-wide element on a narrow phone
       gets clipped instead of quietly widening the page. Deliberately set
       on <html>, not <body> — forcing overflow-x on body computes its
       overflow-y to auto too (an unrelated corner of the CSS overflow
       spec), turning body into its own nested scroll container, which is
       a known way to break this app's sticky top navbar (position: sticky
       tracks the nearest scrolling ancestor) — worst of all in Safari.
       <html> doesn't have that problem since it's already the root
       scroller. */
    overflow-x: hidden;
}

body {
    max-width: 100%;
}

img, svg, video {
    max-width: 100%;
    height: auto;
}

body {
    background-color: var(--shda-bg);
    color: var(--shda-text);
    font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 0.95rem;
}

h1, h2, h3, h4, h5, h6 {
    font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-weight: 600;
}

body.has-bottom-tabbar {
    padding-bottom: calc(var(--shda-bottom-tabbar-height) + env(safe-area-inset-bottom));
}

/* Root cause of fields becoming invisible/unusable behind the fixed bottom
   tab bar on mobile (reported via Add Expense, but this is a page-agnostic
   layout bug — any form field can land here): padding-bottom above only
   reserves enough scroll room to get PAST the tab bar at the very end of
   the page, but the browser has no idea the tab bar visually covers the
   bottom ~64px of EVERY scroll position, not just the last one. When a
   field is focused (tapping into an input triggers the browser's own
   native "scroll this into view" behavior) or something runs
   scrollIntoView() programmatically, the browser can happily land a field
   exactly where the fixed tab bar is sitting on top of it. scroll-padding
   tells the browser "treat this much of the viewport edge as already
   taken" for exactly that class of scroll, so focusing/scrolling to a
   field now stops with it sitting above the tab bar instead of under it.
   Set on both html and body since different browsers/layouts treat either
   as the actual document scroll container. */
@media (max-width: 767.98px) {
    html:has(body.has-bottom-tabbar),
    body.has-bottom-tabbar {
        scroll-padding-bottom: calc(var(--shda-bottom-tabbar-height) + env(safe-area-inset-bottom) + 0.5rem);
    }
}

a {
    color: var(--shda-navy);
    transition: color var(--shda-transition);
}

::selection {
    background-color: var(--shda-amber);
    color: var(--shda-navy-dark);
}

/* One consistent keyboard-focus ring reused on every interactive element
   (buttons, links, chips, tabs, sortable headers) instead of whatever
   color each Bootstrap component defaults to on its own — layers on top
   of a component's own focus style rather than replacing it, so nothing
   that already has a focus treatment loses it. Only shows for keyboard
   focus (:focus-visible), never on a mouse/touch click. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
.shda-tab:focus-visible,
.shda-filter-chip:focus-visible,
.shda-admin-subnav-link:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--shda-btn-primary);
    outline-offset: 2px;
    border-radius: var(--shda-control-radius);
}

/* ----------------------------------------------------------------------
   Material Symbols — consistent, evenly-weighted outline icons everywhere
   ---------------------------------------------------------------------- */

.material-symbols-outlined {
    font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
    font-size: 1.2em;
    line-height: 1;
    vertical-align: -0.2em;
    display: inline-block;
    user-select: none;
}

/* ----------------------------------------------------------------------
   Top navbar
   ---------------------------------------------------------------------- */

.shda-navbar {
    background-color: var(--shda-navy);
    /* env(safe-area-inset-top) is 0 on Android/desktop/a regular Safari tab
       (no change there) and only non-zero on an installed iOS home-screen
       app, where apple-mobile-web-app-status-bar-style=black-translucent
       (see includes/header.php) makes the status bar overlay page content
       by design — this padding is what actually keeps the logo/hamburger/
       notification icons below the time/signal/battery row instead of
       behind it, on both notched and non-notched iPhones alike. */
    padding-top: calc(0.65rem + env(safe-area-inset-top));
    padding-bottom: 0.65rem;
    box-shadow: 0 2px 8px rgba(15, 31, 61, 0.25);
}

/* Desktop nav overflow safety net — confirmed via headless Chromium at
   768px/1024px: a Super Admin/Admin account (every module + a long user-
   menu with avatar/name/role badge) makes the nav's natural content width
   (~1400px+) exceed the viewport with nothing to shrink or wrap it,
   pushing the WHOLE PAGE into horizontal scroll on any tablet/small-laptop
   width between 768px and roughly 1400px. Flex children default to
   min-width:auto (won't shrink below content), so min-width:0 has to be
   threaded through the chain; the module list then scrolls horizontally
   within itself instead of widening the page — same idea as the mobile
   bottom-tabbar fix above, one desktop-nav-width tier up. */
.shda-navbar .container-fluid {
    min-width: 0;
}

.shda-navbar .d-md-flex {
    min-width: 0;
}

.shda-navbar .navbar-nav.me-auto {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    min-width: 0;
}

.shda-navbar .navbar-nav.me-auto .nav-link {
    white-space: nowrap;
}

.shda-navbar .navbar-brand {
    display: flex;
    align-items: center;
    padding-top: 0;
    padding-bottom: 0;
}

.shda-brand-chip {
    display: inline-flex;
    align-items: center;
    background-color: #ffffff;
    border-radius: var(--shda-radius-sm);
    padding: 0.3rem 0.6rem;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}

.shda-brand-chip img {
    height: 28px;
    width: auto;
    max-width: none;
    display: block;
}

.shda-navbar .nav-link {
    color: rgba(255, 255, 255, 0.82);
    font-weight: 500;
    padding-left: 0.85rem;
    padding-right: 0.85rem;
    border-radius: var(--shda-radius-sm);
    display: flex;
    align-items: center;
    gap: 0.4rem;
    transition: background-color var(--shda-transition), color var(--shda-transition);
}

.shda-navbar .nav-link:hover,
.shda-navbar .nav-link:focus {
    color: #ffffff;
    background-color: rgba(255, 255, 255, 0.08);
}

.shda-navbar .nav-link.active {
    color: #ffffff;
    background-color: var(--shda-navy-light);
}

.shda-navbar .navbar-toggler {
    color: #ffffff;
    border: none;
    font-size: 1.5rem;
    padding: 0.15rem 0.4rem;
    line-height: 1;
}

.shda-navbar .navbar-toggler:focus {
    /* Drop Bootstrap's default box-shadow ring (too heavy against the navy
       bar) but keep a real, visible focus indicator for keyboard users —
       removing it outright with nothing in its place fails "proper focus
       states" the moment someone tabs to this button. */
    box-shadow: none;
    outline: 2px solid rgba(255, 255, 255, 0.7);
    outline-offset: 2px;
    border-radius: var(--shda-radius-sm);
}

.shda-role-badge {
    background-color: var(--shda-amber);
    color: var(--shda-navy-dark);
    font-weight: 600;
    font-size: 0.65rem;
    vertical-align: middle;
    border-radius: 999px;
    padding: 0.25em 0.6em;
}

.shda-notif-badge {
    position: absolute;
    top: 0.15rem;
    right: 0.1rem;
    background-color: var(--shda-danger);
    color: #ffffff;
    font-weight: 600;
    font-size: 0.6rem;
    line-height: 1;
    border-radius: 999px;
    padding: 0.25em 0.45em;
}

.shda-notif-badge-inline {
    position: static;
    margin-left: 0.4rem;
}

.shda-notif-dropdown {
    width: 340px;
    max-width: calc(100vw - 2rem);
    padding: 0;
}

.shda-notif-item {
    white-space: normal;
    padding: 0.6rem 1rem;
    border-bottom: 1px solid var(--shda-border);
}

.shda-notif-item:last-of-type {
    border-bottom: none;
}

.shda-notif-unread {
    background-color: var(--shda-bg);
    position: relative;
}

.shda-notif-unread::before {
    content: '';
    position: absolute;
    left: 0.35rem;
    top: 1rem;
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background-color: var(--shda-danger);
}

.shda-notif-card-unread {
    border-left: 3px solid var(--shda-danger);
}

/* ----------------------------------------------------------------------
   Toasts — client-side success/error notifications for actions that don't
   round-trip through the server (so can't use the flash_set() banner),
   e.g. the admin Clear Cache action.
   ---------------------------------------------------------------------- */
.shda-toast {
    color: #ffffff;
    border: none;
    border-radius: var(--shda-radius-sm);
    box-shadow: var(--shda-shadow-lg);
}

.shda-toast-success { background-color: var(--shda-success); }
.shda-toast-error { background-color: var(--shda-danger); }
.shda-toast-info { background-color: var(--shda-info); }

/* ----------------------------------------------------------------------
   Global Search
   ---------------------------------------------------------------------- */

.shda-search-toggle-btn {
    border: 0;
    background: transparent;
    line-height: 1;
}

.shda-search-modal-content {
    border-radius: var(--shda-radius-lg);
    overflow: hidden;
}

.shda-search-modal-content .modal-header {
    gap: 0.5rem;
    border-bottom: 1px solid var(--shda-border);
}

.shda-search-input-wrap {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--shda-text-muted);
    border: 1.5px solid var(--shda-navy);
    border-radius: var(--shda-control-radius);
    padding: 0.4rem 0.75rem;
}

.shda-search-input-wrap:focus-within {
    border-color: var(--shda-amber);
    box-shadow: 0 0 0 0.2rem rgba(245, 166, 35, 0.2);
}

.shda-search-input-wrap input {
    border: 0;
    outline: none;
    flex: 1 1 auto;
    font-size: 1.05rem;
    padding: 0.25rem 0;
    background: transparent;
}

.shda-search-results {
    max-height: 60vh;
    overflow-y: auto;
    padding: 0.5rem 0;
}

.shda-search-category {
    padding: 0.25rem 0 0.5rem;
}

.shda-search-category-label {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--shda-text-muted);
    padding: 0.25rem 1.5rem;
}

.shda-search-result-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 1.5rem;
    color: var(--shda-text);
    text-decoration: none;
    transition: background-color var(--shda-transition);
}

.shda-search-result-item:hover,
.shda-search-result-item.is-active {
    background-color: var(--shda-amber-soft);
    color: var(--shda-text);
}

.shda-search-result-item .material-symbols-outlined {
    color: var(--shda-text-muted);
    flex-shrink: 0;
}

.shda-search-result-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.shda-search-result-label {
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.shda-search-result-sub {
    font-size: 0.8rem;
    color: var(--shda-text-muted);
}

@media (max-width: 575.98px) {
    .shda-search-results {
        max-height: 70vh;
    }
}

/* ----------------------------------------------------------------------
   Internal Chat / Messaging
   ---------------------------------------------------------------------- */

.shda-chat-toggle-btn {
    border: 0;
    background: transparent;
    line-height: 1;
}

.shda-chat-backdrop {
    position: fixed;
    inset: 0;
    background-color: rgba(15, 31, 61, 0.35);
    z-index: 1050;
}

.shda-chat-panel {
    position: fixed;
    top: calc(var(--shda-navbar-height, 64px) + 0.5rem);
    right: 1rem;
    width: 400px;
    max-width: calc(100vw - 2rem);
    height: min(640px, calc(100vh - var(--shda-navbar-height, 64px) - 1.5rem));
    background-color: var(--shda-card-bg);
    border-radius: var(--shda-radius);
    box-shadow: var(--shda-shadow-lg);
    z-index: 1051;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

@media (max-width: 767.98px) {
    .shda-chat-panel {
        top: 0;
        right: 0;
        width: 100%;
        max-width: 100%;
        height: 100%;
        border-radius: 0;
    }

    /* On mobile the chat panel goes full-screen (above), so its own header
       sits at the physical top edge just like the offcanvas menu — same
       safe-area fix, only needed in this mobile tier since the desktop
       floating panel never touches the top edge. */
    .shda-chat-panel-header {
        padding-top: calc(0.85rem + env(safe-area-inset-top));
    }
}

.shda-chat-panel-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.85rem 1rem;
    background-color: var(--shda-header-navy);
    color: #ffffff;
    flex-shrink: 0;
}

.shda-chat-panel-header .shda-chat-icon-btn {
    color: #ffffff;
}

.shda-chat-panel-title {
    font-weight: 600;
    flex-grow: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.shda-chat-icon-btn {
    border: 0;
    background: transparent;
    color: var(--shda-text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: 50%;
    flex-shrink: 0;
}

.shda-chat-icon-btn:hover,
.shda-chat-icon-btn:focus-visible {
    background-color: rgba(255, 255, 255, 0.15);
}

.shda-chat-panel-header .shda-chat-icon-btn:hover,
.shda-chat-panel-header .shda-chat-icon-btn:focus-visible {
    background-color: rgba(255, 255, 255, 0.15);
}

.shda-chat-view {
    display: flex;
    flex-direction: column;
    min-height: 0;
    flex-grow: 1;
}

.shda-chat-search-wrap {
    padding: 0.75rem 1rem 0.5rem;
    flex-shrink: 0;
}

.shda-chat-tabs {
    display: flex;
    gap: 0.35rem;
    padding: 0 1rem 0.6rem;
    flex-shrink: 0;
}

.shda-chat-tab-btn {
    border: 1px solid var(--shda-border);
    background-color: var(--shda-card-bg);
    color: var(--shda-text-muted);
    font-size: 0.8rem;
    font-weight: 600;
    padding: 0.3rem 0.75rem;
    border-radius: 999px;
}

.shda-chat-tab-btn.active {
    background-color: var(--shda-navy);
    border-color: var(--shda-navy);
    color: #ffffff;
}

.shda-chat-conversation-list {
    flex-grow: 1;
    overflow-y: auto;
    min-height: 0;
}

.shda-chat-conv-item {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    width: 100%;
    padding: 0.65rem 1rem;
    border: 0;
    border-bottom: 1px solid var(--shda-border);
    background-color: transparent;
    text-align: left;
}

.shda-chat-conv-item:hover,
.shda-chat-conv-item:focus-visible {
    background-color: var(--shda-bg);
}

.shda-chat-conv-item.shda-chat-conv-unread {
    background-color: var(--shda-amber-soft);
}

.shda-chat-conv-body {
    flex-grow: 1;
    min-width: 0;
}

.shda-chat-conv-top-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
}

.shda-chat-conv-name {
    font-weight: 600;
    color: var(--shda-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.shda-chat-conv-unread .shda-chat-conv-name {
    font-weight: 700;
}

.shda-chat-conv-time {
    font-size: 0.7rem;
    color: var(--shda-text-muted);
    white-space: nowrap;
    flex-shrink: 0;
}

.shda-chat-conv-preview {
    font-size: 0.82rem;
    color: var(--shda-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.shda-chat-conv-unread .shda-chat-conv-preview {
    color: var(--shda-text);
    font-weight: 600;
}

.shda-chat-unread-dot {
    width: 9px;
    height: 9px;
    border-radius: 999px;
    background-color: var(--shda-danger);
    flex-shrink: 0;
    margin-top: 0.4rem;
}

.shda-chat-avatar {
    width: 2.4rem;
    height: 2.4rem;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    background-color: var(--shda-bg);
}

.shda-chat-avatar-placeholder {
    width: 2.4rem;
    height: 2.4rem;
    border-radius: 50%;
    background-color: var(--shda-navy);
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    flex-shrink: 0;
}

.shda-chat-empty-state,
.shda-chat-loading-state,
.shda-chat-error-state {
    padding: 2.5rem 1.5rem;
    text-align: center;
    color: var(--shda-text-muted);
}

.shda-chat-error-state {
    color: var(--shda-danger);
}

.shda-chat-recipient-list {
    flex-grow: 1;
    overflow-y: auto;
    min-height: 0;
}

.shda-chat-recipient-item {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    width: 100%;
    padding: 0.6rem 1rem;
    border: 0;
    border-bottom: 1px solid var(--shda-border);
    background-color: transparent;
    text-align: left;
}

.shda-chat-recipient-item:hover,
.shda-chat-recipient-item:focus-visible {
    background-color: var(--shda-bg);
}

.shda-chat-thread-header {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 1rem;
    border-bottom: 1px solid var(--shda-border);
    flex-shrink: 0;
}

.shda-chat-thread-header .shda-chat-conv-name {
    font-size: 0.95rem;
}

.shda-chat-thread-inactive-note {
    font-size: 0.72rem;
    color: var(--shda-text-muted);
}

.shda-chat-messages {
    flex-grow: 1;
    overflow-y: auto;
    min-height: 0;
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    background-color: var(--shda-bg);
}

.shda-chat-bubble-row {
    display: flex;
    flex-direction: column;
    max-width: 78%;
}

.shda-chat-bubble-row.shda-chat-bubble-mine {
    align-self: flex-end;
    align-items: flex-end;
}

.shda-chat-bubble-row.shda-chat-bubble-theirs {
    align-self: flex-start;
    align-items: flex-start;
}

.shda-chat-bubble {
    padding: 0.5rem 0.8rem;
    border-radius: var(--shda-radius);
    font-size: 0.88rem;
    white-space: pre-wrap;
    word-break: break-word;
}

.shda-chat-bubble-mine .shda-chat-bubble {
    background-color: var(--shda-navy);
    color: #ffffff;
    border-bottom-right-radius: 0.25rem;
}

.shda-chat-bubble-theirs .shda-chat-bubble {
    background-color: #ffffff;
    color: var(--shda-text);
    border: 1px solid var(--shda-border);
    border-bottom-left-radius: 0.25rem;
}

.shda-chat-bubble-time {
    font-size: 0.68rem;
    color: var(--shda-text-muted);
    margin-top: 0.2rem;
    padding: 0 0.2rem;
}

.shda-chat-compose {
    display: flex;
    align-items: flex-end;
    gap: 0.5rem;
    padding: 0.65rem 0.85rem;
    border-top: 1px solid var(--shda-border);
    flex-shrink: 0;
    background-color: var(--shda-card-bg);
}

.shda-chat-compose textarea {
    flex-grow: 1;
    resize: none;
    max-height: 6rem;
}

/* ----------------------------------------------------------------------
   Offcanvas menu
   ---------------------------------------------------------------------- */

.offcanvas {
    border: none;
    box-shadow: var(--shda-shadow-lg);
}

.offcanvas-header {
    background-color: var(--shda-navy);
    color: #ffffff;
    /* Same iOS status-bar overlay issue as .shda-navbar above — the
       offcanvas menu is its own full-height fixed panel with its own
       header (title + close button), independent of the navbar, so it
       needs the same safe-area padding or its close button ends up behind
       the status bar too on an installed iOS home-screen app. */
    padding-top: calc(1rem + env(safe-area-inset-top));
}

.offcanvas-header .btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
}

.offcanvas-body .nav-link {
    color: var(--shda-text);
    border-radius: var(--shda-radius-sm);
    padding: 0.7rem 0.85rem;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    transition: background-color var(--shda-transition);
}

.offcanvas-body .nav-link:hover {
    background-color: var(--shda-bg);
}

.offcanvas-body .nav-link .material-symbols-outlined {
    color: var(--shda-navy);
    width: 1.4rem;
    text-align: center;
    font-size: 1.3rem;
}

.offcanvas-body .nav-pills .nav-link.active {
    background-color: var(--shda-navy);
    color: #ffffff;
}

.offcanvas-body .nav-pills .nav-link.active .material-symbols-outlined {
    color: var(--shda-amber);
}

/* ----------------------------------------------------------------------
   Modals (Bootstrap) — iOS safe-area + dynamic-viewport fixes
   ---------------------------------------------------------------------- */
/* Root cause of "can't close any modal on iPhone": every modal in this app
   (12+ of them, all plain Bootstrap .modal/.modal-header markup — see
   includes/footer.php, sessions/calendar.php, students/_form.php,
   students/view.php, sessions/list.php, admin/backup.php,
   admin/session_requests.php, includes/terms_and_conditions_modal.php) is a
   position:fixed element starting at top:0, same as .shda-navbar before its
   own safe-area fix — on an installed iOS home-screen app (where
   apple-mobile-web-app-status-bar-style=black-translucent makes the status
   bar overlay page content by design, see includes/header.php), the modal's
   own header — which is where the Close/X button lives — rendered right
   under the time/signal/battery row, same failure as the header bug, just
   repeated once per modal instead of fixed once at a shared layer. Fixing
   it here, on Bootstrap's own .modal-header/.modal-footer classes rather
   than any individual modal's markup, fixes all of them at once and any
   future modal built the normal way automatically inherits it too. */
.modal-header {
    padding-top: calc(1rem + env(safe-area-inset-top));
}

.modal-footer {
    padding-bottom: calc(0.75rem + env(safe-area-inset-bottom));
}

/* iOS Safari's address/toolbar chrome shrinks the visual viewport without
   resizing 100vh (which Bootstrap's own .modal rule uses, pinned to the
   larger layout viewport) — on a tall form-in-modal this could position
   the dialog (and its header/Close button) against a viewport height that
   no longer matches what's actually visible once the chrome has
   collapsed/expanded, or a keyboard has opened. dvh tracks the real visible
   area instead; older browsers without dvh support simply ignore this line
   and keep Bootstrap's own 100vh behavior exactly as before. */
.modal {
    height: 100dvh;
}

/* ----------------------------------------------------------------------
   Main content area
   ---------------------------------------------------------------------- */

.shda-main {
    min-height: calc(100vh - 64px);
    /* iOS Safari's address/toolbar chrome shrinks the visual viewport
       without resizing 100vh, which is pinned to the larger layout
       viewport — dvh tracks the actual visible area instead. Older
       browsers without dvh support simply ignore this line and keep the
       100vh value above. */
    min-height: calc(100dvh - 64px);
    /* 90% keeps comfortable side margins at typical desktop widths, but on
       a large/ultra-wide monitor that alone would let tables and forms
       stretch to 2000px+ — capping the absolute width too keeps line
       lengths and table columns readable no matter how wide the display. */
    max-width: min(90%, 1600px) !important;
    display: flex;
    flex-direction: column;
}

.shda-breadcrumb-nav {
    margin-bottom: 0.5rem;
}

.shda-breadcrumb {
    margin-bottom: 0;
    padding: 0;
    background: transparent;
    font-size: 0.85rem;
    flex-wrap: wrap;
}

.shda-breadcrumb .breadcrumb-item a {
    color: var(--shda-text-muted);
    text-decoration: none;
}

.shda-breadcrumb .breadcrumb-item a:hover {
    color: var(--shda-btn-primary);
    text-decoration: underline;
}

.shda-breadcrumb .breadcrumb-item.active {
    color: var(--shda-text-muted);
}

/* PWA "Install this app" banner — see initInstallPrompt() in app.js. */
.shda-install-banner {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    background: var(--shda-card-bg);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius);
    box-shadow: var(--shda-shadow-sm);
    padding: 0.75rem 1rem;
    margin-bottom: 1.25rem;
}

.shda-install-banner-icon {
    width: 40px;
    height: 40px;
    border-radius: var(--shda-radius-sm);
    flex-shrink: 0;
}

.shda-install-banner-text {
    flex: 1 1 auto;
    min-width: 0;
}

.shda-install-banner-title {
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--shda-navy);
}

.shda-install-banner-sub {
    font-size: 0.8rem;
    color: var(--shda-text-muted);
}

.shda-install-banner-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-shrink: 0;
}

.shda-page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 1.25rem;
}

.shda-page-header h1 {
    font-size: 1.4rem;
    font-weight: 700;
    margin: 0;
    letter-spacing: -0.01em;
}

/* ----------------------------------------------------------------------
   Cards, buttons, forms — shared app-like polish
   ---------------------------------------------------------------------- */

.card {
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius);
    box-shadow: var(--shda-shadow-sm);
}

.card-header {
    background-color: var(--shda-header-navy);
    color: #ffffff;
    border-bottom: 1px solid var(--shda-border);
    border-top-left-radius: var(--shda-radius) !important;
    border-top-right-radius: var(--shda-radius) !important;
    padding: 0.9rem 1.1rem;
}

.card-header .btn-outline-secondary {
    color: #ffffff;
    border-color: rgba(255, 255, 255, 0.6);
    background-color: transparent;
}

.card-header .btn-outline-secondary:hover,
.card-header .btn-outline-secondary:focus {
    background-color: rgba(255, 255, 255, 0.2);
    border-color: #ffffff;
    color: #ffffff;
}

/* A toggle button group in a card-header (e.g. the dashboard chart's date
   range filter) needs its selected button to stay visibly different from
   the rest — the extra .active class here outweighs the plain
   ".card-header .btn-outline-secondary" rule above on specificity, so it
   wins regardless of stylesheet order. */
.card-header .btn-outline-secondary.active {
    background-color: #ffffff;
    border-color: #ffffff;
    color: var(--shda-header-navy);
}

.btn {
    border-radius: var(--shda-control-radius);
    font-weight: 500;
    transition: transform var(--shda-transition), box-shadow var(--shda-transition), background-color var(--shda-transition), border-color var(--shda-transition);
}

.btn:active {
    transform: scale(0.97);
}

.btn .material-symbols-outlined {
    font-size: 1.15em;
}

.btn-shda-primary {
    background-color: var(--shda-btn-primary);
    border: none;
    color: #ffffff;
    font-weight: 600;
    box-shadow: 0 2px 8px rgba(255, 106, 32, 0.35);
}

/* Overall Driving Progress bar (Student View) — same brand color as the
   primary buttons, on top of Bootstrap's own .progress/.progress-bar. */
.progress-bar-shda {
    background-color: var(--shda-btn-primary);
}

.btn-shda-primary:hover,
.btn-shda-primary:focus {
    background-color: var(--shda-btn-primary-dark);
    color: #ffffff;
}

.form-control, .form-select {
    border-radius: var(--shda-control-radius);
    border-color: var(--shda-input-border);
    padding-top: 0.55rem;
    padding-bottom: 0.55rem;
    font-size: 14px;
    transition: border-color var(--shda-transition), box-shadow var(--shda-transition);
}

.form-control:focus, .form-select:focus {
    border-color: var(--shda-amber);
    box-shadow: 0 0 0 0.2rem rgba(245, 166, 35, 0.2);
}

.form-control::placeholder {
    color: #6B7280;
    opacity: 1;
}

.form-check-input {
    border: 1.5px solid var(--shda-navy);
}

.form-check-input:checked {
    background-color: var(--shda-navy);
    border-color: var(--shda-navy);
}

.form-check-input:focus {
    border-color: var(--shda-amber);
    box-shadow: 0 0 0 0.2rem rgba(245, 166, 35, 0.2);
}

.form-label {
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--shda-text);
    margin-bottom: 0.35rem;
}

.badge {
    font-weight: 600;
    letter-spacing: 0.01em;
}

.list-group-item {
    border-color: var(--shda-border);
}

.list-group-item-action:hover {
    background-color: var(--shda-bg);
}

.list-group-item.list-group-item-action.active {
    background-color: var(--shda-header-navy);
    border-color: var(--shda-header-navy);
    color: #ffffff;
}

.alert {
    border: none;
    border-radius: var(--shda-radius);
    box-shadow: var(--shda-shadow-sm);
}

/* ----------------------------------------------------------------------
   Admin section sub-nav
   ---------------------------------------------------------------------- */

.shda-admin-subnav {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    padding-bottom: 0.25rem;
    -webkit-overflow-scrolling: touch;
}

.shda-admin-subnav-link {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    white-space: nowrap;
    padding: 0.5rem 1rem;
    border-radius: 999px;
    background-color: var(--shda-card-bg);
    border: 1px solid var(--shda-border);
    color: var(--shda-text);
    font-weight: 500;
    font-size: 0.85rem;
    text-decoration: none;
    transition: background-color var(--shda-transition), color var(--shda-transition), border-color var(--shda-transition);
}

.shda-admin-subnav-link:hover {
    background-color: var(--shda-bg);
    color: var(--shda-text);
}

.shda-admin-subnav-link.active {
    background-color: var(--shda-navy);
    border-color: var(--shda-navy);
    color: #ffffff;
}

.shda-admin-subnav-link .material-symbols-outlined {
    font-size: 1.1rem;
}

/* ----------------------------------------------------------------------
   Permission matrix (Roles & Permissions)
   ---------------------------------------------------------------------- */

.shda-permission-matrix th,
.shda-permission-matrix td {
    text-align: center;
    vertical-align: middle;
}

.shda-permission-matrix th:first-child,
.shda-permission-matrix td:first-child {
    text-align: left;
}

.shda-permission-matrix .form-check {
    display: flex;
    justify-content: center;
    margin: 0;
}

.shda-permission-matrix .form-check-input {
    width: 1.2em;
    height: 1.2em;
    cursor: pointer;
}

.shda-permission-matrix .form-check-input:disabled {
    opacity: 0.25;
    cursor: not-allowed;
}

.shda-permission-matrix tbody tr:hover {
    background-color: var(--shda-bg);
}

/* ----------------------------------------------------------------------
   KPI stat cards
   ---------------------------------------------------------------------- */

.shda-stat-card {
    background: linear-gradient(155deg, var(--shda-card-bg) 60%, var(--shda-amber-soft) 160%);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius);
    padding: 1.1rem 1.2rem;
    height: 100%;
    box-shadow: var(--shda-shadow-sm);
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    transition: transform var(--shda-transition), box-shadow var(--shda-transition);
}

.shda-stat-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shda-shadow);
}

.shda-stat-card .shda-stat-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.5rem;
}

.shda-stat-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.6rem;
    height: 2.6rem;
    border-radius: var(--shda-radius-sm);
    background-color: var(--shda-amber-soft);
    color: var(--shda-amber-dark);
    flex-shrink: 0;
}

.shda-stat-icon .material-symbols-outlined {
    font-size: 1.4rem;
    vertical-align: middle;
}

.shda-stat-icon.is-navy { background-color: rgba(15, 31, 61, 0.08); color: var(--shda-navy); }
.shda-stat-icon.is-success { background-color: var(--shda-success-soft); color: var(--shda-success); }
.shda-stat-icon.is-danger { background-color: var(--shda-danger-soft); color: var(--shda-danger); }
.shda-stat-icon.is-info { background-color: var(--shda-info-soft); color: var(--shda-info); }

.shda-stat-card .shda-stat-label {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--shda-text-muted);
}

.shda-stat-card .shda-stat-value {
    font-size: 1.55rem;
    font-weight: 700;
    color: var(--shda-navy);
    line-height: 1.15;
}

.shda-stat-card .shda-stat-sub {
    font-size: 0.8rem;
    color: var(--shda-text-muted);
}

.text-shda-danger { color: var(--shda-danger) !important; }
.text-shda-success { color: var(--shda-success) !important; }

/* Revenue vs Expenses dashboard chart — fixed-height container so
   Chart.js (maintainAspectRatio:false) fills it at any width; shorter on
   phones, see the mobile override in the max-width:767.98px block below. */
.shda-chart-wrap {
    position: relative;
    height: 320px;
}

/* ----------------------------------------------------------------------
   Responsive tables: on screens under 768px, a table wrapped in
   .card-on-mobile stops looking like a squeezed table and instead renders
   each row as a stacked card.
   ---------------------------------------------------------------------- */

.shda-table-wrap {
    background-color: var(--shda-card-bg);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius);
    box-shadow: var(--shda-shadow-sm);
    overflow: hidden;
}

.shda-table-wrap table {
    margin-bottom: 0;
}

.shda-table-wrap thead th {
    background-color: var(--shda-header-navy);
    color: #ffffff;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    padding-top: 0.9rem;
    padding-bottom: 0.9rem;
    border-bottom: 1px solid var(--shda-border);
}

/* Tables that aren't wrapped in .shda-table-wrap (dashboard mini-tables,
   permission matrix, invoice line editor, student profile sub-tables) get
   the same treatment for a consistent look app-wide. */
thead th {
    background-color: var(--shda-header-navy);
    color: #ffffff;
    padding-top: 0.9rem;
    padding-bottom: 0.9rem;
}

/* The printable invoice sheet stays plain black-on-white — a colored
   header wastes ink and doesn't match standard invoice conventions. */
.shda-invoice-sheet thead th {
    background-color: transparent;
    color: inherit;
}

@media (min-width: 768px) {
    .shda-details-col + .shda-details-col {
        border-left: 1px solid var(--shda-border);
    }
}

.shda-table-wrap tbody tr {
    transition: background-color var(--shda-transition);
}

.shda-table-wrap tbody tr:hover {
    background-color: var(--shda-bg);
}

@media (max-width: 767.98px) {
    .card-on-mobile,
    .card-on-mobile tbody,
    .card-on-mobile tr,
    .card-on-mobile td {
        display: block;
        width: 100%;
    }

    .card-on-mobile thead {
        display: none;
    }

    .card-on-mobile tr {
        border-bottom: 1px solid var(--shda-border);
        padding: 0.85rem 1.1rem;
    }

    .card-on-mobile tr:last-child {
        border-bottom: none;
    }

    .card-on-mobile td {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0.75rem;
        padding: 0.3rem 0;
        border: none;
        text-align: right;
    }

    .card-on-mobile td[data-label]::before {
        content: attr(data-label);
        font-size: 0.72rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.03em;
        color: var(--shda-text-muted);
        text-align: left;
        margin-right: auto;
        padding-right: 0.75rem;
    }

    .card-on-mobile td:empty {
        display: none;
    }

    /* App-like touches on small screens */
    .shda-page-header h1 {
        font-size: 1.2rem;
    }

    .card-header {
        padding: 0.8rem 1rem;
    }

    .btn {
        min-height: 42px;
    }

    /* 16px+ stops iOS Safari's auto-zoom-on-focus (anything under 16px
       triggers it); also gives every field a real 44px+ touch target. */
    .form-control, .form-select {
        font-size: 16px;
        min-height: 44px;
    }

    /* Page-header action-button rows: most pages already remember
       "d-flex flex-wrap gap-2", but some (e.g. students/list.php's
       Export/Registration buttons) only had "d-flex gap-2" — confirmed via
       headless Chromium at 393px that those pages overflowed horizontally
       by 150px+. .shda-page-header itself already wraps its own children
       (h1 vs. this div); this makes the div's OWN children (the buttons)
       wrap too, app-wide, regardless of whether a given page's markup
       remembered flex-wrap. A no-op on any header div that isn't display:
       flex to begin with, so this is safe everywhere .shda-page-header is used. */
    .shda-page-header > div {
        flex-wrap: wrap;
    }

    /* Dashboard: KPI tiles are 2-up on phones (row-cols-2) — tighten the
       card so longer money values (e.g. "$12,345.67") and "Net Profit"
       don't wrap or crowd a ~165px-wide card. */
    .shda-stat-card {
        padding: 0.85rem 0.9rem;
        gap: 0.4rem;
    }

    .shda-stat-icon {
        width: 2.1rem;
        height: 2.1rem;
    }

    .shda-stat-icon .material-symbols-outlined {
        font-size: 1.15rem;
    }

    .shda-stat-card .shda-stat-value {
        font-size: 1.2rem;
        word-break: break-word;
    }

    .shda-stat-card .shda-stat-label {
        font-size: 0.68rem;
    }

    .shda-stat-card .shda-stat-sub {
        font-size: 0.72rem;
    }

    /* Dashboard filter form's Apply button — full-width on phones (see
       col-12 col-md-auto on the same element in index.php). */
    .shda-btn-block-mobile {
        width: 100%;
    }

    /* Install banner: confirmed via headless-Chromium screenshot at 393px
       that a single row (icon + wrapping 2-line title + button + close)
       squeezes the button/close into an odd position once the title
       wraps — stack it into two rows instead, actions full-width below. */
    .shda-install-banner {
        flex-wrap: wrap;
    }

    .shda-install-banner-actions {
        width: 100%;
        justify-content: space-between;
    }

    /* iOS Safari never shows the Install button (no programmatic prompt
       exists there) — space-between with only the close (X) left visible
       would otherwise pin it to the start instead of the end. */
    .shda-install-banner-actions:has(#shdaInstallBannerBtn[hidden]) {
        justify-content: flex-end;
    }

    .shda-install-banner-actions #shdaInstallBannerBtn {
        flex: 1 1 auto;
    }

    /* Dashboard chart — shorter on phones than the desktop height below,
       since Chart.js's default 2:1 aspect ratio makes it awkwardly tall on
       a narrow screen (see maintainAspectRatio:false in index.php's chart
       init, which makes the chart fill whichever height applies here). */
    .shda-chart-wrap {
        height: 240px;
    }
}

/* ----------------------------------------------------------------------
   Bottom tab bar (mobile only) — native-app style tab bar
   ---------------------------------------------------------------------- */

.shda-bottom-tabbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1030;
    display: flex;
    background-color: rgba(255, 255, 255, 0.96);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-top: 1px solid var(--shda-border);
    box-shadow: 0 -2px 16px rgba(15, 31, 61, 0.1);
    height: var(--shda-bottom-tabbar-height);
    padding-bottom: env(safe-area-inset-bottom);
}

.shda-tab {
    flex: 1 1 0;
    /* Flex items default to min-width:auto, which refuses to shrink below
       the label's own intrinsic width — with 5 tabs (4 nav items + "More")
       that pushed the whole bar past the viewport on real narrow phones
       (confirmed via headless Chromium at 393px: bar rendered ~156px wider
       than the screen). min-width:0 lets flex-shrink actually take effect;
       the label span below then ellipsizes instead of forcing extra width. */
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    color: var(--shda-text-muted);
    text-decoration: none;
    font-size: 0.66rem;
    font-weight: 600;
    background: none;
    border: none;
    transition: color var(--shda-transition);
}

.shda-tab span:last-child {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.shda-tab .material-symbols-outlined {
    font-size: 1.45rem;
    line-height: 1;
    transition: transform var(--shda-transition);
}

.shda-tab:active .material-symbols-outlined {
    transform: scale(0.88);
}

.shda-tab.active {
    color: var(--shda-navy);
}

.shda-tab.active .material-symbols-outlined {
    color: var(--shda-navy);
    font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}

/* ----------------------------------------------------------------------
   Avatars
   ---------------------------------------------------------------------- */

.shda-avatar-lg {
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--shda-border);
}

.shda-avatar-placeholder {
    font-size: 4rem;
    color: var(--shda-text-muted);
    line-height: 1;
}

.shda-avatar-xl {
    width: 4.5rem;
    height: 4.5rem;
}

.shda-upload-preview-wrap {
    flex-shrink: 0;
    width: 4.5rem;
    height: 4.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.shda-licence-preview-wrap {
    width: 100%;
    max-width: 240px;
    min-height: 100px;
    border: 1px dashed var(--shda-input-border);
    border-radius: var(--shda-control-radius);
    background-color: #fdfdfe;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.5rem;
}

.shda-licence-preview {
    max-width: 100%;
    max-height: 140px;
    object-fit: contain;
    border-radius: var(--shda-control-radius);
}

.shda-licence-modal-img {
    max-height: 70vh;
    border-radius: var(--shda-control-radius);
}

.shda-avatar-sm {
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    object-fit: cover;
    vertical-align: -0.4em;
}

/* ----------------------------------------------------------------------
   Access Denied
   ---------------------------------------------------------------------- */

.shda-access-denied-icon {
    font-size: 4.5rem;
    color: var(--shda-danger);
    background-color: var(--shda-danger-soft);
    border-radius: 50%;
    width: 6rem;
    height: 6rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ----------------------------------------------------------------------
   Password strength meter
   ---------------------------------------------------------------------- */

.shda-strength-track {
    height: 6px;
    border-radius: 999px;
    background-color: var(--shda-border);
    overflow: hidden;
    margin-top: 0.4rem;
}

.shda-strength-bar {
    height: 100%;
    width: 0;
    border-radius: 999px;
    transition: width var(--shda-transition), background-color var(--shda-transition);
}

.shda-strength-text {
    font-size: 0.75rem;
    font-weight: 600;
    margin-top: 0.25rem;
    display: inline-block;
}

/* ----------------------------------------------------------------------
   Login page
   ---------------------------------------------------------------------- */

.shda-login-body {
    background: linear-gradient(160deg, var(--shda-navy) 0%, var(--shda-navy-dark) 100%);
    min-height: 100vh;
    min-height: 100dvh;
}

.shda-login-wrap {
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1.5rem 1rem;
}

.shda-login-card {
    background-color: var(--shda-card-bg);
    border-radius: var(--shda-radius-lg);
    box-shadow: var(--shda-shadow-lg);
    padding: 2.25rem 1.85rem;
    width: 100%;
    max-width: 420px;
}

/* Wider variant shared by the three public-facing forms (Enquire Now,
   Student Registration, Book a Session — the last of these also carries
   .shda-booking-card, which used to override this narrower at a fixed
   640px; removed so all three now share one consistent width) — ~90% of
   the viewport, capped so very large/ultra-wide monitors don't stretch it
   absurdly, centered (.shda-login-wrap already centers its children).
   Login/Forgot/Reset Password intentionally keep the narrower default
   .shda-login-card width (420px) — they don't use this class. */
.shda-register-card {
    width: 90%;
    max-width: 1140px;
    text-align: left;
}

.shda-booking-stepper {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
}

.shda-booking-step {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--shda-text-muted);
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.shda-booking-step.active,
.shda-booking-step.done {
    color: var(--shda-navy);
}

.shda-booking-step-num {
    font-size: 1rem;
}

.shda-booking-step-line {
    flex: 0 0 2.5rem;
    height: 1px;
    background-color: var(--shda-border);
}

.shda-booking-slot-legend {
    display: flex;
    align-items: center;
}

.shda-slot-legend-dot {
    display: inline-block;
    width: 0.65rem;
    height: 0.65rem;
    border-radius: 50%;
    margin-right: 0.3rem;
}

.shda-slot-legend-dot.shda-slot-available {
    background-color: var(--shda-success);
}

.shda-slot-legend-dot.shda-slot-unavailable {
    background-color: var(--shda-border);
}

.shda-booking-slot-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 0.5rem;
}

.shda-booking-slot {
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius-sm);
    background-color: var(--shda-card-bg);
    padding: 0.55rem 0.4rem;
    font-size: 0.82rem;
    font-weight: 600;
    min-height: 44px;
    transition: border-color var(--shda-transition), background-color var(--shda-transition);
}

.shda-booking-slot.shda-slot-available {
    color: var(--shda-navy);
    border-color: var(--shda-success);
}

.shda-booking-slot.shda-slot-available:hover {
    background-color: var(--shda-success-soft);
}

.shda-booking-slot.shda-slot-available.selected {
    background-color: var(--shda-navy);
    border-color: var(--shda-navy);
    color: #ffffff;
}

.shda-booking-slot.shda-slot-unavailable {
    color: var(--shda-text-muted);
    background-color: var(--shda-bg);
    cursor: not-allowed;
}

.shda-booking-review {
    background-color: var(--shda-bg);
    border-radius: var(--shda-radius-sm);
    padding: 1rem 1.1rem;
}

.shda-booking-review dt {
    color: var(--shda-text-muted);
    font-weight: 600;
    font-size: 0.85rem;
}

.shda-booking-review dd {
    font-size: 0.9rem;
}

.shda-token-chip {
    font-family: 'Courier New', Courier, monospace;
    font-size: 0.82rem;
    color: var(--shda-text-muted);
}

.shda-login-brand {
    font-size: 2.5rem;
    color: var(--shda-amber);
    margin-bottom: 0.5rem;
}

.shda-login-brand .material-symbols-outlined {
    font-size: inherit;
}

.shda-login-logo {
    height: 44px;
    width: auto;
    max-width: none;
}

.shda-login-title {
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--shda-navy);
    margin-bottom: 0.25rem;
}

/* "or" divider between the password form and "Sign in with Face ID / Passkey". */
.shda-login-divider {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;
    font-size: 0.8rem;
    color: var(--shda-text-muted);
}

.shda-login-divider::before,
.shda-login-divider::after {
    content: "";
    flex: 1;
    border-top: 1px solid var(--shda-border);
}

.shda-login-hint {
    margin-top: 1.5rem;
    padding-top: 1rem;
    border-top: 1px solid var(--shda-border);
    font-size: 0.8rem;
    color: var(--shda-text-muted);
    text-align: center;
}

.shda-login-hint .material-symbols-outlined {
    color: var(--shda-amber);
}

/* ----------------------------------------------------------------------
   Invoice sheet
   ---------------------------------------------------------------------- */

.shda-invoice-brand {
    color: var(--shda-navy);
    font-weight: 700;
}

.shda-invoice-logo {
    display: block;
    max-width: 200px;
    height: auto;
    margin-bottom: 0.5rem;
}

.shda-invoice-sheet {
    position: relative;
    overflow: hidden;
}

.shda-invoice-sheet > .card-body {
    position: relative;
    z-index: 1;
}

.shda-invoice-watermark {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 55%;
    max-width: 340px;
    transform: translate(-50%, -50%);
    opacity: 0.07;
    pointer-events: none;
    user-select: none;
    z-index: 0;
}

/* ----------------------------------------------------------------------
   Powered-by footer line
   ---------------------------------------------------------------------- */

.shda-powered-by {
    text-align: center;
    font-size: 0.78rem;
    color: var(--shda-text-muted);
    padding: 1.5rem 0 1rem;
    margin-top: auto;
    width: 100%;
}

.shda-powered-by a {
    color: var(--shda-text-muted);
    font-weight: 600;
    text-decoration: underline;
}

.shda-powered-by a:hover {
    color: var(--shda-navy);
}

.shda-login-wrap .shda-powered-by {
    padding-top: 1rem;
}

/* ----------------------------------------------------------------------
   Session calendar (FullCalendar theming to match the app)
   ---------------------------------------------------------------------- */

.shda-legend-dot {
    display: inline-block;
    width: 0.65rem;
    height: 0.65rem;
    border-radius: 50%;
}

#sessionCalendar {
    font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 0.85rem;
    --fc-border-color: var(--shda-border);
    --fc-neutral-bg-color: var(--shda-bg);
    --fc-page-bg-color: transparent;
    --fc-list-event-hover-bg-color: var(--shda-bg);
}

/* --- Header toolbar: Prev/Next as circular icon buttons, Today as a
   distinct accent-outlined pill, a bold title, and a segmented view
   switcher — the "modern SaaS dashboard" header called for in the redesign. --- */
#sessionCalendar .fc-header-toolbar {
    margin-bottom: 1.5rem !important;
    flex-wrap: wrap;
    gap: 0.75rem;
}

#sessionCalendar .fc-toolbar-title {
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--shda-navy);
    letter-spacing: -0.01em;
}

#sessionCalendar .fc-button {
    background-color: var(--shda-card-bg);
    border: 1px solid var(--shda-border);
    color: var(--shda-text);
    box-shadow: none !important;
    text-transform: capitalize;
    font-weight: 500;
    border-radius: var(--shda-control-radius) !important;
    padding: 0.4rem 0.9rem;
    transition: background-color var(--shda-transition), border-color var(--shda-transition), transform 120ms ease;
}

#sessionCalendar .fc-button:hover {
    background-color: var(--shda-bg);
    border-color: var(--shda-input-border);
}

#sessionCalendar .fc-button:active,
#sessionCalendar .fc-button:focus {
    box-shadow: none !important;
}

#sessionCalendar .fc-button:active {
    transform: scale(0.96);
}

#sessionCalendar .fc-today-button {
    font-weight: 600;
    color: var(--shda-btn-primary);
    border-color: var(--shda-btn-primary);
}

#sessionCalendar .fc-today-button:hover:not(:disabled) {
    background-color: var(--shda-amber-soft);
}

#sessionCalendar .fc-today-button:disabled {
    opacity: 0.45;
}

#sessionCalendar .fc-prevYear-button,
#sessionCalendar .fc-prev-button,
#sessionCalendar .fc-next-button,
#sessionCalendar .fc-nextYear-button {
    border-radius: 50% !important;
    width: 2.2rem;
    height: 2.2rem;
    padding: 0 !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

#sessionCalendar .fc-button-primary:not(:disabled).fc-button-active,
#sessionCalendar .fc-button-primary:not(:disabled):active {
    background-color: var(--shda-navy);
    border-color: var(--shda-navy);
    color: #ffffff;
}

/* --- Grid chrome: rounded card, muted uppercase weekday headers, subtle
   row/column hover, a refined "today" treatment (accent ring on the date
   number rather than a flat background wash). --- */
#sessionCalendar .fc-scrollgrid {
    border-radius: var(--shda-radius-sm);
    overflow: hidden;
}

#sessionCalendar .fc-col-header-cell {
    background-color: var(--shda-bg);
    padding: 0.55rem 0;
}

#sessionCalendar .fc-col-header-cell-cushion {
    text-transform: uppercase;
    font-size: 0.68rem;
    letter-spacing: 0.06em;
    color: var(--shda-text-muted);
    font-weight: 600;
}

#sessionCalendar .fc-daygrid-day:hover,
#sessionCalendar .fc-timegrid-col:hover {
    background-color: rgba(15, 31, 61, 0.025);
}

#sessionCalendar .fc-daygrid-day.fc-day-today,
#sessionCalendar .fc-timegrid-col.fc-day-today {
    background-color: var(--shda-amber-soft);
}

#sessionCalendar .fc-daygrid-day-number {
    font-weight: 500;
    padding: 0.35rem 0.5rem;
}

#sessionCalendar .fc-day-today .fc-daygrid-day-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.6rem;
    height: 1.6rem;
    background: var(--shda-btn-primary);
    color: #ffffff;
    border-radius: 50%;
    font-weight: 700;
    margin: 0.2rem;
    padding: 0 0.35rem;
}

#sessionCalendar .fc-highlight {
    background: rgba(255, 106, 32, 0.15);
}

/* Live "10:00 AM – 11:30 AM · 1h 30m" readout shown while dragging out a
   new session (see selectAllow in calendar.php) — never intercepts input.
   position: fixed (not absolute within the calendar card) and pinned just
   below the sticky top navbar — confirmed via a real headless-Chromium
   screenshot that positioning it inside the calendar card instead
   overlapped FullCalendar's own toolbar title/view buttons, whose height
   varies (it wraps to multiple rows on mobile), making any offset relative
   to the card fragile. Same "float below the sticky navbar" convention the
   chat panel already uses (--shda-navbar-height, 64px fallback). */
.shda-drag-time-badge {
    position: fixed;
    top: calc(var(--shda-navbar-height, 64px) + 0.5rem);
    left: 50%;
    transform: translateX(-50%);
    z-index: 1029;
    background: var(--shda-navy);
    color: #ffffff;
    padding: 0.35rem 0.9rem;
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 600;
    box-shadow: var(--shda-shadow);
    pointer-events: none;
    white-space: nowrap;
}

/* --- Events: soft-tint cards with a status-colored accent border (set
   per-event from calendar_events.php), a gentle lift + shadow on hover,
   and a compact status dot + label built in eventContent (calendar.php). --- */
#sessionCalendar a {
    color: inherit;
}

#sessionCalendar .fc-event {
    border-left-width: 3px;
    border-radius: 0.5rem;
    padding: 2px 6px;
    cursor: pointer;
    transition: transform 140ms ease, box-shadow 140ms ease;
}

#sessionCalendar .fc-event:hover {
    transform: translateY(-1px);
    box-shadow: var(--shda-shadow);
    z-index: 5;
}

#sessionCalendar .fc-daygrid-event {
    margin-top: 2px;
}

#sessionCalendar .fc-event-main {
    padding: 1px 2px;
}

.shda-event-card {
    line-height: 1.3;
}

.shda-event-title-row {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

/* Employee calendar color picker (Admin > Lookups > Employees) — a
   Google-Calendar-style swatch grid instead of a native OS color wheel,
   backed by a hidden input (see admin/lookups.php + initSwatchPickers() in
   assets/js/app.js). */
.shda-swatch-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.shda-swatch {
    position: relative;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.1);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: transform 120ms ease;
}

.shda-swatch:hover {
    transform: scale(1.1);
}

.shda-swatch:focus-visible {
    outline: 2px solid var(--shda-btn-primary);
    outline-offset: 2px;
}

.shda-swatch-check {
    font-size: 1.05rem !important;
    color: #ffffff;
    opacity: 0;
    text-shadow: 0 0 2px rgba(0, 0, 0, 0.35);
}

.shda-swatch.is-selected .shda-swatch-check {
    opacity: 1;
}

.shda-swatch-custom {
    background: repeating-conic-gradient(#e7eaf3 0% 25%, #ffffff 0% 50%) 50% / 10px 10px;
    margin-bottom: 0;
}

.shda-swatch-custom .shda-swatch-check {
    color: var(--shda-text-muted);
    opacity: 1;
    text-shadow: none;
}

.shda-swatch-custom.is-selected .shda-swatch-check {
    color: #ffffff;
    text-shadow: 0 0 2px rgba(0, 0, 0, 0.35);
}

.shda-swatch-custom-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    border: none;
    padding: 0;
}

.shda-color-swatch {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 4px;
    vertical-align: middle;
    border: 1px solid rgba(0, 0, 0, 0.15);
    margin-right: 0.25rem;
}

.shda-event-title {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.shda-event-sub {
    font-size: 0.72em;
    opacity: 0.85;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-top: 1px;
}

.shda-event-status-icon {
    font-size: 0.85rem !important;
    margin-left: auto;
    opacity: 0.8;
    flex-shrink: 0;
}

/* Status is a SECONDARY signal on top of the employee color (border/dot) —
   border-style + opacity, never a color swap, so two employees' Cancelled
   sessions still read as visually distinct from each other. */
#sessionCalendar .fc-event.shda-cal-cancelled {
    opacity: 0.55;
    border-style: dashed;
}

#sessionCalendar .fc-event.shda-cal-noshow {
    opacity: 0.65;
    border-style: dotted;
}

#sessionCalendar .fc-event.shda-cal-completed {
    opacity: 0.85;
}

#sessionCalendar .fc-event.shda-cal-inprogress {
    border-left-width: 5px;
    box-shadow: 0 0 0 1px rgba(47, 127, 214, 0.25);
}

#sessionCalendar .fc-list-event-title .shda-event-sub {
    display: block;
    opacity: 0.75;
}

#sessionCalendar .fc-list-event:hover td {
    background-color: var(--shda-bg);
}

/* "By Employee" Day-view columns (Admin/Super Admin only, custom-built — no
   FullCalendar resource plugin, that's a paid Premium feature). A plain
   sibling of #sessionCalendar, so it needs its own copies of the handful of
   status-treatment rules above rather than relying on the #sessionCalendar
   .fc-event scoping — deliberately kept out of FullCalendar's own managed
   element. */
.shda-employee-columns {
    overflow: auto;
    max-height: 70vh;
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-control-radius);
}

.shda-emp-col-header-row,
.shda-emp-col-body {
    display: flex;
    min-width: max-content;
}

.shda-emp-col-header-row {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--shda-card-bg);
    border-bottom: 1px solid var(--shda-border);
}

.shda-emp-col-gutter {
    flex: 0 0 60px;
}

.shda-emp-col-header {
    flex: 1 0 150px;
    min-width: 150px;
    padding: 0.5rem;
    font-weight: 600;
    font-size: 0.85rem;
    text-align: center;
    border-top: 3px solid;
    border-left: 1px solid var(--shda-border);
}

.shda-emp-col-body {
    position: relative;
}

.shda-emp-col-time-gutter {
    position: relative;
}

.shda-emp-col-time-label {
    position: absolute;
    left: 0;
    right: 4px;
    transform: translateY(-50%);
    font-size: 0.72rem;
    color: var(--shda-text-muted);
    text-align: right;
}

.shda-emp-col {
    flex: 1 0 150px;
    min-width: 150px;
    position: relative;
    border-left: 1px solid var(--shda-border);
    cursor: pointer;
}

.shda-emp-col-hourline {
    position: absolute;
    left: 0;
    right: 0;
    border-top: 1px solid rgba(0, 0, 0, 0.06);
    pointer-events: none;
}

.shda-emp-col-event {
    position: absolute;
    left: 2px;
    right: 2px;
    overflow: hidden;
    border-radius: 0.4rem;
    border-left-width: 3px;
    border-left-style: solid;
    padding: 2px 6px;
    font-size: 0.78rem;
    cursor: pointer;
    z-index: 1;
}

.shda-emp-col-event.shda-cal-cancelled {
    opacity: 0.55;
    border-left-style: dashed;
}

.shda-emp-col-event.shda-cal-noshow {
    opacity: 0.65;
    border-left-style: dotted;
}

.shda-emp-col-event.shda-cal-completed {
    opacity: 0.85;
}

.shda-emp-col-event.shda-cal-inprogress {
    border-left-width: 5px;
    box-shadow: 0 0 0 1px rgba(47, 127, 214, 0.25);
}

/* Status badges (used in the legend, filters, and details modal — never
   rely on color alone) */
.shda-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    white-space: nowrap;
}

.shda-status-Scheduled { background: #0f1f3d; color: #fff; }
.shda-status-Confirmed { background: #1f9d55; color: #fff; }
.shda-status-Completed { background: #6b7280; color: #fff; }
.shda-status-Cancelled { background: #fdecec; color: #d64545; }
.shda-status-NoShow { background: #f5a623; color: #0a1529; }
.shda-status-InProgress { background: #2f7fd6; color: #fff; }

/* Student self-registration: link statuses (Active/Expired/Revoked/Used)
   and request statuses (Pending/Approved/Rejected) */
.shda-status-Active { background: #1f9d55; color: #fff; }
.shda-status-Expired { background: #6b7280; color: #fff; }
.shda-status-Revoked { background: #fdecec; color: #d64545; }
.shda-status-Used { background: #0e2862; color: #fff; }
.shda-status-Pending { background: #f5a623; color: #0a1529; }
.shda-status-Approved { background: #1f9d55; color: #fff; }
.shda-status-Rejected { background: #fdecec; color: #d64545; }

/* "In Progress" session's End Session button — a subtle, continuous green
   pulse that communicates "this session is live right now" at a glance,
   without being distracting. Only ever applied to a session whose actual
   status (from the database) is In Progress — see sessions/list.php and
   the calendar's details modal, never applied speculatively. */
@keyframes shda-pulse-running {
    0%   { box-shadow: 0 0 0 0 rgba(31, 157, 85, 0.5); }
    70%  { box-shadow: 0 0 0 9px rgba(31, 157, 85, 0); }
    100% { box-shadow: 0 0 0 0 rgba(31, 157, 85, 0); }
}

.shda-session-running {
    background-color: var(--shda-success);
    border-color: var(--shda-success);
    color: #fff;
    animation: shda-pulse-running 2.2s ease-out infinite;
}

.shda-session-running:hover,
.shda-session-running:focus {
    background-color: var(--shda-success);
    border-color: var(--shda-success);
    color: #fff;
    filter: brightness(1.08);
}

@media (prefers-reduced-motion: reduce) {
    .shda-session-running {
        animation: none;
    }
}

/* ----------------------------------------------------------------------
   Table toolbar — search + Advanced Filters toggle + Clear Filters, shared
   by every list page (students, sessions, payments, invoices, expenses,
   enquiries, notifications, admin users/roles). Stacks on narrow screens.
   ---------------------------------------------------------------------- */
.shda-table-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.shda-table-toolbar .shda-toolbar-search {
    flex: 1 1 220px;
    min-width: 0;
}

.shda-table-toolbar .shda-toolbar-search .form-control {
    border-color: var(--shda-navy);
}

.shda-table-toolbar .shda-toolbar-search .form-control:focus {
    border-color: var(--shda-amber);
}

.shda-table-toolbar .shda-toolbar-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* ----------------------------------------------------------------------
   Bulk Actions
   ---------------------------------------------------------------------- */
.shda-bulk-toolbar {
    position: sticky;
    bottom: 0.75rem;
    z-index: 10;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    background-color: var(--shda-navy);
    color: #fff;
    border-radius: var(--shda-radius);
    box-shadow: var(--shda-shadow-lg);
    padding: 0.65rem 1rem;
    margin: 0.75rem 0;
}

.shda-bulk-toolbar[hidden] {
    display: none;
}

.shda-bulk-count {
    font-weight: 600;
    white-space: nowrap;
}

.shda-bulk-toolbar .shda-bulk-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-left: auto;
}

.shda-bulk-checkbox-col {
    width: 2.25rem;
}

@media (max-width: 575.98px) {
    .shda-bulk-toolbar {
        bottom: calc(var(--shda-bottom-tabbar-height, 64px) + 0.5rem);
    }
}

.shda-advanced-filters {
    background-color: var(--shda-bg);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius-sm);
    padding: 1rem;
    margin-bottom: 0.75rem;
}

/* Active-filter chips (a badge per applied filter, each removable) */
.shda-filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    background-color: var(--shda-info-soft);
    color: var(--shda-info);
    font-weight: 500;
    font-size: 0.78rem;
    padding: 0.3rem 0.6rem;
    border-radius: 999px;
    transition: background-color var(--shda-transition);
}

.shda-filter-chip:hover {
    background-color: var(--shda-info);
    color: #fff;
}

.shda-filter-chip .material-symbols-outlined {
    font-size: 0.9em;
}

/* Sortable column header links: keep the header's own white/uppercase
   look (no blue link color, no underline) and shrink the arrow icon to
   match the header's small font-size instead of the default 1.2em. */
.shda-table-wrap thead th a,
thead th a {
    color: inherit;
}

.shda-table-wrap thead th a .material-symbols-outlined,
thead th a .material-symbols-outlined {
    font-size: 1em;
    vertical-align: -0.15em;
}

/* Calendar toolbar: filters + Today's Sessions panel */
.shda-calendar-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: flex-end;
    margin-bottom: 1rem;
    padding: 0.85rem 1rem;
    background-color: var(--shda-bg);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius-sm);
}

.shda-calendar-toolbar .form-label {
    font-size: 0.72rem;
    margin-bottom: 0.2rem;
    color: var(--shda-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
}

.shda-calendar-toolbar select {
    min-width: 160px;
}

.shda-calendar-toolbar select:hover {
    border-color: var(--shda-input-border);
}

/* Employee legend/filter — Admin/Super Admin only (see is_admin_level_user()
   in sessions/calendar.php). Purely a display filter: unchecking an
   employee only hides their events in this browser, never touches data. */
.shda-calendar-legend {
    padding: 0.75rem 1rem;
    background-color: var(--shda-bg);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius-sm);
}

.shda-calendar-legend-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.6rem;
}

.shda-calendar-legend-items {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
}

.shda-legend-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.82rem;
    cursor: pointer;
    user-select: none;
}

/* A clean, borderless solid circle — deliberately NOT reusing
   .shda-color-swatch (a bordered rounded square used in Admin > Lookups'
   table). At this small a size, that border read as a visible dark rim
   around the fill, which looked like two overlapping/nested colored
   squares once compressed in a screenshot — reported as "colors are not
   showing properly." A plain borderless dot avoids that entirely. */
.shda-legend-dot {
    display: inline-block;
    width: 12px;
    height: 12px;
    min-width: 12px;
    border-radius: 50%;
    vertical-align: middle;
}

.shda-legend-chip input[type="checkbox"] {
    cursor: pointer;
}

/* An unchecked employee's chip dims to make "hidden from view" obvious
   without relying on the checkbox state alone. */
.shda-legend-chip:has(input:not(:checked)) {
    opacity: 0.5;
}

/* Status legend row — neutral/icon-only now that color means "employee",
   not "status" (see sessions/calendar_events.php). */
.shda-calendar-status-legend {
    color: var(--shda-text-muted);
}

.shda-cal-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.shda-cal-legend-item .material-symbols-outlined {
    font-size: 1rem;
}

.shda-cal-legend-cancelled .material-symbols-outlined { color: var(--shda-danger, #d64545); }
.shda-cal-legend-noshow .material-symbols-outlined { color: var(--shda-amber, #f5a623); }

.shda-today-panel {
    max-height: 420px;
    overflow-y: auto;
}

.shda-today-item {
    display: flex;
    gap: 0.75rem;
    padding: 0.6rem 0 0.6rem 0.6rem;
    border-bottom: 1px solid var(--shda-border);
}

.shda-today-item:last-child {
    border-bottom: none;
}

.shda-today-time {
    font-weight: 700;
    color: var(--shda-navy);
    min-width: 4.5rem;
    font-size: 0.82rem;
}

.shda-today-item .shda-today-student {
    font-weight: 600;
}

.shda-today-item .shda-today-meta {
    font-size: 0.78rem;
    color: var(--shda-text-muted);
}

/* Searchable select combobox (student/instructor/vehicle pickers) */
.shda-searchable-select {
    position: relative;
}

.shda-searchable-native {
    position: absolute !important;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.shda-searchable-options {
    position: absolute;
    z-index: 1065;
    top: 100%;
    left: 0;
    right: 0;
    margin-top: 0.15rem;
    max-height: 220px;
    overflow-y: auto;
    background: var(--shda-card-bg);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius-sm);
    box-shadow: var(--shda-shadow);
}

.shda-searchable-option {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.5rem 0.75rem;
    border: none;
    background: none;
    font-size: 0.85rem;
}

.shda-searchable-option:hover {
    background-color: var(--shda-bg);
}

.shda-searchable-empty {
    padding: 0.5rem 0.75rem;
    color: var(--shda-text-muted);
    font-size: 0.82rem;
}

/* Loading / empty / error states over the calendar grid */
.shda-calendar-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 3rem 1rem;
    color: var(--shda-text-muted);
    text-align: center;
}

.shda-calendar-state .material-symbols-outlined {
    font-size: 2rem;
}

.shda-calendar-loading .spinner-border {
    width: 2rem;
    height: 2rem;
    color: var(--shda-amber);
}

@media (max-width: 767.98px) {
    #sessionCalendar .fc-toolbar {
        flex-direction: column;
        gap: 0.6rem;
    }

    #sessionCalendar .fc-toolbar-title {
        font-size: 1.1rem;
    }

    #sessionCalendar .fc-toolbar-chunk {
        display: flex;
        justify-content: center;
        width: 100%;
    }

    #sessionCalendar .fc-button {
        padding: 0.35rem 0.7rem;
        font-size: 0.82rem;
    }

    .shda-calendar-toolbar {
        padding: 0.75rem;
    }

    .shda-calendar-toolbar select {
        min-width: 0;
        width: 100%;
    }

    #sessionCalendar,
    .card:has(#sessionCalendar) {
        overflow-x: hidden;
    }

    .shda-drag-time-badge {
        max-width: calc(100% - 1.5rem);
        white-space: normal;
        text-align: center;
        font-size: 0.75rem;
    }

    /* Payments list is the densest table in the app (13 columns) — hides
       the least-essential-on-a-phone ones in card view (Source, Created
       By, Created Date all stay in the desktop table, untouched). */
    .shda-col-secondary-mobile {
        display: none !important;
    }
}

/* ----------------------------------------------------------------------
   Voice-to-text dictation button
   ---------------------------------------------------------------------- */

.shda-voice-status {
    margin-top: 0.3rem;
}

/* Voice Fill toolbar (assets/js/voice-fill.js), injected at the top of any
   <form data-voice-fill>. Sticks below the navbar while listening so the
   status/feedback stays visible on long forms. */
.shda-voice-fill {
    background: var(--shda-card-bg);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius-sm);
    padding: 0.5rem 0.75rem;
    margin-bottom: 1rem;
}

.shda-voice-fill.is-listening {
    position: sticky;
    top: calc(var(--shda-navbar-height, 64px) + 0.5rem);
    z-index: 20;
    border-color: var(--shda-info);
    box-shadow: var(--shda-shadow);
}

.shda-voice-fill-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
}

.shda-voice-fill-bar .btn .material-symbols-outlined {
    font-size: 1.1rem;
    vertical-align: -0.2em;
}

.shda-voice-fill-state {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.85rem;
    color: var(--shda-text-muted);
}

.shda-voice-fill-dot {
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    background: var(--shda-input-border);
}

.shda-voice-fill-state[data-mode="listening"] .shda-voice-fill-dot {
    background: var(--shda-danger);
    animation: shda-voice-pulse 1.2s ease-in-out infinite;
}

.shda-voice-fill-state[data-mode="processing"] .shda-voice-fill-dot {
    background: var(--shda-amber);
}

@keyframes shda-voice-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.35; transform: scale(0.8); }
}

.shda-voice-fill-keep {
    font-size: 0.85rem;
}

.shda-voice-fill-help-btn {
    margin-left: auto;
    font-size: 0.85rem;
}

/* Options of a native <select> listed under it after "open … dropdown",
   when the browser won't open its own dropdown from speech. */
.shda-voice-options {
    margin-top: 0.35rem;
    border: 1px solid var(--shda-info);
    border-radius: var(--shda-control-radius);
    background: var(--shda-card-bg);
    box-shadow: var(--shda-shadow);
    font-size: 0.875rem;
}

.shda-voice-options-title {
    padding: 0.35rem 0.6rem;
    color: var(--shda-text-muted);
    border-bottom: 1px solid var(--shda-border);
}

.shda-voice-options-list {
    max-height: 14rem;
    overflow-y: auto;
}

.shda-voice-options-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.4rem 0.6rem;
    border: 0;
    background: transparent;
    color: var(--shda-text);
    overflow-wrap: anywhere;
}

.shda-voice-options-item:hover,
.shda-voice-options-item:focus-visible {
    background: var(--shda-info-soft);
}

.shda-voice-options-item.is-current {
    font-weight: 600;
}

.shda-voice-fill-feedback {
    margin-top: 0.5rem;
    font-size: 0.875rem;
}

.shda-voice-fill-heard {
    color: var(--shda-text-muted);
    font-style: italic;
    overflow-wrap: anywhere;
}

.shda-voice-fill-result {
    margin-top: 0.15rem;
    overflow-wrap: anywhere;
}

.shda-voice-fill-result[data-tone="ok"] { color: var(--shda-success); }
.shda-voice-fill-result[data-tone="warn"] { color: var(--shda-amber-dark); }
.shda-voice-fill-result[data-tone="error"] { color: var(--shda-danger); }

.shda-voice-fill-help {
    margin-top: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--shda-border);
    font-size: 0.85rem;
    color: var(--shda-text-muted);
}

.shda-voice-fill-help ul {
    padding-left: 1.1rem;
}

/* The field "Next field" / "Go to …" points at, and a brief flash on the
   field a command just updated. */
.shda-voice-fill-active {
    outline: 2px dashed var(--shda-info);
    outline-offset: 2px;
}

.shda-voice-fill-updated {
    animation: shda-voice-updated 1.6s ease-out;
}

@keyframes shda-voice-updated {
    0% { box-shadow: 0 0 0 0.25rem rgba(31, 157, 85, 0.45); }
    100% { box-shadow: 0 0 0 0.25rem rgba(31, 157, 85, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .shda-voice-fill-state[data-mode="listening"] .shda-voice-fill-dot,
    .shda-voice-fill-updated {
        animation: none;
    }
}

/* Wraps a <textarea> so the mic trigger can float inside its bottom-right
   corner, like a chat message composer. */
.shda-notes-wrap {
    position: relative;
}

.shda-notes-wrap textarea {
    padding-right: 2.75rem;
    padding-bottom: 2.75rem;
}

/* Live "N/1000" counter, injected by initNotesCounter() (assets/js/app.js)
   right after a .shda-notes-wrap — kept below the textarea (not floated
   inside it) so it never collides with the mic button's own corner. */
.shda-notes-counter {
    text-align: right;
    font-size: 0.8rem;
    color: var(--shda-text-muted);
    margin-top: 0.25rem;
}

.shda-notes-counter-limit {
    color: var(--shda-danger);
}

.shda-voice-btn-floating {
    position: absolute;
    right: 0.6rem;
    bottom: 0.6rem;
    width: 2.15rem;
    height: 2.15rem;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 1px solid var(--shda-border);
    background-color: var(--shda-card-bg);
    color: var(--shda-text-muted);
    box-shadow: var(--shda-shadow-sm);
    transition: background-color var(--shda-transition), color var(--shda-transition);
}

.shda-voice-btn-floating:hover {
    background-color: var(--shda-bg);
    color: var(--shda-text);
}

.shda-voice-btn-floating .material-symbols-outlined {
    font-size: 1.25rem;
}

/* When recording, the pill takes over the full width of the notes field
   instead of sitting as a small corner control. */
.shda-notes-wrap .shda-voice-recorder {
    position: absolute;
    left: 0.5rem;
    right: 0.5rem;
    bottom: 0.5rem;
}

/* Recording pill: cancel (X) — animated waveform — stop — confirm (send) */
.shda-voice-recorder {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    background-color: var(--shda-card-bg);
    border: 1px solid var(--shda-border);
    border-radius: 999px;
    padding: 0.3rem 0.4rem;
    box-shadow: var(--shda-shadow-sm);
}

.shda-voice-recorder-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 1.9rem;
    height: 1.9rem;
    border-radius: 50%;
    border: none;
    padding: 0;
    transition: background-color var(--shda-transition), transform var(--shda-transition);
}

.shda-voice-recorder-btn:active {
    transform: scale(0.92);
}

.shda-voice-recorder-btn .material-symbols-outlined {
    font-size: 1.1rem;
    vertical-align: middle;
}

.shda-voice-recorder-cancel {
    background-color: transparent;
    color: var(--shda-text-muted);
}

.shda-voice-recorder-cancel:hover {
    background-color: var(--shda-bg);
    color: var(--shda-text);
}

.shda-voice-recorder-stop {
    background-color: var(--shda-bg);
    color: var(--shda-text);
}

.shda-voice-recorder-stop:hover {
    background-color: var(--shda-border);
}

.shda-voice-recorder-confirm {
    background-color: var(--shda-success);
    color: #ffffff;
}

.shda-voice-recorder-confirm:hover {
    background-color: #187a42;
}

.shda-voice-waveform {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 3px;
    height: 1.6rem;
    min-width: 0;
    overflow: hidden;
}

.shda-voice-waveform span {
    flex: 0 0 3px;
    width: 3px;
    border-radius: 999px;
    background-color: var(--shda-amber);
    animation: shda-waveform-bounce 1s ease-in-out infinite;
}

@keyframes shda-waveform-bounce {
    0%, 100% { opacity: 0.45; transform: scaleY(0.55); }
    50% { opacity: 1; transform: scaleY(1); }
}

/* ----------------------------------------------------------------------
   Loaders — top navigation progress bar + in-button loading state
   ---------------------------------------------------------------------- */

.shda-progress-bar {
    position: fixed;
    top: 0;
    left: 0;
    width: 0;
    height: 3px;
    background-color: var(--shda-amber);
    box-shadow: 0 0 8px rgba(245, 166, 35, 0.6);
    z-index: 2000;
    opacity: 0;
    transition: width 0ms;
    pointer-events: none;
}

.shda-progress-bar.is-active {
    opacity: 1;
    width: 80%;
    transition: width 1.2s cubic-bezier(0.1, 0.7, 0.3, 1), opacity 150ms;
}

.btn.is-loading {
    cursor: wait;
}

.btn.is-loading .spinner-border {
    vertical-align: -0.15em;
    margin-right: 0.3rem;
}

/* ----------------------------------------------------------------------
   Print (invoice view)
   ---------------------------------------------------------------------- */

@media print {
    .no-print {
        display: none !important;
    }

    body {
        background-color: #ffffff;
        padding-bottom: 0 !important;
    }

    .shda-invoice-sheet {
        border: none !important;
        box-shadow: none !important;
    }

    .shda-consent-sheet {
        border: none !important;
        box-shadow: none !important;
    }
}

/* ----------------------------------------------------------------------
   Student Consent & Release (DTC205)
   ---------------------------------------------------------------------- */

.shda-consent-header-subtitle {
    /* Sits inside .card-header (dark navy background, white title text) —
       Bootstrap's .text-muted is tuned for light backgrounds and was
       nearly invisible here; a translucent white keeps the "subtitle"
       look while staying readable on the dark header. */
    color: rgba(255, 255, 255, 0.75);
}

.shda-consent-version-badge {
    background-color: var(--shda-bg);
    color: var(--shda-text-muted);
    border: 1px solid var(--shda-border);
    font-weight: 500;
    border-radius: 999px;
    padding: 0.25em 0.7em;
    font-size: 0.75rem;
}

.shda-consent-statement {
    margin: 1rem 0 0.75rem;
}

.shda-consent-list {
    margin-bottom: 1.25rem;
}

.shda-consent-subheader {
    margin: 1.5rem -1rem 1rem;
    background-color: var(--shda-bg);
    /* .card-header (base rule) sets color:#fff for its usual navy
       background — this subheader overrides the background to a light
       tone but was missing its own text color, leaving white-on-near-white
       text that was effectively invisible. */
    color: var(--shda-text);
}

.shda-consent-statements {
    padding-left: 1.25rem;
}

.shda-consent-statements li {
    margin-bottom: 0.85rem;
}

.shda-consent-ack {
    background-color: var(--shda-bg);
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-radius-sm);
    padding: 1rem 1.1rem;
    margin-bottom: 1rem;
}

.shda-signature-pad-frame {
    border: 1px dashed var(--shda-input-border);
    border-radius: var(--shda-control-radius);
    background-color: #fdfdfe;
}

.shda-signature-canvas {
    width: 100%;
    height: 180px;
    display: block;
    touch-action: none;
}

/* Scan Licence modal (students/_form.php + assets/js/licence-scanner.js) */
.shda-scan-video-wrap {
    position: relative;
    background-color: #000;
    border-radius: var(--shda-control-radius);
    overflow: hidden;
}

.shda-scan-video {
    width: 100%;
    height: 260px;
    object-fit: cover;
    display: block;
}

/* Purely a visual framing guide over the live camera preview — has no
   effect on decoding, which reads the whole frame regardless. */
.shda-scan-video-frame {
    position: absolute;
    inset: 15% 8%;
    border: 2px solid rgba(245, 166, 35, 0.85);
    border-radius: var(--shda-radius-sm);
    pointer-events: none;
}

/* Brief "Barcode detected!" confirmation shown over the live camera view for
   a moment right after a successful decode, before the scan modal closes —
   gives the admin a clear positive cue instead of the modal just vanishing. */
.shda-scan-detected {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    background-color: rgba(31, 157, 85, 0.9);
    color: #ffffff;
    font-weight: 600;
    pointer-events: none;
}

.shda-signature-img {
    max-width: 280px;
    max-height: 120px;
    border: 1px solid var(--shda-border);
    border-radius: var(--shda-control-radius);
    background-color: #ffffff;
    display: block;
}

.shda-signature-readonly {
    margin-bottom: 0.5rem;
}

@media (max-width: 575.98px) {
    .shda-signature-canvas {
        height: 220px;
    }
}

/* ============================================================================
   Session Review — star rating (End Session page)
   ============================================================================ */
.shda-star-rating {
    display: inline-flex;
    flex-direction: row-reverse;
    justify-content: flex-end;
    gap: 2px;
}

.shda-star-rating input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.shda-star-rating label {
    cursor: pointer;
    color: var(--shda-border);
    line-height: 1;
    padding: 2px;
    border-radius: var(--shda-radius-sm);
    transition: color var(--shda-transition);
}

.shda-star-rating label .material-symbols-outlined {
    font-size: 1.75rem;
}

.shda-star-rating input:focus-visible ~ label {
    outline: 2px solid var(--shda-info);
    outline-offset: 1px;
}

.shda-star-rating input:checked ~ label,
.shda-star-rating label:hover,
.shda-star-rating label:hover ~ label {
    color: var(--shda-amber);
}

.shda-star-rating.is-invalid label {
    color: var(--shda-danger-soft);
}

.shda-star-rating-readonly {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
}

.shda-star-rating-readonly .material-symbols-outlined {
    font-size: 1rem;
    color: var(--shda-border);
}

.shda-star-rating-readonly .material-symbols-outlined.is-filled {
    color: var(--shda-amber);
}

/* ----------------------------------------------------------------------
   Phones: icon-only page-header buttons + quick-actions FAB
   (assets/js/app.js initPageHeaderIconButtons() / initFabMenu();
   FAB markup in includes/footer.php). Tablet/desktop (>= 768px) untouched.
   ---------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    .shda-page-header .shda-header-icon-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 0;
        min-width: 44px;
        min-height: 44px;
        padding: 0 0.6rem;
    }

    .shda-page-header .shda-header-icon-btn .shda-btn-label {
        display: none;
    }

    .shda-page-header .shda-header-icon-btn .material-symbols-outlined {
        font-size: 1.35rem;
        margin: 0;
    }

    /* Same action is in the quick-actions menu on phones. */
    .shda-page-header .shda-fab-dup {
        display: none !important;
    }

    /* Room so the last content on a page can scroll clear of the tab bar
       AND the FAB. Reserved on .shda-main, not body: html/body are
       height:100% with content overflowing them, so padding on body adds
       no scroll room at all (measured — the page ended under the FAB).
       !important beats the element's own Bootstrap py-3 utility. */
    body.has-fab .shda-main {
        padding-bottom: calc(var(--shda-bottom-tabbar-height) + env(safe-area-inset-bottom) + 76px) !important;
    }
}

.shda-fab {
    position: fixed;
    right: calc(16px + env(safe-area-inset-right));
    bottom: calc(var(--shda-bottom-tabbar-height) + env(safe-area-inset-bottom) + 14px);
    z-index: 1029; /* under the tab bar (1030), offcanvas and modals */
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

/* Hidden while typing (keyboard up), while the bulk-action bar is shown,
   and while any modal is open. */
.shda-fab.is-suppressed,
body.modal-open .shda-fab {
    display: none !important;
}

.shda-fab-toggle {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: 0;
    background: var(--shda-btn-primary-dark);
    color: #fff;
    box-shadow: var(--shda-shadow-lg);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform var(--shda-transition);
}

.shda-fab-toggle .material-symbols-outlined {
    font-size: 1.9rem;
    transition: transform var(--shda-transition);
}

.shda-fab.is-open .shda-fab-toggle .material-symbols-outlined {
    transform: rotate(45deg);
}

.shda-fab-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(10, 21, 41, 0.35);
}

.shda-fab-menu {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
    /* Never taller than the space above the FAB. */
    max-height: calc(100vh - var(--shda-navbar-height, 64px) - var(--shda-bottom-tabbar-height) - 110px);
    overflow-y: auto;
    padding: 0.25rem;
}

.shda-fab-menu[hidden],
.shda-fab-backdrop[hidden] {
    display: none;
}

.shda-fab-item {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 44px;
    text-decoration: none;
    color: var(--shda-navy);
}

.shda-fab-item-label {
    background: var(--shda-card-bg);
    color: var(--shda-navy);
    font-size: 0.85rem;
    font-weight: 600;
    padding: 0.35rem 0.75rem;
    border-radius: 999px;
    box-shadow: var(--shda-shadow);
    white-space: nowrap;
}

.shda-fab-item-icon {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--shda-card-bg);
    color: var(--shda-btn-primary-dark);
    box-shadow: var(--shda-shadow);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.35rem;
}

.shda-fab-item:hover .shda-fab-item-label,
.shda-fab-item:focus-visible .shda-fab-item-label {
    background: var(--shda-amber-soft);
}

@media (prefers-reduced-motion: reduce) {
    .shda-fab-toggle,
    .shda-fab-toggle .material-symbols-outlined {
        transition: none;
    }
}
