:root {
    color-scheme: light;
    --bg: #f3f7fc;
    --surface: #ffffff;
    --text: #1e2f42;
    --muted: #6b7b8c;
    --border: #d7dfe8;
    /* Brand palette (COLOR_PALETTE.md): gold #ef9d10, charcoal #3b4d61,
       grey #6b7b8c (--muted above). --accent is a darker step of the same
       gold hue (OKLCH L .55 vs the swatch's L .76) -- the literal swatch
       only has 2.2:1 contrast against white, well under the 4.5:1 text
       needs when used as a link/button color (--accent fills both roles
       across the app). --gold is the literal swatch, for decorative fills
       and chart highlights where text-on-it isn't a concern. --charcoal is
       the literal swatch for header/nav surfaces. */
    --accent: #a95c00;
    --gold: #ef9d10;
    --charcoal: #3b4d61;
    --row-hover: #e9eff7;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
}

.version-badge {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.55);
}

.site-header-brand {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.site-header {
    background: var(--charcoal);
    color: #fff;
    padding: 18px 32px;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.site-header a {
    color: #fff;
    text-decoration: none;
}

.site-header h1 {
    margin: 0;
    font-size: 1.3em;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 20px;
}

.breadcrumb {
    font-size: 0.9em;
    color: var(--muted);
}

.breadcrumb a {
    color: var(--muted);
}

.user-info {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 0.85em;
}

a.user-icon {
    display: inline-flex;
    align-items: center;
    color: var(--muted);
}

a.user-icon:hover {
    color: var(--text);
}

.logout-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 12px;
    color: var(--muted);
    font-size: 0.85em;
    text-decoration: none;
    transition: color 0.15s ease, border-color 0.15s ease, background-color 0.15s ease;
}

.logout-link:hover {
    color: #dc2626;
    border-color: rgba(220, 38, 38, 0.35);
    background: rgba(220, 38, 38, 0.06);
}

.portal-search {
    position: relative;
}

.portal-search-input {
    width: 220px;
    font: inherit;
    font-size: 0.85em;
    color: #fff;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 999px;
    padding: 6px 14px;
}

.portal-search-input::placeholder {
    color: rgba(255, 255, 255, 0.55);
}

.portal-search-input:focus {
    outline: none;
    width: 280px;
    background: rgba(255, 255, 255, 0.16);
    border-color: rgba(255, 255, 255, 0.45);
    transition: width 0.15s ease;
}

.portal-search-results {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 50;
    width: 320px;
    max-height: 420px;
    overflow-y: auto;
    overflow-x: hidden;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 8px;
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.18);
}

.portal-search-group + .portal-search-group {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border);
}

.portal-search-group-label {
    padding: 4px 8px;
    font-size: 0.72em;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--muted);
}

/* .site-header a { color: #fff } targets every anchor inside the header —
   including .portal-search-item, since the results dropdown is DOM-nested
   inside .site-header even though it renders as a light-background overlay
   below it. That rule's extra tag selector out-specifies plain
   ".portal-search-item", making the text white-on-white and invisible.
   The extra class here (two classes vs. one class + one tag) wins instead. */
.portal-search-results .portal-search-item {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 8px;
    border-radius: 8px;
    color: var(--text);
    text-decoration: none;
    font-size: 0.9em;
}

.portal-search-item:hover {
    background: var(--row-hover);
}

.portal-search-item-title {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.portal-search-item-sub {
    flex-shrink: 0;
    max-width: 40%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.82em;
    color: var(--muted);
}

.portal-search-empty {
    padding: 12px 8px;
    font-size: 0.85em;
    color: var(--muted);
}

@media (max-width: 700px) {
    .portal-search-input,
    .portal-search-input:focus {
        width: 140px;
    }
}

.level-badge {
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 999px;
    padding: 4px 12px;
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
    white-space: nowrap;
}

.view-as-form {
    display: inline-flex;
}

.view-as-form select {
    appearance: none;
    -webkit-appearance: none;
    font: inherit;
    font-size: 0.85em;
    color: #fff;
    background: rgba(79, 70, 229, 0.35);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: 999px;
    padding: 4px 28px 4px 12px;
    cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='white'%3E%3Cpath fill-rule='evenodd' d='M5.23 7.21a.75.75 0 011.06.02L10 11.19l3.71-3.96a.75.75 0 111.1 1.02l-4.25 4.5a.75.75 0 01-1.1 0l-4.25-4.5a.75.75 0 01.02-1.06z' clip-rule='evenodd'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 8px center;
    background-size: 14px;
}

.view-as-form select:hover {
    background-color: rgba(79, 70, 229, 0.5);
}

.view-as-form select option {
    color: var(--text);
    background: var(--surface);
}

/* Uniform warning/notice popups — every flashed message (login errors, form
   confirmations, "not allowed" notices) renders the same way: a toast that
   fades in top-right, sits for 3s, fades out. See main.js setupToasts(). */
.toast-container {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 10px;
    pointer-events: none;
}

.toast {
    max-width: 340px;
    padding: 12px 16px;
    border-radius: 8px;
    font-size: 0.9em;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
    border: 1px solid var(--border);
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.25s ease, transform 0.25s ease;
}

.toast-visible {
    opacity: 1;
    transform: translateY(0);
}

.toast-error {
    background: #dc2626;
    border-color: #dc2626;
    color: #fff;
}

.toast-info {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

/* Auth card */
.auth-card {
    max-width: 400px;
    margin: 40px auto 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 32px;
}

.auth-card h2 {
    margin-top: 0;
}

.auth-hint {
    color: var(--muted);
    font-size: 0.9em;
    margin-bottom: 24px;
}

.auth-form {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.auth-form label {
    font-size: 0.85em;
    color: var(--muted);
}

.auth-form input {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    font-size: 1em;
}

.auth-form input:focus,
.auth-form textarea:focus {
    outline: none;
    border-color: var(--accent);
}

.auth-form input::placeholder {
    font-size: 0.85em;
}

.auth-form textarea {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    font-size: 1em;
    font-family: inherit;
    resize: vertical;
}

.auth-submit {
    margin-top: 12px;
    padding: 10px 16px;
    border: none;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    font-size: 0.95em;
    font-weight: 600;
    cursor: pointer;
}

.auth-resend {
    margin-top: 16px;
    text-align: center;
}

/* Profile page */
.profile-card {
    max-width: 480px;
}

.profile-header {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding-bottom: 20px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--border);
}

.profile-avatar {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--accent);
    color: #fff;
    font-size: 1.3em;
    font-weight: 600;
}

.profile-header-info {
    flex: 1;
    min-width: 0;
}

.profile-name-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.profile-name {
    margin: 0;
    font-size: 1.15em;
    font-weight: 600;
    overflow-wrap: anywhere;
}

.profile-badge {
    flex-shrink: 0;
    display: inline-block;
    border: 1px solid rgba(79, 70, 229, 0.3);
    border-radius: 999px;
    padding: 2px 10px;
    background: rgba(79, 70, 229, 0.08);
    color: var(--accent);
    font-size: 0.72em;
    font-weight: 600;
    white-space: nowrap;
}

.profile-email {
    margin: 4px 0 0;
    color: var(--muted);
    font-size: 0.9em;
    overflow-wrap: anywhere;
}

.profile-details {
    display: flex;
    flex-direction: column;
    margin: 0;
}

.profile-detail {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);
}

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

.profile-detail dt {
    margin: 0;
    color: var(--muted);
    font-size: 0.85em;
}

.profile-detail dd {
    margin: 0;
    font-weight: 500;
    text-align: right;
    overflow-wrap: anywhere;
}

.profile-footer {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    display: flex;
    justify-content: flex-end;
}

@media (max-width: 480px) {
    .profile-header {
        flex-direction: column;
        align-items: flex-start;
    }

    .profile-detail {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }

    .profile-detail dd {
        text-align: left;
    }
}

.link-button {
    background: none;
    border: none;
    color: var(--accent);
    font-size: 0.85em;
    cursor: pointer;
    text-decoration: underline;
}

main {
    max-width: 1100px;
    margin: 0 auto;
    padding: 32px 24px 64px;
}

/* Dev OTP-bypass verification animation */
.verify-anim-card {
    text-align: center;
}

.verify-check {
    width: 72px;
    height: 72px;
    margin: 0 auto 16px;
}

.verify-check svg {
    width: 100%;
    height: 100%;
}

.verify-check-circle {
    stroke: var(--accent);
    stroke-width: 2;
    stroke-dasharray: 151;
    stroke-dashoffset: 38;
    transform-origin: center;
}

.verify-spin {
    animation: verify-spin 1s linear infinite;
}

.verify-check-mark {
    stroke: var(--accent);
    stroke-width: 3;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: 36;
    stroke-dashoffset: 36;
}

.verify-done .verify-check-circle {
    animation: verify-circle 0.5s ease-out forwards;
}

.verify-done .verify-check-mark {
    animation: verify-mark 0.35s ease-out 0.45s forwards;
}

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

@keyframes verify-circle {
    to { stroke-dashoffset: 0; }
}

@keyframes verify-mark {
    to { stroke-dashoffset: 0; }
}

h2 {
    margin-top: 40px;
}

/* Wide data-table pages: use the full viewport width instead of the centered 1100px column */
body:has(main .full-width-page) main {
    max-width: none;
}

/* Home page: welcome hero + a fixed (non-randomized) quick-access grid,
   inside the standard centered/scrolling main layout used everywhere else. */
.portal-home {
    display: flex;
    flex-direction: column;
    gap: 28px;
}

.portal-hero {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    background: linear-gradient(135deg, #16222e, #223344 55%, #3b4d61);
    color: #fff;
    border-radius: 16px;
    padding: 32px 36px;
}

.portal-eyebrow {
    margin: 0;
    font-size: 0.78em;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.65);
}

.portal-hero-title {
    margin: 6px 0 6px;
    font-size: 1.7em;
    line-height: 1.2;
}

.portal-hero-sub {
    margin: 0;
    font-size: 0.9em;
    color: rgba(255, 255, 255, 0.75);
}

.portal-hero-badge {
    flex-shrink: 0;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 999px;
    padding: 6px 16px;
    font-size: 0.8em;
    font-weight: 600;
    letter-spacing: 0.02em;
    background: rgba(255, 255, 255, 0.08);
    white-space: nowrap;
}

.portal-section-title {
    margin: 0 0 14px;
    font-size: 0.8em;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
}

.portal-section-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.portal-section-header .portal-section-title {
    margin-bottom: 0;
}

.portal-section-link {
    flex-shrink: 0;
    font-size: 0.85em;
    font-weight: 600;
    color: var(--accent);
    text-decoration: none;
}

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

.portal-home .blog-list {
    margin-top: 14px;
}

.whatsnew-slideshow {
    position: relative;
    margin: 14px auto 0;
    width: 100%;
    max-width: 680px;
    height: 280px;
    border: 1px solid var(--border);
    border-radius: 16px;
    background: var(--surface);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
    overflow: hidden;
}

.whatsnew-slides {
    position: relative;
    height: 100%;
}

.whatsnew-slide {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 12px;
    padding: 32px 70px;
    text-decoration: none;
    color: var(--text);
    opacity: 0;
    visibility: hidden;
    transform: translateX(16px);
    transition: opacity 0.5s ease, transform 0.5s ease, visibility 0.5s;
}

.whatsnew-slide.active {
    opacity: 1;
    visibility: visible;
    transform: translateX(0);
    z-index: 1;
}

.whatsnew-slide-top {
    display: flex;
    align-items: center;
    gap: 8px;
}

.whatsnew-badge {
    flex-shrink: 0;
    font-size: 0.8em;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 4px 10px;
    border-radius: 6px;
}

.whatsnew-badge-blog {
    background: rgba(169, 92, 0, 0.1);
    color: #a95c00;
}

.whatsnew-badge-library {
    background: rgba(54, 73, 95, 0.1);
    color: #36495f;
}

.whatsnew-badge-people {
    background: rgba(103, 125, 149, 0.12);
    color: #677d95;
}

.whatsnew-slide-title {
    margin: 0;
    font-size: 1.7em;
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.whatsnew-slide-meta {
    margin: 0;
    font-size: 1em;
    color: var(--muted);
}

.whatsnew-slide-desc {
    margin: 0;
    font-size: 1.1em;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.whatsnew-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 42px;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    border-radius: 50%;
    background: var(--surface);
    color: var(--text);
    font-size: 1.6em;
    line-height: 1;
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

.whatsnew-arrow:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.whatsnew-prev {
    left: 20px;
}

.whatsnew-next {
    right: 20px;
}

.whatsnew-dots {
    position: absolute;
    bottom: 14px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    display: flex;
    gap: 6px;
}

.whatsnew-dot {
    width: 8px;
    height: 8px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--border);
    cursor: pointer;
    transition: width 0.2s ease, background-color 0.2s ease;
}

.whatsnew-dot.active {
    width: 20px;
    border-radius: 4px;
    background: var(--accent);
}

@media (max-width: 700px) {
    .whatsnew-slide {
        padding: 24px 20px;
    }

    .whatsnew-arrow {
        display: none;
    }
}

.loan-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 14px;
}

.loan-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
}

.loan-title {
    flex: 1;
    min-width: 0;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.loan-meta {
    flex-shrink: 0;
    font-size: 0.82em;
    color: var(--muted);
    white-space: nowrap;
}


.tile-grid {
    display: grid;
    gap: 16px;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

.tile {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 20px 22px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    text-decoration: none;
    color: var(--text);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.tile:hover {
    transform: translateY(-2px);
    border-color: var(--tile-accent);
    box-shadow: 0 10px 24px rgba(15, 23, 42, 0.08);
}

.tile-icon {
    width: 42px;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    font-size: 1.3em;
    color: var(--tile-accent);
    background: var(--tile-bg);
}

/* Emoji glyphs are fixed-color (COLR/CPAL color fonts) and ignore CSS
   `color`, so they couldn't pick up --tile-accent -- replaced with inline
   stroke="currentColor" SVGs so each tile's icon tints with its brand
   accent automatically. */
.tile-icon svg {
    width: 22px;
    height: 22px;
}

.tile-title {
    font-weight: 600;
    color: var(--tile-accent);
}

.tile-desc {
    font-size: 0.82em;
    color: var(--muted);
    line-height: 1.4;
}

/* Tile identity classes: icon-badge and title colors per section.
   Brand-constrained (COLOR_PALETTE.md: gold/charcoal/grey) -- 9 steps
   alternating the gold and charcoal/grey hue families at varied lightness,
   same method as the ILDB zone donut (validate_palette.js: adjacent CVD
   ΔE 15.9, normal-vision ΔE 18.0, both clear). With only 3 source hues,
   tiles sharing a family necessarily share a bg tint; the emoji icon and
   title text remain each tile's primary identity, this accent is a
   secondary, brand-consistent signal rather than a unique hue per tile. */
.tile-blog { --tile-bg: #ffecc9; --tile-accent: #a95c00; }
.tile-library { --tile-bg: #eaf3fc; --tile-accent: #36495f; }
.tile-attendance { --tile-bg: #ffecc9; --tile-accent: #db8a00; }
.tile-dashboard { --tile-bg: #eaf3fc; --tile-accent: #1c2f44; }
.tile-internal-db { --tile-bg: #ecf3f9; --tile-accent: #505f6f; }
.tile-chat { --tile-bg: #ffecc9; --tile-accent: #c07100; }
.tile-guide { --tile-bg: #eaf3fc; --tile-accent: #677d95; }
.tile-report-archive { --tile-bg: #ffecc9; --tile-accent: #7f3500; }
.tile-audit-log { --tile-bg: #ecf3f9; --tile-accent: #8a9aac; }
.tile-raid-manager { --tile-bg: #ffecc9; --tile-accent: #db8a00; }
.tile-raid-librarian { --tile-bg: #eaf3fc; --tile-accent: #36495f; }
.tile-raid-bot { --tile-bg: #ffecc9; --tile-accent: #c07100; }
.tile-survey-tools { --tile-bg: #ecf3f9; --tile-accent: #6c7c8d; }
.tile-public-site { --tile-bg: #ffecc9; --tile-accent: #a95c00; }

/* Placeholder tiles for not-yet-built features: visually inert, no hover/click affordance. */
.tile-disabled {
    cursor: default;
    opacity: 0.55;
}

.tile-disabled:hover {
    transform: none;
    border-color: var(--border);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

/* Guest (logged-out) home view: branded sign-in prompt, no quick-access grid. */
.portal-guest {
    max-width: 520px;
    margin: 40px auto 0;
    text-align: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 48px 40px;
}

.portal-guest-badge {
    display: inline-block;
    margin-bottom: 16px;
    padding: 6px 16px;
    border-radius: 999px;
    background: rgba(79, 70, 229, 0.08);
    color: var(--accent);
    font-size: 0.8em;
    font-weight: 700;
    letter-spacing: 0.04em;
}

.portal-guest h1 {
    margin: 0 0 12px;
    font-size: 1.4em;
}

.portal-guest p {
    margin: 0 0 24px;
    color: var(--muted);
    line-height: 1.5;
}

.auth-submit-link {
    display: inline-block;
    padding: 10px 24px;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    font-weight: 600;
    text-decoration: none;
}

.portal-hero-signin {
    margin-top: 14px;
}

@media (max-width: 700px) {
    .portal-hero {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* Table search box */
.table-search {
    width: 100%;
    max-width: 320px;
    padding: 8px 12px;
    margin-bottom: 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    font-size: 0.95em;
}

.table-search:focus {
    outline: none;
    border-color: var(--accent);
}

.table-wrap {
    overflow-x: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
}

table.data-table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    font-size: 0.92em;
}

table.data-table th,
table.data-table td {
    text-align: left;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
    overflow-wrap: break-word;
}

table.data-table th:first-child,
table.data-table td:first-child {
    width: 1%;
    white-space: nowrap;
}

table.data-table thead th {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--surface);
    color: var(--muted);
    text-transform: uppercase;
    font-size: 0.75em;
    border-bottom: 2px solid var(--border);
}

table.data-table thead th.sortable {
    cursor: pointer;
    user-select: none;
}

table.data-table thead th.sortable:hover {
    color: var(--text);
}

table.data-table thead th.sort-asc::after,
table.data-table thead th.sort-desc::after {
    margin-left: 6px;
    font-size: 0.9em;
    color: var(--accent);
}

table.data-table thead th.sort-asc::after {
    content: "\2191";
}

table.data-table thead th.sort-desc::after {
    content: "\2193";
}

table.data-table tbody tr:hover {
    background: var(--row-hover);
}

table.data-table tbody tr[data-detail] {
    cursor: pointer;
}

table.data-table tbody tr:last-child td {
    border-bottom: none;
}

/* Full-bleed table: stretches edge-to-edge of the viewport regardless of the
   page's own padding/max-width, independent of ancestor centering. */
.table-wrap-bleed {
    width: 100vw;
    position: relative;
    left: 50%;
    right: 50%;
    margin-left: -50vw;
    margin-right: -50vw;
    border-radius: 0;
    border-left: none;
    border-right: none;
    /* .table-wrap sets overflow-x: auto, which per spec forces the paired
       overflow-y to compute as "auto" too (a "visible" axis can't coexist
       with a non-visible one) — that silently turns this element into a
       scroll container. It never actually grows an internal scrollbar
       (nothing here constrains its height), so visually nothing changes,
       but position:sticky inside it now anchors to *this* element instead
       of the viewport, and since this box always moves in lockstep with
       the page (it never scrolls relative to itself), "sticky" here is
       equivalent to static — the whole thead + genre tabs + search bar
       disappear on scroll instead of sticking. Since this wrapper is
       already 100vw (full-bleed), it doesn't need its own horizontal
       scrollbar the way narrower .table-wrap instances might; resetting
       to overflow: visible removes the accidental scroll container and
       makes the real viewport the sticky positioning ancestor again. */
    overflow: visible;
}

/* The books table has two narrow leading numeric columns (SlNo, No.), not
   just one — the generic first-child squeeze alone left the second column
   at full width under table-layout:fixed, but the first column's own
   width:1% left no room to honor its own padding, so its content and the
   second column's content ended up rendered flush against each other
   (e.g. "7" and "2" reading as "72"). "width:1%" under table-layout:fixed
   is unreliable for this (columns can even render with a negative offset)
   — explicit pixel widths, generous enough for padding + a couple of
   digits, render correctly instead. */
#booksTable th:first-child,
#booksTable td:first-child,
#booksTable th:nth-child(2),
#booksTable td:nth-child(2) {
    width: 56px;
    white-space: nowrap;
}

/* The audit log's first column holds a full ISO timestamp
   ("2026-09-12T12:54:06"), not a short ID — the generic .data-table
   first-child squeeze (width:1%) is meant for narrow ID/checkbox columns
   and is unreliable under table-layout:fixed for anything wider (see the
   #booksTable comment above): it rendered near-zero width here and the
   timestamp text overflowed, visually overlapping the "By" column next to
   it. Same fix as booksTable — an explicit width generous enough for the
   full timestamp plus padding. */
#auditTable th:first-child,
#auditTable td:first-child {
    width: 180px;
    white-space: nowrap;
}

/* The ildb table has no narrow leading column, so it shouldn't inherit the
   generic .data-table first-child squeeze meant for ID/checkbox columns. */
#ildbTable th:first-child,
#ildbTable td:first-child {
    width: auto;
    white-space: normal;
}

/* Same story for the Server Status "Databases" table: its first column is
   the database name (variable length, e.g. "attendance"), not a short ID —
   the generic first-child squeeze rendered it near-zero width and
   overlapped it with the Size column next to it. Here the SECOND column
   is the genuinely narrow one (just a number), so give that the explicit
   width instead. */
#dbSizesTable th:first-child,
#dbSizesTable td:first-child {
    width: auto;
    white-space: normal;
}

#dbSizesTable th:nth-child(2),
#dbSizesTable td:nth-child(2) {
    width: 100px;
    white-space: nowrap;
}

/* Internal database tables can have many/wide columns — size to content and
   let .table-wrap's overflow-x handle horizontal scrolling instead of
   wrapping/squeezing every column into the viewport width. */
#ildbTable {
    width: auto;
    min-width: 100%;
    table-layout: auto;
}

#ildbTable th,
#ildbTable td {
    white-space: nowrap;
}

#ildbTable th {
    position: relative;
    user-select: none;
}

.col-resize-handle {
    position: absolute;
    top: 0;
    right: -4px;
    width: 8px;
    height: 100%;
    cursor: col-resize;
    z-index: 2;
}

.col-resize-handle:hover,
.col-resize-handle.resizing {
    background: var(--accent);
    opacity: 0.4;
}

body.col-resizing {
    cursor: col-resize;
    user-select: none;
}

.row-count {
    color: var(--muted);
    font-size: 0.85em;
    margin: 8px 0 0;
}

@media (max-width: 768px) {
    main {
        padding: 20px 12px 48px;
    }

    table.data-table {
        font-size: 0.85em;
    }

    table.data-table th,
    table.data-table td {
        padding: 8px 10px;
    }
}

@media (max-width: 480px) {
    table.data-table {
        font-size: 0.78em;
    }

    table.data-table th,
    table.data-table td {
        padding: 6px 8px;
    }
}

/* Row detail modal */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    z-index: 100;
}

.modal-overlay[hidden] {
    display: none;
}

.modal {
    position: relative;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 12px;
    width: 100%;
    max-width: 480px;
    max-height: 80vh;
    overflow-y: auto;
    padding: 28px 24px 24px;
}

.modal-title {
    margin: 0 0 16px;
    padding-right: 24px;
    font-size: 1.2em;
}

.modal-close {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--muted);
    font-size: 1.2em;
    line-height: 1;
    cursor: pointer;
}

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

.modal-body {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 8px 16px;
    margin: 0;
}

.modal-body dt {
    color: var(--muted);
    font-size: 0.8em;
    text-transform: uppercase;
    white-space: nowrap;
}

.modal-body dd {
    margin: 0;
    word-break: break-word;
}

.modal-actions {
    margin-top: 20px;
}

.modal-actions form {
    margin: 0;
}

.modal-request-btn {
    width: 100%;
    padding: 10px 16px;
    border: none;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    font-size: 0.95em;
    font-weight: 600;
    cursor: pointer;
}

.modal-request-btn:disabled {
    background: var(--border);
    color: var(--muted);
    cursor: default;
}

/* ILDB detail popup (Director/Senior Manager dashboards) -- click-through
   from a headline stat, a vitality row, or a breakdown card to its full
   underlying list, optionally with a chart (zone donut only -- see
   apps/ildb/__init__.py's health_snapshot for why family/script don't get
   one: too many categories for a pie/donut to stay readable). */
.ildb-detail-modal {
    max-width: 460px;
}

.ildb-detail-modal-sub {
    margin: -10px 0 16px;
    font-size: 0.82em;
    color: var(--muted);
}

.ildb-detail-modal-chart {
    display: flex;
    justify-content: center;
    margin-bottom: 18px;
}

.ildb-donut-svg {
    width: 160px;
    height: 160px;
}

.ildb-donut-svg circle {
    transition: opacity 0.15s ease;
}

.ildb-donut-svg:hover circle {
    opacity: 0.45;
}

.ildb-donut-svg circle:hover {
    opacity: 1;
}

.ildb-detail-modal-list {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 45vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ildb-detail-modal-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 4px;
    border-radius: 6px;
    font-size: 0.88em;
}

.ildb-detail-modal-row:hover {
    background: var(--row-hover);
}

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

.ildb-detail-modal-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ildb-detail-modal-value {
    flex-shrink: 0;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

/* Clickable ILDB boxes -- headline stats, vitality rows, breakdown cards */
[data-ildb-detail] {
    cursor: pointer;
}

.ildb-headline-stat[data-ildb-detail]:hover,
.ildb-vitality-row[data-ildb-detail]:hover {
    background: var(--row-hover);
}

.ildb-breakdown-card-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
}

.ildb-breakdown-card-header h3 {
    margin: 0;
}

.ildb-breakdown-view-all {
    flex-shrink: 0;
    background: none;
    border: none;
    padding: 0;
    font-size: 0.78em;
    font-family: inherit;
    color: var(--accent);
    cursor: pointer;
}

.ildb-breakdown-view-all:hover {
    text-decoration: underline;
}

/* Book requests */
.request-status {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 6px;
    font-size: 0.8em;
    text-transform: uppercase;
    border: 1px solid var(--border);
    color: var(--muted);
}

.request-status-pending {
    color: #6b7b8c;
    border-color: rgba(107, 123, 140, 0.3);
    background: rgba(107, 123, 140, 0.08);
}

.request-status-issued,
.request-status-approved {
    color: #a95c00;
    border-color: rgba(169, 92, 0, 0.3);
    background: rgba(169, 92, 0, 0.08);
}

.request-status-rejected {
    color: #1e2f42;
    border-color: rgba(30, 47, 66, 0.3);
    background: rgba(30, 47, 66, 0.08);
}

.request-actions {
    display: flex;
    gap: 8px;
}

.request-actions form {
    margin: 0;
}

.request-actions button {
    padding: 6px 12px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    font-size: 0.85em;
    cursor: pointer;
}

.request-actions .request-accept-btn {
    border-color: var(--accent);
    color: var(--accent);
}

.request-actions .request-reject-btn {
    border-color: #1e2f42;
    color: #1e2f42;
}

/* Blog */
.blog-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 24px;
}

.blog-header h2 {
    margin: 0;
}

.blog-new-btn {
    padding: 8px 16px;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    font-weight: 600;
    font-size: 0.9em;
    text-decoration: none;
}

.blog-tabs {
    display: flex;
    gap: 4px;
    margin-top: 20px;
    border-bottom: 1px solid var(--border);
}

.blog-tab {
    padding: 8px 16px;
    border: none;
    background: none;
    color: var(--muted);
    font-size: 0.9em;
    font-weight: 600;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

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

.blog-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

.blog-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 16px;
    margin-top: 20px;
}

.blog-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 16px 18px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    text-decoration: none;
    color: var(--text);
    transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
}

.blog-card:hover {
    background: var(--row-hover);
    border-color: var(--accent);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
    transform: translateY(-2px);
}

.blog-card-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    font-size: 1.05em;
}

.blog-internal-badge {
    font-size: 0.65em;
    text-transform: uppercase;
    color: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 6px;
    padding: 1px 6px;
    font-weight: 600;
}

.blog-card-meta {
    font-size: 0.8em;
    color: var(--muted);
}

.blog-card-excerpt {
    font-size: 0.9em;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.blog-empty {
    color: var(--muted);
    margin-top: 20px;
}

.blog-form {
    max-width: 640px;
    margin-top: 20px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.blog-form label {
    font-size: 0.8em;
    text-transform: uppercase;
    color: var(--muted);
    margin-top: 8px;
}

.blog-form input[type="text"],
.blog-form textarea {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 0.95em;
    resize: vertical;
}

.blog-form button {
    align-self: flex-start;
    margin-top: 8px;
    padding: 10px 20px;
    border: none;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    font-weight: 600;
    cursor: pointer;
}

.blog-form input[type="file"] {
    font-size: 0.9em;
}

.blog-checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 12px;
    font-size: 0.9em;
    text-transform: none;
    color: var(--text);
}

.blog-checkbox-label input {
    width: auto;
}

.format-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 4px 0;
}

.format-toolbar button {
    padding: 5px 10px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font-size: 0.8em;
    cursor: pointer;
}

.format-toolbar button:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.format-hint {
    margin: 2px 0 0;
    font-size: 0.78em;
    color: var(--muted);
}

.blog-attachment-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
}

.blog-attachment-remove {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85em;
    font-weight: normal;
    text-transform: none;
    color: var(--text);
}

.blog-attachment-remove input {
    width: auto;
}

.blog-post {
    max-width: 720px;
    margin-top: 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 24px 28px;
}

.blog-post-header h2 {
    margin: 0 0 6px;
    display: flex;
    align-items: center;
    gap: 10px;
}

.blog-post-meta {
    font-size: 0.85em;
    color: var(--muted);
}

.blog-post-actions {
    display: flex;
    gap: 14px;
    align-items: center;
    margin-top: 10px;
    font-size: 0.9em;
}

.blog-post-actions a {
    color: var(--accent);
}

.blog-post-actions form {
    margin: 0;
}

.blog-post-body,
.guide-content {
    margin-top: 20px;
    word-break: break-word;
}

.blog-post-body p,
.guide-content p {
    margin: 0 0 16px;
}

.blog-post-body h3,
.blog-post-body h4,
.blog-post-body h5,
.guide-content h3,
.guide-content h4,
.guide-content h5 {
    margin: 24px 0 10px;
}

.blog-post-body ul,
.guide-content ul {
    margin: 0 0 16px;
    padding-left: 22px;
}

.blog-post-body li,
.guide-content li {
    margin-bottom: 4px;
}

.blog-post-body code,
.guide-content code {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 1px 5px;
    font-size: 0.9em;
}

.blog-post-body a,
.guide-content a {
    color: var(--accent);
}

.guide-layout {
    display: flex;
    align-items: flex-start;
    gap: 32px;
    max-width: 1100px;
    margin: 0 auto;
    padding: 24px 32px;
}

.guide-toc {
    flex: 0 0 220px;
    position: sticky;
    top: 24px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.guide-toc-link {
    padding: 7px 10px;
    border-radius: 6px;
    font-size: 0.88em;
    color: var(--muted);
    text-decoration: none;
    line-height: 1.35;
}

.guide-toc-link:hover {
    background: var(--row-hover);
    color: var(--text);
}

.guide-toc-link.active {
    background: var(--tile-bg, #f5f3ff);
    color: var(--tile-accent, #5b21b6);
    font-weight: 600;
}

.guide-content {
    flex: 1;
    min-width: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 28px 32px;
}

.guide-content h1,
.guide-content h2 {
    margin: 28px 0 12px;
}

.guide-content h1:first-child,
.guide-content h2:first-child {
    margin-top: 0;
}

.guide-content h6 {
    margin: 20px 0 8px;
    color: var(--muted);
    text-transform: uppercase;
    font-size: 0.8em;
    letter-spacing: 0.04em;
}

.guide-content ol {
    margin: 0 0 16px;
    padding-left: 22px;
}

.guide-content ol li {
    margin-bottom: 4px;
}

.guide-content blockquote {
    margin: 0 0 16px;
    padding: 4px 16px;
    border-left: 3px solid var(--border);
    color: var(--muted);
}

.guide-content pre {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 14px 16px;
    overflow-x: auto;
    margin: 0 0 16px;
}

.guide-content pre code {
    background: none;
    border: none;
    padding: 0;
    font-size: 0.85em;
}

.guide-content table {
    border-collapse: collapse;
    width: 100%;
    margin: 0 0 16px;
    font-size: 0.9em;
}

.guide-content th,
.guide-content td {
    border: 1px solid var(--border);
    padding: 6px 10px;
    text-align: left;
}

.guide-content th {
    background: var(--bg);
}

.guide-content hr {
    border: none;
    border-top: 1px solid var(--border);
    margin: 24px 0;
}

.blog-post-attachments {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.blog-attachment {
    font-size: 0.9em;
    color: var(--accent);
    text-decoration: none;
}

.blog-attachment:hover {
    text-decoration: underline;
}

.blog-attachment-size {
    color: var(--muted);
}

.full-width-page h3 {
    margin: 40px 0 0;
}

/* Real genre data runs wider than the tab strip was designed for (long
   names like "Survey Reports", plus near-duplicate genres such as
   "Anthropolgy"/"Anthropology" that both need their own tab) — flex-wrap
   let the strip grow to two ragged lines that pushed the sync button
   around. Kept to a single scrollable line instead: predictable height
   (needed for the sticky stacking below) and no awkward wrap. */
.genre-tabs {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 6px;
    margin: 0;
    min-width: 0;
    flex: 1 1 auto;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
}

.genre-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 0.85em;
    white-space: nowrap;
    flex-shrink: 0;
    cursor: pointer;
}

.genre-tab:hover {
    background: var(--row-hover);
}

.genre-tab.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.genre-tab-count {
    font-size: 0.85em;
    color: var(--muted);
}

/* Library catalog toolbar (genre tabs + sync button) and the search box
   that main.js inserts right after it both stay pinned near the top of the
   viewport while scrolling the 591-row table, stacked one under the other.
   top offsets are set inline by setupStickyToolbar() in main.js (measured
   from actual rendered heights) rather than hardcoded here, since a fixed
   guess would leave a gap or an overlap the moment padding/font-size ever
   changes; the "top: 0" below is just the pre-JS/no-JS fallback for the
   toolbar itself. Opaque backgrounds matter here — without them, table
   rows scrolling underneath would show through. */
.catalog-toolbar {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    margin: 0 0 12px;
    padding: 12px 0;
    background: var(--bg);
}

.catalog-toolbar-sync {
    flex-shrink: 0;
    display: flex;
    gap: 10px;
}

/* "Sync from Sheets" — the primary action here (pulls fresh data, rebuilds
   the table), styled filled/accent like .auth-submit for consistency with
   the rest of the app's primary-action buttons. */
.catalog-toolbar-sync button {
    padding: 8px 16px;
    border: none;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    font: inherit;
    font-size: 0.85em;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}

.catalog-toolbar-sync button:hover {
    filter: brightness(1.08);
}

/* "Open Sheet" — a secondary action (just navigates out, doesn't change
   anything), styled as an accent-outlined button so it reads as related to
   but less prominent than the Sync button next to it. */
.catalog-toolbar-sheet-link {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    padding: 8px 16px;
    border: 1px solid var(--accent);
    border-radius: 8px;
    background: transparent;
    color: var(--accent);
    font-size: 0.85em;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.catalog-toolbar-sheet-link:hover {
    background: var(--accent);
    color: #fff;
}

/* Library admin panel (/library/admin) */
.admin-panel {
    display: flex;
    flex-direction: column;
    gap: 28px;
}

/* A calm, centered placeholder row for an empty table body -- "0 results"
   read as a plain result, not a broken page. */
.table-empty-row td {
    text-align: center;
    color: var(--muted);
    padding: 28px 14px;
}

.admin-panel-source-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 16px 18px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

.admin-panel-source-card-label {
    font-size: 0.75em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
}

.admin-panel-source-card-sub {
    margin: 4px 0 0;
    font-size: 0.85em;
    color: var(--muted);
}

.admin-panel-actions {
    display: flex;
    gap: 10px;
}

.admin-panel-btn {
    display: inline-flex;
    align-items: center;
    padding: 8px 16px;
    border: none;
    border-radius: 8px;
    font: inherit;
    font-size: 0.85em;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.admin-panel-btn-sm {
    padding: 5px 12px;
    font-size: 0.8em;
}

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

.admin-panel-btn-primary:hover {
    filter: brightness(1.08);
}

.admin-panel-btn-outline {
    background: transparent;
    border: 1px solid var(--accent);
    color: var(--accent);
}

.admin-panel-btn-outline:hover {
    background: var(--accent);
    color: #fff;
}

.admin-panel-btn-danger {
    background: transparent;
    border: 1px solid #dc2626;
    color: #dc2626;
}

.admin-panel-btn-danger:hover {
    background: #dc2626;
    color: #fff;
}

.admin-panel-row-actions {
    display: flex;
    gap: 6px;
}

.manager-status-pill,
.manager-approval-pill {
    display: inline-block;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 2px 10px;
    border-radius: 12px;
    color: #fff;
}

.manager-status-present { background: #a95c00; }
.manager-status-absent { background: #1e2f42; }
.manager-status-leave { background: #8c4100; }
.manager-status-unmarked { background: var(--muted); }

.manager-approval-pending { background: var(--muted); }
.manager-approval-approved { background: #a95c00; }
.manager-approval-rejected { background: #1e2f42; }

.leave-balance-box {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 16px 18px;
    margin-bottom: 24px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

.attendance-page-header {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-bottom: 12px;
}

.leave-balance-box-title {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
    margin: 0;
}

.leave-balance-box-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 12px;
}

.leave-balance-tile-lop .leave-balance-tile-remaining {
    color: #1e2f42;
}

.leave-balance-tile-late .leave-balance-tile-remaining {
    color: #d97706;
}

.leave-balance-tile-early .leave-balance-tile-remaining {
    color: #db2777;
}

.leave-balance-tile-worked .leave-balance-tile-remaining {
    color: #0891b2;
}

.leave-balance-tile-remaining-sm {
    font-size: 0.95rem;
}

.leave-balance-tile {
    text-align: center;
    padding: 8px 6px;
    border-radius: 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    min-width: 0;
    overflow: hidden;
}

.leave-balance-tile-label {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--muted);
    letter-spacing: 0.03em;
}

.leave-balance-tile-remaining {
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--accent);
    line-height: 1.2;
    margin: 2px 0;
}

.leave-balance-tile-detail {
    font-size: 0.68rem;
    color: var(--muted);
}

.leave-balance-tile-detail-year {
    margin-top: 1px;
}

.leave-balance-tile-year-num {
    font-weight: 700;
}

.leave-balance-tile-lop .leave-balance-tile-year-num {
    color: #1e2f42;
}

.leave-balance-tile-late .leave-balance-tile-year-num {
    color: #d97706;
}

.leave-balance-tile-bar {
    margin-top: 6px;
    height: 4px;
    border-radius: 3px;
    background: var(--border);
    overflow: hidden;
}

.leave-balance-tile-bar-fill {
    height: 100%;
    background: var(--accent);
    border-radius: 4px;
    transition: width 0.3s ease;
}

.attendance-calendar {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 24px 28px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

.attendance-calendar-header {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 20px;
    margin-bottom: 16px;
}

.attendance-calendar-title {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text);
    min-width: 160px;
    text-align: center;
}

.attendance-calendar-nav {
    color: var(--muted);
    text-decoration: none;
    font-size: 1.2rem;
    padding: 4px 10px;
    border-radius: 6px;
}

.attendance-calendar-nav:hover {
    background: var(--bg);
    color: var(--accent);
}

.attendance-calendar-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 6px;
    margin-bottom: 6px;
}

.attendance-calendar-weekdays {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--muted);
    text-align: center;
    margin-bottom: 10px;
}

.attendance-calendar-cell {
    min-height: 64px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--bg);
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    cursor: pointer;
    position: relative;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.attendance-calendar-cell:not(.attendance-calendar-cell-empty):hover {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    transform: translateY(-1px);
}

.attendance-calendar-cell-empty {
    background: transparent;
    border-color: transparent;
    cursor: default;
}

.attendance-calendar-cell-future {
    cursor: not-allowed;
    opacity: 0.45;
}

.attendance-calendar-cell-future:hover {
    box-shadow: none;
    transform: none;
}

.attendance-calendar-cell-workday.attendance-calendar-cell-unmarked {
    border-color: #a5b4fc;
}

.attendance-calendar-daynum {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text);
}

.attendance-calendar-tag {
    font-size: 0.7rem;
    font-weight: 600;
    align-self: flex-start;
    padding: 2px 6px;
    border-radius: 4px;
}

.attendance-calendar-cell-today {
    border-color: var(--accent);
    border-width: 2px;
    box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
}

.attendance-calendar-today-badge {
    position: absolute;
    top: -8px;
    right: 6px;
    background: var(--accent);
    color: #fff;
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 1px 6px;
    border-radius: 8px;
}

.attendance-calendar-cell-present {
    background: #ffecc9;
    border-color: #f0b85c;
}
.attendance-calendar-cell-present .attendance-calendar-tag {
    background: #a95c00;
    color: #fff;
}

.attendance-calendar-tag-working {
    background: #8c4100 !important;
    animation: attendance-working-pulse 2s ease-in-out infinite;
}

@keyframes attendance-working-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
}

.attendance-calendar-tag-wfh {
    background: #4b6077 !important;
}

.attendance-calendar-times {
    font-size: 0.62rem;
    color: var(--muted);
    align-self: flex-start;
}

.attendance-calendar-cell-absent {
    background: #eaf3fc;
    border-color: #9db0c4;
}
.attendance-calendar-cell-absent .attendance-calendar-tag {
    background: #1e2f42;
    color: #fff;
}

.attendance-calendar-cell-leave {
    background: #ecf3f9;
    border-color: #b9c3cd;
}
.attendance-calendar-cell-leave .attendance-calendar-tag {
    background: #6c7c8d;
    color: #fff;
}

.attendance-calendar-tag-pending {
    background: #6b7b8c !important;
    border: 1px dashed #fff;
}

.attendance-calendar-tag-rejected {
    background: #1e2f42 !important;
    text-decoration: line-through;
}

.attendance-calendar-cell-unmarked {
    background: var(--bg);
}

.attendance-calendar-legend {
    display: flex;
    gap: 18px;
    margin-top: 16px;
    font-size: 0.8rem;
    color: var(--muted);
    flex-wrap: wrap;
}

.attendance-calendar-swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 3px;
    margin-right: 6px;
    vertical-align: middle;
}

@media (max-width: 640px) {
    .attendance-calendar-cell {
        min-height: 40px;
    }
    .attendance-calendar-daynum {
        font-size: 0.7rem;
    }
    .attendance-calendar-tag {
        font-size: 0.6rem;
    }
}

.attendance-mark-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(17, 20, 28, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.attendance-mark-modal-backdrop[hidden] {
    display: none;
}

.attendance-mark-modal {
    background: var(--surface);
    border-radius: 14px;
    padding: 24px 28px;
    width: 320px;
    max-width: calc(100vw - 32px);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
}

.attendance-mark-modal h3 {
    margin: 0 0 14px;
    font-size: 1rem;
    color: var(--text);
}

.attendance-mark-modal form {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.attendance-mark-modal-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.attendance-mark-modal-field[hidden] {
    display: none;
}

.attendance-mark-modal label {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--muted);
}

.attendance-mark-modal select,
.attendance-mark-modal input[type="time"],
.attendance-mark-modal input[type="date"],
.attendance-mark-modal textarea {
    width: 100%;
    padding: 8px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text);
    font-family: inherit;
    resize: vertical;
}

.attendance-mark-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 4px;
}

@media (max-width: 640px) {
    .leave-balance-box-grid {
        grid-template-columns: 1fr;
    }
}

/* Chat page — the messages area fills all remaining space below the
   header (header measures ~70px) down to the viewport bottom; the
   floating input bar (below) sits on top, unaffected by document flow. */
body:has(main .chat-messages-area) main {
    padding: 0;
    height: calc(100vh - 70px);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.chat-title-bar {
    flex-shrink: 0;
    padding: 16px 32px;
    background: var(--surface);
    border: 1px solid var(--border);
    font-weight: 700;
    font-size: 1.05em;
}

.chat-messages-area {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 24px 32px 100px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    border: 1px solid var(--border);
    border-top: none;
}

.chat-message {
    display: flex;
    flex-direction: column;
    max-width: 60%;
}

.chat-message-in {
    align-items: flex-start;
    align-self: flex-start;
}

.chat-message-out {
    align-items: flex-end;
    align-self: flex-end;
}

.chat-message-sender {
    font-size: 0.78em;
    font-weight: 600;
    color: var(--muted);
    margin-bottom: 3px;
    padding: 0 4px;
}

.chat-message-bubble {
    padding: 10px 14px;
    border-radius: 16px;
    font-size: 0.92em;
    line-height: 1.4;
}

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

.chat-message-out .chat-message-bubble {
    background: var(--accent);
    color: #fff;
    border-bottom-right-radius: 4px;
}

.chat-message-time {
    font-size: 0.72em;
    color: var(--muted);
    margin-top: 3px;
    padding: 0 4px;
}

.chat-message-attachment {
    display: inline-block;
    margin-top: 4px;
    font-size: 0.9em;
    text-decoration: underline;
    color: inherit;
}

.chat-box-attach {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    font-size: 1.1em;
    cursor: pointer;
}

.chat-box-attach:hover {
    background: var(--row-hover);
}

.chat-box-filename {
    flex-shrink: 0;
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.8em;
    color: var(--muted);
}

/* Chat page — text box placeholder, floating above the bottom of the
   viewport as a soft rounded "pill" bar rather than a flush-edge strip
   (chat feature being rebuilt from zero, not wired to anything yet). */
.chat-box-placeholder {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    width: min(720px, calc(100% - 48px));
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 8px 8px 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
    transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.chat-box-placeholder:focus-within {
    border-color: var(--accent);
    box-shadow: 0 12px 32px rgba(79, 70, 229, 0.18);
}

.chat-box-input {
    flex: 1;
    padding: 10px 4px;
    border: none;
    background: transparent;
    font: inherit;
    color: var(--text);
}

.chat-box-input:focus {
    outline: none;
}

.chat-box-send {
    flex-shrink: 0;
    padding: 10px 20px;
    border: none;
    border-radius: 999px;
    background: var(--accent);
    color: #fff;
    font: inherit;
    font-size: 0.9em;
    font-weight: 600;
    cursor: pointer;
}

.chat-box-send:hover {
    filter: brightness(1.08);
}

/* The search <input> itself is only max-width:320px — sticky-positioning
   it directly left the rest of that horizontal band (everything right of
   x=320px, e.g. the Call No./L_id/TOC Link columns) with no opaque cover,
   so tall tbody rows (ones that wrap to 2+ lines in a narrow column) still
   showed through above the table header once scrolled. Wrapping the input
   in a full-width bar (below) and making *that* the sticky/opaque element
   fixes it — the input keeps its compact width, the bar behind it doesn't. */
.catalog-search-bar {
    position: sticky;
    z-index: 29;
    background: var(--bg);
    padding-top: 6px;
    padding-bottom: 14px;
}

.table-search.catalog-sticky-search {
    margin: 0;
}

/* Internal database — table switcher within the active .db (real links,
   full page nav — not the client-side genre-tab filter). */
.ildb-table-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 4px 0 16px;
}

.ildb-table-tab {
    display: inline-flex;
    align-items: center;
    padding: 7px 14px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text);
    text-decoration: none;
    font-size: 0.88em;
}

.ildb-table-tab:hover {
    background: var(--row-hover);
}

.ildb-table-tab.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    font-weight: 600;
}

.ildb-empty {
    padding: 32px 20px;
    text-align: center;
    color: var(--muted);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
}

.genre-tab.active .genre-tab-count {
    color: rgba(255, 255, 255, 0.85);
}

/* Admin Dashboard's top-level split: "raid-system" (the app itself) vs.
   "raid-server" (the machine it runs on). Same pill-tab look as
   .ildb-table-tab above. Only present on dashboard_index.html — every
   other dashboard page's .dashboard-app has no sibling tab bar, so this
   never affects them. */
.dashboard-top-tabs {
    display: flex;
    gap: 6px;
    margin: 0 0 16px;
}

.dashboard-top-tab {
    display: inline-flex;
    align-items: center;
    padding: 8px 18px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 0.9em;
    cursor: pointer;
}

.dashboard-top-tab:hover {
    background: var(--row-hover);
}

.dashboard-top-tab.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    font-weight: 600;
}

/* Dashboard — left panel for switching between tables */
.dashboard-app {
    display: flex;
    align-items: flex-start;
    gap: 24px;
}

.dashboard-sidebar {
    width: 220px;
    flex-shrink: 0;
    position: sticky;
    top: 24px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px;
}

.dashboard-nav-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.dashboard-nav-group[hidden] {
    display: none;
}

.dashboard-nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    border: none;
    border-radius: 8px;
    background: none;
    color: var(--text);
    font-family: inherit;
    font-size: 0.92em;
    text-align: left;
    cursor: pointer;
}

.dashboard-nav-item:hover {
    background: var(--row-hover);
}

.dashboard-nav-item.active {
    background: var(--accent);
    color: #fff;
}

.dashboard-nav-item.active .dashboard-nav-count {
    background: rgba(255, 255, 255, 0.2);
    color: #fff;
}

.dashboard-nav-icon {
    font-size: 1.1em;
    flex-shrink: 0;
}

.dashboard-nav-label {
    flex: 1;
    min-width: 0;
}

.dashboard-nav-count {
    flex-shrink: 0;
    min-width: 20px;
    padding: 1px 6px;
    border-radius: 10px;
    background: var(--bg);
    color: var(--muted);
    font-size: 0.78em;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.dashboard-content {
    flex: 1;
    min-width: 0;
}

.dashboard-content h2 {
    margin-top: 0;
}

@media (max-width: 768px) {
    .dashboard-app {
        flex-direction: column;
    }

    .dashboard-sidebar {
        width: 100%;
        position: static;
        flex-direction: row;
        overflow-x: auto;
    }

    .dashboard-nav-item {
        width: auto;
        white-space: nowrap;
    }
}

/* RAID Bot floating widget — global bubble + panel, injected by base.html
   on every page for logged-in staff (tier <= raid_staff), replacing the
   old dedicated /ai-chat page. Deliberately self-contained/dark, same
   ChatGPT-ish look the old page had, scaled down to a corner widget. */
.ai-bot-widget {
    --ai-bot-bg: #ffffff;
    --ai-bot-text: #0d0d0d;
    --ai-bot-muted: #8e8ea0;
    --ai-bot-border: #e5e5e5;
    --ai-bot-bubble-bg: #f4f4f4;
    --ai-bot-accent: #111111;
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 500;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.ai-bot-fab {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: none;
    background: var(--ai-bot-accent);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
    transition: transform 0.15s ease;
}

.ai-bot-fab:hover {
    transform: scale(1.06);
}

.ai-bot-widget.open .ai-bot-fab {
    display: none;
}

.ai-bot-panel {
    display: none;
    flex-direction: column;
    position: absolute;
    right: 0;
    bottom: 0;
    width: 360px;
    height: 520px;
    max-height: calc(100vh - 40px);
    background: var(--ai-bot-bg);
    border-radius: 16px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
    overflow: hidden;
}

.ai-bot-widget.open .ai-bot-panel {
    display: flex;
}

.ai-bot-header {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    background: var(--ai-bot-accent);
    color: #fff;
}

.ai-bot-header-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    font-size: 0.95em;
}

.ai-bot-header-actions {
    display: flex;
    gap: 4px;
}

.ai-bot-icon-btn {
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0.85;
}

.ai-bot-icon-btn:hover {
    opacity: 1;
    background: rgba(255, 255, 255, 0.15);
}

.ai-bot-scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    background: var(--ai-bot-bg);
}

.ai-bot-empty {
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    text-align: center;
    padding: 0 20px;
    color: var(--ai-bot-muted);
}

.ai-bot-empty-icon {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    background: var(--ai-bot-accent);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ai-bot-empty-sub {
    font-size: 0.85em;
    line-height: 1.4;
}

.ai-bot-messages {
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.ai-bot-msg {
    display: flex;
    gap: 8px;
    align-items: flex-start;
}

.ai-bot-msg-user {
    justify-content: flex-end;
}

.ai-bot-msg-avatar {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    background: var(--ai-bot-accent);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ai-bot-msg-avatar-error {
    background: #dc2626;
}

.ai-bot-msg-content {
    flex: 1;
    min-width: 0;
    padding-top: 2px;
    color: var(--ai-bot-text);
    font-size: 0.88em;
    line-height: 1.5;
    word-wrap: break-word;
}

/* Rendered-markdown children (see ai_chat_widget.js's renderMarkdown) --
   marked.js emits real <p>/<ul>/<pre> elements now, so this resets their
   default margins for a compact chat bubble instead of pre-wrap-ing raw text. */
.ai-bot-msg-content p {
    margin: 0 0 8px;
}

.ai-bot-msg-content p:last-child {
    margin-bottom: 0;
}

.ai-bot-msg-content ul,
.ai-bot-msg-content ol {
    margin: 4px 0 8px;
    padding-left: 20px;
}

.ai-bot-msg-content li {
    margin-bottom: 2px;
}

.ai-bot-msg-content code {
    background: rgba(0, 0, 0, 0.06);
    padding: 1px 4px;
    border-radius: 4px;
    font-size: 0.9em;
    font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
}

.ai-bot-msg-content pre {
    background: rgba(0, 0, 0, 0.06);
    padding: 8px;
    border-radius: 6px;
    overflow-x: auto;
    font-size: 0.85em;
    margin: 0 0 8px;
}

.ai-bot-msg-content pre code {
    background: none;
    padding: 0;
}

.ai-bot-msg-content a {
    color: var(--ai-bot-accent);
}

.ai-bot-msg-error-text {
    color: #dc2626;
}

.ai-bot-msg-bubble {
    max-width: 80%;
    padding: 8px 12px;
    border-radius: 14px;
    background: var(--ai-bot-bubble-bg);
    color: var(--ai-bot-text);
    font-size: 0.88em;
    line-height: 1.45;
    white-space: pre-wrap;
    word-wrap: break-word;
}

.ai-bot-loading {
    display: inline-block;
    width: 5px;
    height: 5px;
    background: var(--ai-bot-muted);
    border-radius: 50%;
    animation: ai-bot-pulse 1s infinite;
    margin-right: 3px;
}

.ai-bot-loading:nth-child(2) { animation-delay: 0.15s; }
.ai-bot-loading:nth-child(3) { animation-delay: 0.3s; }

@keyframes ai-bot-pulse {
    0%, 100% { opacity: 0.25; }
    50% { opacity: 1; }
}

.ai-bot-composer {
    flex-shrink: 0;
    padding: 10px;
    border-top: 1px solid var(--ai-bot-border);
}

.ai-bot-form {
    display: flex;
    align-items: flex-end;
    gap: 6px;
    padding: 6px 6px 6px 12px;
    border: 1px solid var(--ai-bot-border);
    border-radius: 20px;
    background: var(--ai-bot-bg);
}

.ai-bot-form:focus-within {
    border-color: #c9c9c9;
}

.ai-bot-input {
    flex: 1;
    border: none;
    outline: none;
    resize: none;
    background: transparent;
    color: var(--ai-bot-text);
    font-family: inherit;
    font-size: 0.88em;
    line-height: 1.4;
    max-height: 100px;
    padding: 6px 0;
}

.ai-bot-input::placeholder {
    color: var(--ai-bot-muted);
}

.ai-bot-send-btn {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 50%;
    background: var(--ai-bot-accent);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.15s ease;
}

.ai-bot-send-btn:hover:not(:disabled) {
    opacity: 0.85;
}

.ai-bot-send-btn:disabled {
    background: var(--ai-bot-border);
    color: var(--ai-bot-muted);
    cursor: not-allowed;
}

@media (max-width: 480px) {
    .ai-bot-widget {
        right: 12px;
        bottom: 12px;
    }

    .ai-bot-panel {
        width: calc(100vw - 24px);
        height: calc(100vh - 100px);
    }
}

/* RAID Bot Dash (/dashboard/raid-bot-dash) headline banner -- same
   boxed-stat-card pattern as the other dashboards' headlines. */
.aibot-headline {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 12px;
    margin-bottom: 18px;
}

.aibot-headline-stat {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 14px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
}

.aibot-headline-num {
    font-size: 1.4em;
    font-weight: 700;
    line-height: 1.2;
    overflow-wrap: anywhere;
}

.aibot-headline-label {
    font-size: 0.75em;
    color: var(--muted);
}

/* Generic bordered card wrapper for a whole .portal-section -- .portal-
   section itself has no box (just a title + bare content), which reads as
   unstructured on pages with several stacked sections. Opt individual
   sections into this rather than changing every .portal-section site-wide. */
.dashboard-card-section {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 18px 20px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

/* RAID Bot Dash (/dashboard/raid-bot-dash) config forms */
.ai-bot-dash-form {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: 520px;
}

.ai-bot-dash-form label {
    font-size: 0.85em;
    font-weight: 600;
    color: var(--muted);
    margin-top: 6px;
}

.ai-bot-dash-form select,
.ai-bot-dash-form input[type="text"] {
    padding: 8px 10px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 0.9em;
}

.ai-bot-dash-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 500;
    color: var(--text);
    cursor: pointer;
}

.ai-bot-dash-prompt {
    max-width: none;
    width: 100%;
    padding: 12px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
    font-size: 0.85em;
    line-height: 1.5;
    resize: vertical;
}

.ai-bot-dash-note {
    font-size: 0.85em;
    color: var(--muted);
    max-width: 640px;
}

.ai-bot-dash-subheading {
    margin: 12px 0 4px;
    font-size: 0.9em;
    font-weight: 700;
    color: var(--text);
}

.ai-bot-dash-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px;
    max-width: 720px;
}

.ai-bot-dash-grid label {
    margin-top: 0;
}

.ai-bot-dash-grid input[type="number"] {
    width: 100%;
    padding: 8px 10px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 0.9em;
}

.ai-bot-dash-hint {
    margin: 4px 0 0;
    font-size: 0.75em;
    color: var(--muted);
    line-height: 1.3;
}

/* RAID Manager Dash > Attendance / Library headline banners, and Director
   Dashboard > ILDB headline -- all the same "grid of individually boxed
   stat cards" pattern (same look as .server-status-card), one class set
   per page so each can restyle independently without touching the others. */
.attendance-headline,
.library-headline,
.ildb-headline {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 12px;
    margin-bottom: 18px;
}

.attendance-headline-stat,
.library-headline-stat,
.ildb-headline-stat {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 14px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
}

.attendance-headline-num,
.library-headline-num,
.ildb-headline-num {
    font-size: 1.6em;
    font-weight: 700;
    line-height: 1.1;
}

.attendance-headline-label,
.library-headline-label,
.ildb-headline-label {
    font-size: 0.75em;
    color: var(--muted);
}

/* Director Dashboard > ILDB headline + vitality chart panel */
.ildb-panel {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 20px 22px 18px;
    margin-bottom: 20px;
}

.ildb-panel-header {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 6px 16px;
    margin-bottom: 16px;
}

.ildb-panel-header h2 {
    margin: 0;
    font-size: 1.15em;
}

/* ildb-panels side by side (EGIDS Vitality / Bible Translation Status /
   Language Status) -- auto-fit so 3 panels share a wide row, 2 share a
   medium one, and it falls back to a single column once a column would get
   too narrow for the vitality-row grid (140px label + track + 80px count)
   to stay comfortable. */
.ildb-panel-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    align-items: stretch;
    gap: 20px;
}

.ildb-panel-row .ildb-panel {
    margin-bottom: 0;
    display: flex;
    flex-direction: column;
}

/* EGIDS Vitality has no donut, so it's naturally shorter than its two
   neighbors (which do) -- stretching the card to match height (above) keeps
   the row's bottom edge even; centering its bars in the leftover space
   avoids a dead gap sitting under them. */
.ildb-panel-row .ildb-vitality-chart {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.ildb-panel-sub {
    font-size: 0.8em;
    color: var(--muted);
}

.ildb-panel-subheading {
    margin: 0 0 14px;
    font-size: 0.95em;
}

.ildb-headline-stat {
    position: relative;
}

.ildb-headline-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 7px;
    border-radius: 50%;
    vertical-align: middle;
}

/* Director Dashboard > ILDB vitality (EGIDS) bar chart */
.ildb-vitality-chart {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ildb-vitality-row {
    display: grid;
    grid-template-columns: 140px 1fr 80px;
    align-items: center;
    gap: 10px;
    padding: 4px 6px;
    margin: 0 -6px;
    border-radius: 6px;
    font-size: 0.85em;
    transition: background 0.15s ease;
}

.ildb-vitality-row:hover {
    background: var(--row-hover);
}

.ildb-vitality-row-label {
    color: var(--text);
}

.ildb-vitality-track {
    display: block;
    height: 12px;
    border-radius: 6px;
    background: var(--bg);
    overflow: hidden;
}

.ildb-vitality-fill {
    display: block;
    height: 100%;
    /* square at the baseline (left), rounded only at the growing end */
    border-radius: 0 4px 4px 0;
    transition: width 0.3s ease;
}

.ildb-vitality-row-count {
    text-align: right;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

@media (max-width: 560px) {
    .ildb-vitality-row {
        grid-template-columns: 1fr;
        gap: 4px;
        padding: 8px 6px;
    }
    .ildb-vitality-row-count {
        text-align: left;
    }
}

/* Director Dashboard > ILDB family/zone/script breakdown lists */
.ildb-breakdown-grid {
    display: grid;
    gap: 18px;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    margin-bottom: 20px;
}

.ildb-breakdown-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 14px 16px;
}

.ildb-breakdown-card h3 {
    margin: 0 0 10px;
    font-size: 0.85em;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.ildb-breakdown-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.ildb-breakdown-row {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 0.85em;
}

.ildb-breakdown-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ildb-breakdown-name-group {
    display: flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

/* Inline donuts (zone, scripture status, language status) -- rendered
   directly on the page (server-computed slice geometry, see
   apps/ildb/__init__.py's donut_slices), not behind a click. Identity comes
   from the list/bars already shown below each one (plus the native <title>
   hover tooltip per slice). */
.ildb-inline-donut {
    display: flex;
    justify-content: center;
    margin-bottom: 16px;
}

.ildb-inline-donut .ildb-donut-svg {
    width: 170px;
    height: 170px;
}

.ildb-breakdown-list .ildb-breakdown-count {
    flex-shrink: 0;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.ildb-breakdown-more {
    margin: 10px 0 0;
    font-size: 0.78em;
    color: var(--muted);
}

/* Senior Manager Dashboard's copy of this page still uses the old flat
   <li><span>name</span><span class="ildb-breakdown-count">n</span></li>
   markup (pre-redesign) -- keep it working unchanged, scoped away from the
   Director Dashboard's new .ildb-breakdown-row markup. */
.ildb-breakdown-list > li:not(.ildb-breakdown-row) {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 0.85em;
}

/* Director Dashboard > ILDB data-completeness meters */
.ildb-completeness {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    margin-bottom: 14px;
}

.ildb-meter-label {
    display: flex;
    justify-content: space-between;
    font-size: 0.78em;
    color: var(--muted);
    margin-bottom: 5px;
}

.ildb-meter-track {
    display: block;
    height: 8px;
    border-radius: 4px;
    background: var(--bg);
}

.ildb-meter-fill {
    display: block;
    height: 100%;
    border-radius: 0 4px 4px 0;
    background: var(--accent);
}

/* Admin Dashboard > Server Status */
.server-status-grid {
    display: grid;
    gap: 12px;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    margin-bottom: 20px;
}

.server-status-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
}

.server-status-label {
    font-size: 0.72em;
    text-transform: uppercase;
    color: var(--muted);
}

.server-status-value {
    font-size: 1.1em;
    font-weight: 600;
}

.server-status-sub {
    font-size: 0.72em;
    color: var(--muted);
}

.error-log-box {
    max-height: 320px;
    overflow-y: auto;
    margin: 0;
    padding: 12px 14px;
    font-family: "Consolas", "Menlo", monospace;
    font-size: 0.8em;
    white-space: pre-wrap;
    word-break: break-word;
}

/* Admin Dashboard > Terminal */
.terminal-box {
    display: flex;
    flex-direction: column;
    border-radius: 10px;
    overflow: hidden;
    background: #0d1117;
    border: 1px solid var(--border);
}

.terminal-output {
    margin: 0;
    padding: 14px;
    height: 360px;
    overflow-y: auto;
    font-family: "Consolas", "Menlo", monospace;
    font-size: 0.85em;
    color: #c9d1d9;
    white-space: pre-wrap;
    word-break: break-word;
}

.terminal-line-command {
    color: #58a6ff;
    font-weight: 600;
}

.terminal-line-error {
    color: #f85149;
}

.terminal-line-stderr {
    color: #f0883e;
}

.terminal-form {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    border-top: 1px solid #21262d;
    background: #161b22;
}

.terminal-prompt {
    color: #58a6ff;
    font-family: "Consolas", "Menlo", monospace;
}

.terminal-input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    color: #c9d1d9;
    font-family: "Consolas", "Menlo", monospace;
    font-size: 0.9em;
}

