/* ============================================================
   Bottom Nav Bar (dashboard only) - replaces the slide-out drawer
   5 slots: 4 customisable favourites (#bottomNavFavs) + a fixed three-dot
   More button. Fixed at the viewport bottom, centred with a max-width on wide
   screens. Markup in dashboard.html; behaviour in js/bottom-nav.js.
   ============================================================ */

.bottom-nav {
    position: fixed;
    left: 50%;
    bottom: 0;
    transform: translateX(-50%);
    width: 100%;
    max-width: 1000px;
    /* Icon row + the clearance below it (floored gap + home-indicator inset), all
       ADDITIVE below the row. The clearance lives in padding-bottom, never in the
       row height, so global box-sizing:border-box can't squeeze the buttons
       (L224 family: a bottom-anchored bar must clear the curved edge). The
       max(--bottom-nav-min-clear, ...) floor keeps Android/web off the curved edge
       where env()=0 leaves only the 4px gap. */
    height: calc(var(--bottom-nav-row) + max(var(--bottom-nav-min-clear), calc(var(--bottom-nav-gap) + max(env(safe-area-inset-bottom, 0px), var(--sab-floor, 0px)))));
    display: flex;
    align-items: stretch;
    background: var(--color-card);
    border-top: 1px solid var(--color-border);
    /* Above page content, below modal overlays (1000) and the View As bar (975). */
    z-index: 800;
    padding-bottom: max(var(--bottom-nav-min-clear), calc(var(--bottom-nav-gap) + max(env(safe-area-inset-bottom, 0px), var(--sab-floor, 0px))));
}

/* Shipped native builds inset the web content themselves (.cap-inset-always),
   so the OS already clears the home indicator - drop the env() inset (it would
   double the gap) but keep the same floored clearance so the slots still sit
   comfortably above the curved bottom edge instead of flush against it. */
html.cap-inset-always .bottom-nav {
    height: calc(var(--bottom-nav-row) + max(var(--bottom-nav-min-clear), var(--bottom-nav-gap)));
    padding-bottom: max(var(--bottom-nav-min-clear), var(--bottom-nav-gap));
}

/* CSS-floor fallback (fallback_mode='css-floor'): native-init.js stamps
   cap-inset-floor alongside cap-inset-always, so the rule above must be
   restored with the floor value in place of env() (mirrors the body
   three-rule pattern in css/style-03.css). .bottom-nav is position:fixed
   and escapes body padding entirely, so it needs its own restore. Ported
   from canopy 2026-08-11. */
html.cap-inset-always.cap-inset-floor .bottom-nav {
    height: calc(var(--bottom-nav-row) + max(var(--bottom-nav-min-clear), calc(var(--bottom-nav-gap) + var(--sab-floor, 0px))));
    padding-bottom: max(var(--bottom-nav-min-clear), calc(var(--bottom-nav-gap) + var(--sab-floor, 0px)));
}

/* Hidden while a non-modal text field is focused (the native-resize webview
   shrinks, so a fixed bar would ride up over the keyboard). */
.bottom-nav.kb-hidden {
    display: none;
}

.bottom-nav-item {
    flex: 1;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-light);
    font-size: var(--dt-bottom-nav-icon);
    text-decoration: none;
    transition: color 0.15s var(--ease-out);
    -webkit-tap-highlight-color: transparent;
    /* The slot glyphs are icon-font characters (i.e. selectable text), so a
       long-press or drag would select them and paint the blue text-selection
       box. Nav icons are never meant to be selectable - kill it. */
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

.bottom-nav-item i {
    display: inline-flex;
    line-height: 0;
    transition: background 0.15s var(--ease-out), color 0.15s var(--ease-out), padding 0.15s var(--ease-out);
}

/* Duolingo-style active slot: primary glyph on a soft rounded square. */
.bottom-nav-item.active {
    color: var(--color-primary);
}
.bottom-nav-item.active i {
    background: var(--color-bg-subtle);
    color: var(--color-primary);
    border-radius: 12px;
    padding: 6px 14px;
}

/* Press-pop: the WHOLE slot pulses on tap so the icon and its unread badge
   scale together from the slot centre. Popping only the <i> left the badge
   stationary, so the icon appeared to jump out from under it. Transform-only
   (reuses the msgrTickPulse curve), so the flex layout is untouched; added on
   pointerdown in bottom-nav.js. */
.bottom-nav-item.bottom-nav-pop {
    animation: msgrTickPulse 300ms var(--ease-spring);
}
@media (prefers-reduced-motion: reduce) {
    .bottom-nav-item.bottom-nav-pop { animation: none; }
}

/* Pending pulse dot, top-right of the slot glyph. Messenger-only (the non-
   messenger modules moved to the Notifications tab). It only POSITIONS the dot
   (never sets display): the messenger slot carries .msgr-pending-dot, whose
   shared.js painter toggles inline display. The descendant selector raises
   specificity so the size/position override .msgr-pending-dot's own (later-
   defined) box. The dot is now the quiet-attention fallback beside the numeric
   .msgr-nav-unread-badge (see the NOTIFICATIONS block). */
.bottom-nav-item .bottom-nav-pending {
    position: absolute;
    top: 9px;
    right: calc(50% - 15px);
    width: 9px;
    height: 9px;
    margin: 0;
    border-radius: 50%;
    background: var(--color-pulse-dot);
    border: 2px solid var(--color-card);
    pointer-events: none;
    animation: livePulse 1.5s ease-in-out infinite;
}

/* Dashboard body clearance so fixed/scrolled content clears the bar. Scoped to
   the dashboard via .has-bottom-nav (added by bottom-nav.js) because style.css
   loads on every page. */
body.has-bottom-nav {
    padding-bottom: calc(var(--bottom-nav-row) + max(var(--bottom-nav-min-clear), calc(var(--bottom-nav-gap) + max(env(safe-area-inset-bottom, 0px), var(--sab-floor, 0px)))));
}
html.cap-inset-always body.has-bottom-nav {
    padding-bottom: calc(var(--bottom-nav-row) + max(var(--bottom-nav-min-clear), var(--bottom-nav-gap)));
}
/* CSS-floor fallback: this selector's higher specificity + later source order
   beats the generic "html.cap-inset-always.cap-inset-floor body" restore rule
   in css/style-03.css, so the floor is silently dropped without its own
   restore here even though this is body-level padding. Mirrors the
   three-rule pattern. Ported from canopy 2026-08-11. */
html.cap-inset-always.cap-inset-floor body.has-bottom-nav {
    padding-bottom: calc(var(--bottom-nav-row) + max(var(--bottom-nav-min-clear), calc(var(--bottom-nav-gap) + var(--sab-floor, 0px))));
}

/* While the keyboard is open the bar itself is hidden (.bottom-nav.kb-hidden,
   display: none) but without this override the body above kept reserving the
   bar's full row + clearance anyway, leaving a dead grey band between the
   content and the keyboard (measured live: 578px viewport - 52px top inset -
   74px reserved nav space = 452px .app-container, a 74px empty strip). Collapse
   the reservation to 0 whenever nav-kb-hidden is set (js/bottom-nav.js toggles it
   in lockstep with .kb-hidden on the same focusin/focusout pair): the home
   indicator itself is covered by the keyboard while it is up, so there is no
   safe-area strip left to clear either, in both inset modes. */
body.has-bottom-nav.nav-kb-hidden {
    padding-bottom: 0;
}
html.cap-inset-always body.has-bottom-nav.nav-kb-hidden {
    padding-bottom: 0;
}
/* No cap-inset-floor companion needed: the keyboard is up, covering the home
   indicator itself, so there is no safe area left to restore regardless of
   floor state. Allowlisted in scripts/check-safe-area-pattern.mjs. Ported
   from canopy 2026-08-11. */

/* ── More page > Favourites customiser ─────────────────────────────────────── */
.more-favs-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.more-favs-head h2 { margin: 0; }
.more-favs-reset {
    font-size: var(--font-size-label);
    color: var(--color-primary);
    text-decoration: none;
    white-space: nowrap;
}
@media (hover: hover) {
    .more-favs-reset:hover { text-decoration: underline; }
}
.more-favs-hint { margin: 6px 0 14px; }
.more-favs-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
}
.more-fav-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 14px 6px;
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    cursor: pointer;
    color: var(--color-primary);
    transition: background 0.15s var(--ease-out), border-color 0.15s var(--ease-out);
}
@media (hover: hover) {
    .more-fav-tile:hover { border-color: var(--color-primary); }
}
.more-fav-tile i { font-size: 24px; display: inline-flex; }
.more-fav-tile-label {
    font-size: var(--font-size-small);
    color: var(--color-text);
    text-align: center;
    line-height: 1.2;
    max-width: 100%;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: break-word;
}

/* Favourite picker modal rows */
.fav-picker-group { margin-bottom: 12px; }
.fav-picker-group-label {
    display: block;
    font-size: var(--font-size-subheading);
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--color-text-light);
    padding: 4px 4px 6px;
}
.fav-picker-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 10px 12px;
    background: none;
    border: none;
    border-radius: 10px;
    text-align: left;
    font-family: inherit;
    font-size: var(--font-size-body);
    color: var(--color-text);
    cursor: pointer;
    transition: background 0.15s var(--ease-out);
}
@media (hover: hover) {
    .fav-picker-row:hover { background: var(--color-bg-subtle); }
}
.fav-picker-row i { font-size: 20px; color: var(--color-primary); display: inline-flex; width: 24px; justify-content: center; flex-shrink: 0; }
.fav-picker-row-label { flex: 1; }
.fav-picker-row-current { background: var(--color-bg-subtle); font-weight: 600; }
.fav-picker-row-check { color: var(--color-primary); font-weight: 700; }
.fav-picker-row-disabled { opacity: 0.4; cursor: not-allowed; }
@media (hover: hover) {
    .fav-picker-row-disabled:hover { background: none; }
}

/* ── More page (tab-more) - designed layout ────────────────────────────────
   The relocated nav drawer is restyled into a calm settings-style page: a
   compact profile card, then one card per nav section with icon + label rows.
   Account + Sign Out keep their list rows (no icons) inside the same card
   chrome. Icons come from js/modules.js tabIcon() (see js/auth.js renderers). */
/* Flat cards (border only, no shadow): with ~16 nav sections, per-card shadows
   read as many floating objects; flat grouped cards read as one calm page. */
/* margin-bottom matches the 10px rhythm of the nav-menu cards below; without it
   the favourites card inherits the phone .card override (margin-bottom: 0) and
   sits flush against the profile card while every card below has a 10px gap. */
#moreFavsSection .card { box-shadow: none; margin-bottom: 10px; }
#tab-more .nav-menu-profile {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 14px;
    padding: 14px 16px;
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    margin-bottom: 10px;
}
#tab-more .nav-menu-profile-img,
#tab-more .nav-menu-profile-placeholder {
    width: 56px;
    height: 56px;
}
#tab-more .nav-menu-profile-name { margin-top: 0; }

#tab-more .nav-menu-section,
#tab-more .nav-menu-signout {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 6px 8px 8px;
    margin-bottom: 10px;
}
#tab-more .nav-menu-signout { padding: 4px 8px; }
#tab-more .nav-menu-section-label { padding: 8px 10px 4px; }

/* Icon + label rows, comfortably spaced. min-height keeps every row at the
   44px tap-target floor; the Dark Mode toggle joins the list so its label
   x-aligns with the sibling account links (its base rule pads 12px). */
#tab-more .nav-menu-tab,
#tab-more .nav-menu-section > a,
#tab-more .dark-mode-toggle {
    gap: 14px;
    padding: 11px 10px;
    border-radius: 10px;
    min-height: 44px;
}
/* Plain text links (Edit Profile, Sign Out) are block in the base rule; flex
   centers their single line inside the 44px row. */
#tab-more .nav-menu-section > a {
    display: flex;
    align-items: center;
}
#tab-more .nav-menu-tab i,
#tab-more .dark-mode-toggle i {
    font-size: 20px;
    color: var(--color-primary);
    display: inline-flex;
    width: 24px;
    justify-content: center;
    flex-shrink: 0;
}
#tab-more .nav-menu-tab-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Group the moon icon + label so they stay left while the toggle track keeps
   its right anchor (the button is justify-content: space-between). The 14px gap
   matches .nav-menu-tab, so "Dark Mode" x-aligns with the sibling rows' labels. */
#tab-more .dark-mode-label { display: flex; align-items: center; gap: 14px; min-width: 0; }

/* ============================================================
   Dark Mode Transition
   ============================================================ */

.theme-transitioning,
.theme-transitioning *,
.theme-transitioning *::before,
.theme-transitioning *::after {
    transition: background-color 0.5s ease, color 0.5s ease, border-color 0.5s ease, box-shadow 0.5s ease !important;
}

/* ============================================================
   Dark Mode
   ============================================================ */

[data-theme="dark"] select {
    color-scheme: dark;
}

[data-theme="dark"] {
    color-scheme: dark;
    --color-bg: #111313;
    --color-card: #1d2020;
    --color-surface: #1d2020;
    --color-text: #F0ECF7;
    --color-text-light: #9A9A9A;
    --color-border: #2f3736;
    --color-shadow: 0 2px 8px rgba(242, 149, 78, 0.15);
    --color-primary: #F2954E;
    --color-primary-light: #F7B27E;
    --color-primary-dark: #D9772E;
    --color-accent: #E0996A;
    --color-success: #2E9E5E;
    --color-success-bg: #1a3d28;
    --color-error: #E05555;
    --color-error-bg: #3d1a1a;
    --color-danger: #E05555;
    --color-warning-bg: rgba(212, 168, 67, 0.15);
    /* Slightly deeper amber than light mode so a full-strength swatch does not glare
       against dark surfaces; still OPAQUE with its own dark text, so legibility does not
       depend on whatever bubble it lands on. */
    --color-search-mark-bg: #e6b229;
    --color-search-mark-text: #241c00;
    --color-msgr-tick-read: #4fc3f7;
    --color-primary-soft: rgba(242, 149, 78, 0.18);
    --color-surface-alt: #252929;
    --color-hover: rgba(255, 255, 255, 0.06);
    --color-bg-subtle: rgba(255, 255, 255, 0.04);
    --color-border-subtle: rgba(255, 255, 255, 0.10);
}

[data-theme="dark"] body {
    background-color: var(--color-bg);
    color: var(--color-text);
}

[data-theme="dark"] .card {
    background: var(--color-card);
    border-color: var(--color-border);
}

[data-theme="dark"] .modal {
    background: var(--color-card);
    border: 1px solid var(--color-border);
}

[data-theme="dark"] .data-table th {
    background: var(--color-bg);
    color: var(--color-primary-light);
}

[data-theme="dark"] .form-group input,
[data-theme="dark"] .form-group select,
[data-theme="dark"] .form-group textarea,
[data-theme="dark"] .detail-edit-input,
[data-theme="dark"] select.detail-edit-input {
    background-color: var(--color-bg);
    color: var(--color-text);
    border-color: var(--color-border);
}
[data-theme="dark"] .form-group select,
[data-theme="dark"] select.detail-edit-input,
[data-theme="dark"] .phone-input-group .country-code-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23AAAAAA' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
}

[data-theme="dark"] .planner-slot {
    background: var(--color-card);
    border-color: var(--color-border);
}

[data-theme="dark"] .planner-slot-registered {
    background: color-mix(in srgb, var(--color-primary) 15%, transparent);
    border-color: var(--color-primary);
}

[data-theme="dark"] .planner-day-header {
    background: var(--color-primary-dark);
}

[data-theme="dark"] .nav-menu {
    background: transparent;
}

[data-theme="dark"] .nav-menu-profile {
    border-color: var(--color-border);
}

[data-theme="dark"] .nav-menu-section {
    border-color: var(--color-border);
}

[data-theme="dark"] .announcement-card {
    background: var(--color-card);
}

[data-theme="dark"] .announcement-card.unread {
    background: rgba(212, 168, 67, 0.12);
}

[data-theme="dark"] .student-card {
    background: var(--color-card);
}

[data-theme="dark"] .detail-row {
    border-color: var(--color-border);
}

[data-theme="dark"] .alert-error {
    background: rgba(224, 85, 85, 0.15);
    color: var(--color-error);
    border-color: rgba(224, 85, 85, 0.3);
}

[data-theme="dark"] .alert-info {
    background: rgba(242, 149, 78, 0.15);
    color: var(--color-text);
    border-color: rgba(242, 149, 78, 0.3);
}

[data-theme="dark"] .tabs {
    border-color: var(--color-border);
}

[data-theme="dark"] .search-bar input {
    background: var(--color-bg);
    color: var(--color-text);
    border-color: var(--color-border);
}

[data-theme="dark"] .badge-success {
    background: rgba(46, 158, 94, 0.2);
    color: var(--color-success);
}

[data-theme="dark"] .badge-warning { color: #F5D78A; }

[data-theme="dark"] .badge-purple {
    background: rgba(139, 92, 246, 0.2);
    color: #A78BFA;
}

[data-theme="dark"] .badge-teal {
    background: rgba(20, 184, 166, 0.2);
    color: #5EEAD4;
}

/* Dark mode toggle button on the More page (Account section) */
.dark-mode-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 10px 12px;
    background: none;
    border: none;
    border-radius: 8px;
    font-family: inherit;
    font-size: var(--font-size-body);
    font-weight: 500;
    color: var(--color-text);
    cursor: pointer;
    transition: background 0.15s var(--ease-out);
    text-align: left;
}
@media (hover: hover) {
    .dark-mode-toggle:hover {
        background: rgba(232, 105, 30, 0.06);
    }
}
.dark-mode-track {
    width: 36px;
    height: 20px;
    border-radius: 10px;
    background: var(--color-border);
    position: relative;
    transition: background 0.2s var(--ease-out);
    flex-shrink: 0;
}
.dark-mode-track.on {
    background: var(--color-primary);
}
.dark-mode-thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #fff;
    transition: transform 0.2s var(--ease-out);
}
.dark-mode-track.on .dark-mode-thumb {
    transform: translateX(16px);
}

/* Language toggle segmented control (More page, Account section, right after
   Dark Mode). Reuses .ann-seg-control/.ann-seg (Announcement segmented
   control, style-01.css); sized compact like the messenger Mine/All owner
   filter (#msgrOwnerFilterControl, style-08.css) rather than the default
   .ann-seg mobile 44px touch-target floor, since this sits inside an
   already-44px .dark-mode-toggle row. Ported from canopy. */
#langSegControl { width: auto; flex-shrink: 0; }
#langSegControl .ann-seg { min-height: 0; padding: 5px 12px; font-size: 13px; white-space: nowrap; flex: 0 0 auto; }

[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(1) brightness(1.5);
}

/* ============================================================
   Org Switcher
   ============================================================ */
.org-switcher { position: relative; }
.org-switcher-btn { background: none; border: 1px solid rgba(255,255,255,0.35); border-radius: 6px; color: white; padding: 4px 10px; font-size: var(--font-size-label); cursor: pointer; display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.org-switcher-btn:hover { background: rgba(255,255,255,0.12); }
.org-panel { position: absolute; top: calc(100% + 8px); right: 0; background: var(--color-card); border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); min-width: 180px; z-index: 200; padding: 8px 0; border: 1px solid var(--color-border); }
.org-panel-label { font-size: var(--font-size-subheading); font-weight: 700; text-transform: uppercase; color: var(--color-text-light); padding: 4px 14px 8px; letter-spacing: 0.04em; }
.org-panel ul { list-style: none; margin: 0; padding: 0; }
.org-panel li button { width: 100%; text-align: left; padding: 9px 14px; background: none; border: none; cursor: pointer; font-size: var(--font-size-body); color: var(--color-text); }
.org-panel li button:hover { background: var(--color-bg); }
.org-panel li button.active { color: var(--color-primary); font-weight: 600; }

/* ============================================================
   Branding Settings
   ============================================================ */
.section-divider-label {
    font-size: var(--font-size-small);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-light);
    margin: 20px 0 4px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--color-border);
}
.branding-color-row { display: flex; align-items: center; gap: 8px; }
.branding-color-swatch { width: 36px; height: 36px; border: 1px solid var(--color-border); border-radius: 6px; padding: 2px; cursor: pointer; background: none; flex-shrink: 0; }
.branding-color-swatch::-webkit-color-swatch-wrapper { padding: 0; }
.branding-color-swatch::-webkit-color-swatch { border-radius: 4px; border: none; }
.branding-color-row .detail-edit-input { flex: 1; font-family: monospace; text-transform: uppercase; }

/* ── Theme Colour Tab Toggle (Light / Dark) ── */
.theme-colour-tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.theme-colour-tab { padding: 5px 14px; font-size: var(--font-size-label); border: 1px solid var(--color-border); border-radius: 20px; background: none; color: var(--color-text-light); cursor: pointer; transition: background 0.15s, color 0.15s; }
.theme-colour-tab.active { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.theme-colour-tab:hover:not(.active) { background: var(--color-primary-light); color: #fff; border-color: var(--color-primary-light); }
@media (max-width: 767px) { .theme-colour-tab { min-height: 44px; padding: 10px 16px; } }

/* ── Theme Advanced disclosure toggle ── */
.theme-advanced-toggle { background: none; border: none; color: var(--color-text-light); font-size: var(--font-size-small); cursor: pointer; padding: 4px 0; display: flex; align-items: center; gap: 4px; }

/* ── Generic toggle switch (used in Theme Management) ── */
.toggle-label { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; }
.toggle-label input[type="checkbox"] { display: none; }
.toggle-track { position: relative; width: 40px; height: 22px; background: var(--color-border); border-radius: 11px; transition: background 0.2s; flex-shrink: 0; }
.toggle-thumb { position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; background: #fff; border-radius: 50%; transition: transform 0.2s; box-shadow: 0 1px 3px rgba(0,0,0,0.25); }
.toggle-label input:checked + .toggle-track { background: var(--color-primary); }
.toggle-label input:checked + .toggle-track .toggle-thumb { transform: translateX(18px); }
.toggle-text { font-size: var(--font-size-body); color: var(--color-text); }

/* Module Management toggles */
.module-toggle-row { padding: 10px 0; border-bottom: 1px solid var(--color-border); transition: opacity 0.2s; }
.module-toggle-row:last-child { border-bottom: none; }
.module-toggle-row .toggle-label { align-items: flex-start; }
.module-toggle-row .toggle-text { line-height: 1.4; }
.module-toggle-row .module-desc { font-size: 0.85em; color: var(--color-muted); }
.module-toggle-row .dep-note { font-size: 0.8em; color: var(--color-muted); }
/* "Requires:" is always visible (informational). Muted by default; turns
   accent-coloured when deps are unmet (.dep-unmet, set by _applyModuleCascade). */
.module-toggle-row .dep-requires { display: block; font-style: italic; margin-top: 2px; color: var(--color-muted); }
.module-toggle-row .dep-requires.dep-unmet { color: var(--color-accent, #e67e22); }
.module-toggle-row.dep-disabled { opacity: 0.45; }
.module-toggle-row.dep-disabled .toggle-label { cursor: not-allowed; }

/* "Always on" base modules (Core, Announcements): disabled toggle reads as
   a permanent grey pill (not a broken/blocked state - those use 0.45
   dep-disabled opacity above). HTML's `disabled` attribute already blocks
   the click; this just communicates the permanence visually. */
.module-toggle-row.always-on .toggle-label { cursor: not-allowed; }
.module-toggle-row.always-on .toggle-track { background: var(--color-border); opacity: 0.65; }
.module-toggle-row.always-on .toggle-thumb { background: #f4f4f4; box-shadow: 0 1px 2px rgba(0,0,0,0.15); }

/* ============================================================
   HR Pending Dot Indicators
   ============================================================ */

/* The non-messenger red pulse dot classes (the HR/leave pulse and its TA,
   holiday, staff-schedule and enrolment variants) were removed with the red-dot
   system; those events now surface in the Notifications tab. Only the messenger
   pulse (.msgr-pending-dot, below) and the messenger-only More-button aggregate
   remain. --color-pulse-dot + @keyframes livePulse are kept for the messenger dot. */

/* ── Flatpickr date range picker overrides ──────────────────── */
/* !important needed - Flatpickr ships hardcoded rgba colours that */
/* otherwise win on specificity against var() declarations.        */
.flatpickr-calendar {
    background: var(--color-card) !important;
    border-color: var(--color-border) !important;
    box-shadow: 0 4px 16px rgba(0,0,0,0.25) !important;
    position: fixed !important; /* escapes overflow-y:auto clipping on .modal */
    z-index: 99999 !important; /* showModal() starts at 10010 and increments; must stay above */
}
.flatpickr-months,
.flatpickr-months .flatpickr-month,
.flatpickr-weekdays,
span.flatpickr-weekday {
    background: var(--color-primary) !important;
    color: #fff !important;
    fill: #fff !important;
}
.flatpickr-current-month,
.flatpickr-current-month .flatpickr-monthDropdown-months,
.flatpickr-current-month input.cur-year {
    color: #fff !important;
    fill: #fff !important;
    background: transparent !important;
}
.flatpickr-days, .dayContainer { background: var(--color-card) !important; }
.flatpickr-day {
    color: var(--color-text) !important;
    border-color: transparent !important;
}
.flatpickr-day:hover {
    background: var(--color-primary) !important;
    border-color: var(--color-primary) !important;
    color: #fff !important;
}
.fp-multiple-mode .flatpickr-day:not(.selected):hover {
    background: transparent !important;
    border-color: var(--color-primary) !important;
    color: var(--color-text) !important;
}
.flatpickr-day.selected,
.flatpickr-day.startRange,
.flatpickr-day.endRange,
.flatpickr-day.selected:hover,
.flatpickr-day.startRange:hover,
.flatpickr-day.endRange:hover {
    background: var(--color-primary) !important;
    border-color: var(--color-primary) !important;
    color: #fff !important;
}
/* inRange: use rgba so only the background gets transparency, not the text */
.flatpickr-day.inRange {
    background: rgba(242, 149, 78, 0.2) !important;
    border-color: transparent !important;
    box-shadow: -5px 0 0 rgba(242, 149, 78,0.2), 5px 0 0 rgba(242, 149, 78,0.2) !important;
    color: var(--color-text) !important;
}
.flatpickr-day.flatpickr-disabled,
.flatpickr-day.flatpickr-disabled:hover {
    color: var(--color-text-light) !important;
    background: transparent !important;
    cursor: not-allowed !important;
}
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay {
    color: var(--color-text-light) !important;
    opacity: 0.5;
}
.flatpickr-day.today:not(.selected) { border-color: var(--color-primary) !important; }
.numInputWrapper:hover { background: transparent !important; }

/* ── HuoMa date picker - custom month/year overlay nav ────── */
/* Hide flatpickr's arrows everywhere; clickable labels + grid overlay replace them. */
.flatpickr-prev-month,
.flatpickr-next-month {
    display: none !important;
}

/* Clickable month/year labels with caret affordance */
.fp-nav-label {
    display: inline-block;
    font-weight: 700;
    font-size: inherit;
    color: inherit;
    cursor: pointer;
    border-bottom: 1px solid currentColor;
    line-height: 1.4;
}

.fp-nav-label::after {
    content: ' ▾';
    font-size: 0.75em;
    vertical-align: 1px;
}

@media (hover: hover) {
    .fp-nav-label:hover {
        opacity: 0.7;
    }
}

/* ── Simple-nav pickers (e.g. trial form) — static label + native prev/next arrows ── */
/* Re-show the arrows the global rule hides (higher specificity wins). */
.flatpickr-calendar.fp-simple-nav .flatpickr-prev-month,
.flatpickr-calendar.fp-simple-nav .flatpickr-next-month {
    display: flex !important;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}
.flatpickr-calendar.fp-simple-nav .flatpickr-prev-month svg,
.flatpickr-calendar.fp-simple-nav .flatpickr-next-month svg {
    fill: #fff !important;
    width: 16px;
    height: 16px;
}
.flatpickr-calendar.fp-simple-nav .flatpickr-prev-month.flatpickr-disabled {
    display: flex !important;
    opacity: 0.35;
    cursor: default;
}
/* Static month/year label - white header text, no caret, not clickable */
.fp-nav-static {
    display: inline-block;
    font-weight: 700;
    font-size: inherit;
    color: #fff;
    line-height: 1.4;
}
/* Disabled days (weekends, public holidays, centre closures) read the SAME faded
   grey as prev/next-month overflow days so the blocked state is obvious. The
   global .flatpickr-disabled rule sets the colour but not the opacity. */
.flatpickr-calendar.fp-simple-nav .flatpickr-day.flatpickr-disabled,
.flatpickr-calendar.fp-simple-nav .flatpickr-day.flatpickr-disabled:hover {
    opacity: 0.5;
}
@media (hover: hover) {
    .flatpickr-calendar.fp-simple-nav .flatpickr-prev-month:not(.flatpickr-disabled):hover,
    .flatpickr-calendar.fp-simple-nav .flatpickr-next-month:hover {
        opacity: 0.7;
    }
}

/* ── Month-only picker (huomaDatePicker mode: 'month' via monthSelect plugin) ── */
/* The calendar carries BOTH .fp-month-mode and .fp-simple-nav — the latter handles
   prev/next chevron display + disabled state, no duplicate rules needed here. */

/* Pin the whole calendar to a tight, fixed width so the header bar, inner
   container, and month grid all line up without trailing dead space. Without
   this the inner container inherits flatpickr's default ~308px while the grid
   sits at 280px, producing an obvious 26px gap on the right edge. */
.flatpickr-calendar.fp-month-mode,
.flatpickr-calendar.fp-month-mode .flatpickr-months,
.flatpickr-calendar.fp-month-mode .flatpickr-innerContainer,
.flatpickr-calendar.fp-month-mode .flatpickr-rContainer {
    width: 280px !important;
    min-width: 280px !important;
    max-width: 280px !important;
    box-sizing: border-box !important;
}

/* Month-grid cells: match the same primary/text tokens the day grid uses. */
/* 3×4 grid (mirrors the legacy day-grid month overlay) so the calendar doesn't
   collapse to a narrow strip. width:100% makes the grid fill its inner container
   so it sits flush with the header bar above — without it, the grid is narrower
   than the header and leaves a trailing dead zone on the right (only). */
.flatpickr-monthSelect-months {
    background: var(--color-card) !important;
    padding: 10px !important;
    display: grid !important;
    grid-template-columns: repeat(3, 1fr) !important;
    gap: 6px !important;
    width: 100% !important;
    box-sizing: border-box !important;
}
.flatpickr-monthSelect-month {
    color: var(--color-text) !important;
    background: transparent !important;
    border: 1px solid transparent !important;
    border-radius: 6px !important;
    /* width:100% overrides the plugin's `width: 33%` (which resolves against the
       grid track, leaving the element ~27px wide — far narrower than e.g.
       "September") so the highlight box always fully contains its text. */
    display: block !important;
    width: 100% !important;
    box-sizing: border-box !important;
    padding: 8px 4px !important;
    margin: 0 !important;
    text-align: center !important;
    font-size: var(--font-size-body) !important;
    cursor: pointer !important;
    transition: background 0.15s cubic-bezier(0.22, 1, 0.36, 1),
                color 0.15s cubic-bezier(0.22, 1, 0.36, 1),
                border-color 0.15s cubic-bezier(0.22, 1, 0.36, 1) !important;
}
.flatpickr-monthSelect-month:hover {
    background: var(--color-primary) !important;
    color: #fff !important;
    border-color: var(--color-primary) !important;
}
/* Today's month gets a primary-coloured border (matches .flatpickr-day.today). */
.flatpickr-monthSelect-month.today:not(.selected) {
    border-color: var(--color-primary) !important;
}
.flatpickr-monthSelect-month.selected,
.flatpickr-monthSelect-month.selected:hover {
    background: var(--color-primary) !important;
    color: #fff !important;
    border-color: var(--color-primary) !important;
}
.flatpickr-monthSelect-month.flatpickr-disabled,
.flatpickr-monthSelect-month.flatpickr-disabled:hover {
    color: var(--color-text-light) !important;
    background: transparent !important;
    border-color: transparent !important;
    opacity: 0.5;
    cursor: not-allowed !important;
}

/* Inline month/year picker - replaces the day grid in-flow (no z-index fight) */
.fp-overlay {
    background: var(--color-card-bg, var(--color-card, #fff));
    box-sizing: border-box;
    padding: 8px;
    display: flex;
    flex-direction: column;
    /* height set by JS to match the hidden weekdays + days region */
}

/* 4×3 month grid - rows share the overlay height equally */
.fp-overlay-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: repeat(3, minmax(0, 60px));
    gap: 4px;
    align-content: start;
    flex: 1;
    min-height: 0;
}

/* Year grid - 4 columns; rows cap at 60px so a narrow range (e.g. 3 years)
   doesn't stretch a single row to fill the entire day-grid area. */
.fp-overlay-years {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: minmax(0, 60px);
    gap: 4px;
    align-content: start;
    flex: 1;
    min-height: 0;
}

.fp-overlay-btn {
    background: none;
    border: none;
    padding: 8px 4px;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 500;
    color: var(--color-text, #333);
    cursor: pointer;
    text-align: center;
    transition: background 0.12s;
    width: 100%;
    height: 100%;
}

@media (hover: hover) {
    .fp-overlay-btn:hover:not(.fp-overlay-active) {
        background: var(--color-bg-hover, #f5f5f5);
    }
}

.fp-overlay-btn.fp-overlay-active {
    background: var(--color-primary, #E8691E);
    color: #fff;
    font-weight: 600;
}

/* ── HuoMa time wheel (mode:'time') ───────────────────────────
   A rolling-digit selector that replaces flatpickr's editable-number
   spinner. Built in js/datepicker.js (_cdtwBuild). Cell height 40px MUST
   match CDTW_CELL there; the scroll viewport shows 5 cells (200px) with
   80px spacers so the first/last value can centre under the band. */
.flatpickr-calendar.cdtw-cal {
    width: auto !important;
    padding: 8px 6px !important;
}
.cdtw {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
}
/* Centre selection band: a neutral tint (org-agnostic) under the chosen row. */
.cdtw-band {
    position: absolute;
    left: 6px;
    right: 6px;
    top: 80px;
    height: 40px;
    border-radius: 8px;
    background: rgba(128, 128, 128, 0.14);
    pointer-events: none;
    z-index: 0;
}
.cdtw-col {
    position: relative;
    width: 60px;
    height: 200px;
    z-index: 1;
}
.cdtw-scroll {
    height: 200px;
    overflow-y: auto;
    scroll-snap-type: y mandatory;
    scrollbar-width: none;            /* Firefox */
    -ms-overflow-style: none;         /* old Edge */
    overscroll-behavior: contain;     /* don't scroll the page behind the popup */
    touch-action: pan-y;
}
.cdtw-scroll::-webkit-scrollbar { display: none; }   /* WebKit/Blink */
.cdtw-scroll.cdtw-dragging { scroll-snap-type: none; cursor: grabbing; }
.cdtw-spacer { height: 80px; }       /* (5-1)/2 cells, so end values can centre */
.cdtw-cell {
    height: 40px;
    line-height: 40px;
    text-align: center;
    font-size: 20px;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-light);
    scroll-snap-align: center;
    cursor: pointer;
    user-select: none;
    transition: color 0.12s, font-weight 0.12s;
}
.cdtw-cell.cdtw-cell-active {
    color: var(--color-primary);
    font-weight: 700;
}
.cdtw-colon {
    z-index: 1;
    font-size: 20px;
    font-weight: 700;
    color: var(--color-text);
    padding-bottom: 2px;
}
/* Up/down chevrons: precision stepping on desktop. Hover-revealed (touch uses
   swipe), positioned over the top and bottom edges of each column. */
.cdtw-chev {
    position: absolute;
    left: 0;
    right: 0;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    color: var(--color-text-light);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.12s, color 0.12s;
    z-index: 2;
    font-size: 13px;
}
.cdtw-chev-up { top: 0; }
.cdtw-chev-down { bottom: 0; }
@media (hover: hover) {
    .cdtw-col:hover .cdtw-chev { opacity: 0.85; }
    .cdtw-chev:hover { color: var(--color-primary); opacity: 1; }
}

/* ── Apply Leave picker - group leave chip overlay ─────────── */
.flatpickr-day {
    position: relative;
}
/* Shift day number up so chips fit below it within the 39px cell */
.flatpickr-day.fp-has-chips {
    line-height: 1 !important;
    padding-top: 5px !important;
}
.fp-group-chips {
    display: flex;
    gap: 1px;
    flex-wrap: wrap;
    justify-content: center;
    margin-top: 2px;
}
.fp-group-chip {
    flex-shrink: 0;
    width: 10px;
    height: 10px;
    border-radius: 2px;
    font-size: 0.48rem;
    font-weight: 700;
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.fp-group-chip-more {
    font-size: 0.45rem;
    color: var(--color-text-light);
    line-height: 10px;
    align-self: center;
}
/* Capacity-full days get a subtle red tint */
.flatpickr-day.fp-day-at-capacity {
    background: rgba(239, 68, 68, 0.12) !important;
}
/* Restore primary bg on hover/selection so tint doesn't bleed through */
.flatpickr-day.fp-day-at-capacity:hover,
.flatpickr-day.fp-day-at-capacity.selected,
.flatpickr-day.fp-day-at-capacity.startRange,
.flatpickr-day.fp-day-at-capacity.endRange,
.flatpickr-day.fp-day-at-capacity.inRange {
    background: var(--color-primary) !important;
}

/* Non-working days (weekends, off-days per workweek, public holidays) - quiet grey wash */
.flatpickr-day.fp-non-working:not(.selected):not(.startRange):not(.endRange):not(.inRange):not(:hover) {
    background: rgba(128, 128, 128, 0.08) !important;
    color: var(--color-text-light) !important;
}

/* Designated work days - subtle blue accent to show override of weekend/holiday */
.flatpickr-day.fp-designated-work {
    position: relative;
}
.flatpickr-day.fp-designated-work:not(.selected):not(.startRange):not(.endRange):not(.inRange):not(:hover) {
    background: rgba(59, 130, 246, 0.08) !important;
    color: var(--color-text) !important;
}
.flatpickr-day.fp-designated-work::after {
    content: '';
    position: absolute;
    bottom: 2px;
    left: 50%;
    transform: translateX(-50%);
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--color-primary);
}

