﻿/* GK EMS - Modern Responsive Interface System */

:root {
    /* Terra/amber match the brand already used by the sidebar (--sb-terra) and the login
       page — the interior app previously ran a generic blue/orange admin palette that didn't
       match either. #b04a1a (not the lighter #df5f28 used on dark surfaces) is used as the
       *resting* button/link shade specifically because it is the one that clears 4.5:1 against
       both a white card and a white button label; the lighter terra does not (checked, 3.6:1). */
    --gk-primary: #b04a1a;
    --gk-primary-strong: #8f3c15;
    --gk-accent: #f2a541;
    --gk-teal: #0f766e;
    --gk-rose: #be123c;
    --gk-ink: #172033;
    --gk-muted: #667085;
    --gk-line: #d0d7e2;
    --gk-soft-line: #e8eef6;
    --gk-surface: #ffffff;
    --gk-surface-alt: #f6f8fb;
    --gk-sidebar: #1d2939;
    --gk-sidebar-2: #101828;
    --gk-radius: 8px;
    --gk-shadow: 0 16px 44px rgba(16, 24, 40, 0.10);
    --gk-shadow-sm: 0 4px 16px rgba(16, 24, 40, 0.06);
    --gk-ease: cubic-bezier(.2, .8, .2, 1);

    /* ── Buttons ────────────────────────────────────────────────────────────────────
       Every button colour is read from these and from nowhere else, so the dark theme
       is a token swap rather than a twenty-sixth [data-bs-theme="dark"] patch. That
       matters here specifically: the recurring contrast bug in this stylesheet is a
       component hardcoding a light value and inheriting a flipped one for its text,
       and the button family is where that would be most visible. */
    --btn-radius: 10px;

    --btn-primary-bg: var(--gk-primary);
    --btn-primary-bg-hover: var(--gk-primary-strong);
    --btn-primary-fg: #fff;
    --btn-primary-lift: 0 1px 2px rgba(23, 32, 51, .10), 0 4px 14px rgba(176, 74, 26, .20);
    --btn-primary-lift-hover: 0 3px 6px rgba(23, 32, 51, .12), 0 10px 22px rgba(176, 74, 26, .26);
    --btn-primary-press: inset 0 2px 4px rgba(89, 35, 10, .28);

    /* Secondary is a tint, not an outline: the approved direction. */
    --btn-tint-bg: rgba(176, 74, 26, .10);
    --btn-tint-bg-hover: rgba(176, 74, 26, .17);
    --btn-tint-fg: var(--gk-primary-strong);

    /* Quiet is for Cancel and for the second action in a toolbar. */
    --btn-quiet-fg: #475467;
    --btn-quiet-fg-hover: var(--gk-ink);
    --btn-quiet-bg-hover: rgba(23, 32, 51, .06);

    --btn-danger-bg: var(--gk-rose);
    --btn-danger-bg-hover: #9f1239;
    --btn-danger-tint-bg: rgba(190, 18, 60, .10);
    --btn-danger-tint-bg-hover: rgba(190, 18, 60, .18);
    --btn-danger-tint-fg: #9f1239;
    /* Named durations for the entrance/hover animations added in the accent-color pass, so the
       next animation added has a shared vocabulary instead of a new arbitrary number. Values
       match exactly what was already in use — this is a naming pass, not a re-tuning. */
    --motion-fast: 120ms;      /* table row hover */
    --motion-micro: 150ms;     /* button hover lift, small focus/state changes */
    --motion-standard: 360ms;  /* page-hero/detail-hero entrance */
    --motion-complex: 400ms;   /* card-grid entrance — slightly slower + delayed so the page reads top-to-bottom */
    --bs-body-font-family: "Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
    --bs-body-color: var(--gk-ink);
    --bs-primary: var(--gk-primary);
    /* Was 37, 99, 235 — didn't even match this file's own --gk-primary before (#1f6feb is
       31,111,235), a pre-existing mismatch. site-modern.css's :root loads after this one and is
       the value that actually renders; fixed here too so this file isn't self-contradictory. */
    --bs-primary-rgb: 176, 74, 26;
}

html {
    scroll-behavior: smooth;
}

body {
    font-size: 0.95rem;
}

.app-body {
    /* Was amber (245,158,11) + blue (31,111,235) — a two-tone wash from before this app had one
       consistent accent. Now amber + terra, the same pairing used on every module's page-hero. */
    background:
        radial-gradient(circle at top left, rgba(242, 165, 65, 0.10), transparent 28rem),
        radial-gradient(circle at 90% 12%, rgba(176, 74, 26, 0.08), transparent 26rem),
        linear-gradient(180deg, #f8fafc 0%, #eef3f8 100%);
    color: var(--gk-ink);
    text-rendering: optimizeLegibility;
}

a {
    color: var(--gk-primary);
}

a:hover {
    color: var(--gk-primary-strong);
}

*:focus-visible {
    /* Was rgba(245, 158, 11, ...) — the old accent's raw hex before it became #f2a541. */
    outline: 3px solid rgba(242, 165, 65, 0.55);
    outline-offset: 2px;
}

.skip-link {
    position: fixed;
    top: 0.75rem;
    left: 0.75rem;
    z-index: 2000;
    transform: translateY(-150%);
    background: var(--gk-ink);
    color: #fff;
    border-radius: var(--gk-radius);
    padding: 0.6rem 0.85rem;
    text-decoration: none;
}

.skip-link:focus {
    transform: translateY(0);
    color: #fff;
}

/* === App Shell === */
.app-shell {
    min-height: 100vh;
}

#wrapper {
    min-height: 100vh;
}

#page-content {
    min-width: 0;
    overflow: hidden;
}

.app-main {
    padding: 1.5rem;
}

.app-footer {
    background: rgba(255, 255, 255, 0.86);
    border-top: 1px solid var(--gk-soft-line);
    backdrop-filter: blur(12px);
}

/* === Page Structure === */
.page-hero,
.detail-hero,
.profile-header,
.app-main > .d-flex.justify-content-between.align-items-center.mb-4,
.app-main > .d-flex.justify-content-between.align-items-start.mb-4,
.app-main > .d-flex.justify-content-between.align-items-center.mb-4.flex-wrap,
.app-main > .d-flex.justify-content-between.align-items-start.gap-3.flex-wrap.mb-4 {
    padding: 1.15rem 1.25rem;
    border: 1px solid rgba(217, 226, 236, 0.72);
    border-left: 5px solid var(--gk-primary);
    border-radius: var(--gk-radius);
    /* Was rgba(31, 111, 235, ...) + rgba(15, 118, 110, ...) — a blue/teal tint from before this
       app had an accent color at all, left untouched through the orange reskin. Matched to the
       terra/amber accent now instead. */
    background:
        linear-gradient(135deg, rgba(176, 74, 26, 0.12), rgba(242, 165, 65, 0.10)),
        radial-gradient(circle at right top, rgba(242, 165, 65, 0.14), transparent 18rem),
        linear-gradient(135deg, #ffffff, #f8fafc);
    box-shadow: var(--gk-shadow-sm);
    /* Every module's list/detail screen opens with this header — a page-load fade+rise ties them
       all to the same entrance the login page uses, cascading everywhere with no view-file change. */
    animation: fadeInUp var(--motion-standard) var(--gk-ease) both;
}

.page-hero h1,
.page-hero h2,
.page-hero h3,
.page-hero h4,
.detail-hero h1,
.detail-hero h2,
.detail-hero h3,
.detail-hero h4 {
    text-wrap: balance;
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 600;
    letter-spacing: -0.01em;
}

.app-main h4,
.app-main h5 {
    letter-spacing: 0;
}

.app-main > .alert.alert-light {
    background: #fff !important;
    border-color: var(--gk-soft-line) !important;
    box-shadow: var(--gk-shadow-sm) !important;
}

.filter-panel,
.app-main > .card.mb-4 > .card-body:has(form[data-auto-filter="true"]) {
    background: linear-gradient(180deg, #fff 0%, #fbfdff 100%);
}

.section-title {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    margin-bottom: 0;
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 600;
    color: var(--gk-ink);
}

.section-title i {
    color: var(--gk-primary);
}

/* === KPI Cards === */
.metric-card .card-body,
.row.g-3.mb-4 > [class*="col-"] > .card > .card-body.d-flex.align-items-center {
    min-height: 116px;
}

.metric-card-icon,
.row.g-3.mb-4 .rounded-3.p-3 {
    display: inline-grid;
    place-items: center;
    width: 48px;
    height: 48px;
    border-radius: var(--gk-radius) !important;
    flex: 0 0 auto;
}

.metric-value {
    font-size: clamp(1.35rem, 2vw, 1.95rem);
    font-weight: 800;
    line-height: 1;
    color: var(--gk-ink);
}

/* === Workflow Cards === */
.workflow-card,
.receipt-entry,
.liquidation-card {
    border: 1px solid var(--gk-soft-line) !important;
    border-radius: var(--gk-radius) !important;
    background: #fff;
    box-shadow: var(--gk-shadow-sm);
}

.receipt-entry {
    position: relative;
}

.receipt-entry::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    background: linear-gradient(180deg, var(--gk-primary), var(--gk-teal));
    border-radius: var(--gk-radius) 0 0 var(--gk-radius);
}

/* A theme colour, not #f8fafc: this outranks the page styles (!important) and stayed light in dark
   mode, under file names drawn in the light dark-mode text colour - light on light. */
.selected-file-item {
    border-color: var(--gk-soft-line) !important;
    background: var(--bs-tertiary-bg) !important;
}

.empty-state {
    display: grid;
    place-items: center;
    gap: 0.35rem;
    padding: 2.5rem 1rem;
    color: var(--gk-muted);
    text-align: center;
}

.empty-state i {
    font-size: 2rem;
    opacity: 0.35;
}

.quick-action-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 0.85rem;
}

.quick-action-card {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    min-height: 92px;
    padding: 1rem;
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: #fff;
    color: var(--gk-ink);
    text-decoration: none;
    box-shadow: var(--gk-shadow-sm);
    transition: transform 0.18s var(--gk-ease), box-shadow 0.18s var(--gk-ease), border-color 0.18s var(--gk-ease);
}

.quick-action-card:hover {
    /* Was rgba(31, 111, 235, ...), the same stale blue as the other hover/focus rings below. */
    border-color: rgba(176, 74, 26, 0.32);
    color: var(--gk-ink);
    transform: translateY(-2px);
    box-shadow: var(--gk-shadow);
}

.quick-action-icon {
    display: inline-grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border-radius: var(--gk-radius);
    /* Was #eef5ff - the last live survivor of the pre-terracotta blue. The comment on the hover
       ring above records that blue being replaced; this plate sat right beneath it and was missed,
       so a terracotta icon has been sitting on a blue tile ever since.
       Picked to keep the component looking the same rather than merely to be warm: at 1.12:1
       against the white card it carries almost exactly the weight #eef5ff did (1.10:1), so the
       plate still reads as a tile. The icon on it clears 4.5:1. */
    background: #fdf0e6;
    color: var(--gk-primary);
    flex: 0 0 auto;
}

.action-buttons,
.btn-group.action-buttons {
    gap: 0.25rem;
}

.btn-group.action-buttons > .btn {
    border-radius: var(--gk-radius) !important;
}

.sticky-action-bar {
    position: sticky;
    bottom: 0;
    z-index: 20;
    margin: 1rem -1.5rem -1.5rem;
    padding: 1rem 1.5rem;
    background: rgba(255, 255, 255, 0.94);
    border-top: 1px solid var(--gk-soft-line);
    backdrop-filter: blur(12px);
}

.fund-request-list,
.liquidation-list {
    display: grid;
    gap: 0.85rem;
}

.fund-request-card,
.liquidation-card {
    overflow: hidden;
}

.fund-request-meta,
.liquidation-meta {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.75rem;
}

/* === Detail and Form Pages === */
.detail-hero {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.2rem;
    border: 1px solid rgba(217, 226, 236, 0.72);
    border-radius: var(--gk-radius);
    /* Was rgba(37, 99, 235, ...) — same stale blue as the shared page-hero/detail-hero rule
       above; this more specific rule (later in the cascade) is the one that actually wins for
       .detail-hero, so it needed the same fix separately. */
    background:
        linear-gradient(135deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.94)),
        radial-gradient(circle at right top, rgba(242, 165, 65, 0.10), transparent 18rem);
    box-shadow: var(--gk-shadow-sm);
}

.detail-kicker {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.35rem;
    color: var(--gk-muted);
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.detail-title {
    margin: 0;
    color: var(--gk-ink);
    font-size: clamp(1.25rem, 2.2vw, 1.8rem);
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 600;
    line-height: 1.15;
}

.detail-subtitle {
    margin-top: 0.35rem;
    color: var(--gk-muted);
    font-size: 0.92rem;
}

.detail-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.detail-stat-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.75rem;
}

.detail-stat {
    min-height: 84px;
    padding: 0.8rem;
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: #fff;
    box-shadow: var(--gk-shadow-sm);
    transition: transform 0.18s var(--gk-ease), box-shadow 0.18s var(--gk-ease);
}

.detail-stat:hover,
.metric-card:hover,
.workflow-card:hover {
    transform: translateY(-1px);
    box-shadow: var(--gk-shadow);
}

.detail-stat-label,
.info-label {
    color: var(--gk-muted);
    font-size: 0.75rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.detail-stat-value {
    margin-top: 0.25rem;
    color: var(--gk-ink);
    font-size: 1.05rem;
    font-weight: 800;
    overflow-wrap: anywhere;
}

.info-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
}

.info-item {
    min-width: 0;
    padding: 0.78rem;
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: linear-gradient(180deg, #fff 0%, #fbfdff 100%);
}

.info-value {
    margin-top: 0.25rem;
    color: var(--gk-ink);
    font-weight: 700;
    overflow-wrap: anywhere;
}

.info-item-wide {
    grid-column: 1 / -1;
}

.app-main .card {
    border-color: var(--gk-soft-line) !important;
    border-radius: var(--gk-radius);
    box-shadow: var(--gk-shadow-sm);
}

/* Top-level content cards (filter panels, the main list/table card, a detail page's info cards)
   are direct children of <main class="app-main">, or sit one grid cell deep in a metric-card
   row — both shapes are already used throughout the app, so this reaches every module without
   a single view file changing. A touch later than the header above, so the page reads
   top-to-bottom rather than popping in as one block. */
.app-main > .card,
.app-main > .row > [class*="col-"] > .card {
    animation: fadeInUp var(--motion-complex) var(--gk-ease) 0.06s both;
}

.app-main .card-header {
    border-color: var(--gk-soft-line) !important;
    background: linear-gradient(180deg, #fff 0%, #fbfdff 100%) !important;
}

.app-main .card-header h5,
.app-main .card-header h6 {
    letter-spacing: 0;
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
    .page-hero,
    .detail-hero,
    .profile-header,
    .app-main > .d-flex.justify-content-between.align-items-center.mb-4,
    .app-main > .d-flex.justify-content-between.align-items-start.mb-4,
    .app-main > .d-flex.justify-content-between.align-items-center.mb-4.flex-wrap,
    .app-main > .d-flex.justify-content-between.align-items-start.gap-3.flex-wrap.mb-4,
    .app-main > .card,
    .app-main > .row > [class*="col-"] > .card {
        animation: none !important;
    }
}

.app-main .form-label {
    color: #344054;
    font-size: 0.82rem;
    font-weight: 700;
}

.app-main .form-control,
.app-main .form-select {
    border-color: #d0d5dd;
    border-radius: var(--gk-radius);
    min-height: 42px;
}

.app-main .form-control:focus,
.app-main .form-select:focus {
    border-color: var(--gk-primary);
    /* Was rgba(37, 99, 235, ...) — every text field's focus ring was still blue while its border
       went terra; the two are supposed to be the same color. */
    box-shadow: 0 0 0 0.2rem rgba(176, 74, 26, 0.16);
}

.app-main textarea.form-control {
    min-height: auto;
}

.app-main .btn {
    border-radius: var(--gk-radius);
    font-weight: 700;
}

.app-main .table {
    /* Matches the warmed tr[data-href] hover above — same stale blue-white, same fix. */
    --bs-table-hover-bg: #fdf6ee;
    color: var(--gk-ink);
}

.app-main .table thead th {
    border-bottom: 1px solid var(--gk-soft-line);
    color: #475467;
    font-size: 0.76rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    white-space: nowrap;
}

.app-main .table tbody td {
    border-color: var(--gk-soft-line);
    vertical-align: middle;
}

.app-main tr[data-href] {
    cursor: pointer;
}

.app-main tr[data-href]:hover td {
    /* Was #f8fbff, a cool blue-white left over from the same pre-accent era as the button
       shadows above — swapped for a warm cream so a hovered row matches the rest of the app's
       accent, and given a transition so it eases in instead of snapping. */
    background: #fdf6ee;
    transition: background-color var(--motion-fast) var(--gk-ease);
}

[data-href-card] {
    cursor: pointer;
}

.leave-date-cell {
    min-width: 190px;
    color: var(--gk-ink);
    font-size: 0.86rem;
    font-weight: 700;
    white-space: normal;
}

.table-responsive {
    border-radius: var(--gk-radius);
}

.pagination .page-link {
    border-color: var(--gk-soft-line);
    color: var(--gk-ink);
    font-weight: 700;
}

.pagination .active .page-link,
.page-item.active .page-link {
    background: var(--gk-primary);
    border-color: var(--gk-primary);
}

.badge {
    font-weight: 800;
}

.form-section {
    padding: 1rem;
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: #fff;
    box-shadow: var(--gk-shadow-sm);
}

.form-section + .form-section {
    margin-top: 1rem;
}

.form-section-title {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    margin-bottom: 0.85rem;
    color: var(--gk-ink);
    font-weight: 800;
}

.form-section-title i {
    color: var(--gk-primary);
}

.approval-panel,
.review-panel {
    /* Was rgba(245, 158, 11, ...) — the old accent's raw hex. */
    border: 1px solid rgba(242, 165, 65, 0.32);
    border-radius: var(--gk-radius);
    background: linear-gradient(180deg, rgba(255, 251, 235, 0.94), #fff);
    box-shadow: var(--gk-shadow-sm);
}

.timeline {
    display: grid;
    gap: 0.8rem;
}

.timeline-item {
    position: relative;
    padding-left: 1.65rem;
}

.timeline-item::before {
    content: "";
    position: absolute;
    left: 0.2rem;
    top: 0.25rem;
    width: 0.72rem;
    height: 0.72rem;
    border: 3px solid #fff;
    border-radius: 999px;
    background: var(--gk-primary);
    /* Was rgba(37, 99, 235, ...) — the dot itself already used --gk-primary; only its outer
       ring was still hardcoded to the old blue. */
    box-shadow: 0 0 0 1px rgba(176, 74, 26, 0.3);
}

.timeline-item::after {
    content: "";
    position: absolute;
    left: 0.52rem;
    top: 1.1rem;
    bottom: -0.85rem;
    width: 1px;
    background: var(--gk-soft-line);
}

.timeline-item:last-child::after {
    display: none;
}

.timeline-title {
    color: var(--gk-ink);
    font-weight: 800;
}

.timeline-meta {
    color: var(--gk-muted);
    font-size: 0.78rem;
}

.attachment-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 0.75rem;
}

.attachment-card {
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: #fff;
    box-shadow: var(--gk-shadow-sm);
    overflow: hidden;
}

.attachment-card-preview {
    display: grid;
    place-items: center;
    min-height: 120px;
    background: #f8fafc;
}

.attachment-card-body {
    padding: 0.72rem;
}

/* === Profiles, Logs, Confirmations === */
.profile-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1.15rem;
    border: 1px solid rgba(217, 226, 236, 0.72);
    border-radius: var(--gk-radius);
    background:
        linear-gradient(135deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.95)),
        radial-gradient(circle at right top, rgba(15, 118, 110, 0.08), transparent 18rem);
    box-shadow: var(--gk-shadow-sm);
}

.avatar,
.avatar-lg {
    display: inline-grid;
    place-items: center;
    border-radius: 999px;
    background: linear-gradient(135deg, var(--gk-primary), var(--gk-teal));
    color: #fff;
    font-weight: 800;
    flex: 0 0 auto;
}

.avatar {
    width: 42px;
    height: 42px;
}

.avatar-lg {
    width: 72px;
    height: 72px;
    font-size: 1.45rem;
}

.profile-list {
    display: grid;
    grid-template-columns: minmax(150px, .82fr) 1fr;
    gap: 0.58rem 1rem;
    margin: 0;
    font-size: 0.9rem;
}

.profile-list dt {
    color: var(--gk-muted);
    font-weight: 800;
}

.profile-list dd {
    margin: 0;
    color: var(--gk-ink);
    font-weight: 700;
    overflow-wrap: anywhere;
}

.profile-list-grid {
    grid-template-columns: minmax(120px, .7fr) 1fr;
}

@media (min-width: 768px) {
    .profile-list-grid {
        grid-template-columns: repeat(2, minmax(120px, .7fr) 1fr);
    }
}

/* The email template preview shows the EMAIL, not the app, so this one surface opts out of the
   dark repaint on purpose: mail clients render on white in both themes, and a preview that
   restyles itself to match the app would hide the very contrast mistakes it exists to catch
   (a template with dark grey text reads fine on a dark pane and is invisible in the inbox).
   Deliberately NOT .bg-white, which site-modern.css repaints with !important under
   [data-bs-theme="dark"]. */
.email-preview-surface {
    background: #ffffff;
    color: #172033;
}

.email-preview-surface a {
    color: #0b5ed7;
}

.audit-list {
    display: grid;
    gap: 0.8rem;
}

.audit-card {
    padding: 0.9rem 1rem;
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: #fff;
    box-shadow: var(--gk-shadow-sm);
}

.confirm-panel {
    max-width: 760px;
    margin: 0 auto;
    border: 1px solid rgba(190, 18, 60, 0.22);
    border-radius: var(--gk-radius);
    background: #fff;
    box-shadow: var(--gk-shadow);
    overflow: hidden;
}

.confirm-panel-header {
    padding: 1.25rem;
    /* The rose (190, 18, 60 / --gk-rose) is intentional and untouched — this is a delete
       confirmation panel. Only its amber gradient partner is the old accent's raw hex. */
    background: linear-gradient(135deg, rgba(190, 18, 60, 0.10), rgba(242, 165, 65, 0.08));
    border-bottom: 1px solid var(--gk-soft-line);
}

.media-frame {
    width: 100%;
    max-height: min(760px, 76vh);
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: #f8fafc;
    object-fit: contain;
}

.receipt-pdf-frame {
    height: min(760px, 76vh);
}

.mobile-card-list {
    display: grid;
    gap: 0.85rem;
}

.data-card {
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: #fff;
    box-shadow: var(--gk-shadow-sm);
}

.data-card-body {
    padding: 1rem;
}

/* === Auth === */
/*
   The KAISA sign-in gate. Two grounds, one idea: the dark side is the field — where Kalinga,
   Action, Integration and Service happen — and the light side is the desk, where Accountability
   is kept: the sign-in itself, a record of who came in and when. The acrostic ledger is the one
   signature move; everything else stays quiet around it.

   Palette continues the warm terracotta/cream identity already used on the public project pages
   (see PublicProjects/Index.cshtml) — a rebrand here would fragment the brand, not modernise it.
   What changes is the execution: an espresso-dark ground instead of a bright gradient, and a
   structural mono face standing in for the "record" side of the work.
*/
.auth-body {
    --k-ground: #1b140f;
    --k-ground-2: #251b13;
    --k-terra: #e2622b;
    --k-terra-d: #a8431a;
    --k-amber: #f3ac4d;
    --k-cream: #faf5ec;
    --k-ink: #2a2018;
    --k-mist: #725c47;
    --k-hair: rgba(255, 255, 255, 0.11);
    min-height: 100vh;
    background: var(--k-ground);
    font-family: 'Nunito', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

.auth-shell {
    width: min(1080px, 100%);
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    min-height: 620px;
    border-radius: 22px;
    background: var(--k-cream);
    box-shadow: 0 40px 100px -20px rgba(0, 0, 0, 0.55), 0 1px 0 rgba(255, 255, 255, 0.04) inset;
    overflow: hidden;
}

/* ---- Brand panel (the field) ---- */
.auth-brand-panel {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 2rem;
    padding: 2.75rem 3rem;
    color: #fff;
    background:
        radial-gradient(120% 140% at 100% 0%, rgba(226, 98, 43, 0.22), transparent 60%),
        var(--k-ground);
    overflow: hidden;
}

/* A woven sawali/bamboo-slat texture — the literal material GK builds with — rendered as a
   repeating diagonal lattice rather than a decorative blur. Quiet at this opacity; it reads as
   texture, not pattern, until you look for it. */
.auth-brand-panel::before {
    content: "";
    position: absolute;
    inset: 0;
    opacity: 0.05;
    background-image:
        repeating-linear-gradient(58deg, #fff 0, #fff 1px, transparent 1px, transparent 22px),
        repeating-linear-gradient(-58deg, #fff 0, #fff 1px, transparent 1px, transparent 22px);
    pointer-events: none;
}

.auth-brand-top {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.875rem;
}

.auth-logo {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    padding: 0.5rem;
    border-radius: 14px;
    background: linear-gradient(160deg, #fff 0%, #fff8f0 100%);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.35);
}

.auth-logo img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.auth-org-mark {
    font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace;
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.55);
    line-height: 1.5;
}

.auth-org-mark strong {
    display: block;
    color: rgba(255, 255, 255, 0.88);
    font-weight: 700;
}

.auth-wordmark {
    position: relative;
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 600;
    font-size: clamp(3rem, 6vw, 4.25rem);
    line-height: 0.95;
    letter-spacing: -0.01em;
    color: #fff;
    margin: 0;
}

.auth-wordmark-sub {
    position: relative;
    margin-top: 0.6rem;
    max-width: 34ch;
    color: rgba(255, 255, 255, 0.62);
    font-size: 0.95rem;
    line-height: 1.5;
}

/* ---- The acrostic ledger: the signature element ---- */
.auth-ledger {
    position: relative;
    display: grid;
    gap: 0;
    border-top: 1px solid var(--k-hair);
}

.auth-ledger-row {
    display: grid;
    grid-template-columns: 2.1rem 1fr;
    align-items: baseline;
    gap: 0.9rem;
    padding: 0.65rem 0;
    border-bottom: 1px solid var(--k-hair);
    opacity: 0;
    transform: translateY(6px);
    animation: ledgerIn 0.5s var(--gk-ease, ease) both;
}

/* Staggered one row at a time — the name assembling into its meaning, like an entry being
   written into a ledger. The single orchestrated moment this page gets. */
.auth-ledger-row:nth-child(1) { animation-delay: 0.15s; }
.auth-ledger-row:nth-child(2) { animation-delay: 0.28s; }
.auth-ledger-row:nth-child(3) { animation-delay: 0.41s; }
.auth-ledger-row:nth-child(4) { animation-delay: 0.54s; }
.auth-ledger-row:nth-child(5) { animation-delay: 0.67s; }

.auth-ledger-letter {
    font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--k-amber);
    transition: color 0.2s var(--gk-ease, ease);
}

.auth-ledger-row:hover .auth-ledger-letter {
    color: #fff;
}

.auth-ledger-word {
    font-family: 'Nunito', sans-serif;
    font-weight: 800;
    font-size: 0.98rem;
    color: #fff;
}

.auth-ledger-gloss {
    display: block;
    margin-top: 0.1rem;
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.5);
    transition: color 0.2s var(--gk-ease, ease);
}

.auth-ledger-row:hover .auth-ledger-gloss {
    color: rgba(255, 255, 255, 0.78);
}

.auth-brand-foot {
    position: relative;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    font-size: 0.78rem;
    /* 0.55, not the 0.4 first tried — that measured 3.82:1 against the ground and failed AA
       for text this small. */
    color: rgba(255, 255, 255, 0.55);
    border-top: 1px solid var(--k-hair);
    padding-top: 1rem;
}

/* ---- Sign-in card (the desk) ---- */
.auth-card {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 3rem 3.25rem;
    background: var(--k-cream);
    font-family: 'Nunito', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

.auth-card-inner {
    opacity: 0;
    animation: ledgerIn 0.5s var(--gk-ease, ease) 0.5s both;
}

.detail-kicker.auth-kicker {
    font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--k-terra-d);
}

.auth-title {
    color: var(--k-ink);
    font-family: 'Fraunces', Georgia, serif;
    font-size: clamp(1.6rem, 2.6vw, 2rem);
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: -0.01em;
}

.auth-subtitle {
    color: var(--k-mist);
    line-height: 1.55;
}

/* Bootstrap's input-group renders the icon as its own boxed sibling; merged here into one
   field so the icon reads as part of the input, not a second control glued to it. */
.auth-card .input-group {
    border: 1.5px solid #e4d8c6;
    border-radius: 12px;
    background: #fff;
    transition: border-color 0.15s var(--gk-ease, ease), box-shadow 0.15s var(--gk-ease, ease);
}

.auth-card .input-group:focus-within {
    border-color: var(--k-terra);
    box-shadow: 0 0 0 4px rgba(226, 98, 43, 0.12);
}

.auth-card .input-group-text {
    background: transparent;
    border: 0;
    color: var(--k-mist);
    padding-right: 0.4rem;
}

.auth-card .form-control {
    border: 0;
    background: transparent;
    padding-left: 0.25rem;
    color: var(--k-ink);
}

.auth-card .form-control:focus {
    box-shadow: none;
}

.auth-card .form-control::placeholder {
    color: #b9ab98;
}

.auth-card .btn-outline-secondary {
    border: 0;
    color: var(--k-mist);
    background: transparent;
}

.auth-card .btn-outline-secondary:hover,
.auth-card .btn-outline-secondary:focus {
    color: var(--k-terra-d);
    background: transparent;
}

.auth-card .form-label {
    font-weight: 700;
    font-size: 0.86rem;
    color: var(--k-ink);
}

.auth-card .btn-primary {
    background: linear-gradient(155deg, var(--k-terra) 0%, var(--k-terra-d) 100%);
    border: 0;
    font-weight: 800;
    letter-spacing: 0.01em;
    box-shadow: 0 10px 24px -8px rgba(168, 67, 26, 0.55);
    transition: transform 0.15s var(--gk-ease, ease), box-shadow 0.15s var(--gk-ease, ease);
}

.auth-card .btn-primary:hover,
.auth-card .btn-primary:focus-visible {
    transform: translateY(-1px);
    box-shadow: 0 14px 30px -8px rgba(168, 67, 26, 0.6);
}

.auth-card .btn-primary:active {
    transform: translateY(0);
}

.auth-card a {
    color: var(--k-terra-d);
}

@keyframes ledgerIn {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .auth-ledger-row,
    .auth-card-inner {
        animation: none !important;
        opacity: 1 !important;
        transform: none !important;
    }
}


/* ---- Login splash: the logo, alone, for a moment, before the sign-in page underneath ----
   A fixed overlay rather than a separate route, so there is nothing to redirect away from and
   nothing for a bookmark or a password manager to land on wrong. It sits on top of .auth-shell
   (already rendering underneath, animating in on its own delays) and fades itself out — the page
   does not wait for it and needs no JS to reveal correctly if the fade-out script never ran.
   Skipped outright, via the .login-splash-seen class _AuthLayout's head script adds, on every
   login-page load after the first one in a browser session — including a failed-login reload,
   which lands in that same session. */
.login-splash {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--k-ground, #1b140f);
    animation: loginSplashOut 0.25s ease 0.8s forwards;
}

.login-splash img {
    width: 200px;
    height: auto;
    animation: loginSplashZoom 0.6s var(--gk-ease, ease) both;
}

@keyframes loginSplashZoom {
    0% { transform: scale(0.3); opacity: 0; }
    55% { transform: scale(1.2); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}

@keyframes loginSplashOut {
    to { opacity: 0; visibility: hidden; pointer-events: none; }
}

html.login-splash-seen .login-splash {
    display: none !important;
}

@media (prefers-reduced-motion: reduce) {
    .login-splash {
        display: none !important;
    }
}

/* ---- Responsive: brand panel condenses instead of disappearing ---- */
@media (max-width: 992px) {
    .auth-shell {
        grid-template-columns: 1fr;
        min-height: 0;
    }

    /* Sign-in first, brand panel underneath.
       Side by side there is no "first" — the eye takes both at once. Stacked there is, and the
       brand panel was taking the whole of a phone screen before the password field appeared:
       somebody opening the app to sign in had to scroll past the acrostic every single time to
       reach the thing they came for. The panel still gets its entrance, it just no longer stands
       in the doorway.

       Done with `order` rather than by moving the markup, so the desktop grid keeps its natural
       source order. Safe for keyboard users specifically because the brand panel holds nothing
       focusable — there is no tab stop being reordered away from the visual flow, which is what
       makes CSS reordering a problem when it is a problem. */
    .auth-card {
        order: 1;
    }

    .auth-brand-panel {
        order: 2;
        padding: 2rem 2.25rem;
        gap: 1.25rem;
    }

    .auth-wordmark {
        font-size: 2.5rem;
    }

    .auth-wordmark-sub {
        display: none;
    }
}

@media (max-width: 575.98px) {
    .auth-body {
        padding: 0 !important;
        align-items: stretch !important;
    }

    .auth-shell {
        min-height: 100vh;
        border-radius: 0;
    }

    .auth-brand-panel {
        padding: 1.5rem;
    }

    .auth-card {
        padding: 1.75rem 1.5rem 2.25rem;
    }

    /* Gloss lines are the first thing to go on a phone — letter and word alone still spell out
       the acronym, which is the part that has to survive. */
    .auth-ledger-gloss {
        display: none;
    }

    .auth-ledger-row {
        padding: 0.45rem 0;
    }
}

.fade-in-up {
    animation: fadeInUp 0.42s var(--gk-ease) both;
}

@keyframes fadeInUp {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* === Sidebar ===
   Revived from previously-dormant rules that predated the current top-nav layout, then
   restyled to Gawad Kalinga's actual brand palette (terra/amber/cream — the same colors
   already used on the public project pages) instead of the generic slate/blue-amber the
   dormant version had. Scoped as custom properties on #sidebar itself rather than touching
   the app-wide --gk-primary etc., so this stays a sidebar-only brand accent, not a full reskin. */
#sidebar {
    --sb-terra: #df5f28;
    --sb-terra-d: #b04a1a;
    --sb-amber: #f2a541;
    --sb-cream: #fbf6ee;
    --sb-bg-1: #45230f;
    --sb-bg-2: #20100a;
    --sb-ink-soft: rgba(251, 246, 238, 0.76);
    /* Was 0.56 — sat right at the AA cutoff (~4.5:1) against the lighter end of the sidebar's
       own gradient (--sb-bg-1). Bumped for headroom rather than just barely passing. */
    --sb-ink-faint: rgba(251, 246, 238, 0.68);
    --sb-line: rgba(251, 246, 238, 0.12);

    width: 276px;
    min-height: 100vh;
    transition: width 0.22s ease, transform 0.22s ease;
    flex-shrink: 0;
    position: sticky;
    top: 0;
    /* position:sticky makes #sidebar its own stacking context — without an explicit z-index
       here, ANY positioned element later in the DOM (e.g. a dashboard card using
       position:relative for its own hover/shadow effect) paints its whole subtree above
       #sidebar's whole subtree, trapping footer flyouts (notification/profile dropdowns)
       behind ordinary page content no matter what position trick is used on the flyout
       itself. This has to live on #sidebar, not on the dropdown-menu — you can't out-z-index
       your way out of a parent stacking context from inside it. */
    z-index: 20;
    height: 100vh;
    display: flex;
    flex-direction: column;
    background:
        radial-gradient(120% 60% at 100% 0%, rgba(242, 165, 65, 0.16), transparent 55%),
        linear-gradient(165deg, var(--sb-bg-1) 0%, var(--sb-bg-2) 100%);
    box-shadow: 8px 0 24px rgba(15, 23, 42, 0.12);
}

/* Full brand lockup at the top of the rail — the app's only logo now that the top bar is
   gone. The toggle button lives right beside it, so collapse (desktop) / close (mobile)
   is always reachable without a separate top bar. */
.sidebar-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
    padding: 1rem 0.85rem 0.85rem;
    border-bottom: 1px solid var(--sb-line);
}

.sidebar-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.65rem;
    min-width: 0;
    flex: 1 1 auto;
    text-decoration: none;
    overflow: hidden;
}

.sidebar-brand-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 42px;
    height: 36px;
    padding: 0.3rem;
    border-radius: 12px;
    background: linear-gradient(160deg, var(--sb-cream) 0%, #fff 100%);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.22);
    transition: transform 0.18s ease, box-shadow 0.18s ease;
}

.sidebar-brand-mark img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.sidebar-brand:hover .sidebar-brand-mark {
    transform: translateY(-1px) scale(1.03);
    box-shadow: 0 10px 22px rgba(223, 95, 40, 0.4);
}

.sidebar-brand-copy {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    overflow: hidden;
    white-space: nowrap;
}

.sidebar-brand-title {
    color: var(--sb-cream);
    font-size: 0.95rem;
    font-weight: 850;
    text-overflow: ellipsis;
    overflow: hidden;
}

.sidebar-brand-subtitle {
    color: var(--sb-ink-faint);
    font-size: 0.68rem;
    font-weight: 700;
    text-overflow: ellipsis;
    overflow: hidden;
}

.sidebar-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: 9px;
    background: rgba(251, 246, 238, 0.08);
    color: var(--sb-ink-soft);
    transition: background 0.16s ease, color 0.16s ease;
}

.sidebar-toggle-btn:hover {
    background: rgba(251, 246, 238, 0.16);
    color: var(--sb-cream);
}


/* The scrollable middle section — everything except the pinned header/footer. */
.sidebar-scroll {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
}

.sidebar-menu {
    padding: 0.25rem 0.6rem 1.25rem;
}

.sidebar-menu .nav-item + .nav-item {
    margin-top: 0.15rem;
}

/* Staggered entrance — each item fades/slides in with a small incremental delay driven by
   the --i index JS sets on load. Capped and skipped under reduced-motion. */
.sidebar-menu .nav-item {
    opacity: 0;
    animation: sbItemIn 0.32s ease forwards;
    animation-delay: calc(var(--i, 0) * 28ms);
}

@keyframes sbItemIn {
    from {
        opacity: 0;
        transform: translateX(-6px);
    }
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

.sidebar-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    width: 100%;
    min-height: 42px;
    border: 0;
    background: transparent;
    border-radius: var(--gk-radius);
    padding: 0.62rem 0.78rem;
    font-size: 0.88rem;
    text-align: left;
    /* Bootstrap underlines <a> by default. The class is used on both anchors and buttons, so
       without this the anchors were underlined and the buttons were not — visibly inconsistent
       within the same menu, and most obvious in the indented submenus. */
    text-decoration: none;
    transition: background 0.3s ease, color 0.3s ease, transform 0.3s ease;
    color: var(--sb-ink-soft) !important;
}

/* Active-indicator bar: a slim terra accent that grows in on the left edge, independent of
   the fill behind it — reads clearly even at a glance, and animates in rather than snapping. */
.sidebar-link::before {
    content: "";
    position: absolute;
    left: -0.6rem;
    top: 50%;
    width: 3px;
    height: 0;
    border-radius: 0 4px 4px 0;
    background: linear-gradient(180deg, var(--sb-terra), var(--sb-amber));
    transform: translateY(-50%);
    transition: height 0.18s ease;
}

.sidebar-link.active::before {
    height: 60%;
}

.sidebar-link i:not(.sidebar-caret) {
    width: 1.25rem;
    text-align: center;
    color: var(--sb-ink-faint);
    flex-shrink: 0;
    transition: transform 0.18s ease, color 0.16s ease;
}

.sidebar-link span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* text-decoration repeated on purpose: `a:hover` outranks a bare `.sidebar-link` on specificity
   (both carry one class, but the element selector breaks the tie), so relying on inheritance from
   the base rule would let the underline back in on hover. */
.sidebar-link:hover,
.sidebar-link:focus {
    background: rgba(251, 246, 238, 0.08);
    color: var(--sb-cream) !important;
    transform: translateX(2px);
    text-decoration: none;
}

.sidebar-link:hover i:not(.sidebar-caret) {
    color: var(--sb-cream);
    transform: scale(1.12);
}

.sidebar-link.active i {
    color: #fff;
}

.sidebar-link.active {
    background: linear-gradient(135deg, var(--sb-terra) 0%, var(--sb-amber) 100%) !important;
    color: #fff !important;
    font-weight: 700;
    box-shadow: 0 10px 22px rgba(223, 95, 40, 0.32);
}

/* Group headers (Programs/CRM/Finance/Reports/Administration) are buttons, not links —
   same base look as .sidebar-link, plus a caret that rotates on open. */
.sidebar-caret {
    flex-shrink: 0;
    font-size: 0.72rem;
    transition: transform 0.2s ease;
}

.sidebar-group-toggle[aria-expanded="true"] .sidebar-caret {
    transform: rotate(180deg);
}

.sidebar-submenu {
    margin: 0.15rem 0 0.2rem;
    padding-left: 0.5rem;
    border-left: 2px solid var(--sb-line);
}

/* Bootstrap's own collapse handles the height animation; this adds a quick fade so the
   revealed items feel like they arrive, not just appear once the height settles. */
.sidebar-submenu .sidebar-link {
    min-height: 36px;
    padding: 0.48rem 0.7rem;
    font-size: 0.83rem;
    color: var(--sb-ink-faint) !important;
    animation: sbSubIn 0.2s ease;
}

/* A small heading inside a group (Finance, Reports, CRM, Setup - 2026-10-23). Not a link and not
   announced (the links under it say what they are); it only splits a long drawer into sections.
   Hidden with the rest of the submenu when the sidebar is collapsed to icons. */
.sidebar-submenu .sidebar-subhead {
    padding: 0.7rem 0.7rem 0.2rem;
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--sb-ink-faint);
    opacity: 0.8;
}

/* A plain rule instead of a heading: Report Schedules, a setting, below the reports themselves. */
.sidebar-submenu .sidebar-subrule {
    margin: 0.55rem 0.7rem 0.3rem;
    border-top: 1px solid var(--sb-line);
}

/* What is waiting for you, beside Requests & Approvals (2026-10-23). On the closed rail the
   number hides with the label and a dot on the icon says the same. */
.sidebar-count {
    min-width: 1.4rem;
    padding: 0.05rem 0.45rem;
    border-radius: 999px;
    background: var(--sb-amber, #f59e0b);
    color: #1f1300;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1.35;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

#sidebar.collapsed .sidebar-link.has-waiting { position: relative; }
#sidebar.collapsed .sidebar-link.has-waiting::after {
    content: "";
    position: absolute;
    top: 0.45rem;
    right: 1.35rem;
    width: 0.55rem;
    height: 0.55rem;
    border-radius: 50%;
    background: var(--sb-amber, #f59e0b);
    box-shadow: 0 0 0 2px var(--sb-bg-1, #1f2937);
}

/* Everyday work above, administration below (2026-10-23): a quiet label, and a plain rule on the
   closed rail where words do not fit. */
.sidebar-menu .sidebar-section-label {
    margin: 0.9rem 0.7rem 0.3rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--sb-line);
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--sb-ink-faint);
    opacity: 0.8;
    list-style: none;
}

#sidebar.collapsed .sidebar-section-label {
    margin: 0.6rem 0.9rem 0.3rem;
    padding-top: 0;
    font-size: 0;
}

@keyframes sbSubIn {
    from {
        opacity: 0;
        transform: translateY(-3px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Icon-only collapsed state (desktop). The dormant version only had "gone" (width: 0, used
   for the old mobile push-down nav) — this collapsed state is new: the rail stays, labels
   and submenus hide, so a person can keep the rail for quick access without the full width. */
#sidebar.collapsed {
    width: 76px;
}

#sidebar.collapsed .sidebar-link {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
}

#sidebar.collapsed .sidebar-link span,
#sidebar.collapsed .sidebar-caret,
#sidebar.collapsed .sidebar-submenu {
    display: none;
}

/* Collapsed rail is only 76px wide — logo + text + toggle button don't fit side by side,
   and the toggle is the ONLY way back to expanded, so both have to stay visible. Stacking
   the logo mark above the toggle (instead of hiding one of them) keeps the brand anchor
   at the top of the rail the way it always has been, collapsed or not. */
#sidebar.collapsed .sidebar-header {
    flex-direction: column;
    justify-content: center;
    gap: 0.6rem;
    padding: 0.9rem 0.4rem 0.7rem;
}

#sidebar.collapsed .sidebar-brand {
    flex: 0 0 auto;
}

#sidebar.collapsed .sidebar-brand-copy {
    display: none;
}

#sidebar.collapsed .sidebar-footer-tools {
    flex-direction: column;
}

#sidebar.collapsed .sidebar-profile-copy {
    display: none;
}

#sidebar.collapsed .sidebar-profile-btn {
    flex-direction: column;
    justify-content: center;
    gap: 0.2rem;
}

/* The dropdown-toggle caret is a real flex-item (::after), not covered by .sidebar-caret's
   hiding rule above — without this it sits squeezed right next to the avatar in the
   76px rail. */
#sidebar.collapsed .sidebar-profile-btn::after {
    display: none;
}

/* === Sidebar footer: notifications, dark-mode toggle, profile — moved in from the
   removed top bar so the app has one persistent nav surface instead of two. Pinned below
   the scrollable menu via the #sidebar flex column, not part of the scroll area. */
.sidebar-footer {
    flex-shrink: 0;
    padding: 0.75rem 0.85rem 0.9rem;
    border-top: 1px solid var(--sb-line);
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.sidebar-footer-tools {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.sidebar-footer-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 1px solid var(--sb-line);
    border-radius: 9px;
    background: rgba(251, 246, 238, 0.06);
    color: var(--sb-ink-soft);
    transition: background 0.16s ease, color 0.16s ease;
}

.sidebar-footer-btn:hover {
    background: rgba(251, 246, 238, 0.14);
    color: var(--sb-cream);
}

/* NotificationBell's own markup renders a plain .btn.btn-icon.app-notification-button —
   these overrides restyle it for the dark rail instead of the light top bar it was built for. */
.sidebar-footer .app-notification-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px !important;
    height: 38px !important;
    border: 1px solid var(--sb-line) !important;
    border-radius: 9px !important;
    background: rgba(251, 246, 238, 0.06) !important;
    color: var(--sb-ink-soft) !important;
}

.sidebar-footer .app-notification-button:hover {
    background: rgba(251, 246, 238, 0.14) !important;
    color: var(--sb-cream) !important;
}

/* Now a row holding two controls: the identity link, and the menu button. */
.sidebar-profile-btn {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    width: 100%;
    /* The account menu lives inside this row (Bootstrap 5 only finds a dropdown menu that is the
       toggle's next sibling), and sizes itself to it. Without a positioned ancestor here, the
       menu's width: 100% would resolve against whichever ancestor happened to be positioned. */
    position: relative;
    border: 1px solid var(--sb-line);
    border-radius: var(--gk-radius);
    background: rgba(251, 246, 238, 0.06);
    padding: 0.35rem 0.4rem;
    color: var(--sb-cream);
}

/* Clicking your own name goes to your profile. */
.sidebar-profile-identity {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex: 1 1 auto;
    min-width: 0;
    padding: 0.1rem 0.2rem;
    border-radius: calc(var(--gk-radius) - 3px);
    color: var(--sb-cream);
    text-decoration: none;
    transition: background 0.16s ease;
}

.sidebar-profile-identity:hover,
.sidebar-profile-identity:focus {
    background: rgba(251, 246, 238, 0.14);
    color: var(--sb-cream);
}

/* The caret is gone: this opens a menu of actions, and an upward arrow in a footer reads as
   "scroll up" or "collapse" rather than "more". A three-dot glyph says menu. */
.sidebar-profile-more::after {
    display: none;
}

.sidebar-profile-more {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--sb-cream);
    opacity: 0.7;
    transition: background 0.16s ease, opacity 0.16s ease;
}

.sidebar-profile-more:hover,
.sidebar-profile-more:focus,
.sidebar-profile-more[aria-expanded="true"] {
    background: rgba(251, 246, 238, 0.18);
    opacity: 1;
    color: var(--sb-cream);
}

/* Collapsed to the 76px rail there is no room for the avatar and the dots side by side, so they
   stack. They were not stacked before - the dots were hidden - and hiding the only toggle meant
   the rail had no way to sign out: My Profile survived as the avatar link, Logout did not. */
#sidebar.collapsed .sidebar-profile-more {
    width: 1.75rem;
    height: 1.75rem;
}

/* The account menu.

   Bootstrap positions this against a dark footer while the menu itself uses the page's own
   surface colours, so left alone it inherits whichever set the theme last flipped and can land
   dark-on-dark. Both colours are stated here, from the same variables the cards use, so the menu
   is legible in either theme rather than legible in whichever one it was last looked at. */
/* The menu appeared instantly, which in a footer reads as a flicker rather than an opening.
   Animated as a KEYFRAME on .show rather than a transition, for two reasons: Bootstrap toggles
   display, and a transition does not run across a display change; and Popper writes its own
   inline transform for positioning, which would win over anything this file said about transform.
   Fading and a small rise are all that is needed, and both are left to the browser to compose. */
/* It must NOT animate transform, and the note above had this exactly backwards.

   A running CSS animation sits in a higher cascade origin than an inline style, so animating
   transform here BEAT Popper's inline positioning transform rather than losing to it. For the
   0.14s the keyframe was running, the menu was positioned by translateY alone — parked at its
   untransformed origin — and then snapped to the right place when the animation ended. That snap
   is the jump: the menu did not open at the top of the box, it appeared somewhere else and arrived.

   So the reveal uses clip-path instead, which Popper does not touch. inset(100% 0 0 0) is a zero-
   height window at the bottom edge; growing the top inset to 0 unfurls the menu upward from that
   edge. The menu is a dropup sitting directly above the profile row, so its bottom edge IS the top
   of the box, which is where the opening now starts. */
@keyframes sidebarMenuIn {
    from { opacity: 0; clip-path: inset(100% 0 0 0); }
    to   { opacity: 1; clip-path: inset(0 0 0 0); }
}

/* The #sidebar prefix is load-bearing, not decoration.

   The app-wide ".dropdown-menu.show" rule further down animates TRANSFORM, and it has the same
   specificity as ".sidebar-profile-menu.show" (two classes) while sitting later in this file - so
   it won, and this rule never ran. That reinstated the exact bug the note above describes: for the
   0.48s of the global animation the menu ignored Popper's inline transform and parked at its
   untransformed origin, which - because Popper anchors it with "inset: auto 0 0 auto" - is
   directly on top of the profile row. Measured: the menu's bottom landed at the row's bottom, and
   elementFromPoint over the user's own name returned the LOGOUT item. Clicking your name while it
   was open signed you out. Then it snapped upward when the animation ended.

   One id plus two classes beats two classes whatever the order, so the clip-path reveal below is
   what actually runs. Do not "simplify" this selector back to a bare class. */
#sidebar .sidebar-profile-menu.show {
    animation: sidebarMenuIn 0.16s ease-out;
}

/* Somebody who has asked for less motion gets none. Same specificity as the rule above, or the
   app-wide dropdown animation takes it back for exactly the people who asked for less. */
@media (prefers-reduced-motion: reduce) {
    #sidebar .sidebar-profile-menu.show {
        animation: none;
    }
}

.sidebar-profile-menu {
    width: 100%;
    /* Collapsed, the row it measures against is about 50px wide. Without a floor the menu comes
       out that wide too - technically open, and unreadable. */
    min-width: 12rem;
    background: var(--bs-body-bg);
    border: 1px solid var(--gk-border, rgba(0, 0, 0, 0.12));
    border-radius: var(--gk-radius);
    padding: 0.35rem;
}

.sidebar-profile-menu .dropdown-item {
    color: var(--bs-body-color);
    border-radius: calc(var(--gk-radius) - 2px);
    padding: 0.5rem 0.65rem;
}

.sidebar-profile-menu .dropdown-item:hover,
.sidebar-profile-menu .dropdown-item:focus {
    background: var(--bs-secondary-bg, rgba(0, 0, 0, 0.06));
    color: var(--bs-body-color);
}

/* The logout item keeps its danger colour on hover; the rule above would otherwise take it. */
.sidebar-profile-menu .dropdown-item.text-danger,
.sidebar-profile-menu .dropdown-item.text-danger:hover,
.sidebar-profile-menu .dropdown-item.text-danger:focus {
    color: var(--bs-danger, #dc3545) !important;
}

/* The form wrapping Logout is a block element and would otherwise indent the item inside it. */
.sidebar-profile-menu form {
    margin: 0;
}

.sidebar-profile-copy {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    overflow: hidden;
    text-align: left;
    min-width: 0;
}

.sidebar-profile-name {
    color: var(--sb-cream);
    font-size: 0.82rem;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar-profile-role {
    color: var(--sb-ink-faint);
    font-size: 0.7rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar-backdrop {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .sidebar-menu .nav-item {
        animation: none;
        opacity: 1;
    }

    .sidebar-link,
    .sidebar-link i:not(.sidebar-caret),
    .sidebar-link::before,
    .sidebar-caret,
    .sidebar-mark-badge {
        transition: none;
        animation: none;
    }
}

/* === Topbar === */
.topbar {
    position: sticky;
    top: 0;
    z-index: 1020;
    min-height: 68px;
    background: rgba(255, 255, 255, 0.88);
    border-bottom: 1px solid rgba(217, 226, 236, 0.9);
    box-shadow: 0 1px 0 rgba(16, 24, 40, 0.04);
    backdrop-filter: blur(14px);
}

.navbar-brand {
    color: var(--gk-ink) !important;
    font-size: 1.05rem;
    line-height: 1.15;
    letter-spacing: 0;
}

.topbar-subtitle {
    color: var(--gk-muted);
    font-size: 0.74rem;
}

.app-user-menu {
    border: 1px solid var(--gk-line);
    box-shadow: var(--gk-shadow-sm);
}

.min-w-0 {
    min-width: 0;
}

/* === Cards & Containers === */
.card {
    border: 1px solid var(--gk-soft-line) !important;
    border-radius: var(--gk-radius);
    box-shadow: var(--gk-shadow-sm) !important;
    background: var(--gk-surface);
}

.card-header {
    border-bottom-color: var(--gk-soft-line) !important;
}

.card-body {
    color: var(--gk-ink);
}

.hover-lift {
    transition: transform 0.16s ease, box-shadow 0.16s ease;
}

.hover-lift:hover {
    transform: translateY(-2px);
    box-shadow: var(--gk-shadow) !important;
}

/* === Tables === */
.table-responsive {
    border-radius: var(--gk-radius);
}

.table {
    --bs-table-bg: transparent;
    margin-bottom: 0;
}

.table thead th {
    background: #263445 !important;
    color: #fff;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 0.78rem 0.85rem;
    border-bottom: none;
    white-space: nowrap;
}

.table td {
    vertical-align: middle;
    font-size: 0.88rem;
    padding: 0.82rem 0.85rem;
    border-color: var(--gk-soft-line);
}

.table-hover > tbody > tr:hover > * {
    background-color: #f8fafc;
}

/* === Badges === */
.badge {
    border-radius: 999px;
    font-weight: 700;
    letter-spacing: 0;
    padding: 0.42em 0.62em;
}

/* === Forms === */
.form-label {
    margin-bottom: 0.35rem;
    color: #344054;
}

.form-control,
.form-select,
.input-group-text {
    border-color: var(--gk-line);
    border-radius: var(--gk-radius);
    min-height: 42px;
}

.input-group > .form-control:not(:first-child),
.input-group > .form-select:not(:first-child) {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

.input-group > .form-control:not(:last-child),
.input-group > .form-select:not(:last-child) {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.form-control:focus,
.form-select:focus {
    border-color: var(--gk-primary);
    /* Was rgba(37, 99, 235, ...) — the global counterpart to the .app-main-scoped one above,
       same stale blue. */
    box-shadow: 0 0 0 0.2rem rgba(176, 74, 26, 0.16);
}

.form-text {
    color: var(--gk-muted);
}

.form-check-input:checked {
    background-color: var(--gk-primary);
    border-color: var(--gk-primary);
}

/* === Buttons === */
/* ── Buttons on the dark theme ──────────────────────────────────────────────────
   Terracotta at #b04a1a carries a relative luminance of about 0.14. On the light
   surface that is a 5.5:1 fill under white text and it reads well; on #101828 the
   fill is only about 3.2:1 against its own background, so the button stops looking
   like a raised object and starts looking like a slightly warm patch of the page.
   That is the "thin on dark" this fixes.

   Three changes, and the first is the smallest:
     - the fill lifts to #ba5420, which keeps white text at 4.8:1 (AA for the 0.88rem
       semibold these buttons use) while separating from the page at 3.7:1;
     - the shadow stops being terracotta. A coloured glow is invisible on a dark
       ground; what reads as raised there is a dark cast plus a light inner edge along
       the top, which is what the inset highlight below is for;
     - the tint variant is re-pointed entirely. A 10% terracotta wash over #101828 is
       nothing, and its text colour was --gk-primary-strong (#8f3c15) — near-black on
       near-black. Both were unreadable rather than merely dim.
   ────────────────────────────────────────────────────────────────────────────────── */
[data-bs-theme="dark"] {
    --btn-primary-bg: #ba5420;
    --btn-primary-bg-hover: #cf6128;
    --btn-primary-lift: inset 0 1px 0 rgba(255, 255, 255, .14), 0 2px 10px rgba(0, 0, 0, .50);
    --btn-primary-lift-hover: inset 0 1px 0 rgba(255, 255, 255, .18), 0 6px 18px rgba(0, 0, 0, .60);
    --btn-primary-press: inset 0 2px 5px rgba(0, 0, 0, .45);

    --btn-tint-bg: rgba(226, 128, 74, .16);
    --btn-tint-bg-hover: rgba(226, 128, 74, .26);
    --btn-tint-fg: #f0a97f;

    --btn-quiet-fg: #cbd5e1;
    --btn-quiet-fg-hover: #f8fafc;
    --btn-quiet-bg-hover: rgba(255, 255, 255, .08);

    --btn-danger-bg: #d02748;
    --btn-danger-bg-hover: #e13a59;
    --btn-danger-tint-bg: rgba(244, 106, 134, .16);
    --btn-danger-tint-bg-hover: rgba(244, 106, 134, .26);
    --btn-danger-tint-fg: #f7a4b5;
}

.btn {
    border-radius: var(--btn-radius);
    /* 600 rather than 700: the same word set slightly lighter is most of what
       separates "approachable" from "insistent" at this size. */
    font-weight: 600;
    font-size: 0.88rem;
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
}

.btn-sm {
    min-height: 34px;
    border-radius: calc(var(--btn-radius) - 2px);
    font-size: 0.8rem;
}

.btn-icon {
    width: 40px;
    min-width: 40px;
    padding-left: 0;
    padding-right: 0;
}

.btn-primary {
    background: var(--btn-primary-bg);
    border-color: var(--btn-primary-bg);
    color: var(--btn-primary-fg);
    box-shadow: var(--btn-primary-lift);
    transition: transform var(--motion-micro) var(--gk-ease),
                box-shadow var(--motion-micro) var(--gk-ease),
                background-color var(--motion-micro) var(--gk-ease);
}

.btn-primary:hover,
.btn-primary:focus {
    background: var(--btn-primary-bg-hover);
    border-color: var(--btn-primary-bg-hover);
    color: var(--btn-primary-fg);
    transform: translateY(-1px);
    box-shadow: var(--btn-primary-lift-hover);
}

/* The press. It was only a transform reset before, so a click looked like the hover
   state ending rather than like the button going down. On a system where people press
   Save all day, the feedback is worth the two lines. */
.btn-primary:active {
    transform: translateY(1px);
    box-shadow: var(--btn-primary-press);
}

/* Secondary reads as a tint rather than an outline. An outlined button beside a solid
   one gives two competing rectangles; a tint sits behind the primary rather than
   arguing with it. */
.btn-outline-primary {
    color: var(--btn-tint-fg);
    background: var(--btn-tint-bg);
    border-color: transparent;
    transition: background-color var(--motion-micro) var(--gk-ease),
                color var(--motion-micro) var(--gk-ease);
}

.btn-outline-primary:hover,
.btn-outline-primary:focus {
    background: var(--btn-tint-bg-hover);
    border-color: transparent;
    color: var(--btn-tint-fg);
}

/* Quiet: Cancel, and the second action in a toolbar. The border is kept transparent
   rather than removed so the button occupies exactly the same box as its neighbours —
   dropping it would shift every toolbar by a pixel. */
.btn-outline-secondary {
    color: var(--btn-quiet-fg);
    border-color: transparent;
    background: transparent;
    transition: background-color var(--motion-micro) var(--gk-ease),
                color var(--motion-micro) var(--gk-ease);
}

.btn-outline-secondary:hover,
.btn-outline-secondary:focus {
    color: var(--btn-quiet-fg-hover);
    background: var(--btn-quiet-bg-hover);
    border-color: transparent;
}

.btn-danger {
    background: var(--btn-danger-bg);
    border-color: var(--btn-danger-bg);
    box-shadow: var(--btn-primary-lift);
}

.btn-danger:hover,
.btn-danger:focus {
    background: var(--btn-danger-bg-hover);
    border-color: var(--btn-danger-bg-hover);
    transform: translateY(-1px);
}

.btn-danger:active {
    transform: translateY(1px);
    box-shadow: var(--btn-primary-press);
}

.btn-outline-danger {
    color: var(--btn-danger-tint-fg);
    background: var(--btn-danger-tint-bg);
    border-color: transparent;
}

.btn-outline-danger:hover,
.btn-outline-danger:focus {
    background: var(--btn-danger-tint-bg-hover);
    border-color: transparent;
    color: var(--btn-danger-tint-fg);
}

/* Row actions: spaced and independently rounded rather than one segmented block.
   Applied to the small groups because that is the row-action idiom here — real
   segmented controls in this app are .seg-toggle, not .btn-group.

   NOT forced to circles, deliberately. Several of these groups hold text buttons
   ("Disable", "Enable" on the record rules screen), and a fixed square width would
   crop the words. Rounded and spaced is the same gesture without that cost. */
.btn-group.btn-group-sm {
    gap: 0.25rem;
}

.btn-group.btn-group-sm > .btn {
    border-radius: calc(var(--btn-radius) - 2px) !important;
}

/* An icon-only button, where the class says so, does become a circle. */
.btn-icon {
    border-radius: 999px;
}

/* === Pagination === */
.pagination {
    gap: 0.25rem;
}

.pagination .page-link {
    border-radius: var(--gk-radius) !important;
    border: 1px solid var(--gk-line);
    color: #475467;
    min-width: 36px;
    text-align: center;
}

.pagination .active .page-link {
    background: var(--gk-primary);
    border-color: var(--gk-primary);
    color: #fff;
}

/* === Alerts & Modals === */
.alert {
    border-radius: var(--gk-radius);
    border-width: 1px;
}

.modal-content {
    border: 0;
    border-radius: var(--gk-radius);
}

.modal-header,
.modal-footer {
    border-color: var(--gk-soft-line);
}

.dropdown-menu {
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
}

.dropdown-item {
    border-radius: calc(var(--gk-radius) - 2px);
}

/* Every dropdown in the app (not just the sidebar's) gets a quick fade + scale-in instead of
   Bootstrap's instant snap-open. Scale grows from whichever edge sits against the trigger
   button, so it reads as "growing out of the button" whichever direction it opens.
   No reduced-motion guard needed here — the app-wide catch-all further down zeroes out
   all animation/transition durations already. */
/* Animated with the individual `scale` and `translate` properties, NEVER `transform`.
   Popper positions a menu with an inline `transform: translate(...)`, and a running animation
   outranks an inline style - so a keyframe on `transform` threw that position away for the length
   of the animation: the Budgets "New" menu sat on top of its own button for half a second, then
   jumped 42px down to where it belonged. `scale` and `translate` compose with Popper's transform
   instead of replacing it. (The sidebar profile menu met the same bug and uses clip-path below.)
   0.18s: long enough to read as coming out of the button, short enough not to be waited for. */
.dropdown-menu.show {
    animation: dropdownIn 0.18s cubic-bezier(0.16, 1, 0.3, 1);
    transform-origin: top left;
}

.dropdown-menu-end.show {
    transform-origin: top right;
}

.dropup .dropdown-menu.show {
    transform-origin: bottom left;
}

@keyframes dropdownIn {
    from {
        opacity: 0;
        scale: 0.96;
        translate: 0 4px;
    }
    to {
        opacity: 1;
        scale: 1;
        translate: 0 0;
    }
}

/* === Scrollbar ===
   .sidebar-scroll is the actual scrolling element now (the flex-column rework moved
   overflow off #sidebar itself so the header/footer could stay pinned) — the old rules
   here still targeted #sidebar, which no longer scrolls, so they'd gone dead. */
.sidebar-scroll,
.notification-list {
    scrollbar-width: thin;
}

.sidebar-scroll {
    scrollbar-color: var(--sb-amber, #f2a541) rgba(251, 246, 238, 0.08);
}

.notification-list {
    scrollbar-color: var(--sb-terra-d, #b04a1a) #f1eee8;
}

.sidebar-scroll::-webkit-scrollbar,
.notification-list::-webkit-scrollbar {
    width: 10px;
}

.sidebar-scroll::-webkit-scrollbar-track {
    background: rgba(251, 246, 238, 0.08);
    border-radius: 999px;
}

.notification-list::-webkit-scrollbar-track {
    background: #f1eee8;
    border-radius: 999px;
}

.sidebar-scroll::-webkit-scrollbar-thumb {
    background: var(--sb-amber, #f2a541);
    border: 2px solid var(--sb-bg-1, #45230f);
    border-radius: 999px;
    transition: background 0.25s ease;
}

.sidebar-scroll:hover::-webkit-scrollbar-thumb {
    background: #ffbf66;
}

.notification-list::-webkit-scrollbar-thumb {
    background: var(--sb-terra-d, #b04a1a);
    border: 2px solid #f1eee8;
    border-radius: 999px;
    transition: background 0.25s ease;
}

.notification-list:hover::-webkit-scrollbar-thumb {
    background: var(--sb-terra, #df5f28);
}

/* === Responsive === */
@media (max-width: 992px) {
    .app-main {
        padding: 1rem;
    }

    /* .auth-shell / .auth-brand-panel have their own dedicated responsive rules in === Auth ===
       above — the app shell's breakpoint block is not the right place for them. */
}

/* Page density below lg. The sidebar is no longer part of this block: tablets keep the icon
   rail, and only phones (below 768px) get the drawer - see "Sidebar modes" at the end. */
@media (max-width: 991.98px) {
    body {
        overflow-x: hidden;
    }

    #page-content {
        width: 100%;
    }

    .topbar {
        min-height: 62px;
        padding-left: 0.75rem !important;
        padding-right: 0.75rem !important;
    }

    .navbar-brand {
        max-width: 48vw;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 1rem;
    }

    .app-user-menu {
        max-width: 44px;
        padding-left: 0.55rem;
        padding-right: 0.55rem;
    }

    .app-main {
        padding: 0.85rem;
    }

    .card-body {
        padding: 1rem;
    }

    .d-flex.justify-content-between.align-items-center.mb-4 {
        align-items: flex-start !important;
        flex-direction: column;
        gap: 0.85rem;
    }

    .d-flex.justify-content-between.align-items-center.mb-4 > .btn,
    .d-flex.justify-content-between.align-items-center.mb-4 > .d-flex {
        width: 100%;
    }

    .d-flex.justify-content-between.align-items-center.mb-4 > .d-flex {
        flex-wrap: wrap;
    }

    .d-flex.justify-content-between.align-items-center.mb-4 > .d-flex .btn,
    .d-flex.gap-2.flex-wrap.justify-content-end .btn {
        flex: 1 1 auto;
    }

    .table-responsive {
        overflow: visible;
    }

    .table-mobile thead {
        display: none;
    }

    .table-mobile tbody,
    .table-mobile tr,
    .table-mobile td {
        display: block;
        width: 100%;
    }

    .table-mobile tr {
        background: #fff;
        border: 1px solid var(--gk-soft-line);
        border-radius: var(--gk-radius);
        box-shadow: var(--gk-shadow-sm);
        /* width auto (not 100%) so the horizontal margin doesn't push the card past
           its container — 100% + margin was overflowing the parent card. */
        width: auto;
        margin: 0.75rem;
        overflow: hidden;
    }

    .table-mobile td {
        border-bottom: 1px solid var(--gk-soft-line);
        display: block;
        padding: 0.55rem 0.9rem !important;
        text-align: left !important;
        white-space: normal;
    }

    /* Each mobile-card cell: small uppercase label on top, value stacked beneath. This
       renders rich cells (e.g. ticket number + title + category) cleanly instead of
       cramming them into a right-aligned column. */
    .table-mobile td::before {
        content: attr(data-label);
        display: block;
        color: var(--gk-muted);
        font-weight: 700;
        font-size: 0.68rem;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        margin-bottom: 0.15rem;
    }

    /* Cells with no label (blank header) shouldn't reserve label space */
    .table-mobile td:not([data-label])::before,
    .table-mobile td[data-label=""]::before {
        display: none;
    }

    .table-mobile td:last-child {
        border-bottom: 0;
    }

    /* Long text in mobile cards should wrap, not truncate to an unhelpful width */
    .table-mobile .text-truncate {
        max-width: 100% !important;
        white-space: normal;
    }

    .table-mobile td .btn-group,
    .table-mobile td .d-flex {
        flex-wrap: wrap;
        justify-content: flex-start;
    }

    .fund-request-meta,
    .liquidation-meta {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .detail-hero {
        flex-direction: column;
    }

    .detail-actions {
        justify-content: flex-start;
        width: 100%;
    }

    .detail-actions .btn,
    .detail-actions form,
    .detail-actions form .btn {
        flex: 1 1 auto;
    }

    .detail-stat-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .info-grid {
        grid-template-columns: 1fr;
    }

    .sticky-action-bar {
        margin-left: -1rem;
        margin-right: -1rem;
        margin-bottom: -1rem;
        padding: 0.85rem 1rem;
    }

    .sticky-action-bar .btn {
        flex: 1 1 auto;
    }

    .modal-dialog {
        margin: 0.75rem;
    }

    .profile-header {
        align-items: flex-start;
        flex-direction: column;
    }

    .profile-header .detail-actions {
        width: 100%;
    }

    /* .auth-body / .auth-shell / .auth-card have their own dedicated 575.98px rules in
       === Auth === above. */
}

@media (max-width: 575.98px) {
    .fund-request-meta,
    .liquidation-meta,
    .detail-stat-grid {
        grid-template-columns: 1fr;
    }

    .page-hero,
    .detail-hero,
    .app-main > .d-flex.justify-content-between.align-items-center.mb-4,
    .app-main > .d-flex.justify-content-between.align-items-start.mb-4,
    .app-main > .d-flex.justify-content-between.align-items-center.mb-4.flex-wrap,
    .app-main > .d-flex.justify-content-between.align-items-start.gap-3.flex-wrap.mb-4 {
        padding: 0.95rem;
    }

    .detail-actions .btn,
    .detail-actions form,
    .detail-actions form .btn,
    .sticky-action-bar .btn {
        width: 100%;
    }

    .form-section {
        padding: 0.85rem;
    }

    .profile-list {
        grid-template-columns: 1fr;
        gap: 0.15rem;
    }

    .profile-list dd {
        margin-bottom: 0.65rem;
    }

    .quick-action-grid {
        grid-template-columns: 1fr;
    }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        scroll-behavior: auto !important;
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
    }
}

/* === Utility === */
.text-truncate-2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.text-preline {
    white-space: pre-line;
}

.bg-gradient-primary {
    background: linear-gradient(135deg, var(--gk-primary) 0%, var(--gk-teal) 100%);
}

.fs-7 {
    font-size: 0.8rem;
}

.chart-canvas-sm {
    max-height: 220px;
}

.priority-critical { color: #dc2626; }
.priority-high { color: #ea580c; }
.priority-medium { color: #0f766e; }
.priority-low { color: #667085; }

/* === Notifications === */
.notification-menu {
    width: min(380px, calc(100vw - 1.5rem));
}

.notification-list {
    max-height: 420px;
    overflow-y: auto;
}

.notification-item-form {
    margin: 0;
}

.notification-item {
    display: flex;
    gap: 0.75rem;
    width: 100%;
    border: 0;
    border-bottom: 1px solid var(--gk-soft-line);
    background: #fff;
    padding: 0.78rem 1rem;
    text-align: left;
    transition: background 0.3s ease, transform 0.3s ease;
}

.notification-item:hover,
.notification-item.unread {
    background: #f8fafc;
}

.notification-item:hover {
    transform: translateX(2px);
}

.notification-icon {
    display: inline-grid;
    place-items: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: #e8f3ff;
    color: var(--gk-primary);
    flex: 0 0 auto;
    transition: transform 0.3s ease;
}

.notification-item:hover .notification-icon {
    transform: scale(1.1);
}

.notification-content {
    display: grid;
    gap: 0.15rem;
    min-width: 0;
}

.notification-title {
    font-weight: 700;
    font-size: 0.86rem;
    color: var(--gk-ink);
}

.notification-message {
    color: var(--gk-muted);
    font-size: 0.78rem;
    line-height: 1.3;
}

.notification-time {
    color: #98a2b3;
    font-size: 0.72rem;
}


/* ---- Access-rights picker tree (Admin -> Access Groups / Manage Users) ----
   Renders Category > Feature > individual rights. Shared by the
   _AccessRightsPicker partial wherever it appears. */
.access-tree {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
    gap: 12px;
    align-items: start;
}

.access-cat {
    border: 1px solid var(--bs-border-color, #e5e7eb);
    border-radius: 10px;
    padding: 0.75rem 0.9rem;
    background: #fff;
}

.access-cat-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.72rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--gk-muted, #6b7280);
    padding-bottom: 0.5rem;
    margin-bottom: 0.25rem;
    border-bottom: 1px solid var(--bs-border-color, #e5e7eb);
}

.access-feature + .access-feature {
    margin-top: 0.65rem;
    padding-top: 0.65rem;
    border-top: 1px dashed var(--bs-border-color, #e5e7eb);
}

.access-feature-head {
    display: flex;
    align-items: center;
    gap: 0.45rem;
}

.access-feature-name {
    font-weight: 700;
    font-size: 0.875rem;
    cursor: pointer;
    margin: 0;
}

.access-rights {
    margin: 0.3rem 0 0 1.55rem;
    padding-left: 0.7rem;
    border-left: 2px solid var(--bs-border-color, #e5e7eb);
}

.access-right {
    margin-bottom: 0.35rem;
}

.access-right .form-check-label {
    font-size: 0.82rem;
    font-weight: 600;
}

.access-right-desc {
    font-size: 0.72rem;
    color: var(--gk-muted, #6b7280);
    line-height: 1.35;
}

/* Dark-mode repaint — .access-cat hardcodes a light background (so the category card reads
   as a card in light mode), which overrides .card's own dark-mode repaint while
   .access-feature-name has no color of its own and was inheriting the flipped (light)
   --gk-ink, going invisible against the still-light .access-cat background. */
[data-bs-theme="dark"] .access-cat {
    background: #111827;
    border-color: #334155;
}

[data-bs-theme="dark"] .access-cat-head {
    border-bottom-color: #334155;
}

[data-bs-theme="dark"] .access-feature-name {
    color: #f8fafc;
}

[data-bs-theme="dark"] .access-feature + .access-feature {
    border-top-color: #334155;
}

[data-bs-theme="dark"] .access-rights {
    border-left-color: #334155;
}

/* ---- Dashboard greeting hero ----
   Time-of-day aware banner. The colour band and the soft moving glow shift between
   morning / afternoon / evening so the dashboard reads as "now". */
.greeting-hero {
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
    padding: 1.4rem 1.6rem;
    border-radius: 18px;
    color: #fff;
    /* The gradient repeats a-b-a across double width, then slowly pans — a seam-free shimmer
       rather than a bounce back and forth. */
    background: linear-gradient(120deg, var(--greet-a) 0%, var(--greet-b) 50%, var(--greet-a) 100%);
    background-size: 220% 220%;
    animation: greetShimmer 16s ease-in-out infinite;
    box-shadow: 0 12px 30px rgba(44, 33, 24, 0.16);
    isolation: isolate;
}

@keyframes greetShimmer {
    0%, 100% { background-position: 0% 50%; }
    50% { background-position: 100% 50%; }
}

.greeting-morning {
    --greet-a: #e8843f;
    --greet-b: #f2a541;
}

.greeting-afternoon {
    --greet-a: #df5f28;
    --greet-b: #b04a1a;
}

.greeting-evening {
    --greet-a: #3f5c78;
    --greet-b: #24384d;
}

/* Soft off-centre light source that drifts lazily, like sun/moon movement — purely decorative. */
.greeting-glow {
    position: absolute;
    inset: -40% -10% auto auto;
    width: 460px;
    height: 460px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255, 255, 255, 0.30), transparent 62%);
    pointer-events: none;
    z-index: -1;
    animation: greetDrift 12s ease-in-out infinite;
}

@keyframes greetDrift {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(-22px, 16px) scale(1.08); }
}

.greeting-main {
    display: flex;
    align-items: center;
    gap: 1rem;
    min-width: 0;
}

.greeting-icon {
    flex: 0 0 auto;
    width: 54px;
    height: 54px;
    display: grid;
    place-items: center;
    font-size: 1.6rem;
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.18);
    border: 1px solid rgba(255, 255, 255, 0.28);
    backdrop-filter: blur(2px);
    animation: greetIconGlow 4s ease-in-out infinite;
}

/* A slow breathing halo behind the icon — enough to catch the eye once, not to distract. */
@keyframes greetIconGlow {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); }
    50% { box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.10); }
}

.greeting-copy {
    min-width: 0;
}

.greeting-title {
    margin: 0;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.15;
}

.greeting-sub {
    margin: 0.15rem 0 0;
    font-size: 0.85rem;
    opacity: 0.88;
}

.greeting-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.greeting-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.5rem 0.95rem;
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 700;
    color: #fff;
    text-decoration: none;
    background: rgba(255, 255, 255, 0.16);
    border: 1px solid rgba(255, 255, 255, 0.32);
    transition: background 0.18s ease, transform 0.18s ease;
}

.greeting-chip:hover,
.greeting-chip:focus {
    background: rgba(255, 255, 255, 0.28);
    color: #fff;
    transform: translateY(-1px);
}

@media (max-width: 575.98px) {
    .greeting-hero {
        padding: 1.15rem 1.15rem;
    }

    .greeting-icon {
        width: 44px;
        height: 44px;
        font-size: 1.3rem;
    }

    .greeting-title {
        font-size: 1.15rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .greeting-chip {
        transition: none;
    }

    .greeting-hero,
    .greeting-glow,
    .greeting-icon {
        animation: none;
    }
}

/* ---- Notifications page rows ----
   Each row is a form button (marking read is a POST) styled as a list row, sharing the
   icon/tone vocabulary of the notification bell dropdown. */
.notif-list {
    display: flex;
    flex-direction: column;
}

.notif-form + .notif-form .notif-row {
    border-top: 1px solid var(--bs-border-color, #e5e7eb);
}

.notif-row {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 0.85rem;
    width: 100%;
    padding: 0.95rem 1.1rem 0.95rem 1.35rem;
    background: #fff;
    border: 0;
    text-align: left;
    cursor: pointer;
    transition: background 0.15s ease;
}

.notif-row:hover,
.notif-row:focus-visible {
    background: #faf7f2;
}

.notif-row.is-unread {
    background: #fffdf7;
}

.notif-row.is-unread:hover {
    background: #fdf8ee;
}

/* Colour bar keyed to the notification type; only shown while unread. */
.notif-accent {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    opacity: 0;
}

.notif-row.is-unread .notif-accent {
    opacity: 1;
}

.notif-icon {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    font-size: 1.05rem;
    border-radius: 10px;
    background: rgba(0, 0, 0, 0.04);
}

.notif-body {
    display: grid;
    gap: 0.15rem;
    min-width: 0;
    flex: 1 1 auto;
}

.notif-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.notif-title {
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--gk-ink, #2c2118);
}

.notif-row.is-unread .notif-title {
    font-weight: 800;
}

.notif-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #df5f28;
    flex: 0 0 auto;
}

.notif-message {
    font-size: 0.82rem;
    color: var(--gk-muted, #6b7280);
    line-height: 1.35;
}

.notif-meta {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex-wrap: wrap;
    margin-top: 0.2rem;
    font-size: 0.72rem;
    /* Was a hardcoded #98a2b3 (~2.6:1 on white — fails AA in light mode already, regardless
       of dark mode). Matches .notif-message's own var now, so it also gets dark mode's flip. */
    color: var(--gk-muted, #6b7280);
}

.notif-ref {
    font-variant-numeric: tabular-nums;
}

.notif-go {
    flex: 0 0 auto;
    align-self: center;
    color: #c9cdd4;
    transition: transform 0.15s ease, color 0.15s ease;
}

.notif-row:hover .notif-go {
    color: var(--gk-primary, #df5f28);
    transform: translateX(2px);
}

/* Dark-mode repaint — .notif-row hardcodes a light background (needed so the unread/hover
   tints stay visible against a card in light mode), which otherwise overrides .card's own
   dark-mode repaint while .notif-title/.notif-message keep inheriting the flipped (light)
   --gk-ink/--gk-muted text colors, going invisible against the light background. */
[data-bs-theme="dark"] .notif-row {
    background: #111827;
}

[data-bs-theme="dark"] .notif-row:hover,
[data-bs-theme="dark"] .notif-row:focus-visible {
    background: #1a2436;
}

[data-bs-theme="dark"] .notif-row.is-unread {
    background: #172033;
}

[data-bs-theme="dark"] .notif-row.is-unread:hover {
    background: #1e2a40;
}

[data-bs-theme="dark"] .notif-icon {
    background: rgba(255, 255, 255, 0.06);
}

[data-bs-theme="dark"] .notif-title {
    color: #f8fafc;
}

[data-bs-theme="dark"] .notif-message,
[data-bs-theme="dark"] .notif-meta {
    color: #b7c3d4;
}

[data-bs-theme="dark"] .notif-go {
    color: #475569;
}

[data-bs-theme="dark"] .notif-row:hover .notif-go {
    color: var(--sb-amber, #f2a541);
}

[data-bs-theme="dark"] .notif-form + .notif-form .notif-row {
    border-top-color: #334155;
}

@media (prefers-reduced-motion: reduce) {
    .notif-row,
    .notif-go {
        transition: none;
    }
}

/* ---- Segmented pill toggle ----
   Modern replacement for a plain Bootstrap btn-group where the two options are views of the
   same list (My Approvals / My Requests), not independent actions. */
.seg-toggle {
    display: inline-flex;
    padding: 4px;
    border-radius: 999px;
    background: #f1f0ee;
    gap: 2px;
}

.seg-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.45rem 0.9rem;
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--gk-muted, #6b7280);
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.seg-item:hover {
    color: var(--gk-ink, #2c2118);
}

.seg-item.active {
    background: #fff;
    color: var(--gk-ink, #2c2118);
    box-shadow: 0 1px 3px rgba(16, 24, 40, 0.12);
}

/* A tab that exists but is not this person's — My Approvals for someone who approves nothing.
   Muted and inert rather than removed, so the control reads the same for everybody.
   No new colour: it fades the muted token the tab already uses, which keeps it correct in
   both light and dark without a second definition. */
.seg-item.disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

.seg-item.disabled:hover {
    color: var(--gk-muted, #6b7280);
}

.seg-item .seg-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.35rem;
    padding: 0 0.35rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 800;
    background: rgba(0, 0, 0, 0.06);
}

.seg-item.active .seg-count {
    background: var(--bs-primary, #df5f28);
    color: #fff;
}

/* Dark-mode repaint — .seg-toggle/.seg-item.active both hardcode light backgrounds (#f1f0ee
   track, #fff active pill), which .seg-item's inactive/active text colors (var(--gk-muted)/
   var(--gk-ink)) don't account for since those variables flip to LIGHT values in dark mode —
   light text on a still-light track/pill, both effectively invisible. */
[data-bs-theme="dark"] .seg-toggle {
    background: #1e293b;
}

[data-bs-theme="dark"] .seg-item {
    color: #b7c3d4;
}

[data-bs-theme="dark"] .seg-item:hover {
    color: #f8fafc;
}

[data-bs-theme="dark"] .seg-item.active {
    background: #111827;
    color: #f8fafc;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}

[data-bs-theme="dark"] .seg-item .seg-count {
    background: rgba(255, 255, 255, 0.1);
}

@media (prefers-reduced-motion: reduce) {
    .seg-item {
        transition: none;
    }
}

/* ---- Page-level view transitions ----
   Pairs with the <meta name="view-transition"> tag in _Layout.cshtml. Browsers that don't
   support it (Firefox, older Safari) just navigate normally — nothing to guard here. */
@media (prefers-reduced-motion: no-preference) {
    ::view-transition-old(root),
    ::view-transition-new(root) {
        animation-duration: 0.22s;
        animation-timing-function: ease;
    }
}

@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) {
        animation: none !important;
    }
}

/* ================= Quick Answers (help bubble) =================
   Colours come from Bootstrap's own theme variables (--bs-body-bg, --bs-border-color, …), which
   flip with [data-bs-theme="dark"] on their own. Deliberate: the recurring dark-mode fault in this
   stylesheet has been a component hardcoding a light background while its text inherits a colour
   that does flip, leaving invisible text. Nothing below hardcodes a surface colour. */
.kb-root {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    z-index: 1045; /* over content and the sticky footer, under Bootstrap modals (1055). */

    /* Text colour is carried on this variable rather than taken from --bs-body-color, which does
       NOT flip in this stylesheet: :root above sets it to var(--gk-ink), and because site.css loads
       after Bootstrap at equal specificity, that assignment beats Bootstrap's own
       [data-bs-theme="dark"] value. Reading it here produced dark-on-dark text — the same fault
       .seg-item had to be repainted for. --bs-body-bg and --bs-border-color are not overridden and
       do flip, so those are used directly. */
    --kb-text: var(--gk-ink);
}

[data-bs-theme="dark"] .kb-root {
    --kb-text: #dee2e6; /* Bootstrap's own dark body colour. */
}

.kb-bubble {
    width: 52px;
    height: 52px;
    border-radius: 50%;
    border: none;
    background: linear-gradient(150deg, var(--gk-primary) 0%, var(--gk-primary-strong) 100%);
    color: #fff;
    font-size: 1.35rem;
    box-shadow: var(--gk-shadow);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: transform var(--motion-micro) var(--gk-ease);
}

.kb-bubble:hover {
    transform: translateY(-2px);
}

.kb-bubble-close {
    display: none;
}

.kb-open .kb-bubble-open {
    display: none;
}

.kb-open .kb-bubble-close {
    display: inline-block;
}

.kb-panel {
    position: absolute;
    right: 0;
    bottom: 64px;
    width: min(360px, calc(100vw - 2.5rem));
    max-height: min(520px, calc(100vh - 8rem));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--bs-body-bg);
    color: var(--kb-text);
    border: 1px solid var(--bs-border-color);
    border-radius: 14px;
    box-shadow: var(--gk-shadow);
}

/* The panel appeared instantly, which at the size of a dialog reads as a flash rather than an
   opening. It grows from the bubble's corner, which is what says the two are the same thing.

   Animated as a KEYFRAME on the open state, not a transition: the panel is shown by clearing the
   [hidden] attribute, and a transition does not run across a display change.

   Animating transform is safe HERE and would not be a few hundred lines up. This panel is placed
   by plain right/bottom, so nothing else is writing a transform to fight with. The sidebar's
   account menu is placed by Popper, whose inline transform a running animation would beat - which
   is exactly how that menu ended up opening on top of the user's own name. */
@keyframes kbPanelIn {
    from { opacity: 0; transform: translateY(8px) scale(0.97); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.kb-open .kb-panel {
    animation: kbPanelIn 0.18s var(--gk-ease, ease-out);
    /* Bottom right is where the bubble is, so it unfolds out of the button rather than drifting in. */
    transform-origin: bottom right;
}

/* Somebody who has asked for less motion gets none. */
@media (prefers-reduced-motion: reduce) {
    .kb-open .kb-panel {
        animation: none;
    }
}

.kb-head {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    padding: .75rem .9rem;
    background: linear-gradient(150deg, var(--gk-primary) 0%, var(--gk-primary-strong) 100%);
    color: #fff;
}

.kb-head-text {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    min-width: 0;
}

.kb-title {
    font-weight: 600;
    line-height: 1.2;
}

.kb-sub {
    font-size: .75rem;
    opacity: .85;
}

.kb-head-close {
    border: none;
    background: transparent;
    color: #fff;
    opacity: .8;
    padding: .1rem .25rem;
    cursor: pointer;
}

.kb-head-close:hover {
    opacity: 1;
}

.kb-log {
    flex-grow: 1;
    overflow-y: auto;
    padding: .85rem;
    display: flex;
    flex-direction: column;
    gap: .5rem;
    font-size: .875rem;
}

.kb-msg {
    max-width: 88%;
    padding: .5rem .7rem;
    border-radius: 12px;
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.kb-msg-bot {
    align-self: flex-start;
    background: var(--bs-secondary-bg);
    border-bottom-left-radius: 4px;
}

.kb-msg-me {
    align-self: flex-end;
    background: var(--gk-primary);
    color: #fff;
    border-bottom-right-radius: 4px;
}

.kb-msg-me a {
    color: #fff;
    text-decoration: underline;
}

.kb-hint {
    font-size: .75rem;
    color: var(--bs-secondary-color);
    margin-top: .15rem;
}

.kb-chips {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
}

.kb-chip {
    border: 1px solid var(--bs-border-color);
    background: var(--bs-body-bg);
    color: var(--kb-text);
    border-radius: 999px;
    padding: .3rem .7rem;
    font-size: .8rem;
    text-align: left;
    cursor: pointer;
    transition: border-color var(--motion-micro) var(--gk-ease), transform var(--motion-micro) var(--gk-ease);
}

.kb-chip:hover {
    border-color: var(--gk-primary);
    transform: translateY(-1px);
}

.kb-ticket {
    display: inline-flex;
    align-items: center;
    margin-top: .5rem;
    border: 1px solid var(--gk-primary);
    background: transparent;
    color: var(--gk-primary);
    border-radius: 8px;
    padding: .3rem .65rem;
    font-size: .8rem;
    font-weight: 600;
    cursor: pointer;
}

.kb-ticket:hover {
    background: var(--gk-primary);
    color: #fff;
}

.kb-dots {
    display: inline-flex;
    gap: .22rem;
    align-items: center;
    height: 1.2em;
}

.kb-dots i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--bs-secondary-color);
    animation: kb-blink 1.1s infinite ease-in-out;
}

.kb-dots i:nth-child(2) { animation-delay: .16s; }
.kb-dots i:nth-child(3) { animation-delay: .32s; }

@keyframes kb-blink {
    0%, 80%, 100% { opacity: .25; }
    40% { opacity: 1; }
}

.kb-compose {
    display: flex;
    gap: .4rem;
    padding: .6rem .65rem;
    border-top: 1px solid var(--bs-border-color);
}

.kb-input {
    flex-grow: 1;
    min-width: 0;
    /* 16px keeps iOS from zooming the whole page when this is focused. */
    font-size: 1rem;
    padding: .4rem .6rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
    background: var(--bs-body-bg);
    color: var(--kb-text);
}

.kb-input:focus {
    outline: 2px solid var(--gk-primary);
    outline-offset: 1px;
}

.kb-send {
    border: none;
    border-radius: 8px;
    padding: .4rem .7rem;
    background: var(--gk-primary);
    color: #fff;
    cursor: pointer;
}

.kb-send:hover {
    background: var(--gk-primary-strong);
}

/* Keeps the panel clear of the bottom navigation on small screens. */
@media (max-width: 575.98px) {
    .kb-root {
        right: .75rem;
        bottom: .75rem;
    }
}

@media print {
    .kb-root {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .kb-bubble,
    .kb-chip {
        transition: none;
    }

    .kb-dots i {
        animation: none;
        opacity: .6;
    }
}

/* ================= Email body preview =================
   An email body is arbitrary HTML written by whoever composed it, so it is rendered inside a
   sandboxed iframe rather than into the page. Rendering it inline let an unclosed tag — a linked
   image missing its </a> is the usual one — run on past the preview and swallow the Send buttons
   into the link, so pressing Send followed the link instead of sending. Scripts and forms are
   disabled inside the frame; remote images still load, so the preview looks like the real thing. */
.email-preview-frame {
    display: block;
    width: 100%;
    height: 420px;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--gk-radius);
    /* The cream the emails themselves use, so the preview reads as an email rather than as a page. */
    background: #fbf6ee;
}

.email-preview-frame.is-tall {
    height: 480px;
}

/* ================= Liquidation receipts: collapsible list =================
   The "Receipts" section on a liquidation's Details page collapses under Bootstrap's own
   collapse component (data-bs-toggle="collapse"), which sets aria-expanded on the toggle button
   itself — this just rotates the caret to match, no extra JS needed. */
.receipt-list-caret {
    /* !important on both: this stylesheet is large enough that a bare-specificity rule for a
       one-off element like this can lose to something unrelated further up the cascade — verified
       against a live page, where an unqualified `display: inline-block` here was overridden to
       `block` by something else in this file, which is why an unqualified `transform` never
       visibly rotated the icon despite the rule being present and matching. */
    display: inline-block !important;
    transition: transform var(--motion-micro) var(--gk-ease);
}

[aria-expanded="true"] .receipt-list-caret {
    transform: rotate(180deg) !important;
}

/* === Events: cards, and the switch between cards and the table =================
   The calendar is read by date, so the date is a badge rather than the second of six
   columns. The table is kept because scanning and sorting a list is a different job
   from seeing what is coming up, and the choice is remembered per person.

   Every colour here comes from a token that both themes define, which is the point:
   the recurring contrast fault in this stylesheet is a component hardcoding a light
   value and inheriting a flipped one for its text. */
.event-viewswitch {
    display: inline-flex;
    padding: 2px;
    gap: 2px;
    border-radius: var(--btn-radius);
    background: var(--gk-surface-alt);
    border: 1px solid var(--gk-soft-line);
}

.event-viewswitch a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 30px;
    border-radius: calc(var(--btn-radius) - 3px);
    color: var(--gk-muted);
    text-decoration: none;
    transition: background-color var(--motion-micro) var(--gk-ease),
                color var(--motion-micro) var(--gk-ease);
}

.event-viewswitch a:hover {
    color: var(--gk-ink);
    background: var(--btn-quiet-bg-hover);
}

.event-viewswitch a.is-on {
    background: var(--gk-surface);
    color: var(--gk-primary);
    box-shadow: 0 1px 2px rgba(23, 32, 51, .10);
}

[data-bs-theme="dark"] .event-viewswitch {
    background: rgba(255, 255, 255, .04);
    border-color: rgba(255, 255, 255, .10);
}

[data-bs-theme="dark"] .event-viewswitch a.is-on {
    background: rgba(255, 255, 255, .10);
    color: var(--btn-tint-fg);
    box-shadow: none;
}

/* auto-fill rather than auto-fit: a single event keeps a card's width instead of
   stretching across the whole page, which reads as a mistake. */
.event-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 0.85rem;
}

.event-card {
    display: flex;
    gap: 0.9rem;
    align-items: flex-start;
    padding: 0.95rem 1rem;
    background: var(--gk-surface);
    border: 1px solid var(--gk-soft-line);
    border-radius: 12px;
    box-shadow: var(--gk-shadow-sm);
    text-decoration: none;
    color: inherit;
    transition: transform var(--motion-micro) var(--gk-ease),
                box-shadow var(--motion-micro) var(--gk-ease),
                border-color var(--motion-micro) var(--gk-ease);
}

.event-card:hover,
.event-card:focus-visible {
    transform: translateY(-2px);
    border-color: rgba(176, 74, 26, .28);
    box-shadow: var(--gk-shadow);
    color: inherit;
}

.event-card:focus-visible {
    outline: 2px solid var(--gk-primary);
    outline-offset: 2px;
}

/* A draft or a cancelled event still lists for whoever can manage events, and has to
   read as not-quite-real without becoming unreadable. */
.event-card.is-draft { border-style: dashed; }
.event-card.is-cancelled .event-title { text-decoration: line-through; }
.event-card.is-cancelled { opacity: .72; }

.event-date {
    flex: 0 0 auto;
    width: 54px;
    text-align: center;
    padding: 0.4rem 0;
    border-radius: 10px;
    background: var(--btn-tint-bg);
    color: var(--btn-tint-fg);
    font-variant-numeric: tabular-nums;
}

.event-date .m {
    display: block;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
}

.event-date .d {
    display: block;
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.05;
}

.event-date .w {
    display: block;
    font-size: 0.6rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    opacity: .75;
}

.event-body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

.event-title {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--gk-ink);
    line-height: 1.3;
}

[data-bs-theme="dark"] .event-title { color: var(--bs-body-color); }

.event-meta {
    font-size: 0.78rem;
    color: var(--gk-muted);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.28rem;
}

.event-meta .sep { opacity: .5; }

.event-tags {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.1rem;
}

.event-chip {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    background: rgba(15, 118, 110, .12);
    color: var(--gk-teal);
}

[data-bs-theme="dark"] .event-chip {
    background: rgba(79, 209, 197, .16);
    color: #7fded3;
}

.event-who {
    font-size: 0.72rem;
    color: var(--gk-muted);
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
}

@media (prefers-reduced-motion: reduce) {
    .event-card,
    .event-card:hover { transition: none; transform: none; }
}

/* === Partner portal ============================================================
   Its own shell, because the staff layout renders the sidebar and the sidebar is a
   map of the application. A partner cannot reach any of it, but showing an external
   funder the shape of our internal system is its own kind of leak.

   Committed to the light theme: this is a page shown to somebody outside the
   organisation, and the dark toggle lives in the staff sidebar they do not have. So
   every colour here is stated rather than inherited, and none of it depends on a
   theme attribute that will never be set. */
.partner-body {
    background: var(--gk-surface-alt);
    color: var(--gk-ink);
    min-height: 100vh;
}

.partner-shell {
    max-width: 1140px;
    margin-inline: auto;
    padding-inline: 1rem;
}

.partner-header {
    background: var(--gk-surface);
    border-bottom: 1px solid var(--gk-soft-line);
    padding: 0.85rem 0;
    position: sticky;
    top: 0;
    z-index: 10;
}

.partner-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    text-decoration: none;
    color: var(--gk-ink);
}

.partner-brand strong { display: block; font-size: 0.95rem; line-height: 1.1; }
.partner-brand small { display: block; font-size: 0.72rem; color: var(--gk-muted); }

/* Holds the GK logo, not two letters. Sized a little larger than the old lettermark because a
   logo needs room to read; the pale plate behind it is what keeps a dark logo legible on the
   partner header rather than relying on the image having its own background. */
.partner-mark {
    display: inline-grid;
    place-items: center;
    flex-shrink: 0;
    width: 44px;
    height: 38px;
    padding: 0.25rem;
    border-radius: 10px;
    background: linear-gradient(160deg, #fff7ef 0%, #fff 100%);
    border: 1px solid var(--gk-soft-line);
}

/* The funder's own mark, beside ours. Same plate and sizing so neither looks like the junior
   partner, which is the whole point of showing them together. */
.partner-mark-theirs {
    background: var(--gk-surface);
}

.partner-lockup-x {
    color: var(--gk-muted);
    font-size: 1rem;
    line-height: 1;
    flex-shrink: 0;
}

/* On a phone the two marks and the "x" are the partnership; the wordmark is the first thing that
   can go, because the page title already says where they are. */
@media (max-width: 420px) {
    .partner-brand-copy { display: none; }
}

.partner-mark img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.partner-org {
    font-size: 0.82rem;
    color: var(--gk-muted);
    max-width: 22ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Two links in the partner shell's header. Built here rather than with .nav-pills because the
   header sits on the partner surface rather than on a card, and the Bootstrap pill's filled active
   state reads as a button next to the two real buttons beside it. */
.partner-nav-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.75rem;
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--gk-muted);
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.partner-nav-link:hover,
.partner-nav-link:focus-visible {
    color: var(--gk-ink);
    background: var(--gk-surface-alt);
}

.partner-nav-link.active {
    color: var(--gk-primary);
    background: var(--gk-surface-alt);
}

/* On a phone the header is one row (2026-10-15): marks, the two pages with short labels, and a menu
   button holding the account and sign-out. Two bare icons were two destinations nobody could name. */
@media (max-width: 575.98px) {
    .partner-header-row { flex-wrap: nowrap; }
    .partner-nav-link { padding: 0.35rem 0.55rem; font-size: 0.8rem; gap: 0.3rem; }
}

/* The partner tables scroll sideways inside their own box on a narrow screen. An earlier rule in this
   file turns .table-responsive to overflow: visible below 992px for the staff app's stacked tables; the
   partner tables do not stack, so a grants table widened the whole page to 605px on a 375px phone. */
@media (max-width: 991.98px) {
    .partner-body .table-responsive { overflow-x: auto; }
}

/* What the funder has to act on: overdue and soon-due reports, unread messages. Above the tiles. */
.partner-attention {
    background: var(--gk-surface);
    border: 1px solid var(--gk-soft-line);
    border-left: 4px solid var(--gk-rose, #c0392b);
    border-radius: 0;
    padding: 0.9rem 1rem;
}
.partner-attention-item { padding: 0.45rem 0; border-top: 1px solid var(--gk-soft-line); }
.partner-attention-item:first-child { border-top: 0; padding-top: 0; }
.partner-attention-item .badge { margin-left: 0.35rem; }

.partner-hero {
    padding: 0.25rem 0 0;
}

.partner-stat {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    height: 100%;
    padding: 1rem 1.1rem;
    background: var(--gk-surface);
    border: 1px solid var(--gk-soft-line);
    border-radius: 12px;
    box-shadow: var(--gk-shadow-sm);
}

.partner-stat .label {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--gk-muted);
}

.partner-stat .value {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
}

.partner-stat .foot { font-size: 0.75rem; color: var(--gk-muted); }

/* Overdue reporting is the one thing on this page somebody has to act on, so it is
   the one thing that carries colour. */
.partner-stat.is-alert {
    border-color: rgba(190, 18, 60, .35);
    background: rgba(190, 18, 60, .04);
}

.partner-stat.is-alert .value { color: var(--gk-rose); }

.partner-project {
    display: block;
    height: 100%;
    padding: 1rem 1.1rem;
    background: var(--gk-surface);
    border: 1px solid var(--gk-soft-line);
    border-radius: 12px;
    box-shadow: var(--gk-shadow-sm);
    text-decoration: none;
    color: inherit;
    transition: transform var(--motion-micro) var(--gk-ease),
                box-shadow var(--motion-micro) var(--gk-ease),
                border-color var(--motion-micro) var(--gk-ease);
}

.partner-project:hover,
.partner-project:focus-visible {
    transform: translateY(-2px);
    border-color: rgba(176, 74, 26, .28);
    box-shadow: var(--gk-shadow);
    color: inherit;
}

.partner-project .progress { height: 6px; }

.partner-counts {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    font-size: 0.78rem;
    color: var(--gk-muted);
}

.partner-timeline {
    list-style: none;
    margin: 0;
    padding: 0 0 0 1.1rem;
    border-left: 2px solid var(--gk-soft-line);
}

.partner-timeline > li {
    position: relative;
    padding-bottom: 1.4rem;
}

.partner-timeline > li:last-child { padding-bottom: 0; }

.partner-timeline > li::before {
    content: "";
    position: absolute;
    left: calc(-1.1rem - 5px);
    top: 0.45rem;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--gk-primary);
}

.partner-timeline .progress { height: 6px; }

.partner-photos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 0.5rem;
}

/* The community map's colour scale. One row, wrapping, quiet - it explains the map rather than
   competing with it. The swatch is a circle because the marks on the map are circles; a square
   key beside round marks makes the reader do a translation for no reason. */
.map-legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem 0.9rem;
    font-size: 0.78rem;
    color: var(--gk-muted);
}

.map-legend-label { font-weight: 600; color: var(--gk-ink); }

.map-legend-step { display: inline-flex; align-items: center; gap: 0.35rem; }

/* The key's marks are house glyphs now, matching what the map draws. Sized to read at a glance
   without competing with the label beside them. */
.map-legend-step i {
    font-size: 1rem;
    line-height: 1;
    flex-shrink: 0;
    /* A thin dark edge, the same trick the map icons use: the palest fill would otherwise vanish
       into a white card exactly as it would vanish into a pale basemap. */
    -webkit-text-stroke: 0.5px rgba(23, 32, 51, 0.55);
}

@media (max-width: 575.98px) {
    /* The "single community" key stops being pushed to the far edge once the row wraps. */
    .map-legend-step.ms-auto { margin-left: 0 !important; }
}

/* ── Partner map: list beside the map (2026-10-15) ──────────────────────────────────────────────
   Wide: numbers, filters and the community list on the left, as tall as the map, the list scrolling
   inside it. Phone: numbers and filters on top, then a Map | List switch shows one or the other. */
.partner-map { overflow: hidden; }
.partner-map-side {
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--gk-soft-line);
    background: var(--gk-surface);
}
.partner-map-top { padding: 1rem; border-bottom: 1px solid var(--gk-soft-line); }
.partner-map-numbers {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.5rem;
    margin-bottom: 0.85rem;
}
.partner-map-numbers > div {
    background: var(--gk-surface-alt);
    border-radius: 10px;
    padding: 0.5rem 0.6rem;
    min-width: 0;
}
.partner-map-numbers .value { display: block; font-size: 1.15rem; font-weight: 800; color: var(--gk-ink); line-height: 1.15; }
.partner-map-numbers .label { display: block; font-size: 0.72rem; color: var(--gk-muted); }
.partner-map-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.partner-site-list > li + li { border-top: 1px solid var(--gk-soft-line); }
.partner-site {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: 0;
    padding: 0.55rem 1rem;
    color: var(--gk-ink);
}
.partner-site:hover, .partner-site:focus-visible { background: var(--gk-surface-alt); }
.partner-site-name { display: block; font-weight: 600; font-size: 0.88rem; }
.partner-site-place, .partner-site-families { display: block; font-size: 0.76rem; color: var(--gk-muted); }

@media (min-width: 992px) {
    /* The side is as tall as the map beside it, and the list scrolls inside that. */
    .partner-map-side { height: clamp(380px, 68vh, 700px); }
}
@media (max-width: 991.98px) {
    .partner-map-side { border-right: 0; }
    .partner-map[data-mode="map"] .partner-map-list { display: none; }
    .partner-map[data-mode="list"] .partner-map-main { display: none; }
    .partner-map[data-mode="list"] .partner-map-list { max-height: none; }
}

/* ── Partner sign-in page ───────────────────────────────────────────────────────────────────────
   Its own page, not the staff sign-in. Two panels: what this is, and the form. The welcome panel
   carries the weight, because a funder arriving here needs to know whose portal this is before
   they are asked for a password. Below 900px the form comes FIRST — somebody returning for the
   tenth time wants the fields, not the pitch. */
.pl-body {
    margin: 0;
    min-height: 100dvh;
    background: var(--gk-surface);
    color: var(--gk-ink);
}

.pl-shell {
    display: grid;
    grid-template-columns: 1.1fr 0.9fr;
    min-height: 100dvh;
}

.pl-welcome {
    padding: clamp(1.75rem, 5vw, 4rem);
    background:
        radial-gradient(1200px 500px at 15% -10%, rgba(242, 165, 65, 0.22), transparent 60%),
        linear-gradient(150deg, #2a1206 0%, #5d2410 45%, var(--gk-primary) 100%);
    color: #fff;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1.25rem;
}

.pl-brand { display: flex; align-items: center; gap: 0.85rem; }

.pl-mark {
    display: inline-grid;
    place-items: center;
    width: 52px;
    height: 46px;
    padding: 0.3rem;
    border-radius: 12px;
    background: #fff;
    flex-shrink: 0;
}

.pl-mark img { width: 100%; height: 100%; object-fit: contain; }

.pl-brand-name { font-weight: 700; line-height: 1.1; }
.pl-brand-sub { font-size: 0.8rem; opacity: 0.85; }

.pl-headline {
    font-family: "Fraunces", Georgia, serif;
    font-size: clamp(1.9rem, 4vw, 3rem);
    font-weight: 700;
    line-height: 1.1;
    margin: 0.5rem 0 0;
}

.pl-lede { max-width: 46ch; opacity: 0.92; margin: 0; }

.pl-points { list-style: none; margin: 0.5rem 0 0; padding: 0; display: grid; gap: 0.6rem; }

.pl-points li { display: flex; align-items: center; gap: 0.7rem; font-size: 0.92rem; opacity: 0.95; }

.pl-points i { opacity: 0.85; }

.pl-form-panel {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1rem;
    padding: clamp(1.75rem, 5vw, 4rem);
    background: var(--gk-surface-alt);
}

.pl-form {
    width: 100%;
    max-width: 24rem;
    margin-inline: auto;
    padding: clamp(1.25rem, 3vw, 2rem);
    background: var(--gk-surface);
    border: 1px solid var(--gk-soft-line);
    border-radius: 14px;
    box-shadow: var(--gk-shadow-sm);
}

.pl-staff-note {
    max-width: 24rem;
    margin: 0 auto;
    font-size: 0.8rem;
    color: var(--gk-muted);
    text-align: center;
}

@media (max-width: 900px) {
    .pl-shell { grid-template-columns: 1fr; }

    /* The form first on a phone. The welcome panel is for a first visit; the field is for every
       visit after it, and making somebody scroll past the pitch each time is a small daily tax. */
    .pl-form-panel { order: -1; }
    .pl-welcome { padding-block: 2.5rem; }
    .pl-points { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 520px) {
    .pl-points { grid-template-columns: 1fr; }
}

/* The partner portal reads as a journey: what you funded, where it went, what changed, what is
   outstanding. These are the signposts between those four sections. Numbered rather than merely
   headed, because the order is the point - a funder should be able to see that the page answers
   their questions in the sequence they would ask them. */
.partner-welcome {
    padding: 1.25rem 1.4rem;
    border-radius: 14px;
    border: 1px solid var(--gk-soft-line);
    background: linear-gradient(135deg, #fff7ef 0%, var(--gk-surface) 60%);
    box-shadow: var(--gk-shadow-sm);
}

.partner-welcome p {
    max-width: 62ch;
    color: var(--gk-muted);
    font-size: 0.95rem;
}

.journey-step {
    margin: 2.25rem 0 1rem;
}

.journey-step:first-of-type { margin-top: 1.5rem; }

.journey-step-head {
    display: flex;
    align-items: flex-start;
    gap: 0.85rem;
    padding-bottom: 0.6rem;
    border-bottom: 2px solid var(--gk-soft-line);
}

.journey-step-num {
    display: inline-grid;
    place-items: center;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--gk-primary);
    color: #fff;
    font-weight: 700;
    font-size: 0.9rem;
}

@media (max-width: 575.98px) {
    .journey-step { margin-top: 1.75rem; }
    .journey-step-num { width: 28px; height: 28px; font-size: 0.8rem; }
}

/* The grant conversation. Two sides, distinguished by alignment and tint rather than by a label
   alone - the label is there too, because colour on its own is not a distinction everybody can see. */
.partner-thread { display: flex; flex-direction: column; gap: 0.85rem; }

.partner-msg {
    max-width: 44rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--gk-soft-line);
    border-radius: 12px;
    background: var(--gk-surface-alt);
}

/* The partner's own messages sit to the right, the way every messaging app the reader has ever
   used puts them. */
.partner-msg.is-mine {
    margin-left: auto;
    background: var(--gk-surface);
    border-color: var(--gk-line);
}

.partner-msg-meta {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    font-size: 0.75rem;
    margin-bottom: 0.3rem;
}

/* pre-wrap, so the writer's own paragraphs survive without the body being HTML. */
.partner-msg-body {
    font-size: 0.9rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

@media (max-width: 575.98px) {
    .partner-msg { max-width: 100%; }
    .partner-msg-meta { flex-direction: column; gap: 0; }
}

.partner-photos img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid var(--gk-soft-line);
}

@media (prefers-reduced-motion: reduce) {
    .partner-project,
    .partner-project:hover { transition: none; transform: none; }
}


/* ── Access Groups: the inheritance picker ──────────────────────────────────────────────────────
   The group list is an ordinary table now, on the house pattern, so it needs nothing of its own.
   This one does: with forty groups the picker is forty checkboxes, and the tab it lives in should
   not become the tallest thing on the page.

   Colours anywhere here would be Bootstrap theme variables, not fixed values. This file already
   carries three dark-mode repaints for components that hardcoded a light background and then had
   their text go invisible against it; --bs-* flips on its own. */
.inherit-list {
    max-height: 22rem;
    overflow-y: auto;
    overscroll-behavior: contain;
}


/* ── Quick Answers: the guided-action button ────────────────────────────────────────────────────
   Deliberately the FILLED sibling of .kb-ticket rather than another outline button. The ticket
   button is the consolation when there is no answer; this one is the answer working, so it is the
   one that should look like the thing to press. Both take their colour from the brand token, so
   dark mode is already handled. */
.kb-action-wrap {
    margin-top: .15rem;
}

.kb-action {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--btn-primary-bg);
    background: var(--btn-primary-bg);
    color: var(--btn-primary-fg);
    border-radius: 8px;
    padding: .34rem .7rem;
    font-size: .8rem;
    font-weight: 600;
    text-decoration: none;
}

.kb-action:hover,
.kb-action:focus-visible {
    background: var(--btn-primary-bg-hover);
    border-color: var(--btn-primary-bg-hover);
    color: var(--btn-primary-fg);
    text-decoration: none;
}

/* ── Summary-card figures ───────────────────────────────────────────────────────────────────────
   The money on a detail page's summary strip. These cards are half-width on a phone, and a peso
   figure in the millions at fs-4 does not fit: "₱2,450,000.00" broke after the second-to-last
   digit, so the card read "₱2,450,000.0" with a lone "0" underneath. Size only — colour and
   weight stay with the utility classes on the element. */
.kpi-value {
    font-size: 1.5rem;
    line-height: 1.25;
}

@media (max-width: 575.98px) {
    .kpi-value {
        font-size: 1.15rem;
    }
}
/* ============================================================================
   Team Sites
   ----------------------------------------------------------------------------
   Two things live here: how a published team page renders, and the editor's
   three-pane layout.

   Every colour is a token defined on :root and swapped under
   [data-bs-theme="dark"], never a literal. A component hardcoding a light
   background while its text inherits a flipped dark-mode variable is the
   recurring bug in this stylesheet's history, and a page built by somebody
   who is not a developer is the worst place for it to appear.
   ============================================================================ */

:root {
    --ts-section-subtle: var(--gk-surface-alt);
    --ts-section-accent: rgba(176, 74, 26, .07);
    --ts-block-hover: rgba(176, 74, 26, .06);
    --ts-block-selected: var(--gk-primary);
    --ts-canvas: var(--gk-surface-alt);
    --ts-palette-bg: var(--gk-surface);
}

[data-bs-theme="dark"] {
    --ts-section-subtle: rgba(255, 255, 255, .04);
    --ts-section-accent: rgba(226, 128, 74, .12);
    --ts-block-hover: rgba(226, 128, 74, .10);
    --ts-block-selected: #e2804a;
    --ts-canvas: rgba(0, 0, 0, .18);
    --ts-palette-bg: transparent;
}

/* ---- the page itself ---- */

.ts-section { width: 100%; }
.ts-section--subtle { background: var(--ts-section-subtle); }
.ts-section--accent { background: var(--ts-section-accent); }

.ts-pad-none   { padding-block: 0; }
.ts-pad-small  { padding-block: .75rem; }
.ts-pad-medium { padding-block: 1.75rem; }
.ts-pad-large  { padding-block: 3rem; }

/* Side padding is set once here so no section can lose its gutter on a phone. */
.ts-inner { margin-inline: auto; padding-inline: 16px; }
.ts-width-normal .ts-inner { max-width: 860px; }
.ts-width-wide   .ts-inner { max-width: 1200px; }
.ts-width-full   .ts-inner { max-width: none; }

.ts-text { white-space: pre-wrap; overflow-wrap: anywhere; }

.ts-scale-small   { font-size: .875rem; color: var(--gk-muted); }
.ts-scale-body    { font-size: 1rem; }
.ts-scale-lead    { font-size: 1.15rem; }
.ts-scale-h3      { font-size: 1.35rem; font-weight: 600; }
.ts-scale-h2      { font-size: 1.7rem; font-weight: 700; }

.ts-image { max-width: 100%; height: auto; border-radius: var(--gk-radius); }

.ts-member { border: 1px solid var(--gk-soft-line); border-radius: var(--gk-radius); padding: .85rem 1rem; height: 100%; }
.ts-doc { display: flex; gap: .6rem; align-items: center; padding: .55rem .75rem; border: 1px solid var(--gk-soft-line); border-radius: var(--gk-radius); }
.ts-doc + .ts-doc { margin-top: .4rem; }

/* ---- adding a file to the site ---- */

/* A drop zone in place of the browser's own file control.

   `<input type="file">` is the one widget the browser draws itself, and no amount of
   .form-control makes it match anything else here: it arrived as a grey "Choose File / No file
   chosen" plate, the only piece of operating-system chrome on the page, which is what made this
   panel read as broken rather than merely plain. The input is still there and still the thing
   that posts — it is clipped, not removed, so it keeps its place in the tab order and the form
   submits exactly as before. Everything visible is the label wrapped around it. */
.ts-drop {
    display: block;
    width: 100%;
    padding: 1.35rem 1rem;
    text-align: center;
    cursor: pointer;
    border: 1.5px dashed var(--gk-soft-line);
    border-radius: var(--gk-radius);
    background: var(--gk-surface-alt);
    transition: border-color .12s var(--gk-ease), background .12s var(--gk-ease);
}

.ts-drop:hover,
.ts-drop.is-dragging { border-color: var(--gk-primary); }

/* The ring belongs on the zone, because the control it describes is invisible. Without this a
   keyboard user tabs onto the file field and nothing on screen moves. */
.ts-drop:focus-within {
    border-color: var(--gk-primary);
    box-shadow: 0 0 0 .2rem rgba(176, 74, 26, .18);
}

/* Clipped rather than display:none. A hidden input cannot be focused or announced, and a
   `required` one that cannot be focused makes Chrome refuse the submit with nothing on screen to
   explain it — which is why the requirement lives on the Upload button being disabled instead. */
.ts-drop-input {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
}

.ts-drop-icon { display: block; font-size: 1.6rem; color: var(--gk-primary); margin-bottom: .35rem; }
.ts-drop-call { color: var(--gk-primary); font-weight: 700; text-decoration: underline; }
.ts-drop-hint { font-size: .8rem; color: var(--gk-muted); margin-top: .2rem; }

/* Shown only once something is picked, so the person can see WHICH file is about to go up. */
.ts-drop-chosen {
    display: none;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    font-weight: 600;
    color: var(--gk-ink);
    overflow-wrap: anywhere;
}

.ts-drop.has-file .ts-drop-chosen { display: flex; }
.ts-drop.has-file .ts-drop-prompt { display: none; }
.ts-drop.has-file { border-style: solid; border-color: var(--gk-primary); }

/* ---- the editor ---- */

/* The stage is the page. No panes, no tray — what is on screen is what readers will get, and
   the editing affordances stay out of the way until they are needed. */
.ts-stage {
    background: var(--gk-surface);
    border: 1px solid var(--gk-soft-line);
    border-radius: var(--gk-radius);
    padding: .5rem .75rem 1rem;
    min-height: 340px;
}

/* A round + between sections and at the foot of a column. Quiet until the row is hovered, so an
   empty page invites a click and a full one does not shout. */
.ts-plus {
    width: 28px; height: 28px; flex: 0 0 28px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--gk-line); border-radius: 50%;
    background: var(--gk-surface); color: var(--gk-primary);
    font-size: .8rem; line-height: 1; padding: 0;
    transition: background .12s var(--gk-ease), border-color .12s var(--gk-ease);
}
.ts-plus:hover { background: var(--ts-block-hover); border-color: var(--ts-block-selected); }
.ts-plus:disabled { opacity: .4; cursor: not-allowed; }
.ts-plus:disabled:hover { background: var(--gk-surface); border-color: var(--gk-line); }

/* The section bar's own controls: move, duplicate, remove. Disabled ones stay visible and stop
   responding rather than disappearing, so the row does not reflow as you move a section to the
   top or bottom of the page. */
.ts-section-bar button:disabled { opacity: .35; cursor: not-allowed; }

.ts-add-section {
    display: flex; align-items: center; justify-content: center;
    height: 26px; margin: .1rem 0; position: relative;
    opacity: 0; transition: opacity .12s var(--gk-ease);
}
.ts-add-section::before {
    content: ""; position: absolute; left: 0; right: 0; top: 50%;
    border-top: 1px dashed var(--gk-line);
}
.ts-add-section > .ts-plus { position: relative; }
.ts-add-section:hover,
.ts-stage:hover .ts-add-section { opacity: 1; }

.ts-add-block { display: flex; align-items: center; padding: .15rem .35rem; opacity: 0; transition: opacity .12s var(--gk-ease); }
.ts-column:hover .ts-add-block { opacity: 1; }
/* An empty column has nothing else to offer, so its + is always visible. */
.ts-add-block--empty { opacity: 1; }

/* Text being typed on the page. No box — the point is that it looks like the finished page —
   just a faint ring while focused so it is clear what is being edited. */
.ts-editable:focus { outline: 2px solid var(--ts-block-selected); outline-offset: 3px; border-radius: 3px; }
.ts-editable:empty::before {
    content: attr(data-placeholder);
    color: var(--gk-muted); font-style: italic;
}

/* The component picker. */
.ts-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: .5rem; }
.ts-picker-item {
    display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto;
    column-gap: .6rem; align-items: center; text-align: left;
    padding: .65rem .75rem;
    border: 1px solid var(--gk-soft-line); border-radius: var(--gk-radius);
    background: var(--gk-surface);
}
.ts-picker-item i { grid-row: 1 / span 2; font-size: 1.3rem; color: var(--gk-primary); }
.ts-picker-item:hover { background: var(--ts-block-hover); border-color: var(--ts-block-selected); }

/* Settings slide in from the right, over the page rather than squeezing it. */
.ts-panel {
    position: fixed; top: 0; right: 0; bottom: 0; width: 320px; max-width: 92vw;
    background: var(--gk-surface); border-left: 1px solid var(--gk-soft-line);
    box-shadow: var(--gk-shadow);
    transform: translateX(100%); transition: transform .16s var(--gk-ease);
    z-index: 1045; display: flex; flex-direction: column;
}
.ts-panel.open { transform: none; }
.ts-panel-head { display: flex; align-items: center; gap: .5rem; padding: .75rem; border-bottom: 1px solid var(--gk-soft-line); }
.ts-panel-body { padding: .75rem; overflow-y: auto; }

.ts-canvas-section { border: 1px dashed var(--gk-line); border-radius: var(--gk-radius); margin-bottom: .75rem; }
.ts-canvas-section.selected { border-color: var(--ts-block-selected); border-style: solid; }
.ts-section-bar { display: flex; align-items: center; gap: .4rem; padding: .35rem .5rem; border-bottom: 1px dashed var(--gk-line); font-size: .8rem; color: var(--gk-muted); }

/* Proportions are set inline from the layout's own widths, so there is no class per shape to
   keep in step with the enum. */
.ts-columns { display: grid; gap: .5rem; padding: .5rem; grid-template-columns: 1fr; }

/* Five little diagrams instead of a dropdown: the choice is a shape, so it is shown as one. */
.ts-layouts { display: flex; flex-wrap: wrap; gap: .4rem; }
.ts-layout {
    padding: .3rem; border: 1px solid var(--gk-soft-line); border-radius: var(--gk-radius);
    background: var(--gk-surface); width: 56px;
}
.ts-layout:hover { border-color: var(--ts-block-selected); background: var(--ts-block-hover); }
.ts-layout.selected { border-color: var(--ts-block-selected); box-shadow: 0 0 0 1px var(--ts-block-selected) inset; }
.ts-layout-diagram { display: flex; gap: 2px; height: 22px; }
.ts-layout-col { background: var(--gk-line); border-radius: 2px; flex-basis: 0; }
.ts-layout.selected .ts-layout-col { background: var(--ts-block-selected); }

.ts-column { min-height: 60px; border: 1px dashed transparent; border-radius: var(--gk-radius); padding: .25rem; }
.ts-column.dragover { border-color: var(--ts-block-selected); background: var(--ts-block-hover); }

/* A block on the canvas is the real thing, not a card around it. Anything with its own
   background or border here would sit on top of the page's own design and hide exactly what the
   editor exists to show. So: no chrome at rest, a hairline on hover, an outline when selected. */
.ts-block { position: relative; border-radius: var(--gk-radius); margin-bottom: .25rem; outline: 1px dashed transparent; outline-offset: 2px; }
.ts-block:hover { outline-color: var(--gk-line); }
.ts-block.selected { outline: 2px solid var(--ts-block-selected); outline-offset: 2px; }
.ts-block.dragging { opacity: .45; }

/* The grab handle. Dragging the body directly would start a drag every time somebody tried to
   select a word, and an image would swallow the gesture entirely — browsers drag those
   themselves. It stays out of the way until the block is hovered or selected. */
.ts-block-handle {
    display: flex; align-items: center; gap: .35rem;
    padding: .1rem .35rem; cursor: grab;
    opacity: 0; transition: opacity .12s var(--gk-ease);
}
.ts-block:hover > .ts-block-handle,
.ts-block.selected > .ts-block-handle { opacity: 1; }
.ts-block-handle:active { cursor: grabbing; }
.ts-block-body { padding: .1rem .35rem; }

.ts-block-kind { font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; color: var(--gk-muted); }

/* What the server fills in — documents, contact, team members. Drawn as a labelled placeholder
   rather than faked, because inventing rows here would show content the page does not have. */
.ts-dynamic {
    border: 1px dashed var(--gk-line); border-radius: var(--gk-radius);
    padding: .6rem .75rem; background: var(--ts-section-subtle);
}

/* On a phone the settings panel takes the full width rather than a 320px strip over a 375px
   screen, and the + affordances stop hiding: there is no hover to reveal them with. */
@media (max-width: 767.98px) {
    .ts-panel { width: 100%; }
    .ts-add-section, .ts-add-block { opacity: 1; }
}

/* Every layout is one column on a phone. Two thirds of a 375px screen is not a column. */
@media (max-width: 767.98px) {
    .ts-columns { grid-template-columns: 1fr !important; }
}

/* Team site navigation: the strip of pages under a site's header. Quiet by design — it is a
   handful of internal pages, not a product's main menu. */
.ts-nav { border-bottom: 1px solid var(--gk-soft-line); margin-bottom: .25rem; }
.ts-nav-inner { display: flex; flex-wrap: wrap; gap: .25rem; padding: 0 16px; max-width: 1200px; margin-inline: auto; }
.ts-nav-link {
    padding: .5rem .75rem; text-decoration: none; color: var(--gk-muted);
    border-bottom: 2px solid transparent; font-size: .92rem;
}
.ts-nav-link:hover { color: var(--gk-ink); background: var(--ts-block-hover); }
.ts-nav-link.active { color: var(--gk-primary); border-bottom-color: var(--gk-primary); font-weight: 600; }

/* The inline rename row under each page in the Pages list. */
.ts-page-settings td { border-top: 0; }

/* Stacked on a phone every row becomes its own card, which would float the rename row away
   from the page it renames. Joined to the card above instead. */
@media (max-width: 767.98px) {
    .table-mobile tr.ts-page-settings {
        margin-top: -0.75rem;
        border-top: 0;
        border-top-left-radius: 0;
        border-top-right-radius: 0;
        box-shadow: none;
    }
}

/* A news item on a team page. */
.ts-news { padding: .6rem 0; }
.ts-news + .ts-news { border-top: 1px solid var(--gk-soft-line); }

/* Edge draws its own "reveal" eye inside a password box once you start typing. Where the page
   already has a show/hide button, that made two eyes side by side. Hidden ONLY on fields that carry
   their own button (mark them has-own-reveal); every other password field keeps the browser's one. */
input.has-own-reveal::-ms-reveal,
input.has-own-reveal::-ms-clear {
    display: none;
}

/* A small heading for a group of fields inside one form section — "Application", "Grant period". */
.form-subgroup-label {
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--gk-muted);
    margin: 0 0 .35rem;
}

/* A button in a row of form fields, at the fields' height. Every .form-control and .form-select is at
   least 42px (above), while .btn is 40px and .btn-sm 34px, so a bottom-aligned button beside fields
   stood short and its top sat lower than theirs. */
.btn.btn-field {
    min-height: 42px;
}

/* ============================================================================
   Global search: the sidebar box and the palette (_GlobalSearch.cshtml).
   Colours are Bootstrap's own theme variables, which flip under
   [data-bs-theme="dark"], plus two tokens of our own swapped there too.
   ============================================================================ */

:root {
    --gs-active-bg: rgba(176, 74, 26, .10);
    --gs-active-ring: rgba(176, 74, 26, .35);
}

[data-bs-theme="dark"] {
    --gs-active-bg: rgba(226, 128, 74, .18);
    --gs-active-ring: rgba(226, 128, 74, .45);
}

.sidebar-search {
    flex-shrink: 0;
    padding: 0.7rem 0.85rem 0.2rem;
}

.sidebar-search-btn {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    min-height: 40px;
    padding: 0 0.7rem;
    border: 1px solid var(--sb-line);
    border-radius: 10px;
    background: rgba(251, 246, 238, 0.06);
    color: var(--sb-ink-soft);
    font-size: 0.86rem;
    text-align: left;
    transition: background 0.16s ease, color 0.16s ease, border-color 0.16s ease;
}

.sidebar-search-btn:hover,
.sidebar-search-btn:focus-visible {
    background: rgba(251, 246, 238, 0.13);
    color: var(--sb-cream);
}

.sidebar-search-label { flex: 1 1 auto; white-space: nowrap; overflow: hidden; }

.sidebar-search-kbd {
    padding: 0.05rem 0.35rem;
    border: 1px solid var(--sb-line);
    border-radius: 5px;
    background: transparent;
    color: var(--sb-ink-faint);
    font-size: 0.68rem;
    font-family: inherit;
    white-space: nowrap;
}

/* More room above on the rail: the edge tab sits on the header divider just over it. */
#sidebar.collapsed .sidebar-search { padding: 1.1rem 0.4rem 0.1rem; }
#sidebar.collapsed .sidebar-search-btn { justify-content: center; padding: 0; }
#sidebar.collapsed .sidebar-search-label,
#sidebar.collapsed .sidebar-search-kbd { display: none; }

/* The palette */
.global-search-modal .modal-dialog { margin-top: 8vh; }
.global-search-modal .modal-content { overflow: hidden; }

.global-search-head {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--bs-border-color);
    color: var(--bs-secondary-color);
}

.global-search-input {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 42px;
    border: 0;
    outline: 0;
    background: transparent;
    color: var(--bs-body-color);
    font-size: 1.05rem;
}

.global-search-input::-webkit-search-cancel-button { display: none; }

.global-search-body { padding: 0.35rem 0.5rem 0.5rem; min-height: 120px; }

.global-search-group + .global-search-group { margin-top: 0.35rem; }

.global-search-group-label {
    padding: 0.55rem 0.65rem 0.25rem;
    color: var(--bs-secondary-color);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.global-search-option {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    min-height: 44px;
    padding: 0.4rem 0.65rem;
    border-radius: 8px;
    color: var(--bs-body-color);
    text-decoration: none;
}

.global-search-option:hover,
.global-search-option:focus { color: var(--bs-body-color); }

.global-search-option > .bi { color: var(--bs-secondary-color); font-size: 1rem; }

.global-search-option[aria-selected="true"] {
    background: var(--gs-active-bg);
    box-shadow: inset 0 0 0 1px var(--gs-active-ring);
    color: var(--bs-body-color);
}

.global-search-option-text,
.search-hit-text { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }

.global-search-option-title,
.search-hit-title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.global-search-option-subtitle,
.search-hit-subtitle { color: var(--bs-secondary-color); font-size: 0.8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.global-search-option-badge,
.search-hit-badge,
.search-tab-count {
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    border: 1px solid var(--bs-border-color);
    font-weight: 600;
}

.global-search-status { padding: 1rem 0.65rem; color: var(--bs-secondary-color); font-size: 0.9rem; }
.global-search-status:empty { display: none; }

.global-search-foot {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.55rem 1rem;
    border-top: 1px solid var(--bs-border-color);
    color: var(--bs-secondary-color);
    font-size: 0.78rem;
}

.global-search-foot kbd {
    margin-right: 0.2rem;
    padding: 0.05rem 0.35rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 4px;
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    font-family: inherit;
    font-size: 0.72rem;
}

@media (max-width: 575.98px) {
    .global-search-modal .modal-dialog { margin: 0.5rem; }
    .global-search-foot span { display: none; }
}

/* The results page */
.search-tabs { gap: 0.35rem; flex-wrap: wrap; }
.search-hit { display: flex; align-items: center; gap: 0.75rem; min-height: 48px; }

/* ============================================================================
   Dashboard: "Waiting on you" strip (Views/Home/Index.cshtml). Tones use
   Bootstrap's *-bg-subtle / *-text-emphasis / *-border-subtle variables, which
   flip under [data-bs-theme="dark"], so no colour here is a literal.
   ============================================================================ */

.waiting-strip {
    padding: 0.9rem 1rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--gk-radius, 8px);
    background: var(--bs-body-bg);
}

.waiting-title {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin: 0 0 0.65rem;
    color: var(--bs-secondary-color);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.waiting-items {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 0.6rem;
}

.waiting-item {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    min-height: 56px;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--waiting-border);
    border-radius: 10px;
    background: var(--waiting-bg);
    color: var(--waiting-ink);
    text-decoration: none;
    transition: transform var(--motion-fast, 120ms) ease, box-shadow var(--motion-fast, 120ms) ease;
}

.waiting-item:hover,
.waiting-item:focus-visible {
    color: var(--waiting-ink);
    transform: translateY(-1px);
    box-shadow: var(--gk-shadow-sm);
}

.waiting-warning { --waiting-bg: var(--bs-warning-bg-subtle); --waiting-ink: var(--bs-warning-text-emphasis); --waiting-border: var(--bs-warning-border-subtle); }
.waiting-danger  { --waiting-bg: var(--bs-danger-bg-subtle);  --waiting-ink: var(--bs-danger-text-emphasis);  --waiting-border: var(--bs-danger-border-subtle); }
.waiting-info    { --waiting-bg: var(--bs-info-bg-subtle);    --waiting-ink: var(--bs-info-text-emphasis);    --waiting-border: var(--bs-info-border-subtle); }

.waiting-icon { font-size: 1.25rem; flex-shrink: 0; }
.waiting-label { display: block; font-weight: 700; }
.waiting-detail { display: block; font-size: 0.8rem; opacity: 0.85; overflow-wrap: anywhere; }
.waiting-empty { color: var(--bs-secondary-color); font-size: 0.9rem; }

@media (prefers-reduced-motion: reduce) {
    .waiting-item { transition: none; }
    .waiting-item:hover { transform: none; }
}

/* ============================================================================
   Automation Center (Views/Automation). Theme variables only.
   ============================================================================ */

.automation-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    margin-right: 0.5rem;
    border-radius: 50%;
    background: var(--gs-active-bg);
    color: var(--bs-body-color);
    font-size: 0.8rem;
}

.automation-rows { display: flex; flex-direction: column; gap: 0.75rem; }

.automation-action {
    padding: 0.85rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--gk-radius, 8px);
    background: var(--bs-tertiary-bg);
}

.job-interval { width: 8.5rem; }
/* A job's own days ("Close after [30] days resolved"): the words stay beside the box. */
.job-days { width: auto; flex-wrap: nowrap; }
.job-days .form-control { flex: 0 0 5.5rem; width: 5.5rem; }

/* Workflow editor: each state is a card with the steps that leave it underneath. The left edge
   says what kind of state it is; a warning edge marks one a record could get stuck in. */
.wf-state { border-left: 3px solid var(--bs-secondary-border-subtle) !important; }
.wf-state-start { border-left-color: var(--bs-primary) !important; }
.wf-state-end { border-left-color: var(--bs-success) !important; }
.wf-state-warn { border-left-color: var(--bs-warning) !important; }
.wf-steps > li + li { border-top: 1px solid var(--bs-border-color-translucent); }
.wf-step-label {
    display: inline-block; padding: .05rem .5rem; border: 1px solid var(--bs-border-color);
    border-radius: .375rem; font-weight: 600; background: var(--bs-body-bg); color: var(--bs-body-color);
}
.wf-flow .min-w-0 { min-width: 0; overflow-wrap: anywhere; }
#diagramPanel > summary { cursor: pointer; list-style: revert; }

/* An error summary with no errors in it. The tag helper renders the box anyway (so client-side
   validation can fill it), which on a page styling it as an alert left an empty red bar above
   the form. */
.validation-summary-valid { display: none !important; }

/* Automation Center rules, grouped by module: a rule on but failing gets a red edge. */
.auto-rules .list-group-item { border-left: 3px solid transparent; }
.auto-rules .auto-rule-failing { border-left-color: var(--bs-danger); }
.auto-rules .min-w-0 { min-width: 0; overflow-wrap: anywhere; }
.automation-summary { border-left: 3px solid var(--bs-primary); }

/* === Sidebar modes (2026-10-01) ===
   One sidebar, three states, the same from a wide desktop down to a tablet:
   - RAIL (html.sb-rail, the default): a 76px icon rail fixed to the left edge. Opening it
     (.sb-open) widens it OVER the page, so the content never jumps, and any click on the page
     closes it again.
   - PINNED (html.sb-pinned): kept open beside the page, as the sidebar always used to be.
     Chosen with the pin button and remembered.
   - PHONE (below 768px): a full-width drawer opened from a slim top bar.
   The state is set before the page paints by the script right after the sidebar markup, and
   driven by site.js. */

.sidebar-pin-btn,
.sidebar-pin-btn .bi-pin-angle-fill {
    display: none;
}

/* The pin: only where pinning means something - the open rail, or a pinned sidebar. */
html.sb-rail #sidebar.sb-open .sidebar-pin-btn,
html.sb-pinned #sidebar .sidebar-pin-btn {
    display: inline-flex;
}

html.sb-pinned #sidebar .sidebar-pin-btn .bi-pin-angle { display: none; }
html.sb-pinned #sidebar .sidebar-pin-btn .bi-pin-angle-fill { display: inline; }
html.sb-pinned #sidebar .sidebar-pin-btn { color: var(--sb-terra); }

.mobile-topbar {
    display: none;
}

/* The edge tab: a round accent button half over the sidebar's right edge, the one open/close
   control at every size. The button is the hit area and .sidebar-edge-face the circle you see,
   so a phone gets a 44px target around the same 30px circle. The top bar's opener wears the same
   face (.sidebar-edge-tab-inline). */
.sidebar-edge-tab {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    /* Seated on the header's bottom divider: clear of the logo on the rail and of the pin when open. */
    top: 3.1rem;
    right: -15px;
    z-index: 2;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    background: transparent;
}

.sidebar-edge-face {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 2px solid var(--kt-surface, #fff);
    border-radius: 50%;
    background: var(--kt-accent, #df5f28);
    color: #fff;
    font-size: 0.85rem;
    box-shadow: 0 4px 12px rgba(15, 23, 42, 0.22);
    transition: transform 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease;
}

:is(.sidebar-edge-tab, .sidebar-edge-tab-inline):hover .sidebar-edge-face,
:is(.sidebar-edge-tab, .sidebar-edge-tab-inline):focus-visible .sidebar-edge-face {
    background: var(--kt-accent-hover, #b04a1a);
    box-shadow: 0 6px 16px rgba(15, 23, 42, 0.28);
    transform: scale(1.08);
}

:is(.sidebar-edge-tab, .sidebar-edge-tab-inline):focus-visible {
    outline: none;
}

:is(.sidebar-edge-tab, .sidebar-edge-tab-inline):focus-visible .sidebar-edge-face {
    outline: 2px solid var(--kt-accent, #df5f28);
    outline-offset: 2px;
}

/* The flip: the chevron turns over on its vertical axis, so right becomes left. */
.sidebar-edge-face i {
    display: inline-block;
    transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

#sidebar.sb-open .sidebar-edge-tab i,
#sidebar.mobile-open .sidebar-edge-tab i,
html.sb-pinned #sidebar .sidebar-edge-tab i {
    transform: rotateY(180deg);
}

@media (max-width: 767.98px) {
    /* A full touch target, and out of sight while the drawer is shut: the top bar's tab opens it. */
    .sidebar-edge-tab {
        top: 1rem;
        right: -22px;
        width: 44px;
        height: 44px;
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.18s ease;
    }

    #sidebar.mobile-open .sidebar-edge-tab {
        opacity: 1;
        pointer-events: auto;
    }
}

@media (min-width: 768px) {
    html.sb-rail #sidebar {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        height: 100vh;
        /* Over the page and its sticky bits, under modals (1055) and the search palette. */
        z-index: 1045;
    }

    /* Room for the rail; the open sidebar then lies over the page instead of pushing it. */
    html.sb-rail .app-content-col {
        margin-left: 76px;
    }

    html.sb-rail #sidebar.sb-open {
        width: 276px;
        box-shadow: 14px 0 34px rgba(15, 23, 42, 0.22);
    }

    html.sb-rail .sidebar-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 1040;
        background: rgba(15, 23, 42, 0.28);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.18s ease;
    }

    html.sb-rail .sidebar-backdrop.show {
        opacity: 1;
        pointer-events: auto;
    }
}

@media (max-width: 767.98px) {
    #sidebar {
        position: fixed;
        z-index: 1050;
        height: 100%;
        transform: translateX(-100%);
        width: min(86vw, 300px);
        box-shadow: 14px 0 34px rgba(15, 23, 42, 0.28);
    }

    #sidebar.mobile-open {
        transform: translateX(0);
    }

    .sidebar-backdrop {
        position: fixed;
        inset: 0;
        z-index: 1040;
        background: rgba(15, 23, 42, 0.42);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.18s ease;
        display: block;
    }

    .sidebar-backdrop.show {
        opacity: 1;
        pointer-events: auto;
    }

    /* The slim bar the drawer opens from. It replaces the floating round button, which sat
       over whatever the page had in its top-left corner. */
    .mobile-topbar {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: 1030;
        height: 56px;
        padding: 0 0.6rem;
        background: var(--kt-surface, var(--bs-body-bg));
        border-bottom: 1px solid var(--kt-line, var(--bs-border-color));
    }

    .app-content-col {
        padding-top: 56px;
    }

    .mobile-topbar-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        border: 0;
        border-radius: 10px;
        background: transparent;
        color: var(--kt-ink, var(--bs-body-color));
        font-size: 1.35rem;
    }

    .mobile-topbar-btn:hover,
    .mobile-topbar-btn:focus-visible {
        background: var(--kt-line, var(--bs-secondary-bg));
    }

    /* The opener shows its round face, not a grey square behind it. */
    .mobile-topbar-btn.sidebar-edge-tab-inline:hover,
    .mobile-topbar-btn.sidebar-edge-tab-inline:focus-visible {
        background: transparent;
    }

    .mobile-topbar-brand {
        display: inline-flex;
        align-items: center;
        gap: 0.5rem;
        min-width: 0;
        color: var(--kt-ink, var(--bs-body-color));
        font-weight: 700;
        text-decoration: none;
    }

    .mobile-topbar-brand img {
        width: 30px;
        height: 30px;
        object-fit: contain;
    }

    .mobile-topbar-brand span {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* Set before the first paint and lifted by site.js a moment later: the page arrives already in
   its rail or pinned state instead of animating into it. */
html.sb-no-anim #sidebar,
html.sb-no-anim #sidebar *,
html.sb-no-anim .app-content-col {
    transition: none !important;
}

@media (prefers-reduced-motion: reduce) {
    #sidebar,
    .sidebar-backdrop,
    .sidebar-edge-tab,
    .sidebar-edge-face,
    .sidebar-edge-face i {
        transition: none;
    }
}

/* ── Admin › Liquidation Approvers: one row per region (2026-10-15) ────────────────────────────
   Each approver is a small card in the region's row: name, email, what stops them acting, and
   Pause / Remove. One who cannot act is greyed so a region's real cover reads at a glance. */
.liq-approver {
    border: 1px solid var(--gk-soft-line, #e5e7eb);
    border-radius: 10px;
    padding: 0.45rem 0.65rem;
    min-width: 12rem;
    background: var(--bs-body-bg, #fff);
}
.liq-approver.is-off { background: var(--bs-tertiary-bg, #f6f7f9); }
.liq-approver.is-off .liq-approver-name { color: var(--bs-secondary-color, #6b7280); }
.liq-approver-name { font-weight: 600; font-size: 0.88rem; }
.liq-approver-email { font-size: 0.75rem; color: var(--bs-secondary-color, #6b7280); }
.liq-approver-warn { font-size: 0.75rem; color: var(--bs-warning-text-emphasis, #92400e); margin-top: 0.15rem; }
.liq-approver-actions { font-size: 0.78rem; margin-top: 0.25rem; }
.liq-approver-actions .btn-link { font-size: 0.78rem; text-decoration: none; }

/* Liquidation details, approver view: the "Show all details" toggle says what it will do. */
.top-sheet-toggle .when-open { display: none; }
.top-sheet-toggle[aria-expanded="true"] .when-open { display: inline; }
.top-sheet-toggle[aria-expanded="true"] .when-closed { display: none; }
.top-sheet-toggle .bi-chevron-down { display: inline-block; transition: transform .2s ease; }
.top-sheet-toggle[aria-expanded="true"] .bi-chevron-down { transform: rotate(180deg); }

/* A menu opened from a page header (2026-10-16, the CRM contact page's More). The header keeps an
   identity transform from its entrance animation, so it is its own stacking layer and the cards
   below painted over the open menu. Raised only while a menu in it is open - a header raised for
   good would trap a dialog opened from it under the backdrop. */
.page-hero:has(.dropdown-menu.show),
.detail-hero:has(.dropdown-menu.show) { position: relative; z-index: 1000; }

/* The region picker (2026-10-22, Views/Shared/_RegionPicker.cshtml) opens inside a filter card; every
   card is its own stacking layer (see .ss-panel.open in responsive.css), so the cards below painted
   over the open list. Raised only while it is open, for the same reason as above. */
.app-main .card:has(.region-pick .dropdown-menu.show),
.app-main .row:has(.region-pick .dropdown-menu.show),
.app-main .row > [class*="col-"]:has(.region-pick .dropdown-menu.show) { position: relative; z-index: 1300; }
.region-pick-menu { min-width: 100%; max-height: 20rem; overflow-y: auto; }
