/* The White Orchid - Mobile-First Styles */

/* ═══ 0. BRAND FONTS ═══ */

@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-Light.ttf') format('truetype');
    font-weight: 300;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-LightItalic.ttf') format('truetype');
    font-weight: 300;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-Regular.ttf') format('truetype');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-Italic.ttf') format('truetype');
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-Medium.ttf') format('truetype');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-MediumItalic.ttf') format('truetype');
    font-weight: 500;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-SemiBold.ttf') format('truetype');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-SemiBoldItalic.ttf') format('truetype');
    font-weight: 600;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-Bold.ttf') format('truetype');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-BoldItalic.ttf') format('truetype');
    font-weight: 700;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-ExtraBold.ttf') format('truetype');
    font-weight: 800;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Fira Sans';
    src: url('/fonts/FiraSans-ExtraBoldItalic.ttf') format('truetype');
    font-weight: 800;
    font-style: italic;
    font-display: swap;
}

/* ═══ 1. RESET & BASE ═══ */

:root {
    /* Drives the UA canvas/backdrop colour. Without this the browser's base
       layer stays light, so iOS WebKit flashes a pale-cream backdrop during
       cross-document navigation (dashboard ↔ messenger) before the new page's
       dark body paints. [data-theme="dark"] flips it to dark below. */
    color-scheme: light;
    --color-primary: #254E48;
    --color-primary-light: #48716b;
    --color-primary-dark: #022b25;
    --color-on-primary: #fff;
    --color-accent: #DEC5D8;
    --color-whatsapp: #25D366;
    --color-bg: #F5F6E7;
    --color-card: #FFFFFF;
    --color-surface: #FFFFFF;
    --color-text: #2D2D2D;
    --color-text-light: #6B6B6B;
    --color-muted: var(--color-text-light);
    --color-bg-subtle: rgba(0, 0, 0, 0.03);
    --color-border-subtle: rgba(0, 0, 0, 0.08);
    --color-success: #1E6B3D;
    --color-success-bg: #e8f7ee;
    --color-error: #C0392B;
    --color-error-bg: #fdecea;
    --color-border: #e1e2d3;
    --color-shadow: 0 2px 8px rgba(37, 78, 72, 0.1);
    --color-danger: #C0392B;
    --color-msgr-tick-read: #4fc3f7;
    --color-primary-soft: rgba(37, 78, 72, 0.12);
    --color-warning: #f59e0b;
    --color-warning-bg: #fff8e1;
    --font-family: 'Fira Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --color-surface-alt: #EDEEE0;
    --color-title-color: var(--color-primary);
    --color-title-font: inherit;

    /* Font size tokens - 5 categories, desktop defaults */
    --font-size-heading: 1.25rem;
    --font-size-subheading: 0.75rem;
    --font-size-body: 0.88rem;
    --font-size-label: 0.82rem;
    --font-size-small: 0.72rem;
    /* Messenger message body. Desktop matches --font-size-body (unchanged); the
       mobile override below bumps it one step larger for comfortable phone reading. */
    --font-size-msgr: var(--font-size-body);

    /* Animation easing tokens */
    --ease-out: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
    --ease-keyboard: cubic-bezier(0.38, 0.7, 0.125, 1); /* approximates the iOS soft-keyboard slide curve */

    /* Soft-keyboard inset (px). Runtime value driven by _wireKeyboardInset() in
       js/shared.js from visualViewport — height of the on-screen keyboard, or 0
       when hidden / on desktop. Consumed by .modal-overlay + .modal so a focused
       field is always lifted clear of the keyboard. See js/shared.js for why. */
    --kb-inset: 0px;

    /* Animation duration tokens (orion_motion). The companion to the easing
       tokens above; the Motion Library primitives reference these by name so
       js/animations.js ANIMATION_REGISTRY durations stay parity-checkable. */
    --dur-micro: 120ms;       /* press / tactile give */
    --dur-enter: 220ms;       /* card / list entrance */
    --dur-feedback: 250ms;    /* pop / pulse / value bump */
    --dur-transition: 300ms;  /* tab / view swap */
    --dur-celebrate: 450ms;   /* success */
    --dur-swipe: 500ms;       /* full-panel push / pop (matches Telegram iOS) */
}

/* Font size tokens - mobile defaults */
@media (max-width: 767px) {
    :root {
        --font-size-heading: 1.1rem;
        --font-size-subheading: 0.7rem;
        --font-size-body: 0.85rem;
        --font-size-label: 0.78rem;
        --font-size-small: 0.68rem;
        /* Messenger bubble text — half a step above mobile body (0.85rem) so chat
           reads easier on a phone without making bubbles chunky or fitting less. */
        --font-size-msgr: 0.9rem;
    }
}

/* Prevent iOS Safari/Chrome auto-zoom on input focus (requires font-size ≥ 16px).
   !important is needed because many module-scoped selectors (e.g.
   #tab-settings .form-group input) have higher specificity and would otherwise
   pull font-size back down to var(--font-size-body) ≈ 13.6px on mobile. */
@media (max-width: 767px) {
    input, select, textarea {
        font-size: 16px !important;
    }
}

/* ═══ 2. TYPOGRAPHY & FONT SCALE ═══ */

/* Typography utility classes */
.text-heading    { font-size: var(--font-size-heading) !important; }
.text-subheading { font-size: var(--font-size-subheading) !important; }
.text-body       { font-size: var(--font-size-body) !important; }
.text-label      { font-size: var(--font-size-label) !important; }
.text-small      { font-size: var(--font-size-small) !important; }

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* Paint the root canvas itself (not just <body>) so the html element behind
   the body is the theme bg, never the UA default. Covers the navigation gap and
   the first pre-body-paint frame, where body's background hasn't drawn yet. */
html {
    background-color: var(--color-bg);
}

body {
    font-family: var(--font-family);
    background-color: var(--color-bg);
    color: var(--color-text);
    min-height: 100vh;   /* fallback for browsers without dvh support */
    min-height: 100dvh;  /* fits the current visible viewport on mobile */
    display: flex;
    flex-direction: column;
}

/* ═══ 3. LAYOUT (grid, flex, containers) ═══ */

/* App Shell */
.app-container {
    margin: 0 auto;
    padding: 16px;
    width: 100%;
    min-width: 0; /* flex item: prevent expanding past viewport width */
    flex: 1;
    display: flex;
    flex-direction: column;
    position: relative;
}

/* Header */
.app-header {
    text-align: left;
    padding: 24px 0 16px;
    border: none;
}

.app-header .logo {
    font-size: var(--font-size-heading);
    font-weight: 700;
    color: var(--color-primary);
    letter-spacing: -0.5px;
    display: flex;
    align-items: center;
    gap: 5px;
}

.org-logo-img {
    height: 54px;
    width: auto;
    max-width: 210px;
    object-fit: contain;
    flex-shrink: 0;
}

#orgLogoName {
    color: var(--color-title-color);
    font-family: var(--color-title-font);
}

.app-header .logo small {
    display: block;
    font-size: var(--font-size-subheading);
    font-weight: 400;
    color: var(--color-text-light);
    letter-spacing: 1px;
    text-transform: uppercase;
    margin-top: 4px;
}

/* Navigation bar */
.nav-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    margin-bottom: 16px;
    border: none;
}

.nav-bar .user-info {
    font-size: var(--font-size-body);
    color: var(--color-text-light);
}

.nav-bar .nav-links {
    display: flex;
    align-items: center;
    gap: 12px;
}

.nav-bar .nav-links a {
    font-size: var(--font-size-body);
    color: var(--color-primary);
    text-decoration: none;
}



.nav-bar .nav-links a:hover {
    text-decoration: underline;
}

/* Hide desktop inline links - hamburger menu used at all sizes */
.nav-bar .nav-links > a {
    display: none;
}

.nav-bar .nav-links > .view-toggle {
    display: none;
}

/* View Toggle */
.view-toggle {
    display: flex;
    background: rgba(107, 76, 138, 0.1);
    border-radius: 20px;
    padding: 3px;
    gap: 2px;
    font-size: var(--font-size-label);
}

.view-toggle a,
.view-toggle span {
    font-size: inherit;
}

.view-toggle-btn {
    padding: 5px 12px;
    border: none;
    border-radius: 18px;
    background: transparent;
    color: var(--color-text-light);
    font-size: inherit;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    transition: all 0.2s;
    white-space: nowrap;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1.4;
    text-align: center;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.view-toggle-btn:hover {
    background: rgba(107, 76, 138, 0.12);
    color: var(--color-primary);
    text-decoration: none;
}

.view-toggle-btn.active {
    background: var(--color-primary);
    color: white;
    cursor: default;
}

.view-toggle-btn.active:hover {
    background: var(--color-primary);
    color: white;
}

/* ═══ 4. COMPONENTS (buttons, badges, cards, modals, forms, alerts) ═══ */

/* Cards */
.card {
    background: var(--color-card);
    border-radius: 12px;
    padding: 24px;
    margin-bottom: 16px;
    box-shadow: var(--color-shadow);
    border: 1px solid var(--color-border);
}

.card h2 {
    font-size: var(--font-size-heading);
    margin-bottom: 16px;
    color: var(--color-primary-dark);
}

/* Forms */
.form-group {
    margin-bottom: 16px;
}

.form-group label {
    display: block;
    font-size: var(--font-size-label);
    font-weight: 600;
    color: var(--color-text);
    margin-bottom: 6px;
}

.form-group input,
.form-group select,
.form-group textarea {
    width: 100%;
    padding: 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    font-size: var(--font-size-body);
    background: var(--color-card);
    color: var(--color-text);
    transition: border-color 0.2s;
}

.form-group textarea {
    resize: none;
    overflow-y: auto;
}

/* Date/time inputs: force them to respect width:100% on iOS.
   WebKit's native date/time picker chrome sets an intrinsic min-width
   that overrides width:100%, causing overflow on narrow screens. */
input[type="date"],
input[type="time"] {
    min-width: 0;
    max-width: 100%;
}

/* Hide native number input spinners */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    -moz-appearance: textfield;
}

.form-group select {
    padding-right: 36px;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    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='%236B6B6B' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    cursor: pointer;
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(107, 76, 138, 0.15);
}

.form-group input:disabled,
.form-group select:disabled,
.form-group textarea:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

.radio-group {
    display: flex;
    gap: 16px;
    padding: 8px 0;
}

.radio-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--font-size-body);
    cursor: pointer;
    color: var(--color-text);
}

/* Global: constrain all checkboxes/radios - Safari iOS ignores flex sizing without this */
input[type="checkbox"],
input[type="radio"] {
    width: 16px;
    height: 16px;
    min-width: 16px;
    min-height: 16px;
    flex-shrink: 0;
    accent-color: var(--color-primary);
    margin: 0;
    vertical-align: middle;
    cursor: pointer;
}

.radio-label input[type="radio"] {
    accent-color: var(--color-primary);
    width: 16px;
    height: 16px;
    margin: 0;
    vertical-align: middle;
    cursor: pointer;
}

/* Announcement audience pill selector */
.ann-audience-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 4px 0;
}
.ann-pill {
    padding: 5px 14px;
    border-radius: 20px;
    border: 1.5px solid var(--color-border);
    background: var(--color-card);
    color: var(--color-text-light);
    font-size: var(--font-size-label);
    cursor: pointer;
    transition: all 0.15s ease;
}
.ann-pill:hover { border-color: var(--color-primary); color: var(--color-primary); }
.ann-pill.active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

/* Document body formatting toolbar */
.doc-format-toolbar {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 5px 8px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-bottom: none;
    border-radius: 8px 8px 0 0;
}
.doc-format-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4px 8px;
    min-width: 30px;
    border: none;
    background: transparent;
    border-radius: 4px;
    cursor: pointer;
    color: var(--color-text);
    font-size: var(--font-size-small);
    line-height: 1;
    transition: background 0.12s;
}
.doc-format-btn:hover { background: var(--color-bg); }
.doc-format-btn-italic { font-style: italic; }
.doc-format-divider {
    width: 1px;
    height: 16px;
    background: var(--color-border);
    margin: 0 4px;
}
.doc-format-toolbar + textarea {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
}

/* Message/Document type toggle pill buttons */
.msg-type-btn {
    padding: 5px 14px;
    border-radius: 20px;
    border: 1.5px solid var(--color-border);
    background: transparent;
    color: var(--color-text-light);
    font-size: var(--font-size-body);
    cursor: pointer;
    transition: all 0.15s ease;
}
.msg-type-btn:hover { border-color: var(--color-primary); color: var(--color-primary); }
.msg-type-btn.active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

/* Announcement segmented control */
.ann-seg-control {
    display: flex;
    border: 1.5px solid var(--color-border);
    border-radius: 8px;
    overflow: hidden;
}
.ann-seg {
    flex: 1;
    padding: 7px 6px;
    border: none;
    background: var(--color-card);
    color: var(--color-text-light);
    font-size: var(--font-size-label);
    cursor: pointer;
    transition: background 0.15s var(--ease-out), color 0.15s var(--ease-out);
    text-align: center;
}
.ann-seg:not(:last-child) { border-right: 1.5px solid var(--color-border); }
.ann-seg:hover { background: var(--color-bg); }
.ann-seg.active {
    background: var(--color-primary);
    color: #fff;
}
/* Mobile touch target — desktop padding (7px) yields ~28px height; thumb taps need 44px. */
@media (max-width: 767px) {
    .ann-seg { min-height: 44px; }
}

.form-group input::placeholder {
    color: #B0A0C0;
}

.form-group .hint {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 4px;
}

/* Password field with show/hide toggle */
.password-field-wrap {
    position: relative;
    display: flex;
    align-items: stretch;
}

.password-field-wrap input {
    flex: 1;
    padding-right: 44px !important;
}

.pw-toggle {
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    width: 42px;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    color: var(--color-text-light);
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 0 8px 8px 0;
    transition: color 0.15s;
}

.pw-toggle:hover {
    color: var(--color-text);
}

.pw-toggle svg {
    width: 18px;
    height: 18px;
    pointer-events: none;
}

/* Info Icon - small filled circle with italic i, click to open info modal */
.info-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: #9baabf;
    color: #fff;
    font-size: 9px; /* fixed - pixel-precise 15px circle, must not scale with font preset */
    font-weight: 800;
    font-style: italic;
    font-family: Georgia, 'Times New Roman', serif;
    cursor: pointer;
    margin-left: 4px;
    flex-shrink: 0;
    user-select: none;
    vertical-align: middle;
    position: relative;
    top: -1px;
    transition: background 0.15s;
    line-height: 1;
}
.info-icon:hover {
    background: var(--color-primary);
}

/* Student Profile Photos */
.student-photo-thumb {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}

.student-photo-placeholder {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-primary);
}

.student-photo-section {
    text-align: center;
    margin-bottom: 16px;
}

img.student-photo-large,
.student-photo-large img {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
    margin: 0 auto 8px;
}

.student-photo-placeholder-lg {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-primary);
    margin: 0 auto;
}

/* Profile photo in detail/edit modals - 128px, no border */
.modal-profile-photo img {
    width: 128px;
    height: 128px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
    margin: 0 auto 8px;
}

.modal-profile-photo .student-photo-placeholder-lg {
    width: 128px;
    height: 128px;
    font-size: 2.4rem;
    margin-bottom: 8px;
}

.student-photo-upload-btn {
    cursor: pointer;
    font-size: 0.8rem !important;
}

/* Settings School List */
.settings-school-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid var(--color-border);
}

.settings-school-item:last-child {
    border-bottom: none;
}

.school-item-actions {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-shrink: 0;
}

.school-item .school-name {
    font-size: var(--font-size-body);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.school-item .btn {
    font-size: var(--font-size-label);
    padding: 5px 12px;
}

/* Settings tab - compact sizing */
#tab-settings .card h2 {
    font-size: var(--font-size-body);
    margin-bottom: 10px;
}

#tab-settings .card > p.text-muted {
    font-size: var(--font-size-label);
}

#tab-settings .form-group label {
    font-size: var(--font-size-label);
}

#tab-settings .form-group select,
#tab-settings .form-group input {
    font-size: var(--font-size-body);
    padding: 9px 12px;
}

#tab-settings .btn {
    font-size: var(--font-size-label);
    padding: 9px 18px;
}

#tab-settings .btn.btn-small {
    font-size: var(--font-size-label);
    padding: 5px 12px;
}

/* History tab - compact Load More */
#tab-history .btn {
    font-size: var(--font-size-label);
    padding: 9px 18px;
}

/* Flaticon icons - ensure vertical centering inside any container */
.fi {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

/* Buttons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 12px 24px;
    border: none;
    border-radius: 8px;
    font-size: var(--font-size-body);
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s cubic-bezier(0.22, 1, 0.36, 1), transform 0.15s cubic-bezier(0.22, 1, 0.36, 1);
    text-decoration: none;
    width: 100%;
}

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

.btn-primary {
    background-color: var(--color-primary);
    color: white;
}

.btn-primary:hover {
    background-color: var(--color-primary-dark);
    transform: translateY(-1px);
}

.btn-primary:disabled {
    background-color: var(--color-primary-light);
    opacity: 0.6;
    cursor: not-allowed;
}

.btn-secondary {
    background-color: transparent;
    color: var(--color-primary);
    border: 1px solid var(--color-primary);
}

.btn-secondary:hover {
    background-color: rgba(107, 76, 138, 0.05);
}

.btn-secondary:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.btn-danger {
    background-color: var(--color-error);
    color: white;
}

.btn-danger:hover {
    background-color: #A93226;
}

.btn-ghost-danger {
    background-color: transparent;
    color: var(--color-error);
    border: none;
    padding-left: 8px;
    padding-right: 8px;
}

.btn-ghost-danger:hover {
    background-color: rgba(var(--color-error-rgb, 180, 50, 50), 0.08);
}

.btn-success {
    background-color: var(--color-success);
    color: #fff;
}

.btn-success:hover {
    filter: brightness(1.15);
}

.btn-small {
    padding: 10px 16px;
    font-size: var(--font-size-body);
    width: auto;
}

.btn-group {
    display: flex;
    gap: 8px;
    margin-top: 16px;
}

.btn-group .btn {
    flex: 1;
}

.btn-group--wrap {
    flex-wrap: wrap;
}
.btn-group--wrap .btn {
    flex: 1 1 calc(50% - 4px);
}

/* Links */
.text-link {
    color: var(--color-primary);
    text-decoration: none;
    font-size: var(--font-size-body);
    text-align: center;
    display: block;
    margin-top: 12px;
}

.text-link:hover {
    text-decoration: underline;
}

/* Alerts */
.alert {
    padding: 12px 16px;
    border-radius: 8px;
    margin-bottom: 16px;
    font-size: var(--font-size-body);
    display: none;
}

.alert.show {
    display: block;
}

.alert-error {
    background-color: #FDEDEC;
    color: var(--color-error);
    border: 1px solid #F5C6CB;
}

.alert-info {
    background-color: #F0E8F7;
    color: var(--color-primary-dark);
    border: 1px solid var(--color-border);
}

/* QR Code Display */
.qr-container {
    text-align: center;
    padding: 24px;
}

.qr-container canvas,
.qr-container img {
    max-width: 280px;
    width: 100%;
    height: auto;
    border-radius: 12px;
}

.qr-timer {
    margin-top: 12px;
    font-size: var(--font-size-body);
    color: var(--color-text-light);
}

.qr-timer .countdown {
    font-weight: 700;
    color: var(--color-primary);
    font-size: var(--font-size-heading);
}

/* Scanner result */
.scan-result {
    text-align: center;
    padding: 24px;
    border-radius: 12px;
    margin-top: 16px;
    display: none;
}

.scan-result.show {
    display: block;
}

.scan-result.valid {
    background-color: #E8F5E9;
    border: 2px solid var(--color-success);
}

.scan-result.invalid {
    background-color: #FDEDEC;
    border: 2px solid var(--color-error);
}

.scan-result .result-icon {
    font-size: 3rem;
    margin-bottom: 12px;
}

.scan-result .parent-name {
    font-size: var(--font-size-heading);
    font-weight: 700;
    margin-bottom: 8px;
}

.scan-result .student-list {
    font-size: var(--font-size-body);
    color: var(--color-text-light);
}

/* Student cards */
.student-card {
    display: flex;
    align-items: center;
    padding: 12px;
    background: var(--color-bg);
    border-radius: 8px;
    margin-bottom: 8px;
}

.student-card .student-avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--color-primary-light);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: var(--font-size-body);
    margin-right: 12px;
    flex-shrink: 0;
}

.student-card .student-info h3 {
    font-size: var(--font-size-body);
    margin-bottom: 2px;
}

.student-card .student-info p {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
}

/* Admin tables */
.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--font-size-body);
}

.data-table-fixed {
    table-layout: fixed;
}

.data-table th,
.data-table td {
    padding: 10px 8px;
    text-align: left;
    border-bottom: 1px solid var(--color-border);
}
.data-table th:last-child,
.data-table td:last-child {
    padding-right: 16px;
}

.data-table .btn.btn-small {
    padding: 3px 10px;
    font-size: var(--font-size-label);
}

.data-table th {
    font-weight: 600;
    color: var(--color-primary-dark);
    background: var(--color-bg);
    position: sticky;
    top: 0;
}

.data-table tr:hover td {
    background-color: rgba(107, 76, 138, 0.03);
}

/* Vendor Tagging (admin-manage-enrichments) */
.vt-list { border-top: 1px solid var(--color-border); }
.vt-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border);
}
.vt-row-label { min-width: 180px; font-weight: 500; }
.vt-row-vendors { flex: 1; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.vt-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px 3px 12px;
    border-radius: 999px;
    background: var(--color-primary);
    color: #fff;
    font-size: var(--font-size-small);
}
.vt-pill-remove {
    background: none;
    border: none;
    color: rgba(255,255,255,0.75);
    cursor: pointer;
    font-size: 14px;
    line-height: 1;
    padding: 0;
    display: flex;
    align-items: center;
}
.vt-pill-remove:hover { color: #fff; }
.vt-add-select {
    height: 28px;
    font-size: var(--font-size-small);
    padding: 0 8px;
    border-radius: 999px;
    border: 1.5px dashed var(--color-border);
    background: transparent;
    color: var(--color-text-light);
    cursor: pointer;
}

/* Sortable / filterable table headers */
.th-sortable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.th-sortable:hover { color: var(--color-primary); }

.th-sort-arrow {
    font-size: var(--font-size-label);
    margin-left: 3px;
    color: var(--color-text-light);
    vertical-align: middle;
}
.th-sort-arrow.active { color: var(--color-primary); }

.th-filterable {
    cursor: pointer;
    user-select: none;
    font-size: var(--font-size-body);
    margin-left: 4px;
    color: var(--color-text-light);
    padding: 1px 3px;
    border-radius: 3px;
    vertical-align: middle;
}
.th-filterable:hover { color: var(--color-primary); }
.th-filterable.active {
    color: var(--color-primary);
    font-weight: 700;
    background: rgba(107, 76, 138, 0.1);
}

/* Filter dropdown */
.table-filter-dropdown {
    position: fixed;
    background: var(--color-card, #fff);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.12);
    z-index: 2000;
    min-width: 130px;
    padding: 4px 0;
}
.table-filter-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    cursor: pointer;
    font-size: var(--font-size-body);
    color: var(--color-text);
}
.table-filter-option:hover { background: var(--color-bg); }
.table-filter-option.selected { color: var(--color-primary); font-weight: 600; }
.filter-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    border: 2px solid var(--color-text-light);
    flex-shrink: 0;
}
.table-filter-option.selected .filter-dot {
    border-color: var(--color-primary);
    background: var(--color-primary);
}

.table-container {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
@media (min-width: 769px) {
    .table-container {
        overflow-x: hidden;
    }
}

/* Search bar */
.search-bar {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
}

.search-bar input {
    flex: 1;
    padding: 10px 14px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    font-size: var(--font-size-body);
}

/* Tabs */
.tabs {
    display: none;
    flex-wrap: wrap;
    border-bottom: 2px solid var(--color-border);
    margin-bottom: 16px;
    gap: 0;
}

.tabs .tab {
    padding: 8px 14px;
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--color-text-light);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    white-space: nowrap;
    background: none;
    border-top: none;
    border-left: none;
    border-right: none;
}

.tabs .tab.active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.tab-content {
    display: none;
}

.tab-content.active {
    display: block;
}

/* Badge */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px 2px; /* asymmetric: +1px top compensates for cap-height sitting high in em square */
    border-radius: 12px;
    font-size: var(--font-size-small);
    font-weight: 600;
    line-height: 1;
    text-transform: uppercase;
}

.badge-success {
    background: rgba(30, 107, 61, 0.12);
    color: var(--color-success);
}

.badge-warning {
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

.badge-error {
    background: rgba(192, 57, 43, 0.1);
    color: var(--color-error);
}

.badge-muted {
    background: rgba(107, 107, 107, 0.12);
    color: var(--color-text-light);
}

.badge-trial {
    background: rgba(222, 197, 216, 0.35);
    color: #6B3F62;
}

[data-theme="dark"] .badge-trial {
    background: rgba(222, 197, 216, 0.18);
    color: #E8C4DF;
}

.status-edit-btn {
    background: none;
    border: none;
    padding: 2px 4px;
    color: var(--color-text-light);
    cursor: pointer;
    font-size: var(--font-size-small);
    line-height: 1;
    border-radius: 4px;
}
.status-edit-btn:hover { color: var(--color-primary); background: var(--color-primary-soft); }

/* Modal */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 16px;
    /* Reserve the soft-keyboard height at the bottom so the flex-centred modal
       re-centres in the band ABOVE the keyboard (any field near the modal's
       bottom would otherwise sit under the keyboard on the messenger page,
       where keyboard resize mode is "none", and in mobile web Safari, where
       the layout viewport never shrinks). --kb-inset is 0 at rest / on desktop,
       so this is a no-op there. */
    padding-bottom: calc(16px + var(--kb-inset, 0px));
    transition: padding-bottom 0.25s var(--ease-keyboard);
}

.modal-overlay.show {
    display: flex;
}

/* Feedback modals must float above all other modals */
#genericSuccessModal,
#customErrorModal,
#customConfirmModal {
    z-index: 1100;
}

.modal {
    background: var(--color-card);
    border-radius: 12px;
    padding: 24px;
    width: 100%;
    max-width: 700px;
    /* Subtract the soft-keyboard height so a tall modal shrinks and scrolls its
       own content (overflow-y) above the keyboard rather than overflowing the
       visible band. --kb-inset is 0 at rest, so this stays 90vh on desktop. */
    max-height: calc(90vh - var(--kb-inset, 0px));
    overflow-y: auto;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
    transition: max-height 0.25s var(--ease-keyboard);
}

/* Hero-image modal - image bleeds edge-to-edge at top */
.modal-hero {
    padding: 0;
    position: relative;
}

.modal-hero .modal-close {
    position: absolute;
    top: 10px;
    right: 10px;
    background: rgba(255,255,255,0.88);
    border-radius: 50%;
    width: 30px;
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 20;
    font-size: 18px; /* fixed - circle is fixed-size, must not scale with font preset */
    line-height: 1;
    float: none;
}

.modal-hero-content {
    padding: 20px 24px 24px;
}

/* Clip image at modal top corners; remove side rounding & bottom margin */
.modal-hero .enrich-carousel {
    border-radius: 12px 12px 0 0;
    margin-bottom: 0;
    overflow: hidden;
}

.modal-hero .enrich-carousel-single {
    border-radius: 12px 12px 0 0;
    margin-bottom: 0;
}

.modal h2 {
    font-size: var(--font-size-heading);
    margin-bottom: 16px;
    color: var(--color-primary-dark);
}

.modal-close {
    float: right;
    background: none;
    border: none;
    font-size: var(--font-size-heading);
    cursor: pointer;
    color: var(--color-text-light);
    line-height: 1;
}

/* Loading spinner. linear (not ease) is correct here: a continuously rotating
   indicator must spin at constant speed, or it visibly pulses each revolution. */
.spinner {
    display: inline-block;
    width: 20px;
    height: 20px;
    border: 3px solid rgba(255, 255, 255, 0.3);
    border-radius: 50%;
    border-top-color: white;
    animation: spin 0.8s linear infinite;
}

.spinner-dark {
    border-color: rgba(107, 76, 138, 0.2);
    border-top-color: var(--color-primary);
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

/* ── Ambient loaders ──────────────────────────────────────────────────────
   A waiting state should breathe, never freeze. These are AMBIENT (declarative,
   looping) indicators - the counterpart to the played Motion Library primitives
   in Section 5. The global prefers-reduced-motion block freezes them to a
   single static frame, so reduced-motion users get a calm placeholder.

   .loading-text  - the canonical breathing "Loading…" placeholder. Replaces the
                    dead grey <p class="text-muted">Loading...</p> pattern.
   .skeleton      - shows the SHAPE of content that is still loading; compose
                    with a sized box or the .skeleton-circle / .skeleton-text
                    shape helpers. */
.loading-text {
    color: var(--color-text-light);
    animation: loadingPulse 1.4s var(--ease-out) infinite;
}
@keyframes loadingPulse {
    0%, 100% { opacity: 0.45; }
    50%      { opacity: 1; }
}

.skeleton {
    background: linear-gradient(90deg,
        var(--color-border) 25%,
        var(--color-card) 50%,
        var(--color-border) 75%);
    background-size: 200% 100%;
    animation: skeletonShimmer 1.4s ease-in-out infinite;
    border-radius: 6px;
}
@keyframes skeletonShimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
.skeleton-circle { border-radius: 50%; }
.skeleton-text   { height: 0.72em; border-radius: 4px; }

/* View As banner - sticky, in normal document flow, full page width.
   Sits above .app-container so it pushes the entire page down naturally.
   Pins below the safe-area inset when scrolling so the Exit button always
   stays clear of the status bar / notch. (It used to pin at top:0 = behind the
   status bar, sliding the bar out of reach on native edge-to-edge builds.) */

/* Sticky thead inside a scrollable modal */
.sticky-thead th {
    position: sticky;
    top: 0;
    background: var(--color-card);
    z-index: 1;
}

.view-as-bar {
    position: sticky;
    top: env(safe-area-inset-top, 0px);
    z-index: 975; /* above nav menu (950) but below modals (1000+) */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px 20px;
    background: #fff3cd;
    border-bottom: 2px solid #ffc107;
    gap: 12px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
.view-as-label {
    font-size: var(--font-size-body);
    color: #856404;
}
[data-theme="dark"] .view-as-bar {
    background: #3a2e00;
    border-bottom-color: #ffc107;
}
[data-theme="dark"] .view-as-label { color: #ffd966; }
/* contentInset:"always" builds: the OS already insets the webview below the
   notch (body padding-top is suppressed to 0), so pin at the webview top.
   env() would push the bar down by a phantom inset on those builds. */
html.cap-inset-always .view-as-bar { top: 0; }

/* Greeting emoji spin animation */
.greeting-emoji {
    display: inline-block;
    margin-left: 2px;
}

@keyframes greetingEmojiSpin {
    0%   { transform: rotate(0deg); }
    100% { transform: rotate(720deg); }
}

.greeting-emoji--spin {
    animation: greetingEmojiSpin 1.1s cubic-bezier(0.34, 1.3, 0.64, 1);
}

/* Event banner - Announcements tab */
.event-banner {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border-radius: 8px;
    margin-bottom: 10px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-left-width: 3px;
    cursor: pointer;
    transition: background 0.15s;
}
.event-banner:hover        { background: var(--color-border); }
.event-banner-live         { border-left-color: var(--color-error); }
.event-banner-upcoming     { border-left-color: var(--color-primary); }
.event-banner-badge {
    font-size: var(--font-size-small);
    font-weight: 700;
    letter-spacing: 0.07em;
    padding: 3px 9px;
    border-radius: 20px;
    flex-shrink: 0;
    white-space: nowrap;
}
.event-banner-live .event-banner-badge {
    background: #fdecea;
    color: var(--color-error);
}
.event-banner-upcoming .event-banner-badge {
    background: #ede6f5;
    color: var(--color-primary);
}
.event-banner-badge-live { animation: livePulse 1.5s ease-in-out infinite; }
.event-banner-name {
    font-weight: 600;
    font-size: var(--font-size-body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--color-text);
}
.event-banner-sub {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    margin-top: 2px;
}
@keyframes livePulse {
    0%, 100% { opacity: 1; }
    50%       { opacity: 0.45; }
}

/* ═══ 5. FEATURES (Announcements · Enrichments · HR · TA · Messenger · Broadcast) ═══ */

/* Announcements */
.announcement-card {
    padding: 16px;
    background: var(--color-bg);
    border-radius: 8px;
    margin-bottom: 12px;
    border-left: 3px solid var(--color-primary);
}

.announcement-card.unread {
    border-left-color: var(--color-accent);
    background: #FFFBF0;
}

.announcement-card .announcement-title {
    font-weight: 600;
    margin-bottom: 4px;
}

.announcement-card .announcement-date {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-bottom: 8px;
}

.announcement-card .announcement-body {
    font-size: var(--font-size-body);
    line-height: 1.5;
}

.announcement-card .announcement-preview {
    font-size: var(--font-size-body);
    color: var(--color-text-light);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-top: 4px;
    line-height: 1.4;
}

.announcement-card .announcement-thumbs {
    display: flex;
    gap: 6px;
    margin-top: 8px;
    flex-wrap: wrap;
}

.announcement-card .announcement-thumbs img {
    width: 60px;
    height: 60px;
    object-fit: cover;
    border-radius: 6px;
}

.announcement-card.clickable {
    cursor: pointer;
    transition: background 0.15s;
}

.announcement-card.clickable:hover {
    background: rgba(107, 76, 138, 0.04);
}

/* Announcement detail modal */
.ann-detail-body {
    font-size: var(--font-size-body);
    line-height: 1.7;
    white-space: pre-wrap;
    margin: 16px 0;
}

.ann-detail-images {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 12px;
}

.ann-detail-images img {
    width: 100px;
    height: 100px;
    object-fit: cover;
    border-radius: 8px;
    cursor: pointer;
    transition: opacity 0.15s;
}

.ann-detail-images img:hover {
    opacity: 0.8;
}

.ann-detail-image-wrap {
    position: relative;
    display: inline-block;
}

.ann-detail-image-wrap img {
    display: block;
}

.ann-detail-image-delete {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    border: none;
    font-size: 30px;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

.ann-detail-title {
    font-size: var(--font-size-heading);
    font-weight: 700;
    margin-bottom: 4px;
}

.ann-detail-byline {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    margin-bottom: 16px;
}

.ann-detail-meta {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--color-border);
}

.ann-detail-meta-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    padding: 6px 0;
    font-size: var(--font-size-body);
}

.ann-detail-meta-label {
    font-weight: 600;
    color: var(--color-text-light);
    flex-shrink: 0;
}

.ann-detail-delete {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--color-border);
    text-align: center;
}

.ann-reads-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: var(--color-bg-subtle, #f5f5f5);
    font-size: var(--font-size-label);
    color: var(--color-text);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
    user-select: none;
}
.ann-reads-chip:hover {
    background: rgba(107, 76, 138, 0.1);
    border-color: var(--color-primary);
    color: var(--color-primary);
}
[data-theme="dark"] .ann-reads-chip {
    background: #2a2a2a;
    border-color: var(--color-border);
    color: var(--color-text);
}

/* Announcement image upload previews */
.ann-image-preview {
    display: inline-block;
    position: relative;
    margin: 4px;
}

.ann-image-thumb {
    width: 60px;
    height: 60px;
    object-fit: cover;
    border-radius: 6px;
}

.ann-image-remove {
    position: absolute;
    top: -8px;
    right: -8px;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--color-error);
    color: #fff;
    border: none;
    font-size: 18px;
    line-height: 28px;
    text-align: center;
    cursor: pointer;
    padding: 0;
}

.enr-image-thumb {
    width: 80px;
    height: 80px;
    cursor: pointer;
}

/* Image lightbox */
.image-lightbox {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.9);
    z-index: 99999 !important;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.image-lightbox.show {
    display: flex;
    /* MA6 — open: backdrop fades in (staging) while the photo rises from a
       slightly smaller scale and settles (follow-through). The animation plays
       the instant .show flips display:none -> flex. */
    animation: lightboxBackdropIn 200ms var(--ease-out);
}
.image-lightbox.show img {
    animation: lightboxImgIn 260ms var(--ease-spring);
}
/* Shared-element FLIP open: image-crop.js drives the backdrop's background-color
   inline so it fades in over the SAME duration + easing as the grow (and only the
   backdrop dims — the photo grows without also fading). Suppress the CSS opacity
   keyframe so the two don't compound. Must !important-beat .show's animation. */
.image-lightbox.lb-bd-js { animation: none !important; }
/* MA6 — close: JS adds .lb-closing, the reverse animation plays, then
   closeLightbox() removes .show after a setTimeout (image-crop.js). These
   rules must follow .show in source order so the close animation wins. */
.image-lightbox.lb-closing {
    animation: lightboxBackdropOut 160ms var(--ease-out) forwards;
}
.image-lightbox.lb-closing img {
    animation: lightboxImgOut 160ms var(--ease-out) forwards;
}
@keyframes lightboxBackdropIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes lightboxBackdropOut {
    from { opacity: 1; }
    to   { opacity: 0; }
}
/* Resting transform is translate(0,0) scale(1) (see .image-lightbox img); the
   keyframes land exactly there so the photo hands back to its zoom/pan transform
   without a jump once the open animation ends. */
@keyframes lightboxImgIn {
    from { transform: translate(0,0) scale(0.92); }
    to   { transform: translate(0,0) scale(1); }
}
@keyframes lightboxImgOut {
    from { transform: translate(0,0) scale(1); }
    to   { transform: translate(0,0) scale(0.96); }
}

.image-lightbox img {
    max-width: 90vw;
    max-height: 90vh;
    object-fit: contain;
    border-radius: 8px;
    transform-origin: center center;
    transform: translate(0,0) scale(1);
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    -webkit-user-drag: none;
    /* Suppress iOS's native long-press callout — its "Save to Photos" silently
       fails for this element (the -webkit-user-* + will-change styling breaks
       WKWebView image saving). The lightbox Save button replaces it. */
    -webkit-touch-callout: none;
    cursor: zoom-in;
    will-change: transform;
}
.image-lightbox img.lb-zoomed    { cursor: zoom-out; }
.image-lightbox img.lb-grabbing  { cursor: grabbing; }
.image-lightbox img.lb-animating { transition: transform 0.2s ease-out; }

/* Shared-element FLIP (expand-from-origin / shrink-back, driven by image-crop.js;
   the "expand-origin" motion primitive). While the photo flies to/from its origin
   thumbnail, suppress the centre-scale open/close keyframes so the JS-driven
   inline transform owns the geometry. */
.image-lightbox img.lb-flip { animation: none !important; }
/* On the close FLIP the chrome fades out of the way (the backdrop dims via an
   inline transition) so only the shrinking photo and the revealed page remain.
   Reuses the .lb-dragging transition on .image-lightbox-control / -counter. */
.image-lightbox.lb-flip-out .image-lightbox-control,
.image-lightbox.lb-flip-out .image-lightbox-counter {
    opacity: 0;
    pointer-events: none;
}

.image-lightbox-close {
    position: absolute;
    /* The lightbox is position:fixed against the viewport, so on notched iOS the
       top sits under the status bar / Dynamic Island. Inset below it. env() is 0
       on desktop/web (no-op). Mirrors the messenger-header pattern. */
    top: calc(env(safe-area-inset-top, 0px) + 14px);
    right: 20px;
    color: white;
    font-size: 2rem;
    cursor: pointer;
    background: rgba(255,255,255,0.15);
    border: none;
    border-radius: 6px;
    /* Asymmetric vertical padding (3 top / 5 bottom, same 8px total height as
       4/4) nudges the × glyph 1px up within the square without resizing the box —
       the glyph's ink sits slightly low in its line box. */
    padding: 3px 10px 5px;
    line-height: 1;
    z-index: 2001;
}
/* contentInset:"always" builds: the OS already insets the webview below the
   notch, so env() would double it — keep the plain 14px there. */
html.cap-inset-always .image-lightbox-close { top: 14px; }

/* Save button — bottom-right, clear of the iOS home indicator (safe-area). */
.image-lightbox-save {
    position: absolute;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 16px);
    right: 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 38px;
    color: #fff;
    cursor: pointer;
    background: rgba(255,255,255,0.15);
    border: none;
    border-radius: 6px;
    z-index: 2001;
    transition: background 0.15s, opacity 0.15s;
}
html.cap-inset-always .image-lightbox-save { bottom: 16px; }
.image-lightbox-save:hover { background: rgba(255,255,255,0.32); }
.image-lightbox-save.lb-saving { opacity: 0.45; pointer-events: none; }
/* Brief green pulse on the Save button the moment a save lands. */
.image-lightbox-save.lb-saved-flash { background: rgba(74,222,128,0.9); }

/* "Saved" confirmation toast — floats above the Save button, fades in/out. */
.image-lightbox-toast {
    position: absolute;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 78px);
    left: 50%;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    max-width: 80vw;
    background: rgba(18,18,18,0.86);
    color: #fff;
    font-size: var(--font-size-small);
    line-height: 1;
    padding: 10px 16px;
    border-radius: 999px;
    z-index: 2002;
    opacity: 0;
    pointer-events: none;
    transform: translateX(-50%) translateY(8px);
    transition: opacity 0.2s ease, transform 0.2s ease;
}
html.cap-inset-always .image-lightbox-toast { bottom: 78px; }
.image-lightbox-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.image-lightbox-toast svg { width: 17px; height: 17px; color: #4ade80; flex-shrink: 0; }

/* Lightbox carousel - prev/next arrows */
.image-lightbox-prev,
.image-lightbox-next {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(255,255,255,0.18);
    border: none;
    color: #fff;
    font-size: 2.8rem;
    padding: 6px 14px;
    cursor: pointer;
    border-radius: 6px;
    z-index: 2001;
    line-height: 1;
    transition: background 0.15s;
}
.image-lightbox-prev { left: 16px; }
.image-lightbox-next { right: 16px; }
.image-lightbox-prev:hover,
.image-lightbox-next:hover { background: rgba(255,255,255,0.32); }

/* Lightbox carousel - counter */
.image-lightbox-counter {
    position: absolute;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    color: rgba(255,255,255,0.85);
    font-size: var(--font-size-body);
    pointer-events: none;
}

/* Flick-to-dismiss: a vertical drag on the photo (handled in image-crop.js)
   closes the lightbox the way Telegram's media viewer does: the image tracks
   the finger 1:1 while JS sets its transform + the backdrop alpha inline. Here
   we only fade the chrome out of the way so the photo and the dimming backdrop
   are all that remain during the gesture. The transition also fades the chrome
   back in on a spring-back. */
.image-lightbox-close,
.image-lightbox-save,
.image-lightbox-prev,
.image-lightbox-next,
.image-lightbox-counter {
    transition: opacity 0.15s ease, background 0.15s ease;
}
.image-lightbox.lb-dragging .image-lightbox-control,
.image-lightbox.lb-dragging .image-lightbox-counter {
    opacity: 0;
    pointer-events: none;
}

/* Cropper modal z-index (above other modals) */
#imageCropperModal { z-index: 99999 !important; }
@media (max-width: 480px) { #cropperContainer { height: 220px !important; } }

/* Utilities */
.text-center { text-align: center; }
.text-muted { color: var(--color-text-light); }
.empty-state-text { color: var(--color-text-light); font-style: italic; font-size: var(--font-size-body); }
.mt-8 { margin-top: 8px; }
.mt-16 { margin-top: 16px; }
.mt-24 { margin-top: 24px; }
.mb-8 { margin-bottom: 8px; }
.mb-16 { margin-bottom: 16px; }
.hidden { display: none !important; }

/* =====================================================
   Hamburger Menu (base styles - must be BEFORE media queries)
   ===================================================== */

.hamburger-btn {
    display: block;
    position: absolute;
    top: 38px;
    right: 16px;
    z-index: 100;
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px;
    border-radius: 6px;
    transition: background 0.2s;
}

.hamburger-btn:hover {
    background: rgba(107, 76, 138, 0.08);
}

.hamburger-icon {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    width: 20px;
    height: 16px;
    line-height: 0;
    font-size: 0;
}

.hamburger-icon span {
    display: block;
    flex: 0 0 2px;
    width: 100%;
    height: 2px !important;
    min-height: 2px;
    max-height: 2px;
    background: var(--color-primary);
    transition: transform 0.3s, opacity 0.3s;
    transform: translateZ(0);
    will-change: transform;
}

.hamburger-btn.open .hamburger-icon {
    justify-content: center;
}

.hamburger-btn.open .hamburger-icon span:nth-child(1) {
    transform: rotate(45deg) translate(1px, 0);
}

.hamburger-btn.open .hamburger-icon span:nth-child(2) {
    opacity: 0;
}

.hamburger-btn.open .hamburger-icon span:nth-child(3) {
    transform: rotate(-45deg) translate(1px, 0);
}

/* Mobile menu backdrop */
.nav-menu-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.3);
    z-index: 900;
}

.nav-menu-overlay.open {
    display: block;
}

/* Mobile menu panel */
.nav-menu {
    display: block;
    background: var(--color-bg);
    border: none;
    border-radius: 8px;
    box-shadow: none;
    overflow: hidden;
    transform: scaleY(0);
    transform-origin: top center;
    visibility: hidden;
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear 0.25s;
    z-index: 950;
    position: absolute;
    right: 16px;
    margin-top: 16px;
    width: 60%;
    max-width: 280px;
}

.nav-menu-profile {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px 16px 12px;
    border-bottom: 1px solid var(--color-border);
}

.nav-menu-profile-img {
    width: 128px;
    height: 128px;
    border-radius: 50%;
    object-fit: cover;
}

.nav-menu-profile-placeholder {
    width: 128px;
    height: 128px;
    border-radius: 50%;
    background: var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-primary);
}

.nav-menu-profile-name {
    margin-top: 8px;
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--color-text);
}

.nav-menu.open {
    transform: scaleY(1);
    visibility: visible;
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s;
    max-height: 85vh;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    box-shadow: 0 4px 16px rgba(107, 76, 138, 0.15);
}

.nav-menu-section {
    padding: 8px 16px;
    border-bottom: 1px solid var(--color-border);
}

.nav-menu-section:last-child {
    border-bottom: none;
}

.nav-menu-section a {
    display: block;
    padding: 10px 12px;
    color: var(--color-text);
    text-decoration: none;
    font-family: inherit;
    font-size: var(--font-size-body);
    font-weight: 500;
    border-radius: 8px;
    transition: background 0.15s;
}

.nav-menu-section a:hover {
    background: rgba(107, 76, 138, 0.06);
}

.nav-menu-tab {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 10px 12px;
    background: none;
    border: none;
    border-radius: 8px;
    text-align: left;
    font-family: inherit;
    font-size: var(--font-size-body);
    font-weight: 500;
    color: var(--color-text);
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s;
    box-sizing: border-box;
}

.nav-menu-tab:hover {
    background: rgba(107, 76, 138, 0.06);
}

.nav-menu-tab.active {
    color: var(--color-primary);
    background: rgba(107, 76, 138, 0.08);
    font-weight: 600;
}

.nav-menu-section .view-toggle {
    justify-content: center;
}

/* Hide empty mobile menu sections */
.nav-menu-section:empty {
    display: none;
    padding: 0;
    border-bottom: none;
}

.nav-menu-section-label {
    font-size: var(--font-size-subheading);
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--color-text-light);
    padding: 4px 12px 2px;
    display: block;
}

.nav-menu-signout a {
    display: block;
    padding: 10px 12px;
    color: var(--color-error);
    text-decoration: none;
    font-size: var(--font-size-body);
    font-weight: 500;
    border-radius: 8px;
    transition: background 0.15s;
}

.nav-menu-signout a:hover {
    background: rgba(192, 57, 43, 0.06);
}

/* Menu Order Settings */
.menu-order-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border);
}
.menu-order-item:last-child {
    border-bottom: none;
}
.menu-order-label {
    font-size: 14px;
    font-weight: 500;
    color: var(--color-text);
}
.menu-order-btns {
    display: flex;
    gap: 6px;
}

/* Responsive - desktop enhancements */
@media (min-width: 1025px) {
    .app-container {
        padding: 24px 40px;
        max-width: 1000px;
    }

    .card {
        padding: 32px;
    }
}

/* Phone-only compact styling */
@media (max-width: 767px) {
    body {
        font-size: var(--font-size-body);
    }

    .app-container {
        padding: 0;
    }

    .hamburger-btn {
        top: 22px;
        right: 12px;
    }

    .app-header {
        padding: 12px 12px 8px;
    }

    .app-header .logo {
        font-size: var(--font-size-heading);
    }

    .app-header .logo small {
        font-size: var(--font-size-subheading);
    }

    .nav-bar {
        padding: 0 12px 6px;
        margin-bottom: 8px;
    }

    .nav-bar .user-info {
        font-size: var(--font-size-small);
    }

    .view-toggle {
        font-size: var(--font-size-subheading);
    }

    .view-toggle-btn {
        padding: 4px 10px;
    }

    .card {
        border-radius: 0;
        border-left: none;
        border-right: none;
        border-top: none;
        box-shadow: none;
        margin-bottom: 0;
        border-bottom: 1px solid var(--color-border);
        padding: 16px 12px;
    }

    .data-table {
        font-size: var(--font-size-small);
    }
    .data-table th,
    .data-table td {
        padding: 8px 6px;
    }

    /* Users tab: collapse Role and Parent columns into name cell on mobile */
    .user-col-role, .user-col-parent { display: none; }
    .user-mobile-badges { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 4px; }
    #tab-users .data-table td:last-child,
    #tab-users .data-table th:last-child { padding-right: 8px; }

    /* History tab: allow Details column to wrap rather than squish */
    #tab-history .data-table td:last-child {
        white-space: normal;
        word-break: break-word;
        min-width: 80px;
    }


    /* Detail rows: stack label + value on mobile when editing */
    .detail-row {
        flex-wrap: wrap;
    }

    .detail-edit-form {
        width: 100%;
    }

    .modal {
        padding: 20px 16px;
    }

    .modal-cf-sign {
        padding: 0;
    }

    .modal-cf-sign .modal {
        border-radius: 0;
        max-height: 100svh;
    }

    .modal-hero {
        padding: 0;
    }

    .modal-hero-content {
        padding: 20px 16px 24px;
    }

    .modal-hero .enrich-carousel {
        border-radius: 12px 12px 0 0;
    }

    .settings-school-item {
        gap: 8px;
    }

    .settings-school-item .school-item-name {
        font-size: var(--font-size-small);
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .school-item .school-name {
        font-size: var(--font-size-small);
    }

    .school-item .btn,
    .school-item-actions .btn {
        font-size: var(--font-size-small);
        padding: 4px 8px;
    }

    #newSchoolName {
        font-size: 0.75rem !important;
        padding: 5px 8px !important;
    }

    /* Settings tab - mobile compact */
    #tab-settings .card h2 {
        font-size: var(--font-size-body);
        margin-bottom: 8px;
    }

    #tab-settings .card > p.text-muted {
        font-size: var(--font-size-subheading);
    }

    #tab-settings .form-group {
        margin-bottom: 10px;
    }

    #tab-settings .form-group label {
        font-size: var(--font-size-subheading);
        margin-bottom: 4px;
    }

    #tab-settings .form-group select,
    #tab-settings .form-group input {
        font-size: var(--font-size-small);
        padding: 7px 10px;
    }

    #tab-settings .btn {
        font-size: var(--font-size-subheading);
        padding: 7px 14px;
    }

    #tab-settings .btn.btn-small {
        font-size: var(--font-size-small);
        padding: 4px 8px;
    }

    /* History tab - mobile compact */
    #tab-history .btn {
        font-size: var(--font-size-small);
        padding: 7px 14px;
    }
}

/* Phone input group (country code + phone field) */
.phone-input-group {
    display: flex;
    gap: 8px;
    align-items: stretch;
}

.phone-input-group .country-code-select {
    width: 88px !important;
    min-width: 88px;
    max-width: 88px;
    flex: 0 0 88px;
    padding: 12px 28px 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    font-size: var(--font-size-body);
    background: var(--color-card);
    color: var(--color-text);
    text-align: left;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    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='%236B6B6B' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
}

.phone-input-group .country-code-select:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(107, 76, 138, 0.15);
}

.phone-input-group input[type="tel"] {
    flex: 1 1 auto;
    width: auto !important;
    min-width: 0;
    padding: 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    font-size: var(--font-size-body);
    background: var(--color-card);
    color: var(--color-text);
}

.phone-input-group input[type="tel"]:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(107, 76, 138, 0.15);
}

/* Form row (side-by-side fields) */
.form-row {
    display: flex;
    gap: 12px;
}

.form-row .form-group {
    flex: 1;
    min-width: 0;
}

/* Badge info variant */
.badge-info {
    background: rgba(107, 76, 138, 0.12);
    color: var(--color-primary-dark);
}

/* Welcome card preview */
.welcome-card-preview {
    text-align: center;
    padding: 16px;
    background: var(--color-bg);
    border-radius: 8px;
    min-height: 100px;
}

.welcome-card-preview img {
    max-width: 100%;
    border-radius: 8px;
    box-shadow: var(--color-shadow);
}

/* Welcome card - Messenger conversation picker */
.card-conv-picker-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
}
.card-conv-picker-header h2 { margin: 0; }
.card-conv-list {
    max-height: 320px;
    overflow-y: auto;
}
.card-conv-list--sending {
    opacity: 0.5;
    pointer-events: none;
}
.card-conv-row {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.15s;
}
.card-conv-row:hover { background: var(--color-surface-alt); }
.card-conv-row-name {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 500;
    font-size: var(--font-size-body);
}
.card-conv-row-preview {
    font-size: 12px;
    color: var(--color-text-light);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.card-conv-wa-badge {
    font-size: 10px;
    background: #25D366;
    color: #fff;
    border-radius: 4px;
    padding: 1px 5px;
    line-height: 1.4;
    flex-shrink: 0;
}

/* Parent detail modal */
.parent-detail-info {
    background: var(--color-bg);
    border-radius: 8px;
    padding: 16px;
    margin-bottom: 16px;
}

.detail-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 0;
    gap: 16px;
    border-bottom: 1px solid var(--color-border);
}

.detail-row:last-child {
    border-bottom: none;
}

.detail-label {
    font-weight: 600;
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    flex-shrink: 0;
}

.detail-value {
    font-size: var(--font-size-body);
    color: var(--color-text);
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    overflow: hidden;
    flex: 1;
}

.detail-value > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.detail-value a {
    color: var(--color-primary);
}

.detail-edit-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-light);
    font-size: var(--font-size-label);
    padding: 8px 10px;
    border-radius: 4px;
    transition: color 0.2s, background 0.2s;
}

.detail-edit-btn:hover {
    color: var(--color-primary);
    background: rgba(107, 76, 138, 0.08);
}

.detail-row:has(.detail-edit-btn):hover .detail-edit-btn {
    color: var(--color-primary);
}

.detail-row.editing .detail-edit-btn {
    display: none;
}

.detail-row.editing {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 6px 8px;
    align-items: center;
}

.detail-row.editing .detail-label {
    grid-row: 1;
    grid-column: 1;
}

.detail-row.editing .detail-edit-form {
    grid-row: 1;
    grid-column: 2;
    justify-self: end;
}

.detail-row.editing .detail-value {
    grid-row: 2;
    grid-column: 1 / -1;
    overflow: visible;
}

.detail-edit-form {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-shrink: 0;
}


.detail-edit-input {
    flex: 1;
    min-width: 0;
    max-width: 100%;
    padding: 6px 10px;
    border: 1px solid var(--color-primary);
    border-radius: 6px;
    font-size: var(--font-size-body);
    outline: none;
    box-shadow: 0 0 0 2px rgba(107, 76, 138, 0.15);
    box-sizing: border-box;
}

select.detail-edit-input {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    padding-right: 28px;
    background-color: var(--color-card);
    color: var(--color-text);
    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='%236B6B6B' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 8px center;
    cursor: pointer;
    text-overflow: ellipsis;
}

/* Compact phone input inside detail edit modals */
.detail-value .country-code-select {
    width: 64px !important;
    min-width: 64px;
    max-width: 64px;
    flex: 0 0 64px;
    padding: 6px 22px 6px 8px;
    font-size: var(--font-size-body);
    border: 1px solid var(--color-primary);
    border-radius: 6px;
    box-shadow: 0 0 0 2px rgba(107, 76, 138, 0.15);
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    background-color: var(--color-card);
    color: var(--color-text);
    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='%236B6B6B' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 6px center;
    cursor: pointer;
}

.detail-edit-save,
.detail-edit-cancel {
    background: none;
    border: none;
    cursor: pointer;
    font-size: var(--font-size-body);
    padding: 8px 10px;
    border-radius: 4px;
    line-height: 1;
}

.detail-edit-save {
    color: var(--color-success);
}

.detail-edit-save:hover {
    background: rgba(46, 139, 87, 0.1);
}

.detail-edit-cancel {
    color: var(--color-error);
}

.detail-edit-cancel:hover {
    background: rgba(192, 57, 43, 0.1);
}

/* Clickable table rows */
/* Users tab - filter bar always visible; badges only on mobile */
.users-filter-bar { display: flex; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
@media (min-width: 768px) {
    .user-mobile-badges { display: none; }
}

.data-table tr.clickable-row {
    cursor: pointer;
}

.data-table tr.clickable-row:hover td {
    background-color: rgba(107, 76, 138, 0.06);
}

/* Child list in detail modal */
.detail-child-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border);
}

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

/* Modal success state */
.modal-success {
    text-align: center;
    padding: 32px 16px;
}

.modal-success .success-icon {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: #E8F5E9;
    color: var(--color-success);
    font-size: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto 16px;
    animation: successPop 0.4s ease-out;
}

.modal-success .success-message {
    font-size: var(--font-size-heading);
    font-weight: 600;
    color: var(--color-success);
    margin-bottom: 8px;
}

.modal-success .success-sub {
    font-size: var(--font-size-body);
    color: var(--color-text-light);
    margin-bottom: 24px;
}

/* Ticket Cards */
.ticket-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 0;
    border-bottom: 1px solid var(--color-border);
}

.ticket-card:last-child {
    border-bottom: none;
}

.ticket-card-info {
    flex: 1;
    min-width: 0;
}

.ticket-card-date {
    font-weight: 600;
    font-size: var(--font-size-body);
    color: var(--color-text);
}

.ticket-card-count {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    margin-top: 2px;
}

/* ============================================================
   Enrichment Cards (parent browse)
   ============================================================ */

.enrichment-card {
    background: var(--color-bg);
    border-radius: 10px;
    border: 1px solid var(--color-border);
    margin-bottom: 12px;
    overflow: hidden;
    cursor: pointer;
    transition: box-shadow 0.15s, border-color 0.15s;
}
.enrichment-card:hover {
    box-shadow: 0 2px 8px rgba(107, 76, 138, 0.1);
    border-color: var(--color-primary-light);
}
.enrichment-card-registered {
}

.enrichment-card-full {
    opacity: 0.65;
}
.enrichment-card-img {
    width: 100%;
    height: 120px;
    object-fit: cover;
}
.enrichment-card-body {
    padding: 12px 14px;
}
.enrichment-card-price {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    white-space: nowrap;
    flex-shrink: 0;
}
.enrichment-card-layout {
    display: flex;
    align-items: stretch;
    gap: 12px;
}
.enrichment-card-left {
    flex: 1;
    min-width: 0;
}
.enrichment-card-price-stack {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    flex-shrink: 0;
    gap: 2px;
    white-space: nowrap;
}
.enrichment-card-public-price {
    text-decoration: line-through;
    color: var(--color-text-light);
    font-size: var(--font-size-small);
    white-space: nowrap;
}
.price-calc-hint {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    margin-top: 4px;
}
.enrichment-card-provider {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    margin: 0 0 8px;
}
.enrichment-card-meta {
    display: flex;
    gap: 12px;
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    flex-wrap: wrap;
}
.badge-registered {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px;
    border-radius: 12px;
    font-size: var(--font-size-small);
    font-weight: 600;
    background: var(--color-primary);
    color: #fff;
    white-space: nowrap;
}
.badge-full {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 12px;
    font-size: var(--font-size-small);
    font-weight: 600;
    background: var(--color-text-light);
    color: #fff;
    white-space: nowrap;
}
.badge-subsidy {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 3px 8px;
    border-radius: 12px;
    font-size: var(--font-size-small);
    font-weight: 600;
    background: var(--color-primary);
    color: #fff;
    white-space: nowrap;
}
.subsidy-callout {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 30%, transparent);
    border-radius: 8px;
    padding: 10px 14px;
    margin-top: 12px;
    margin-bottom: 14px;
    font-size: var(--font-size-body);
    color: var(--color-text);
    line-height: 1.4;
}

/* ============================================================
   Enrichment Image Carousel
   ============================================================ */

.enrich-carousel {
    position: relative;
    border-radius: 10px;
    overflow: hidden;
    margin-bottom: 16px;
    background: var(--color-border);
}

.enrich-carousel-inner {
    position: relative;
    overflow: hidden;
    touch-action: pan-y;
}

.enrich-carousel-track {
    display: flex;
    transition: transform 0.3s ease;
    will-change: transform;
}

.enrich-carousel-slide {
    flex: 0 0 100%;
}

.enrich-carousel-slide img {
    width: 100%;
    height: 220px;
    object-fit: cover;
    display: block;
    cursor: pointer;
}

.enrich-carousel-arrow {
    position: absolute;
    top: 92px; /* centred in 220px image: (220-36)/2 */
    z-index: 10;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: none;
    background: rgba(0, 0, 0, 0.35);
    color: #fff;
    font-size: var(--font-size-body);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 0.15s;
    line-height: 1;
}
.enrich-carousel-arrow:hover { background: rgba(0, 0, 0, 0.6); }
.enrich-carousel-prev { left: 10px; }
.enrich-carousel-next { right: 10px; }

@media (max-width: 768px) {
    .enrich-carousel-arrow { display: none; }
}

.enrich-carousel-dots {
    display: flex;
    justify-content: center;
    gap: 6px;
    padding: 8px 0 6px;
    background: var(--color-card);
}

.enrich-carousel-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-border);
    border: none;
    cursor: pointer;
    padding: 0;
    transition: background 0.15s, transform 0.15s;
}

.enrich-carousel-dot.active {
    background: var(--color-primary);
    transform: scale(1.3);
}


.enrich-carousel-single {
    width: 100%;
    max-height: 220px;
    object-fit: cover;
    border-radius: 10px;
    margin-bottom: 16px;
    cursor: pointer;
    display: block;
}

/* ============================================================
   Planner Grid (Mon-Fri weekly view)
   ============================================================ */

.planner-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
    margin-top: 12px;
}
.planner-day-column {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.planner-time-grid {
    position: relative;
    overflow: visible;
}
.planner-day-header {
    font-weight: 700;
    font-size: var(--font-size-body);
    text-align: center;
    padding: 6px 0;
    background: var(--color-primary);
    color: #fff;
    border-radius: 6px;
}
.planner-empty {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    text-align: center;
    padding: 16px 4px;
}
.planner-slot {
    border-radius: 6px;
    padding: 8px;
    font-size: var(--font-size-label);
    border: 1px dashed var(--color-border);
    background: var(--color-bg);
    cursor: pointer;
    overflow: hidden;
    transition: box-shadow 0.2s cubic-bezier(0.22, 1, 0.36, 1), transform 0.15s cubic-bezier(0.22, 1, 0.36, 1);
}
.planner-slot:hover {
    box-shadow: 0 2px 8px rgba(107, 76, 138, 0.15);
    transform: translateY(-1px);
}
.planner-slot:active {
    transform: translateY(0);
}
.planner-slot-registered {
    border: 1px solid var(--color-primary);
    background: rgba(107, 76, 138, 0.06);
}
.planner-slot-available {
    border: 1px solid rgba(107, 76, 138, 0.25);
    background: rgba(107, 76, 138, 0.02);
}
.planner-slot-available:hover {
    border-color: rgba(107, 76, 138, 0.5);
    background: rgba(107, 76, 138, 0.06);
}
.planner-slot-clash {
    border: 2px solid var(--color-danger);
    background: rgba(220, 53, 69, 0.06);
}
.planner-slot-cta {
    font-size: var(--font-size-small);
    color: var(--color-primary);
    font-weight: 600;
    margin-top: 4px;
    text-align: right;
}
.planner-slot-name {
    font-weight: 600;
    font-size: var(--font-size-label);
    margin-bottom: 2px;
    word-break: break-word;
}
.planner-slot-time {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.planner-slot-badge {
    font-size: var(--font-size-small);
    color: var(--color-primary);
    font-weight: 700;
    margin-top: 4px;
}
.planner-slot-clash-warn {
    font-size: var(--font-size-small);
    color: var(--color-danger);
    font-weight: 600;
    margin-top: 2px;
}

/* Planner mobile: column dividers */
@media (max-width: 768px) {
    .planner-day-column {
        border-bottom: 1px solid var(--color-border);
        padding-bottom: 12px;
    }
    .planner-day-column:last-child {
        border-bottom: none;
    }
}

/* Safe area for notched phones */
@supports (padding-top: env(safe-area-inset-top)) {
    body {
        padding-top: env(safe-area-inset-top);
        padding-bottom: env(safe-area-inset-bottom);
    }
    /* Shipped native builds use ios.contentInset:"always" - the OS already
       insets the web content below the notch, so the env() padding above would
       double it, leaving an empty band over the header. Suppress it for those
       builds (.cap-inset-always, set in supabase-client.js). Web keeps the
       padding; edge-to-edge builds (contentInset:"never") swap to
       .cap-edge-to-edge in native-init.js and keep the single, correct inset. */
    html.cap-inset-always body {
        padding-top: 0;
        padding-bottom: 0;
    }
}

/* ============================================================
   Contextual Alert Cards (Announcements page)
   ============================================================ */

.ctx-alert {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 14px;
    border-radius: 8px;
    margin-bottom: 8px;
    font-size: var(--font-size-body);
    line-height: 1.4;
    border-left-width: 3px;
    border-left-style: solid;
}
.ctx-alert-link {
    cursor: pointer;
}
.ctx-alert-link:hover {
    filter: brightness(0.96);
}
.ctx-alert-link:active {
    filter: brightness(0.92);
}
.ctx-alert-chevron {
    font-size: var(--font-size-heading);
    flex-shrink: 0;
    margin-left: auto;
    align-self: center;
    opacity: 0.5;
}
.ctx-alert-icon {
    font-size: var(--font-size-body);
    flex-shrink: 0;
    margin-top: 1px;
}
.ctx-alert-title {
    display: block;
    font-weight: 600;
    margin-bottom: 1px;
}
.ctx-alert-urgent {
    background: #FFF4F4;
    border-left-color: var(--color-error);
    color: #8B1A1A;
}
.ctx-alert-warn {
    background: #FFFBF0;
    border-left-color: #D4A843;
    color: #7A5500;
}
.ctx-alert-info {
    background: #F4F0FA;
    border-left-color: var(--color-primary);
    color: var(--color-primary-dark);
}
.ctx-alert-success {
    background: #F0FBF4;
    border-left-color: var(--color-success);
    color: #1A5C34;
}
[data-theme="dark"] .ctx-alert-urgent { background: rgba(192,57,43,0.12); color: #F9BABA; }
[data-theme="dark"] .ctx-alert-warn   { background: rgba(212,168,67,0.12); color: #F5D78A; }
[data-theme="dark"] .ctx-alert-info   { background: rgba(107,76,138,0.15); color: var(--color-primary-light); }
[data-theme="dark"] .ctx-alert-success{ background: rgba(46,158,94,0.12); color: #90DEB0; }
[data-theme="dark"] .event-banner-upcoming .event-banner-badge { background: var(--color-primary); color: #fff; }
[data-theme="dark"] .event-banner-live .event-banner-badge     { background: rgba(192,57,43,0.2);   color: #F9BABA; }

/* ============================================================
   Micro-animations
   ============================================================ */

/* Auth page card lift-in - login, first-login, forgot-password */
@keyframes cardLiftIn {
    from { opacity: 0; transform: translateY(12px) scale(0.99); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
.app-container > .card {
    animation: cardLiftIn 0.35s cubic-bezier(0.22, 1, 0.36, 1) both;
    animation-delay: 0.1s;
}

/* Modal overlay fade-in */
@keyframes overlayFade {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.modal-overlay.show {
    animation: overlayFade 0.2s ease both;
}

/* Modal box scale-in */
@keyframes modalEnter {
    from { opacity: 0; transform: scale(0.95) translateY(8px); }
    to   { opacity: 1; transform: none; }
}
.modal-overlay.show .modal {
    animation: modalEnter 0.22s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* Alert slide-in from top */
@keyframes alertSlideIn {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}
.alert.show {
    animation: alertSlideIn 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* Fee notes - saved indicator fade in → hold → fade out */
@keyframes feeNotesSaved {
    0%   { opacity: 0; transform: translateY(-3px); }
    15%  { opacity: 1; transform: translateY(0); }
    75%  { opacity: 1; }
    100% { opacity: 0; }
}
.fee-notes-status.show {
    animation: feeNotesSaved 1.8s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

/* Card enter animation - list items fade in and slide up */
@keyframes cardEnter {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: translateY(0); }
}
.enrichment-card,
.announcement-card {
    animation: cardEnter 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* Stagger siblings up to 6 */
.enrichment-card:nth-child(1), .announcement-card:nth-child(1) { animation-delay: 0ms; }
.enrichment-card:nth-child(2), .announcement-card:nth-child(2) { animation-delay: 30ms; }
.enrichment-card:nth-child(3), .announcement-card:nth-child(3) { animation-delay: 60ms; }
.enrichment-card:nth-child(4), .announcement-card:nth-child(4) { animation-delay: 90ms; }
.enrichment-card:nth-child(5), .announcement-card:nth-child(5) { animation-delay: 120ms; }
.enrichment-card:nth-child(n+6), .announcement-card:nth-child(n+6) { animation-delay: 150ms; }

/* Success modal scale-in (upgrade existing successPop) */
@keyframes successPop {
    0%   { transform: scale(0.6); opacity: 0; }
    60%  { transform: scale(1.12); }
    100% { transform: scale(1); opacity: 1; }
}

/* Tab content crossfade. Only the FALLBACK for browsers without the View
   Transitions API: where VT is supported, switchTab() wraps the swap in
   document.startViewTransition() and the @view-transition root crossfade (below)
   owns the animation, so also running tabFade would double up the fade. The
   @supports test detects VT via the view-transition-name property, which ships
   together with document.startViewTransition(). */
@supports not (view-transition-name: none) {
    .tab-content.active {
        animation: tabFade 0.18s ease-out;
    }
}
@keyframes tabFade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ═══ Page transitions (View Transitions API) ═══

   One unified crossfade for BOTH navigation styles so the whole app feels
   continuous instead of hard-cutting:

   1. Cross-document (e.g. Messenger to Calendar, which loads messages.html to
      dashboard.html): @view-transition opts every page in (style.css is shared).
      The browser holds the outgoing page, then crossfades to the incoming page's
      first painted frame. Theme + color-scheme are set synchronously in each
      page's <head> before first paint, so both frames are already correctly
      themed and there is no light/dark flash across the fade.
   2. Same-document tab switch (e.g. Announcements to Enrichment): switchTab()
      calls document.startViewTransition(), which reuses this same root crossfade.

   Pure progressive enhancement: unsupported browsers (older iOS/Safari, Firefox)
   navigate exactly as before. The first cold load is not a navigation, so it
   does not animate. The outgoing page fades out a touch faster than the incoming
   one fades in, and the incoming page drifts up 8px as it arrives (Disney
   follow-through), so it reads as "settled into place", not teleported. */
@view-transition {
    navigation: auto;
}

::view-transition-old(root) {
    animation: pageNavOut 200ms var(--ease-out) both;
}
::view-transition-new(root) {
    animation: pageNavIn 260ms var(--ease-out) both;
}
@keyframes pageNavOut {
    from { opacity: 1; }
    to   { opacity: 0; }
}
@keyframes pageNavIn {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* The global prefers-reduced-motion block targets the * selector, which does
   NOT match ::view-transition-* pseudo-elements. Disable the crossfade here too
   so reduced-motion users get an instant cut on both nav styles. */
@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) {
        animation: none !important;
    }
}

/* Messages module - recipient row reveal */
@keyframes rowFadeIn {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}
.row-reveal {
    animation: rowFadeIn 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* Messages module - card entrances */
#tab-messages.active .card,
#tab-messages-settings.active .card {
    animation: cardEnter 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}
#tab-messages-settings.active .card:nth-child(2) { animation-delay: 60ms; }

/* Messages module - recipient preview crossfade */
@keyframes previewFade {
    from { opacity: 0.3; }
    to   { opacity: 1; }
}
.preview-updated {
    animation: previewFade 0.18s ease-out both;
}

/* Messages module - recipient summary bar */
.msg-recipient-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 8px;
}
.msg-recipient-count {
    font-size: var(--font-size-body);
    font-weight: 500;
    color: var(--color-text);
}
.msg-excluded-note {
    font-weight: 400;
    color: var(--color-muted);
}
.msg-exclude-toggle {
    background: none;
    border: none;
    cursor: pointer;
    font-size: var(--font-size-label);
    color: var(--color-primary);
    padding: 0;
    white-space: nowrap;
    flex-shrink: 0;
}
.msg-exclude-toggle:hover { text-decoration: underline; }

/* Messages module - exclude panel */
.msg-exclude-panel {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    max-height: 200px;
    overflow-y: auto;
    margin-bottom: 12px;
}
.msg-exclude-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    cursor: pointer;
    border-bottom: 1px solid var(--color-border);
    transition: background 0.12s;
    gap: 8px;
}
.msg-exclude-row:last-child { border-bottom: none; }
.msg-exclude-row:hover { background: var(--color-surface); }
.msg-exclude-row.excluded { opacity: 0.45; }
.msg-exclude-row-name {
    font-size: var(--font-size-body);
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.msg-exclude-row.excluded .msg-exclude-row-name {
    text-decoration: line-through;
}
.msg-exclude-action {
    font-size: var(--font-size-label);
    color: var(--color-muted);
    flex-shrink: 0;
}
.msg-exclude-row:hover .msg-exclude-action { color: var(--color-primary); }
.msg-exclude-row.excluded:hover .msg-exclude-action { color: var(--color-success); }

/* Ticket issuance - mode toggle */
.issue-mode-toggle {
    display: inline-flex;
    background: var(--color-bg);
    border-radius: 20px;
    padding: 3px;
    gap: 2px;
    margin-bottom: 12px;
}
.issue-mode-btn {
    padding: 5px 14px;
    border: none;
    background: transparent;
    border-radius: 18px;
    font-size: var(--font-size-label);
    font-weight: 500;
    cursor: pointer;
    color: var(--color-text-light);
    transition: background 0.15s, color 0.15s;
}
.issue-mode-btn.active {
    background: var(--color-primary);
    color: white;
}
.issue-mode-btn:hover:not(.active) {
    background: rgba(107, 76, 138, 0.12);
    color: var(--color-primary);
}

/* Ticket issuance - search results */
.issue-search-results {
    max-height: 200px;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-top: 4px;
}
.issue-search-results:empty { display: none; }
.issue-search-result {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    cursor: pointer;
    font-size: var(--font-size-body);
    transition: background 0.1s;
}
.issue-search-result:hover { background: var(--color-bg); }
.issue-search-result + .issue-search-result {
    border-top: 1px solid var(--color-border);
}
.issue-search-result-add {
    color: var(--color-primary);
    font-size: var(--font-size-label);
    font-weight: 500;
    white-space: nowrap;
}

/* Ticket issuance - selected user chips */
.issue-user-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}
.issue-user-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 8px 4px 10px;
    border-radius: 99px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    font-size: var(--font-size-label);
    color: var(--color-text);
}
.issue-chip-remove {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-light);
    font-size: var(--font-size-body);
    line-height: 1;
    padding: 0 2px;
    display: flex;
    align-items: center;
    transition: color 0.15s;
}
.issue-chip-remove:hover { color: var(--color-error); }
.issue-selected-label {
    font-size: var(--font-size-label);
    font-weight: 600;
    color: var(--color-text-light);
    margin-top: 12px;
    margin-bottom: 2px;
}

/* Messages module - attach button (photo previews reuse the shared .msgr-media-* thumbnail grid) */
.msg-attach-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--font-size-label);
    cursor: pointer;
    color: var(--color-muted);
    background: none;
    border: 1px dashed var(--color-border);
    border-radius: 8px;
    padding: 7px 12px;
    transition: color 0.15s, border-color 0.15s;
    margin-bottom: 12px;
    width: 100%;
    justify-content: center;
}
.msg-attach-btn:hover,
.msg-attach-btn.drag-over {
    color: var(--color-primary);
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 6%, transparent);
}

/* Voice note - action row, mic button, recording overlay, preview */
.msg-action-row {
    display: flex;
    gap: 8px;
    margin-bottom: 12px;
    align-items: stretch;
}
.msg-action-row .msg-attach-btn { flex: 1; margin-bottom: 0; }

.msg-voice-btn {
    width: 40px;
    min-height: 40px;
    border-radius: 50%;
    border: 1px dashed var(--color-border);
    background: none;
    color: var(--color-text-light);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: all 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}
.msg-voice-btn:hover {
    color: var(--color-primary);
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 6%, transparent);
}

.msg-voice-overlay {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 16px;
    animation: msgFadeIn 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.msg-voice-recording {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    font-size: var(--font-size-body);
    color: var(--color-text);
}
.msg-recording-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--color-danger);
    flex-shrink: 0;
    animation: msgPulse 1s ease-in-out infinite;
}
.msg-recording-label { color: var(--color-text-light); }
.msg-recording-time {
    font-variant-numeric: tabular-nums;
    font-weight: 500;
    color: var(--color-text);
    margin-left: auto;
}
.msg-voice-stop {
    width: 40px;
    height: 40px;
    border-radius: 8px;
    border: none;
    background: var(--color-danger);
    color: white;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: transform 0.15s;
}
.msg-voice-stop:active { transform: scale(0.92); }

@keyframes msgPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}
@keyframes msgFadeIn {
    from { opacity: 0; transform: scale(0.97); }
    to { opacity: 1; transform: scale(1); }
}
@keyframes msgFadeOut {
    from { opacity: 1; transform: scale(1); }
    to   { opacity: 0; transform: scale(0.97); }
}
@keyframes vpEnter {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes vpExit {
    from { opacity: 1; transform: translateY(0); }
    to   { opacity: 0; transform: translateY(-4px); }
}
@keyframes vpPlayPop {
    0%   { transform: scale(0.8); }
    100% { transform: scale(1); }
}
.msg-voice-overlay.exiting {
    animation: msgFadeOut 150ms var(--ease-out) forwards;
}

.msg-voice-preview { margin-bottom: 12px; }

/* Custom voice preview player */
.msg-voice-preview-card {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 10px 12px;
}
.msg-vp-play {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: none;
    background: var(--color-primary);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: opacity 0.15s;
}
.msg-vp-play:hover { opacity: 0.85; }
.msg-vp-track {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}
.msg-vp-bar {
    flex: 1;
    height: 3px;
    background: var(--color-border);
    border-radius: 2px;
    overflow: hidden;
}
.msg-vp-fill {
    height: 100%;
    width: 100%;
    background: var(--color-primary);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.1s var(--ease-out);
}
.msg-vp-time {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.msgr-voice-clear-btn {
    background: none;
    border: none;
    color: var(--color-text-light);
    cursor: pointer;
    padding: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-size: 16px;
    transition: color 0.15s;
}
.msgr-voice-clear-btn:hover { color: var(--color-danger); }

.msg-action-row.voice-active .msg-attach-btn {
    opacity: 0.4;
    pointer-events: none;
    cursor: not-allowed;
}

@media (max-width: 400px) {
    .msg-action-row { flex-direction: column; }
    .msg-voice-btn {
        width: 100%;
        border-radius: 8px;
        height: auto;
        padding: 7px 12px;
    }
}

/* ============================================================
   Purple Badges
   ============================================================ */

/* ============================================================
   Empty States
   ============================================================ */

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 48px 24px;
    text-align: center;
    color: var(--color-text-light);
    gap: 12px;
}
.empty-state-icon {
    font-size: 2.4rem;
    line-height: 1;
    opacity: 0.5;
}
.empty-state-title {
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--color-text);
    margin: 0;
}
.empty-state-body {
    font-size: var(--font-size-body);
    color: var(--color-text-light);
    max-width: 280px;
    margin: 0;
    line-height: 1.5;
}

/* ============================================================
   Keyboard Focus Visible (accessible focus ring)
   ============================================================ */

:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

/* ============================================================
   Brand Mark - SVG wordmark footer
   ============================================================ */

.brand-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 18px 16px 22px;
    margin-top: auto;
    text-decoration: none;
    position: relative;
    border-top: 1px solid var(--color-border);
}
.brand-mark-logo {
    height: 28px;
    width: auto;
    display: block;
    flex-shrink: 0;
}
.brand-mark-version {
    position: absolute;
    right: 16px;
    font-size: 0.58rem;
    color: var(--color-text-light);
    opacity: 0.5;
    letter-spacing: 0.04em;
}
.brand-mark-legal {
    position: absolute;
    left: 16px;
    display: flex;
    gap: 12px;
    align-items: center;
    font-size: 0.58rem;
    color: var(--color-text-light);
    opacity: 0.5;
    letter-spacing: 0.04em;
}
.brand-mark-legal a {
    color: inherit;
    text-decoration: none;
}
.brand-mark-legal a:hover {
    opacity: 1;
}
.brand-mark-text {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}
.brand-mark-canopy {
    font-size: 0.84rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    color: #6B3FA8;
}
.brand-mark-byline {
    font-size: 0.56rem;
    font-weight: 300;
    letter-spacing: 0.08em;
    color: var(--color-text-light);
}

/* ============================================================
   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 - deep purple theme
   ============================================================ */

[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(141, 205, 196, 0.15);
    --color-primary: #8dcdc4;
    --color-primary-light: #b0f0e7;
    --color-primary-dark: #6aaaa1;
    --color-accent: #b57da8;
    --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);
    --color-msgr-tick-read: #4fc3f7;
    --color-primary-soft: rgba(141, 205, 196, 0.18);
    --color-surface-alt: #252929;
    --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"] .enrichment-card {
    background: var(--color-card);
    border-color: var(--color-border);
}

[data-theme="dark"] .enrichment-card:hover {
    border-color: var(--color-primary);
}

[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: var(--color-card);
    border-color: var(--color-border);
}

[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"] .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;
}

/* Dark mode toggle button in hamburger menu */
.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;
    text-align: left;
}
.dark-mode-toggle:hover {
    background: rgba(107, 76, 138, 0.06);
}
.dark-mode-track {
    width: 36px;
    height: 20px;
    border-radius: 10px;
    background: var(--color-border);
    position: relative;
    transition: background 0.2s;
    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;
}
.dark-mode-track.on .dark-mode-thumb {
    transform: translateX(16px);
}

[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
   ============================================================ */

/* Inline pulsing dot - used in nav menu and application status rows */
.hr-pending-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    animation: livePulse 1.5s ease-in-out infinite;
    vertical-align: middle;
    flex-shrink: 0;
    margin-left: 5px;
}

/* Dot positioned on the hamburger button (top-right corner) */
#hamburgerPendingDot {
    position: absolute;
    top: 0px;
    right: 0px;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: #ef4444;
    animation: livePulse 1.5s ease-in-out infinite;
    display: none;
    pointer-events: none;
    border: 2px solid var(--color-bg);
}
#hamburgerPendingDot.visible { display: block; }

/* ── 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(141, 205, 196, 0.2) !important;
    border-color: transparent !important;
    box-shadow: -5px 0 0 rgba(141,205,196,0.2), 5px 0 0 rgba(141,205,196,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; }

/* ── Canopy 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 (canopyDatePicker 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, #6B4C8A);
    color: #fff;
    font-weight: 600;
}

/* ── 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);
}

/* ============================================================
   Shared Calendar Base - single source of truth for both
   the School Calendar and the HR Leave Calendar
   ============================================================ */

.cal-wrap {
    max-width: 540px;
    margin: 0 auto;
    background: var(--color-card);
    border-radius: 12px;
    padding: 12px;
    border: 1px solid var(--color-border);
    box-shadow: var(--color-shadow);
}

/* Header row: prev / month label / next */
.cal-header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
}
.cal-header .cal-month-label {
    flex: 1;
    text-align: center;
    font-weight: 600;
    font-size: var(--font-size-body);
}
.cal-nav-btn {
    background: none;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: var(--font-size-body);
    color: var(--color-text);
    flex-shrink: 0;
    transition: background 0.15s;
}
.cal-nav-btn:hover { background: var(--color-bg); }
.cal-nav-btn:disabled { opacity: 0.25; cursor: default; pointer-events: none; }

/* Day-of-week label row */
.cal-dow-row {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    margin-bottom: 4px;
    gap: 2px;
}
.cal-dow-label {
    text-align: center;
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--color-text-light);
    padding: 2px 0;
}

/* Calendar grid */
.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}
.cal-loading {
    grid-column: 1 / -1;
    text-align: center;
    padding: 32px;
    color: var(--color-text-light);
    font-size: var(--font-size-body);
}
.cal-cell--empty { visibility: hidden; }

/* Individual day cell */
.cal-cell {
    background: var(--color-bg);
    border: 1.5px solid transparent;
    border-radius: 8px;
    padding: 6px 4px 5px;
    min-height: 58px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
    position: relative;
    -webkit-tap-highlight-color: transparent;
    color: inherit;
}
.cal-cell:hover { background: color-mix(in srgb, var(--color-primary) 7%, var(--color-bg)); }
.cal-cell--dim { opacity: 0.45; }
.cal-cell--has-items .cal-day-num { font-weight: 700; }
.cal-cell--today .cal-day-num {
    background: var(--color-primary);
    color: #fff;
    border-radius: 50%;
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.cal-cell--selected {
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 8%, transparent);
}

.cal-day-num {
    font-size: var(--font-size-label);
    font-weight: 500;
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

/* Dot/chip container */
.cal-dots {
    display: flex;
    align-items: center;
    gap: 3px;
    flex-wrap: wrap;
    justify-content: center;
    min-height: 10px;
}

/* Detail panel - accordion expand */
.cal-detail {
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    margin-top: 0;
    padding: 0 12px;
    background: var(--color-bg);
    border-radius: 10px;
    transition: max-height 0.4s cubic-bezier(0.22, 1, 0.36, 1),
                opacity     0.3s ease,
                margin-top  0.35s ease,
                padding     0.35s ease;
}
.cal-detail.show {
    max-height: 500px;
    opacity: 1;
    margin-top: 8px;
    padding: 10px 12px;
}

/* Detail panel content */
.cal-detail-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}
.cal-detail-date {
    font-weight: 600;
    font-size: var(--font-size-body);
}
.cal-detail-list { display: flex; flex-direction: column; gap: 6px; }
.cal-detail-item {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--font-size-body);
}
.cal-detail-name { flex: 1; font-weight: 500; }
.cal-detail-badge {
    font-size: var(--font-size-small);
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 4px;
    flex-shrink: 0;
}

/* Legend */
.cal-legend { margin-top: 14px; }
.cal-legend-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}
.cal-legend-item {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: var(--font-size-label);
    color: var(--color-text-light);
}
.cal-legend-label { font-weight: 500; }

/* Shared animations */
@keyframes calItemIn {
    from { opacity: 0; transform: translateY(7px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes calCellPop {
    0%   { transform: scale(1); }
    30%  { transform: scale(0.84); }
    70%  { transform: scale(1.06); }
    100% { transform: scale(1); }
}
.cal-cell--selected {
    animation: calCellPop 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes calSlideLeft {
    from { opacity: 0; transform: translateX(22px); }
    to   { opacity: 1; transform: translateX(0); }
}
@keyframes calSlideRight {
    from { opacity: 0; transform: translateX(-22px); }
    to   { opacity: 1; transform: translateX(0); }
}
@keyframes calExitLeft {
    from { opacity: 1; transform: translateX(0); }
    to   { opacity: 0; transform: translateX(-22px); }
}
@keyframes calExitRight {
    from { opacity: 1; transform: translateX(0); }
    to   { opacity: 0; transform: translateX(22px); }
}
.cal-grid--slide-left  { animation: calSlideLeft  0.26s cubic-bezier(0.22, 1, 0.36, 1) both; }
.cal-grid--slide-right { animation: calSlideRight 0.26s cubic-bezier(0.22, 1, 0.36, 1) both; }
.cal-grid--exit-left   { animation: calExitLeft   0.22s cubic-bezier(0.4, 0, 1, 1) forwards; pointer-events: none; }
.cal-grid--exit-right  { animation: calExitRight  0.22s cubic-bezier(0.4, 0, 1, 1) forwards; pointer-events: none; }

/* ─── Shared dark mode ─── */
[data-theme="dark"] .cal-nav-btn {
    border-color: var(--color-border);
    color: var(--color-text);
}
[data-theme="dark"] .cal-cell {
    background: #28322f;
    border-color: #3a4a47;
}
[data-theme="dark"] .cal-cell:hover { background: #2f3d39; }
[data-theme="dark"] .cal-cell--dim { opacity: 0.6; }
[data-theme="dark"] .cal-cell--selected {
    background: rgba(141, 205, 196, 0.15);
    border-color: var(--color-primary);
}
[data-theme="dark"] .cal-detail {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
}

/* ─── Shared mobile tweaks ─── */
@media (max-width: 360px) {
    .cal-cell { min-height: 50px; padding: 4px 2px; }
    .cal-day-num { font-size: 0.73rem; width: 20px; height: 20px; }
    .cal-cell--today .cal-day-num { width: 20px; height: 20px; }
}

/* ============================================================
   HR Leave Calendar - module-specific styles only
   ============================================================ */

.hr-cal-cell--dwd { opacity: 1; border-left: 2px solid var(--color-primary); }
.hr-cal-ph-badge,
.hr-cal-dwd-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--font-size-label);
    font-weight: 600;
    color: var(--color-text-light);
    background: rgba(128,128,128,0.1);
    border-radius: 6px;
    padding: 4px 10px;
    margin-bottom: 8px;
}
.hr-cal-ph-icon { font-size: var(--font-size-body); }
.hr-cal-dwd-badge { color: var(--color-primary); background: rgba(59, 130, 246, 0.08); }

/* Initial chips (avatar badges in day cells) */
.hr-cal-initial-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 3px;
    font-size: 0.62rem;
    font-weight: 700;
    color: #fff;
    line-height: 1;
    flex-shrink: 0;
}
.hr-cal-dot-more {
    font-size: 0.6rem;
    font-weight: 700;
    color: var(--color-text-light);
    line-height: 1;
}

/* Detail panel - HR-specific dot (larger, squared for initials) */
.hr-cal-detail-dot {
    width: 20px;
    height: 20px;
    border-radius: 4px;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-small);
    font-weight: 700;
    color: #fff;
}

/* Half-day indicator - sits to the left of the leave type badge */
.hr-cal-half-day-label {
    font-size: var(--font-size-small);
    font-weight: 500;
    color: var(--color-text-light);
    flex-shrink: 0;
}

/* Legend - HR-specific dot (larger, squared for initials) */
.hr-cal-legend-dot {
    width: 18px;
    height: 18px;
    border-radius: 3px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-small);
    font-weight: 700;
    color: #fff;
    flex-shrink: 0;
}

/* HR dark mode specifics */
[data-theme="dark"] .hr-cal-cell--dwd { opacity: 1; }
[data-theme="dark"] .hr-cal-dot-more { color: var(--color-text-light); }

/* HR mobile tweaks */
@media (max-width: 360px) {
    .hr-cal-initial-chip { width: 13px; height: 13px; font-size: 0.58rem; }
}

/* ============================================================
   Resources Calendar
   ============================================================ */

/* ─── Category color tokens ─── */
:root {
    --cd-color-closure: #e05555;
    --cd-color-holiday: #3a7fd4;
    --cd-color-event:   #7c3aed;
    --cd-color-custom:  #3da05a;
    --cd-color-programme: #d4930a;
    --cd-color-extended: #0e9f9f;
}

.cd-view-toggle {
    display: flex;
    gap: 0;
    margin-bottom: 16px;
    background: var(--color-bg);
    border-radius: 8px;
    padding: 3px;
    width: fit-content;
}
.cd-view-btn {
    background: none;
    border: none;
    padding: 6px 16px;
    border-radius: 6px;
    font-size: var(--font-size-label);
    font-weight: 600;
    color: var(--color-text-light);
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.cd-view-btn.active {
    background: var(--color-card);
    color: var(--color-text);
    box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}
.cd-view-btn:hover:not(.active) { color: var(--color-text); }

/* Sub-toggle (Monthly / Year) - visually subordinate to top section toggle */
.cd-sub-toggle {
    display: flex;
    gap: 4px;
    margin-bottom: 12px;
}
.cd-sub-btn {
    background: none;
    border: none;
    padding: 4px 10px;
    border-radius: 4px;
    font-size: var(--font-size-small);
    font-weight: 500;
    color: var(--color-text-light);
    cursor: pointer;
    transition: color 0.15s;
}
.cd-sub-btn.active {
    color: var(--color-text);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
}
.cd-sub-btn:hover:not(.active) { color: var(--color-text); }

/* Category dot indicators */
.cd-cal-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}
.cd-cal-dot--closure  { background: var(--cd-color-closure); }
.cd-cal-dot--holiday  { background: var(--cd-color-holiday); }
.cd-cal-dot--event    { background: var(--cd-color-event); }
.cd-cal-dot--custom   { background: var(--cd-color-custom); }
.cd-cal-dot--programme { background: var(--cd-color-programme); }
.cd-cal-dot--extended { background: var(--cd-color-extended); }

/* Programme band - subtle tint across date range cells */
.cd-cal-cell--programme {
    background: color-mix(in srgb, var(--cd-color-programme) 12%, var(--color-bg));
    border-radius: 0;
}
[data-theme="dark"] .cal-cell.cd-cal-cell--programme {
    background: #3a564e;
}
.cd-cal-cell--programme-start { border-top-left-radius: 8px; border-bottom-left-radius: 8px; }
.cd-cal-cell--programme-end   { border-top-right-radius: 8px; border-bottom-right-radius: 8px; }
.cd-cal-cell--programme.cal-cell--selected {
    background: color-mix(in srgb, var(--cd-color-programme) 22%, var(--color-bg));
}

/* Detail panel - Resources-specific dot (small circle for category) */
.cd-cal-detail-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}
.cd-cal-detail-badge--closure  { background: color-mix(in srgb, var(--cd-color-closure) 13%, transparent); color: var(--cd-color-closure); }
.cd-cal-detail-badge--holiday  { background: color-mix(in srgb, var(--cd-color-holiday) 13%, transparent); color: var(--cd-color-holiday); }
.cd-cal-detail-badge--event    { background: color-mix(in srgb, var(--cd-color-event)   13%, transparent); color: var(--cd-color-event); }
.cd-cal-detail-badge--custom   { background: color-mix(in srgb, var(--cd-color-custom)  13%, transparent); color: var(--cd-color-custom); }
.cd-cal-detail-badge--programme { background: color-mix(in srgb, var(--cd-color-programme) 13%, transparent); color: var(--cd-color-programme); }
.cd-cal-detail-badge--extended { background: color-mix(in srgb, var(--cd-color-extended) 13%, transparent); color: var(--cd-color-extended); }
.cd-cal-detail-event-link {
    cursor: pointer;
    text-decoration: underline;
    text-decoration-style: dotted;
    text-underline-offset: 2px;
}
.cd-cal-detail-event-link:hover { opacity: 0.8; }

/* Legend - Resources-specific dot (small circle) */
.cd-cal-legend-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}
.cd-cal-legend-swatch {
    width: 16px;
    height: 8px;
    border-radius: 3px;
    flex-shrink: 0;
    background: color-mix(in srgb, var(--cd-color-programme) 35%, var(--color-bg));
    border: 1px solid var(--cd-color-programme);
}
[data-theme="dark"] .cd-cal-legend-swatch {
    background: #3a564e;
    border-color: #4d7a6e;
}

/* ─── Year-at-a-Glance ─── */
.cd-year-wrap { max-width: 720px; margin: 0 auto; }
.cd-year-header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 16px;
}
.cd-year-label {
    flex: 1;
    text-align: center;
    font-weight: 600;
    font-size: var(--font-size-body);
}
.cd-year-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}
.cd-year-month {
    background: var(--color-bg);
    border-radius: 10px;
    padding: 10px 8px;
    cursor: pointer;
    transition: box-shadow 0.15s;
}
.cd-year-month:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
.cd-year-month-title {
    font-weight: 600;
    font-size: var(--font-size-label);
    text-align: center;
    margin-bottom: 6px;
    color: var(--color-text);
}
.cd-year-mini-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
}
.cd-year-mini-dow {
    text-align: center;
    font-size: 0.55rem;
    font-weight: 600;
    color: var(--color-text-light);
    padding: 1px 0;
}
.cd-year-mini-cell {
    text-align: center;
    font-size: 0.6rem;
    padding: 2px 0;
    border-radius: 3px;
    color: var(--color-text-light);
    position: relative;
}
.cd-year-mini-cell--today {
    background: var(--color-primary);
    color: #fff;
    font-weight: 700;
    border-radius: 50%;
}
.cd-year-mini-cell--has-items::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 4px;
    height: 4px;
    border-radius: 50%;
}
.cd-year-mini-cell--closure::after   { background: var(--cd-color-closure); }
.cd-year-mini-cell--holiday::after   { background: var(--cd-color-holiday); }
.cd-year-mini-cell--event::after     { background: var(--cd-color-event); }
.cd-year-mini-cell--custom::after    { background: var(--cd-color-custom); }
.cd-year-mini-cell--extended::after  { background: var(--cd-color-extended); }
.cd-year-mini-cell--dim { opacity: 0.4; }
.cd-year-mini-cell--programme {
    background: color-mix(in srgb, var(--cd-color-programme) 12%, var(--color-bg));
    border-radius: 0;
}
.cd-year-mini-cell--programme-start { border-top-left-radius: 3px; border-bottom-left-radius: 3px; }
.cd-year-mini-cell--programme-end   { border-top-right-radius: 3px; border-bottom-right-radius: 3px; }
[data-theme="dark"] .cd-year-mini-cell.cd-year-mini-cell--programme { background: #3a564e; }

/* ─── Closure Quick-Reference ─── */
.cd-closure-list { display: flex; flex-direction: column; gap: 0; }
.cd-closure-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border);
    font-size: var(--font-size-body);
}
.cd-closure-item:last-child { border-bottom: none; }
.cd-closure-date {
    font-weight: 600;
    min-width: 72px;
    flex-shrink: 0;
    font-size: var(--font-size-label);
}
.cd-closure-name { flex: 1; }
.cd-closure-badge {
    font-size: var(--font-size-small);
    font-weight: 600;
    padding: 3px 8px 2px;
    border-radius: 4px;
    flex-shrink: 0;
}
.cd-closure-badge--closure { background: color-mix(in srgb, var(--cd-color-closure) 13%, transparent); color: var(--cd-color-closure); }
.cd-closure-badge--holiday { background: color-mix(in srgb, var(--cd-color-holiday) 13%, transparent); color: var(--cd-color-holiday); }
.cd-closure-badge--extended_hours { background: color-mix(in srgb, var(--cd-color-extended) 13%, transparent); color: var(--cd-color-extended); }
.cd-event-type-hint {
    margin: 6px 0 0;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    line-height: 1.45;
}

/* ─── Markdown-rendered document bodies (reset undoes browser list defaults) ─── */
#docBodyPreview ul, #consentFormSignBody ul, #docStaticViewBody ul,
#docBodyPreview ol, #consentFormSignBody ol, #docStaticViewBody ol {
    padding-left: 1.5em;
    margin: 6px 0;
}
#docBodyPreview li, #consentFormSignBody li, #docStaticViewBody li {
    margin-bottom: 4px;
}

/* ─── Documents Section ─── */
.cd-doc-list { display: flex; flex-direction: column; gap: 0; }
.cd-doc-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 0;
    border-bottom: 1px solid var(--color-border);
    font-size: var(--font-size-body);
}
.cd-doc-item:last-child { border-bottom: none; }
.cd-doc-icon {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    background: var(--color-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.1rem;
    flex-shrink: 0;
}
.cd-doc-info { flex: 1; min-width: 0; }
.cd-doc-name { font-weight: 600; }
.cd-doc-type {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    text-transform: capitalize;
}
.cd-doc-actions { display: flex; gap: 6px; align-items: center; flex-shrink: 0; }
.cd-doc-view-btn {
    background: var(--color-primary);
    color: #fff;
    border: none;
    border-radius: 6px;
    padding: 6px 14px;
    font-size: var(--font-size-label);
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.15s;
}
.cd-doc-view-btn:hover { opacity: 0.85; }
.cd-doc-delete-btn {
    background: none;
    border: none;
    color: var(--color-text-light);
    cursor: pointer;
    font-size: var(--font-size-body);
    padding: 4px;
    transition: color 0.15s;
}
.cd-doc-delete-btn:hover { color: var(--color-error); }

/* ─── Action Required Cards ─── */
.cd-action-list { display: flex; flex-direction: column; gap: 8px; }
.cd-action-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-left: 3px solid var(--color-error);
    border-radius: 10px;
    cursor: pointer;
    transition: transform 0.15s var(--ease-out), box-shadow 0.15s var(--ease-out);
}
@media (hover: hover) {
    .cd-action-card:hover {
        transform: translateY(-1px);
        box-shadow: var(--color-shadow);
    }
}
.cd-action-body { flex: 1; min-width: 0; }
.cd-action-title { font-weight: 600; font-size: var(--font-size-body); }
.cd-action-meta {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 3px;
}
.cd-action-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.cd-action-pill {
    background: rgba(192, 57, 43, 0.1);
    color: var(--color-error);
    border: 1px solid rgba(192, 57, 43, 0.25);
    padding: 3px 10px;
    border-radius: 999px;
    font-size: var(--font-size-small);
    font-weight: 500;
    white-space: nowrap;
}
.cd-action-chevron {
    color: var(--color-text-light);
    font-size: 1rem;
    line-height: 1;
    flex-shrink: 0;
}

/* ─── Resources Settings List ─── */
.cd-settings-list { display: flex; flex-direction: column; }
.cd-settings-item {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    padding: 12px 0;
    border-bottom: 1px solid var(--color-border);
}
.cd-settings-item:last-child { border-bottom: none; }
.cd-settings-item-info {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.cd-settings-item-date {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    font-weight: 500;
}
.cd-settings-item-name { font-weight: 500; }
.cd-settings-item-desc { font-size: var(--font-size-small); }
.cd-settings-item-actions { display: flex; align-items: center; gap: 8px; justify-content: space-between; }

/* ─── Calendar settings type filter pills ─── */
.cd-type-filter {
    font-size: var(--font-size-small);
    font-weight: 500;
    padding: 3px 10px 2px;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    background: transparent;
    color: var(--color-text-light);
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.cd-type-filter.active                     { background: var(--color-text); border-color: var(--color-text); color: var(--color-card); }
.cd-type-filter--public_holiday.active     { background: color-mix(in srgb, var(--cd-color-holiday)   20%, transparent); border-color: var(--cd-color-holiday);   color: var(--cd-color-holiday); }
.cd-type-filter--closure.active            { background: color-mix(in srgb, var(--cd-color-closure)   20%, transparent); border-color: var(--cd-color-closure);   color: var(--cd-color-closure); }
.cd-type-filter--event.active              { background: color-mix(in srgb, var(--cd-color-event)     20%, transparent); border-color: var(--cd-color-event);     color: var(--cd-color-event); }
.cd-type-filter--programme.active          { background: color-mix(in srgb, var(--cd-color-programme) 20%, transparent); border-color: var(--cd-color-programme); color: var(--cd-color-programme); }
.cd-type-filter--extended_hours.active     { background: color-mix(in srgb, var(--cd-color-extended)  20%, transparent); border-color: var(--cd-color-extended);  color: var(--cd-color-extended); }

/* ─── Resources dark mode (module-specific only) ─── */
[data-theme="dark"] .cd-view-btn.active {
    background: #28322f;
}
[data-theme="dark"] .cd-year-month {
    background: #28322f;
}

/* ─── Mobile tweaks ─── */
@media (max-width: 600px) {
    .cd-year-grid { grid-template-columns: repeat(3, 1fr); gap: 8px; }
}
@media (max-width: 400px) {
    .cd-year-grid { grid-template-columns: repeat(2, 1fr); gap: 6px; }
}

/* ============================================================ */
/* Teaching Assistants Module                                    */
/* ============================================================ */

/* Messenger pending pulse dot - mirrors .hr-pending-dot */
.msgr-pending-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    animation: livePulse 1.5s ease-in-out infinite;
    vertical-align: middle;
    flex-shrink: 0;
    margin-left: 5px;
}

/* TA pending pulse dot - mirrors .hr-pending-dot */
.ta-pending-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    animation: livePulse 1.5s ease-in-out infinite;
    vertical-align: middle;
    flex-shrink: 0;
    margin-left: 5px;
}

/* Holiday Programme pending pulse dot - mirrors .hr-pending-dot */
.holiday-programme-pending-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    animation: livePulse 1.5s ease-in-out infinite;
    vertical-align: middle;
    flex-shrink: 0;
    margin-left: 5px;
}

/* Teaching Assistant role badge */
.badge-purple {
    background: #EDE9FE;
    color: #5B21B6;
}

/* TA slot card */
.ta-slot-card {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 14px 16px;
    margin-bottom: 12px;
    transition: box-shadow 0.15s;
}
.ta-slot-card:hover {
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.ta-slot-card.ta-slot-confirmed {
    border-left: 3px solid var(--color-success, #16a34a);
}
.ta-slot-card.ta-slot-filled {
    border-left: 3px solid #9CA3AF;
    opacity: 0.85;
}
.ta-slot-card.ta-slot-cancelled {
    opacity: 0.6;
}
.ta-slot-header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}
.ta-slot-title {
    font-weight: 600;
    font-size: var(--font-size-body);
    color: var(--color-text, #111827);
}
.ta-slot-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    font-size: var(--font-size-body);
    color: var(--color-text-light, #6B7280);
    margin-bottom: 6px;
}
.ta-slot-desc {
    font-size: var(--font-size-body);
    color: var(--color-text-light, #6B7280);
    margin: 6px 0;
}
.ta-slot-actions {
    margin-top: 10px;
    display: flex;
    align-items: center;
    gap: 8px;
}
/* TA manager search result items */
#notifTaManagerResults > div {
    transition: background-color 0.15s ease-out;
}
#notifTaManagerResults > div:hover {
    background: var(--color-bg);
}
#notifTaManagerResults > div:last-child {
    border-bottom: none;
}

.ta-section-heading {
    font-size: var(--font-size-body);
    font-weight: 600;
    margin-bottom: 12px;
    color: var(--color-text, #111827);
}
.attendance-section-heading {
    font-size: var(--font-size-body);
    font-weight: 600;
    margin: 0 0 6px;
    color: var(--color-primary);
}
.hr-settings-section-heading {
    margin: 24px 0 12px;
}
.hr-staff-card {
    background: var(--color-bg);
    border-radius: 8px;
    border: 1px solid var(--color-border);
    padding: 16px;
    margin-bottom: 12px;
}
.hr-staff-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
}
.hr-staff-card-name {
    font-weight: 600;
    font-size: var(--font-size-body);
    color: var(--color-text);
}
.hr-staff-card-delete {
    padding: 0;
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.hr-staff-card-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}
.hr-staff-card-fields label {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-bottom: 4px;
}

/* ── HR Year Picker ───────────────────────────────────────── */
.hr-year-picker {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--color-border);
    border-radius: 20px;
    overflow: hidden;
    background: var(--color-surface);
}
.hr-year-nav {
    background: none;
    border: none;
    padding: 5px 14px;
    cursor: pointer;
    color: var(--color-text);
    font-size: 20px;
    line-height: 1;
    transition: background 0.15s;
    display: flex;
    align-items: center;
}
.hr-year-nav:hover:not(:disabled) { background: var(--color-border); }
.hr-year-nav:disabled { opacity: 0.25; cursor: default; }
.hr-year-label {
    padding: 5px 2px;
    font-weight: 600;
    font-size: var(--font-size-body);
    min-width: 44px;
    text-align: center;
    color: var(--color-text);
    user-select: none;
}

/* ── HR Workweek day toggle buttons ──────────────────────── */
.hr-ww-btn {
    padding: 6px 14px;
    border-radius: 6px;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text);
    cursor: pointer;
    font-size: var(--font-size-body);
}
.hr-ww-btn--active {
    border-color: var(--color-primary);
    background: var(--color-primary);
    color: var(--color-bg);
    font-weight: 600;
}

/* ── HR Team Balance ──────────────────────────────────────── */
.hr-team-cards { display: flex; flex-direction: column; gap: 10px; }

/* Mobile staff balance card */
.hr-bal-card {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    background: var(--color-surface);
    cursor: pointer;
    transition: background 0.15s;
}
.hr-bal-card:active { background: var(--color-border); }
.hr-bal-card-name {
    font-weight: 600;
    font-size: var(--font-size-body);
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.hr-bal-chips {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}
.hr-bal-chip {
    display: flex;
    flex-direction: column;
    align-items: center;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 6px;
    padding: 4px 8px;
    min-width: 42px;
}
.hr-bal-chip-code {
    font-size: 10px;
    font-weight: 700;
    color: var(--color-text-light);
    letter-spacing: 0.05em;
    line-height: 1.2;
}
.hr-bal-chip-val {
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text);
    line-height: 1.3;
}

.hr-bal-card-arrow {
    color: var(--color-text-light);
    font-size: 14px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
}

/* ── My Leaves - activity log timeline ────────────────────── */
.hr-activity-log { display: flex; flex-direction: column; }
.hr-activity-row {
    display: flex;
    gap: 16px;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border);
}
.hr-activity-row:last-child { border-bottom: none; }
.hr-activity-time {
    min-width: 52px;
    text-align: right;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    line-height: 1.4;
    flex-shrink: 0;
}
.hr-activity-body { flex: 1; line-height: 1.4; }

.ta-stats-row {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 12px;
}
.ta-stat-box {
    flex: 1;
    min-width: 100px;
    background: var(--color-bg, #F9FAFB);
    border: 1px solid var(--color-border, #E5E7EB);
    border-radius: 8px;
    padding: 14px 16px;
    text-align: center;
}
.ta-stat-value {
    font-size: var(--font-size-heading);
    font-weight: 700;
    color: var(--color-primary, #0f766e);
    margin-bottom: 4px;
}
.ta-stat-label {
    font-size: var(--font-size-label);
    color: var(--color-text-light, #6B7280);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.ta-applicant-row {
    padding: 6px 0;
    border-bottom: 1px solid var(--color-border, #F3F4F6);
    font-size: var(--font-size-body);
}
.ta-applicant-row:last-child {
    border-bottom: none;
}

/* TA location chips */
.ta-location-add-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
}
.ta-location-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}
.ta-location-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--color-primary);
    color: #fff;
    border-radius: 999px;
    padding: 4px 12px 4px 14px;
    font-size: var(--font-size-body);
    font-weight: 500;
}
.ta-location-chip-remove {
    background: none;
    border: none;
    cursor: pointer;
    color: inherit;
    font-size: var(--font-size-body);
    line-height: 1;
    padding: 0;
    opacity: 0.6;
}
.ta-location-chip-remove:hover {
    opacity: 1;
}

/* ============================================================
   Accessibility - Reduced Motion
   ============================================================ */
/* ============================================================
   My Family - Redesigned
   ============================================================ */

.constellation-root {
    position: relative;
}

.family-canvas {
    background: var(--color-bg);
    border-radius: 10px;
    border: 1px solid var(--color-border);
    overflow: hidden;
}


.constellation-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 55vh;
    padding: 40px 0;
    gap: 36px;
}

.constellation-node.no-anim {
    animation: none;
    opacity: 1;
}

.constellation-row {
    display: flex;
    gap: 44px;
    justify-content: center;
    align-items: flex-start;
}

.constellation-node {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    opacity: 0;
    animation: nodeIn 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.node-circle {
    width: 132px;
    height: 132px;
    border-radius: 50%;
    overflow: hidden;
    transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1),
                box-shadow 0.18s ease;
    box-shadow: 0 4px 18px rgba(107, 76, 138, 0.12);
}

[data-theme="dark"] .node-circle {
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
}


.constellation-node:not(.constellation-node--self):active .node-circle {
    transform: scale(0.91);
}

@media (hover: hover) {
    .constellation-node:not(.constellation-node--self):hover .node-circle {
        transform: translateY(-3px) scale(1.04);
        box-shadow: 0 10px 28px rgba(107, 76, 138, 0.18);
    }
}

.node-circle img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.node-circle-initials {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(145deg, var(--color-primary-light) 0%, var(--color-primary-dark) 100%);
    color: #fff;
    font-size: 2.4rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.node-name {
    font-size: var(--font-size-label);
    font-weight: 600;
    color: var(--color-text);
    text-align: center;
    max-width: 96px;
    line-height: 1.35;
    letter-spacing: 0.01em;
}


@keyframes nodeIn {
    from { opacity: 0; transform: scale(0.72); }
    to   { opacity: 1; transform: scale(1); }
}

@keyframes nodeHop {
    0%   { transform: translate(var(--hop-dx), var(--hop-dy)) scale(1); }
    45%  { transform: translate(calc(var(--hop-dx) * 0.5), calc(var(--hop-dy) * 0.5)) scale(1.18); }
    100% { transform: translate(0px, 0px) scale(1); }
}


@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ============================================================
   Vendor Chat
   ============================================================ */

.vendor-chat-root {
    display: flex;
    height: calc(100vh - 120px);
    min-height: 400px;
    background: var(--color-bg);
    border-radius: 16px;
    border: 1px solid var(--color-border);
    overflow: hidden;
}

/* Sidebar - family list */
.vendor-chat-sidebar {
    width: 280px;
    min-width: 220px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--color-border);
    background: var(--color-surface);
}

.vendor-chat-sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px;
    border-bottom: 1px solid var(--color-border);
    gap: 10px;
}

.vendor-chat-sidebar-header h2 {
    font-size: var(--font-size-body);
    font-weight: 700;
    margin: 0;
    white-space: nowrap;
}

.vendor-family-list {
    flex: 1;
    overflow-y: auto;
}

.vendor-family-item {
    padding: 12px 16px;
    cursor: pointer;
    border-bottom: 1px solid var(--color-border);
    transition: background 0.15s;
}

.vendor-family-item:hover { background: var(--color-hover); }
.vendor-family-item.active { background: var(--color-primary-light, rgba(100,200,180,0.12)); }

.vendor-family-item-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 3px;
}

.vendor-family-name {
    font-weight: 600;
    font-size: var(--font-size-body);
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 140px;
}

.vendor-family-time {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    white-space: nowrap;
}

.vendor-family-preview {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.vendor-window-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    background: var(--color-primary);
    color: #fff;
    border-radius: 9px;
    font-size: var(--font-size-small);
    font-weight: 700;
}

/* Thread panel */
.vendor-chat-thread {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--color-bg);
}

.vendor-chat-thread-empty {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

.vendor-chat-messages {
    flex: 1;
    overflow-y: auto;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.vendor-chat-no-messages {
    text-align: center;
    padding: 32px;
    font-size: var(--font-size-body);
}

/* Message bubbles */
.vendor-msg { display: flex; flex-direction: column; max-width: 72%; }
.vendor-msg-out { align-self: flex-end; align-items: flex-end; }
.vendor-msg-in  { align-self: flex-start; align-items: flex-start; }

.vendor-msg-bubble {
    padding: 9px 13px;
    border-radius: 14px;
    font-size: var(--font-size-body);
    line-height: 1.45;
    word-break: break-word;
    white-space: pre-wrap;
}

.vendor-msg-out .vendor-msg-bubble {
    background: var(--color-primary);
    color: #fff;
    border-bottom-right-radius: 4px;
}

.vendor-msg-in .vendor-msg-bubble {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-bottom-left-radius: 4px;
}

.vendor-msg-meta {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 3px;
    padding: 0 2px;
}

.vendor-msg-sender { font-weight: 600; }

/* Compose bar */
.vendor-chat-compose {
    border-top: 1px solid var(--color-border);
    padding: 10px 14px;
    background: var(--color-surface);
}

.vendor-chat-compose-row {
    display: flex;
    gap: 8px;
    align-items: flex-end;
}

.vendor-chat-input {
    flex: 1;
    padding: 9px 12px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    background: var(--color-bg);
    color: var(--color-text);
    font-size: var(--font-size-body);
    resize: none;
    min-height: 38px;
    max-height: 120px;
    line-height: 1.4;
    font-family: inherit;
}

.vendor-chat-input:focus { outline: none; border-color: var(--color-primary); }

/* Window info banner */
.vendor-window-info {
    font-size: var(--font-size-small);
    text-align: center;
    padding: 5px 10px;
    border-radius: 6px;
    margin-bottom: 8px;
}

.vendor-window-open   { background: rgba(46,158,94,0.12); color: var(--color-success); }
.vendor-window-closed { background: rgba(255,165,0,0.12); color: #b36b00; }

/* Mobile */
@media (max-width: 600px) {
    .vendor-chat-root { flex-direction: column; height: auto; min-height: 0; }
    .vendor-chat-sidebar { width: 100%; border-right: none; border-bottom: 1px solid var(--color-border); max-height: 220px; }
    .vendor-chat-thread { min-height: 300px; }
}

/* ============================================================
   Messenger
   ============================================================ */

.msgr-root {
    display: flex;
    border: 1px solid var(--color-border);
    border-radius: 12px;
    overflow: hidden;
    min-height: 500px;
    max-height: 70vh;
    background: var(--color-bg);
}

/* ── Sidebar ── */

.msgr-sidebar {
    width: 300px;
    min-width: 300px;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--color-border);
    background: var(--color-surface);
    overflow: hidden;
    min-height: 0;
}
.msgr-sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    border-bottom: 1px solid var(--color-border);
}
.msgr-sidebar-header h2 { margin: 0; font-size: var(--font-size-heading); }
.msgr-icon-btn {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    background: var(--color-primary);
    color: #fff;
    border: none;
    cursor: pointer;
    font-size: 15px;
    flex-shrink: 0;
    transition: opacity 0.15s;
}
.msgr-icon-btn:hover { opacity: 0.85; }
.msgr-search-bar {
    padding: 8px 10px;
    border-bottom: 1px solid var(--color-border);
    position: relative;
}
.msgr-search-clear {
    position: absolute;
    right: 16px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    padding: 0;
    color: var(--color-text-light);
    cursor: pointer;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    width: 18px;
    height: 18px;
    font-size: 13px;
    transition: color 0.15s;
}
.msgr-search-clear:hover {
    color: var(--color-text);
}
.msgr-search-input {
    width: 100%;
    padding: 7px 32px 7px 10px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-bg);
    color: var(--color-text);
    font-size: var(--font-size-body);
    box-sizing: border-box;
}
.msgr-scrollable-area {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}
.msgr-conv-list {
    flex: 1;
}
.msgr-conv-list .empty-state-text {
    padding: 20px 16px;
}

/* Conversation-list skeleton - shown only on the genuine first-ever load (every
   later open paints instantly from the durable cache). Mirrors .msgr-conv-item
   geometry so the real list swaps in without a layout jump. The per-row phase
   offset on the shimmer makes the wait feel like a living surface, not a freeze. */
.msgr-conv-skeleton-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--color-border);
}
.msgr-conv-skeleton-row .skeleton-circle { width: 40px; height: 40px; flex-shrink: 0; }
.msgr-conv-skeleton-lines {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 9px;
}
.msgr-conv-skeleton-lines .line-1 { width: 42%; }
.msgr-conv-skeleton-lines .line-2 { width: 78%; }
.msgr-conv-skeleton-row:nth-child(2) .skeleton { animation-delay: 0.08s; }
.msgr-conv-skeleton-row:nth-child(3) .skeleton { animation-delay: 0.16s; }
.msgr-conv-skeleton-row:nth-child(4) .skeleton { animation-delay: 0.24s; }
.msgr-conv-skeleton-row:nth-child(5) .skeleton { animation-delay: 0.32s; }
.msgr-conv-skeleton-row:nth-child(6) .skeleton { animation-delay: 0.40s; }
.msgr-retention-notice {
    padding: 10px 14px;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    text-align: center;
    border-top: 1px solid var(--color-border);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
}

/* Conversation items */
.msgr-conv-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    cursor: pointer;
    transition: background 0.15s, transform 100ms var(--ease-out);
    border-bottom: 1px solid var(--color-border);
    /* Bypass iOS WebKit's tap-delay heuristics that fire :hover on the first
       tap and withhold the click until the second (the "two taps required
       after swipe-back" bug — L162 epilogue, v2.92). On touch devices iOS
       treats a div with :hover as a hover-discovery target after an
       inconclusive prior gesture (a swipe whose touchend got classified as
       a drag, suppressing the click), and the next conv-item tap shows the
       :hover background without firing the click. `manipulation` short-
       circuits the heuristic and dispatches click on the first touchend. */
    touch-action: manipulation;
    /* The row is a tap/long-press gesture target, never selectable text. Without
       this, a long-press starts the native text-selection gesture, which grabs
       the word under the finger (the notif popup's title appears there). */
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}
/* Hover background only on devices with true hover capability — touch
   devices (iOS, Android) would otherwise have the :hover background "stick"
   after a tap, indistinguishable from .active, masking whether the click
   actually fired. The exact misdiagnosis the user reported as "highlight
   moves but thread doesn't open." */
@media (hover: hover) {
    .msgr-conv-item:hover { background: var(--color-surface-hover, rgba(0,0,0,0.03)); }
}
.msgr-conv-item:active { transform: scale(0.99); }
.msgr-conv-item.active { background: var(--color-surface-hover, rgba(0,0,0,0.04)); }

.msgr-conv-avatar {
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}
.msgr-avatar-img {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    object-fit: cover;
}
.msgr-avatar-initials, .msgr-avatar-group {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 14px; /* fixed: 40×40px circle - font-size must not scale with preset */
    color: #fff;
    background: var(--color-primary);
}
.msgr-avatar-group {
    background: var(--color-text-light);
    font-size: 13px; /* fixed: same circle */
}
.msgr-avatar-plant {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    flex-shrink: 0;
}

/* ── WhatsApp bridge UI ─────────────——───────────────────────────────────────── */

/* Avatar container for WA conversations - wraps initials + badge */
.msgr-conv-avatar { position: relative; flex-shrink: 0; }

/* WA avatar uses primary theme color */
.msgr-avatar-wa { background: var(--color-primary) !important; color: #fff !important; }

/* Point-of-Contact initial chip pinned to bottom-right of the avatar circle.
   Visually matches .hr-cal-initial-chip (Leave Calendar): same color SoT
   (resolveUserColor in shared.js), same first-initial pattern. Positioned
   as an avatar overlay with a surface-colored halo to lift it off the photo. */
.msgr-poc-chip {
    position: absolute;
    bottom: -3px;
    right: -4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 4px;
    background: var(--color-primary);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    border: 2px solid var(--color-surface);
    pointer-events: none;
}

/* ── Source Nav (vertical column desktop / scroll strip mobile) ── */
.msgr-source-nav {
    display: flex;
    flex-direction: column;
    width: 72px;
    min-width: 72px;
    border-right: 1px solid var(--color-border);
    background: var(--color-surface);
    padding: 8px 0;
    gap: 2px;
    overflow-y: auto;
    overflow-x: hidden;
    flex-shrink: 0;
}
.msgr-source-nav-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    width: 100%;
    padding: 10px 6px;
    border: none;
    background: transparent;
    color: var(--color-text-light);
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    position: relative;
    border-radius: 0;
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
}
.msgr-source-nav-item::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 0;
    background: var(--item-color, var(--color-primary));
    border-radius: 0 2px 2px 0;
    transition: height 0.2s;
}
.msgr-source-nav-item.is-active::before { height: 28px; }
.msgr-source-nav-item.is-active {
    color: var(--color-text);
    background: var(--color-surface-hover);
}
.msgr-source-nav-item:hover:not(.is-active) { background: var(--color-surface-hover); }
.msgr-source-nav-icon { font-size: 20px; line-height: 1; }
.msgr-source-nav-label {
    font-size: 10px;
    font-weight: 600;
    text-align: center;
    line-height: 1.2;
    word-break: break-word;
}
.msgr-source-nav-strip { display: none; }


/* Thread header subtitle */
.msgr-thread-subtitle { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* WA external sender label in message bubbles */
.msgr-msg-sender-wa {
    color: #25d366;
    font-weight: 600;
}

/* Bridge status indicator in settings */
.msgr-wa-status { font-size: var(--font-size-label); font-weight: 500; }
.msgr-wa-status-online  { color: var(--color-whatsapp); }
.msgr-wa-status-idle    { color: var(--color-text-light); }
.msgr-wa-status-unknown { color: var(--color-text-light); font-style: italic; }

/* Manage Communication — repeated section card wrapper */
.comm-section-card {
    background: var(--color-bg);
    border-radius: 10px;
    border: 1px solid var(--color-border);
    padding: 20px;
    margin-bottom: 12px;
}

/* Role permissions grid */
.msgr-access-grid { width: 100%; border-collapse: collapse; table-layout: fixed; }
.msgr-access-grid thead th {
    padding: 0 0 10px 0;
    text-align: center;
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--color-text-light);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.msgr-access-grid thead th:first-child { text-align: left; width: 46%; }
.msgr-access-grid tbody td {
    padding: 10px 0;
    text-align: center;
    border-top: 1px solid var(--color-border-subtle, rgba(0,0,0,0.06));
    vertical-align: middle;
}
.msgr-access-grid tbody td:first-child { text-align: left; }
.msgr-grid-feature { display: flex; flex-direction: column; gap: 2px; padding-right: 12px; }
.msgr-grid-label { font-size: var(--font-size-body); font-weight: 500; color: var(--color-text); }
.msgr-grid-desc { font-size: var(--font-size-small); color: var(--color-text-light); }
.msgr-grid-cb { width: 18px; height: 18px; accent-color: var(--color-accent); cursor: pointer; }
.color-whatsapp { color: var(--color-whatsapp); }

/* ── end WhatsApp bridge UI ──────────────────——───────────────────────────────── */

.msgr-conv-info { flex: 1; min-width: 0; }
.msgr-conv-header-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 6px;
}
.msgr-conv-name {
    font-weight: 600;
    font-size: var(--font-size-body);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.msgr-dm-name-link:hover {
    color: var(--color-primary);
    text-decoration: underline;
    cursor: pointer;
}
.msgr-conv-time {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    flex-shrink: 0;
}
.msgr-conv-preview-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 6px;
    margin-top: 2px;
}
.msgr-conv-preview {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
}
/* Telegram-style "Draft:" preview — the red label flags an unsent message in the
   conversation list; the draft body keeps the normal muted preview colour. */
.msgr-draft-label { color: var(--color-danger, #e74c3c); font-weight: 600; }
.msgr-unread-badge {
    background: var(--color-danger, #e74c3c);
    color: #fff;
    font-size: var(--font-size-small);
    font-weight: 700;
    min-width: 18px;
    height: 18px;
    border-radius: 9px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1px 5px 0; /* +1px top notches numeral down 1px optically */
    flex-shrink: 0;
}
.msgr-source-icon-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.msgr-source-badge {
    position: absolute;
    top: -5px;
    right: -7px;
    background: var(--color-danger, #e74c3c);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    min-width: 16px;
    height: 16px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2px 4px 0; /* +2px top notches numeral down 1px optically */
    line-height: 1;
    pointer-events: none;
}
/* Persistent "needs reply" indicator - POC has read but not replied yet.
   Solid red dot (no count, no pulse) so it reads quieter than a fresh-unread badge. */
.msgr-needs-reply-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--color-danger, #e74c3c);
    flex-shrink: 0;
    display: inline-block;
}
.msgr-source-needs-reply-dot {
    position: absolute;
    top: -2px;
    right: -4px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--color-danger, #e74c3c);
    border: 2px solid var(--color-bg, #fff);
    pointer-events: none;
}

/* ── Thread ── */

.msgr-thread {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--color-surface);
    position: relative; /* anchor for the floating scroll-to-latest button */
}
/* Scroll-to-latest button — floats above the compose bar, appears when the
   user has scrolled up from the bottom of the thread (.show toggled in JS). */
.msgr-scroll-btn {
    position: absolute;
    bottom: 80px;
    left: 50%;
    transform: translateX(-50%) translateY(8px);
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    box-shadow: 0 2px 10px rgba(0,0,0,0.18);
    color: var(--color-text);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out);
    z-index: 5;
}
.msgr-scroll-btn.show {
    opacity: 1;
    pointer-events: auto;
    transform: translateX(-50%) translateY(0);
}
.msgr-scroll-btn:hover { color: var(--color-primary); }
/* Keep the .fi base's inline-flex centering — don't override display, or the glyph
   falls back to text-baseline and rides high in the circle. */
.msgr-scroll-btn .fi { font-size: 20px; line-height: 1; position: relative; top: 2px; }
.msgr-thread-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-surface);
}
.msgr-back-btn {
    display: none;
    background: none;
    border: none;
    font-size: var(--font-size-heading);
    cursor: pointer;
    color: var(--color-text);
    padding: 4px 8px;
    transition: transform 100ms var(--ease-out), color 0.15s;
}
.msgr-back-btn:active { transform: scale(0.88); }
.msgr-thread-header-info { cursor: pointer; flex: 1; min-width: 0; }
.msgr-thread-title { font-weight: 600; font-size: var(--font-size-heading); display: block; }
.msgr-thread-subtitle { font-size: var(--font-size-small); color: var(--color-text-light); }

/* Thread header avatar */
.msgr-thread-avatar {
    position: relative;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 600;
    color: var(--color-primary);
    flex-shrink: 0;
    cursor: pointer;
}
.msgr-thread-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.msgr-thread-avatar .msgr-avatar-initials { width: 100%; height: 100%; }

/* Group photo section in member modal */
.msgr-group-photo-section {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 12px 0 16px;
    margin-bottom: 20px;
}
.msgr-group-photo-wrap {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--color-surface);
    border: 2px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 28px;
    font-weight: 700;
    color: var(--color-primary);
    position: relative;
}
.msgr-group-photo-wrap img { width: 100%; height: 100%; object-fit: cover; }
.msgr-group-photo-container {
    position: relative;
    display: inline-flex;
}
.msgr-group-photo-badge {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--color-primary);
    border: 2px solid var(--color-card);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 12px;
    pointer-events: none;
}
/* Centered modal title for group info */
.msgr-member-modal-title {
    text-align: center;
    margin: 8px 0 0;
    font-size: var(--font-size-h2);
}
.msgr-member-count {
    text-align: center;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 4px;
}

/* Conversation ID block in the chat info modal - two-row card */
.msgr-conv-id-row {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    margin: 10px auto 0;
    padding: 8px 12px;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    max-width: 100%;
    width: 100%;
    box-sizing: border-box;
    text-align: center;
}
.msgr-conv-id-label {
    color: var(--color-text-light);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    font-size: 0.7rem;
}
.msgr-conv-id-value-row {
    display: flex;
    align-items: center;
    gap: 4px;
    width: 100%;
}
.msgr-conv-id {
    font-family: 'Courier New', Courier, monospace;
    color: var(--color-text);
    background: transparent;
    padding: 0;
    user-select: all;
    word-break: break-all;
    font-size: var(--font-size-small);
    flex: 1;
}
.msgr-conv-id-copy {
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 2px 4px;
    color: var(--color-text-light);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    border-radius: 4px;
    flex-shrink: 0;
    transition: color 0.15s, background 0.15s;
}
.msgr-conv-id-copy:hover { color: var(--color-primary); background: var(--color-card); }
.msgr-conv-id-copy--ok   { color: var(--color-success); }
/* Group name row - title + edit affordance */
.msgr-group-name-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    margin: 0;
}
.msgr-group-name-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.msgr-group-name-edit-btn {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-light);
    border-radius: 8px;
    font-size: 15px;
    transition: color 0.15s, background 0.15s;
}
.msgr-group-name-edit-btn:hover { color: var(--color-primary); background: rgba(107,76,138,0.08); }
/* Group name edit - full-width input + below actions */
.msgr-group-name-edit-wrap { width: 100%; }
.msgr-group-name-input-row {
    position: relative;
    display: flex;
    align-items: center;
    margin-bottom: 10px;
}
.msgr-group-name-input {
    width: 100%;
    padding: 8px 44px 8px 12px;
    border: 1.5px solid var(--color-primary);
    border-radius: 8px;
    font-size: var(--font-size-heading);
    font-weight: 600;
    outline: none;
    box-shadow: 0 0 0 3px rgba(107,76,138,0.12);
    background: var(--color-card);
    color: var(--color-text);
    box-sizing: border-box;
}
.msgr-group-name-counter {
    position: absolute;
    right: 10px;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    font-size: 11px;
    font-weight: 500;
    color: var(--color-text-light);
    pointer-events: none;
    white-space: nowrap;
}
.msgr-group-name-counter.near-limit { color: #b07d00; }
.msgr-group-name-counter.at-limit { color: var(--color-error); }
.msgr-group-name-actions {
    display: flex;
    gap: 8px;
}
.msgr-group-name-actions .btn {
    flex: 1;
    justify-content: center;
}
[data-theme="dark"] .msgr-group-name-input { background: #253030; }
@keyframes msgr-spin { to { transform: rotate(360deg); } }
.msgr-spin { display: inline-block; animation: msgr-spin 0.8s linear infinite; }

.msgr-thread-empty {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}
.msgr-messages .empty-state-text {
    font-size: var(--font-size-small);
}
.msgr-new-choice-btn {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 12px 14px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    cursor: pointer;
    text-align: left;
    transition: background 0.15s, border-color 0.15s;
}
@media (hover: hover) {
    .msgr-new-choice-btn:hover {
        background: color-mix(in srgb, var(--color-primary) 8%, var(--color-bg));
        border-color: var(--color-primary);
    }
}
.msgr-new-choice-btn .fi {
    font-size: 1.3rem;
    color: var(--color-primary);
    flex-shrink: 0;
}
.msgr-new-choice-label {
    font-weight: 600;
    font-size: var(--font-size-body);
    color: var(--color-text);
}
.msgr-new-choice-sub {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 2px;
}

.msgr-messages {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* ── Message Bubbles ── */

.msgr-msg {
    max-width: 72%;
    display: flex;
    flex-direction: column;
    position: relative;
}
.msgr-msg-out { align-self: flex-end; }
.msgr-msg-in { align-self: flex-start; }

.msgr-msg-sender {
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--color-primary);
    margin-bottom: 2px;
    padding-left: 4px;
}
.msgr-wa-sender {
    /* color set via inline style */
}
.msgr-msg-bubble {
    padding: 8px 12px;
    border-radius: 14px;
    font-size: var(--font-size-msgr);
    line-height: 1.4;
    /* flow-root so the floated timestamp (Telegram-style trailing time) is
       contained inside the bubble even when there are no reactions below it. */
    display: flow-root;
}
/* The message text itself. white-space:pre-wrap lives here, NOT on the bubble:
   the bubble now also holds the sender name, timestamp and reactions, and the
   template's inter-element newlines would otherwise render as blank lines. */
.msgr-msg-text {
    white-space: pre-wrap;
    word-break: break-word;
}
@media (max-width: 640px) {
    .msgr-msg-bubble { user-select: none; -webkit-user-select: none; }
}
.msgr-msg-out .msgr-msg-bubble {
    background: var(--color-primary);
    color: #fff;
    border-bottom-right-radius: 4px;
}
.msgr-msg-in .msgr-msg-bubble {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-bottom-left-radius: 4px;
}
/* Staff replies in WA conversations: right-aligned but white bubble */
.msgr-msg-staff-reply .msgr-msg-bubble {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-bottom-right-radius: 4px;
}
.msgr-msg-staff-reply .msgr-voice-player { background: var(--color-surface); border: 1px solid var(--color-border); }
.msgr-msg-staff-reply .msgr-voice-play-btn { background: var(--color-primary); color: #fff; }
.msgr-msg-staff-reply .msgr-wv-bar { background: var(--color-border); }
.msgr-msg-staff-reply .msgr-wv-bar.played { background: var(--color-primary); }
.msgr-msg-staff-reply .msgr-voice-dur { color: var(--color-text-light); }
/* Clickable URLs inside message text + captions */
.msgr-link { text-decoration: underline; }
.msgr-msg-out .msgr-link { color: #fff; }
.msgr-msg-in .msgr-link,
.msgr-msg-staff-reply .msgr-link { color: var(--color-primary); }
/* General auto-linked URL (announcement bodies, etc.) - the default class
   used by linkifyText() when no link class is passed. */
.inline-link { color: var(--color-primary); text-decoration: underline; word-break: break-word; }
.msgr-msg-deleted .msgr-msg-bubble {
    opacity: 0.6;
    font-style: italic;
}
/* Failed send — keep the message fully legible (the user must read it to decide to
   resend); a red outline on the bubble + the retry row below carry the status. */
.msgr-msg-failed { opacity: 1; }
.msgr-msg-failed .msgr-msg-bubble,
.msgr-msg-failed .msgr-bubble-photo {
    box-shadow: 0 0 0 1.5px var(--color-danger, #e74c3c);
}
/* "Not delivered · Tap to retry" affordance under a failed bubble. */
.msgr-msg-retry {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-top: 3px;
    padding: 1px 4px;
    font-size: var(--font-size-small);
    color: var(--color-danger, #e74c3c);
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
}
.msgr-msg-retry i { font-size: 11px; line-height: 1; }
.msgr-msg-retry:active { opacity: 0.6; }
.msgr-msg-out .msgr-msg-retry { align-self: flex-end; }
.msgr-msg-in  .msgr-msg-retry { align-self: flex-start; }

/* Conv-list "a message didn't send" alert — red pill with a ! (action required, so it
   pulses per the Red Pulse Notification Rule). */
.msgr-send-failed-badge {
    background: var(--color-danger, #e74c3c);
    color: #fff;
    font-size: var(--font-size-small);
    font-weight: 800;
    min-width: 18px;
    height: 18px;
    border-radius: 9px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 5px 1px;
    flex-shrink: 0;
    margin-left: 4px;
    animation: msgrFailedPulse 1.6s ease-in-out infinite;
}
@keyframes msgrFailedPulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.5); }
    50%      { box-shadow: 0 0 0 4px rgba(231, 76, 60, 0); }
}

.msgr-msg-meta {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 2px 4px 0;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.msgr-msg-out .msgr-msg-meta { justify-content: flex-end; }
.msgr-msg-edited { font-style: italic; }

/* ── Telegram-style unified text bubble ──
   For text messages the sender name, message text, timestamp and reactions all
   live INSIDE .msgr-msg-bubble instead of as separate stacked rows. Media
   messages (.msgr-msg-media-msg) keep their own chrome and external meta row. */
.msgr-msg-bubble .msgr-msg-sender { padding-left: 0; margin-bottom: 2px; }
/* Bottom strip = reactions + timestamp. With NO reactions it floats into the last
   text line (trailing time, Telegram-style). Once a reaction is present it reflows
   into its own row: reactions on the LEFT, timestamp on the RIGHT. */
.msgr-msg-bubble .msgr-msg-bottom {
    float: right;
    margin-left: 10px;
    line-height: 1;
    transform: translateY(5px); /* drop onto the last text line's baseline */
}
.msgr-msg-bottom .msgr-msg-meta {
    float: none;
    display: inline-flex;
    gap: 3px;
    padding: 0;
    margin: 0;
}
.msgr-msg-bottom .msgr-reactions { margin-top: 0; }
.msgr-msg-bubble:has(.msgr-reactions:not(:empty)) .msgr-msg-bottom {
    float: none;
    clear: both;
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 6px 0 0;
    transform: none;
}
.msgr-msg-bubble:has(.msgr-reactions:not(:empty)) .msgr-msg-bottom .msgr-msg-meta {
    margin-left: auto; /* push the time to the right of the reactions row */
}

/* Keep sender, timestamp and ticks legible on the coloured outgoing fill now that
   they sit inside the bubble. Excludes staff-reply bubbles (right-aligned but white). */
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-msg-sender { color: rgba(255,255,255,0.92) !important; }
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-msg-meta,
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-msg-time,
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-tick-sent { color: rgba(255,255,255,0.8); }
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-tick-read { color: #fff; }
/* Reply reference inside an outgoing bubble: translucent-white so it reads on the fill. */
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-reply-ref {
    background: rgba(255,255,255,0.16);
    border-left-color: rgba(255,255,255,0.7);
}
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-reply-ref-text { color: rgba(255,255,255,0.82); }

/* Ticks */
.msgr-tick { font-size: var(--font-size-small); letter-spacing: -2px; }
.msgr-tick-sent { color: var(--color-text-light); }
.msgr-tick-read { color: var(--color-msgr-tick-read); }
.msgr-tick-pending { color: var(--color-text-light); letter-spacing: 0; }


/* Reply reference */
.msgr-reply-ref {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 8px 4px 10px;
    margin-bottom: 2px;
    border-left: 3px solid var(--color-primary);
    border-radius: 4px;
    background: rgba(0,0,0,0.04);
    cursor: pointer;
    font-size: var(--font-size-small);
}
.msgr-reply-ref-text-col {
    flex: 1;
    min-width: 0; /* allow ellipsis inside flex */
    overflow: hidden;
}
.msgr-reply-ref-name { font-weight: 600; display: block; font-size: var(--font-size-small); }
.msgr-reply-ref-text { color: var(--color-text-light); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.msgr-reply-ref-thumb {
    width: 36px;
    height: 36px;
    object-fit: cover;
    border-radius: 6px;
    flex-shrink: 0;
}

/* Pending message - animated bouncing dots */
@keyframes msgrDotBounce {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.35; }
    30%            { transform: translateY(-3px); opacity: 1; }
}
.msgr-tick-pending .msgr-dot {
    display: inline-block;
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: currentColor;
    animation: msgrDotBounce 1.1s ease-in-out infinite;
    margin: 0 1px;
    vertical-align: middle;
}
.msgr-tick-pending .msgr-dot:nth-child(2) { animation-delay: 0.18s; }
.msgr-tick-pending .msgr-dot:nth-child(3) { animation-delay: 0.36s; }

/* Media in bubbles */
.msgr-msg-media { margin-bottom: 4px; position: relative; overflow: hidden; }
.msgr-msg-img {
    max-width: 100%;
    max-height: 280px;
    border-radius: 10px;
    cursor: pointer;
    display: block;
    /* iOS WebKit fires its native image callout (Share / Save to Photos / Copy)
       on long-press of an <img>, intercepting our JS long-press timer before the
       emoji react menu can open. Suppress the callout so the bubble's long-press
       handler wins; short-tap still opens the lightbox via onclick. */
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}
/* Video bubbles size to the video's TRUE aspect ratio so portrait and wide clips are
   never center-cropped (the old fixed 4/3 + object-fit:cover chopped everything that
   wasn't 4:3). The wrapper carries the ratio: --msgr-ar / --msgr-w are set inline from
   the stored media_meta dimensions (recipient's first paint), or by _msgrApplyVideoBox
   once metadata loads (old messages without stored dims). The video is absolutely
   positioned to fill the box. Until the ratio is known the default 4/3 box holds the
   loading skeleton. --msgr-w is pre-fitted so height stays within the 360px cap; that
   cap is just a safety net, and max-width:100% keeps it responsive on narrow screens.
   object-fit:contain guarantees no crop even if a poster's ratio differs by a rounding px. */
.msgr-msg-media:has(> .msgr-msg-video) {
    width: var(--msgr-w, 240px);
    max-width: 100%;
    aspect-ratio: var(--msgr-ar, 4 / 3);
    max-height: 440px;          /* mirrors _msgrVideoBoxWidth MAX_H so a portrait clip fills the column */
    border-radius: 10px;
    overflow: hidden;
}
.msgr-msg-video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border-radius: 10px;
    display: block;
    background: #1a1a1a;
    object-fit: contain;
}
/* ── Loading media placeholder ──
   PHOTOS: if the message carries an inline base64 LQIP (media_meta.jpeg_thumbnail,
   set on every Canopy-sent photo), the box shows a BLURRED blow-up of it (Telegram-
   style blur-up) while the full image downloads, then _msgrPatchMediaSrc blooms the
   sharp photo in on top and crossfades the blur away (.msgr-media-lqip /
   .msgr-msg-lqip-layer below). When there's NO LQIP (some WhatsApp-inbound photos)
   it falls back to the black square + shimmer sheen, held until the full image loads.
   VIDEOS: keep their own calm sage-on-cream skeleton; this rule stops matching the
   moment a [poster] is set (_msgrAttachPosterCapture, or a bridge jpeg_thumbnail),
   so the animation halts cleanly with no JS. */
.msgr-msg-video:not([poster]) {
    background-color: #e8ecdb;
    background-image:
        linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.55) 50%, transparent 70%),
        linear-gradient(135deg, #eef1e1 0%, #e2e6d1 100%);
    background-size: 200% 100%, 100% 100%;
    background-repeat: no-repeat;
    background-position: 200% 0, 0 0;
    animation: msgrSkeletonDrift 2.4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
/* Dark thread is near-black (--color-bg #111313). The old skeleton lifted the box to
   #1f2422 with a 135deg gradient whose top-left corner (#252b28) was brighter still, so
   the box perimeter read as a hard light "outline" around the loading clip. Flatten it to
   a single fill only a hair above the thread - the box stays just perceptible, but its
   edge no longer draws a bright line - and keep the diagonal sheen as the loading cue. */
[data-theme="dark"] .msgr-msg-video:not([poster]) {
    background-color: #171b1a;
    background-image:
        linear-gradient(105deg, transparent 30%, rgba(205, 222, 210, 0.08) 50%, transparent 70%);
}

/* Photo placeholder: a box reserved at photo size. CONDITIONAL loading state - the box
   carries only a barely-there tint up front; the visible loading cue (dark square + a
   shimmer sweep) is DELAYED ~260ms (the animation-delay below). A photo that resolves from
   cache within that window is swapped in before any loading state is seen, so fast/cached
   photos never flash a placeholder - only a genuine wait surfaces the shimmer. The box is
   replaced by the real image (scale-bloom) once it loads; see .msgr-img-bloom. */
.msgr-msg-img.msgr-img-pending {
    width: min(72vw, 240px);
    aspect-ratio: 1;
    height: auto;
    border-radius: 10px;
    object-fit: cover;
    background-color: rgba(120, 130, 124, 0.10);
    background-image: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.13) 50%, transparent 70%);
    background-size: 200% 100%;
    background-repeat: no-repeat;
    background-position: 200% 0;
    animation:
        msgrPhotoShimmer 1.4s linear 260ms infinite,
        msgrImgArm 200ms var(--ease-out) 260ms forwards;
}
@keyframes msgrImgArm { to { background-color: #1a1a1a; } }
/* Dark chat background is near-black (--color-bg #111313), so the armed square lifts to a
   visible charcoal; light mode arms to a true dark square on the cream surface. */
[data-theme="dark"] .msgr-msg-img.msgr-img-pending {
    background-color: rgba(200, 215, 208, 0.06);
    background-image: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.10) 50%, transparent 70%);
    animation:
        msgrPhotoShimmer 1.4s linear 260ms infinite,
        msgrImgArmDark 200ms var(--ease-out) 260ms forwards;
}
@keyframes msgrImgArmDark { to { background-color: #2b2f2f; } }

/* Photo entrance: a snappy SCALE BLOOM, added by _msgrPatchMediaSrc once the image has
   loaded. The picture grows from 90% to full while fading in, with a small spring
   overshoot - replacing the old ~1.2s "develop from black" reveal. The final size is set
   inline before this runs, so the bloom scales the photo at its true aspect (no black
   backdrop, no size morph). A per-photo animation-delay (set inline) staggers a burst so
   several photos bloom in sequence down the thread. */
@keyframes msgrPhotoBloom {
    0%   { opacity: 0; transform: scale(0.9); }
    65%  { opacity: 1; transform: scale(1.025); }
    100% { opacity: 1; transform: scale(1); }
}
.msgr-msg-img.msgr-img-bloom {
    transform-origin: center center;
    animation: msgrPhotoBloom 320ms var(--ease-out) both;
}

/* ── Blur-up LQIP placeholder ──
   When a pending photo has an inline base64 LQIP, render a blurred blow-up of it
   behind the (src-less) main img instead of the shimmer. Specificity (0,4,0) beats
   the dark-mode pending rule above so the shimmer is suppressed in both themes. The
   main img sits on top (z-index 1) and is transparent until its src resolves, so the
   blur shows through; _msgrPatchMediaSrc then blooms the sharp photo in and removes
   this layer. */
.msgr-msg-media.msgr-media-lqip .msgr-msg-img.msgr-img-pending {
    background: transparent;
    background-image: none;
    animation: none;
    position: relative;
    z-index: 1;
}
.msgr-msg-lqip-layer {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transform: scale(1.08);   /* push the blur's soft edges past the clip so no fringe shows */
    filter: blur(12px);
    z-index: 0;
    pointer-events: none;
    transition: opacity 320ms ease-out;
}
.msgr-msg-lqip-layer.msgr-lqip-gone { opacity: 0; }

/* ── Telegram-style photo album (mosaic) ──
   N photos sharing a media_group_id render as ONE tiled bubble. Each tile reuses the
   standard .msgr-msg-media (so the blur-up LQIP, the % upload overlay and the reveal
   all work unchanged), sized to fill its grid cell via object-fit:cover. Albums are
   2-4 photos (the send cap); a larger one shows 4 tiles with a "+N" overlay. */
.msgr-album-bubble { position: relative; }
.msgr-album-grid {
    display: grid;
    gap: 2px;
    width: min(72vw, 280px);
    border-radius: 14px;
    overflow: hidden;
    background: var(--color-card);   /* shows through the 2px tile seams */
}
.msgr-album-n2 { grid-template-columns: 1fr 1fr; aspect-ratio: 2 / 1.18; }
.msgr-album-n3 {
    grid-template-columns: 1.5fr 1fr;
    grid-template-rows: 1fr 1fr;
    aspect-ratio: 1 / 0.82;
}
.msgr-album-n3 .msgr-album-tile:first-child { grid-row: 1 / span 2; }  /* big photo, left */
.msgr-album-n4 { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; aspect-ratio: 1 / 1; }
.msgr-album-tile { position: relative; overflow: hidden; min-width: 0; min-height: 0; cursor: pointer; }
/* Tile media fills its cell — override the standalone-photo sizing AND the pending
   placeholder's fixed 240px square so a still-loading tile fills the cell too. */
.msgr-album-tile .msgr-msg-media { margin: 0; width: 100%; height: 100%; border-radius: 0; }
.msgr-album-tile .msgr-msg-img,
.msgr-album-tile .msgr-msg-img.msgr-img-pending {
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    aspect-ratio: auto;
    border-radius: 0;
    object-fit: cover;
}
/* The per-tile scrim+ring already reads as "sending", so don't ALSO 55%-dim the tile
   (that double-darkens). Shrink the ring a touch to suit a smaller cell. */
.msgr-album-tile.msgr-msg-sending { opacity: 1; }
.msgr-album-tile .msgr-upload-ring { width: 38px; height: 38px; }
.msgr-album-tile .msgr-upload-pct { font-size: 11px; }
/* "+N" overlay on the last visible tile of a larger album. */
.msgr-album-more {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.45);
    color: #fff;
    font-size: 1.5rem;
    font-weight: 700;
    z-index: 2;
    pointer-events: none;
}
/* A failed tile: red inset ring + a compact icon-only retry overlay (the full
   "Not delivered · Tap to retry" row is too wide for a tile). */
.msgr-album-tile.msgr-msg-failed { box-shadow: inset 0 0 0 2px var(--color-danger, #e74c3c); }
.msgr-album-tile .msgr-msg-retry {
    position: absolute;
    inset: 0;
    margin: 0;
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    background: rgba(0, 0, 0, 0.42);
    color: #fff;
    z-index: 3;
}
.msgr-album-tile .msgr-msg-retry span { display: none; }   /* icon only in a tight tile */
.msgr-album-tile .msgr-msg-retry i { font-size: 18px; }
/* Caption under the mosaic. */
.msgr-album-caption {
    margin-top: 4px;
    max-width: min(72vw, 280px);
    font-size: var(--font-size-body);
    line-height: 1.35;
    word-break: break-word;
}
.msgr-msg-out .msgr-album-caption { align-self: flex-end; }

/* ── Telegram-style media ──
   Bare photo/video (no caption, no reply) renders frameless: the picture goes
   edge-to-edge with the sender name ABOVE it (like a text message) and only the
   timestamp overlaid bottom-right.
   Captioned media, voice and documents sit inside the standard coloured bubble. */
.msgr-bubble-photo {
    position: relative;
    overflow: hidden;
    border-radius: 14px;
    line-height: 0;
    max-width: 100%;
}
.msgr-msg-out .msgr-bubble-photo { border-bottom-right-radius: 4px; }
.msgr-msg-in  .msgr-bubble-photo { border-bottom-left-radius: 4px; }
.msgr-bubble-photo .msgr-msg-media { margin: 0; border-radius: 0; }
.msgr-bubble-photo .msgr-msg-img,
.msgr-bubble-photo .msgr-msg-video { border-radius: 0; }
.msgr-bubble-photo .msgr-msg-img { max-height: 360px; }
/* Timestamp/ticks overlaid bottom-right on a dark chip */
.msgr-meta-overlay {
    position: absolute;
    bottom: 8px; right: 8px;
    z-index: 2;
    padding: 2px 7px;
    border-radius: 10px;
    background: rgba(0,0,0,0.45);
    color: #fff !important;
    line-height: 1.3;
}
.msgr-meta-overlay .msgr-msg-time { color: #fff; }
.msgr-meta-overlay .msgr-tick-sent { color: rgba(255,255,255,0.85); }
.msgr-meta-overlay .msgr-tick-read { color: #fff; }

/* Media inside the standard coloured bubble (captioned image/video, voice, document):
   strip the inner element's own chrome so it sits ON the bubble fill, not boxed inside. */
.msgr-bubble-media .msgr-voice-player,
.msgr-bubble-media .msgr-doc-bubble,
.msgr-bubble-media .msgr-doc-bubble:hover {
    background: transparent !important;
    border: none !important;
    padding: 0 !important;
}
/* Captioned image/video: the picture goes edge-to-edge (paddingless) - only the
   name above and caption/time below keep the bubble padding, exactly like Telegram.
   A fixed media width keeps the bubble from collapsing to the caption's width. */
.msgr-bubble-media:has(> .msgr-msg-media) { width: 300px; max-width: 100%; }
.msgr-bubble-media > .msgr-msg-media {
    margin: 0 -12px 6px;   /* break out of the bubble's side padding */
    width: auto;
    border-radius: 0;
}
.msgr-bubble-media > .msgr-msg-media:first-child {
    margin-top: -8px;       /* and the top padding, when the image is the first row */
    border-radius: 14px 14px 0 0;
}
/* A captioned video must break out edge-to-edge like a captioned image. The video
   sizing rule (.msgr-msg-media:has(> .msgr-msg-video)) carries max-width:100%, which
   clamps the width:auto breakout to the bubble's padding box (276px) - the -12px side
   margins then shift the box left but it can't grow, leaving a strip of bubble fill on
   the RIGHT. Lift the clamp here so width:auto fills the full 300px bubble, edge to edge. */
.msgr-bubble-media > .msgr-msg-media:has(> .msgr-msg-video) {
    max-width: none;
}
.msgr-bubble-media .msgr-msg-img {
    width: 100%;
    border-radius: 0;
    max-height: 360px;
    object-fit: cover;
    display: block;
}

/* Shimmer keyframe - the sheen layer glides across (the base gradient stays
   anchored), then holds off-screen for the tail of the cycle so the wait
   breathes (a calm pass-and-rest) instead of sweeping like a metronome.
   Used by the VIDEO placeholder (its load is brief, so one calm pass reads well). */
@keyframes msgrSkeletonDrift {
    0%   { background-position: 200% 0, 0 0; }
    65%  { background-position: -120% 0, 0 0; }
    100% { background-position: -120% 0, 0 0; }
}

/* Photo placeholder shimmer - a CONTINUOUS repeating sweep (no rest). A photo can sit
   loading for a while, so the black square keeps actively shimmering the whole time
   rather than passing once and pausing. */
@keyframes msgrPhotoShimmer {
    from { background-position: 200% 0; }
    to   { background-position: -200% 0; }
}

/* Honour OS-level reduce-motion preference - show the skeleton statically. */
@media (prefers-reduced-motion: reduce) {
    .msgr-msg-video:not([poster]),
    .msgr-msg-img.msgr-img-pending {
        animation: none;
    }
}
/* Custom voice bubble player (no native <audio> - eliminates iOS loading spinner) */
.msgr-voice-player {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 12px;
    border-radius: 20px;
    cursor: pointer;
    min-width: 180px;
    max-width: 240px;
    margin-bottom: 4px;
    user-select: none;
}
.msgr-msg-in  .msgr-voice-player { background: var(--color-surface); border: 1px solid var(--color-border); }
.msgr-msg-out .msgr-voice-player { background: var(--color-primary); }
.msgr-voice-play-btn {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.msgr-msg-in  .msgr-voice-play-btn { background: var(--color-primary); color: #fff; }
.msgr-msg-out .msgr-voice-play-btn { background: rgba(255,255,255,0.22); color: #fff; }
.msgr-voice-bar {
    flex: 1;
    height: 3px;
    border-radius: 2px;
    position: relative;
    overflow: hidden;
}
.msgr-msg-in  .msgr-voice-bar { background: var(--color-border); }
.msgr-msg-out .msgr-voice-bar { background: rgba(255,255,255,0.3); }
.msgr-voice-fill {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 0%;
    border-radius: 2px;
    transition: width 0.1s linear;
}
.msgr-msg-in  .msgr-voice-fill { background: var(--color-primary); }
.msgr-msg-out .msgr-voice-fill { background: rgba(255,255,255,0.9); }
.msgr-voice-dur {
    font-size: 11px;
    flex-shrink: 0;
    min-width: 34px;
    text-align: right;
}
.msgr-msg-in  .msgr-voice-dur { color: var(--color-text-light); }
.msgr-msg-out .msgr-voice-dur { color: rgba(255,255,255,0.85); }
.msgr-voice-player .vp-pause { display: none; }
.msgr-voice-player.playing .vp-play  { display: none; }
.msgr-voice-player.playing .vp-pause { display: block; }

/* ── Document attachment bubble ── */
.msgr-doc-bubble {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 10px;
    text-decoration: none;
    max-width: 260px;
    background: rgba(0,0,0,0.06);
    color: var(--color-text);
    transition: background 120ms;
}
.msgr-doc-bubble:visited { color: var(--color-text); }
.msgr-doc-bubble:hover { background: rgba(0,0,0,0.12); }
[data-theme="dark"] .msgr-doc-bubble { background: rgba(255,255,255,0.08); }
[data-theme="dark"] .msgr-doc-bubble:hover { background: rgba(255,255,255,0.14); }
.msgr-msg-out .msgr-doc-bubble,
.msgr-msg-out .msgr-doc-bubble:visited { background: rgba(255,255,255,0.18); color: #fff; }
.msgr-msg-out .msgr-doc-bubble:hover { background: rgba(255,255,255,0.28); }
.msgr-msg-out .msgr-doc-bubble svg { color: rgba(255,255,255,0.9); }
.msgr-doc-bubble svg { flex-shrink: 0; color: var(--color-primary); }
.msgr-doc-name {
    font-size: 0.8rem;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: inherit;
}

/* ── Expired media placeholder (90-day cleanup) ── */
.msgr-media-expired {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border-radius: 10px;
    background: rgba(0,0,0,0.04);
    border: 1px dashed rgba(0,0,0,0.18);
    font-size: 0.78rem;
    font-style: italic;
    color: var(--color-text-light);
    max-width: 320px;
    margin-bottom: 4px;
}
.msgr-media-expired svg { flex-shrink: 0; opacity: 0.7; }
.msgr-msg-out .msgr-media-expired {
    background: rgba(255,255,255,0.12);
    border-color: rgba(255,255,255,0.28);
    color: rgba(255,255,255,0.85);
}

/* ── Waveform bars ── */
.msgr-waveform {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 2px;
    height: 32px;
    padding: 0 4px;
    overflow: hidden;
}
.msgr-wv-bar {
    flex: 1;
    min-width: 2px;
    border-radius: 2px;
    transition: background 0.06s;
}
/* Sent (dark bg) */
.msgr-msg-out .msgr-wv-bar         { background: rgba(255,255,255,0.32); }
.msgr-msg-out .msgr-wv-bar.played  { background: rgba(255,255,255,0.92); }
/* Received (light bg) */
.msgr-msg-in  .msgr-wv-bar         { background: var(--color-border); }
.msgr-msg-in  .msgr-wv-bar.played  { background: var(--color-primary); }

/* System messages */
.msgr-msg-system {
    display: flex;
    justify-content: center;
    margin: 6px 0;
}
.msgr-msg-system span {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    font-style: italic;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    padding: 2px 14px;
    border-radius: 12px;
}

/* Date separator */
.msgr-date-sep {
    text-align: center;
    padding: 8px 0;
}
.msgr-date-sep span {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 2px 12px;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}

/* Highlight on search result click */
.msgr-msg-highlight {
    animation: msgrHighlight 2s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes msgrHighlight {
    0%, 30% { background: rgba(255,213,79,0.3); }
    100% { background: transparent; }
}

/* Typing indicator */
.msgr-typing {
    padding: 4px 16px;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    font-style: italic;
}

/* ── Compose Bar ── */

.msgr-compose {
    border-top: 1px solid var(--color-border);
    padding: 8px 12px;
    background: var(--color-surface);
    transition: border-color 150ms var(--ease-out), padding-bottom 0.25s var(--ease-keyboard);
}
.msgr-compose:focus-within {
    border-color: rgba(107,76,138,0.35);
}
.msgr-compose-dragover {
    background: rgba(107,76,138,0.06);
    border-top: 2px dashed var(--color-primary);
}
.msgr-compose-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.msgr-attach-btn {
    background: none;
    border: none;
    padding: 0;
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    color: var(--color-text-light);
    cursor: pointer;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 25px;
    transition: color 0.15s, transform 100ms var(--ease-out);
}
.msgr-attach-btn:hover  { color: var(--color-primary); }
.msgr-attach-btn:active { transform: scale(0.88); }
.msgr-voice-btn {
    background: none;
    border: none;
    padding: 0;
    width: 44px;
    height: 44px;
    color: var(--color-text-light);
    cursor: pointer;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-heading);
    transition: color 0.15s var(--ease-out), transform 120ms var(--ease-out), opacity 150ms var(--ease-out);
}
.msgr-voice-btn:hover  { color: var(--color-primary); }
.msgr-voice-btn:active { transform: scale(0.88); }
.msgr-action-slot {
    position: relative;
    width: 38px;
    height: 38px;
    flex-shrink: 0;
}
.msgr-action-slot > .msgr-voice-btn,
.msgr-action-slot > .msgr-send-btn {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    flex-shrink: unset;
}
.msgr-send-btn {
    border-radius: 50%;
    background: var(--color-primary);
    color: #fff;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--font-size-heading);
    transition: opacity 150ms var(--ease-out), transform 120ms var(--ease-out);
}
.msgr-send-btn:hover  { opacity: 0.85; }
.msgr-send-btn:active { transform: scale(0.9); }
.msgr-send-btn .fi { position: relative; top: 1px; left: -1px; }
.msgr-compose-input {
    flex: 1;
    border: none;
    border-radius: 8px;
    padding: 10px 10px 6px;
    font-size: var(--font-size-body);
    resize: none;
    max-height: 186px;
    min-height: 38px;
    background: var(--color-bg);
    color: var(--color-text);
    font-family: inherit;
    box-sizing: border-box;
}

/* Compose input + response star button live together in this wrapper
   so the star pins to the bottom-right of the text input area (inline-smiley
   placement). The wrapper carries the same background as the textarea so the
   star reads as "inside" the text field rather than alongside it — match the
   textarea in BOTH themes (the dark theme hardcodes the textarea bg, so we
   mirror that override here). */
.msgr-input-wrap {
    flex: 1;
    display: flex;
    align-items: flex-end;
    gap: 0;
    background: var(--color-bg);
    border-radius: 8px;
    min-width: 0;
    position: relative; /* anchor for the @mention typeahead dropdown */
}

/* @mention typeahead — floats above the composer (chat-app pattern) */
.msgr-mention-dropdown {
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(100% + 8px);
    max-height: 220px;
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18);
    z-index: 20;
    padding: 4px;
}
.msgr-mention-option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 8px;
    border-radius: 7px;
    cursor: pointer;
}
.msgr-mention-option.active {
    background: var(--color-bg);
}
.msgr-mention-option-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--color-primary);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.msgr-mention-option-name {
    font-size: var(--font-size-body);
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* @mention highlight inside a rendered bubble */
.msgr-mention {
    color: var(--color-primary);
    font-weight: 600;
}
.msgr-msg-out .msgr-mention {
    color: #fff;
    text-decoration: underline;
    text-underline-offset: 2px;
}
/* Staff-reply bubbles are right-aligned (.msgr-msg-out) but white — keep the
   accent colour, not the white-on-coloured treatment. */
.msgr-msg-staff-reply .msgr-mention {
    color: var(--color-primary);
    text-decoration: none;
}
/* Messenger Settings modal — notification preferences */
/* Each top-level settings category is a titled group. Siblings (future
   categories) are delineated by a top divider + spacing. */
.msgr-settings-group + .msgr-settings-group {
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--color-border);
}
.msgr-settings-group-title {
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--color-text);
    margin: 0 0 12px;
}
.msgr-settings-section { display: flex; flex-direction: column; }
.msgr-notif-row {
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border);
    width: 100%;
}
.msgr-notif-row:last-of-type { border-bottom: none; }
.msgr-notif-icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--color-primary) 12%, transparent);
    color: var(--color-primary);
    font-size: 17px;
}
.msgr-notif-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    line-height: 1.3;
}
.msgr-settings-foot { margin: 12px 0 0; line-height: 1.4; }
.msgr-settings-sub { margin: 0 0 8px; line-height: 1.4; }
/* Notification popups (per-conversation + per-folder) — reuse .msgr-ctx-menu +
   .msgr-notif-row. Only the toggle-popup width + small headers are new. */
.msgr-ctx-menu-notif { width: 300px; min-width: 264px; }
.msgr-ctx-menu-notif .msgr-notif-row { padding: 9px 8px; }
.msgr-ctx-menu-notif .msgr-notif-icon { width: 32px; height: 32px; font-size: 15px; }
.msgr-notif-menu-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px 8px;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: 2px;
    font-weight: 600;
    color: var(--color-text);
}
.msgr-notif-menu-head i { color: var(--color-primary); flex-shrink: 0; }
.msgr-notif-menu-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msgr-notif-menu-subhead {
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--color-text-light);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 4px 8px 2px;
}
.msgr-notif-usedefault {
    display: block;
    margin-top: 4px;
    padding: 8px;
    font-size: var(--font-size-small);
    color: var(--color-primary);
    font-weight: 600;
    cursor: pointer;
    border-top: 1px solid var(--color-border);
}
.msgr-notif-usedefault:hover { text-decoration: underline; }
/* Pinned-message bar — sits below the thread header, jumps to the pinned
   message on tap. Accent left border (chat-app convention). */
.msgr-pinned-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    background: var(--color-surface, #fff);
    border-bottom: 1px solid var(--color-border);
    border-left: 3px solid var(--color-primary);
    cursor: pointer;
    flex-shrink: 0;
    transition: background 0.15s;
}
.msgr-pinned-bar:hover { background: color-mix(in srgb, var(--color-primary) 6%, transparent); }
.msgr-pinned-icon {
    color: var(--color-primary);
    font-size: 15px;
    flex-shrink: 0;
    transform: rotate(45deg);
}
.msgr-pinned-info {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.3;
}
.msgr-pinned-label {
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--color-primary);
}
.msgr-pinned-count { color: var(--color-text-light); font-weight: 500; }
.msgr-pinned-text {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* "@" badge: conversation has an unread message that @mentions
   me. Accent (not danger red) so it reads distinctly from the unread count. */
.msgr-mention-badge {
    background: var(--color-primary);
    color: #fff;
    font-size: var(--font-size-small);
    font-weight: 700;
    min-width: 18px;
    height: 18px;
    border-radius: 9px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 5px 1px;
    flex-shrink: 0;
    margin-left: 4px;
}
[data-theme="dark"] .msgr-input-wrap {
    background: rgb(37, 48, 48);
}
.msgr-input-wrap > .msgr-compose-input {
    background: transparent;
    flex: 1;
    padding-right: 6px;
}
[data-theme="dark"] .msgr-input-wrap > .msgr-compose-input {
    background: transparent;
}
.msgr-response-btn {
    background: none;
    border: none;
    padding: 0;
    width: 36px;
    height: 38px;
    flex-shrink: 0;
    color: var(--color-text-light);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    transition: color 0.15s var(--ease-out), transform 120ms var(--ease-out);
}
.msgr-response-btn:hover  { color: var(--color-warning, #e0a000); }
.msgr-response-btn:active { transform: scale(0.88); }

/* ============================================================
   Responses — picker modal (messenger compose)
   ============================================================ */
.response-picker-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 60vh;
    overflow-y: auto;
}
.response-picker-item {
    display: flex;
    flex-direction: column;
    gap: 4px;
    text-align: left;
    background: var(--color-bg-subtle, rgba(0,0,0,0.03));
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 10px 12px;
    cursor: pointer;
    transition: background 0.12s var(--ease-out), border-color 0.12s var(--ease-out), transform 100ms var(--ease-out);
    width: 100%;
}
.response-picker-item:hover  { background: var(--color-bg); border-color: var(--color-primary); }
.response-picker-item:active { transform: scale(0.99); }
.response-picker-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    font-weight: 600;
    font-size: var(--font-size-body);
    color: var(--color-text);
}
.response-picker-preview {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    line-height: 1.4;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.response-att-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 500;
    color: var(--color-text-light);
    background: var(--color-bg);
    border-radius: 999px;
    padding: 2px 8px;
}
.response-att-badge .fi { font-size: 11px; }

/* ============================================================
   Responses — admin list (Messenger Management section)
   ============================================================ */
.response-admin-row {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 12px 0;
    border-bottom: 1px solid var(--color-border-subtle, rgba(0,0,0,0.06));
}
.response-admin-row:last-child { border-bottom: none; }
.response-admin-row-main { flex: 1; min-width: 0; }
.response-admin-row-reorder {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
    padding-top: 2px;
}
.response-reorder-btn {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--color-text-light);
    width: 22px;
    height: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font-size: 12px;
    line-height: 1;
    transition: color 0.12s var(--ease-out);
}
.response-reorder-btn:hover:not(:disabled) { color: var(--color-primary); }
.response-reorder-btn:active:not(:disabled) {
    transform: scale(0.78);
    transition: transform 80ms var(--ease-out);
}
.response-reorder-btn:disabled { opacity: 0.25; cursor: default; }

/* Brief highlight pulse on the row the user just moved — paired with the
   FLIP slide animation in moveResponse(). 700ms total. */
@keyframes responseRowMovedPulse {
    0%   { background: rgba(76, 175, 145, 0); }
    25%  { background: rgba(76, 175, 145, 0.18); }
    100% { background: rgba(76, 175, 145, 0); }
}
.response-row-moved {
    animation: responseRowMovedPulse 700ms ease-out;
    border-radius: 8px;
}
.response-admin-row-title {
    font-weight: 600;
    font-size: var(--font-size-body);
    color: var(--color-text);
    margin-bottom: 2px;
}
.response-admin-row-preview {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    line-height: 1.4;
    margin-bottom: 4px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.response-admin-row-actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}

/* ============================================================
   Responses — auto-response cards (sub-sub-tab "Auto Response")
   ============================================================ */
.response-auto-card {
    background: var(--color-bg-subtle, rgba(0,0,0,0.03));
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 14px 16px;
    margin-bottom: 12px;
}
.response-auto-card:last-child { margin-bottom: 0; }
.response-auto-card-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 8px;
}
.response-auto-card-title {
    font-weight: 600;
    font-size: var(--font-size-body);
    color: var(--color-text);
    margin-bottom: 4px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.response-auto-card-rule {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    line-height: 1.45;
    display: block;
}
.response-auto-card-rule .fi {
    color: var(--color-primary);
    margin-right: 6px;
    vertical-align: -1px;
}
.response-auto-card-rule strong {
    color: var(--color-text);
}
.response-auto-card-body {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    line-height: 1.45;
    padding-top: 8px;
    border-top: 1px dashed var(--color-border-subtle, rgba(0,0,0,0.06));
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.response-auto-badge {
    display: inline-flex;
    align-items: center;
    font-size: var(--font-size-small);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 2px 8px;
    border-radius: 999px;
}
.response-auto-badge--on  { background: var(--color-success-bg); color: var(--color-success); }
.response-auto-badge--off { background: var(--color-bg-subtle); color: var(--color-text-light); }

/* Firing-rule banner inside the editor modal — shown only when editing an auto row. */
.response-editor-rule-banner {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 14px;
    margin-bottom: 14px;
    background: var(--color-success-bg);
    border: 1px solid var(--color-success);
    border-radius: 8px;
    font-size: var(--font-size-small);
    color: var(--color-text);
    line-height: 1.45;
}
.response-editor-rule-banner .fi {
    flex-shrink: 0;
    margin-top: 3px;
    color: var(--color-primary);
}

/* ============================================================
   Responses — editor modal
   ============================================================ */
.response-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 6px;
}
.response-placeholder-chip {
    background: var(--color-bg-subtle, rgba(0,0,0,0.04));
    border: 1px solid var(--color-border);
    border-radius: 999px;
    padding: 3px 10px;
    font-size: var(--font-size-small);
    font-family: var(--font-mono, monospace);
    color: var(--color-text);
    cursor: pointer;
    transition: background 0.12s var(--ease-out), border-color 0.12s var(--ease-out);
}
.response-placeholder-chip:hover {
    background: var(--color-bg);
    border-color: var(--color-primary);
    color: var(--color-primary);
}
.response-editor-preview {
    background: var(--color-bg-subtle, rgba(0,0,0,0.03));
    border: 1px dashed var(--color-border);
    border-radius: 8px;
    padding: 10px 12px;
    min-height: 56px;
    font-size: var(--font-size-body);
    color: var(--color-text);
    white-space: pre-wrap;
    line-height: 1.5;
}
#responseEditorBody {
    font-family: inherit;
    font-size: var(--font-size-body);
    line-height: 1.5;
}
.response-att-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-bg-subtle, rgba(0,0,0,0.02));
}
.response-att-meta { flex: 1; min-width: 0; }
.response-att-name {
    font-size: var(--font-size-body);
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Reply preview */
.msgr-reply-preview {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    margin-bottom: 6px;
    background: rgba(0,0,0,0.04);
    border-left: 3px solid var(--color-primary);
    border-radius: 4px;
    font-size: var(--font-size-label);
}
.msgr-reply-text { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--color-text-light); }
.msgr-reply-close { background: none; border: none; cursor: pointer; font-size: var(--font-size-body); color: var(--color-text-light); padding: 0 4px; }

/* Media preview */
.msgr-media-preview {
    display: flex;
    gap: 8px;
    padding: 6px 0;
    flex-wrap: wrap;
    /* Containing block for the FLIP lift in _msgrAnimateThumbRemoval — the
       exiting thumb goes position:absolute and is offset within this row. */
    position: relative;
}
.msgr-media-thumb {
    position: relative;
    width: 64px;
    height: 64px;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--color-border);
}
.msgr-media-thumb img,
.msgr-media-thumb video { width: 100%; height: 100%; object-fit: cover; }
.msgr-media-thumb.msgr-media-file {
    width: auto;
    height: auto;
    padding: 6px 8px;
    font-size: var(--font-size-small);
    display: flex;
    align-items: center;
    gap: 4px;
}
.msgr-media-hint {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    align-self: center;
    margin-left: auto;
    white-space: nowrap;
    flex-shrink: 0;
}
.msgr-media-remove {
    position: absolute;
    top: 4px;
    right: 4px;
    background: rgba(0,0,0,0.55);
    color: #fff;
    border: 1.5px solid rgba(255,255,255,0.9);
    border-radius: 50%;
    width: 22px;
    height: 22px;
    font-size: 13px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    line-height: 1;
    box-shadow: 0 1px 4px rgba(0,0,0,0.35);
    transition: background 0.15s ease, transform 0.15s ease;
}
.msgr-media-remove:hover { background: rgba(0,0,0,0.82); transform: scale(1.08); }
.msgr-media-remove:active { transform: scale(0.94); }

/* Document/video chip remove button - flows inline at right, not a corner badge */
.msgr-media-remove-inline {
    position: static;
    top: auto;
    right: auto;
    width: 20px;
    height: 20px;
    font-size: 11px;
    background: rgba(0,0,0,0.15);
    border: none;
    box-shadow: none;
    flex-shrink: 0;
}
.dark .msgr-media-remove-inline,
[data-theme="dark"] .msgr-media-remove-inline {
    background: rgba(255,255,255,0.15);
}

/* Edit inline */
.msgr-msg-editing {
    max-width: 100%;
    width: 100%;
}
.msgr-msg-editing .msgr-msg-bubble {
    background: var(--color-bg) !important;
    color: var(--color-text) !important;
    border: 1px solid var(--color-border);
}
.msgr-edit-input {
    width: 100%;
    padding: 6px 8px;
    border: 1px solid var(--color-primary);
    border-radius: 6px;
    font-size: var(--font-size-body);
    line-height: 1.5;
    color: var(--color-text);
    background: var(--color-bg);
    resize: none;
    height: auto;
    max-height: calc(10 * 1.5em + 12px);
    overflow-y: auto;
    font-family: inherit;
    box-sizing: border-box;
}
.msgr-edit-input:focus { outline: none; }
.msgr-edit-actions {
    display: flex;
    gap: 6px;
    margin-top: 3px;
    justify-content: flex-end;
}

/* Tab dot */
.msgr-tab-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ef4444;
    animation: livePulse 1.5s ease-in-out infinite;
    margin-left: 4px;
    vertical-align: middle;
}

/* ── Search Results ── */

.msgr-search-results { overflow-y: auto; flex: 1; }
.msgr-search-result {
    padding: 10px 14px;
    cursor: pointer;
    border-bottom: 1px solid var(--color-border);
    transition: background 0.15s;
}
.msgr-search-result:hover { background: var(--color-surface-hover, rgba(0,0,0,0.03)); }
.msgr-search-result-header { display: flex; justify-content: space-between; gap: 6px; }
.msgr-search-result-sender { font-weight: 600; font-size: var(--font-size-label); }
.msgr-search-result-time { font-size: var(--font-size-small); color: var(--color-text-light); }
.msgr-search-result-text { font-size: var(--font-size-label); color: var(--color-text); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.msgr-search-result-conv { font-size: var(--font-size-small); color: var(--color-text-light); margin-top: 2px; }

/* ── Modals: member picker, DM picker ── */

.msgr-member-picker, .msgr-dm-picker {
    max-height: 200px;
    overflow-y: auto;
    margin-top: 8px;
}
.msgr-member-pick-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    cursor: pointer;
    font-size: var(--font-size-body);
    border-bottom: 1px solid var(--color-border);
}
.msgr-member-pick-item:last-child { border-bottom: none; }
.msgr-member-pick-item:hover { background: var(--color-surface-hover, rgba(0,0,0,0.03)); }
.msgr-member-pick-item input[type="checkbox"] { flex-shrink: 0; }
.msgr-member-role { font-size: var(--font-size-small); color: var(--color-text-light); margin-left: auto; }
.msgr-member-role--admin { color: var(--color-primary); }

.msgr-dm-pick-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px;
    cursor: pointer;
    font-size: var(--font-size-body);
    border-bottom: 1px solid var(--color-border);
}
.msgr-dm-pick-item:last-child { border-bottom: none; }
.msgr-dm-pick-item:hover { background: var(--color-surface-hover, rgba(0,0,0,0.03)); }

.msgr-selected-members {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    min-height: 28px;
}
.msgr-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: var(--color-primary);
    color: #fff;
    padding: 4px 10px;
    border-radius: 12px;
    font-size: var(--font-size-label);
    font-weight: 500;
    cursor: pointer;
    user-select: none;
}
.msgr-chip-x {
    color: rgba(255,255,255,0.65);
    font-size: 14px;
    line-height: 1;
}

/* ── New Message modal animations ── */

/* FB1 - Choice button press feel */
.msgr-new-choice-btn {
    transition: background 0.15s var(--ease-out), border-color 0.15s var(--ease-out), transform 0.1s var(--ease-out);
}
.msgr-new-choice-btn:active { transform: scale(0.97); }

/* FB2 - DM / member list item press feel */
.msgr-dm-pick-item,
.msgr-member-pick-item {
    transition: background 0.1s var(--ease-out), transform 0.1s var(--ease-out);
}
.msgr-dm-pick-item:active,
.msgr-member-pick-item:active { transform: scale(0.99); }

/* FB3 - Row flash on checkbox check */
@keyframes msgrRowCheck {
    0%   { background: color-mix(in srgb, var(--color-primary) 14%, transparent); }
    100% { background: transparent; }
}
.msgr-row-checked { animation: msgrRowCheck 350ms var(--ease-out) forwards; }

/* SC1 - Chip enters with spring */
@keyframes msgrChipEnter {
    0%   { transform: scale(0); opacity: 0; }
    60%  { transform: scale(1.1); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}
.msgr-chip-enter { animation: msgrChipEnter 220ms var(--ease-spring) forwards; }

/* SC2 - Chip exits */
@keyframes msgrChipExit {
    to { transform: scale(0); opacity: 0; }
}
.msgr-chip-exit {
    animation: msgrChipExit 150ms var(--ease-out) forwards;
    pointer-events: none;
}

/* SC3 - Selected members section rises in */
#msgrSelectedSection {
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
    pointer-events: none;
    margin-bottom: 12px;
}
#msgrSelectedSection.msgr-chips-visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

/* ── Messenger micro-animations (Disney pass) ── */

/* MA1 - Message bubble entrance - direction-aware spring pop */
@keyframes msgrMsgIn {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: translateY(0); }
}
/* MA4 - Image materialises inside bubble 60ms after the shell arrives */
@keyframes msgrImgReveal {
    from { opacity: 0; }
    to   { opacity: 1; }
}
/* Outgoing: bubble rises from bottom-right (where you typed) */
.msgr-msg-out.msgr-msg-enter {
    animation: msgrMsgIn 300ms var(--ease-spring) both;
    transform-origin: bottom right;
}
/* Incoming: bubble rises from bottom-left (the other person's side) */
.msgr-msg-in.msgr-msg-enter {
    animation: msgrMsgIn 300ms var(--ease-spring) both;
    transform-origin: bottom left;
}
/* System messages: simple centre fade */
.msgr-msg-system.msgr-msg-enter {
    animation: msgrMsgIn 180ms var(--ease-out) both;
    transform-origin: center bottom;
}
/* Image inside a new bubble materialises 60ms after the shell.
   Skip pending placeholders (they own their shimmer) AND images mid reveal
   (.msgr-img-reveal) - in both cases the `animation` shorthand here would
   otherwise clobber the placeholder's / reveal's own choreography. */
.msgr-msg-enter .msgr-msg-img:not(.msgr-img-pending):not(.msgr-img-reveal) {
    animation: msgrImgReveal 200ms var(--ease-out) 60ms both;
}

/* Optimistic / sending state - dimmed until confirmed by DB */
.msgr-msg-sending { opacity: 0.55; }

/* MA-Upload - real-progress overlay (dark scrim + circular ring + live %) painted
   on the sending image. Driven by actual XHR upload-progress bytes (see
   _msgrUploadWithProgress), so the number is definitive — the sender watches the
   full file climb to 100% and can long-press → Delete a send that's crawling. */
.msgr-msg-sending .msgr-msg-media {
    border-radius: 10px; /* clip overlay corners to match image */
}
.msgr-upload-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: rgba(0, 0, 0, 0.34);
    z-index: 3;
    pointer-events: none;
    transition: opacity 240ms ease-out;
}
.msgr-upload-overlay-done { opacity: 0; }
.msgr-upload-ring {
    width: 46px;
    height: 46px;
    transform: rotate(-90deg); /* start the arc at 12 o'clock */
}
.msgr-upload-ring-track { fill: none; stroke: rgba(255, 255, 255, 0.32); stroke-width: 4; }
.msgr-upload-ring-fill {
    fill: none;
    stroke: #fff;
    stroke-width: 4;
    stroke-linecap: round;
    transition: stroke-dashoffset 200ms ease-out;
}
.msgr-upload-pct {
    color: #fff;
    font-size: var(--font-size-small);
    font-weight: 700;
    letter-spacing: 0.2px;
    font-variant-numeric: tabular-nums;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}

/* MA-Sent - spring pop on media wrapper when upload confirms delivery */
@keyframes msgrMediaSentPop {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.025); }
    100% { transform: scale(1); }
}
.msgr-media-sent {
    animation: msgrMediaSentPop 380ms var(--ease-spring) forwards;
}

/* MA2 - Message delete: anticipation "gather" then dissolve into dust.
   GPU-only (transform + opacity) - the old filter:blur implosion was the jank
   source (filter repaints every frame, fights the 150 animating motes). */
@keyframes msgrMsgDisintegrate {
    0%   { opacity: 1; transform: scale(1)    translateY(0);    }
    22%  { opacity: 1; transform: scale(1.05) translateY(0);    }  /* gather / inhale */
    100% { opacity: 0; transform: scale(0.94) translateY(-8px); }  /* lift + fade with the dust */
}
.msgr-msg-exit { animation: msgrMsgDisintegrate 380ms var(--ease-out) forwards; pointer-events: none; }

/* MA2-collapse - once the bubble is dust, glide the now-empty row closed so the
   messages below slide up to fill the gap instead of snapping. A single-row
   layout transition is acceptable for a one-shot delete and far less jarring. */
.msgr-msg-collapse {
    transition: height 260ms var(--ease-out),
                margin 260ms var(--ease-out),
                padding 260ms var(--ease-out);
}

/* MA2-particle - motes lift off the bubble, rise + drift outward on a faint
   wind, then thin out and fade (Thanos ash). Per-mote delay + duration are set
   inline so the cloud disperses unevenly instead of all snapping at once. */
@keyframes msgrParticleFly {
    0%   { opacity: 1; transform: translate(0, 0) scale(1) rotate(0deg); }
    30%  { opacity: 1; }
    50%  { transform: translate(var(--pmx), var(--pmy)) scale(0.7) rotate(calc(var(--pr) * 0.4)); }
    100% { opacity: 0; transform: translate(var(--px), var(--py)) scale(0.12) rotate(var(--pr)); }
}
.msgr-particle {
    position: fixed;
    pointer-events: none;
    z-index: 9999;
    border-radius: 1px;
    will-change: transform, opacity;
    animation: msgrParticleFly 460ms var(--ease-out) both;
}

/* MA3 - Conversation / search item stagger entrance */
@keyframes msgrConvIn {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}
.msgr-conv-enter, .motion-list-enter { animation: msgrConvIn 200ms var(--ease-out) both; } /* .motion-list-enter = orion_motion 'list-stagger' */
.msgr-search-enter { animation: msgrConvIn 200ms var(--ease-out) both; }

/* MA4 - Reply preview bar slide in / out */
@keyframes msgrReplyIn {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes msgrReplyOut {
    from { opacity: 1; transform: translateY(0); }
    to   { opacity: 0; transform: translateY(6px); }
}
.msgr-reply-enter { animation: msgrReplyIn 180ms var(--ease-out) both; }
.msgr-reply-exit  { animation: msgrReplyOut 150ms var(--ease-out) forwards; pointer-events: none; }

/* MA5 - Typing indicator fade */
@keyframes msgrTypingIn {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}
.msgr-typing-enter { animation: msgrTypingIn 200ms var(--ease-out) both; }

/* MA7 - Read receipt tick pulse on change */
@keyframes msgrTickPulse {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.3); }
    100% { transform: scale(1); }
}
.msgr-tick-pulse, .motion-tick-pulse { display: inline-block; animation: msgrTickPulse 300ms var(--ease-spring); } /* .motion-tick-pulse = orion_motion 'tick-pulse' */

/* MA8 - Unread badge spring pop-in */
@keyframes msgrBadgeIn {
    0%   { transform: scale(0); opacity: 0; }
    60%  { transform: scale(1.15); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}
.msgr-badge-enter { animation: msgrBadgeIn 250ms var(--ease-spring) both; }

/* MA10 - Send button pop when content entered */
@keyframes msgrSendPop {
    0%   { transform: scale(0.85); }
    60%  { transform: scale(1.08); }
    100% { transform: scale(1); }
}
.msgr-send-pop { animation: msgrSendPop 200ms var(--ease-spring); }

/* MA11 - Media preview thumbnail entrance */
@keyframes msgrThumbIn {
    from { opacity: 0; transform: scale(0.9); }
    to   { opacity: 1; transform: scale(1); }
}
.msgr-thumb-enter { animation: msgrThumbIn 180ms var(--ease-out) both; }

/* MA11 - thumbnail exit (removal): the removed thumb shrinks + fades while its
   surviving siblings glide over to close the gap (FLIP in
   _msgrAnimateThumbRemoval). */
@keyframes msgrThumbOut {
    from { opacity: 1; transform: scale(1); }
    to   { opacity: 0; transform: scale(0.8); }
}
.msgr-thumb-exit { animation: msgrThumbOut 160ms var(--ease-out) both; }

/* MA9 — Mobile thread slide-in / slide-out
   Restored in v2.96 after L163 identified the real cause of the "two taps after
   swipe-back" bug (iOS WebKit click suppression, fixed via touchend delegation
   in admin-messenger.js — nothing animation-related). The animations were
   guilty by association during the long debug.

   Slide-out deliberately has NO `forwards` fill — at animation end, transform
   reverts to translateX(0) naturally, which lands in the same paint frame as
   onDone's conv-open removal (→ display:none). No flicker, no compositor layer
   cached at translateX(100%). */
@keyframes msgrThreadSlideIn {
    from { transform: translateX(100%); }
    to   { transform: translateX(0); }
}
@keyframes msgrThreadSlideOut {
    from { transform: translateX(0); }
    to   { transform: translateX(100%); }
}
/* Timing matches Telegram iOS exactly: its navigation push (open a chat) and pop
   (swipe/back) both run 0.5s with kCAMediaTimingFunctionSpring: a genuine spring,
   not a cubic ease. We reproduce that spring with a linear() easing sampled from a
   damped-spring simulation (~1.5% overshoot, the gently-damped iOS settle), and fall
   back to an iOS-style cubic-bezier on engines without linear() support. Both
   directions share one duration and one curve, exactly as Telegram does. */
/* The generic motion-swipe-* aliases (orion_motion 'swipe-spring' primitive)
   share this one declaration + linear() curve, so the spring is written once.
   Existing messenger JS keeps adding .msgr-thread-*; new uses add .motion-swipe-*. */
.msgr-thread-enter, .motion-swipe-enter { animation: msgrThreadSlideIn 500ms cubic-bezier(0.32, 0.72, 0, 1) both; }
.msgr-thread-exit,  .motion-swipe-exit  { animation: msgrThreadSlideOut 500ms cubic-bezier(0.32, 0.72, 0, 1); }
/* Whole-page slide-out when leaving messenger back to the main app (swipe-right on
   the conv list, or tapping ← Main Dashboard). Same spring as the conv-thread exit,
   but with animation-fill-mode:forwards so the page stays at translateX(100%) while
   the next page loads — no snap-back, no flash. JS removes the class on pageshow as
   a bfcache safety. */
.msgr-page-leave { animation: msgrThreadSlideOut 500ms cubic-bezier(0.32, 0.72, 0, 1) forwards; will-change: transform; }
@supports (animation-timing-function: linear(0, 1)) {
    .msgr-thread-enter, .motion-swipe-enter,
    .msgr-thread-exit,  .motion-swipe-exit,
    .msgr-page-leave { animation-timing-function: linear(0, 0.072, 0.228, 0.407, 0.574, 0.714, 0.822, 0.899, 0.951, 0.984, 1.003, 1.012, 1.015, 1.015, 1.013, 1.010, 1.007, 1.005, 1.003, 1.002, 1); }
}

/* ── End Messenger micro-animations ── */

/* ============================================================
   MOTION LIBRARY  (orion_motion canonical primitives)
   SoT registry: js/animations.js (ANIMATION_REGISTRY).
   Human index:   docs/animation-library.md.
   Parity guard:  /orion_audit_visual Cat 9g (keyframes <-> registry).
   Reduced motion is handled by the global @media block (search
   "prefers-reduced-motion") + the JS helper early-return; do NOT add a
   redundant block here.
   Wire these via playAnimation() / staggerAnimation() in js/animations.js;
   never set the inline `animation` shorthand (it would beat the @supports
   linear() upgrade on .motion-swipe-*).
   Reused primitives (swipe-spring, list-stagger, tick-pulse) live with their
   messenger declarations above via shared selector groups, NOT duplicated here.
   Add a primitive: new @keyframes + .motion-* class below (animate only
   transform/opacity/filter), a --dur-* token in :root if a new tier is needed,
   an ANIMATION_REGISTRY entry, one docs line, then run the Cat 9g parity check.
   ============================================================ */

/* panel-fade - view / tab swap. Add the class synchronously after inserting
   content; both-fill hides it from frame 0 so there is no flash-then-fade. */
@keyframes motionPanelFade {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.motion-panel-enter { animation: motionPanelFade var(--motion-dur, var(--dur-transition)) var(--ease-out) both; }

/* card-enter - staggered card lift-in (via staggerAnimation) */
@keyframes motionCardEnter {
    from { opacity: 0; transform: translateY(12px) scale(0.99); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
.motion-card-enter { animation: motionCardEnter var(--motion-dur, var(--dur-enter)) var(--ease-out) both; }

/* react-pop - emoji reaction / badge pop: up then settle back to rest */
@keyframes motionReactPop {
    0%   { opacity: 0; transform: scale(0); }
    60%  { opacity: 1; transform: scale(1.25); }
    100% { opacity: 1; transform: scale(1); }
}
.motion-react-pop { animation: motionReactPop var(--motion-dur, var(--dur-feedback)) var(--ease-spring); }

/* value-bump - a displayed number / total just changed */
@keyframes motionValueBump {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.2); }
    100% { transform: scale(1); }
}
.motion-value-bump { display: inline-block; animation: motionValueBump var(--motion-dur, var(--dur-feedback)) var(--ease-spring); }

/* success-pop - rare celebratory confirm (use sparingly, never loop) */
@keyframes motionSuccessPop {
    0%   { opacity: 0; transform: scale(0.6); }
    60%  { opacity: 1; transform: scale(1.12); }
    100% { opacity: 1; transform: scale(1); }
}
.motion-success-pop { animation: motionSuccessPop var(--motion-dur, var(--dur-celebrate)) var(--ease-spring); }

/* press-give - CSS-only tactile press (no JS); add .motion-press to a control */
.motion-press { transition: transform var(--dur-micro) var(--ease-out); }
.motion-press:active { transform: scale(0.97); }

/* fly-to - parameterized launch -> land flight. The consumer positions the
   element at its DESTINATION (left/top, no own transform) and sets --fly-dx /
   --fly-dy (origin minus destination, px) + optional --fly-scale (launch
   scale). Generic: add-to-cart fly, reaction emoji -> pill, etc. */
@keyframes motionFlyTo {
    0%   { opacity: 1; transform: translate(var(--fly-dx, 0px), var(--fly-dy, 0px)) scale(var(--fly-scale, 1.5)); }
    100% { opacity: 1; transform: translate(0, 0) scale(1); }
}
.motion-fly-to { animation: motionFlyTo var(--motion-dur, var(--dur-transition)) var(--ease-out) both; }

/* expand-origin - shared-element FLIP: an element grows out of a source rect to
   fill the screen (lightbox open) and shrinks back into it on close, the way iOS
   expands a photo / video to fullscreen. Parameterized: the consumer measures the
   origin + final rects at runtime and sets --flip-dx / --flip-dy (origin centre
   minus final centre, px) + --flip-scale (cover-scale = max(originW/finalW,
   originH/finalH)). Reference driver: image-crop.js openLightbox/closeLightbox,
   which drives the SAME motion with an inline transition (it must read two live
   rects per direction + hand back to zoom/pan) rather than this class. */
@keyframes motionExpandOrigin {
    from { transform: translate(var(--flip-dx, 0px), var(--flip-dy, 0px)) scale(var(--flip-scale, 0.4)); }
    to   { transform: translate(0, 0) scale(1); }
}
.motion-expand-origin { animation: motionExpandOrigin var(--motion-dur, var(--dur-transition)) var(--ease-out) both; }

/* burst - celebratory particle. The consumer spawns N short-lived fixed nodes
   at a centre point and sets per-node --burst-dx / --burst-dy / --burst-rot.
   Like .msgr-particle (delete crumble) but radiating + celebratory. Restraint:
   gate at high frequency, keep subtle, never loop. */
@keyframes motionBurst {
    0%   { opacity: 1; transform: translate(-50%, -50%) scale(0.3); }
    100% { opacity: 0; transform: translate(calc(-50% + var(--burst-dx, 0px)), calc(-50% + var(--burst-dy, 0px))) scale(1) rotate(var(--burst-rot, 0deg)); }
}
.motion-burst {
    position: fixed;
    z-index: 9998;
    width: 7px;
    height: 7px;
    border-radius: 2px;
    pointer-events: none;
    will-change: transform, opacity;
    animation: motionBurst var(--motion-dur, var(--dur-celebrate)) var(--ease-out) both;
}
/* ── End Motion Library ── */

.msgr-section-heading {
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--color-text);
    margin: 0 0 8px;
}
.msgr-vis-hint {
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    margin-top: 6px;
    margin-bottom: 0;
}
.msgr-my-note-wrapper {
    margin-top: 12px;
}
.msgr-member-list { }
.msgr-member-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    min-height: 52px;
    font-size: var(--font-size-body);
}
.msgr-member-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    color: #fff;
    flex-shrink: 0;
    letter-spacing: 0.02em;
}
.msgr-member-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.msgr-role-chip {
    font-size: 11px;
    font-weight: 600;
    padding: 3px 9px;
    border-radius: 20px;
    white-space: nowrap;
    flex-shrink: 0;
}
.msgr-role-chip--admin  { background: rgba(107,76,138,0.12); color: var(--color-primary); }
.msgr-role-chip--staff  { background: rgba(0,0,0,0.07); color: var(--color-text-light); }
.msgr-role-chip--vendor { background: rgba(180,100,20,0.1); color: #a05a10; }
[data-theme="dark"] .msgr-role-chip--staff  { background: rgba(255,255,255,0.1); }
[data-theme="dark"] .msgr-role-chip--vendor { color: #e0924a; background: rgba(180,100,20,0.2); }
.msgr-role-chip--bot { background: rgba(0,130,120,0.1); color: #0a8078; }
[data-theme="dark"] .msgr-role-chip--bot { background: rgba(0,180,160,0.15); color: #2ecfc3; }
.msgr-danger-zone {
    border-top: 1px solid var(--color-border);
    padding-top: 16px;
    margin-top: 24px;
}
.msgr-modal-section-label--danger { color: var(--color-danger) !important; }
.msgr-remove-btn {
    background: none;
    border: none;
    padding: 0;
    width: 44px;
    height: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--color-text-light);
    border-radius: 6px;
    transition: color 0.15s, background 0.15s;
    flex-shrink: 0;
    font-size: 16px;
    align-self: stretch;
}
.msgr-remove-btn:hover {
    color: var(--color-danger);
    background: rgba(var(--color-error-rgb, 180, 50, 50), 0.08);
}

/* ── Mobile Responsive ── */

@media (hover: none) {
    .msgr-group-photo-wrap .msgr-group-photo-overlay { opacity: 1; }
}

@media (max-width: 600px) {
    .msgr-root { flex-direction: column; min-height: 0; max-height: none; }
    /* Hide the desktop column on mobile; show the inline strip instead */
    #msgrSourceNav { display: none !important; }
    .msgr-source-nav-strip {
        display: flex;
        flex-direction: row;
        width: 100%;
        min-width: 0;
        height: 48px;
        min-height: 48px;
        border-right: none;
        border-bottom: 1px solid var(--color-border);
        padding: 6px 10px;
        gap: 6px;
        overflow-x: auto;
        overflow-y: hidden;
        scrollbar-width: none;
        -ms-overflow-style: none;
        -webkit-overflow-scrolling: touch;
        align-items: center;
    }
    .msgr-source-nav-strip::-webkit-scrollbar { display: none; }
    .msgr-source-nav-strip .msgr-source-nav-item {
        flex-direction: row;
        flex-shrink: 0;
        width: auto;
        padding: 5px 12px;
        border-radius: 20px;
        gap: 5px;
        border: 1px solid var(--color-border);
    }
    .msgr-source-nav-strip .msgr-source-nav-item::before { display: none; }
    .msgr-source-nav-strip .msgr-source-nav-item.is-active {
        background: var(--item-color, var(--color-primary));
        color: #fff;
        border-color: transparent;
    }
    .msgr-source-nav-strip .msgr-source-nav-icon { font-size: 14px; }
    .msgr-source-nav-strip .msgr-source-nav-label { font-size: 13px; }
    .msgr-sidebar { width: 100%; min-width: 0; border-right: none; border-bottom: 1px solid var(--color-border); max-height: none; min-height: 200px; }
    .msgr-thread { display: none; width: 100%; min-height: 0; }
    .msgr-root.conv-open .msgr-sidebar { display: none; }
    .msgr-root.conv-open .msgr-thread { display: flex; position: fixed; top: 0; left: 0; right: 0; height: 100%; max-height: none; z-index: 960; background: var(--color-surface); overflow-x: hidden; transition: height 0.25s var(--ease-keyboard), top 0.25s var(--ease-keyboard); }
    /* The fixed thread above positions against the viewport, escaping the
       body's env(safe-area-inset-top) padding — so the header would sit under
       the status bar / notch. Inset the header itself below it. env() is 0 on
       non-notched devices (desktop/web), so this is a no-op there. View As is
       left untouched (the thread is already offset 44px for its banner). */
    body:not(.view-as-active) .msgr-root.conv-open .msgr-thread-header {
        padding-top: calc(env(safe-area-inset-top) + 10px);
    }
    /* contentInset:"always" builds: the OS already insets the webview below the
       notch, so env() would double it — keep the plain 10px there. */
    html.cap-inset-always body:not(.view-as-active) .msgr-root.conv-open .msgr-thread-header {
        padding-top: 10px;
    }
    .msgr-back-btn { display: inline-flex; }
    .msgr-msg { max-width: 85%; }
    body.view-as-active .msgr-root.conv-open .msgr-thread { top: 44px; height: calc(100% - 44px); }
    /* Lift the compose row clear of the home indicator AND the phone's curved bottom
       corners (which were clipping the attach/mic icons). The fixed thread escapes the
       body's env(safe-area-inset-bottom) padding, so pad the compose itself. env()
       collapses to 0 while the keyboard is up, so this only pads at rest. */
    .msgr-root.conv-open .msgr-compose {
        padding-bottom: calc(env(safe-area-inset-bottom) + 12.6px);
    }
    /* contentInset:"always" builds already inset the webview above the home indicator,
       so env() would double it — keep just the generous extra. */
    html.cap-inset-always .msgr-root.conv-open .msgr-compose {
        padding-bottom: 12.6px;
    }
}

/* ── Messenger Dark Mode ── */
[data-theme="dark"] .msgr-conv-item.active {
    background: rgba(255,255,255,0.06);
}
[data-theme="dark"] .msgr-compose-input {
    background: #253030;
    color: var(--color-text);
}
.msgr-compose-input:focus {
    outline: none;
}
[data-theme="dark"] .msgr-compose-input:focus {
    outline: none;
}
[data-theme="dark"] .msgr-search-input {
    background: #1a1e1e;
    border-color: #4a5555;
    color: var(--color-text);
}
[data-theme="dark"] .msgr-reply-preview {
    background: rgba(141, 205, 196, 0.08);
}
[data-theme="dark"] .msgr-edit-input {
    background: #1a1e1e;
    border-color: #4a5555;
    color: var(--color-text);
}

/* ============================================================
   Message Sending Progress Overlay
   ============================================================ */
#msgSendingOverlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 9999;
    background: rgba(15, 10, 25, 0.55);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    align-items: center;
    justify-content: center;
}
#msgSendingOverlay.active {
    display: flex;
    animation: sendingOverlayIn 0.25s ease;
}
@keyframes sendingOverlayIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
#msgSendingCard {
    background: var(--color-card);
    border-radius: 28px;
    padding: 44px 52px 40px;
    width: 320px;
    text-align: center;
    box-shadow: 0 32px 80px rgba(74, 51, 96, 0.22), 0 4px 16px rgba(0,0,0,0.12);
    animation: sendingCardIn 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes sendingCardIn {
    from { opacity: 0; transform: scale(0.86) translateY(16px); }
    to   { opacity: 1; transform: scale(1) translateY(0); }
}
.sending-plane {
    color: var(--color-primary);
    margin-bottom: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    animation: sendingFloat 2.4s ease-in-out infinite;
}
@keyframes sendingFloat {
    0%, 100% { transform: translateY(0) rotate(-8deg); }
    50%       { transform: translateY(-7px) rotate(2deg); }
}
.sending-eyebrow {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-text-light);
    margin-bottom: 20px;
}
.sending-bar-track {
    height: 6px;
    background: var(--color-border);
    border-radius: 99px;
    overflow: hidden;
    margin-bottom: 28px;
}
.sending-bar-fill {
    height: 100%;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--color-primary-dark), var(--color-primary-light));
    width: 0%;
    transition: width 0.45s cubic-bezier(0.4, 0, 0.2, 1);
    position: relative;
    overflow: hidden;
}
.sending-bar-fill::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.45) 50%, transparent 100%);
    animation: sendingShimmer 1.6s ease-in-out infinite;
}
@keyframes sendingShimmer {
    from { transform: translateX(-200%); }
    to   { transform: translateX(200%); }
}
.sending-count-row {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 6px;
    margin-bottom: 4px;
}
.sending-count-done {
    font-size: 52px;
    font-weight: 700;
    line-height: 1;
    color: var(--color-primary-dark);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    transition: transform 0.15s ease;
}
.sending-count-done.bump {
    transform: scale(1.12);
}
.sending-count-sep {
    font-size: 24px;
    font-weight: 400;
    color: var(--color-border);
    line-height: 1;
}
.sending-count-total {
    font-size: 24px;
    font-weight: 600;
    color: var(--color-text-light);
    line-height: 1;
    font-variant-numeric: tabular-nums;
}
.sending-sublabel {
    font-size: 0.75rem;
    color: var(--color-text-light);
    font-weight: 500;
}
.sending-name-ticker {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--color-primary);
    height: 1.3em;
    overflow: hidden;
    text-align: center;
    margin-bottom: 20px;
    opacity: 0;
}
.sending-name-ticker.flash {
    animation: sendingNameFlash 0.55s ease forwards;
}
@keyframes sendingNameFlash {
    0%   { opacity: 0; transform: translateY(5px); }
    25%  { opacity: 1; transform: translateY(0); }
    65%  { opacity: 1; transform: translateY(0); }
    100% { opacity: 0; transform: translateY(-5px); }
}
.sending-action-btn {
    margin-top: 20px;
    padding: 9px 36px;
    border-radius: 99px;
    border: 1.5px solid var(--color-border);
    background: transparent;
    color: var(--color-text-light);
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
}
.sending-action-btn:hover {
    background: var(--color-bg);
    color: var(--color-text);
}
.sending-action-btn:active {
    transform: scale(0.96);
}
.sending-action-btn.done-btn {
    background: var(--color-primary);
    color: #fff;
    border-color: var(--color-primary);
}
.sending-action-btn.done-btn:hover {
    background: var(--color-primary-dark);
    border-color: var(--color-primary-dark);
    color: #fff;
}
#msgSendingOverlay.done .sending-bar-fill {
    background: linear-gradient(90deg, var(--color-success), #2ecc71);
}
#msgSendingOverlay.done .sending-count-done {
    color: var(--color-success);
}

/* ============================================================
   Messenger Context Menu + Reactions
   ============================================================ */

@keyframes msgrCtxIn {
    from { opacity: 0; transform: scale(0.92) translateY(-4px); }
    to   { opacity: 1; transform: scale(1) translateY(0); }
}

.msgr-ctx-menu {
    position: fixed;
    z-index: 1100;
    min-width: 200px;
    max-width: calc(100vw - 24px);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: 0 10px 28px rgba(0,0,0,0.18);
    padding: 6px;
    animation: msgrCtxIn 120ms var(--ease-out);
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

.msgr-ctx-emoji-row {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 4px 4px 6px;
    border-bottom: 1px solid var(--color-border);
    margin-bottom: 4px;
    overflow-x: auto;
}
.msgr-ctx-emoji-btn {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border: none;
    background: transparent;
    border-radius: 50%;
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: background 120ms var(--ease-out), transform 120ms var(--ease-out);
}
.msgr-ctx-emoji-btn:hover { background: var(--color-bg); transform: scale(1.15); }
.msgr-ctx-emoji-btn.is-mine { background: var(--color-primary-soft); }
.msgr-ctx-emoji-more { font-size: 14px; color: var(--color-text-light); }

.msgr-ctx-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-radius: 8px;
    cursor: pointer;
    font-size: var(--font-size-body);
    color: var(--color-text);
    user-select: none;
}
.msgr-ctx-item:hover { background: var(--color-bg); }
.msgr-ctx-item i { width: 16px; text-align: center; color: var(--color-text-light); }
.msgr-ctx-item.is-danger { color: var(--color-danger); }
.msgr-ctx-item.is-danger i { color: var(--color-danger); }
.msgr-ctx-item.is-disabled { opacity: 0.45; cursor: default; pointer-events: none; }
.msgr-ctx-item.is-disabled:hover { background: transparent; }

/* Context menu info rows (reactions count + seen-by) */
.msgr-ctx-divider {
    height: 1px;
    background: var(--color-border);
    margin: 4px 6px;
}
.msgr-ctx-info-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 12px;
    border-radius: 8px;
    cursor: pointer;
    font-size: var(--font-size-body);
    color: var(--color-text-light);
    user-select: none;
}
.msgr-ctx-info-row:hover { background: var(--color-bg); }
.msgr-ctx-info-row i { width: 16px; text-align: center; font-size: 13px; flex: 0 0 16px; }
.msgr-ctx-info-label { flex: 1; }
.msgr-ctx-avatar-stack {
    display: flex;
    align-items: center;
    flex-direction: row-reverse;
}
.msgr-ctx-mini-avatar {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    object-fit: cover;
    border: 1.5px solid var(--color-surface);
    margin-left: -6px;
    flex: 0 0 20px;
    font-size: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-bg);
    color: var(--color-text-light);
}
.msgr-ctx-avatar-stack .msgr-ctx-mini-avatar:last-child { margin-left: 0; }
.msgr-ctx-mini-fallback { background: var(--color-primary-soft); color: var(--color-primary); font-weight: 600; }
.msgr-ctx-mini-overflow { background: var(--color-bg); color: var(--color-text-light); }

/* Reactions pills under a bubble */
.msgr-reactions {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 4px;
    justify-content: flex-start; /* reactions always sit on the LEFT, even on own messages (Telegram) */
}
.msgr-reactions:empty { display: none; }

/* Borderless pills (Telegram-style). A subtle fill gives contrast against the
   chat background and the incoming bubble; outgoing coloured bubbles get a
   translucent-white pill instead (below). */
/* Reaction-pill system — borderless, with ONE consistent idea across all 4 states:
   a reaction someone ELSE made recedes (quiet neutral tint); a reaction I made
   stands out via the background's natural accent direction. Never a glaring white
   block, and the count is legible in every state + theme. */
.msgr-reaction-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 12px;
    background: rgba(0,0,0,0.07);   /* not-mine on a light surface: quiet, recedes */
    border: none;
    font-size: var(--font-size-small);
    cursor: pointer;
    line-height: 1.4;
    user-select: none;
    -webkit-user-select: none;
    transition: transform 100ms var(--ease-out);
}
.msgr-reaction-pill:hover { transform: scale(1.05); }
.msgr-reaction-pill.is-mine {
    background: var(--color-primary-soft);   /* mine on a light surface: teal accent */
}
.msgr-reaction-pill .msgr-reaction-pill-emoji { font-size: 14px; }
.msgr-reaction-pill .msgr-reaction-pill-count { color: var(--color-text-light); font-weight: 500; }
.msgr-reaction-pill.is-mine .msgr-reaction-pill-count { color: var(--color-primary); }
/* On the dark-teal outgoing fill a white pill glares, so others' reactions recede
   into a soft DARK tint while MY reaction reads as a light frost - distinct, calm. */
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-reaction-pill {
    background: rgba(0,0,0,0.18);
}
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-reaction-pill .msgr-reaction-pill-count {
    color: rgba(255,255,255,0.72);
}
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-reaction-pill.is-mine {
    background: rgba(255,255,255,0.26);
}
.msgr-msg-out:not(.msgr-msg-staff-reply) .msgr-msg-bubble .msgr-reaction-pill.is-mine .msgr-reaction-pill-count {
    color: #fff;
}

/* Flying emoji clone (reaction-commit choreography). Outer holds the fixed
   destination + centring; the inner glyph carries the fly-to primitive so its
   animated transform never fights the centring transform. */
.msgr-reaction-fly {
    position: fixed;
    z-index: 9999;
    transform: translate(-50%, -50%);
    pointer-events: none;
}
.msgr-reaction-fly-glyph {
    font-size: 22px;
    line-height: 1;
    will-change: transform, opacity;
}

/* Who-reacted popover */
.msgr-who-reacted {
    position: fixed;
    z-index: 1200;
    min-width: 220px;
    max-width: calc(100vw - 24px);
    max-height: 50vh;
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: 0 10px 28px rgba(0,0,0,0.18);
    padding: 6px;
    animation: msgrCtxIn 120ms var(--ease-out);
    user-select: none;
    -webkit-user-select: none;
}
.msgr-who-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 8px;
}
.msgr-who-row:hover { background: var(--color-bg); }
.msgr-who-avatar {
    width: 28px; height: 28px;
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 28px;
    background: var(--color-bg);
}
.msgr-who-name {
    flex: 1;
    font-size: var(--font-size-body);
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.msgr-who-time {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.msgr-who-emoji { font-size: 16px; }

/* Full emoji picker */
.msgr-emoji-picker {
    position: fixed;
    z-index: 1150;
    width: 320px;
    max-width: calc(100vw - 24px);
    max-height: 320px;
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: 0 10px 28px rgba(0,0,0,0.18);
    padding: 8px;
    animation: msgrCtxIn 120ms var(--ease-out);
}
.msgr-emoji-cell {
    border: none;
    background: transparent;
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
    padding: 4px;
    border-radius: 6px;
    transition: background 100ms var(--ease-out);
}
.msgr-emoji-cell:hover { background: var(--color-bg); }

[data-theme="dark"] .msgr-ctx-menu,
[data-theme="dark"] .msgr-emoji-picker,
[data-theme="dark"] .msgr-who-reacted,
[data-theme="dark"] #msgrSeenBy {
    background: #1a1e1e;
    border-color: #4a5555;
}
[data-theme="dark"] .msgr-ctx-item:hover,
[data-theme="dark"] .msgr-ctx-emoji-btn:hover,
[data-theme="dark"] .msgr-emoji-cell:hover,
[data-theme="dark"] .msgr-who-row:hover {
    background: #2a3232;
}
[data-theme="dark"] .msgr-reaction-pill {
    background: rgba(255,255,255,0.10);
}
[data-theme="dark"] .msgr-reaction-pill.is-mine {
    background: var(--color-primary-soft);
}
/* In dark mode --color-primary is pinned to the (dark) brand teal by org branding,
   which would be illegible on the dark teal-tint is-mine pill. Use the light text
   token for the count instead; the teal-tint fill still carries the "mine" signal. */
[data-theme="dark"] .msgr-reaction-pill.is-mine .msgr-reaction-pill-count {
    color: var(--color-text);
}

/* ============================================================ */
/* STAFF SCHEDULE                                               */
/* ============================================================ */

.ss-section-title {
    font-size: var(--font-size-body);
    font-weight: 600;
    margin: 0 0 12px;
    color: var(--color-text);
}
.ss-card-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.shift-card {
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 16px;
}
.shift-card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}
.shift-card-title {
    font-weight: 600;
    font-size: var(--font-size-body);
}
.shift-card-meta {
    color: var(--color-text-light);
    font-size: var(--font-size-small);
    margin-top: 2px;
}
.shift-card-body {
    margin-top: 10px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.shift-card-foot {
    margin-top: 10px;
    display: flex;
    justify-content: flex-end;
}
.shift-time-pill {
    display: inline-block;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    border-radius: 999px;
    padding: 3px 10px;
    font-size: var(--font-size-small);
    font-variant-numeric: tabular-nums;
}
[data-theme="dark"] .shift-time-pill {
    background: #2a3232;
}
.shift-capacity-bar {
    height: 4px;
    background: var(--color-border);
    border-radius: 999px;
    overflow: hidden;
    margin-top: 6px;
}
.shift-capacity-bar > span {
    display: block;
    height: 100%;
    background: var(--color-primary);
}

/* Apply modal radio rows + date chips */
.ss-radio-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.ss-radio-row:hover { border-color: var(--color-primary); }
.ss-radio-row.ss-disabled { opacity: 0.5; cursor: not-allowed; }
.ss-radio-label {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
}
.ss-shift-radio-list { display: flex; flex-direction: column; gap: 0; }
.ss-date-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 8px;
}
.ss-date-chip {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    cursor: pointer;
    font-size: 13px;
    transition: border-color 0.15s, background 0.15s;
}
.ss-date-chip:hover { border-color: var(--color-primary); }
.ss-date-chip input[type="checkbox"] { margin: 0; }
.ss-date-chip.ss-disabled { opacity: 0.45; cursor: not-allowed; }
.ss-date-cap { margin-left: auto; }

/* Manager - filter row + groups */
.ss-filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
}
.ss-chip-group { display: flex; gap: 6px; flex-wrap: wrap; }
.ss-chip {
    background: transparent;
    border: 1px solid var(--color-border);
    color: var(--color-text);
    padding: 6px 12px;
    border-radius: 999px;
    font-size: 13px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.ss-chip:hover { border-color: var(--color-primary); }
.ss-chip--active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}
[data-theme="dark"] .ss-chip--active { color: #1a2222; }
.ss-filter-select {
    padding: 6px 10px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-card);
    color: var(--color-text);
    font-size: 13px;
}

.ss-group { margin-bottom: 18px; }
.ss-group-head {
    font-weight: 600;
    margin: 0 0 8px;
    color: var(--color-text);
}
.ss-group-body { display: flex; flex-direction: column; gap: 8px; }

.shift-application-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    background: var(--color-card);
}
.ss-row-main { flex: 1; min-width: 0; }
.ss-row-name { font-weight: 600; font-size: var(--font-size-body); }
.ss-row-meta { color: var(--color-text-light); font-size: var(--font-size-small); margin-top: 2px; }
.ss-row-actions { display: flex; gap: 6px; }
.ss-avatar {
    width: 36px; height: 36px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}
.ss-avatar--initials {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--color-border);
    color: var(--color-text);
    font-weight: 600;
    font-size: var(--font-size-body);
}

/* Manager - schedules pane */
.ss-sched-head { display: flex; justify-content: flex-end; margin-bottom: 12px; }
.ss-sched-list { display: flex; flex-direction: column; gap: 8px; }
.ss-sched-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    background: var(--color-card);
}
.ss-sched-main { flex: 1; min-width: 0; }
.ss-sched-title { font-weight: 600; font-size: var(--font-size-body); }
.ss-sched-meta { color: var(--color-text-light); font-size: var(--font-size-small); margin-top: 2px; }

/* Schedule modal - shift row builder */
.ss-shifts-builder { display: flex; flex-direction: column; gap: 8px; }
.ss-shift-row {
    display: grid;
    grid-template-columns: 1.4fr 1fr 12px 1fr 80px 36px;
    align-items: center;
    gap: 8px;
}
.ss-shift-dash { text-align: center; color: var(--color-text-light); }
.ss-shift-row input { padding: 8px 10px; }

/* ============================================================
   Shift model v2 - cards, calendar, drawer, swap chips
   ============================================================ */

/* Shift card */
.ss-shift-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 14px 16px;
    transition: border-color 0.15s cubic-bezier(0.22, 1, 0.36, 1), transform 0.05s cubic-bezier(0.22, 1, 0.36, 1);
}
.ss-shift-card[onclick] { cursor: pointer; }
.ss-shift-card[onclick]:hover { border-color: var(--color-primary); }
.ss-shift-card[onclick]:active { transform: scale(0.997); }
.ss-shift-card-head {
    display: flex; align-items: center; gap: 8px; margin-bottom: 4px;
}
.ss-shift-title { font-weight: 600; font-size: var(--font-size-body); color: var(--color-text); }
.ss-shift-card-past { opacity: 0.7; }

.ss-meta { font-size: var(--font-size-small); color: var(--color-text-light); margin-top: 2px; }
.ss-meta-row { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.ss-meta-mode {
    font-size: var(--font-size-small); text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--color-text-light);
}

.ss-badge {
    display: inline-block;
    background: var(--color-surface-alt);
    color: var(--color-text-light);
    font-size: var(--font-size-small); font-weight: 500;
    padding: 3px 8px 2px; border-radius: 10px;
    margin-left: 6px;
}
.ss-badge-muted { background: var(--color-surface-alt); color: var(--color-text-light); }

/* Calendar grid */
.ss-cal-nav {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 0; margin-bottom: 8px;
}
.ss-cal-nav-title { font-weight: 600; font-size: var(--font-size-body); flex: 1; text-align: center; }
.ss-cal-add-btn { margin-left: auto; }

.ss-cal-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 4px;
}
.ss-cal-head {
    display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
    font-size: var(--font-size-small); text-transform: uppercase;
    color: var(--color-text-light); text-align: center;
    padding: 6px 0; letter-spacing: 0.04em;
}
.ss-cal-cell {
    min-height: 64px;
    min-width: 0;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 6px;
    background: var(--color-surface);
    font-size: var(--font-size-small);
    display: flex; flex-direction: column;
    cursor: default;
}
.ss-cal-cell-empty { border: none; background: transparent; }
.ss-cal-cell-date { font-weight: 600; font-size: var(--font-size-small); color: var(--color-text-light); margin-bottom: 4px; }
.ss-cal-chip {
    display: block;
    padding: 3px 6px;
    border-radius: 6px;
    background: var(--color-primary-soft);
    color: var(--color-text);
    font-size: var(--font-size-small);
    margin-top: 2px;
    cursor: pointer;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ss-cal-chip:hover { filter: brightness(0.95); }
.ss-cal-chip-vacant { background: var(--color-surface-alt); color: var(--color-text-light); }
.ss-cal-chip-swapped { outline: 1px dashed var(--color-warning, #d69e2e); }

/* Pool chips (manager modal) */
.ss-pool-chip {
    display: inline-flex; align-items: center; gap: 6px;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    padding: 4px 10px 4px 8px;
    font-size: var(--font-size-small);
    margin: 0 6px 6px 0;
}
.ss-pool-num {
    background: var(--color-primary); color: var(--color-bg);
    width: 18px; height: 18px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 10px; font-weight: 600;
}
.ss-pool-remove {
    background: transparent; border: none; cursor: pointer;
    color: var(--color-text-light); font-size: var(--font-size-body); padding: 0;
    line-height: 1;
}
.ss-pool-remove:hover { color: var(--color-error); }

/* Day-of-week picker */
.ss-dow-btn {
    min-width: 44px; height: 40px;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    border-radius: 8px;
    font-size: var(--font-size-small); font-weight: 500;
    cursor: pointer;
    color: var(--color-text);
}
.ss-dow-btn.ss-dow-btn-active {
    background: var(--color-primary); color: var(--color-bg);
    border-color: var(--color-primary);
}

/* Swap chip (staff shift card) */
.ss-swap-chip {
    margin-top: 10px;
    padding: 8px 12px;
    border-radius: 8px;
    font-size: var(--font-size-small);
    cursor: pointer;
    display: flex; align-items: center; gap: 8px;
}
.ss-swap-chip-incoming {
    background: var(--color-error-bg, #fdecea);
    color: var(--color-error, #c53030);
}
[data-theme="dark"] .ss-swap-chip-incoming { background: #3a1a1a; color: #ff8a8a; }
.ss-swap-chip-outgoing {
    background: var(--color-surface-alt);
    color: var(--color-text-light);
}
.ss-swap-chip-response {
    background: var(--color-warning-bg, #fff7e6);
    color: var(--color-warning, #b8860b);
}
[data-theme="dark"] .ss-swap-chip-response { background: #3a2d0f; color: #ffd27a; }

/* Occurrence drawer actions */
.ss-drawer-actions { display: flex; flex-direction: column; gap: 8px; }
.ss-drawer-actions .btn { min-height: 44px; justify-content: center; }

/* Picker rows (assignee / pool / swap target) */
.ss-picker-row {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 10px 12px;
    border-radius: 8px;
    border: 1px solid var(--color-border);
    cursor: pointer;
    margin-bottom: 6px;
    background: var(--color-surface);
}
.ss-picker-row .btn { width: auto; flex-shrink: 0; }
.ss-picker-row:hover { border-color: var(--color-primary); }
.ss-picker-row-selected { border-color: var(--color-primary); background: var(--color-primary-light, #e6f0ff); }

/* Bids section */
.ss-bids-section { margin-top: 20px; }
.ss-bid-row {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-bottom: 6px;
    background: var(--color-surface);
}
.ss-bid-row-main { flex: 1; min-width: 0; }
.ss-bid-row-actions { display: flex; gap: 6px; }

.ss-detail-row { padding: 6px 0; font-size: var(--font-size-body); color: var(--color-text); display: flex; gap: 8px; }
.ss-detail-row .text-label { flex-shrink: 0; color: var(--color-text-light); }

/* Saturday shift cards (v3) */
.ss-card {
    position: relative;
    background: var(--color-card);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    transition: border-color 0.15s cubic-bezier(0.22, 1, 0.36, 1), transform 0.05s cubic-bezier(0.22, 1, 0.36, 1);
}
.ss-card-row1 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
}
.ss-card-info {
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.ss-card-date {
    font-weight: 700;
    font-size: var(--font-size-body);
    color: var(--color-text);
}
.ss-card-time,
.ss-card-name {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.ss-card-action { position: relative; }
.ss-card-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-danger, #e53935);
    margin-left: 6px;
    vertical-align: middle;
}
.ss-card-past { opacity: 0.7; }
/* Dot to the RIGHT of date text (new-assignment indicator) */
.ss-dot-right {
    margin-left: 5px;
    margin-right: 0;
    vertical-align: middle;
    flex-shrink: 0;
}
/* Dot to the LEFT of the Review button (outside the button) */
.ss-dot-left {
    margin-left: 0;
    margin-right: 0;
    vertical-align: middle;
    flex-shrink: 0;
}
/* Wrapper that places the pulse dot to the left of the Review button */
.ss-review-wrap {
    display: flex;
    align-items: center;
    gap: 5px;
}
.ss-swap-note {
    margin: 0;
    font-size: var(--font-size-body);
    color: var(--color-text);
    white-space: pre-wrap;
}
.ss-outcome-header {
    text-align: center;
    padding: 8px 0 20px;
}
.ss-outcome-actions {
    margin-top: 20px;
    text-align: center;
}
.ss-swap-response-status {
    display: inline-block;
    padding: 10px 28px;
    border-radius: 20px;
    font-weight: 700;
    font-size: 1.1rem;
}
.ss-status-accepted {
    background: rgba(30, 107, 61, 0.12);
    color: var(--color-success);
}
.ss-status-rejected {
    background: rgba(192, 57, 43, 0.1);
    color: var(--color-error);
}
[data-theme="dark"] .ss-status-accepted {
    background: rgba(46, 158, 94, 0.2);
    color: var(--color-success);
}
[data-theme="dark"] .ss-status-rejected {
    background: rgba(192, 57, 43, 0.2);
    color: var(--color-error);
}
.ss-pending-wrap {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
}
.ss-card-btns {
    display: flex;
    flex-direction: column;
    gap: 6px;
    align-items: stretch;
    flex-shrink: 0;
}
.ss-input-locked,
.flatpickr-input.ss-input-locked {
    opacity: 0.45 !important;
    cursor: not-allowed !important;
    pointer-events: none !important;
}
.ss-past-toggle-btn {
    background: transparent;
    border: none;
    color: var(--color-text-light);
    font-size: var(--font-size-small);
    cursor: pointer;
    padding: 6px 0;
}
.ss-past-toggle-btn:hover { color: var(--color-text); }
.ss-you { color: var(--color-primary); font-weight: 500; }
.ss-empty { text-align: center; padding: 24px 0; }

.ss-rotation-list {
    display: flex; flex-wrap: wrap; gap: 6px;
    min-height: 32px; margin-bottom: 8px;
}
.ss-rotation-chip {
    display: inline-flex; align-items: center; gap: 6px;
    background: var(--color-bg); border: 1px solid var(--color-border);
    border-radius: 999px; padding: 4px 8px 4px 6px; font-size: var(--font-size-small);
}
.ss-rotation-idx {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; height: 18px; border-radius: 50%;
    background: var(--color-primary); color: var(--color-bg); font-size: 11px; font-weight: 600;
}
.ss-rotation-remove {
    background: none; border: none; cursor: pointer; color: var(--color-text-light);
    font-size: var(--font-size-body); line-height: 1; padding: 0 0 0 2px;
}
.ss-rotation-remove:hover { color: var(--color-danger, #c00); }

.ss-swap-preview {
    background: var(--color-surface);
    border-radius: 10px;
    padding: 10px 12px;
    font-size: var(--font-size-small);
    color: var(--color-text);
}
.ss-offer-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}
.ss-offer-item { transition: border-color 0.15s cubic-bezier(0.22, 1, 0.36, 1), background 0.15s cubic-bezier(0.22, 1, 0.36, 1); }
.ss-offer-item:hover { border-color: var(--color-primary); }
.ss-offer-item-disabled { opacity: 0.5; cursor: not-allowed; }
.ss-offer-item-body { flex: 1; }

/* ── Batch Family Chats modal ── */
#msgrBatchSelectedStaffSection { margin-bottom: 12px; }
.msgr-batch-dup-warning {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--color-warning-bg);
    color: var(--color-warning);
    border-radius: 8px;
    padding: 8px 12px;
    font-size: var(--font-size-small);
    font-weight: 500;
    margin-bottom: 8px;
}
.msgr-batch-preview-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;
}
.msgr-batch-select-all-label {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 5px;
    font-weight: normal;
}
.msgr-batch-preview {
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 6px;
    background: var(--color-surface);
}
.msgr-batch-row {
    display: grid;
    grid-template-columns: 24px 1fr auto;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 8px;
    transition: background 0.15s;
}
.msgr-batch-row:hover { background: var(--color-surface-alt); }
.msgr-batch-row.duplicate { background: var(--color-warning-bg); }
.msgr-batch-row.duplicate .msgr-batch-name-input { color: var(--color-text-muted, #777); }
.msgr-batch-row.error { background: rgba(192, 57, 43, 0.08); }
.msgr-batch-row.created { opacity: 0.7; }
.msgr-batch-name-input {
    border: 1px solid transparent;
    background: transparent;
    padding: 4px 6px;
    font-size: var(--font-size-body);
    border-radius: 6px;
    min-width: 0;
}
.msgr-batch-name-input:focus {
    outline: none;
    border-color: var(--color-border);
    background: var(--color-surface);
}
.msgr-batch-summary {
    font-size: var(--font-size-label);
    color: var(--color-text-muted, #777);
    white-space: nowrap;
}
.msgr-batch-row .badge { white-space: nowrap; }
.msgr-batch-choice-btn .fi { color: var(--color-primary); }
[data-theme="dark"] .msgr-batch-row.duplicate .msgr-batch-name-input:focus { background: transparent; }
#messengerBatchModal .modal { max-height: 85vh; overflow-y: auto; }
#messengerBatchModal .msgr-member-picker { max-height: none; overflow-y: unset; }
.msgr-batch-staff-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    background: none;
    border: 1px dashed var(--color-border);
    border-radius: 8px;
    padding: 9px 12px;
    color: var(--color-text-light);
    font-size: var(--font-size-body);
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
    text-align: left;
}
.msgr-batch-staff-toggle:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
}
.msgr-batch-staff-toggle.has-staff {
    border-style: solid;
    border-color: var(--color-primary);
    color: var(--color-primary);
}
.msgr-batch-staff-picker-body { margin-top: 8px; }

/* ── Messenger Broadcast ───────────────────────────────────── */
.msgr-broadcast-choice-btn .fi { color: var(--color-primary); }

/* ── Messenger New WhatsApp ────────────────────────────────── */
.msgr-whatsapp-choice-btn .fi { color: var(--color-primary); }
.msgr-new-wa-fail-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 8px 12px;
    padding: 8px 12px;
    border-radius: 8px;
    background: color-mix(in srgb, #DC2626 12%, var(--color-bg));
    color: var(--color-text);
    font-size: var(--font-size-small);
    border: 1px solid color-mix(in srgb, #DC2626 40%, transparent);
}
.msgr-new-wa-fail-banner .fi { color: #DC2626; flex-shrink: 0; }


.msgr-bc-recipient-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    background: var(--color-surface-alt);
    border-radius: 8px;
    margin-top: 4px;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--color-text);
}
.msgr-bc-exclude-toggle {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 0.8rem;
    color: var(--color-primary);
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 2px 6px;
    border-radius: 4px;
    white-space: nowrap;
}
.msgr-bc-exclude-toggle:hover { background: var(--color-hover); }
.msgr-bc-exclude-toggle .fi { transition: transform 0.2s; font-size: 0.75rem; }

.msgr-bc-exclude-list {
    max-height: 220px;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-top: 4px;
}
.msgr-bc-exclude-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.875rem;
}
.msgr-bc-exclude-row:last-child { border-bottom: none; }
.msgr-bc-exclude-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--color-text);
}

.msgr-bc-progress {
    position: absolute;
    inset: 0;
    background: rgba(var(--color-surface-rgb, 255,255,255), 0.85);
    border-radius: inherit;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
}
.msgr-bc-progress-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    font-size: 0.9rem;
    color: var(--color-text-muted, #777);
    font-weight: 500;
}
.msgr-bc-spinner {
    width: 32px;
    height: 32px;
    border: 3px solid var(--color-border);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

/* Messenger Broadcast - full-screen sending overlay (mirrors #msgSendingOverlay) */
#msgrBcSendingOverlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 19999;
    background: rgba(15, 10, 25, 0.55);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    align-items: center;
    justify-content: center;
}
#msgrBcSendingOverlay.active {
    display: flex;
    animation: sendingOverlayIn 0.25s ease;
}
#msgrBcSendingCard {
    background: var(--color-card);
    border-radius: 28px;
    padding: 44px 52px 40px;
    width: 320px;
    text-align: center;
    box-shadow: 0 32px 80px rgba(74, 51, 96, 0.22), 0 4px 16px rgba(0,0,0,0.12);
    animation: sendingCardIn 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Plane → checkmark crossfade swap (Tier B4) */
#msgrBcSendingCard .sending-plane {
    position: relative;
    width: 56px;
    height: 56px;
    margin: 0 auto 18px;
    transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1);
}
#msgrBcSendingCard .sending-plane-icon,
#msgrBcSendingCard .sending-check-icon {
    position: absolute;
    inset: 0;
    transition: opacity 220ms ease;
}
#msgrBcSendingCard .sending-check-icon {
    color: var(--color-success);
    opacity: 0;
    transform: scale(0.8);
    transition: opacity 220ms ease, transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
#msgrBcSendingOverlay.done .sending-plane-icon { opacity: 0; }
#msgrBcSendingOverlay.done .sending-check-icon { opacity: 1; transform: scale(1); }
#msgrBcSendingOverlay.done .sending-plane { animation: none; }

/* Plane "throw" cue when an RPC fires (Tier B2) */
#msgrBcSendingCard .sending-plane.throwing {
    transform: translateX(4px) rotate(6deg);
}

/* Predictive bar fill - 1s linear matches the inter-tick cadence so the
   bar appears to flow continuously rather than snapping in 1s steps (Tier A1) */
#msgrBcSendingCard .sending-bar-fill {
    transition: width 1000ms linear, background 240ms ease;
}
#msgrBcSendingOverlay.done .sending-bar-fill {
    background: linear-gradient(90deg, var(--color-success), #2ecc71);
    transition: width 320ms cubic-bezier(0.4, 0, 0.2, 1), background 240ms ease;
}

/* Bar leading-edge spark (Tier B3) */
.sending-bar-spark {
    position: absolute;
    right: -2px;
    top: 50%;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: rgba(255,255,255,0.95);
    box-shadow: 0 0 8px 2px rgba(255,255,255,0.55);
    transform: translateY(-50%);
    animation: sendingSparkPulse 1.1s ease-in-out infinite;
    pointer-events: none;
}
@keyframes sendingSparkPulse {
    0%, 100% { transform: translateY(-50%) scale(0.7); opacity: 0.55; }
    50%      { transform: translateY(-50%) scale(1.1); opacity: 1; }
}
#msgrBcSendingOverlay.done .sending-bar-spark { opacity: 0; animation: none; }

/* Persistent crossfade name ticker (Tier A2) */
#msgrBcSendingCard .sending-name-ticker {
    position: relative;
    overflow: hidden;
    height: 1.3em;
    margin-bottom: 20px;
    animation: none;            /* override the legacy .flash keyframe */
    opacity: 1;
}
#msgrBcSendingCard .sending-name-slot {
    position: absolute;
    inset: 0;
    text-align: center;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--color-primary);
    transition: opacity 220ms ease, transform 220ms cubic-bezier(0.4, 0, 0.2, 1);
    will-change: transform, opacity;
}
#msgrBcSendingCard .sending-name-current {
    opacity: 1;
    transform: translateY(0);
}
#msgrBcSendingCard .sending-name-incoming {
    opacity: 0;
    transform: translateY(8px);
}
#msgrBcSendingCard .sending-name-ticker.swapping .sending-name-current {
    opacity: 0;
    transform: translateY(-8px);
}
#msgrBcSendingCard .sending-name-ticker.swapping .sending-name-incoming {
    opacity: 1;
    transform: translateY(0);
}

/* Counter roll-up (Tier B1) */
#msgrBcSendingCard .sending-count-done-wrap {
    position: relative;
    display: inline-block;
    height: 52px;
    line-height: 1;
    overflow: hidden;
    vertical-align: bottom;
    min-width: 1ch;
}
#msgrBcSendingCard .sending-count-done {
    display: inline-block;
    transition: transform 220ms cubic-bezier(0.4, 0, 0.2, 1), opacity 220ms ease;
    will-change: transform, opacity;
}
#msgrBcSendingCard .sending-count-current {
    position: relative;
    transform: translateY(0);
    opacity: 1;
}
#msgrBcSendingCard .sending-count-incoming {
    position: absolute;
    inset: 0;
    transform: translateY(100%);
    opacity: 0;
}
#msgrBcSendingCard .sending-count-done-wrap.rolling .sending-count-current {
    transform: translateY(-100%);
    opacity: 0;
}
#msgrBcSendingCard .sending-count-done-wrap.rolling .sending-count-incoming {
    transform: translateY(0);
    opacity: 1;
}

/* Done celebration on count (Tier B4) */
#msgrBcSendingOverlay.done .sending-count-done {
    color: var(--color-success);
    animation: sendingCountCelebrate 460ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes sendingCountCelebrate {
    0%   { transform: scale(1); }
    55%  { transform: scale(1.08); }
    100% { transform: scale(1); }
}

/* Live sublabel - "Delivering…" with animated dots (Tier A3) */
#msgrBcSendingCard .sending-sublabel {
    transition: color 240ms ease;
}
#msgrBcSendingCard .sending-dots span {
    opacity: 0.2;
    animation: sendingDot 1.2s ease-in-out infinite;
}
#msgrBcSendingCard .sending-dots span:nth-child(2) { animation-delay: 0.2s; }
#msgrBcSendingCard .sending-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes sendingDot {
    0%, 80%, 100% { opacity: 0.2; }
    40%           { opacity: 1; }
}
#msgrBcSendingOverlay.done .sending-dots { display: none; }
#msgrBcSendingOverlay.done .sending-sublabel { color: var(--color-success); }

/* Transient per-recipient failure notice in the sublabel */
#msgrBcSendingCard .sending-sublabel-fail {
    color: #f59e0b;
}

@media (prefers-reduced-motion: reduce) {
    #msgrBcSendingCard *,
    #msgrBcSendingCard *::before,
    #msgrBcSendingCard *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

/* Section heading inside messenger modals */
.msgr-section-heading { font-size: var(--font-size-heading); font-weight: 600; margin: 0 0 6px 0; }

/* Conversation notes */
.msgr-note-item {
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border-subtle, rgba(0,0,0,0.06));
}
.msgr-note-item:last-child { border-bottom: none; }
.msgr-note-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 4px;
    gap: 8px;
}
.msgr-note-body {
    white-space: pre-wrap;
    word-break: break-word;
    color: var(--color-text);
    font-size: 0.92em;
    line-height: 1.5;
}

/* Unified note cards */
.msgr-note-card {
    background: rgba(0, 0, 0, 0.04);
    border-radius: 8px;
    padding: 10px 12px;
    margin-bottom: 8px;
}
[data-theme="dark"] .msgr-note-card {
    background: rgba(255, 255, 255, 0.06);
}
.msgr-note-card:last-child { margin-bottom: 0; }
.msgr-note-card-header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
}
.msgr-note-avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--color-primary);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    letter-spacing: 0.03em;
}
.msgr-note-meta {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex-wrap: wrap;
}
.msgr-note-author {
    font-weight: 500;
    font-size: var(--font-size-label);
}
.msgr-note-card-body {
    white-space: pre-wrap;
    word-break: break-word;
    font-size: 0.92em;
    line-height: 1.5;
    color: var(--color-text);
    padding-left: 34px;
}
.msgr-note-edit-area {
    margin: 8px 0 0 34px;
    margin-bottom: 0;
}
.msgr-note-edit-actions {
    display: flex;
    gap: 8px;
    margin: 8px 0 0 34px;
}

/* "+ Add your note" prompt */
.msgr-add-note-btn {
    background: none;
    border: none;
    color: var(--color-primary);
    font-size: var(--font-size-body);
    font-weight: 500;
    cursor: pointer;
    padding: 8px 0 0 0;
    display: block;
}
.msgr-add-note-btn:hover { text-decoration: underline; }

/* POC view state */
.msgr-poc-view {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Name edit row (below modal h2, above details) */
.msgr-name-edit-row {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 4px;
}

/* Lightweight section label replacing h3+p in modals */
.msgr-modal-section-label {
    font-size: var(--font-size-label);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-muted, #888);
    margin: 0 0 10px 0;
}

/* ============================================================ */
/* ── Pending Registrations ── */
/* ============================================================ */

.reg-admin-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.reg-admin-item {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 14px 16px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 12px;
    transition: background 0.15s;
}

.reg-admin-item:hover {
    background: var(--color-bg);
}

.reg-admin-main {
    flex: 1;
    min-width: 0;
}

.reg-admin-name {
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--color-text);
}

.reg-admin-meta {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 3px;
}

.reg-admin-right {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

.reg-admin-chevron {
    color: var(--color-text-light);
    font-size: 18px;
    flex-shrink: 0;
    line-height: 1;
    align-self: center;
    transform: translateY(-2px);
}

/* Card wrapper for child / parent detail blocks */
.reg-detail-card {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 12px;
    margin-bottom: 12px;
}

[data-theme="dark"] .reg-admin-item:hover {
    background: rgba(255, 255, 255, 0.04);
}

/* Multi-step Process Registration panels */

.reg-step-panel {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-bottom: 10px;
    overflow: hidden;
}

.reg-step-panel[data-state="done"] {
    background: var(--color-bg);
}

.reg-step-panel[data-state="locked"] {
    opacity: 0.7;
}

.reg-step-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    cursor: pointer;
    user-select: none;
    transition: background 0.15s;
}

.reg-step-header:hover {
    background: rgba(0, 0, 0, 0.03);
}

[data-theme="dark"] .reg-step-header:hover {
    background: rgba(255, 255, 255, 0.04);
}

.reg-step-title {
    font-weight: 600;
    flex: 1;
    min-width: 0;
}

.reg-step-chevron {
    color: var(--color-text-light);
    font-size: 14px;
    flex-shrink: 0;
    line-height: 1;
}

.reg-step-body {
    padding: 12px 14px 14px 14px;
    border-top: 1px solid var(--color-border);
}

.reg-step-body[hidden] {
    display: none;
}

.reg-step-state {
    font-size: var(--font-size-label);
    font-weight: 600;
    padding: 3px 8px 2px;
    border-radius: 12px;
    flex-shrink: 0;
}

.reg-step-state.done {
    background: rgba(30, 107, 61, 0.12);
    color: var(--color-success);
}

.reg-step-state.pending {
    background: var(--color-warning-bg);
    color: var(--color-warning);
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.reg-step-state.locked,
.reg-step-state.skipped {
    background: rgba(107, 107, 107, 0.12);
    color: var(--color-text-light);
}

.reg-chat-list {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    max-height: 320px;
    overflow-y: auto;
}

.reg-chat-row {
    padding: 10px 12px;
    cursor: pointer;
    border-bottom: 1px solid var(--color-border);
    transition: background 0.15s;
}

.reg-chat-row:last-child {
    border-bottom: none;
}

.reg-chat-row:hover {
    background: var(--color-bg);
}

[data-theme="dark"] .reg-chat-row:hover {
    background: rgba(255, 255, 255, 0.04);
}

.reg-chat-name {
    font-weight: 600;
}

.reg-chat-sub {
    font-size: var(--font-size-label);
    margin-top: 2px;
}

.reg-payment-message-sent {
    background: var(--color-bg);
    padding: 12px;
    border-radius: 6px;
    white-space: pre-wrap;
    font-family: monospace;
    font-size: var(--font-size-small);
    margin-top: 8px;
}

.reg-sub-heading {
    margin-top: 20px;
    margin-bottom: 8px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: var(--font-size-label);
    color: var(--color-text-light);
    font-weight: 600;
}

.reg-payment-message-textarea {
    font-family: monospace;
    font-size: var(--font-size-small);
}

.reg-panel-title {
    font-size: var(--font-size-heading);
    font-weight: 700;
    margin-bottom: 16px;
    color: var(--color-text);
}

.reg-section-heading {
    font-size: var(--font-size-heading);
    font-weight: 700;
    color: var(--color-text);
    margin-top: 0;
    margin-bottom: 2px;
}

/* =====================================================
   REGISTRATION FUNNEL TAB (Enrolment module)
   ===================================================== */

.reg-funnel-section-heading {
    font-size: var(--font-size-heading);
    font-weight: 600;
    margin: 24px 0 8px 0;
    color: var(--color-text);
}
.reg-funnel-section-heading:first-child { margin-top: 0; }

.reg-funnel-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 20px;
}
.reg-funnel-header-meta {
    margin: 0;
    color: var(--color-text-light);
    font-size: var(--font-size-small);
}

.reg-funnel-metrics {
    display: flex;
    gap: 24px;
    margin-bottom: 12px;
}
.reg-funnel-metric-label {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.reg-funnel-metric-value {
    font-size: var(--font-size-heading);
    font-weight: 600;
}

.reg-funnel-row {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 12px;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid var(--color-border);
}
.reg-funnel-row-label {
    font-weight: 500;
}
.reg-funnel-bar-track {
    background: var(--color-border);
    height: 8px;
    border-radius: 4px;
    overflow: hidden;
    margin-top: 4px;
}
.reg-funnel-bar-fill {
    background: var(--color-primary);
    height: 100%;
    width: 100%;
    transform-origin: left center;
    transform: scaleX(0);
    transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1);
}
.reg-funnel-row-count {
    font-weight: 600;
    min-width: 42px;
    text-align: right;
}
.reg-funnel-row-dropoff {
    min-width: 60px;
    text-align: right;
    font-size: var(--font-size-small);
}
.reg-funnel-dropoff-bad   { color: var(--color-error); }
.reg-funnel-dropoff-flat  { color: var(--color-success); }

.reg-funnel-chart-block { margin-bottom: 24px; }

.reg-funnel-intro {
    margin: 0 0 8px 0;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}

.reg-funnel-step-label {
    color: var(--color-text-light);
    font-size: var(--font-size-small);
    margin-left: 4px;
}

.reg-funnel-dwell {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}

.reg-funnel-completion {
    font-weight: 600;
    text-align: right;
}
.reg-funnel-completion-good { color: var(--color-success); }
.reg-funnel-completion-mid  { color: var(--color-warning); }
.reg-funnel-completion-bad  { color: var(--color-error); }

.reg-funnel-chip {
    display: inline-block;
    background: var(--color-surface-alt);
    color: var(--color-text);
    padding: 1px 6px;
    border-radius: 8px;
    font-size: var(--font-size-small);
    margin: 1px 2px;
}

.reg-funnel-session-id {
    font-family: monospace;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}

.reg-funnel-error-detail {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}

/* Range segmented control - reuses .ann-seg-control + .ann-seg, just sized smaller */
.reg-funnel-range { max-width: 100%; }

/* Registration detail - Details / History tab bar */
.reg-detail-tabs {
    display: flex;
    gap: 0;
    border-bottom: 2px solid var(--color-border);
    margin-bottom: 16px;
}

.reg-detail-tab {
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    padding: 8px 16px;
    font-size: var(--font-size-label);
    font-weight: 500;
    color: var(--color-text-light);
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}

.reg-detail-tab:hover {
    color: var(--color-text);
}

.reg-detail-tab.active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

/* Registration detail - History tab entries */
.reg-history-list {
    display: flex;
    flex-direction: column;
    gap: 0;
    margin-top: 8px;
}

.reg-history-entry {
    padding: 12px 0;
    border-bottom: 1px solid var(--color-border);
}

.reg-history-entry:last-child {
    border-bottom: none;
}

.reg-history-meta {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-bottom: 4px;
}

.me-section-heading {
    font-size: var(--font-size-body);
    font-weight: 600;
    margin-bottom: 16px;
    color: var(--color-text);
}


.me-chat-dropdown {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-top: none;
    border-radius: 0 0 8px 8px;
    z-index: 20;
    max-height: 220px;
    overflow-y: auto;
}

.me-template-toolbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-bottom: 16px;
    flex-wrap: wrap;
}

.me-tags-details {
    margin-bottom: 16px;
}

.me-tags-summary {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    cursor: pointer;
    user-select: none;
    padding: 4px 0;
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.me-tags-summary::-webkit-details-marker {
    display: none;
}

.me-tags-summary::marker {
    content: '';
}

.me-tags-summary::before {
    content: '▸';
    font-size: var(--font-size-small);
    transition: transform 0.15s;
    display: inline-block;
}

.me-tags-details[open] .me-tags-summary::before {
    transform: rotate(90deg);
}

.me-tags-body {
    padding: 8px 0 4px 16px;
}

.reg-history-change {
    font-size: var(--font-size-small);
    color: var(--color-text);
    word-break: break-word;
}

/* ============================================================
   Invoice + Payslip styles (Phase 1 foundations)
   ============================================================ */

/* Generic alias for badge-error so JS using badge-danger works */
.badge-danger { background: rgba(192, 57, 43, 0.1); color: var(--color-error); }

/* Invoice list (parent + staff shared) */
.invoice-list { display: flex; flex-direction: column; gap: 8px; }

.invoice-year-heading {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 16px 0 4px;
}

.invoice-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.15s;
}
.invoice-row:hover { background: var(--color-surface-alt); }

.invoice-row-month { font-weight: 600; color: var(--color-text); }
.invoice-row-student { font-size: var(--font-size-small); color: var(--color-text-light); margin-top: 4px; }
/* "Paid dd/mm/yy" line under a receipt row in the parent's My Receipts list. */
.invoice-row-paid { font-size: var(--font-size-small); color: var(--color-success); margin-top: 2px; }

/* Invoice / Receipt kind tag — neutral accounting presentation, no red, no
   warning icons. Receipts are finalised history; invoices are outstanding.
   The tag's existence carries the meaning — no progress-percentage, no
   "paid"/"partial" badge. */
.invoice-row-kind {
    display: inline-block;
    font-size: var(--font-size-small);
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 4px;
    margin-left: 8px;
    vertical-align: 1px;
    letter-spacing: 0.02em;
}
.invoice-row-kind-receipt {
    background: var(--color-surface-alt);
    color: var(--color-text-light);
}
.invoice-row-kind-invoice {
    background: var(--color-primary);
    color: var(--color-on-primary);
}

.invoice-row-right { display: flex; align-items: center; gap: 12px; }
.invoice-row-amount { font-weight: 600; }
.invoice-row-chevron { color: var(--color-text-light); font-size: 18px; }

/* Staff summary */
.invoice-summary-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: flex-end;
    margin-bottom: 16px;
}

.invoice-summary-cards,
.payslip-summary-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
    margin-bottom: 16px;
}

.summary-card {
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 12px 14px;
}
.summary-card-label {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 4px;
}
.summary-card-value { font-weight: 600; font-size: 18px; color: var(--color-text); }

.invoice-summary-table { overflow-x: auto; }

/* Invoice detail modal */
.invoice-detail-header { margin-bottom: 12px; }
.invoice-detail-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-bottom: 14px;
    font-size: var(--font-size-small);
}
.invoice-detail-h3 {
    font-size: var(--font-size-subheading);
    color: var(--color-text-light);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 18px 0 8px;
}
.invoice-line-items tfoot td { padding-top: 8px; }
.invoice-line-negative td { color: var(--color-success); }

/* Per-line remove control (Draft state, student_fee_discounts source only). */
.invoice-line-desc-wrap {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.invoice-line-remove-btn {
    background: transparent;
    border: none;
    padding: 6px 8px;
    margin: 0;
    color: var(--color-text-light);
    cursor: pointer;
    border-radius: 4px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    transition: color 120ms ease, background 120ms ease;
}
.invoice-line-remove-btn:hover {
    color: var(--color-error);
    background: color-mix(in srgb, var(--color-error) 10%, transparent);
}
.invoice-line-remove-btn i { font-size: 14px; line-height: 1; }

.invoice-parent-message {
    background: var(--color-surface-alt);
    padding: 12px 14px;
    border-radius: 8px;
    margin: 14px 0;
    font-size: var(--font-size-small);
}

/* Payment Instructions block on the parent's outstanding-invoice view: how to
   pay (bank / PayNow), sourced from settings.school_fees.payment_details. */
.invoice-payment-instructions {
    margin: 16px 0 4px;
    padding: 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface-alt);
}
.invoice-payment-instructions-title {
    font-size: var(--font-size-small);
    font-weight: 600;
    margin-bottom: 6px;
    color: var(--color-text);
}
.invoice-payment-instructions-body {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    white-space: pre-line;
    line-height: 1.5;
}
.invoice-payment-instructions-note {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--color-border);
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    line-height: 1.5;
}
/* Receipt-only footer note: "Remaining balance will be reflected in the next
   invoice." (or the credit variant). Neutral wording, no warning icons, no red. */
.invoice-receipt-footer-note {
    margin: 12px 0 4px;
    padding: 10px 14px;
    border-left: 2px solid var(--color-text-light);
    background: var(--color-surface-alt);
    color: var(--color-text-light);
    font-size: var(--font-size-small);
    line-height: 1.5;
}
/* Subtle reference number at the bottom of every receipt — audit / dispute
   handle. Quiet, low-priority, never a header field. */
.invoice-receipt-ref {
    margin: 18px 0 0;
    color: var(--color-text-light);
    font-size: var(--font-size-small);
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace;
    letter-spacing: 0.04em;
    text-align: right;
}
.invoice-detail-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 16px;
    border-top: 1px solid var(--color-border);
    padding-top: 14px;
}

/* Variance cells in the staff invoice table — colour-coded so a glance at
   the column shows where shortfalls and overpayments are. Subtle, not
   alarming: variance is bookkeeping context, not an error state. */
.invoice-variance-shortfall {
    color: var(--color-error);
    font-weight: 500;
    font-size: var(--font-size-small);
}
.invoice-variance-overpayment {
    color: var(--color-success);
    font-weight: 500;
    font-size: var(--font-size-small);
}

/* Per-invoice receipt flow (June 2026): selection checkboxes, the floating
   "N selected → Confirm Payment" bar, the Paid badge, and the inline Undo. */
.invoice-check-col {
    width: 36px;
    text-align: center;
    padding-right: 0;
}
.invoice-check-col input[type="checkbox"] {
    width: 17px;
    height: 17px;
    cursor: pointer;
    accent-color: var(--color-primary);
    vertical-align: middle;
}
.invoice-selection-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
    padding: 10px 14px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-primary) 25%, transparent);
}
.invoice-selection-count {
    font-weight: 600;
    color: var(--color-primary);
    font-size: var(--font-size-small);
}
.invoice-selection-actions {
    display: flex;
    gap: 8px;
}
/* Paid badge in the staff invoice table: green pill carrying the payment
   date. Reads as a settled state, sibling of the month-status chips. */
.invoice-paid-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: 11px;
    font-size: var(--font-size-small);
    font-weight: 500;
    white-space: nowrap;
    background: color-mix(in srgb, var(--color-success) 12%, transparent);
    color: var(--color-success);
    border: 1px solid color-mix(in srgb, var(--color-success) 25%, transparent);
}
.invoice-undo-btn {
    margin-left: 8px;
    padding: 0;
    border: none;
    background: none;
    color: var(--color-text-light);
    font-size: var(--font-size-small);
    text-decoration: underline;
    cursor: pointer;
}
.invoice-undo-btn:hover {
    color: var(--color-error);
}
/* Confirmed month, mobile only: strip the table to the essentials —
   Student · Parents · Payment. Total + Variance are bookkeeping context that
   crowds a phone-width row, so we hide just those two columns. Desktop and the
   Draft/Closed states keep the full table. */
@media (max-width: 767px) {
    .data-table.invoice-table--confirmed .invoice-total-col,
    .data-table.invoice-table--confirmed .invoice-variance-col {
        display: none;
    }
}

/* Month-status chip — Draft / Confirmed / Closed indicator shown on the
   Manage Invoices toolbar and inside the per-invoice detail modal. Mirrors
   the muted-badge look so it reads as context, not action. */
.invoice-month-status-chip {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: 12px;
    font-size: var(--font-size-small);
    font-weight: 500;
    letter-spacing: 0.02em;
    border: 1px solid transparent;
    background: var(--color-surface-alt);
    color: var(--color-text-light);
}
.invoice-month-status-chip.invoice-month-status-draft {
    background: var(--color-surface-alt);
    color: var(--color-text-light);
    border-color: var(--color-border);
}
.invoice-month-status-chip.invoice-month-status-confirmed {
    /* Tinted from --color-primary so the chip background follows the theme
       — was hardcoded rgba(37,78,72) which pinned the tint to light-mode
       primary even after the text colour shifted in dark mode. */
    background: color-mix(in srgb, var(--color-primary) 12%, transparent);
    color: var(--color-primary);
    border-color: color-mix(in srgb, var(--color-primary) 25%, transparent);
}
.invoice-month-status-chip.invoice-month-status-closed {
    background: color-mix(in srgb, var(--color-success) 12%, transparent);
    color: var(--color-success);
    border-color: color-mix(in srgb, var(--color-success) 25%, transparent);
}

/* Invoice detail modal — single chip row replaces the old four-field meta
   row. The chip is the one piece of state the line-items footer doesn't
   already carry. */
.invoice-detail-chip-row {
    margin: 6px 0 14px;
    display: flex;
}

/* Modal section labels — small uppercase divider for grouping related
   fields inside a long modal (Add Mandate, Add Charge, etc.). Quieter
   than an <h3> but stronger than nothing — reads as "this is a group". */
.modal-section-label {
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--color-text-light);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin: 18px 0 10px;
    padding-bottom: 4px;
    border-bottom: 1px solid var(--color-border);
}
.modal-section-label:first-of-type { margin-top: 4px; }

/* Invoices header band — single cohesive top-of-tab strip that holds the
   month picker, status chip, summary line, primary action, and overflow
   menu. Replaces the old four-stack (auto-confirm card + status legend +
   toolbar + KPI tiles) with one band. */
.invoice-header-band {
    padding: 14px 16px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-bottom: 16px;
}
.invoice-header-top {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.invoice-header-month-picker {
    width: auto;
    min-width: 120px;
    padding: 6px 10px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: transparent;
    color: var(--color-text);
    font-size: var(--font-size-body);
    font-weight: 600;
    cursor: pointer;
}
.invoice-header-month-picker:hover { border-color: var(--color-primary); }
.invoice-header-spacer { flex: 1; }
.invoice-header-action { display: inline-flex; gap: 8px; }
.invoice-header-summary {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--color-border);
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.invoice-header-summary strong { color: var(--color-text); font-weight: 600; }

/* Overflow menu — the ⋯ button in the header band drops a small menu
   for secondary actions (Generate UFF). Hidden by default; .is-open
   reveals it. */
.invoice-header-overflow { position: relative; }
.invoice-header-overflow-btn {
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: transparent;
    color: var(--color-text-light);
    cursor: pointer;
    font-size: 16px;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.invoice-header-overflow-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-text);
}
.invoice-header-overflow-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 280px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.2);
    padding: 6px;
    z-index: 100;
    visibility: hidden;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.15s, transform 0.15s, visibility 0s linear 0.15s;
}
.invoice-header-overflow-menu.is-open {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
    transition: opacity 0.15s, transform 0.15s, visibility 0s;
}
.invoice-overflow-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 10px 12px;
    background: transparent;
    border: none;
    border-radius: 6px;
    color: var(--color-text);
    cursor: pointer;
    font: inherit;
}
.invoice-overflow-item:hover:not(.is-disabled) { background: var(--color-surface-alt); }
.invoice-overflow-item.is-disabled {
    cursor: not-allowed;
    color: var(--color-text-light);
}
.invoice-overflow-item-label { font-weight: 500; font-size: var(--font-size-body); }
.invoice-overflow-item-hint {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 3px;
    line-height: 1.4;
}

/* Settings sub-tab sections — auto-confirm card stacks on top, then the
   Adjustment Types list below. Each section gets a header (h3 + desc) so
   it's clear what each control set does without a wall of intro text. */
.invoice-settings-section {
    margin-top: 24px;
    padding-top: 20px;
    border-top: 1px solid var(--color-border);
}
.invoice-settings-section:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.invoice-settings-section-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    margin-bottom: 14px;
}
.invoice-settings-section-title {
    font-size: var(--font-size-body);
    font-weight: 600;
    color: var(--color-text);
    margin: 0 0 4px;
}
.invoice-settings-section-desc {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin: 0;
    line-height: 1.5;
}

/* Auto-confirm card — single-sentence composition with an inline day-picker
   styled like editable text inside the sentence, and a right-aligned toggle.
   Replaces the old multi-element card (title + checkbox + dropdown + Save
   button) that bunched controls into the left ~38% of the card width. */
.invoice-autoconfirm-card {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 14px 16px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-bottom: 16px;
}
.invoice-autoconfirm-sentence {
    flex: 1;
    margin: 0;
    line-height: 1.6;
    color: var(--color-text);
    font-size: var(--font-size-body);
}
.invoice-autoconfirm-card.is-off .invoice-autoconfirm-sentence {
    color: var(--color-text-light);
}
.invoice-autoconfirm-toggle {
    align-self: center;
    flex-shrink: 0;
}
/* Inline day-picker — styled like an editable inline element inside running
   text, NOT a standard form-group select. The native chevron is preserved
   (the helper already handles dark-mode visibility on the system select). */
.invoice-autoconfirm-day-select {
    display: inline-block;
    width: auto;
    margin: 0 2px;
    padding: 2px 8px;
    font: inherit;
    font-weight: 600;
    color: var(--color-primary);
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    cursor: pointer;
    vertical-align: baseline;
}
.invoice-autoconfirm-day-select:hover { border-color: var(--color-primary); }
.invoice-autoconfirm-day-select:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 20%, transparent);
}
.invoice-autoconfirm-card.is-off .invoice-autoconfirm-day-select {
    color: var(--color-text-light);
    border-color: var(--color-border);
}

/* Per-invoice variance reason — shown to staff in the detail modal beneath
   the line-item table whenever a variance has been recorded. Borrows the
   subtle-callout treatment of .invoice-receipt-footer-note. */
.invoice-variance-meta {
    margin: 14px 0 4px;
    padding: 10px 14px;
    border-left: 2px solid var(--color-border);
    background: var(--color-surface-alt);
    font-size: var(--font-size-small);
    line-height: 1.5;
}
.invoice-variance-meta > div:first-child {
    margin-bottom: 2px;
}

/* Payslip list */
.payslip-list { display: flex; flex-direction: column; gap: 8px; }

.payslip-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.15s;
}
.payslip-row:hover { background: var(--color-surface-alt); }

.payslip-row-month { font-weight: 600; }
.payslip-row-meta { margin-top: 2px; }
.payslip-row-right { display: flex; align-items: center; gap: 12px; }

/* Payslip PDF / on-screen layout */
.payslip-pdf {
    background: #fff;
    color: #111;
    border-radius: 8px;
    padding: 0;
    overflow: hidden;
    border: 1px solid var(--color-border);
}

.payslip-pdf-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 24px 28px;
    color: #fff;
}
.payslip-pdf-company { font-size: 20px; font-weight: 700; }
.payslip-pdf-uen { font-size: 13px; margin-top: 4px; opacity: 0.9; }
.payslip-pdf-address { font-size: 12px; margin-top: 4px; opacity: 0.85; white-space: pre-wrap; }
.payslip-pdf-logo { max-height: 64px; max-width: 160px; }

.payslip-pdf-title {
    text-align: center;
    font-size: 24px;
    font-weight: 700;
    margin-top: 24px;
    color: #111;
}
.payslip-pdf-period {
    text-align: center;
    font-size: 14px;
    color: #555;
    margin-bottom: 18px;
}

.payslip-pdf-staff {
    padding: 0 28px 12px;
    border-bottom: 1px solid #e5e5e5;
}
.payslip-pdf-staff-name { font-weight: 600; font-size: 16px; }
.payslip-pdf-work-days { font-size: 13px; color: #666; margin-top: 2px; }

.payslip-pdf-section {
    padding: 14px 28px;
    border-bottom: 1px solid #f3f3f3;
}
.payslip-pdf-section-title {
    font-size: 11px;
    letter-spacing: 0.08em;
    color: #666;
    text-transform: uppercase;
    margin-bottom: 8px;
}
.payslip-pdf-line {
    display: flex;
    justify-content: space-between;
    padding: 4px 0;
    font-size: 13px;
}
.payslip-pdf-line-total { border-top: 1px solid #e5e5e5; padding-top: 8px; margin-top: 6px; font-weight: 600; }

.payslip-pdf-net {
    padding: 14px 28px;
    background: #fafafa;
}
.payslip-pdf-line-net {
    font-size: 16px;
    font-weight: 700;
    padding: 6px 0;
}
.payslip-pdf-footer {
    text-align: center;
    padding: 18px 28px;
    color: #666;
    font-style: italic;
    font-size: 13px;
}

.payslip-detail-actions {
    display: flex;
    gap: 8px;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--color-border);
}

/* GIRO + batch builder */
.invoice-summary-tabs { display:flex; flex-wrap: wrap; gap:8px; margin-bottom: 16px; }
.giro-empty { text-align:center; padding: 24px; color: var(--color-text-light); }
.giro-toolbar { display:flex; gap:8px; margin-bottom: 12px; }
.mandate-student-list {
    border: 1px solid var(--color-border);
    border-radius: 6px;
    padding: 8px 12px;
    max-height: 160px;
    overflow-y: auto;
}
.mandate-student-row {
    display: flex; align-items: center; gap: 8px;
    padding: 4px 0;
    cursor: pointer;
}
.mandate-student-row input { margin: 0; }
.batch-meta {
    display: flex; gap: 16px; flex-wrap: wrap;
    margin-bottom: 14px; font-size: var(--font-size-small);
}

/* ── Module Management (Canopy HQ only) ── */
#moduleManagementContent .mm-segmented {
    display: inline-flex;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    padding: 3px;
    gap: 2px;
    margin-bottom: 18px;
}
#moduleManagementContent .mm-seg {
    padding: 8px 18px;
    border: none;
    background: transparent;
    color: var(--color-text-light);
    font-weight: 500;
    font-size: var(--font-size-small);
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
#moduleManagementContent .mm-seg.active {
    background: var(--color-primary);
    color: var(--color-on-primary);
}
#moduleManagementContent .mm-section { display: none; }
#moduleManagementContent .mm-section.active { display: block; }
#moduleManagementContent .mm-org-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px;
    border-bottom: 1px solid var(--color-border);
    width: 100%;
    background: none;
    border: none;
    border-bottom: 1px solid var(--color-border);
    text-align: left;
    cursor: pointer;
    font: inherit;
    color: inherit;
}
#moduleManagementContent .mm-org-row:last-child { border-bottom: none; }
#moduleManagementContent .mm-org-row:hover { background: var(--color-bg); }
#moduleManagementContent .mm-org-chevron {
    color: var(--color-text-light);
    font-size: 1.25rem;
    line-height: 1;
    flex-shrink: 0;
}
#moduleManagementContent .mm-org-name {
    font-weight: 600;
    color: var(--color-text);
}
#moduleManagementContent .mm-org-meta {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 2px;
}
#moduleManagementContent .mm-gating-module {
    margin-bottom: 22px;
    padding: 14px 16px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 8px;
}
#moduleManagementContent .mm-gating-module h3 {
    margin: 0 0 4px;
    font-size: var(--font-size-body);
    color: var(--color-text);
}
#moduleManagementContent .mm-gating-module .mm-flag-note {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin: 0 0 12px;
}
#moduleManagementContent .mm-gating-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 0;
}
#moduleManagementContent .mm-actions { margin-top: 16px; display: flex; gap: 12px; align-items: center; }
#moduleManagementContent .mm-status { font-size: var(--font-size-small); color: var(--color-text-light); }

/* ============================================================
   5.X Organisation Management (Canopy HQ control plane)
   ============================================================ */
#organisationManagementContent .om-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 6px;
}
#organisationManagementContent .om-header h2 { margin: 0; }
#organisationManagementContent .om-intro {
    font-size: var(--font-size-small);
    margin: 0 0 18px;
}
#organisationManagementContent .om-group { margin-bottom: 22px; }
#organisationManagementContent .om-group-title {
    font-size: var(--font-size-small);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-light);
    margin-bottom: 8px;
}
#organisationManagementContent .om-org-list {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    overflow: hidden;
}
#organisationManagementContent .om-org-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    width: 100%;
    background: none;
    border: none;
    border-bottom: 1px solid var(--color-border);
    text-align: left;
    cursor: pointer;
    font: inherit;
    color: inherit;
}
#organisationManagementContent .om-org-row:last-child { border-bottom: none; }
#organisationManagementContent .om-org-row:hover { background: var(--color-bg); }
#organisationManagementContent .om-org-name {
    font-weight: 600;
    color: var(--color-text);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
#organisationManagementContent .om-org-meta {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin-top: 3px;
}
#organisationManagementContent .om-org-chevron {
    color: var(--color-text-light);
    font-size: 1.25rem;
    line-height: 1;
    flex-shrink: 0;
}
#organisationManagementContent .om-badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.4;
    border: 1px solid transparent;
    white-space: nowrap;
}
#organisationManagementContent .om-badge-superadmin {
    background: var(--color-primary);
    color: var(--color-on-primary);
}
#organisationManagementContent .om-badge-parent {
    background: transparent;
    color: var(--color-primary-light);
    border-color: var(--color-primary-light);
}
#organisationManagementContent .om-badge-regular {
    background: transparent;
    color: var(--color-text-light);
    border-color: var(--color-border);
}
/* Form */
#organisationManagementContent .om-form-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
}
#organisationManagementContent .om-form-head h3 { margin: 0; font-size: var(--font-size-body); }
#organisationManagementContent .om-form { max-width: 520px; }
#organisationManagementContent .om-field { margin-bottom: 16px; }
#organisationManagementContent .om-label {
    display: block;
    font-weight: 600;
    font-size: var(--font-size-small);
    margin-bottom: 6px;
    color: var(--color-text);
}
#organisationManagementContent .om-input {
    width: 100%;
    padding: 9px 12px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-card);
    color: var(--color-text);
    font: inherit;
}
#organisationManagementContent .om-field-static {
    padding: 9px 0;
    color: var(--color-text);
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
#organisationManagementContent .om-inline-link {
    font-size: var(--font-size-small);
    color: var(--color-primary);
    text-decoration: none;
}
#organisationManagementContent .om-inline-link:hover { text-decoration: underline; }
#organisationManagementContent .om-help {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    margin: 6px 0 0;
}
#organisationManagementContent .om-actions {
    margin-top: 20px;
    display: flex;
    gap: 12px;
    align-items: center;
}
#organisationManagementContent .om-status { font-size: var(--font-size-small); color: var(--color-text-light); }

/* ============================================================
   5.X Holiday Programme Module
   ============================================================ */
.hp-toolbar {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    align-items: flex-end;
    margin-bottom: 16px;
}
.hp-toolbar .form-group { min-width: 200px; }
.hp-child-select {
    font-size: var(--font-size-small);
    padding: 4px 10px;
    height: 32px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: var(--color-surface);
    color: var(--color-text);
    cursor: pointer;
    max-width: 150px;
}

.hp-locked-banner {
    background: color-mix(in srgb, var(--color-warning, #d4930a) 12%, var(--color-bg));
    color: var(--color-text);
    border: 1px solid color-mix(in srgb, var(--color-warning, #d4930a) 35%, transparent);
    border-radius: 8px;
    padding: 12px 16px;
    margin-bottom: 16px;
    font-size: var(--font-size-body);
}

.hp-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
    align-items: start;
}


.hp-cal-wrap { min-width: 0; }
.hp-cost-panel {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 20px;
}
.hp-panel-title { margin: 0 0 4px; font-size: var(--font-size-subheading); }
.hp-panel-dates { color: var(--color-text-light); font-size: var(--font-size-small); margin-bottom: 12px; }
.hp-submit-by { font-size: var(--font-size-small); color: var(--color-text-light); margin-bottom: 12px; }
.hp-day-counter { font-size: var(--font-size-body); margin-bottom: 12px; }
.hp-day-counter strong { font-size: var(--font-size-heading); }

.hp-progress-wrap { margin: 8px 0 16px; }
.hp-progress-bar {
    height: 8px;
    background: var(--color-border);
    border-radius: 999px;
    overflow: hidden;
    position: relative;
}
.hp-progress-fill {
    height: 100%;
    background: var(--cd-color-programme, #d4930a);
    border-radius: 999px;
    transition: width 280ms var(--ease-out);
}
.hp-progress-caption {
    margin-top: 6px;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.hp-sparkle {
    color: var(--cd-color-programme, #d4930a);
    font-weight: 600;
}

.hp-lines { margin: 12px 0; }
.hp-line {
    display: flex;
    justify-content: space-between;
    padding: 6px 0;
    font-size: var(--font-size-body);
    border-bottom: 1px dashed var(--color-border);
}
.hp-line--waived { color: var(--color-text-light); }
.hp-mini-note {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    background: color-mix(in srgb, var(--cd-color-programme, #d4930a) 8%, var(--color-bg));
    border-left: 3px solid var(--cd-color-programme, #d4930a);
    padding: 8px 10px;
    margin: 6px 0;
    border-radius: 4px;
}
.hp-total {
    display: flex;
    justify-content: space-between;
    padding: 12px 0 16px;
    font-size: var(--font-size-heading);
    font-weight: 600;
    border-top: 1px solid var(--color-border);
}
.hp-cost-panel .btn { width: 100%; }
.hp-fineprint {
    margin: 12px 0 0;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
    text-align: center;
}

/* Calendar cell states layered on top of .cd-cal-cell--programme */
.hp-cell--out-of-range {
    opacity: 0.35;
    pointer-events: none;
}
.hp-cell--closed {
    opacity: 0.35;
    pointer-events: none;
}
.hp-cell--picked {
    background: color-mix(in srgb, var(--cd-color-programme, #d4930a) 36%, var(--color-bg)) !important;
    box-shadow: inset 0 0 0 2px var(--cd-color-programme, #d4930a);
}
.hp-excursion-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 3px;
    font-size: 0.62rem;
    font-weight: 700;
    color: var(--color-on-primary);
    background: var(--cd-color-programme, #d4930a);
    line-height: 1;
    flex-shrink: 0;
}
.hp-cell--locked {
    cursor: not-allowed !important;
}

/* Legend */
.hp-legend {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    margin-top: 12px;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.hp-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.hp-legend-swatch {
    width: 16px; height: 8px; border-radius: 3px;
    background: color-mix(in srgb, var(--cd-color-programme, #d4930a) 12%, var(--color-bg));
    border: 1px solid var(--cd-color-programme, #d4930a);
}
.hp-legend-swatch--exc { background: color-mix(in srgb, var(--cd-color-programme, #d4930a) 12%, var(--color-bg)); }
.hp-legend-swatch--picked { background: color-mix(in srgb, var(--cd-color-programme, #d4930a) 36%, var(--color-bg)); }

/* Admin: Manage Holiday Programme */
.hp-manage-toolbar {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    align-items: flex-end;
    margin-bottom: 20px;
}
/* Launch status banner — not-launched (primary tint) vs live (success tint) */
.hp-launch-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    background: color-mix(in srgb, var(--color-primary) 8%, var(--color-bg));
    border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
    border-radius: 12px;
    padding: 14px 16px;
    margin-bottom: 20px;
}
.hp-launch-banner--live {
    background: color-mix(in srgb, var(--color-success) 10%, var(--color-bg));
    border-color: color-mix(in srgb, var(--color-success) 32%, transparent);
}
.hp-launch-banner-text {
    flex: 1;
    min-width: 220px;
    font-size: var(--font-size-body);
    color: var(--color-text);
    line-height: 1.45;
}
.hp-launch-banner .btn { flex-shrink: 0; }
.hp-manage-grid {
    display: grid;
    grid-template-columns: 320px 1fr;
    gap: 24px;
}
@media (max-width: 900px) {
    .hp-manage-grid { grid-template-columns: 1fr; }
}
.hp-manage-settings,
.hp-manage-excursions {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 16px;
}
.hp-manage-excursions { display: flex; flex-direction: column; }
.hp-manage-settings h3,
.hp-manage-excursions h3 { margin: 0 0 12px; font-size: var(--font-size-subheading); }

.hp-exc-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 8px;
}
.hp-exc-toggle {
    border: 1px solid var(--color-border);
    background: var(--color-card);
    color: var(--color-text);
    padding: 6px 12px;
    border-radius: 999px;
    font-size: var(--font-size-small);
    cursor: pointer;
    transition: background 120ms ease;
}
.hp-exc-toggle:hover {
    background: color-mix(in srgb, var(--cd-color-programme, #d4930a) 8%, var(--color-card));
}
.hp-exc-toggle--on {
    background: color-mix(in srgb, var(--cd-color-programme, #d4930a) 22%, var(--color-card));
    border-color: var(--cd-color-programme, #d4930a);
    color: var(--color-text);
}

.hp-exc-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}
.hp-exc-row .form-group {
    flex: 1;
    min-width: 0;
    margin-bottom: 0;
}
.hp-exc-row .form-group input { padding: 8px 8px; }
.hp-exc-row .hp-exc-title-group { flex: 2; }

.hp-manage-enrollments {
    margin-top: 24px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 16px;
}
.hp-manage-enrollments h3 { margin: 0 0 12px; font-size: var(--font-size-subheading); }
.hp-manage-enrollments--empty { background: transparent; border-color: transparent; }

.hp-override-student { margin: 0 0 12px; }
.hp-override-summary {
    margin: 12px 0;
    padding: 10px 12px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 8px;
}

/* --- Holiday Programme - Motion --- */

/* Pricing reveal: expand/collapse with CSS grid height trick */
.hp-pricing-reveal {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 300ms var(--ease-out);
}
.hp-pricing-reveal.visible { grid-template-rows: 1fr; }
.hp-pricing-reveal.instant { transition: none; }
.hp-pricing-reveal > div { min-height: 0; overflow: hidden; }

/* Calendar cell: smooth pick / release */
.hp-cal-wrap .cal-cell {
    transition: background 140ms var(--ease-out), box-shadow 140ms var(--ease-out),
                transform 100ms var(--ease-out), opacity 150ms var(--ease-out);
}
.hp-cal-wrap .cal-cell.hp-pressing:not(.hp-cell--locked):not(.hp-cell--out-of-range):not(.hp-cell--closed) {
    transform: scale(0.88);
}

/* Excursions-unlocked celebration pop */
@keyframes hpSparkleIn {
    0%  { transform: scale(0.7) translateY(4px); opacity: 0; }
    65% { transform: scale(1.1) translateY(-1px); opacity: 1; }
    100% { transform: scale(1) translateY(0); opacity: 1; }
}
.hp-sparkle { display: inline-block; animation: hpSparkleIn 360ms var(--ease-spring) both; }

/* Day counter number bump */
@keyframes hpCounterBump {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.2); }
    100% { transform: scale(1); }
}
.hp-day-counter strong.hp-bump {
    display: inline-block;
    animation: hpCounterBump 220ms var(--ease-spring);
}

/* Button press squash */
.hp-cost-panel .btn { transition: transform 100ms var(--ease-out); }
.hp-cost-panel .btn.hp-pressing { transform: scale(0.93); }
#hpLegend .btn { transition: transform 100ms var(--ease-out); }
#hpLegend .btn.hp-pressing { transform: scale(0.90); }
#hpLegend .btn.hp-legend-toggle { min-width: 96px; text-align: center; }

@media (prefers-reduced-motion: reduce) {
    .hp-pricing-reveal { transition: none; }
    .hp-pricing-reveal.visible { grid-template-rows: 1fr; }
    .hp-cal-wrap .cal-cell { transition: none; }
    .hp-sparkle, .hp-day-counter strong.hp-bump { animation: none; }
}

/* Print rules - only the .payslip-pdf or .invoice-detail-print-wrapper visible */
@media print {
    body * { visibility: hidden; }
    .payslip-pdf, .payslip-pdf *,
    .invoice-detail-print-wrapper, .invoice-detail-print-wrapper * {
        visibility: visible;
    }
    .modal-overlay {
        position: static;
        background: transparent;
        display: block !important;
    }
    .modal {
        max-width: 100% !important;
        box-shadow: none;
    }
    .modal-close,
    .invoice-detail-actions,
    .payslip-detail-actions { display: none !important; }
    .payslip-pdf, .invoice-detail-print-wrapper {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
    }
}

/* ═══ Attendance Summary ═══ */
/* Attendance Summary — month calendar picker (inside the date modal) */
.att-cal-wrap { margin-top: 4px; }
.att-cal-wrap .cal-grid { margin-top: 2px; }
/* Numeric count chip shown under a day number in the picker grid */
.att-count-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 16px;
    padding: 0 4px;
    border-radius: 4px;
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1;
    color: var(--color-on-primary);
    background: var(--color-success);   /* checked-in (actual) — green */
    flex-shrink: 0;
}
/* Future days: expected count — gold, echoing the holiday-programme chip */
.att-count-chip--expected { background: var(--cd-color-programme, #d4930a); }
.att-count-chip--legend { min-width: 16px; }
.att-cal-legend {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    justify-content: center;
    margin-top: 12px;
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.att-cal-legend-item { display: inline-flex; align-items: center; gap: 6px; }

.att-summary-header {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}
.att-summary-stepper {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--color-bg);
    border-radius: 999px;
    padding: 4px;
}
.att-summary-step {
    width: 36px;
    height: 36px;
    border: none;
    background: transparent;
    color: var(--color-text);
    font-size: 1.3rem;
    line-height: 1;
    border-radius: 999px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.att-summary-step:hover:not(:disabled) { background: var(--color-card); }
.att-summary-step:disabled { opacity: 0.3; cursor: default; }
.att-summary-date {
    background: var(--color-card);
    border: none;
    border-radius: 999px;
    padding: 8px 18px;
    font-weight: 600;
    color: var(--color-text);
    cursor: pointer;
    min-width: 200px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.08);
    font-size: 0.95rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
}
.att-summary-date-counts {
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--color-text-light);
    min-height: 1em;
}
.att-summary-today {
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    padding: 7px 14px;
    color: var(--color-text-light);
    font-weight: 500;
    cursor: pointer;
    font-size: 0.85rem;
}
.att-summary-today:hover {
    color: var(--color-text);
    border-color: var(--color-text-light);
}

.att-summary-banner {
    background: rgba(255, 165, 0, 0.08);
    border: 1px solid rgba(255, 165, 0, 0.35);
    border-radius: 12px;
    padding: 12px 16px;
    margin-bottom: 18px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.att-summary-banner-text {
    color: var(--color-warning);
    font-weight: 500;
}
.att-summary-banner-text i { margin-right: 6px; }
.att-summary-banner-actions {
    display: flex;
    gap: 8px;
    align-items: center;
}
.att-summary-banner-action {
    background: transparent;
    border: none;
    color: var(--color-warning);
    font-weight: 500;
    cursor: pointer;
    padding: 6px 10px;
    text-decoration: underline;
    font-size: 0.9rem;
}

.att-summary-counters {
    display: flex;
    gap: 36px;
    margin-bottom: 22px;
    flex-wrap: wrap;
}
.att-summary-counter-value {
    font-size: 2rem;
    font-weight: 600;
    color: var(--color-text);
    line-height: 1;
}
.att-summary-counter-label {
    font-size: 0.72rem;
    color: var(--color-text-light);
    text-transform: uppercase;
    letter-spacing: 0.6px;
    margin-top: 6px;
}

.att-summary-filterbar {
    font-size: 0.85rem;
    color: var(--color-text-light);
    margin-bottom: 12px;
}
.att-summary-clear-link {
    background: none;
    border: none;
    color: var(--color-primary);
    cursor: pointer;
    padding: 0;
    font-size: 0.85rem;
    text-decoration: underline;
}

.att-summary-list {
    display: flex;
    flex-direction: column;
}
.att-summary-row {
    display: grid;
    grid-template-columns: 52px 1fr 44px;
    grid-template-areas:
        "time main thumb"
        ".    status status";
    column-gap: 14px;
    row-gap: 4px;
    align-items: center;
    padding: 14px 0;
    border-bottom: 1px solid var(--color-border);
}
.att-summary-row:last-child { border-bottom: none; }
.att-summary-row-time {
    grid-area: time;
    font-variant-numeric: tabular-nums;
    color: var(--color-text);
    font-weight: 500;
}
.att-summary-row-main {
    grid-area: main;
    min-width: 0;
}
.att-summary-row-name {
    font-weight: 600;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.att-summary-row-meta {
    font-size: 0.85rem;
    color: var(--color-text-light);
    margin-top: 2px;
}
.att-summary-row-status {
    grid-area: status;
    font-size: 0.82rem;
    color: var(--color-warning);
}
.att-summary-row-status i { margin-right: 4px; }
.att-summary-thumb {
    grid-area: thumb;
    width: 44px;
    height: 44px;
    border-radius: 10px;
    border: none;
    padding: 0;
    overflow: hidden;
    cursor: pointer;
    background: var(--color-bg);
}
.att-summary-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.att-summary-thumb-empty {
    color: var(--color-text-light);
    font-size: 0.9rem;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: default;
}

/* Expected-attendance view (future dates) — gold accent so it reads clearly
   as "scheduled to attend", not actual check-ins. */
.att-summary-expected-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 14px;
    padding: 10px 14px;
    border-radius: 10px;
    font-size: 0.9rem;
    color: var(--color-text);
    background: color-mix(in srgb, var(--cd-color-programme, #d4930a) 12%, var(--color-card));
    border: 1px solid color-mix(in srgb, var(--cd-color-programme, #d4930a) 40%, var(--color-card));
}
.att-summary-expected-banner i { color: var(--cd-color-programme, #d4930a); }
.att-summary-row--expected {
    grid-template-columns: 1fr 44px;
    grid-template-areas: "main thumb";
    border-left: 3px solid var(--cd-color-programme, #d4930a);
    padding-left: 12px;
}
.att-expected-pill {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1.5;
    color: var(--color-on-primary);
    background: var(--cd-color-programme, #d4930a);
}
.att-summary-thumb--avatar {
    border-radius: 50%;
    cursor: default;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--color-text-light);
}

.att-summary-photo-modal {
    max-width: 520px;
    padding: 0;
    background: var(--color-card);
    overflow: hidden;
}
.att-summary-photo-modal img {
    display: block;
    width: 100%;
    height: auto;
    background: var(--color-bg);
}
.att-summary-photo-modal #attendancePhotoCaption {
    padding: 12px 16px;
    text-align: center;
    color: var(--color-text);
    font-weight: 500;
}

@media (max-width: 640px) {
    .att-summary-header {
        gap: 8px;
    }
    .att-summary-stepper {
        flex: 1;
        min-width: 0;
    }
    .att-summary-date {
        flex: 1;
        min-width: 0;
        padding: 8px 12px;
    }
}

/* ── Expense Claims upload options ── */
.ec-upload-options {
    display: flex;
    gap: 10px;
    margin-bottom: 16px;
}
.ec-upload-option {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 14px 8px;
    border: 1.5px solid var(--color-border);
    border-radius: 10px;
    background: var(--color-surface);
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
    user-select: none;
    -webkit-user-select: none;
    text-align: center;
    gap: 6px;
}
.ec-upload-option:hover { border-color: var(--color-primary-light); }
.ec-upload-option.is-selected {
    border-color: var(--color-primary);
    background: var(--color-primary-soft);
}
.ec-upload-option__icon { font-size: 22px; color: var(--color-primary); line-height: 1; }
.ec-upload-option__label { font-size: var(--font-size-label); font-weight: 600; color: var(--color-text); line-height: 1.3; }
.ec-upload-dropzone {
    margin-bottom: 16px;
    border: 1.5px dashed var(--color-border);
    border-radius: 10px;
    padding: 18px 12px;
    text-align: center;
    transition: border-color 0.15s, background 0.15s;
}
.ec-upload-dropzone.is-dragover {
    border-color: var(--color-primary);
    background: var(--color-primary-soft);
}
.ec-upload-dropzone.has-file {
    border-style: solid;
    padding: 12px;
}
.ec-upload-dropzone-hint {
    font-size: var(--font-size-small);
    color: var(--color-text-light);
}
.ec-upload-dropzone.has-file .ec-upload-dropzone-hint { display: none; }
/* Touch devices: no drag-and-drop - collapse the empty zone entirely */
@media (hover: none), (pointer: coarse) {
    .ec-upload-dropzone:not(.has-file) { display: none; }
}
.ec-upload-preview { margin-bottom: 0; display: none; text-align: center; }
.ec-upload-thumb { max-height: 120px; max-width: 100%; border-radius: 8px; object-fit: contain; }
.ec-upload-filename-pill {
    display: inline-block;
    padding: 6px 12px;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: 20px;
    font-size: var(--font-size-small);
    color: var(--color-text);
    word-break: break-all;
    max-width: 100%;
}
@media (max-width: 380px) {
    .ec-upload-options { flex-direction: column; }
}
.ec-meta-pill {
    display: inline-block;
    padding: 1px 7px;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: 20px;
    font-size: 11px;
    color: var(--color-muted);
    margin-right: 4px;
    white-space: nowrap;
}
.ec-section-heading {
    font-size: var(--font-size-body);
    font-weight: 600;
    margin: 0 0 8px;
    color: var(--color-text);
}
.ec-inline-input {
    padding: 6px 10px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font-size: var(--font-size-body);
    background: var(--color-card);
    color: var(--color-text);
    transition: border-color 0.2s;
    max-width: 240px;
    width: 100%;
    box-sizing: border-box;
}
.ec-inline-input:focus {
    outline: none;
    border-color: var(--color-primary);
}
/* Manage Expense Claims — Log action badges, AI-learning pills, vendor chips, summary chevron */
.ec-log-badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 10px;
    font-size: var(--font-size-small);
    font-weight: 600;
    color: var(--color-on-primary);
    background: var(--color-text-light);
}
.ec-log-badge--upload  { background: var(--color-primary); }
.ec-log-badge--edit    { background: var(--color-warning); }
.ec-log-badge--delete  { background: var(--color-danger); }
.ec-log-badge--restore { background: var(--color-success); }
.ec-learn-pill {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 9px;
    font-size: var(--font-size-small);
    font-weight: 600;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.ec-vendor-chip {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 12px;
    font-size: var(--font-size-small);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
}
.ec-summary-chevron {
    display: inline-block;
    min-width: 9px;
    margin-right: 8px;
    font-size: 9px;
    opacity: 0.45;
}
/* Quiet row-delete icon — matches the inline edit pencil's muted weight,
   reddens only on hover (no wall of red on routine config rows). */
.ec-row-delete {
    border: none;
    background: none;
    color: var(--color-text-light);
    cursor: pointer;
    padding: 6px 8px;
    line-height: 1;
    font-size: var(--font-size-body);
    border-radius: 6px;
    transition: color 0.15s;
}
.ec-row-delete:hover { color: var(--color-danger); }
