/* ═══════════════════════════════════════════
   Jam3ah – Admin Dashboard
   Self-contained dark theme (navy brand)
   ═══════════════════════════════════════════ */

@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&family=DM+Sans:wght@400;500;600&family=Noto+Kufi+Arabic:wght@400;500&display=swap');

/* ── Design Tokens ── */
:root {
    --bg-primary: #0A0D1A;
    --bg-secondary: #101428;
    --bg-card: rgba(16, 20, 40, 0.7);
    --bg-input: rgba(16, 20, 40, 0.6);

    --text-primary: #F1F3F9;
    --text-secondary: #9BA3C2;
    --text-muted: #636D8C;

    --accent-primary: #2E3192;
    --accent-light: #7B80D4;
    --accent-glow: rgba(46, 49, 146, 0.3);

    --border-default: rgba(155, 163, 194, 0.12);
    --border-focus: #2E3192;

    --error-color: #EF4136;
    --success-color: #22C55E;

    --font-display: 'Outfit', sans-serif;
    --font-body: 'DM Sans', sans-serif;

    --space-xs: 4px;
    --space-sm: 8px;
    --space-md: 16px;
    --space-lg: 24px;
    --space-xl: 32px;
    --space-2xl: 48px;
    --space-3xl: 64px;

    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;

    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --duration-fast: 150ms;
    --duration-normal: 250ms;
}

/* ── Reset ── */
*,
*::before,
*::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    font-size: 16px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    font-family: var(--font-body);
    background: var(--bg-primary);
    color: var(--text-primary);
    min-height: 100vh;
}

/* ── Background ── */
.bg-grid {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 0;
    background:
        radial-gradient(ellipse at top left, rgba(46, 49, 146, 0.05) 0%, transparent 50%),
        radial-gradient(ellipse at bottom right, rgba(239, 65, 54, 0.03) 0%, transparent 50%);
}

.bg-glow {
    display: none;
}

/* ── Layout ── */
.admin-layout {
    display: flex;
    min-height: 100vh;
    position: relative;
    z-index: 1;
}

/* ── Sidebar ── */
.sidebar {
    width: 240px;
    background: rgba(17, 24, 39, 0.85);
    backdrop-filter: blur(20px);
    border-right: 1px solid var(--border-default);
    padding: var(--space-lg);
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 50;
    transition: transform var(--duration-normal) var(--ease-out);
}

.sidebar-header {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-2xl);
    padding-bottom: var(--space-lg);
    border-bottom: 1px solid var(--border-default);
}

.sidebar-brand {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    background: linear-gradient(135deg, var(--text-primary), var(--accent-light));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.nav-item {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 10px 14px;
    font-family: var(--font-body);
    font-size: 0.9rem;
    color: var(--text-secondary);
    text-decoration: none;
    border-radius: var(--radius-sm);
    transition: all var(--duration-fast) var(--ease-out);
    cursor: pointer;
}

.nav-item:hover {
    background: rgba(148, 163, 184, 0.08);
    color: var(--text-primary);
}

.nav-item.active {
    background: rgba(46, 49, 146, 0.1);
    color: var(--accent-light);
}

.nav-item.active svg {
    color: var(--accent-primary);
}

/* ── Main ── */
.admin-main {
    flex: 1;
    margin-left: 240px;
    padding: var(--space-lg) var(--space-xl);
    min-width: 0;
}

/* ── Header ── */
.admin-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-lg);
    flex-wrap: wrap;
    gap: var(--space-md);
}

.header-left {
    display: flex;
    align-items: center;
    gap: var(--space-md);
}

.menu-toggle {
    display: none;
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 4px;
}

.admin-title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--text-primary);
}

.header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.submission-count {
    font-size: 0.85rem;
    color: var(--text-muted);
    padding: 6px 14px;
    background: var(--bg-input);
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-default);
}

/* ── Action Buttons ── */
.action-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    font-family: var(--font-body);
    font-size: 0.85rem;
    font-weight: 500;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all var(--duration-fast) var(--ease-out);
    background: var(--bg-input);
    color: var(--text-secondary);
}

.action-btn:hover {
    border-color: rgba(148, 163, 184, 0.3);
    color: var(--text-primary);
    background: rgba(148, 163, 184, 0.08);
}

.export-btn:hover {
    border-color: var(--accent-primary);
    color: var(--accent-light);
    background: rgba(46, 49, 146, 0.08);
}

.delete-btn {
    color: var(--error-color);
    border-color: rgba(239, 68, 68, 0.2);
}

.delete-btn:hover {
    background: rgba(239, 68, 68, 0.1);
    border-color: rgba(239, 68, 68, 0.4);
    color: #FCA5A5;
}

.clear-btn {
    padding: 8px 12px;
}

/* ── Filters ── */
.filters-bar {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
    flex-wrap: wrap;
}

.search-box {
    position: relative;
    flex: 1;
    min-width: 200px;
}

.search-box svg {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-muted);
    pointer-events: none;
}

.filter-input {
    width: 100%;
    padding: 9px 14px 9px 40px;
    font-family: var(--font-body);
    font-size: 0.875rem;
    color: var(--text-primary);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    outline: none;
    transition: all var(--duration-fast);
}

.filter-input:focus {
    border-color: var(--border-focus);
    box-shadow: 0 0 0 2px var(--accent-glow);
}

.filter-input::placeholder {
    color: var(--text-muted);
}

.filter-select {
    padding: 9px 14px;
    font-family: var(--font-body);
    font-size: 0.875rem;
    color: var(--text-primary);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    outline: none;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    min-width: 150px;
}

.filter-select option {
    background: var(--bg-secondary);
    color: var(--text-primary);
}

.filter-select:focus {
    border-color: var(--border-focus);
}

.filter-date {
    padding-left: 14px;
    min-width: 140px;
    color-scheme: dark;
}

/* ── Data Table ── */
.table-wrapper {
    background: rgba(17, 24, 39, 0.5);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.875rem;
}

.data-table thead {
    background: rgba(46, 49, 146, 0.06);
}

.data-table th {
    padding: 12px 16px;
    text-align: left;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 0.8rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 1px solid var(--border-default);
    white-space: nowrap;
}

.data-table td {
    padding: 12px 16px;
    color: var(--text-secondary);
    border-bottom: 1px solid rgba(148, 163, 194, 0.06);
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.data-table tbody tr {
    transition: background var(--duration-fast);
    cursor: pointer;
}

.data-table tbody tr:hover {
    background: rgba(46, 49, 146, 0.04);
}

.data-table tbody tr:hover td {
    color: var(--text-primary);
}

.td-name {
    font-weight: 500;
    color: var(--text-primary) !important;
}

.td-university {
    color: var(--accent-light) !important;
    font-size: 0.8rem;
    font-weight: 500;
}

.td-actions {
    display: flex;
    gap: 4px;
}

.icon-btn {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px;
    border-radius: 6px;
    display: flex;
    align-items: center;
    transition: all var(--duration-fast);
}

.icon-btn:hover {
    background: rgba(148, 163, 184, 0.1);
    color: var(--text-primary);
}

.icon-btn.delete:hover {
    background: rgba(239, 68, 68, 0.1);
    color: var(--error-color);
}

/* ── WhatsApp Button ── */
.wa-btn {
    text-decoration: none;
}

.wa-btn:hover {
    background: rgba(37, 211, 102, 0.15);
}

.wa-btn svg {
    transition: transform var(--duration-fast);
}

.wa-btn:hover svg {
    transform: scale(1.15);
}

/* ── HR sub-tabs (Appointments / CV Vault / Requests / Approve to Hire) ── */
.subtabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    padding: var(--space-xs);
    margin-bottom: var(--space-md);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    width: fit-content;
    max-width: 100%;
}
.subtab-btn {
    padding: 9px 20px;
    font-family: var(--font-display);
    font-size: 0.88rem;
    font-weight: 500;
    color: var(--text-secondary);
    background: transparent;
    border: none;
    border-radius: calc(var(--radius-sm) - 2px);
    cursor: pointer;
    transition: all var(--duration-fast) var(--ease-out);
    white-space: nowrap;
}
.subtab-btn:hover { color: var(--text-primary); }
.subtab-btn.active {
    color: #fff;
    background: var(--accent-primary);
}
.hr-subview { display: none; }
.hr-subview.active { display: block; }

/* ── Segmented toggle (appointment: existing request / without request) ── */
.seg-toggle {
    display: inline-flex;
    gap: var(--space-xs);
    padding: var(--space-xs);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
}
.seg-btn {
    padding: 8px 18px;
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-secondary);
    background: transparent;
    border: none;
    border-radius: calc(var(--radius-sm) - 2px);
    cursor: pointer;
    transition: all var(--duration-fast) var(--ease-out);
}
.seg-btn:hover { color: var(--text-primary); }
.seg-btn.active {
    color: #fff;
    background: var(--accent-primary);
}
.field-hint {
    margin: 6px 0 0;
    font-size: 0.78rem;
    color: var(--text-muted);
}
.wa-send-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: #25D366;
    color: #fff;
    border: none;
}
.wa-send-btn:hover { background: #1EBE5A; color: #fff; }
.phone-row { display: flex; gap: var(--space-sm); }
.phone-row select { flex: 0 0 auto; max-width: 48%; }
.phone-row input { flex: 1 1 auto; min-width: 0; }

.wa-contact-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 20px;
    font-family: var(--font-display);
    font-size: 0.9rem;
    font-weight: 500;
    color: #fff;
    background: #25D366;
    border: none;
    border-radius: var(--radius-sm);
    text-decoration: none;
    transition: all var(--duration-normal) var(--ease-out);
    cursor: pointer;
}

.wa-contact-btn:hover {
    background: #128C7E;
    transform: translateY(-1px);
    box-shadow: 0 4px 16px rgba(37, 211, 102, 0.3);
}

/* ── Empty State ── */
.empty-state {
    padding: var(--space-3xl) var(--space-lg);
    text-align: center;
    color: var(--text-muted);
}

.empty-state svg {
    opacity: 0.3;
    margin-bottom: var(--space-md);
}

.empty-title {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 500;
    color: var(--text-secondary);
    margin-bottom: var(--space-xs);
}

.empty-text {
    font-size: 0.875rem;
}

/* ── Loading State ── */
.loading-state {
    padding: var(--space-3xl) var(--space-lg);
    text-align: center;
    color: var(--text-muted);
    font-size: 0.9rem;
}

.loading-spinner {
    width: 32px;
    height: 32px;
    border: 2px solid var(--border-default);
    border-top-color: var(--accent-primary);
    border-radius: 50%;
    margin: 0 auto var(--space-md);
    animation: spin 0.8s linear infinite;
}

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

/* ── Modal Overlay ── */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(10, 13, 26, 0.7);
    backdrop-filter: blur(6px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
    opacity: 0;
    visibility: hidden;
    transition: all var(--duration-normal) var(--ease-out);
    padding: var(--space-md);
}

.modal-overlay.active {
    opacity: 1;
    visibility: visible;
}

.modal-content {
    background: var(--bg-secondary);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    text-align: center;
    max-width: 420px;
    width: 100%;
    box-shadow: 0 8px 40px rgba(0, 0, 0, 0.4);
    transform: scale(0.9) translateY(20px);
    transition: transform 0.3s var(--ease-out);
}

.modal-overlay.active .modal-content {
    transform: scale(1) translateY(0);
}

.modal-title {
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: var(--space-sm);
}

.modal-text {
    font-size: 0.9rem;
    color: var(--text-secondary);
    line-height: 1.6;
}

.modal-icon {
    margin-bottom: var(--space-md);
}

.modal-btn {
    padding: 10px 24px;
    font-family: var(--font-display);
    font-size: 0.9rem;
    font-weight: 500;
    color: #fff;
    background: var(--accent-primary);
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all var(--duration-normal);
}

.modal-btn:hover {
    background: #1F2270;
}

/* ── Detail Modal ── */
.detail-modal-content {
    max-width: 560px;
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    text-align: left;
}

.detail-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-bottom: var(--space-md);
    border-bottom: 1px solid var(--border-default);
    margin-bottom: var(--space-lg);
}

.modal-close {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 4px;
    transition: color var(--duration-fast);
}

.modal-close:hover {
    color: var(--text-primary);
}

.detail-body {
    overflow-y: auto;
    flex: 1;
}

.detail-row {
    display: flex;
    padding: 10px 0;
    border-bottom: 1px solid rgba(148, 163, 184, 0.06);
}

.detail-label {
    width: 150px;
    flex-shrink: 0;
    font-size: 0.8rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-family: var(--font-display);
}

.detail-value {
    flex: 1;
    font-size: 0.9rem;
    color: var(--text-primary);
    word-break: break-word;
}

.detail-files {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.detail-file-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--accent-light);
    text-decoration: none;
    font-size: 0.85rem;
    padding: 4px 8px;
    background: rgba(46, 49, 146, 0.06);
    border-radius: 6px;
    transition: background var(--duration-fast);
}

.detail-file-link:hover {
    background: rgba(46, 49, 146, 0.12);
}

.detail-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-top: var(--space-md);
    border-top: 1px solid var(--border-default);
    margin-top: var(--space-lg);
}

.modal-actions {
    display: flex;
    gap: var(--space-sm);
    justify-content: center;
    margin-top: var(--space-lg);
}

/* ── Responsive ── */
@media (max-width: 900px) {
    .sidebar {
        transform: translateX(-100%);
        /* Keep the drawer content below the iPhone status bar / notch. */
        padding-top: calc(var(--space-lg) + env(safe-area-inset-top));
    }

    .sidebar.open {
        transform: translateX(0);
    }

    .admin-main {
        margin-left: 0;
        padding: 0 var(--space-md) var(--space-md);
    }

    /* App-like top bar: full-width, sticky, and pushed below the iPhone status
       bar (safe-area) so the menu button is actually reachable in the installed
       PWA instead of hiding under the clock/notch. */
    .admin-header {
        position: sticky;
        top: 0;
        z-index: 40;
        margin: 0 calc(-1 * var(--space-md)) var(--space-md);
        padding: calc(8px + env(safe-area-inset-top)) var(--space-md) 8px;
        background: rgba(10, 13, 26, 0.92);
        -webkit-backdrop-filter: blur(14px);
        backdrop-filter: blur(14px);
        border-bottom: 1px solid var(--border-default);
    }

    .menu-toggle {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        margin-left: -8px;
        border-radius: var(--radius-sm);
        flex-shrink: 0;
    }

    .menu-toggle:active {
        background: rgba(148, 163, 184, 0.15);
    }

    .filters-bar {
        flex-direction: column;
        align-items: stretch;
    }

    .search-box {
        min-width: 100%;
    }

    .data-table th:nth-child(5),
    .data-table td:nth-child(5),
    .data-table th:nth-child(6),
    .data-table td:nth-child(6) {
        display: none;
    }
}

@media (max-width: 600px) {
    .header-actions {
        width: 100%;
        justify-content: flex-end;
    }

    .data-table th:nth-child(7),
    .data-table td:nth-child(7) {
        display: none;
    }

    .admin-title {
        font-size: 1.2rem;
    }
}

/* ── Google Drive Backup Section ── */
.backup-section {
    margin-top: var(--space-xl);
    background: rgba(17, 24, 39, 0.5);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.backup-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-lg);
    border-bottom: 1px solid var(--border-default);
}

.backup-title-row {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.backup-title {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-primary);
}

.backup-status {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85rem;
}

.status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.status-dot.connected {
    background: var(--success-color);
    box-shadow: 0 0 8px rgba(34, 197, 94, 0.4);
}

.status-dot.disconnected {
    background: var(--text-muted);
}

.status-text {
    color: var(--text-secondary);
}

.backup-body {
    padding: var(--space-lg);
}

.backup-notice {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding: var(--space-md);
    background: rgba(239, 65, 54, 0.06);
    border: 1px solid rgba(239, 65, 54, 0.15);
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
    color: var(--text-secondary);
    line-height: 1.5;
}

.backup-notice svg {
    flex-shrink: 0;
    margin-top: 1px;
}

.backup-notice strong {
    color: var(--error-color);
}

.backup-desc {
    font-size: 0.9rem;
    color: var(--text-secondary);
    margin-bottom: var(--space-md);
}

.backup-info {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
    padding: var(--space-md);
    background: rgba(46, 49, 146, 0.04);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
}

.backup-info-row {
    display: flex;
    justify-content: space-between;
    font-size: 0.85rem;
}

.info-label {
    color: var(--text-muted);
}

.info-value {
    color: var(--text-primary);
    font-weight: 500;
}

.backup-actions {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
}

.gdrive-btn {
    background: var(--accent-primary);
    color: #fff;
    border-color: var(--accent-primary);
}

.gdrive-btn:hover {
    background: #1F2270;
    color: #fff;
    border-color: #1F2270;
}

.backup-now-btn {
    background: var(--accent-primary);
    color: #fff;
    border-color: var(--accent-primary);
}

.backup-now-btn:hover {
    background: #1F2270;
    border-color: #1F2270;
    color: #fff;
}

.restore-btn {
    background: var(--bg-input);
    color: var(--text-secondary);
}

.restore-btn:hover {
    background: rgba(148, 163, 184, 0.08);
    color: var(--text-primary);
}

.disconnect-btn {
    background: none;
    border-color: rgba(239, 68, 68, 0.2);
    color: var(--text-muted);
    font-size: 0.8rem;
}

.disconnect-btn:hover {
    background: rgba(239, 68, 68, 0.08);
    border-color: rgba(239, 68, 68, 0.3);
    color: var(--error-color);
}

/* ═══════════════════════════════════════════
   CRM additions
   ═══════════════════════════════════════════ */

/* Sidebar footer (current admin) */
.sidebar-footer {
    margin-top: auto;
    padding: var(--space-md) var(--space-lg);
    border-top: 1px solid var(--border-default);
}
.current-admin {
    font-size: 0.85rem;
    color: var(--text-secondary);
    font-family: var(--font-display);
}

/* Generic panel section (reused by Admins + Drive backup) */
.panel-section {
    margin-top: var(--space-xl);
    background: rgba(17, 24, 39, 0.5);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
.panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-lg);
    border-bottom: 1px solid var(--border-default);
}
.panel-title {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-primary);
}
.panel-body { padding: var(--space-lg); }

/* Dashboard stat cards */
.stats-row {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
}
.stat-card {
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    padding: var(--space-md) var(--space-lg);
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.stat-card[data-status] { cursor: pointer; transition: border-color var(--duration-fast), transform var(--duration-fast); }
.stat-card[data-status]:hover { border-color: var(--accent-light); transform: translateY(-2px); }
.stat-value { font-family: var(--font-display); font-size: 1.8rem; font-weight: 700; color: var(--text-primary); line-height: 1.1; }
.stat-label { font-size: 0.8rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
.stat-sub { font-size: 0.72rem; color: var(--text-muted); margin-top: 2px; }
.stat-new { border-left: 3px solid #6366F1; }
.stat-processing { border-left: 3px solid #F59E0B; }
.stat-completed { border-left: 3px solid #22C55E; }
.stat-cancelled { border-left: 3px solid #EF4444; }
.stat-total { border-left: 3px solid var(--accent-light); }

/* Status badges */
.badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    font-family: var(--font-display);
    letter-spacing: 0.02em;
    white-space: nowrap;
    vertical-align: middle;
}
.badge-new { background: rgba(99, 102, 241, 0.15); color: #A5A8FF; }
.badge-processing { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.badge-completed { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }
.badge-cancelled { background: rgba(239, 68, 68, 0.15); color: #F87171; }

/* Inline link */
.link { color: var(--accent-light); text-decoration: none; }
.link:hover { text-decoration: underline; }

/* Detail modal layout */
.detail-grid { margin-bottom: var(--space-md); }
.detail-section {
    padding-top: var(--space-md);
    margin-top: var(--space-md);
    border-top: 1px solid var(--border-default);
}
.detail-section .detail-label { width: auto; margin-bottom: var(--space-sm); display: block; }

/* Status pipeline buttons */
.status-pipeline { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.status-btn {
    padding: 8px 16px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-default);
    background: var(--bg-input);
    color: var(--text-secondary);
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: 500;
    cursor: pointer;
    transition: all var(--duration-fast);
}
.status-btn:hover { border-color: var(--accent-light); color: var(--text-primary); }
.status-btn.active { cursor: default; }
.status-btn.status-new.active { background: rgba(99, 102, 241, 0.18); color: #A5A8FF; border-color: #6366F1; }
.status-btn.status-processing.active { background: rgba(245, 158, 11, 0.18); color: #FBBF24; border-color: #F59E0B; }
.status-btn.status-completed.active { background: rgba(34, 197, 94, 0.18); color: #4ADE80; border-color: #22C55E; }
.status-btn.status-cancelled.active { background: rgba(239, 68, 68, 0.18); color: #F87171; border-color: #EF4444; }

.status-note-wrap { margin-top: var(--space-sm); }
.status-note-actions, .note-actions { display: flex; gap: var(--space-sm); justify-content: flex-end; margin-top: var(--space-sm); }

/* Note textarea */
.note-input {
    width: 100%;
    min-height: 70px;
    resize: vertical;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-default);
    background: var(--bg-input);
    color: var(--text-primary);
    font-family: var(--font-body);
    font-size: 0.9rem;
    outline: none;
}
.note-input:focus { border-color: var(--border-focus); }
.note-input.error { border-color: var(--error-color); }

/* Activity timeline */
.timeline { display: flex; flex-direction: column; gap: var(--space-sm); max-height: 280px; overflow-y: auto; }
.timeline-empty { color: var(--text-muted); font-size: 0.85rem; }
.timeline-item {
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    background: var(--bg-input);
    border-left: 3px solid var(--border-default);
}
.timeline-item.ti-status { border-left-color: var(--accent-light); }
.timeline-item.ti-note { border-left-color: #F59E0B; }
.timeline-item.ti-assign { border-left-color: #22C55E; }

/* Assignment row (detail modal) */
.assign-row { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; }
.assign-who { font-size: 0.9rem; color: var(--text-primary); }
.assign-who .muted { color: var(--text-muted); }
.ti-head { font-size: 0.85rem; color: var(--text-primary); }
.ti-meta { color: var(--text-muted); font-size: 0.75rem; font-weight: 400; }
.ti-body { margin-top: 4px; font-size: 0.85rem; color: var(--text-secondary); white-space: pre-wrap; }

/* Admins list */
.admins-list { display: flex; flex-direction: column; gap: var(--space-sm); margin-bottom: var(--space-lg); }
.admin-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
}
.admin-meta { display: flex; flex-direction: column; }
.admin-name { font-weight: 600; color: var(--text-primary); }
.admin-username { font-size: 0.8rem; color: var(--text-muted); }
.admin-actions { display: flex; align-items: center; gap: var(--space-sm); }
.add-admin-form { border-top: 1px solid var(--border-default); padding-top: var(--space-lg); }
.add-admin-title { font-family: var(--font-display); font-size: 0.95rem; color: var(--text-secondary); margin-bottom: var(--space-sm); }
.add-admin-fields { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.add-admin-fields .filter-input { flex: 1; min-width: 150px; }
.add-admin-error { color: var(--error-color); font-size: 0.85rem; margin-top: var(--space-sm); min-height: 1em; }

@media (max-width: 900px) {
    .stats-row { grid-template-columns: repeat(2, 1fr); }
}

/* ═══════════════════════════════════════════
   Appointments + Teachers + PWA additions
   ═══════════════════════════════════════════ */

/* Tab views: one visible at a time */
.view { display: none; }
.view.active { display: block; }
.panel-section.no-top-margin { margin-top: 0; }

/* Inputs used inside modal forms (no search icon → normal padding) */
.filter-input.no-icon { padding-left: 14px; }
.filter-select.full-width { width: 100%; }
.filter-input, .filter-select { color-scheme: dark; }

/* Form layout in modals */
.form-field { margin-bottom: var(--space-md); }
.form-field .detail-label { width: auto; display: block; margin-bottom: 6px; }
.form-row { display: flex; gap: var(--space-sm); flex-wrap: wrap; }
.form-row .form-field.grow { flex: 1; min-width: 160px; }

.check-row {
    display: flex; align-items: center; gap: 10px;
    font-size: 0.9rem; color: var(--text-primary);
    cursor: pointer; padding: 6px 0;
}
.check-row input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--accent-primary); cursor: pointer; }
.check-row.indent { margin-left: 26px; color: var(--text-secondary); }
.check-row input:disabled + span { color: var(--text-muted); }

/* Request picker (search a request by name / contact number) */
.req-picker { position: relative; }
.req-results {
    position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
    background: var(--bg-secondary);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
    max-height: 240px; overflow-y: auto;
}
.req-result-item {
    display: flex; flex-direction: column; gap: 2px;
    padding: 10px 14px; cursor: pointer;
    border-bottom: 1px solid rgba(148, 163, 194, 0.06);
    transition: background var(--duration-fast);
}
.req-result-item:hover { background: rgba(46, 49, 146, 0.12); }
.req-result-name { font-weight: 500; color: var(--text-primary); font-size: 0.9rem; }
.req-result-sub { font-size: 0.78rem; color: var(--text-muted); }
.req-result-empty { padding: 12px 14px; color: var(--text-muted); font-size: 0.85rem; }

.req-chip {
    display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm);
    padding: 10px 14px;
    background: rgba(46, 49, 146, 0.12);
    border: 1px solid rgba(123, 128, 212, 0.35);
    border-radius: var(--radius-sm);
    color: var(--text-primary); font-size: 0.9rem;
}
.chip-x {
    background: none; border: none; color: var(--text-muted);
    cursor: pointer; font-size: 0.9rem; padding: 2px 6px; border-radius: 4px;
}
.chip-x:hover { color: var(--error-color); background: rgba(239, 68, 68, 0.1); }

/* Availability indicator */
.avail-line { margin: -4px 0 var(--space-md); min-height: 0; }
.avail-pill {
    display: inline-block; padding: 5px 12px; border-radius: 999px;
    font-size: 0.8rem; font-weight: 600; font-family: var(--font-display);
}
.avail-pill.ok { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }
.avail-pill.bad { background: rgba(239, 68, 68, 0.15); color: #F87171; }
.avail-pill.checking { background: rgba(148, 163, 194, 0.1); color: var(--text-muted); }
.avail-conflict { font-size: 0.8rem; color: #F87171; margin-top: 4px; }
/* Run 5 §11.2 — the teacher DECLARED he is busy. Amber, never red: this is a
   warning that never blocks a booking, and it always sits BELOW the green/red
   pill so a real double-booking still reads first. */
.avail-declared {
    display: flex;
    gap: 6px;
    margin-top: 6px;
    padding: 7px 10px;
    font-size: 0.8rem;
    line-height: 1.45;
    color: #FBBF24;
    background: rgba(251, 191, 36, 0.1);
    border: 1px solid rgba(251, 191, 36, 0.28);
    border-radius: var(--radius-sm);
}

/* Appointment status badges */
.badge-appt-scheduled { background: rgba(99, 102, 241, 0.15); color: #A5A8FF; }
.badge-appt-completed { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }
.badge-appt-cancelled { background: rgba(239, 68, 68, 0.15); color: #F87171; }

/* Appointment audit entries on timelines */
.timeline-item.ti-appt { border-left-color: #A855F7; }
.ti-appt-link { cursor: pointer; }
.ti-appt-link:hover { background: rgba(168, 85, 247, 0.08); }

/* Mini lists (sessions on a request, teacher upcoming/history) */
.mini-list { display: flex; flex-direction: column; gap: var(--space-sm); }
.mini-list.scroll-list { max-height: 260px; overflow-y: auto; }
.mini-item {
    display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm);
    padding: 10px 12px;
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    transition: border-color var(--duration-fast);
}
.mini-item.appt-mini { cursor: pointer; }
.mini-item.appt-mini:hover { border-color: var(--accent-light); }
.mini-main { font-size: 0.85rem; color: var(--text-primary); }
.mini-sub { font-size: 0.75rem; color: var(--text-muted); }
.mini-side { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.meet-dot { font-size: 0.8rem; }

/* Appointment detail actions */
.appt-actions { display: flex; gap: var(--space-sm); flex-wrap: wrap; }
.copy-btn { padding: 3px 10px; font-size: 0.75rem; margin-left: 8px; vertical-align: middle; }
.link-like { color: var(--accent-light); cursor: pointer; }
.link-like:hover { text-decoration: underline; }

/* Appointments / teachers tables on small screens.
   ⚠ The GENERIC rule above already hides columns 5 and 6 of every .data-table
   (and 7 below 600px). The teachers table grew to 9 columns in Run 4
   (Name · Subjects · Source · Contract · Phone · Upcoming · Total · Rating ·
   Status), so the generic rule drops Phone + Upcoming; Subjects and Total are
   dropped here as well, leaving exactly the columns that carry the meaning on a
   phone: Name, Source, Contract, Rating, Status. */
@media (max-width: 900px) {
    #apptTable th:nth-child(5), #apptTable td:nth-child(5),
    #apptTable th:nth-child(7), #apptTable td:nth-child(7),
    #teacherTable th:nth-child(2), #teacherTable td:nth-child(2),
    #teacherTable th:nth-child(7), #teacherTable td:nth-child(7) {
        display: none;
    }
}

/* ═══════════════════════════════════════════
   Billing / CRM expansion additions
   (customers, subscriptions, accounting)
   ═══════════════════════════════════════════ */

/* Subscriptions + Accounting sub-tab views (same pattern as .hr-subview) */
.subs-subview { display: none; }
.subs-subview.active { display: block; }
.acct-subview { display: none; }
.acct-subview.active { display: block; }

/* Negative hour balance */
.balance-neg { color: #F87171; font-weight: 600; }

/* Voided subscriptions: struck through. Badges/buttons are inline-block, so the
   ancestor line-through does not draw across them. */
tr.row-voided td { text-decoration: line-through; color: var(--text-muted); }
.sub-mini.sub-voided .mini-main { text-decoration: line-through; color: var(--text-muted); }
.sub-mini.sub-voided .void-reason { display: inline-block; text-decoration: none; color: #F87171; }

/* Subscription entries on timelines */
.timeline-item.ti-sub { border-left-color: #38BDF8; }

/* Payroll totals row */
tr.payroll-totals { cursor: default; }
tr.payroll-totals td {
    font-weight: 700;
    color: var(--text-primary);
    border-top: 2px solid rgba(155, 163, 194, 0.35);
}
.data-table tbody tr.payroll-totals:hover { background: none; }

/* ═══════════════════════════════════════════
   Sessions Billing v2 additions
   (group sessions, session charges, extra time,
   pricing sub-tab, ratings)
   ═══════════════════════════════════════════ */

/* Extra-students repeater rows (appointment form) */
.extra-student-row {
    display: flex;
    gap: var(--space-sm);
    align-items: center;
    margin-bottom: var(--space-sm);
}
.extra-student-row .xs-name { flex: 1 1 30%; min-width: 0; }
.extra-student-row .xs-country { flex: 0 1 32%; min-width: 0; max-width: 34%; }
.extra-student-row .xs-phone { flex: 1 1 26%; min-width: 0; }
.extra-student-row .xs-remove { flex-shrink: 0; }

/* Live price quote line ("N students × H h → default X.XXX KWD") */
.quote-line {
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin: 6px 0 10px;
    min-height: 1em;
}
.quote-line strong { color: var(--text-primary); }
.pay-chip-line { margin-bottom: 8px; }

/* Inputs flagged invalid client-side (pricing table, amounts) */
.filter-input.error { border-color: var(--error-color); }

/* Edit-mode "charge no longer matches" warning box */
.recompute-warn {
    margin-top: 10px;
    padding: var(--space-md);
    background: rgba(245, 158, 11, 0.06);
    border: 1px solid rgba(245, 158, 11, 0.25);
    border-radius: var(--radius-sm);
}
.recompute-text { font-size: 0.85rem; color: #FBBF24; margin-bottom: 4px; }

/* Teacher star ratings */
.star-mini { color: #FBBF24; font-size: 0.8rem; font-weight: 600; }

/* "👥 N" group chip next to a student name */
.group-chip { margin-left: 6px; }

/* Pricing sub-tab */
.pricing-input { max-width: 140px; }
#pricingTable tbody tr { cursor: default; }
.data-table tbody tr.pricing-row:hover { background: none; }
.pricing-actions {
    justify-content: flex-start;
    align-items: center;
    gap: var(--space-md);
    margin-top: var(--space-md);
    flex-wrap: wrap;
}
.pricing-actions .field-hint { margin: 0; }

/* ═══════════════════════════════════════════
   Payzah payment links + teacher payouts
   ═══════════════════════════════════════════ */

/* Payment-link status badges (effective_status) */
.badge-pl-active { background: rgba(99, 102, 241, 0.15); color: #A5A8FF; }
.badge-pl-paid { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }
.badge-pl-cancelled { background: rgba(239, 68, 68, 0.15); color: #F87171; }
.badge-pl-expired { background: rgba(148, 163, 194, 0.15); color: #9BA3C2; }

/* Ledger "Payzah" gateway badge */
.badge-gateway { background: rgba(56, 189, 248, 0.15); color: #38BDF8; }

/* Payment-attempt status badges */
.badge-att-pending { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.badge-att-captured { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }
.badge-att-failed { background: rgba(239, 68, 68, 0.15); color: #F87171; }
.badge-att-stale { background: rgba(148, 163, 194, 0.15); color: #9BA3C2; }

/* Create-modal success view */
.pl-success-head {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    color: #4ADE80;
    margin-bottom: var(--space-sm);
}
.pl-url-row { display: flex; gap: var(--space-sm); align-items: center; margin-bottom: var(--space-sm); }
.pl-url-row input { flex: 1; min-width: 0; font-size: 0.8rem; color: var(--accent-light); }
.pl-warn { color: #FBBF24; }

/* Payroll "Transferred" cell */
.payout-cell { white-space: normal; }
.payout-cell-sub { display: block; margin-top: 4px; }
.payout-cell .payout-mark-btn { padding: 5px 12px; font-size: 0.78rem; white-space: nowrap; }

/* Pending transfers strip (Payroll sub-tab) */
.pending-strip {
    margin-bottom: var(--space-lg);
    background: rgba(17, 24, 39, 0.5);
    border: 1px solid rgba(245, 158, 11, 0.25);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
.pending-strip-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    padding: var(--space-md) var(--space-lg);
    border-bottom: 1px solid var(--border-default);
    flex-wrap: wrap;
}
.pending-strip-title {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-primary);
}
.pending-total { font-size: 0.9rem; font-weight: 600; color: #FBBF24; }
.pending-strip-body {
    padding: var(--space-md) var(--space-lg);
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}
.pending-teacher {
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    padding: 10px 14px;
}
.pending-teacher-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    flex-wrap: wrap;
}
.pending-teacher-name { font-weight: 600; color: var(--text-primary); }
.pending-month {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: 8px 0;
    margin-top: 6px;
    font-size: 0.85rem;
    color: var(--text-secondary);
    border-top: 1px solid rgba(148, 163, 194, 0.06);
    flex-wrap: wrap;
}
.pending-month strong { color: var(--text-primary); }
.pending-month .payout-mark-btn { margin-left: auto; padding: 5px 12px; font-size: 0.78rem; }
.pending-toggle { display: inline-block; margin-top: 8px; font-size: 0.8rem; }
/* ── Recording block (appointment detail modal, Phase 2) ── */
.rec-status {
    font-size: 0.85rem;
    color: var(--text-muted);
    margin-bottom: var(--space-sm);
}
.rec-status.rec-error { color: var(--error-color); }
.rec-link-row {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-sm);
    overflow-wrap: anywhere;
}
.rec-send-label {
    font-size: 0.8rem;
    color: var(--text-secondary);
    margin: var(--space-md) 0 var(--space-sm);
}
.rec-recipient {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    flex-wrap: wrap;
    padding: 6px 0;
    border-top: 1px solid var(--border-default);
}
.rec-send-label + .rec-recipient { border-top: none; }
.rec-recipient-name { font-size: 0.85rem; color: var(--text-primary); }

/* ═══════════════════════════════════════════
   Pay-by-link on a session · re-issue · editable messages
   ═══════════════════════════════════════════ */

/* The one shared "money state" chip (appointments list + detail) */
.badge-pay-collected { background: rgba(148, 163, 194, 0.15); color: #C3CAE0; }
.badge-pay-link { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.badge-pay-link.warn { background: rgba(245, 158, 11, 0.22); color: #FCD34D; }
.badge-pay-paid { background: rgba(34, 197, 94, 0.18); color: #4ADE80; }
.badge-pay-review { background: rgba(239, 68, 68, 0.18); color: #F87171; }

/* Appointment detail → Payment block */
.pay-state-line { margin-bottom: var(--space-sm); }
.pay-links-label { margin: var(--space-md) 0 var(--space-sm); }
.pay-actions { margin-top: var(--space-md); }
.pay-review-banner {
    margin-bottom: var(--space-sm);
    padding: 10px 14px;
    font-size: 0.85rem;
    line-height: 1.5;
    color: #FCA5A5;
    background: rgba(239, 68, 68, 0.08);
    border: 1px solid rgba(239, 68, 68, 0.3);
    border-radius: var(--radius-sm);
}
.pay-review-banner .link-like { color: #FCD34D; }

/* Re-issue modal */
.pl-reissue-warn {
    margin-bottom: var(--space-md);
    padding: 10px 14px;
    font-size: 0.85rem;
    color: #FBBF24;
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.28);
    border-radius: var(--radius-sm);
}
/* Inline "another active link — re-issue anyway?" confirm (duplicate-link 409) */
.pl-additional-confirm {
    margin-top: var(--space-sm);
    padding: 10px 14px;
    font-size: 0.85rem;
    line-height: 1.5;
    color: #FBBF24;
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.28);
    border-radius: var(--radius-sm);
}

/* WhatsApp buttons rendered without templates (payload unavailable) */
.wa-send-btn.disabled {
    background: rgba(148, 163, 194, 0.18);
    color: var(--text-muted);
    cursor: not-allowed;
}
.wa-send-btn.disabled:hover { background: rgba(148, 163, 194, 0.18); color: var(--text-muted); }

/* ── Messages tab (editable EN/AR templates) ── */
.tpl-layout {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: var(--space-lg);
    align-items: start;
}
.tpl-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    padding: var(--space-md);
}
.tpl-list-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    width: 100%;
    text-align: left;
    padding: 10px 12px;
    font-size: 0.88rem;
    color: var(--text-secondary);
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all 0.15s ease;
}
.tpl-list-item:hover { color: var(--text-primary); background: var(--bg-input); }
.tpl-list-item.active {
    color: var(--text-primary);
    background: var(--bg-input);
    border-color: var(--accent-light);
}
.tpl-list-label { flex: 1 1 auto; }
.tpl-editor {
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    min-width: 0;
}
.tpl-title {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-primary);
}
.tpl-ph-panel {
    margin: var(--space-md) 0;
    padding: var(--space-md);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
}
.tpl-ph-panel summary { cursor: pointer; font-size: 0.85rem; color: var(--text-secondary); }
.tpl-ph-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--space-md); }
.tpl-ph-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    font-size: 0.75rem;
    color: var(--text-secondary);
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: 999px;
    cursor: pointer;
}
.tpl-ph-chip:hover { color: var(--text-primary); border-color: var(--accent-light); }
.tpl-ph-chip code { color: var(--accent-light); font-size: 0.75rem; }
.tpl-ph-label { color: var(--text-muted); }
.tpl-cols {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-lg);
}
.tpl-col { min-width: 0; }
.tpl-col-head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: 6px;
    flex-wrap: wrap;
}
.tpl-reset {
    margin-left: auto;
    padding: 0;
    font-size: 0.75rem;
    color: var(--accent-light);
    background: none;
    border: none;
    cursor: pointer;
}
.tpl-reset:hover { text-decoration: underline; }
.tpl-textarea { min-height: 240px; font-family: inherit; line-height: 1.6; }
.tpl-rtl { font-family: 'Noto Kufi Arabic', 'Segoe UI', sans-serif; }
.tpl-preview-label { margin-top: var(--space-md); }
.tpl-preview {
    margin-top: 6px;
    padding: var(--space-md);
    min-height: 120px;
    max-height: 320px;
    overflow: auto;
    font-family: inherit;
    font-size: 0.82rem;
    line-height: 1.6;
    color: var(--text-secondary);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
}
.tpl-warn { color: #FBBF24; }
.tpl-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-top: var(--space-md);
    flex-wrap: wrap;
}
.tpl-actions .field-hint { margin: 0; }

@media (max-width: 900px) {
    .tpl-layout { grid-template-columns: minmax(0, 1fr); }
    .tpl-cols { grid-template-columns: minmax(0, 1fr); }
}

/* ═══════════════════════════════════════════
   Access control (Run 2 — per-area permissions)
   ═══════════════════════════════════════════ */

/* Toasts — the only channel for "the server just refused that". */
.toast-host {
    position: fixed;
    right: var(--space-lg);
    bottom: var(--space-lg);
    z-index: 3000;
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    max-width: min(380px, calc(100vw - 2 * var(--space-lg)));
    pointer-events: none;
}
.toast {
    pointer-events: auto;
    cursor: pointer;
    padding: 12px 16px;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-primary);
    background: var(--bg-secondary);
    border: 1px solid var(--border-default);
    border-left: 3px solid var(--accent-light);
    border-radius: var(--radius-sm);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
    opacity: 0;
    transform: translateY(8px);
    transition: opacity var(--duration-normal) var(--ease-out), transform var(--duration-normal) var(--ease-out);
}
.toast.show { opacity: 1; transform: translateY(0); }
.toast-warn { border-left-color: #FBBF24; }

/* "No sections enabled" / "this account cannot use the admin panel" cards */
.access-card {
    max-width: 520px;
    margin: var(--space-2xl) auto;
    padding: var(--space-xl);
    text-align: center;
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
}
.access-card-icon { font-size: 2rem; margin-bottom: var(--space-sm); }
.access-card-title {
    font-family: var(--font-display);
    font-size: 1.1rem;
    color: var(--text-primary);
    margin-bottom: var(--space-sm);
}
.access-card-text { color: var(--text-secondary); font-size: 0.9rem; line-height: 1.6; margin-bottom: var(--space-md); }
.access-card .action-btn { display: inline-block; text-decoration: none; }
/* Two ways out of the role-denied screen; they wrap instead of overflowing on a phone. */
.access-card-actions { display: flex; flex-wrap: wrap; gap: var(--space-sm); justify-content: center; }

/* The access picker (create form + Edit-access modal) */
.access-picker { margin-top: var(--space-md); }
.access-full { margin-bottom: var(--space-sm); }
.access-full span { font-size: 0.85rem; color: var(--text-secondary); }
.access-presets { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-bottom: var(--space-md); }
.preset-btn {
    padding: 6px 12px;
    font-family: var(--font-body);
    font-size: 0.78rem;
    color: var(--text-secondary);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: 999px;
    cursor: pointer;
    transition: color var(--duration-fast), border-color var(--duration-fast);
}
.preset-btn:hover { color: var(--text-primary); border-color: var(--accent-light); }
.preset-btn.active { color: var(--text-primary); border-color: var(--accent-light); background: var(--accent-glow); }
.access-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-sm);
}
.access-check {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding: 10px 12px;
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.access-check input { margin-top: 3px; flex-shrink: 0; }
.access-check input:disabled { opacity: 0.4; }
.access-check-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.access-check-label { font-size: 0.85rem; color: var(--text-primary); }
.access-check-hint { font-size: 0.72rem; color: var(--text-muted); }
.access-summary { margin-top: var(--space-md); }
.add-admin-actions { margin-top: var(--space-md); }
.admin-you { font-size: 0.75rem; color: var(--text-muted); font-weight: 400; }
.admin-actions .action-btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* Money columns/cells vanish for an account with neither `payments` nor
   `accounting` — one class so rows rendered later are covered too (§16). */
body.no-money-areas #apptThPayment,
body.no-money-areas .td-appt-pay { display: none; }

/* ── Refunds (Run 3) ── */
/* A refund is stored POSITIVE (what the customer gets back) but its ledger row is
   negative — the first negative amounts this table has ever carried. */
/* `.data-table td` already sets a colour, so the cell form needs the extra
   specificity — without it a refund row would render in the ordinary text colour. */
.amount-negative,
.data-table td.amount-negative { color: var(--error-color); font-weight: 600; }
.badge-refund-active { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.badge-refund-voided { background: rgba(148, 163, 194, 0.15); color: #9BA3C2; }
.refund-form-intro { margin-bottom: var(--space-md); }
.refund-type-seg { flex-wrap: wrap; }
.refund-type-legend {
    margin: var(--space-sm) 0 0;
    padding-left: 18px;
    font-size: 0.75rem;
    color: var(--text-muted);
    line-height: 1.7;
}
.refund-type-legend strong { color: var(--text-secondary); }
.timeline-item.ti-refund { border-left-color: #FBBF24; }

/* Unused-hours band on the appointment detail, shown once right after a duration
   reduction: the hours already went back, only the money needs a decision. */
.unused-band {
    padding: var(--space-md);
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-md);
}
.unused-band-head { font-size: 0.9rem; color: #FBBF24; font-weight: 600; margin-bottom: 6px; }
.unused-band-text { font-size: 0.85rem; color: var(--text-secondary); line-height: 1.6; }
.unused-band .appt-actions { margin-top: var(--space-sm); }

/* Delete confirm: the money/consequence lines, stated BEFORE the delete. */
.delete-warnings { margin-top: var(--space-md); text-align: left; }
.delete-warnings:empty { display: none; }
.delete-warning {
    padding: 10px 12px;
    margin-bottom: var(--space-sm);
    font-size: 0.82rem;
    line-height: 1.55;
    color: #FBBF24;
    background: rgba(245, 158, 11, 0.08);
    border-left: 3px solid #FBBF24;
    border-radius: var(--radius-sm);
}
.delete-warning:last-child { margin-bottom: 0; }

/* The generic ≤900px rule hides columns 5 and 6 of EVERY data table. On the two
   refunds tables those are the Amount and its paid-out state — the whole point of
   the row. Keep them and drop Session / By instead. */
@media (max-width: 900px) {

    #refundsTable th:nth-child(5),
    #refundsTable td:nth-child(5),
    #refundsTable th:nth-child(6),
    #refundsTable td:nth-child(6),
    #acctRefundsTable th:nth-child(5),
    #acctRefundsTable td:nth-child(5),
    #acctRefundsTable th:nth-child(6),
    #acctRefundsTable td:nth-child(6) {
        display: table-cell;
    }

    #refundsTable th:nth-child(3),
    #refundsTable td:nth-child(3),
    #refundsTable th:nth-child(7),
    #refundsTable td:nth-child(7),
    #acctRefundsTable th:nth-child(3),
    #acctRefundsTable td:nth-child(3),
    #acctRefundsTable th:nth-child(7),
    #acctRefundsTable td:nth-child(7) {
        display: none;
    }
}

/* ═══════════════════════════════════════════
   Run 4 — persistent unused hours, teacher provenance/contract/bank,
   Teacher Calendar, Ratings, Recordings
   ═══════════════════════════════════════════ */

/* The unused-hours decision AFTER someone resolved it: same band, muted, one line. */
.unused-band.resolved {
    background: rgba(148, 163, 194, 0.07);
    border-color: rgba(148, 163, 194, 0.25);
}
.unused-band.resolved .unused-band-head { color: #9BA3C2; margin-bottom: 0; }

/* "A decision is pending" marker in the Appointments list Payment cell. */
.badge-unused { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }

/* Contract expiry — WARN ONLY, nothing is ever blocked. */
.badge-contract-soon { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.badge-contract-expired { background: rgba(239, 68, 68, 0.15); color: #F87171; }

.contract-period { font-size: 0.85rem; color: var(--text-secondary); margin: 0 0 var(--space-sm); }
.contract-upload { margin-top: var(--space-sm); }
.contract-upload .form-field { margin-bottom: var(--space-sm); }
.contract-upload .add-admin-error { margin-top: 0; }

/* Bank details (teacher profile + the salary-transfer modal). */
/* ⚠ `.detail-section .detail-label` (see above) makes every label inside a section
   a full-width block heading — right for the section's own title, wrong for a
   .detail-grid nested in one, where the label IS the 150px column of the row. The
   teacher profile's Bank details block is the first such grid, and without this it
   renders as "IBANKW81…" with no label column at all. */
.detail-section .detail-row > .detail-label {
    width: 150px;
    display: block;
    margin-bottom: 0;
}
.bank-block:empty { display: none; }
.bank-block { margin-bottom: var(--space-md); }
/* Its own block in the teacher form, not glued to the contract hint above it. */
#teacherBankFields {
    margin-top: var(--space-md);
    padding-top: var(--space-md);
    border-top: 1px solid var(--border-default);
}
.iban-value { font-family: var(--font-display); letter-spacing: 0.04em; overflow-wrap: anywhere; }
.bank-empty { margin-bottom: var(--space-md); }

/* ── Instructor portal login (Run 5 §11.1) ── */
/* The credentials panel is shown EXACTLY ONCE — the server never returns the
   password again — so it has to read as something to act on, not a receipt. */
.cred-panel {
    padding: var(--space-md);
    background: rgba(34, 197, 94, 0.08);
    border: 1px solid rgba(34, 197, 94, 0.3);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-md);
}
.cred-head { font-family: var(--font-display); color: #4ADE80; margin-bottom: var(--space-sm); }
.cred-row { display: flex; align-items: baseline; gap: var(--space-sm); margin-bottom: 6px; flex-wrap: wrap; }
.cred-key { font-size: 0.78rem; color: var(--text-muted); min-width: 76px; }
/* The value and its Copy button are ONE unit: on a phone the row may wrap under
   the label, but the button must never end up on a line of its own. */
.cred-item { display: flex; align-items: center; gap: 8px; min-width: 0; }
.cred-item .copy-btn { margin-left: 0; flex-shrink: 0; }
.cred-val {
    font-family: var(--font-display);
    font-size: 0.95rem;
    color: var(--text-primary);
    letter-spacing: 0.03em;
    overflow-wrap: anywhere;
}
.cred-warn { color: #FBBF24; font-size: 0.85rem; line-height: 1.5; }
/* .field-hint has no bottom margin (it normally sits UNDER a field), so as an
   intro paragraph it would butt straight into the first label. */
#teacherLoginIntro { margin-bottom: var(--space-md); }
.login-line { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; margin-bottom: var(--space-sm); }
.login-user { font-family: var(--font-display); color: var(--text-primary); overflow-wrap: anywhere; }

/* ── Teacher Calendar ── */
.cal-toolbar { align-items: center; }
.cal-nav { display: flex; gap: var(--space-sm); }
.cal-nav .action-btn { min-width: 40px; }
.cal-month-label {
    font-family: var(--font-display);
    font-size: 1rem;
    color: var(--text-primary);
    white-space: nowrap;
}
.cal-empty-note { color: var(--text-muted); font-size: 0.88rem; margin-bottom: var(--space-sm); }

/* The grid never collapses on a phone — it scrolls sideways instead, so a
   session chip is never silently hidden (the inherited-responsive-rule trap). */
.cal-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cal-grid-wrap { min-width: 720px; }
.cal-weekdays, .cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.cal-weekdays { gap: 1px; margin-bottom: 1px; }
.cal-dayname {
    padding: 8px 6px;
    text-align: center;
    font-family: var(--font-display);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    background: var(--bg-secondary);
}
.cal-grid {
    gap: 1px;
    background: var(--border-default);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.cal-cell {
    min-height: 104px;
    padding: 6px;
    background: var(--bg-card);
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.cal-cell.other-month { background: rgba(17, 24, 39, 0.45); }
.cal-cell.other-month .cal-daynum { color: var(--text-muted); opacity: 0.6; }
/* Neighbouring-month days are fetched and DO show their sessions (an empty cell
   would read as "nothing booked"), just dimmed so the month in focus reads first. */
.cal-cell.other-month .cal-chip { opacity: 0.55; }
.cal-cell.other-month .cal-chip:hover { opacity: 1; }
.cal-cell.cal-today { box-shadow: inset 0 0 0 1px var(--accent-light); }
.cal-daynum { font-size: 0.75rem; font-weight: 600; color: var(--text-secondary); }
.cal-cell.cal-today .cal-daynum { color: var(--accent-light); }
.cal-chip {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 4px 6px;
    border-radius: 4px;
    border-left: 3px solid transparent;
    font-size: 0.72rem;
    line-height: 1.3;
    cursor: pointer;
    overflow: hidden;
}
.cal-chip:hover { filter: brightness(1.25); }
.cal-chip-time { font-weight: 600; }
.cal-chip-who { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-chip-scheduled { background: rgba(99, 102, 241, 0.16); border-left-color: #A5A8FF; color: #A5A8FF; }
.cal-chip-completed { background: rgba(34, 197, 94, 0.14); border-left-color: #4ADE80; color: #4ADE80; }
.cal-chip-cancelled { background: rgba(239, 68, 68, 0.12); border-left-color: #F87171; color: #F87171; }
.cal-chip-cancelled .cal-chip-time { text-decoration: line-through; }
.cal-chip-hidden { display: none; }
.cal-more { font-size: 0.7rem; color: var(--accent-light); cursor: pointer; }
.cal-more:hover { text-decoration: underline; }

/* Run 5 §11.3 — declared unavailability. Deliberately grey + striped and INERT
   (no pointer, no click): it is the teacher's own statement, not a booking, and
   nothing opens from it. It renders ABOVE the session chips in the same cell. */
.cal-busy-toggle { padding: 0; white-space: nowrap; }
.cal-chip-busy {
    cursor: default;
    color: var(--text-secondary);
    border-left-color: var(--text-muted);
    background-color: rgba(148, 163, 194, 0.12);
    background-image: repeating-linear-gradient(135deg,
            rgba(148, 163, 194, 0.14) 0, rgba(148, 163, 194, 0.14) 4px,
            transparent 4px, transparent 8px);
}
.cal-chip-busy:hover { filter: none; }
.cal-chip-busy .cal-chip-time { color: var(--text-secondary); }
.cal-chip-busy .cal-chip-who { color: var(--text-muted); }

/* ── Ratings ── */
.rating-summary { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-bottom: var(--space-md); }
.rating-summary:empty { display: none; }
.rating-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    font-size: 0.8rem;
    color: var(--text-primary);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: 999px;
    cursor: pointer;
}
.rating-pill:hover { border-color: var(--accent-light); }
.data-table td.td-comment {
    max-width: 320px;
    white-space: normal;
    overflow-wrap: anywhere;
    color: var(--text-secondary);
}

/* The generic ≤900px rule hides columns 5 and 6 of EVERY data table. On the
   ratings table those are the Teacher ★ and the Comment — the whole point of the
   tab. Keep them and drop Class ★ instead. */
@media (max-width: 900px) {

    #ratingsTable th:nth-child(5),
    #ratingsTable td:nth-child(5),
    #ratingsTable th:nth-child(6),
    #ratingsTable td:nth-child(6) {
        display: table-cell;
    }

    #ratingsTable th:nth-child(4),
    #ratingsTable td:nth-child(4) {
        display: none;
    }

    /* `.table-wrapper` is overflow:hidden, so a table wider than the phone was
       CLIPPED — the columns past the fold were simply unreachable. Keeping a
       column visible in CSS is not the same as being able to read it. Wide
       content scrolls inside its own container instead (overflow-y stays hidden
       so the rounded corners survive). */
    .table-wrapper {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .cal-cell { min-height: 88px; }
}

/* ── Recordings ── */
.rec-cards { display: flex; flex-direction: column; gap: var(--space-md); }
.rec-card {
    padding: var(--space-md);
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
}
.rec-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-sm);
    margin-bottom: var(--space-sm);
    font-size: 0.9rem;
    color: var(--text-primary);
}
.rec-card .rec-send-label { margin-top: var(--space-sm); }

/* `.data-table td` is nowrap + ellipsis with a 180px cap, so a Payment cell that
   carries BOTH the money chip and the ⏳ Unused marker clipped the marker to "…".
   That cell is chips only — let it wrap. */
.data-table td.td-appt-pay {
    max-width: 220px;
    white-space: normal;
    text-overflow: clip;
    line-height: 1.9;
}

/* A date filter is a fixed-size control, not a stretcher. `.filter-input` sets
   width:100%, which made every date input in a filter bar claim its own whole
   row (visible on the shipped Requests/Appointments bars too, not just the new
   Ratings/Recordings ones). Scoped to .filters-bar so modal date fields are
   untouched; the ≤900px rule still stretches them, since that bar is a column. */
.filters-bar .filter-date { width: auto; flex: 0 0 auto; }

/* ═══════════════════════════════════════════
   Run 6 — contract intake: the Contracts inbox, the "no email" chase and
   the "contract pending" flag
   ═══════════════════════════════════════════ */

/* Sidebar count pill: how many arrived contracts are still waiting for a human.
   Pushed to the far end of the nav row so it never crowds the label. */
.nav-badge {
    margin-left: auto;
    min-width: 20px;
    padding: 1px 7px;
    border-radius: 999px;
    background: rgba(245, 158, 11, 0.2);
    color: #FBBF24;
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1.5;
    text-align: center;
}

/* "Contract pending" = no signed FILE has arrived yet. Same amber family as the
   expiry warning: it is a task to finish, not a failure. */
.badge-contract-pending { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
/* "No email" is harder: without one, a contract can NEVER reach this teacher. */
.badge-no-email { background: rgba(239, 68, 68, 0.15); color: #F87171; }

/* Inline red explanation inside a detail row / a form field. */
.detail-warn {
    display: inline-block;
    color: #F87171;
    font-size: 0.82rem;
    line-height: 1.5;
}
p.detail-warn { margin: 6px 0 0; }

/* Persistent chase strip above the Teachers table. Amber, not red: in production
   today only 1 of 8 teachers has an email, so this is the NORMAL state until the
   owner has filled them in — it must read as a job to do, not as an error. */
.warn-banner {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
    padding: 10px var(--space-md);
    background: rgba(245, 158, 11, 0.1);
    border: 1px solid rgba(245, 158, 11, 0.35);
    border-radius: var(--radius-md);
    color: #FBBF24;
    font-size: 0.88rem;
    line-height: 1.5;
}
.warn-banner-text { flex: 1 1 240px; min-width: 0; }
.warn-banner .action-btn { flex: 0 0 auto; }

/* `.data-table td` is nowrap + ellipsis with a 180px cap. Every cell below now
   carries either a chip beside its text or a full email address, both of which
   that cap would silently clip to "…" — the defect class that only shows up in a
   render. Let them wrap instead (the .td-appt-pay precedent). */
#teacherTable td.td-name {
    max-width: 280px;
    white-space: normal;
    text-overflow: clip;
    line-height: 1.9;
}
#teacherTable td.td-contract {
    max-width: 210px;
    white-space: normal;
    text-overflow: clip;
}
#contractsTable td,
#hrVaultTable td:nth-child(4),
#hrReqTable td:nth-child(4) {
    max-width: 240px;
    white-space: normal;
    text-overflow: clip;
    overflow-wrap: break-word;
}

/* Only an address longer than its column may be broken mid-word. `anywhere` on
   the whole table let a narrow viewport shred every cell one character per line
   (seen at 390px: "nadia.ibrahi m@e xampl e.com"). */
#contractsTable td:nth-child(2) { overflow-wrap: anywhere; }
#contractModal .filter-select.full-width { margin-bottom: 0; }
.contract-mini { cursor: pointer; }

/* ── Responsive: the GLOBAL rule hides every table's 5th and 6th column at
   ≤900px (and the 7th at ≤600px). Adding an Email column to the two HR tables
   SHIFTS which columns that rule eats, and on the new 6-column Contracts table
   it would eat Status and Teacher — the two cells that carry the whole meaning.
   Each table below is re-mapped so the same semantic columns stay hidden as
   before. `.table-wrapper` already scrolls horizontally at ≤900px. ── */
@media (max-width: 900px) {

    /* Contracts: Received | Email | Name | File | Status | Teacher.
       Keep Status + Teacher; drop the provider's display name (it is in the
       modal, and the email is the identifier that matters). */
    #contractsTable th:nth-child(5),
    #contractsTable td:nth-child(5),
    #contractsTable th:nth-child(6),
    #contractsTable td:nth-child(6) {
        display: table-cell;
    }

    #contractsTable th:nth-child(3),
    #contractsTable td:nth-child(3) {
        display: none;
    }

    /* HR vault: # | Name | Phone | Email | CV | Status | Source | Added.
       Was hiding Status + Source; keep it that way (CV is now column 5). */
    #hrVaultTable th:nth-child(5),
    #hrVaultTable td:nth-child(5) {
        display: table-cell;
    }

    #hrVaultTable th:nth-child(7),
    #hrVaultTable td:nth-child(7) {
        display: none;
    }

    /* HR requests: # | Name | Phone | Email | CV | Status | Interview | Date.
       Was hiding Status + Interview; same after the shift. */
    #hrReqTable th:nth-child(5),
    #hrReqTable td:nth-child(5) {
        display: table-cell;
    }

    #hrReqTable th:nth-child(7),
    #hrReqTable td:nth-child(7) {
        display: none;
    }

    /* A table narrower than its content does not ellipsise here — the cells wrap,
       and a phone-width table squeezed every column down to a few characters.
       Give it a floor and let the wrapper (overflow-x:auto, above) scroll. */
    #contractsTable { min-width: 560px; }

    /* Run 6 put a FOURTH control in the Teachers filter bar. Stacked one per row
       (the ≤900px `.filters-bar { flex-direction: column }` rule) that pushed the
       table and its new chips off the first screen. Two per row instead. */
    #view-teachers .filters-bar {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: stretch;
    }

    #view-teachers .filters-bar .search-box { flex: 1 1 100%; }

    #view-teachers .filters-bar .filter-select {
        flex: 1 1 calc(50% - 5px);
        min-width: 0;
    }

    #view-teachers .filters-bar .clear-btn { flex: 1 1 100%; }
}

@media (max-width: 600px) {

    /* The last column ("Added" / "Date") is what the global ≤600px rule used to
       drop as the 7th, before Email shifted everything along by one.
       ⚠ Run 16: #hrReqTable gained a Score column at position 8, so its Date column
       is now the NINTH. Left at 8 this rule would have hidden the Score itself on
       every phone — the exact column-index trap §0.3 warns about, and the opposite
       of acceptance criterion 19 ("visible on a phone too"). #hrVaultTable is
       untouched and still ends at 8. */
    #hrVaultTable th:nth-child(8),
    #hrVaultTable td:nth-child(8),
    #hrReqTable th:nth-child(9),
    #hrReqTable td:nth-child(9) {
        display: none;
    }

    /* Phone: the file name is the widest thing in the inbox and the least useful
       — the row opens a modal that carries it, and the download link with it. */
    #contractsTable th:nth-child(4),
    #contractsTable td:nth-child(4) {
        display: none;
    }

    #contractsTable { min-width: 430px; }

    /* Phone: "Source" is the least actionable teacher column, and dropping it is
       what lets the CONTRACT cell — the ⏳ chip this run exists for — finish
       inside the screen instead of being cut off at the fold. */
    #teacherTable th:nth-child(3),
    #teacherTable td:nth-child(3) {
        display: none;
    }

    #teacherTable td.td-name { max-width: 150px; }
    #teacherTable td.td-contract { max-width: 150px; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Run 7 — Sign-up pages (.su-*) and the old-system Import (.im-*)
   Additive only: nothing above is modified.
   ⚠ Every .data-table below is kept to at most 4 MEANINGFUL columns,
   because the global responsive rules hide columns 5–6 (≤900px) and 7
   (≤600px) of every .data-table in the panel.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Sign-up sub-tab views (same pattern as .hr-subview) ── */
.su-subview { display: none; }
.su-subview.active { display: block; }

.su-more-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-top: var(--space-md);
    flex-wrap: wrap;
}

/* Page cell: headline over the /signup/<slug> path */
.su-page-slug {
    display: block;
    margin-top: 2px;
    font-size: 0.75rem;
    color: var(--accent-light);
    word-break: break-all;
}

.badge-live { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }
.badge-off { background: rgba(148, 163, 184, 0.15); color: #A9B2CC; }
/* Leads the name cell rather than trailing it: `.td-name` is nowrap + ellipsis,
   so a trailing chip is the first thing a narrow screen throws away. */
.badge-repeat { background: rgba(245, 158, 11, 0.15); color: #FBBF24; margin-right: 6px; }

/* ── Field builder ── */
.su-catalog {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    margin-bottom: var(--space-sm);
}

.su-cat-btn {
    padding: 7px 14px;
    font-family: var(--font-display);
    font-size: 0.8rem;
    color: var(--text-secondary);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: 999px;
    cursor: pointer;
    transition: all var(--duration-fast) var(--ease-out);
}

.su-cat-btn:hover:not(:disabled) {
    color: var(--text-primary);
    border-color: var(--accent-light);
}

.su-cat-btn:disabled {
    opacity: 0.4;
    cursor: default;
}

.su-fields {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    margin-bottom: var(--space-sm);
}

.su-field {
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    padding: var(--space-sm) var(--space-md);
}

.su-field-head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-sm);
}

.su-field-key {
    font-family: var(--font-display);
    font-size: 0.8rem;
    color: var(--text-muted);
}

.su-field-type {
    font-size: 0.72rem;
    color: var(--accent-light);
    background: rgba(46, 49, 146, 0.25);
    border-radius: 999px;
    padding: 2px 10px;
}

.su-field-spacer { flex: 1; }

.su-field-btn {
    background: transparent;
    border: 1px solid var(--border-default);
    color: var(--text-secondary);
    border-radius: var(--radius-sm);
    width: 30px;
    height: 30px;
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
}

.su-field-btn:hover:not(:disabled) { color: var(--text-primary); border-color: var(--accent-light); }
.su-field-btn:disabled { opacity: 0.3; cursor: default; }
.su-field-btn.danger:hover { color: #F87171; border-color: #F87171; }

.su-field-row {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    align-items: flex-end;
}

.su-field-row > label {
    flex: 1 1 160px;
    min-width: 0;
    display: block;
    font-size: 0.72rem;
    color: var(--text-muted);
}

.su-field-row > label input,
.su-field-row > label select {
    margin-top: 4px;
    width: 100%;
}

.su-field-req {
    flex: 0 0 auto;
    padding-bottom: 8px;
}

.su-fields-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    flex-wrap: wrap;
}

.su-clarity-note {
    margin-top: 8px;
    padding: 8px 12px;
    border-left: 2px solid var(--accent-light);
    background: rgba(46, 49, 146, 0.12);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    line-height: 1.5;
}

.su-slug-warn { color: #FBBF24; }

/* ── Stats ── */
.su-stat-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
}

.su-dists {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: var(--space-lg);
}

.su-bars { display: flex; flex-direction: column; gap: 5px; }

.su-bar-row {
    display: grid;
    grid-template-columns: 42px 1fr 40px;
    align-items: center;
    gap: var(--space-sm);
    font-size: 0.78rem;
    color: var(--text-secondary);
}

/* Both are <span>s inside a grid row. The track is a grid ITEM so it is
   blockified automatically — the FILL is not, and an inline box ignores both
   height and width, which renders every bar as an empty track. */
.su-bar-track {
    display: block;
    height: 12px;
    background: rgba(148, 163, 184, 0.1);
    border-radius: 999px;
    overflow: hidden;
}

.su-bar-fill {
    display: block;
    height: 100%;
    background: var(--accent-light);
    border-radius: 999px;
    min-width: 0;
}

/* Dates ("2026-06-11") need more room than a day number or a month name. */
.su-bars.wide .su-bar-row { grid-template-columns: 92px 1fr 44px; }
.su-bar-row.top .su-bar-fill { background: var(--success-color); }
.su-bar-row.top { color: var(--text-primary); font-weight: 600; }
.su-bar-count { text-align: right; font-variant-numeric: tabular-nums; }

.su-tz-note { margin-top: var(--space-md); }

.su-entry-values {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

/* ═══════ Import ═══════ */
.im-lede { color: var(--text-secondary); line-height: 1.6; margin-bottom: var(--space-md); }

.im-warn {
    display: flex;
    gap: var(--space-sm);
    padding: var(--space-md);
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-md);
}

.im-warn-icon { font-size: 1.1rem; line-height: 1.4; }
.im-warn-title { font-family: var(--font-display); font-weight: 600; color: #FBBF24; margin-bottom: 2px; }
.im-warn-text { font-size: 0.85rem; color: var(--text-secondary); line-height: 1.55; }

.im-intro-actions {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    flex-wrap: wrap;
}

.im-intro-actions .field-hint { margin-top: 0; }

.im-drop {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: var(--space-xl) var(--space-md);
    border: 2px dashed var(--border-default);
    border-radius: var(--radius-md);
    background: var(--bg-input);
    color: var(--text-muted);
    cursor: pointer;
    text-align: center;
    transition: border-color var(--duration-fast), color var(--duration-fast);
}

.im-drop:hover,
.im-drop:focus-visible,
.im-drop.dragover {
    border-color: var(--accent-light);
    color: var(--text-secondary);
    outline: none;
}

.im-drop.has-file { border-style: solid; border-color: var(--accent-light); }
.im-drop-title { font-family: var(--font-display); font-size: 0.95rem; color: var(--text-primary); }
.im-drop .field-hint { margin-top: 0; }

.im-check-actions {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-top: var(--space-md);
}

/* The money card — the whole point of the screen */
.im-money {
    background: rgba(17, 24, 39, 0.5);
    border: 1px solid rgba(245, 158, 11, 0.35);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-top: var(--space-xl);
}

.im-money .panel-header { border-bottom-color: rgba(245, 158, 11, 0.25); }
.im-money .panel-title { color: #FBBF24; }

.im-money-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
}

.im-money-cell {
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    padding: var(--space-md);
}

.im-money-value {
    display: block;
    font-family: var(--font-display);
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.2;
}

.im-money-label {
    display: block;
    margin-top: 2px;
    font-size: 0.74rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.im-money-cell.accent .im-money-value { color: #FBBF24; }
.im-block { margin-top: var(--space-lg); }
.im-block:first-child { margin-top: 0; }

.im-block-title {
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: var(--space-sm);
}

.im-sub { display: block; margin-top: 3px; font-size: 0.72rem; color: var(--text-muted); }
.im-neg { color: #F87171; font-weight: 600; }
/* `.data-table td` (0,1,1) and its hover rule (0,3,2) both out-specify a bare
   `.im-neg` (0,1,0), so a negative balance rendered in the ordinary grey — the
   one colour on this screen that has to be noticed. Beat both explicitly. */
.data-table td.im-neg,
.data-table tbody tr:hover td.im-neg { color: #F87171; font-weight: 600; }
.im-ok { color: #4ADE80; }
.im-amber { color: #FBBF24; }

.im-note {
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
    line-height: 1.55;
    margin-bottom: var(--space-sm);
}

.im-note.amber { background: rgba(245, 158, 11, 0.1); border: 1px solid rgba(245, 158, 11, 0.3); color: #FBBF24; }
.im-note.red { background: rgba(239, 68, 68, 0.1); border: 1px solid rgba(239, 68, 68, 0.3); color: #F87171; }
.im-note.green { background: rgba(34, 197, 94, 0.1); border: 1px solid rgba(34, 197, 94, 0.3); color: #4ADE80; }
.im-note.plain { background: rgba(148, 163, 184, 0.08); border: 1px solid var(--border-default); color: var(--text-secondary); }

.im-list { list-style: none; display: flex; flex-direction: column; gap: 6px; }

.im-list li {
    font-size: 0.85rem;
    color: var(--text-secondary);
    line-height: 1.5;
    padding-left: 14px;
    position: relative;
}

.im-list li::before { content: "•"; position: absolute; left: 0; color: var(--text-muted); }

.im-actions {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    flex-wrap: wrap;
    margin-top: var(--space-lg);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--border-default);
}

.im-result-counts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: var(--space-sm);
}

.im-result-counts div {
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.im-result-counts strong {
    display: block;
    font-family: var(--font-display);
    font-size: 1.15rem;
    color: var(--text-primary);
}

/* The panel has no global disabled style for .action-btn, so "Check the file"
   and "Import" looked pressable while doing nothing. Scoped to this screen —
   the shipped tabs keep the look they shipped with. */
#view-import .action-btn:disabled,
#importConfirmModal .action-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

#importConfirmModal .modal-content { max-width: 560px; text-align: left; }
#importConfirmModal .modal-icon,
#importConfirmModal .modal-title { text-align: center; }
#importConfirmModal .modal-title { display: block; }

.im-confirm-gate {
    margin-top: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    background: rgba(245, 158, 11, 0.1);
    border: 1px solid rgba(245, 158, 11, 0.35);
    border-radius: var(--radius-sm);
}

.im-confirm-gate .check-row { color: #FBBF24; }

@media (max-width: 900px) {
    /* Both new tables are 5–6 columns wide; the global rule already drops 5 and 6.
       Nothing here carries meaning in those slots, so no extra rule is needed —
       this block only stops the value list from squashing on a phone. */
    .su-field-row > label { flex: 1 1 100%; }
    .su-bar-row { grid-template-columns: 38px 1fr 34px; }
}

/* ── Import report tables ──
   Two problems the shipped .data-table rules create for THIS screen, both found
   by rendering rather than by reading the diff:
   1. `.data-table td` is `max-width:180px; overflow:hidden; text-overflow:ellipsis;
      white-space:nowrap`, so the "what is wrong" column — the whole reason the row
      is listed — was truncated mid-sentence on a desktop.
   2. `.table-wrapper` is `overflow:hidden` (NOT auto), so on a phone the right-hand
      columns are clipped and UNREACHABLE. The panel's other tables cope by hiding
      columns 5–6 below 900px, but every column of the money card carries a number
      the operator must read before an irreversible click.
   So: never truncate, and stack into label/value rows on a phone. */
.im-table td {
    max-width: none;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

.im-table .im-sub { white-space: normal; }

@media (max-width: 900px) {

    .im-table,
    .im-table tbody,
    .im-table tr,
    .im-table td {
        display: block;
        width: 100%;
    }

    .im-table thead { display: none; }

    .im-table tr {
        padding: 8px 0;
        border-bottom: 1px solid rgba(148, 163, 194, 0.1);
    }

    .im-table tr:last-child { border-bottom: none; }

    .im-table td {
        display: flex;
        flex-wrap: wrap;
        gap: 4px var(--space-md);
        align-items: baseline;
        justify-content: space-between;
        padding: 4px var(--space-md);
        border-bottom: none;
        text-align: right;
    }

    .im-table td::before {
        content: attr(data-label);
        flex: 0 0 auto;
        font-family: var(--font-display);
        font-size: 0.7rem;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: var(--text-muted);
        text-align: left;
    }

    .im-table td[data-label=""] { display: block; text-align: left; }
    .im-table td[data-label=""]::before { content: none; }
    .im-table td.td-name { text-align: right; }
    /* The sub-line (months, "was 0.0 h", the skipped breakdown) is a flex SIBLING
       of the value here — force it onto its own row instead of letting it sit
       beside the value. */
    .im-table .im-sub { flex: 1 0 100%; text-align: right; }

    /* Browse lists keep the shipped "hide the secondary columns" approach — the
       detail modal carries everything they drop. Without these the 4th column is
       clipped by .table-wrapper's overflow:hidden and simply cannot be read. */
    #suPageTable th:nth-child(4),
    #suPageTable td:nth-child(4),
    #suEntryTable th:nth-child(2),
    #suEntryTable td:nth-child(2),
    #suEntryTable th:nth-child(3),
    #suEntryTable td:nth-child(3) {
        display: none;
    }

    /* Tightened so the remaining columns actually FIT inside .table-wrapper
       (overflow:hidden — anything wider is silently cut off, not scrollable). */
    #suPageTable td,
    #suPageTable th,
    #suEntryTable td,
    #suEntryTable th,
    #suStatsPageTable td,
    #suStatsPageTable th {
        padding-left: 10px;
        padding-right: 10px;
    }

    #suPageTable td.td-name,
    #suStatsPageTable td.td-name { max-width: 150px; }
    #suEntryTable td.td-name { max-width: 190px; }
}

@media (max-width: 600px) {

    #suStatsPageTable th:nth-child(4),
    #suStatsPageTable td:nth-child(4) {
        display: none;
    }
}

/* ═══════ Dashboard (Run 10) ═══════ */

/* Chart palette — VALIDATED with the dataviz six-checks script against the
   panel's effective card surface #0E1224 (bg-card 70% over bg-primary):
   "#7b80d4,#d95926,#199e70" → ALL CHECKS PASS in dark mode (lightness band,
   chroma floor, worst adjacent CVD ΔE 9.4 deutan, normal-vision ΔE 26.0,
   contrast ≥ 3:1). Slot 1 is the brand accent (--accent-light). Do not add a
   4th categorical slot without re-running the validator. --chart-deemph is the
   de-emphasis/context channel (CRM series, sparklines) — gray is deliberately
   NOT a categorical slot. */
:root {
    --chart-1: #7B80D4;
    --chart-2: #D95926;
    --chart-3: #199E70;
    --chart-deemph: #636D8C;
    --chart-grid: rgba(155, 163, 194, 0.13);
    --chart-surface: #0E1224;
}

/* ── Attention strip ── */
.dash-strip {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
}

.dash-att-item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: 999px;
    font-size: 0.82rem;
    color: var(--text-primary);
    cursor: pointer;
    transition: border-color var(--duration-fast), transform var(--duration-fast);
}

.dash-att-item:hover { border-color: #FBBF24; transform: translateY(-1px); }
.dash-att-item .dash-att-n { font-family: var(--font-display); font-weight: 700; color: #FBBF24; }
.dash-att-item.dash-att-static { cursor: default; }
.dash-att-item.dash-att-static:hover { transform: none; border-color: rgba(245, 158, 11, 0.3); }

.dash-att-ok {
    display: inline-flex;
    align-items: center;
    padding: 8px 14px;
    background: rgba(34, 197, 94, 0.08);
    border: 1px solid rgba(34, 197, 94, 0.3);
    border-radius: 999px;
    font-size: 0.82rem;
    color: var(--success-color);
}

/* ── KPI strip ── */
.dash-kpis {
    display: grid;
    /* 170px min lets all six KPI cards share one row on a desktop panel
       (~1150px of main width) instead of orphaning the sixth. */
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
}

.dash-kpis:empty { display: none; }

.dash-kpi {
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    padding: var(--space-md) var(--space-lg);
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.dash-kpi-label { font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
/* Stat-tile contract: proportional figures on the big value (tabular-nums only
   where numbers must align vertically — table columns). */
.dash-kpi-value { font-family: var(--font-display); font-size: 1.7rem; font-weight: 700; color: var(--text-primary); line-height: 1.15; }
.dash-kpi-sub { font-size: 0.74rem; color: var(--text-muted); }

.dash-kpi-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    margin-top: 6px;
    min-height: 26px;
}

.dash-delta { font-size: 0.74rem; white-space: nowrap; }
.dash-delta.up { color: var(--success-color); }
.dash-delta.down { color: var(--error-color); }
.dash-delta.flat { color: var(--text-muted); }
/* The spark is 96px fixed — on a narrow phone KPI card the foot WRAPS instead
   of poking past the card (390px viewport, 2-col KPI grid). */
.dash-kpi-foot { flex-wrap: wrap; }
.dash-spark { flex-shrink: 0; opacity: 0.9; max-width: 100%; }

/* ── Card rows ── */
.dash-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
    gap: var(--space-lg);
    margin-bottom: var(--space-lg);
}

.dash-row:empty { display: none; }

.dash-card {
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    min-width: 0;
}

.dash-card-title {
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 2px;
}

.dash-card-sub { font-size: 0.74rem; color: var(--text-muted); margin-bottom: var(--space-md); }

/* Base .table-wrapper is overflow:hidden — inside a dashboard card that would
   silently CUT columns off on phones. Scroll the table inside the card instead;
   the page itself must never scroll horizontally. */
.dash-card .table-wrapper { margin: 0; overflow-x: auto; }
.dash-card .table-wrapper .data-table { min-width: 420px; }

/* Wide cards (tables) can span the full row. */
.dash-card.dash-span { grid-column: 1 / -1; }

/* Small figures inside a card ("Income 512.000 · Expenses 120.000 …"). */
.dash-figs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-md) var(--space-xl);
    margin-bottom: var(--space-md);
}

.dash-fig { display: flex; flex-direction: column; min-width: 0; }
.dash-fig-v { font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; color: var(--text-primary); }
.dash-fig-v.neg { color: var(--error-color); }
.dash-fig-v.pos { color: var(--success-color); }
.dash-fig-l { font-size: 0.7rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }

.dash-note { font-size: 0.72rem; color: var(--text-muted); margin-top: var(--space-sm); line-height: 1.5; }

/* ── Charts (built by charts.js) ── */
.chart-wrap {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    column-gap: 8px;
}

.chart-y {
    grid-row: 1;
    grid-column: 1;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: flex-end;
    font-size: 0.66rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    line-height: 1;
    padding: 0;
}

.chart-y span:first-child { transform: translateY(-40%); }
.chart-y span:last-child { transform: translateY(40%); }

.chart-plot { grid-row: 1; grid-column: 2; position: relative; min-width: 0; }

.chart-grid-line {
    position: absolute;
    left: 0;
    right: 0;
    height: 1px;
    background: var(--chart-grid);
    pointer-events: none;
}

/* Columns: flex groups growing from a single baseline. */
.chart-cols {
    display: flex;
    align-items: flex-end;
    gap: 2px;
}

.chart-col-group {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 2px; /* the 2px surface gap between touching marks */
    height: 100%;
}

.chart-col {
    display: block;
    position: relative;
    width: 100%;
    max-width: 24px;      /* thin marks — never fill the slot */
    min-width: 2px;
    border-radius: 4px 4px 0 0;  /* rounded data-end, square baseline */
    transition: filter var(--duration-fast);
}

.chart-col:hover { filter: brightness(1.25); }

.chart-peak {
    position: absolute;
    top: -14px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 0.66rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.chart-x {
    grid-row: 2;
    grid-column: 2;
    display: flex;
    margin-top: 4px;
    font-size: 0.66rem;
    color: var(--text-muted);
    min-height: 12px;
}

.chart-x-slot {
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
}

.chart-x-rel { position: relative; }

.chart-x-abs {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    white-space: nowrap;
}

/* Line chart: stretched SVG path (vector-effect keeps the stroke 2px) with
   HTML dots — 8px + a 2px ring in the surface color so they read over the line. */
.chart-line-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

.chart-dot {
    position: absolute;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 0 2px var(--chart-surface);
}

.chart-dot-label {
    position: absolute;
    transform: translate(-50%, -160%);
    font-size: 0.7rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    font-size: 0.72rem;
    color: var(--text-secondary);
    margin-bottom: 8px;
}

.chart-key { display: inline-flex; align-items: center; gap: 6px; }
.chart-key i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

.chart-empty { color: var(--text-muted); font-size: 0.82rem; padding: 14px 0; }

/* ── Bar lists (generalized from the shipped su-bar-* pattern; the su- classes
      themselves are NOT touched) ── */
.dash-bars { display: flex; flex-direction: column; gap: 6px; }

.dash-bar-row {
    display: grid;
    grid-template-columns: minmax(84px, 38%) 1fr 60px;
    align-items: center;
    gap: var(--space-sm);
    font-size: 0.78rem;
    color: var(--text-secondary);
}

/* Names can be Arabic: isolate the bidi run so mixed lists never reorder. */
.dash-bar-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    unicode-bidi: plaintext;
}

/* Same blockified-span rule as .su-bar-track/.su-bar-fill (an inline span
   ignores width/height and would render every bar empty). */
.dash-bar-track {
    display: block;
    height: 12px;
    background: rgba(148, 163, 184, 0.1);
    border-radius: 999px;
    overflow: hidden;
}

.dash-bar-fill {
    display: block;
    height: 100%;
    background: var(--chart-1);
    border-radius: 999px;
    min-width: 0;
}

.dash-bar-value { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.dash-bar-row.neg .dash-bar-value { color: var(--error-color); }
.dash-bar-row.neg .dash-bar-fill { background: var(--error-color); }

/* Clickable rows (negative customers → the customer). */
.dash-bar-row.link { cursor: pointer; }
.dash-bar-row.link:hover .dash-bar-label { color: var(--text-primary); }

/* ── Health strip ── */
.dash-health {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
}

.dash-health-item {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 13px;
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: 999px;
    font-size: 0.78rem;
    color: var(--text-secondary);
}

.dash-health-item.link { cursor: pointer; }
.dash-health-item.link:hover { border-color: var(--accent-light); }
.dash-health-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dash-health-dot.ok { background: var(--success-color); }
.dash-health-dot.warn { background: #FBBF24; }
.dash-health-dot.bad { background: var(--error-color); }

/* ── Run 11: collapsible groups ── */
.dash-group { margin-bottom: var(--space-sm); }

.dash-group-head {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    background: none;
    border: none;
    border-bottom: 1px solid var(--border-default);
    cursor: pointer;
    padding: 6px 0;
    margin-bottom: var(--space-md);
    color: var(--text-secondary);
    font-family: var(--font-display);
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    text-align: left;
    transition: color var(--duration-fast);
}

.dash-group-head:hover { color: var(--text-primary); }

.dash-group-chevron {
    display: inline-block;
    font-size: 0.75rem;
    transition: transform var(--duration-fast);
}

.dash-group.collapsed .dash-group-chevron { transform: rotate(-90deg); }

/* ── Run 11: empty-range rescue banner (§3.3) — informational, not a warning ── */
.dash-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-sm) var(--space-md);
    padding: 12px 16px;
    background: rgba(123, 128, 212, 0.08);
    border: 1px solid rgba(123, 128, 212, 0.35);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-lg);
    font-size: 0.85rem;
    color: var(--text-primary);
}

/* Run 11: muted "· N CRM" suffix in the teachers Sessions cell (the folded
   column). Not a money figure — it names the free subset of the merged count. */
.dash-crm-suffix {
    color: var(--text-muted);
    font-size: 0.92em;
    white-space: nowrap;
}

/* Refetch keeps the frame: previous render dims, no skeleton flash. */
#view-dashboard.dash-refreshing .dash-kpis,
#view-dashboard.dash-refreshing .dash-row,
#view-dashboard.dash-refreshing .dash-strip,
#view-dashboard.dash-refreshing .dash-banner,
#view-dashboard.dash-refreshing .dash-group-head,
#view-dashboard.dash-refreshing .dash-health { opacity: 0.55; }

/* Teachers/upcoming tables inside cards stay compact. */
.dash-card .data-table th, .dash-card .data-table td { padding: 9px 10px; font-size: 0.8rem; }
.dash-card .data-table td { font-variant-numeric: tabular-nums; }
.dash-card .data-table td.td-name { font-variant-numeric: normal; }

@media (max-width: 900px) {
    .dash-kpis { grid-template-columns: repeat(2, 1fr); }
    .dash-row { grid-template-columns: 1fr; }
    .dash-kpi-value { font-size: 1.4rem; }
    /* The dashboard's in-card tables hide nothing: they are 3–5 short numeric
       columns (the global nth-child hiders above target the big list tables). */
    .dash-card .data-table th:nth-child(5), .dash-card .data-table td:nth-child(5),
    .dash-card .data-table th:nth-child(6), .dash-card .data-table td:nth-child(6) {
        display: table-cell;
    }
}

/* ═══════════ Run 12 — per-group-size teacher rates + session subject ═══════════ */

/* The five per-size rate inputs (teacher form + HR hire modal). */
.rate-tiers-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px;
}

.rate-tier-fld {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.rate-tier-fld span {
    font-size: 0.72rem;
    color: var(--text-secondary);
    white-space: nowrap;
}

.rate-tier-fld .filter-input {
    width: 100%;
    min-width: 0;
    padding-left: 10px;
    padding-right: 6px;
}

@media (max-width: 600px) {
    /* Five in a row is unreadable on a phone — 3 + 2. */
    .rate-tiers-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* Payroll rate cell for a tiered teacher; the title attr carries the five rates. */
.rate-by-size {
    color: var(--text-secondary);
    border-bottom: 1px dotted var(--text-muted);
    cursor: help;
    white-space: nowrap;
}

/* Session subject next to the student name in the appointments table. */
.td-subject {
    color: var(--text-muted);
    font-size: 0.82em;
    font-weight: 400;
}

/* ═══════════════════════════════════════════
   Run 13 — Student app: Students tab, Inbox tab,
   App-requests sub-tab, customer app-account chip
   ═══════════════════════════════════════════ */

/* Appointments sub-tab views (same pattern as .hr-subview) */
.appt-subview { display: none; }
.appt-subview.active { display: block; }

/* Count pill inside a sub-tab button (pending app requests). */
.subtab-count {
    display: inline-block;
    min-width: 18px;
    margin-left: 6px;
    padding: 0 6px;
    border-radius: 999px;
    background: rgba(245, 158, 11, 0.2);
    color: #FBBF24;
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1.6;
    text-align: center;
}

/* ── Students tab ── */
/* One pending signup in the approval strip. */
.student-pending-item {
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
}
.student-pending-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    flex-wrap: wrap;
}
.student-pending-name { font-weight: 600; color: var(--text-primary); overflow-wrap: anywhere; }
.student-pending-sub {
    display: block;
    margin-top: 4px;
    font-size: 0.82rem;
    color: var(--text-secondary);
    overflow-wrap: anywhere;
}
.student-pending-unlock {
    display: block;
    margin-top: 6px;
    font-size: 0.8rem;
    color: var(--text-muted);
    line-height: 1.5;
}
.student-pending-actions {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    flex-shrink: 0;
}
/* Student table cells carry emails + chips — let them wrap (teacher-table precedent). */
#studentTable td.td-name,
#studentTable td.td-email {
    max-width: 280px;
    white-space: normal;
    text-overflow: clip;
    overflow-wrap: anywhere;
}
.badge-demo { background: rgba(123, 128, 212, 0.18); color: #A5A8FF; }
.badge-deleted { background: rgba(99, 109, 140, 0.18); color: var(--text-muted); }
.student-settings-row { align-items: flex-end; }
.student-settings-row .form-field { flex: 0 0 auto; }
#studentCutoffMin { max-width: 140px; }

/* "📱 App account" chip on the customer modal (Run 13 §4 mitigation): the
   mismatch between a booked customer and the app account holding it must be
   visible wherever the customer renders. */
.app-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    background: rgba(123, 128, 212, 0.12);
    border: 1px solid rgba(123, 128, 212, 0.35);
    color: var(--accent-light);
    font-size: 0.8rem;
    overflow-wrap: anywhere;
}

/* ── Inbox tab ── */
.inbox-layout {
    display: flex;
    gap: var(--space-lg);
    align-items: stretch;
    min-height: 480px;
}
.inbox-list-pane {
    flex: 0 0 340px;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.inbox-filters { margin-bottom: var(--space-sm); }
.inbox-threads {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}
.inbox-thread-item {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 10px 12px;
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    cursor: pointer;
}
.inbox-thread-item:hover { border-color: var(--accent-light); }
.inbox-thread-item.active { border-color: var(--border-focus); background: rgba(46, 49, 146, 0.15); }
.inbox-thread-main { flex: 1; min-width: 0; }
.inbox-thread-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    color: var(--text-primary);
    font-size: 0.9rem;
    overflow-wrap: anywhere;
}
.inbox-thread-preview {
    margin-top: 2px;
    font-size: 0.8rem;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.inbox-thread-side {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    font-size: 0.72rem;
    color: var(--text-muted);
}
.inbox-unread {
    min-width: 20px;
    padding: 1px 7px;
    border-radius: 999px;
    background: rgba(239, 65, 54, 0.25);
    color: #FCA5A5;
    font-family: var(--font-display);
    font-size: 0.7rem;
    font-weight: 700;
    text-align: center;
}
.chip-teacher-thread { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.chip-ops-thread { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }

.inbox-thread-pane {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
.inbox-thread-placeholder {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    font-size: 0.9rem;
    padding: var(--space-lg);
}
.inbox-thread-view {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}
.inbox-thread-head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 12px var(--space-md);
    border-bottom: 1px solid var(--border-default);
}
.inbox-back { display: none; }
.inbox-thread-who { min-width: 0; }
.inbox-thread-name { display: block; font-weight: 600; color: var(--text-primary); overflow-wrap: anywhere; }
.inbox-thread-sub { display: block; font-size: 0.78rem; color: var(--text-muted); overflow-wrap: anywhere; }
.inbox-oversight {
    padding: 8px var(--space-md);
    background: rgba(245, 158, 11, 0.1);
    border-bottom: 1px solid rgba(245, 158, 11, 0.3);
    color: #FBBF24;
    font-size: 0.8rem;
    line-height: 1.5;
}

/* Message bubbles. The STUDENT is the counterparty → left; us/teacher → right;
   the auto-reply is ours but marked. */
.chat-msgs {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: var(--space-md);
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.chat-msg { max-width: 78%; display: flex; flex-direction: column; }
.chat-msg.from-them { align-self: flex-start; align-items: flex-start; }
.chat-msg.from-us { align-self: flex-end; align-items: flex-end; }
.chat-bubble {
    padding: 8px 12px;
    border-radius: var(--radius-md);
    font-size: 0.9rem;
    line-height: 1.5;
    color: var(--text-primary);
    overflow-wrap: anywhere;
    white-space: pre-wrap;
    unicode-bidi: plaintext; /* Arabic lines render RTL inside an LTR page */
}
.chat-msg.from-them .chat-bubble {
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-bottom-left-radius: 4px;
}
.chat-msg.from-us .chat-bubble {
    background: rgba(46, 49, 146, 0.45);
    border: 1px solid rgba(123, 128, 212, 0.35);
    border-bottom-right-radius: 4px;
}
.chat-msg.from-auto .chat-bubble {
    background: rgba(245, 158, 11, 0.08);
    border: 1px dashed rgba(245, 158, 11, 0.4);
}
.chat-meta {
    margin-top: 3px;
    font-size: 0.7rem;
    color: var(--text-muted);
}
.chat-img {
    display: block;
    max-width: 240px;
    max-height: 240px;
    border-radius: var(--radius-sm);
    margin-top: 6px;
}
.chat-file-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 6px;
    color: var(--accent-light);
    font-size: 0.85rem;
    text-decoration: none;
    overflow-wrap: anywhere;
}
.chat-file-link:hover { text-decoration: underline; }
.chat-day-sep {
    align-self: center;
    font-size: 0.72rem;
    color: var(--text-muted);
    padding: 2px 10px;
    background: var(--bg-input);
    border-radius: 999px;
}

.chat-composer {
    display: flex;
    align-items: flex-end;
    gap: var(--space-sm);
    padding: 10px var(--space-md);
    border-top: 1px solid var(--border-default);
}
.chat-attach-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    background: var(--bg-input);
    cursor: pointer;
    font-size: 1rem;
}
.chat-attach-btn:hover { border-color: var(--accent-light); }
.chat-input {
    flex: 1;
    min-width: 0;
    resize: none;
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: var(--font-body);
    font-size: 0.9rem;
    padding: 9px 12px;
    max-height: 120px;
}
.chat-input:focus { outline: none; border-color: var(--border-focus); }
.chat-send { flex-shrink: 0; }
.chat-attach-chip {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin: 0 var(--space-md) 10px;
    padding: 6px 10px;
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    font-size: 0.82rem;
    color: var(--text-secondary);
    overflow-wrap: anywhere;
}
#inboxSendError { margin: 0 var(--space-md) 10px; }

/* Phones: one pane at a time — the list, then the thread with a Back button.
   Driven by a class so JS controls WHICH pane shows, not a media query alone. */
@media (max-width: 900px) {
    .inbox-layout { flex-direction: column; min-height: 0; }
    .inbox-list-pane { flex: 1 1 auto; }
    .inbox-thread-pane { min-height: 60vh; }
    .inbox-layout.thread-open .inbox-list-pane { display: none; }
    .inbox-layout:not(.thread-open) .inbox-thread-pane { display: none; }
    .inbox-back { display: inline-flex; }
    .chat-msg { max-width: 90%; }
}
.app-chip-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* While the Inbox view is open, toasts dock TOP-right instead of bottom-right:
   they are pointer-events:auto and stack upward, so a burst of them climbs the
   screen and lands exactly on the composer's Send button, eating the click
   (proven by hit-test in the Run 13 harness). Top-right can never reach it. */
body.inbox-active .toast-host { top: 84px; bottom: auto; }
/* Cold-read fixes (Run 13):
   — the srq Student cell carries the "unverified" chip after a free-text name;
     the default 180px nowrap-ellipsis cell clipped the chip out of sight, so
     these cells wrap instead (the #teacherTable precedent);
   — the students table's name/email cells get a floor so the phone layout
     doesn't wrap them into one-character-per-line towers. */
#srqTable td.td-name {
    max-width: 280px;
    min-width: 140px;
    white-space: normal;
    text-overflow: clip;
    overflow-wrap: anywhere;
}
#studentTable td.td-name { min-width: 120px; }
#studentTable td.td-email { min-width: 150px; }

/* Desktop: let the Inbox use the screen — a chat squeezed into 480px with dead
   space below it reads as broken (screenshot cold-read). Phones keep the
   stacked flow (the media block above governs there). */
@media (min-width: 901px) {
    .inbox-layout { height: calc(100vh - 170px); min-height: 480px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Run 14 — teacher approval, staff ↔ teacher chat, mention cards, voice notes
   ═══════════════════════════════════════════════════════════════════════════ */
/* "⏳ Awaiting teacher approval" — amber like every other "waiting on someone" chip. */
.badge-awaiting { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
/* Phones hide the Status column (the nth-child rules above), so the awaiting
   state would vanish from the list there — a ⏳ marker rides in the always-
   visible Student cell on narrow screens only (desktop has the chip). */
.awaiting-dot { display: none; }
@media (max-width: 900px) { .awaiting-dot { display: inline; } }
/* The Appointments STATUS cell now carries up to three chips (status, awaiting,
   CRM) — the 180px nowrap/ellipsis cell clipped the awaiting chip to "…"
   (screenshot cold-read). Same remedy as .td-appt-pay: chips only, let it wrap. */
.data-table td.td-appt-status {
    max-width: 180px;
    white-space: normal;
    text-overflow: clip;
    line-height: 1.9;
}
.cal-chip.cal-chip-awaiting { border-style: dashed; opacity: 0.85; }
.awaiting-band {
    padding: 12px 14px;
    border-radius: var(--radius-md);
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.35);
}
.awaiting-band-head { font-size: 0.9rem; color: #FBBF24; font-weight: 600; margin-bottom: 6px; }
.awaiting-band-text { font-size: 0.85rem; color: var(--text-secondary); line-height: 1.6; }
.awaiting-band .appt-actions { margin-top: var(--space-sm); }
/* Booking form: the approval row sits under the teacher select. */
.approve-field { margin-top: 10px; }
.approve-field .field-hint { margin: 4px 0 0 26px; }

/* Inbox: staff ↔ teacher threads */
.chip-staff-teacher { background: rgba(56, 189, 248, 0.15); color: #38BDF8; }
.tchat-start { position: relative; margin-bottom: var(--space-sm); }
.tchat-start-btn { width: 100%; justify-content: center; }
.tchat-picker {
    margin-top: 6px;
    padding: 8px;
    background: var(--bg-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
}
.tchat-picker-list { margin-top: 6px; max-height: 240px; overflow-y: auto; }

/* Mention picker — docked ABOVE the composer (never over the Send button). */
.mention-picker {
    margin: 0 var(--space-md) 8px;
    padding: 10px;
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
}
.mention-picker-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); margin-bottom: 8px; }
.mention-seg .seg-btn { padding: 6px 10px; font-size: 0.8rem; }
.mention-results { margin-top: 8px; max-height: 220px; overflow-y: auto; }
.mention-results .req-result-name { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.mention-chip { color: var(--accent-light); }

/* The mention card inside a bubble column. */
.ref-card {
    min-width: 220px;
    max-width: 100%;
    margin-bottom: 4px;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    background: rgba(123, 128, 212, 0.1);
    border: 1px solid rgba(123, 128, 212, 0.4);
    font-size: 0.85rem;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}
.ref-card.openable { cursor: pointer; }
.ref-card.openable:hover { border-color: var(--accent-light); }
.ref-card.ref-unavailable { color: var(--text-muted); border-style: dashed; background: transparent; }
.ref-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.ref-card-type { font-size: 0.75rem; color: var(--accent-light); font-weight: 600; letter-spacing: 0.02em; }
.ref-card-name { font-weight: 600; }
.ref-card-facts { margin-top: 2px; font-size: 0.8rem; color: var(--text-secondary); }
.ref-card-pay { margin-top: 6px; font-size: 0.8rem; font-weight: 600; }
.ref-card-pay.due { color: #FBBF24; }
.ref-card-pay.paid { color: #4ADE80; }

/* Voice notes: recorder bar + player bubble (markup from /voice.js). */
.voice-rec-bar {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: 10px var(--space-md);
    border-top: 1px solid var(--border-default);
    font-size: 0.85rem;
    color: var(--text-primary);
}
.voice-rec-dot { width: 10px; height: 10px; border-radius: 50%; background: #EF4136; animation: voicePulse 1s ease-in-out infinite; flex-shrink: 0; }
@keyframes voicePulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
.voice-rec-label { flex: 1; }
.voice-rec-time { font-family: var(--font-display); font-variant-numeric: tabular-nums; }
.voice-msg {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 200px;
    padding: 6px 10px;
    margin-top: 4px;
    border-radius: var(--radius-md);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
}
.chat-msg.from-us .voice-msg { background: rgba(46, 49, 146, 0.45); border-color: rgba(123, 128, 212, 0.35); }
.voice-play {
    width: 32px; height: 32px; flex-shrink: 0;
    border-radius: 50%;
    border: 1px solid var(--border-default);
    background: var(--accent-primary);
    color: #fff;
    font-size: 0.8rem;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
}
.voice-track { flex: 1; height: 6px; border-radius: 999px; background: rgba(255, 255, 255, 0.12); overflow: hidden; min-width: 80px; }
.voice-bar { height: 100%; width: 0%; background: var(--accent-light); transition: width 0.2s linear; }
.voice-time { font-size: 0.72rem; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.voice-msg.voice-error .voice-time { color: var(--error-color); }
.voice-chip { align-items: center; }
.voice-chip .voice-msg { margin-top: 0; flex: 1; }
.voice-chip-player { flex: 1; min-width: 0; }

/* HEIC chip bubble (non-Safari): the link flows as text inside a bubble. */
.chat-file-bubble { display: block; }
.chat-file-link.chat-file-plain { display: inline; margin: 0; }
.chat-file-bubble .mini-sub { display: block; margin-top: 2px; }
/* Phones: the composer row now carries three icon buttons — shrink them and the
   gaps so the text box keeps a usable width at 390px. */
@media (max-width: 600px) {
    .chat-composer { gap: 6px; padding: 8px 10px; }
    .chat-attach-btn { width: 34px; height: 34px; font-size: 0.9rem; }
    .chat-send { padding: 8px 12px; }
    .chat-input { padding: 8px 10px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Run 15 — request lifecycle · "Send via app" · teacher decline ≠ cancel ·
   extra-time payment links · honest recording-wait copy
   ═══════════════════════════════════════════════════════════════════════════ */

/* "📱 Send via app" — the twin of the green WhatsApp buttons, in the panel's
   own accent so the two channels are told apart at a glance. */
.app-send-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--accent-primary);
    color: #fff;
    border: none;
}
.app-send-btn:hover:not(:disabled) { background: var(--accent-light); color: #fff; }
.app-send-btn:disabled { opacity: 0.65; cursor: default; }

/* Toast carrying one inline action ("Open in Inbox"). */
.toast.toast-with-action { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; }
.toast-link {
    flex-shrink: 0;
    padding: 4px 10px;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--accent-light);
    background: rgba(123, 128, 212, 0.14);
    border: 1px solid rgba(123, 128, 212, 0.4);
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.toast-link:hover { background: rgba(123, 128, 212, 0.26); }

/* Declined by the teacher: still awaiting, but the OFFICE has to move now —
   red where the awaiting chip is amber. */
.badge-declined-teacher { background: rgba(239, 68, 68, 0.16); color: #F87171; }
.cal-chip.cal-chip-declined { border-style: dashed; border-color: rgba(239, 68, 68, 0.55); opacity: 1; }
.awaiting-band.declined {
    background: rgba(239, 68, 68, 0.08);
    border-color: rgba(239, 68, 68, 0.35);
}
.awaiting-band.declined .awaiting-band-head { color: #F87171; }
/* The band's red/amber tint drops `--text-muted` (#636D8C) to 3.32:1 on the
   declined band and 3.17:1 on the awaiting one — under AA for a 0.8rem label,
   and "Cancel appointment" / "Mark declined by teacher" are two of the THREE
   answers the office has to give here, not de-emphasised escape hatches.
   #FCA5A5 measures 8.98:1 / 8.56:1 on the same two grounds. (Screenshot
   cold-read; the plain-card .disconnect-btn elsewhere is untouched.) */
.awaiting-band .disconnect-btn { color: #FCA5A5; border-color: rgba(239, 68, 68, 0.45); }
.awaiting-band .disconnect-btn:hover { color: #FECACA; }
/* The app-requests Status cell can carry two chips (derived status + "teacher
   declined") — same remedy as the appointments status cell: let it wrap. */
.data-table td.td-srq-status {
    max-width: 200px;
    white-space: normal;
    text-overflow: clip;
    line-height: 1.9;
}

/* Appointment detail → Payment → the extra-time links, each with its own row of
   share buttons (they are separate purchases from the session's own charge). */
.extra-link-list { margin-top: var(--space-xs); }
.extra-link-row {
    padding: 8px 0;
    border-top: 1px solid var(--border-default);
}
.extra-link-list .extra-link-row:first-child { border-top: none; }
.extra-link-head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    font-size: 0.85rem;
    margin-bottom: 6px;
}
.extra-link-row .appt-actions { margin-top: 0; }

/* Recordings tab → the "still coming" strip above the delivered cards. */
.rec-pending-strip {
    margin-bottom: var(--space-md);
    padding: 12px 14px;
    background: rgba(245, 158, 11, 0.07);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: var(--radius-md);
}
.rec-pending-head { font-size: 0.85rem; font-weight: 600; color: #FBBF24; margin-bottom: 6px; }
.rec-pending-row {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    flex-wrap: wrap;
    padding: 4px 0;
    font-size: 0.85rem;
}
/* Auto-recording was off: nothing is coming, and that is not a warning. */
.rec-status.rec-off { color: var(--text-muted); font-style: italic; }

/* A toast is nearly the full width of a phone and the stack is docked bottom-
   right at z-index 3000 — exactly over a modal's footer buttons (Close / Save).
   Proven unreachable with document.elementFromPoint at 390×844: a "Sent in the
   app" toast swallowed the presses meant for the modal underneath (the Run 14
   click-eating-toast class, now that Run 15 raises a toast at many more send
   sites). On narrow screens only the toast's own ACTION stays clickable; the
   body no longer intercepts anything (toasts still auto-dismiss after ~5 s). */
@media (max-width: 600px) {
    .toast { pointer-events: none; cursor: default; }
    .toast .toast-link { pointer-events: auto; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Run 16 — HR interview recording + the candidate evaluation sheet
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Approve-to-Hire table on phones (reviewer A1) ──
   The generic rule (admin.css:824) hides columns 5 and 6 of EVERY .data-table.
   #hrHireTable is Name · Phone · Status · Score · Interviews · Actions, so the
   generic rule would hide Interviews AND the Hire button — and the Hire button
   was already invisible at ≤900px before this run (a pre-existing defect: the
   owner drives this panel as a phone PWA and could not hire from it).
   Scoped to this ONE table: keep Name · Status · Score · Actions, drop Phone and
   Interviews. `#id td:nth-child(n)` (1,1,1) outranks `.data-table td:nth-child(n)`
   (0,2,1), so the re-show wins wherever the generic rule applies. */
@media (max-width: 900px) {
    #hrHireTable th:nth-child(2),
    #hrHireTable td:nth-child(2),
    #hrHireTable th:nth-child(5),
    #hrHireTable td:nth-child(5) {
        display: none;
    }

    #hrHireTable th:nth-child(6),
    #hrHireTable td:nth-child(6) {
        display: table-cell;
    }

    /* …and re-showing the column is still not the same as being able to press the
       button. Measured at 390 px: this table lives inside a `.panel-section >
       .panel-body`, which leaves the wrapper only 306 px, while the four remaining
       columns wanted 414 px — so the Hire button sat at x=366..440, entirely outside
       the visible strip, reachable only by scrolling a table sideways inside a card.
       Trim the padding this ONE table pays for so the four columns fit. */
    #hr-hire .panel-body {
        padding-left: var(--space-sm);
        padding-right: var(--space-sm);
    }

    #hrHireTable th,
    #hrHireTable td {
        padding-left: 8px;
        padding-right: 8px;
    }

    #hrHireTable .hr-hire-btn {
        padding-left: 10px;
        padding-right: 10px;
    }
}

/* ── Score cell (HR Requests + Approve to Hire) ── */
.eval-score { font-weight: 600; color: var(--text-primary); }
.eval-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 6px;
    vertical-align: middle;
}
.eval-dot-hire { background: #4ADE80; }
.eval-dot-hold { background: #FBBF24; }
.eval-dot-reject { background: #F87171; }

/* ── The evaluation sheet ── */
.eval-head {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
    padding-bottom: var(--space-md);
    border-bottom: 1px solid var(--border-default);
}
.eval-score-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: 999px;
    font-family: var(--font-display);
    font-size: 0.95rem;
    font-weight: 600;
    color: #FBBF24;
    background: rgba(251, 191, 36, 0.12);
    border: 1px solid rgba(251, 191, 36, 0.3);
}
.eval-head-sub { font-size: 0.8rem; color: var(--text-secondary); }
.eval-head-sub .eval-sub-line { display: block; }

.eval-field { margin-bottom: var(--space-md); }
.eval-field:last-child { margin-bottom: 0; }
.eval-flabel {
    display: block;
    margin-bottom: 6px;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-primary);
}
.eval-req { color: var(--error-color); }
.eval-field .field-hint { margin-top: 4px; }

/* One-tap answers: enum / multi / 1–5 scale all render as the same chip row. */
.eval-opts { display: flex; flex-wrap: wrap; gap: 6px; }
.eval-opt {
    padding: 8px 14px;
    font-family: var(--font-display);
    font-size: 0.83rem;
    font-weight: 500;
    color: var(--text-secondary);
    background: var(--bg-input);
    border: 1px solid var(--border-default);
    border-radius: 999px;
    cursor: pointer;
    transition: color var(--duration-fast) var(--ease-out),
        background var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out);
}
.eval-opt:hover { color: var(--text-primary); border-color: var(--accent-light); }
.eval-opt.active {
    color: #fff;
    background: var(--accent-primary);
    border-color: var(--accent-primary);
}

.eval-scale { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; }
.eval-scale-end { font-size: 0.75rem; color: var(--text-secondary); }
.eval-scale-opt { min-width: 42px; text-align: center; }

/* A required field the server named in a failed Submit. */
.eval-field.missing .eval-flabel { color: #F87171; }
.eval-field.missing .eval-opts .eval-opt,
.eval-field.missing .eval-input { border-color: rgba(239, 68, 68, 0.55); }

.eval-error:empty { display: none; }
/* The status line can grow to a full sentence ("⚠ Not saved — …"), which wraps the
   footer onto two rows. `margin-left:auto` keeps Save/Submit on the right edge when
   that happens, instead of dropping them under the error text. */
.eval-footer { gap: var(--space-sm) var(--space-md); flex-wrap: wrap; }
.eval-foot-left,
.eval-foot-right { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; }
.eval-foot-left { flex: 1 1 auto; min-width: 0; }
.eval-foot-right { margin-left: auto; }
.eval-save-status { font-size: 0.8rem; color: var(--text-secondary); }
.eval-save-status.eval-saved { color: #4ADE80; }
.eval-save-status.eval-failed { color: #F87171; }

/* Evaluation entries on the candidate's timeline (E2 D3 — they ride on the
   application, never on the interview, so they survive an interview delete). */
.timeline-item.ti-eval { border-left-color: #FBBF24; }

/* Evaluation rows on the application detail / interview detail. */
.eval-mini { cursor: pointer; }
.eval-mini:hover { border-color: var(--accent-light); }
.eval-chip-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.badge-eval-draft { background: rgba(148, 163, 194, 0.15); color: var(--text-secondary); }
.badge-eval-hire { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }
.badge-eval-hold { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.badge-eval-reject { background: rgba(239, 68, 68, 0.15); color: #F87171; }

/* The read-only verdict strip above the (mandatory) hourly rate in the hire modal. */
.eval-strip {
    margin-bottom: var(--space-md);
    padding: 12px 14px;
    background: rgba(46, 49, 146, 0.12);
    border: 1px solid rgba(123, 128, 212, 0.35);
    border-radius: var(--radius-md);
    font-size: 0.85rem;
    color: var(--text-primary);
    line-height: 1.6;
}
.eval-strip-head { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; margin-bottom: 4px; }
.eval-strip-facts { color: var(--text-secondary); }
.eval-strip-by { font-size: 0.78rem; color: var(--text-secondary); margin-top: 2px; }

/* ═══ Run 17 ═══════════════════════════════════════════════════════════════ */

/* HR → Recordings: the BINDING privacy line (owner decision 2).
   HR interview recordings are shared anyone-with-link, so a staff member about to
   forward one must be told what they are forwarding. A BANNER above the results —
   not a tooltip, not a hover, and never below the fold on a phone: it is the first
   thing in the sub-tab, so it is on screen the moment the tab opens. The same
   sentence appears under the links in the interview detail (as `.detail-warn`) and
   inside both copy toasts, at the exact moment a link leaves the panel. */
.rec-warn-banner {
    margin-bottom: var(--space-md);
    padding: 10px 14px;
    background: rgba(239, 68, 68, 0.08);
    border: 1px solid rgba(239, 68, 68, 0.35);
    border-radius: var(--radius-md);
    color: #F87171;
    font-size: 0.84rem;
    line-height: 1.5;
}
/* Second line of a recording card: status badge + who scheduled the interview
   (`hr_appointments` has no interviewer column — the scheduler is the honest
   stand-in, reviewer R6). */
.rec-card-sub {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-bottom: var(--space-sm);
    font-size: 0.82rem;
    color: var(--text-secondary);
}
/* The interview-detail warning sits under the links, on its own line. */
.rec-link-row + p.detail-warn { margin-top: 2px; }

/* ── The older evaluation sheet (F1) ──
   A score produced by the retired FOUR-scale sheet is not comparable with a
   three-scale one. Never silently recomputed on read (it is a recorded judgment),
   so it is MARKED instead: a `*` on every chip, a notice in the modal, and the
   retired answers listed read-only so nothing that was asked disappears quietly. */
.eval-older-star {
    color: #FBBF24;
    font-weight: 700;
    margin-left: 1px;
    cursor: help;
}

/* Run 17 (checker LOW): a phone cannot show a `title`, and the owner works from
   one — so a starred list also carries this footnote. Muted, small, never shown
   when no starred row is present. */
.eval-older-footnote {
    margin: 6px 2px 0;
    font-size: 0.75rem;
    color: var(--text-secondary);
}

.eval-older-note {
    margin: var(--space-sm) 0 var(--space-md);
    padding: 10px 14px;
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: var(--radius-md);
    color: #FBBF24;
    font-size: 0.82rem;
    line-height: 1.55;
}
.eval-legacy-list { display: flex; flex-direction: column; gap: 6px; margin-top: var(--space-sm); }
/* A GRID, not a flex row: the value column has to line up down the block, and the
   longest label ("Hours per week he can take") is wider than any min-width worth
   setting. On a phone the pair stacks — read side by side at 390px, a muted label
   and its value are one run-on line. */
.eval-legacy-row {
    display: grid;
    grid-template-columns: minmax(0, 210px) minmax(0, 1fr);
    gap: 2px var(--space-sm);
    align-items: baseline;
    font-size: 0.85rem;
}
.eval-legacy-label { color: var(--text-secondary); }
.eval-legacy-value { color: var(--text-primary); overflow-wrap: anywhere; }

@media (max-width: 600px) {
    .eval-legacy-row { grid-template-columns: 1fr; }
    .eval-legacy-label { font-size: 0.78rem; }
}
