/* ── The unit's colours ─────────────────────────────────────────────────────
   Item S01. Navy is the dominant colour: the top bar, the footer and the sign-in
   page. Defined once here so moving it later is an edit rather than a search --
   there are no other colour variables in these stylesheets and every other colour
   is written where it is used.

   NOT APPLIED TO TEXT. The same near-black (#1a2332) serves as ink in ten places,
   and tinting body text navy would make records harder to read for no gain; the
   unit asked for the grey and black of rows to stay as they are.

   Gold (#fcd032) and maroon (#500000) are deliberately absent until there is a
   decision about where they belong. Gold in particular cannot carry white text --
   it needs dark text on it -- so it is an accent, not a button colour.
   ────────────────────────────────────────────────────────────────────────── */
:root {
    --navy:      #252a61;   /* rgb(37, 42, 97) -- the unit's navy */
    --navy-deep: #1b1f49;   /* the far end of the sign-in gradient */

    /* The two accents. They appear in ONE place between them -- the strip that says
       this installation is a rehearsal -- which is what "sparingly" has to mean if it
       is to mean anything. Gold carries dark text only: maroon on gold measures
       10.6:1, while white on gold is 1.5:1 and unreadable. Both figures are Chrome's,
       taken by tests/Browser/accent_badges.js -- computed by hand they came out 11.5
       and 1.7, close enough to look right and wrong in the direction that flatters. */
    --gold:   #fcd032;      /* rgb(252, 208, 50) */
    --maroon: #500000;      /* rgb(80, 0, 0) */
}

/**
 * CaseMS — Main Application Stylesheet
 * Phase 0: Minimal styles for skeleton verification.
 * Bootstrap and full styling will be added in Phase 4.
 */

/* ============================================================
   Layout tunables
   Single place to adjust how wide the application is allowed to
   grow. --content-floor is the old fixed width and acts as a
   guarantee: no viewport ends up narrower than it was before.
   ============================================================ */
:root {
    --content-floor: 1400px;   /* never narrower than this */
    --content-cap:   1920px;   /* never wider — keeps line lengths readable */
    /* Height of the environment banner, when there is one. A FIXED height, because
       .topnav sticks below it at exactly this offset: if the banner grew when its
       text wrapped, the nav would slide under it on every scroll. The strip scrolls
       its own text instead, which no viewport makes happen at the lengths used. */
    --env-banner-h: 44px;
}

@media (max-width: 720px) {
    :root { --env-banner-h: 68px; }   /* room for the same sentence over three lines */
}

/* The browser hides [hidden] with display:none, but that is a user-agent rule and
   any class setting display beats it: .comment-form's `display: flex` kept the
   comment form on screen with hidden set, and .picker-* hit the same trap before.
   Stated once here so `el.hidden = true` means hidden everywhere. */
[hidden] { display: none !important; }

/* Reset & Base */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: 0.875rem;
    line-height: 1.6;
    color: #333;
    background-color: #f4f6f9;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* ============================================================
   Icons (inline SVG)
   ============================================================ */
.icon {
    display: inline-block;
    vertical-align: middle;
    flex-shrink: 0;
}

/* ============================================================
   Top Navigation
   ============================================================ */
.topnav {
    /* Flat navy read as too bright across 56px of full-width colour. It darkens
       downwards instead, which drops the average luminance about a fifth without
       moving either end off the unit's navy -- the two stops are the same pair the
       sign-in page already uses, so the bar and the sign-in page are now the same
       two colours rather than two guesses at one.

       background-color AS WELL, not instead: `background:` shorthand would have set
       the colour to transparent, and a bar whose gradient failed to paint would be
       white text on the page behind it. The solid is the dark end, so the fallback
       is the safe one. */
    background-color: var(--navy-deep);
    background-image: linear-gradient(180deg, var(--navy) 0%, var(--navy-deep) 100%);
    color: #fff;
    height: 56px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
    position: sticky;
    top: 0;
    z-index: 1000;
}

.topnav-inner {
    display: flex;
    align-items: center;
    height: 100%;
    padding: 0 16px;
    max-width: 100%;
}

.topnav-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    color: #fff;
    text-decoration: none;
    font-size: 1.125rem;
    white-space: nowrap;
    margin-right: 24px;
    flex-shrink: 0;
}

.topnav-brand:hover { opacity: 0.9; }

.topnav-logo {
    height: 32px;
    width: auto;
}

/* Hamburger (hidden on desktop) */
.topnav-hamburger {
    display: none;
    background: none;
    border: none;
    color: #fff;
    cursor: pointer;
    padding: 8px;
    margin-left: auto;
}

/* Collapsible section */
.topnav-collapse {
    display: flex;
    align-items: center;
    flex: 1;
    height: 100%;
}

/* Main nav links */
.topnav-links {
    display: flex;
    align-items: center;
    height: 100%;
    /* No gap: the items sit flush and the rule below divides them, so the space either
       side of a divider is each item's own padding and is therefore equal. A gap here
       would add itself to one side only and throw the divider off centre. */
    gap: 0;
}

/* A faint rule between the top-level items, in place of the icons that used to separate
   them. Drawn on the item rather than in a gap so it tracks the item's height, and
   absolutely positioned so it is not a flex child of the link and cannot shift the label.
   Not after the last item, which would leave a rule hanging at the end of the row. */
.topnav-links > *:not(:last-child)::after {
    content: "";
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 1px;
    height: 18px;
    background: rgba(255, 255, 255, 0.16);
    pointer-events: none;
}

.topnav-link {
    position: relative;   /* the task count is placed against this */
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0 18px;
    height: 100%;
    color: rgba(255, 255, 255, 0.75);
    text-decoration: none;
    font-size: 0.8125rem;
    font-weight: 500;
    white-space: nowrap;
    border: none;
    background: none;
    cursor: pointer;
    font-family: inherit;
    transition: color 0.15s, background-color 0.15s;
}

.topnav-link:hover {
    color: #fff;
    background: rgba(255, 255, 255, 0.08);
}

.topnav-link.active,
.topnav-dropdown.active > .topnav-dropdown-toggle {
    color: #fff;
    box-shadow: inset 0 -2px 0 #2563eb;
}

/* Dropdown container */
.topnav-dropdown {
    position: relative;
    height: 100%;
    display: flex;
    align-items: center;
}

.topnav-dropdown-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
}

.icon-chevron {
    margin-left: 2px;
    transition: transform 0.2s;
}

.topnav-dropdown.open .icon-chevron {
    transform: rotate(180deg);
}

/* Dropdown menu */
.topnav-dropdown-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    background: #fff;
    border-radius: 6px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
    min-width: 200px;
    padding: 6px 0;
    z-index: 1010;
}

.topnav-dropdown.open > .topnav-dropdown-menu {
    display: block;
}

.topnav-dropdown-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    color: #374151;
    text-decoration: none;
    font-size: 0.8125rem;
    transition: background-color 0.1s;
    white-space: nowrap;
    border: none;
    background: none;
    width: 100%;
    cursor: pointer;
    font-family: inherit;
    text-align: left;
}

.topnav-dropdown-item:hover {
    background: #f3f4f6;
    color: #1a2332;
}

.topnav-dropdown-item.active {
    color: #2563eb;
    font-weight: 600;
}

.topnav-dropdown-divider {
    height: 1px;
    background: #e5e7eb;
    margin: 4px 0;
}

/* Right section */
.topnav-right {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
    height: 100%;
}

/* Notification bell */
.topnav-icon-btn {
    position: relative;
    background: none;
    border: none;
    color: rgba(255, 255, 255, 0.75);
    cursor: pointer;
    padding: 8px;
    border-radius: 4px;
    transition: color 0.15s;
}

.topnav-icon-btn:hover { color: #fff; }

.topnav-badge {
    position: absolute;
    top: 2px;
    right: 2px;
    background: #ef4444;
    color: #fff;
    font-size: 0.625rem;
    font-weight: 700;
    min-width: 16px;
    height: 16px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 4px;
}

.topnav-badge:empty,
.topnav-badge[data-count="0"] {
    display: none;
}

/* User dropdown */
.topnav-user-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    background: none;
    border: none;
    color: rgba(255, 255, 255, 0.85);
    cursor: pointer;
    padding: 6px 10px;
    border-radius: 4px;
    font-family: inherit;
    transition: background-color 0.15s;
}

.topnav-user-toggle:hover {
    background: rgba(255, 255, 255, 0.08);
}

.topnav-avatar {
    width: 32px;
    height: 32px;
    background: #2563eb;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.875rem;
    font-weight: 700;
    color: #fff;
    flex-shrink: 0;
}

.topnav-user-info {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.2;
}

.topnav-username {
    font-size: 0.8125rem;
    font-weight: 600;
}

.topnav-role {
    font-size: 0.6875rem;
    opacity: 0.6;
}

.topnav-user-menu {
    right: 0;
    left: auto;
}

.topnav-logout-form {
    display: contents;
}

.topnav-logout-btn {
    color: #dc2626;
}

.topnav-logout-btn:hover {
    background: #fef2f2;
    color: #dc2626;
}

/* ============================================================
   Page Body (sidebar + content)
   ============================================================ */
.page-body {
    display: flex;
    flex: 1;
    min-height: calc(100vh - 56px - 40px);
}

/* ============================================================
   Sidebar (case context only)
   ============================================================ */
.sidebar {
    width: 220px;
    background: #fff;
    border-right: 1px solid #e5e7eb;
    flex-shrink: 0;
    overflow-y: auto;
}

.sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 16px;
    border-bottom: 1px solid #e5e7eb;
    font-size: 0.875rem;
    font-weight: 700;
    color: #1a2332;
}

/* Folding the case menu away gives the wider pages — the workplan sheet above all —
   the room they need. The choice is remembered per browser. */
.sidebar-toggle {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid #e5e7eb;
    border-radius: 5px;
    background: #fff;
    color: #6b7280;
    cursor: pointer;
}

.sidebar-toggle:hover { border-color: #93c5fd; color: #2563eb; background: #f8fafc; }

body.sidebar-collapsed .sidebar {
    width: 46px;
    /* The tooltips sit outside the rail, and overflow-y:auto clips the other axis
       with it. The folded menu is a dozen icons, so it has nothing to scroll. */
    overflow: visible;
}
body.sidebar-collapsed .sidebar-case-id { display: none; }
body.sidebar-collapsed .sidebar-header { justify-content: center; padding: 12px 0; }
body.sidebar-collapsed .sidebar-link { justify-content: center; padding: 10px 0; position: relative; }
body.sidebar-collapsed .sidebar-link.active { border-right-width: 2px; }

/* Folded, an icon says little on its own. The label it already carries becomes a
   tooltip on hover or keyboard focus, rather than being thrown away — so the menu
   can still be read without unfolding it. */
body.sidebar-collapsed .sidebar-link span {
    position: absolute;
    left: calc(100% + 10px);
    top: 50%;
    z-index: 70;
    padding: 5px 9px;
    border-radius: 6px;
    background: #111827;
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.3;
    white-space: nowrap;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-50%) translateX(-4px);
    transition: opacity 0.12s ease, transform 0.12s ease, visibility 0s linear 0.12s;
}

/* The little nib pointing back at the icon */
body.sidebar-collapsed .sidebar-link span::before {
    content: '';
    position: absolute;
    top: 50%;
    left: -4px;
    width: 8px;
    height: 8px;
    background: inherit;
    transform: translateY(-50%) rotate(45deg);
    border-radius: 1px;
}

body.sidebar-collapsed .sidebar-link:hover span,
body.sidebar-collapsed .sidebar-link:focus-visible span {
    opacity: 1;
    visibility: visible;
    transform: translateY(-50%) translateX(0);
    transition: opacity 0.12s ease, transform 0.12s ease;
}

/* The fold button says what it will do, in blue — it acts on the menu itself
   rather than going anywhere, so it is deliberately not the same dark chip. */
.sidebar-toggle { position: relative; }
.sidebar-tip {
    position: absolute;
    z-index: 70;
    padding: 5px 9px;
    border-radius: 6px;
    background: #1d4ed8;
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.3;
    white-space: nowrap;
    box-shadow: 0 4px 14px rgba(29, 78, 216, 0.28);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.12s ease, transform 0.12s ease, visibility 0s linear 0.12s;
}
.sidebar-tip::before {
    content: '';
    position: absolute;
    width: 8px;
    height: 8px;
    background: inherit;
    border-radius: 1px;
}

/* Unfolded there is no room to the right of the button, so it drops below */
.sidebar-tip-expand { display: none; }
.sidebar-tip-collapse {
    top: calc(100% + 8px);
    right: 0;
    transform: translateY(-4px);
}
.sidebar-tip-collapse::before {
    top: -3px;
    right: 10px;
    transform: rotate(45deg);
}

/* Folded, it sits out on the rail beside the icon like the others */
body.sidebar-collapsed .sidebar-tip-collapse { display: none; }
body.sidebar-collapsed .sidebar-tip-expand {
    display: block;
    left: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%) translateX(-4px);
}
body.sidebar-collapsed .sidebar-tip-expand::before {
    top: 50%;
    left: -4px;
    transform: translateY(-50%) rotate(45deg);
}

.sidebar-toggle:hover .sidebar-tip-collapse,
.sidebar-toggle:focus-visible .sidebar-tip-collapse {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity 0.12s ease, transform 0.12s ease;
}
body.sidebar-collapsed .sidebar-toggle:hover .sidebar-tip-expand,
body.sidebar-collapsed .sidebar-toggle:focus-visible .sidebar-tip-expand {
    opacity: 1;
    visibility: visible;
    transform: translateY(-50%) translateX(0);
    transition: opacity 0.12s ease, transform 0.12s ease;
}

/* Someone who asked not to be animated gets the tooltip without the movement */
@media (prefers-reduced-motion: reduce) {
    body.sidebar-collapsed .sidebar-link span,
    body.sidebar-collapsed .sidebar-link:hover span,
    body.sidebar-collapsed .sidebar-link:focus-visible span,
    body.sidebar-collapsed .sidebar-tip-expand,
    body.sidebar-collapsed .sidebar-toggle:hover .sidebar-tip-expand {
        transition: none;
        transform: translateY(-50%);
    }
    .sidebar-tip-collapse,
    .sidebar-toggle:hover .sidebar-tip-collapse {
        transition: none;
        transform: none;
    }
}

.sidebar-nav {
    padding: 8px 0;
}

.sidebar-link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    color: #4b5563;
    text-decoration: none;
    font-size: 0.8125rem;
    transition: background-color 0.1s, color 0.1s;
}

.sidebar-link:hover {
    background: #f3f4f6;
    color: #1a2332;
}

.sidebar-link.active {
    color: #2563eb;
    background: #eff6ff;
    font-weight: 600;
    border-right: 3px solid #2563eb;
}

/* ============================================================
   Main Content
   ============================================================ */
/* Fluid content shell.
 *
 * clamp(MIN, PREFERRED, MAX) resolves as max(MIN, min(PREFERRED, MAX)), so:
 *   400px viewport  -> 1400px cap, never reached (width:100% wins)  = unchanged
 *   1400px viewport -> 1400px                                        = unchanged
 *   1920px viewport -> 1766px  (was 1400, ~366px of dead space reclaimed)
 *   2560px viewport -> 1920px  (capped, so text lines stay readable)
 *
 * The floor is deliberately the old fixed value: no screen size gets a
 * narrower layout than it had before this change.
 *
 * margin-inline: auto matters because .page-body is a flex row and this is its
 * only child — without it the content sat hard against the left edge once the
 * cap kicked in, with all the leftover space on the right.
 */
.main-content {
    flex: 1;
    width: 100%;
    max-width: clamp(var(--content-floor, 1400px), 92vw, var(--content-cap, 1920px));
    margin-inline: auto;
    /* Gutters grow with the viewport instead of staying at a fixed 24px. */
    padding: clamp(16px, 1.6vw, 32px);
}

/* ============================================================
   Footer
   ============================================================ */
.main-footer {
    /* The same surface as the top bar, so the two read as one frame around the page
       rather than two different navies. Left flat at the bar's lighter stop it would
       have become the brightest piece of chrome on screen, which is the complaint the
       gradient was added to answer. */
    background-color: var(--navy-deep);
    background-image: linear-gradient(180deg, var(--navy) 0%, var(--navy-deep) 100%);
    color: rgba(255, 255, 255, 0.6);
    text-align: center;
    padding: 12px 20px;
    font-size: 0.75rem;
}

/* ============================================================
   Mobile Responsive
   ============================================================ */
@media (max-width: 768px) {
    .topnav-hamburger {
        display: block;
    }

    .topnav-collapse {
        display: none;
        position: absolute;
        top: 56px;
        left: 0;
        right: 0;
        /* The dark END of the bar's gradient, not its top: this panel hangs directly
           beneath the bar, and starting it at the lighter navy would draw a seam
           across the join at exactly the point the two meet. */
        background: var(--navy-deep);
        flex-direction: column;
        align-items: stretch;
        height: auto;
        padding: 8px 0;
        box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
        z-index: 1001;
    }

    .topnav-collapse.show {
        display: flex;
    }

    .topnav-links {
        flex-direction: column;
        height: auto;
    }

    /* Stacked, the items are one above another, so a rule down the right-hand edge
       divides nothing. The stacking itself separates them. */
    .topnav-links > *:not(:last-child)::after {
        display: none;
    }

    .topnav-link {
        height: auto;
        padding: 12px 16px;
    }

    .topnav-dropdown {
        height: auto;
        flex-direction: column;
    }

    .topnav-dropdown-menu {
        position: static;
        box-shadow: none;
        background: rgba(255, 255, 255, 0.05);
        border-radius: 0;
        padding: 0;
    }

    .topnav-dropdown.open > .topnav-dropdown-menu {
        display: block;
    }

    .topnav-dropdown-item {
        color: rgba(255, 255, 255, 0.75);
        padding: 10px 16px 10px 32px;
    }

    .topnav-dropdown-item:hover {
        background: rgba(255, 255, 255, 0.08);
        color: #fff;
    }

    .topnav-dropdown-item.active {
        color: #60a5fa;
    }

    .topnav-right {
        padding: 8px 16px;
        border-top: 1px solid rgba(255, 255, 255, 0.1);
        margin-left: 0;
        height: auto;
    }

    .topnav-user-menu {
        position: static;
        background: rgba(255, 255, 255, 0.05);
        box-shadow: none;
        border-radius: 0;
    }

    .topnav-user-menu .topnav-dropdown-item {
        color: rgba(255, 255, 255, 0.75);
        padding-left: 16px;
    }

    .topnav-user-menu .topnav-dropdown-divider {
        background: rgba(255, 255, 255, 0.1);
    }

    .topnav-user-menu .topnav-logout-btn {
        color: #fca5a5;
    }

    .sidebar {
        display: none;
    }

    .main-content {
        padding: 16px;
    }
}

/* Dashboard */
.dashboard h1 {
    margin-bottom: 8px;
    color: #1a2332;
}

.dashboard > p {
    color: #666;
    margin-bottom: 24px;
}

.dashboard-info {
    background: #fff;
    padding: 20px;
    border-radius: 6px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.dashboard-info h2 {
    font-size: 1rem;
    margin-bottom: 12px;
    color: #1a2332;
}

.dashboard-info ul {
    list-style: none;
    padding: 0;
}

.dashboard-info li {
    padding: 6px 0;
    border-bottom: 1px solid #eee;
}

.dashboard-info li:last-child {
    border-bottom: none;
}

/* Error Pages */
.error-page {
    max-width: 600px;
    margin: 80px auto;
    background: #fff;
    padding: 40px;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.error-page h1 {
    color: #c0392b;
    margin-bottom: 12px;
}

/* The icon sits with the heading, sized to it and not pinned to the baseline, so the two
   read as one line rather than as a picture next to some words. */
.error-page-heading {
    display: flex;
    align-items: center;
    gap: 12px;
}
.error-page-heading .icon {
    flex: 0 0 auto;
    stroke-width: 2.25;
}

.error-page p {
    color: #666;
    margin-bottom: 20px;
}

.error-page .error-page-note {
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-left: 3px solid #f59e0b;
    border-radius: 4px;
    padding: 12px 14px;
    color: #92400e;
    font-size: 0.875rem;
    line-height: 1.5;
}

.error-page a {
    color: #2980b9;
    text-decoration: none;
}

.error-page a:hover {
    text-decoration: underline;
}

/* ============================================================
   Auth Pages — Login, TOTP Setup, TOTP Verify
   ============================================================ */

/* Auth body replaces the default flex-column layout */
.auth-body {
    background: linear-gradient(135deg, var(--navy) 0%, var(--navy-deep) 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 20px;
}

/* Centered container */
.auth-container {
    width: 100%;
    max-width: 420px;
}

/* Logo block above card */
.auth-logo-block {
    text-align: center;
    margin-bottom: 24px;
    color: #fff;
}

.auth-logo-img {
    max-height: 80px;
    width: auto;
    margin-bottom: 12px;
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.3));
}

.auth-logo-title {
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: 2px;
}

.auth-logo-subtitle {
    font-size: 0.75rem;
    opacity: 0.6;
    margin-top: 4px;
    letter-spacing: 1px;
}

/* Card */
.auth-card {
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.25);
    padding: 32px;
}

/* Title & description inside card */
.auth-title {
    font-size: 1.25rem;
    font-weight: 600;
    color: #1a2332;
    margin-bottom: 4px;
}

.auth-description {
    font-size: 0.8125rem;
    color: #666;
    margin-bottom: 24px;
    line-height: 1.5;
}

/* Alert messages */
.auth-alert {
    padding: 10px 14px;
    border-radius: 4px;
    margin-bottom: 20px;
    font-size: 0.8125rem;
    line-height: 1.5;
}

.auth-alert-error {
    background: #fef2f2;
    color: #991b1b;
    border: 1px solid #fecaca;
}

.auth-alert-success {
    background: #f0fdf4;
    color: #166534;
    border: 1px solid #bbf7d0;
}

.auth-alert-warning {
    background: #fffbeb;
    color: #92400e;
    border: 1px solid #fde68a;
}

/* Form elements */
.auth-form .form-group {
    margin-bottom: 18px;
}

.auth-form label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #374151;
    margin-bottom: 6px;
}

.auth-form input[type="text"],
.auth-form input[type="password"],
.auth-form input[type="email"] {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid #d1d5db;
    border-radius: 4px;
    font-size: 0.875rem;
    font-family: inherit;
    color: #1f2937;
    background: #fff;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.auth-form input:focus {
    outline: none;
    border-color: #2563eb;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

.auth-form input::placeholder {
    color: #9ca3af;
}

/* TOTP code input — large centered digits */
.totp-input {
    text-align: center;
    font-size: 1.75rem !important;
    font-weight: 600;
    letter-spacing: 8px;
    padding: 14px 12px !important;
    font-family: "SF Mono", "Consolas", "Monaco", monospace;
}

/* Buttons */
.btn {
    display: inline-block;
    padding: 10px 20px;
    font-size: 0.875rem;
    font-weight: 600;
    font-family: inherit;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    text-decoration: none;
    text-align: center;
    transition: background-color 0.15s, box-shadow 0.15s;
}

/* A button that cannot be pressed should not look pressable.
   There was no disabled styling at all: `disabled` stopped the click and changed
   nothing on the page, so an officer pressed Edit mode on an empty plan, saw a button
   that looked exactly like every working button, and concluded the page was broken.
   !important, not ordering: .btn-primary, .btn-outline and the rest each set their own
   background and colour, and a disabled button has to beat whichever one it is wearing
   wherever that rule happens to sit in this file. */
.btn:disabled,
.btn[disabled],
.btn.is-disabled {
    background: #f3f4f6 !important;
    border-color: #e5e7eb !important;
    color: #9ca3af !important;
    cursor: not-allowed;
    box-shadow: none !important;
    /* The icon inside goes with it, or a grey button keeps a confident blue glyph. */
    opacity: 1;
}

.btn:disabled svg,
.btn[disabled] svg,
.btn.is-disabled svg {
    opacity: 0.55;
}

.btn:disabled:hover,
.btn[disabled]:hover,
.btn.is-disabled:hover {
    background: #f3f4f6 !important;
    color: #9ca3af !important;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .btn:disabled,
    :root:not([data-theme="light"]) .btn[disabled] {
        background: #1f2937 !important;
        border-color: #374151 !important;
        color: #6b7280 !important;
    }
}

:root[data-theme="dark"] .btn:disabled,
:root[data-theme="dark"] .btn[disabled] {
    background: #1f2937 !important;
    border-color: #374151 !important;
    color: #6b7280 !important;
}

.btn-primary {
    background: #2563eb;
    color: #fff;
}

.btn-primary:hover {
    background: #1d4ed8;
}

.btn-primary:active {
    background: #1e40af;
}

.btn-block {
    display: block;
    width: 100%;
}

.btn-link {
    background: none;
    border: none;
    color: #2563eb;
    font-size: 0.8125rem;
    cursor: pointer;
    text-decoration: none;
    font-family: inherit;
    padding: 0;
}

.btn-link:hover {
    text-decoration: underline;
    color: #1d4ed8;
}

/* Alternative action links below the card */
.auth-alt-action {
    text-align: center;
    margin-top: 16px;
    font-size: 0.8125rem;
}

.auth-alt-action a {
    color: #2563eb;
    text-decoration: none;
}

.auth-alt-action a:hover {
    text-decoration: underline;
}

/* Footer below auth card */
.auth-footer {
    text-align: center;
    margin-top: 32px;
    font-size: 0.6875rem;
    color: rgba(255, 255, 255, 0.4);
}

/* ---- TOTP Setup Page ---- */

/* QR code container */
.totp-qr-container {
    text-align: center;
    padding: 16px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    margin-bottom: 12px;
}

.totp-qr-container svg {
    max-width: 220px;
    height: auto;
}

/* Manual entry toggle */
.totp-manual-toggle {
    margin-bottom: 8px;
    font-size: 0.8125rem;
}

.totp-manual-toggle summary {
    color: #2563eb;
    cursor: pointer;
    padding: 6px 0;
}

.totp-manual-toggle summary:hover {
    text-decoration: underline;
}

.totp-manual-entry {
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 4px;
    padding: 12px;
    margin-top: 8px;
    font-size: 0.8125rem;
}

.totp-manual-entry p {
    margin-bottom: 6px;
    color: #374151;
}

.totp-secret {
    display: block;
    font-family: "SF Mono", "Consolas", "Monaco", monospace;
    font-size: 0.875rem;
    font-weight: 600;
    color: #1f2937;
    letter-spacing: 2px;
    word-break: break-all;
    background: #f3f4f6;
    padding: 10px;
    border-radius: 4px;
    text-align: center;
    margin-top: 4px;
}

/* Recovery codes grid */
.recovery-codes-section {
    margin-bottom: 24px;
}

.recovery-codes-section h3 {
    font-size: 0.875rem;
    font-weight: 600;
    color: #374151;
    margin-bottom: 8px;
}

.recovery-codes-section p {
    font-size: 0.75rem;
    color: #6b7280;
    margin-bottom: 12px;
    line-height: 1.5;
}

.recovery-codes-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 6px;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 4px;
    padding: 12px;
}

.recovery-code {
    font-family: "SF Mono", "Consolas", "Monaco", monospace;
    font-size: 0.875rem;
    font-weight: 600;
    color: #1f2937;
    text-align: center;
    padding: 4px;
    letter-spacing: 1px;
}

.recovery-codes-warning {
    font-size: 0.6875rem;
    color: #92400e;
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-radius: 4px;
    padding: 8px 12px;
    margin-top: 10px;
    line-height: 1.5;
}

/* Inline separator */
.auth-separator {
    display: flex;
    align-items: center;
    margin: 24px 0;
    color: #9ca3af;
    font-size: 0.75rem;
}

.auth-separator::before,
.auth-separator::after {
    content: '';
    flex: 1;
    height: 1px;
    background: #e5e7eb;
}

.auth-separator::before {
    margin-right: 12px;
}

.auth-separator::after {
    margin-left: 12px;
}

/* Setup steps list */
.setup-steps {
    margin-bottom: 20px;
    padding-left: 0;
    counter-reset: step;
    list-style: none;
}

.setup-steps li {
    position: relative;
    padding: 6px 0 6px 32px;
    font-size: 0.8125rem;
    color: #374151;
    line-height: 1.5;
    counter-increment: step;
}

.setup-steps li::before {
    content: counter(step);
    position: absolute;
    left: 0;
    top: 6px;
    width: 22px;
    height: 22px;
    background: #2563eb;
    color: #fff;
    border-radius: 50%;
    font-size: 0.75rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ============================================================
   Admin Pages — Shared Components
   ============================================================ */

/* Page toolbar (title + actions row) */
.page-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 24px;
    flex-wrap: wrap;
    gap: 12px;
}

.page-toolbar h1 {
    font-size: 1.375rem;
    font-weight: 700;
    color: #1a2332;
    margin: 0;
}

.page-toolbar-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Breadcrumb */
.breadcrumb {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8125rem;
    color: #6b7280;
    margin-bottom: 8px;
}

.breadcrumb a {
    color: #2563eb;
    text-decoration: none;
}

.breadcrumb a:hover { text-decoration: underline; }

.breadcrumb-separator { color: #9ca3af; }

/* ---- Alerts (flash messages — toast style) ---- */
.alert-toast-container {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 9999;
    max-width: 420px;
    width: calc(100% - 40px);
}

.alert {
    padding: 14px 44px 14px 48px;
    border-radius: 8px;
    font-size: 0.875rem;
    line-height: 1.5;
    border: 1px solid transparent;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.1);
    position: relative;
    animation: alertSlideIn 0.35s ease-out;
    cursor: pointer;
    transition: opacity 0.3s ease, transform 0.3s ease;
}

.alert::before {
    position: absolute;
    left: 16px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 1.125rem;
}

/* Whether the inquiry number typed is free. Three answers and three colours, because
   "checking" and "taken" must not look the same at a glance. */
.number-check.is-asking { color: #6b7280; }
.number-check.is-good   { color: #15803d; }
.number-check.is-bad    { color: #b45309; }

/* A notice that is part of the page, as opposed to a flash message.
   
   .alert is the flash component: it slides in, carries an absolutely positioned icon in
   padding reserved for it, and is cursor:pointer because a flash is dismissible. Pages
   borrowed it for standing notices and then overrode the padding to suit their layout,
   which took away the space the icon sits in -- so the warning glyph landed on top of
   the second line of text. They also animated on every page load and invited a click
   that does nothing.
   
   This is the same look with none of the behaviour: the icon is in the flow, so no
   padding can collide with it. */
.form-notice {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 12px 16px;
    margin-bottom: 16px;
    border-radius: 6px;
    border: 1px solid #f0c060;
    border-left: 4px solid #f59e0b;
    background: #fffbeb;
    color: #92400e;
    font-size: 0.875rem;
    line-height: 1.5;
}

.form-notice-icon {
    flex: 0 0 auto;
    line-height: 1.5;
}

.form-notice p {
    margin: 0;
}

.alert-dismiss {
    position: absolute;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    font-size: 1.125rem;
    cursor: pointer;
    opacity: 0.6;
    line-height: 1;
    padding: 4px;
    color: inherit;
}

.alert-dismiss:hover {
    opacity: 1;
}

.alert.alert-hiding {
    opacity: 0;
    transform: translateX(30px);
}

/* Progress bar for auto-dismiss */
.alert-progress {
    position: absolute;
    bottom: 0;
    left: 0;
    height: 3px;
    border-radius: 0 0 8px 8px;
    animation: alertProgress 5s linear forwards;
}

.alert-success {
    background: #f0fdf4;
    color: #166534;
    border-color: #22c55e;
    border-left: 4px solid #22c55e;
}

.alert-success::before { content: "\2713"; color: #22c55e; }
.alert-success .alert-progress { background: #22c55e; }

.alert-error {
    background: #fef2f2;
    color: #991b1b;
    border-color: #ef4444;
    border-left: 4px solid #ef4444;
}

.alert-error::before { content: "\2716"; color: #ef4444; }
.alert-error .alert-progress { background: #ef4444; }

.alert-warning {
    background: #fffbeb;
    color: #92400e;
    border-color: #f59e0b;
    border-left: 4px solid #f59e0b;
}

.alert-warning::before { content: "\26A0"; color: #f59e0b; }
.alert-warning .alert-progress { background: #f59e0b; }

.alert-info {
    background: #eff6ff;
    color: #1e40af;
    border-color: #3b82f6;
    border-left: 4px solid #3b82f6;
}

.alert-info::before { content: "\2139"; color: #3b82f6; }
.alert-info .alert-progress { background: #3b82f6; }

@keyframes alertSlideIn {
    from { opacity: 0; transform: translateX(40px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes alertProgress {
    from { width: 100%; }
    to   { width: 0%; }
}

/* ---- Modals ---- */
.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 9000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 60px 16px 16px;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s ease, visibility 0.25s ease;
    overflow-y: auto;
}

.modal-backdrop.modal-open {
    opacity: 1;
    visibility: visible;
}

.modal-dialog {
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
    width: 100%;
    max-width: 600px;
    transform: translateY(-20px) scale(0.97);
    transition: transform 0.25s ease;
}

.modal-backdrop.modal-open .modal-dialog {
    transform: translateY(0) scale(1);
}

.modal-dialog-lg { max-width: 780px; }

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid #e5e7eb;
    font-weight: 600;
    font-size: 0.9375rem;
}

.modal-close {
    background: none;
    border: none;
    font-size: 1.375rem;
    cursor: pointer;
    color: #6b7280;
    padding: 0 4px;
    line-height: 1;
    transition: color 0.15s;
}

.modal-close:hover { color: #111827; }

.modal-body {
    padding: 20px;
    max-height: calc(100vh - 200px);
    overflow-y: auto;
}

/* Success modal (flash) */
.modal-success-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto 16px;
    font-size: 1.75rem;
}

.modal-success-icon.icon-success { background: #dcfce7; color: #16a34a; }
.modal-success-icon.icon-error   { background: #fee2e2; color: #dc2626; }
.modal-success-icon.icon-warning { background: #fef3c7; color: #d97706; }
.modal-success-icon.icon-info    { background: #dbeafe; color: #2563eb; }

.modal-flash-message {
    text-align: center;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: #374151;
    margin-bottom: 20px;
}

.modal-flash-actions {
    text-align: center;
    padding-bottom: 4px;
}

/* ---- Cards ---- */
.card {
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    margin-bottom: 20px;
    border: 1px solid #e5e7eb;
}

.card-header {
    padding: 14px 20px;
    border-bottom: 1px solid #e5e7eb;
    font-size: 0.9375rem;
    font-weight: 600;
    color: #1a2332;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.card-body {
    padding: 20px;
}

.card-body:empty { display: none; }

/* ---- Badges ---- */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1.6;
    white-space: nowrap;
}

.badge-success { background: #dcfce7; color: #166534; }
.badge-warning { background: #fef3c7; color: #92400e; }
.badge-danger  { background: #fee2e2; color: #991b1b; }
.badge-info    { background: #dbeafe; color: #1e40af; }
.badge-muted   { background: #f3f4f6; color: #6b7280; }

/* ---- Progress Bars ---- */
.progress-bar-container {
    height: 6px;
    background: #e5e7eb;
    border-radius: 3px;
    overflow: hidden;
    margin-bottom: 2px;
}
.progress-bar-fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.3s ease;
}

/* ---- Data Tables ---- */
.table-responsive {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.8125rem;
}

.data-table th,
.data-table td {
    padding: 10px 14px;
    text-align: left;
    border-bottom: 1px solid #e5e7eb;
    vertical-align: middle;
}

.data-table th {
    background: #f9fafb;
    font-weight: 600;
    color: #374151;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    white-space: nowrap;
}

.data-table tbody tr:hover {
    background: #f9fafb;
}

.data-table td.actions {
    white-space: nowrap;
}

.data-table .text-muted {
    color: #9ca3af;
}

.data-table .text-mono {
    font-family: "SF Mono", "Consolas", "Monaco", monospace;
    font-size: 0.75rem;
}

.empty-state {
    text-align: center;
    padding: 40px 20px;
    color: #9ca3af;
    font-size: 0.875rem;
}

/* ---- Additional Button Styles ---- */
.btn-secondary {
    background: #6b7280;
    color: #fff;
}

.btn-secondary:hover { background: #4b5563; }

.btn-danger {
    background: #dc2626;
    color: #fff;
}

.btn-danger:hover { background: #b91c1c; }

.btn-outline {
    background: #fff;
    color: #374151;
    border: 1px solid #d1d5db;
}

.btn-outline:hover {
    background: #f9fafb;
    border-color: #9ca3af;
}

.btn-sm {
    padding: 5px 12px;
    font-size: 0.75rem;
}

.btn-icon {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.btn + .btn { margin-left: 6px; }

/* ---- Forms ---- */
.form-grid-2col {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 16px 24px;
}

.form-grid-2col .form-group-full {
    grid-column: 1 / -1;
}

/* Three across, for short answers that would waste a row each: the details
   captured about one document, for instance. */
.form-grid-3col {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px 18px;
}

.form-grid-3col .form-group-full {
    grid-column: 1 / -1;
}

.form-group {
    margin-bottom: 16px;
}

.form-label {
    display: block;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #374151;
    margin-bottom: 6px;
}

/* A register field should look like itself whether it is being read or changed.
   The entry page sets its labels in small caps (.field-grid dt) so that a label
   reads as a heading over its value rather than as content; the edit form said the
   same words in a different voice, which is the second half of the complaint that
   the two pages did not match. The values here are identical to that rule on
   purpose -- if one is changed, change both.

   Marked on the cards holding register FIELDS, not on the whole form. The person
   component inside the same form labels its controls in sentences -- "Step 1 - is
   this person already on file?" - and a sentence set in caps shouts. */
.register-fields .form-label {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #6b7280;
}

.form-input,
.form-select,
.form-textarea {
    width: 100%;
    padding: 8px 12px;
    border: 1px solid #d1d5db;
    border-radius: 4px;
    font-size: 0.875rem;
    font-family: inherit;
    color: #1f2937;
    background: #fff;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
    outline: none;
    border-color: #2563eb;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

.form-input.is-invalid,
.form-select.is-invalid,
.form-textarea.is-invalid {
    border-color: #dc2626;
}

/* A box nobody can type in should not look like one that is waiting to be typed in.
   White on a white card reads as an empty editable field, so an officer tries the
   inquiry number on the edit form, finds it refuses the keystroke, and concludes the
   page is broken rather than that the field is governed elsewhere.

   -webkit-text-fill-color because WebKit washes a disabled box's text out to its own
   grey and ignores `color`, which on top of this background is barely legible. */
.form-input:disabled,
.form-select:disabled,
.form-textarea:disabled,
.form-input[readonly],
.form-textarea[readonly] {
    background: #f3f4f6;
    border-color: #e5e7eb;
    color: #6b7280;
    -webkit-text-fill-color: #6b7280;
    opacity: 1;
}

/* Only on :disabled. A readonly box can still be selected and copied from, which is
   usually the point of showing it, and not-allowed says otherwise. */
.form-input:disabled,
.form-select:disabled,
.form-textarea:disabled {
    cursor: not-allowed;
}

.form-textarea {
    resize: vertical;
    min-height: 80px;
}

.form-help {
    display: block;
    font-size: 0.75rem;
    color: #6b7280;
    margin-top: 4px;
}

/* ── New Case form ─────────────────────────────────────────── */
.new-case-section {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid #e5e7eb;
}

.new-case-section-title {
    font-size: 0.875rem;
    margin: 0 0 12px;
    color: #374151;
}

.deadline-preview {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 2.25rem;
    padding: 8px 12px;
    border: 1px dashed #d1d5db;
    border-radius: 4px;
    background: #f9fafb;
    font-size: 0.875rem;
    color: #6b7280;
}

.deadline-preview.is-set {
    border-style: solid;
    border-color: #bfdbfe;
    background: #eff6ff;
    color: #1e3a8a;
    font-weight: 600;
}

.deadline-preview svg {
    flex-shrink: 0;
}

.case-info-minute {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Pickers (typology methods, predicate offences): shown when ticked, with a quick search */
.picker-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 12px;
    margin-bottom: 10px;
}

.picker-search {
    position: relative;
    flex: 1 1 16rem;
    max-width: 24rem;
}

.picker-search svg {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    color: #9ca3af;
    pointer-events: none;
}

.picker-search .form-input {
    padding-left: 32px;
}

.picker-count {
    font-size: 0.75rem;
    color: #6b7280;
}

.picker-group {
    margin-bottom: 12px;
}

.picker-group-title {
    display: block;
    margin-bottom: 6px;
    font-size: 0.75rem;
    font-weight: 600;
    color: #6b7280;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
    gap: 6px 16px;
}

.picker-option {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    font-size: 0.8125rem;
    font-weight: normal;
    cursor: pointer;
}

.picker-option input {
    margin-top: 2px;
}

.picker-empty {
    padding: 10px 12px;
    border: 1px dashed #d1d5db;
    border-radius: 4px;
    background: #f9fafb;
    font-size: 0.8125rem;
    color: #6b7280;
}

.picker-toolbar[hidden],
.picker-group[hidden],
.picker-option[hidden],
.picker-empty[hidden],
.picker[hidden] {
    display: none;
}

.workflow-preview-recipient {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-bottom: 6px;
    font-size: 0.75rem;
    color: #334155;
}

.workflow-preview-recipient svg {
    flex-shrink: 0;
    color: #3b82f6;
}

.workflow-preview-recipient .workflow-preview-label {
    margin-right: 4px;
    color: #64748b;
}

/* Attachments: one row of classification fields per file */
.attachment-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 12px;
}

.attachment-list:empty {
    display: none;
}

.attachment-row {
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 12px 14px;
    background: #fff;
}

.attachment-row.is-invalid {
    border-color: #fca5a5;
    background: #fef2f2;
}

.attachment-row-head {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
}

.attachment-row-head svg {
    flex-shrink: 0;
    color: #2563eb;
}

.attachment-row-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #1f2937;
}

.attachment-row-size {
    font-size: 0.75rem;
    color: #6b7280;
    white-space: nowrap;
}

.attachment-row-remove {
    border: none;
    background: none;
    padding: 0 4px;
    font-size: 1.25rem;
    line-height: 1;
    color: #9ca3af;
    cursor: pointer;
}

.attachment-row-remove:hover {
    color: #dc2626;
}

.attachment-row-fields {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px 12px;
}

.attachment-row-fields .form-group {
    margin-bottom: 0;
}

.attachment-row-desc {
    grid-column: 1 / -1;
}

.attachment-row-error {
    margin-top: 8px;
    font-size: 0.75rem;
    color: #b91c1c;
}

.attachment-summary {
    margin-top: 8px;
    font-size: 0.75rem;
    color: #6b7280;
}

.attachment-summary.is-over {
    color: #b91c1c;
    font-weight: 600;
}

@media (max-width: 900px) {
    .attachment-row-fields {
        grid-template-columns: minmax(0, 1fr);
    }
}

.workflow-preview {
    margin-top: 10px;
    padding: 10px 14px;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    border-left: 3px solid #3b82f6;
    border-radius: 6px;
    font-size: 0.75rem;
    color: #334155;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}

.workflow-preview-header {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-bottom: 4px;
    color: #64748b;
}

.workflow-preview-header svg {
    color: #3b82f6;
}

.workflow-preview-label {
    font-weight: 600;
    font-size: 0.625rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.workflow-preview-step {
    font-weight: 600;
    font-size: 0.8125rem;
    color: #1e293b;
    margin-bottom: 6px;
}

.workflow-preview-tags {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.workflow-preview-tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    background: #f1f5f9;
    border: 1px solid #e2e8f0;
    border-radius: 10px;
    font-size: 0.6875rem;
    color: #475569;
}

.workflow-preview-tag svg {
    color: #94a3b8;
}

.form-error {
    display: block;
    font-size: 0.75rem;
    color: #dc2626;
    margin-top: 4px;
}

.form-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 24px;
    padding-top: 20px;
    border-top: 1px solid #e5e7eb;
}

/* ---- Filter Bar ---- */
.filter-bar {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 20px;
    padding: 16px;
    background: #fff;
    border-radius: 8px;
    border: 1px solid #e5e7eb;
}

.filter-bar .form-group {
    margin-bottom: 0;
    min-width: 150px;
}

.filter-bar .form-label {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 4px;
}

.filter-bar .form-input,
.filter-bar .form-select {
    padding: 6px 10px;
    font-size: 0.8125rem;
}

/* ---- Pagination ---- */
.pagination {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-top: 20px;
}

.pagination-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    height: 34px;
    padding: 0 8px;
    border: 1px solid #d1d5db;
    border-radius: 4px;
    font-size: 0.8125rem;
    color: #374151;
    text-decoration: none;
    background: #fff;
    transition: background-color 0.1s;
}

.pagination-link:hover:not(.disabled):not(.active) {
    background: #f3f4f6;
}

.pagination-link.active {
    background: #2563eb;
    color: #fff;
    border-color: #2563eb;
    font-weight: 600;
}

.pagination-link.disabled {
    color: #9ca3af;
    cursor: default;
}

.pagination-ellipsis {
    padding: 0 6px;
    color: #9ca3af;
}

.pagination-info {
    font-size: 0.75rem;
    color: #6b7280;
    margin-top: 8px;
}

/* ---- Permission Matrix ---- */
.perm-matrix {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.8125rem;
}

.perm-matrix th,
.perm-matrix td {
    padding: 8px 12px;
    text-align: left;
    border-bottom: 1px solid #e5e7eb;
}

.perm-matrix th {
    background: #f9fafb;
    font-weight: 600;
    font-size: 0.75rem;
    text-transform: uppercase;
}

.perm-matrix .module-header {
    background: #eef2ff;
    font-weight: 700;
    color: #3730a3;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.perm-matrix .module-header td {
    padding: 10px 12px;
    border-bottom: 2px solid #c7d2fe;
}

.perm-matrix .perm-checkbox {
    width: 40px;
    text-align: center;
}

.perm-matrix .perm-checkbox input[type="checkbox"] {
    width: 16px;
    height: 16px;
    cursor: pointer;
    accent-color: #2563eb;
}

.perm-matrix .perm-name {
    font-weight: 500;
}

.perm-matrix .perm-desc {
    color: #6b7280;
    font-size: 0.75rem;
}

.perm-matrix .perm-sensitive {
    color: #dc2626;
    font-size: 0.6875rem;
    font-weight: 600;
    margin-left: 6px;
}

/* ---- Stats Grid (Dashboard) ---- */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 24px;
}

.stat-card {
    background: #fff;
    border-radius: 8px;
    padding: 20px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    border: 1px solid #e5e7eb;
}

.stat-card-value {
    font-size: 1.75rem;
    font-weight: 700;
    color: #1a2332;
    line-height: 1.2;
}

.stat-card-label {
    font-size: 0.8125rem;
    color: #6b7280;
    margin-top: 4px;
}

.stat-card-icon {
    float: right;
    color: #9ca3af;
    opacity: 0.5;
}

/* ---- Config Groups ---- */
.config-group {
    margin-bottom: 8px;
}

.config-group-header {
    padding: 12px 20px;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    font-size: 0.875rem;
    font-weight: 600;
    color: #374151;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.config-group-header:hover {
    background: #f3f4f6;
}

.config-group-body {
    padding: 16px 20px;
    border: 1px solid #e5e7eb;
    border-top: none;
    border-radius: 0 0 6px 6px;
}

.config-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 250px 80px;
    gap: 16px;
    align-items: center;
    padding: 10px 0;
    border-bottom: 1px solid #f3f4f6;
}

.config-row:last-child { border-bottom: none; }

.config-row-label {
    font-size: 0.8125rem;
    color: #374151;
}

.config-row-key {
    font-size: 0.6875rem;
    color: #9ca3af;
    font-family: "SF Mono", "Consolas", monospace;
}

/* ---- Utility ---- */
.text-muted { color: #6b7280; }
.text-danger { color: #dc2626; }
.text-success { color: #166534; }
.text-small { font-size: 0.75rem; }
.text-mono { font-family: "SF Mono", "Consolas", "Monaco", monospace; }
.mt-0 { margin-top: 0; }
.mt-2 { margin-top: 8px; }
.mt-4 { margin-top: 16px; }
.mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: 8px; }
.mb-4 { margin-bottom: 16px; }

/* ============================================================
   Case Management
   ============================================================ */

/* Case overview two-column grid */
.case-overview-grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 16px;
}

/* Case info table (key-value pairs) */
.case-info-table {
    width: 100%;
    border-collapse: collapse;
}

.case-info-table th {
    text-align: left;
    padding: 6px 12px 6px 0;
    color: #6b7280;
    font-weight: 600;
    font-size: 0.75rem;
    white-space: nowrap;
    width: 130px;
    border-bottom: 1px solid #f3f4f6;
}

.case-info-table td {
    padding: 6px 0;
    font-size: 0.8125rem;
    border-bottom: 1px solid #f3f4f6;
}

/* Sub-file grid (3 columns for A-J) */
.subfile-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
}

.subfile-card {
    display: block;
    padding: 16px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.subfile-card:hover {
    border-color: #2563eb;
    box-shadow: 0 2px 8px rgba(37, 99, 235, 0.1);
}

.subfile-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 6px;
}

.subfile-card-code {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 6px;
    background: #e0e7ff;
    color: #3730a3;
    font-weight: 700;
    font-size: 0.875rem;
}

.subfile-card-name {
    font-size: 0.8125rem;
    color: #374151;
    font-weight: 600;
    margin-bottom: 4px;
}

.subfile-card-desc {
    font-size: 0.6875rem;
    color: #6b7280;
    line-height: 1.4;
    margin-bottom: 6px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.subfile-card-phase {
    font-size: 0.625rem;
    color: #9ca3af;
    font-style: italic;
}

.subfile-card-phase::before {
    content: "Phases: ";
    font-weight: 600;
}

/* Sub-file detail page */
.subfile-code-lg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 6px;
    background: #e0e7ff;
    color: #3730a3;
    font-weight: 700;
    font-size: 1rem;
    margin-right: 8px;
    vertical-align: middle;
}

.subfile-info-banner {
    background: #f0f4ff;
    border: 1px solid #c7d2fe;
    border-radius: 8px;
    padding: 12px 16px;
    margin-bottom: 16px;
}

.subfile-info-desc {
    font-size: 0.8125rem;
    color: #374151;
    line-height: 1.5;
    margin-bottom: 4px;
}

.subfile-info-phase {
    font-size: 0.6875rem;
    color: #6366f1;
    font-weight: 600;
}

.subfile-nav-strip {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.subfile-nav-item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 6px;
    background: #f3f4f6;
    color: #374151;
    font-weight: 700;
    font-size: 0.875rem;
    text-decoration: none;
    transition: all 0.15s;
    border: 2px solid transparent;
}

.subfile-nav-item:hover {
    background: #e0e7ff;
    color: #3730a3;
}

.subfile-nav-item.active {
    background: #3730a3;
    color: #fff;
    border-color: #3730a3;
}

/* Sub-file strip on case overview */
.subfile-strip {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 8px;
}

.subfile-strip-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border-radius: 6px;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    text-decoration: none;
    color: inherit;
    transition: all 0.15s;
}

.subfile-strip-item:hover {
    background: #e0e7ff;
    border-color: #a5b4fc;
}

.subfile-strip-code {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 4px;
    background: #e0e7ff;
    color: #3730a3;
    font-weight: 700;
    font-size: 0.75rem;
    flex-shrink: 0;
}

.subfile-strip-name {
    font-size: 0.6875rem;
    color: #374151;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

@media (max-width: 960px) {
    .subfile-strip {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (max-width: 600px) {
    .subfile-strip {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Pagination */
.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 12px 16px;
    border-top: 1px solid #e5e7eb;
}

.pagination-info {
    font-size: 0.75rem;
    color: #6b7280;
}

/* Quick links */
.quick-links {
    display: flex;
    flex-direction: column;
}

/* ============================================================
   Workflow Execution
   ============================================================ */

/* Workflow step cards (active steps panel) */
.workflow-step-card {
    padding: 14px 16px;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    margin-bottom: 10px;
}

.workflow-step-card:last-child {
    margin-bottom: 0;
}

.workflow-step-info {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.workflow-step-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
}

/* Workflow step requirements */
.workflow-step-requirements {
    margin-top: 8px;
    padding: 8px 12px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
}

.req-header {
    font-size: 0.75rem;
    font-weight: 600;
    margin-bottom: 4px;
}

.req-status {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.req-status-ok {
    color: #16a34a;
}

.req-status-blocked {
    color: #dc2626;
}

.req-missing-list {
    list-style: none;
    padding: 0;
    margin: 4px 0 0;
}

.req-missing-list li {
    font-size: 0.75rem;
    color: #6b7280;
    padding: 2px 0;
}

.req-missing-list li::before {
    content: "\2717 ";
    color: #dc2626;
    font-weight: 700;
}

.req-missing-list li a {
    color: #2563eb;
    text-decoration: none;
}

.req-missing-list li a:hover {
    text-decoration: underline;
}

/* Gateway decision radio cards */
.radio-card {
    display: block;
    padding: 14px 16px;
    border: 2px solid #e5e7eb;
    border-radius: 8px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.radio-card:hover {
    border-color: #93c5fd;
    background: #f8fafc;
}

.radio-card input[type="radio"] {
    margin-right: 10px;
    accent-color: #2563eb;
}

.radio-card input[type="radio"]:checked ~ span,
.radio-card:has(input:checked) {
    border-color: #2563eb;
    background: #eff6ff;
    box-shadow: 0 0 0 1px #2563eb;
}

/* Button variants for workflow actions */
.btn-success {
    background: #16a34a;
    color: #fff;
}

.btn-success:hover {
    background: #15803d;
}

.btn-warning {
    background: #d97706;
    color: #fff;
}

.btn-warning:hover {
    background: #b45309;
}

/* ---- Mobile Admin Responsive ---- */
@media (max-width: 768px) {
    .form-grid-2col,
    .form-grid-3col {
        grid-template-columns: minmax(0, 1fr);
    }

    .filter-bar {
        flex-direction: column;
        align-items: stretch;
    }

    .filter-bar .form-group {
        min-width: auto;
    }

    .page-toolbar {
        flex-direction: column;
        align-items: flex-start;
    }

    .config-row {
        grid-template-columns: minmax(0, 1fr);
        gap: 6px;
    }

    .stats-grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .case-overview-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .subfile-grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}

/* Modal */
.modal-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 20px;
}
.modal-content {
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.2);
    width: 100%;
    max-height: 90vh;
    overflow-y: auto;
}
.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    border-bottom: 1px solid #e5e7eb;
}
.modal-header h3 {
    font-size: 1rem;
    font-weight: 600;
    color: #111827;
    margin: 0;
}
.modal-close {
    background: none;
    border: none;
    font-size: 1.375rem;
    color: #6b7280;
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
}
.modal-close:hover { color: #111827; }
.modal-body {
    padding: 20px;
}
.modal-body .form-group {
    margin-bottom: 14px;
}
.modal-body .form-group:last-child {
    margin-bottom: 0;
}

/* Two choices that decide what the field under them means. They were rendering as
   "◉New file◯Existing file" -- labels with no gap, text against its own radio and
   against the next one, so the eye cannot tell which word belongs to which control.
   The gap is the whole point of the rule. */
.number-source {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    margin-bottom: 8px;
}

.number-source-choice {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    cursor: pointer;
    font-size: 0.9375rem;
    line-height: 1.3;
}

/* The radio keeps its own size rather than being stretched by the flex row, and does
   not shrink when the labels wrap on a narrow column. */
.number-source-choice input[type="radio"] {
    flex: 0 0 auto;
    margin: 0;
}

/* The reading dialog. Tall rather than tall-ish: a document read in a short box is a
   document scrolled through a letterbox, and the officer is comparing it against a form
   on the page behind. */
.doc-modal .modal-body {
    max-height: calc(100vh - 220px);
    overflow-y: auto;
    background: #f3f4f6;
}

.doc-modal .doc-viewer-page {
    margin: 16px;
    border: 1px solid #e5e7eb;
}

/* A PDF or a scan: the browser's own viewer, given the room the dialog has. */
.doc-modal-frame {
    display: block;
    width: 100%;
    height: calc(100vh - 220px);
    border: 0;
    background: #fff;
}

.doc-modal .doc-viewer-status {
    margin: 16px;
}

/* A Word document converted for reading. Laid out as a page rather than as a panel,
   because that is what it is, and an officer comparing it against a paper copy reads it
   more easily at a page's width than at the browser's. */
.doc-viewer {
    max-width: 920px;
    margin: 0 auto 24px;
}

.doc-viewer-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

.doc-viewer-title {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}

.doc-viewer-title strong {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.doc-viewer-note {
    margin: 0 0 12px;
    font-size: 0.8125rem;
    color: #6b7280;
}

.doc-viewer-status {
    padding: 28px;
    text-align: center;
    color: #6b7280;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
}

.doc-viewer-status.is-error {
    color: #92400e;
    background: #fffbeb;
    border-color: #f59e0b;
}

/* The document itself. Serif, because it is prose rather than interface, and on white
   with a page's padding so it reads as the thing it came from. */
.doc-viewer-page {
    padding: 40px 48px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    font-family: Georgia, 'Times New Roman', serif;
    font-size: 1rem;
    line-height: 1.65;
    color: #111827;
    overflow-wrap: break-word;
}

.doc-viewer-page table {
    border-collapse: collapse;
    width: 100%;
    margin: 14px 0;
}

.doc-viewer-page th,
.doc-viewer-page td {
    border: 1px solid #d1d5db;
    padding: 6px 9px;
    text-align: left;
    vertical-align: top;
}

/* A .docx carries its images as data URIs, which can be any size at all. */
.doc-viewer-page img {
    max-width: 100%;
    height: auto;
}

@media (max-width: 640px) {
    .doc-viewer-page { padding: 20px 18px; }
}

/* Printing gives the document and nothing around it. */
@media print {
    .doc-viewer-bar,
    .doc-viewer-note,
    .doc-viewer-status { display: none; }

    .doc-viewer,
    .doc-viewer-page {
        max-width: none;
        margin: 0;
        padding: 0;
        border: 0;
    }
}

/* A field whose fixed part is shown rather than typed: "FIU INQ No." sits against the
   box and the officer types only "22/2026". Reproducing a prefix by hand is how a
   register ends up holding FIU INQ NO.22/2026 and FIU INQ No. 22/2026 side by side,
   each invisible to a search for the other. */
.input-affix {
    display: flex;
    align-items: stretch;
}

.input-affix-prefix {
    display: flex;
    align-items: center;
    padding: 0 10px;
    border: 1px solid #d1d5db;
    border-right: 0;
    border-radius: 6px 0 0 6px;
    background: #f3f4f6;
    color: #4b5563;
    font-size: 0.875rem;
    white-space: nowrap;
}

.input-affix .form-input {
    border-radius: 0 6px 6px 0;
    min-width: 0;
    flex: 1 1 auto;
}

/* Greyed with the prefix, so a disabled box does not read as an active one with a
   label stuck to it. */
.input-affix .form-input:disabled + .input-affix-prefix,
.input-affix:has(.form-input:disabled) .input-affix-prefix {
    opacity: 0.6;
}

/* One line of money: the currency, then as many figures as the line carries, then a
   way to drop the line -- all on one row.

   FLEX AND NOT GRID. This was `repeat(auto-fit, minmax(0, 1fr))` for the middle tracks
   and it laid the row out vertically -- the currency above the figure. auto-fit works
   out how many tracks to make from the track's MINIMUM, and a minimum of 0 gives it
   nothing to divide by; every other auto-fill in this file names a real one (220px,
   260px), which is what makes those resolvable.

   Rather than pick a minimum that happens to work, flex: the number of columns is not
   something this rule should be deciding at all. One figure on the inquiry register,
   two on the charge register, and whatever a later one asks for. */
.amount-lines-row {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 8px;
}

/* Wide enough for "KES (KSh)" without growing to swallow the figure beside it. */
.amount-lines-row .amount-field-currency {
    flex: 0 0 140px;
}

/* basis 0 rather than auto, so two figures share the space evenly instead of being
   sized by their placeholder text.

   Right-aligned and tabular, because a figure is read right to left when it is being
   checked against a document: 450,000,000 and 111,111,111 should be the same length on
   the page or neither can be scanned. */
.amount-lines-row .amount-field-value {
    flex: 1 1 0;
    min-width: 0;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.amount-lines-remove {
    padding: 6px 10px;
    line-height: 1;
}

.amount-lines [data-amount-line-add] {
    margin-top: 2px;
}

@media (max-width: 640px) {
    /* At phone width 140px plus a figure plus a button leaves the figure unreadable, so
       the line wraps: the currency takes a row of its own and the figures share the next. */
    .amount-lines-row {
        flex-wrap: wrap;
    }
    .amount-lines-row .amount-field-currency {
        flex: 1 1 100%;
    }
}

/* A dialog whose whole content is a table. The table draws its own edges and its header
   row is sticky against the dialog's scroll, so the usual 20px gutter leaves the rows
   floating inside a box with a second box drawn around them. */
.modal-body-flush {
    padding: 0;
}

.modal-body-flush .table-responsive {
    max-height: calc(100vh - 260px);
    overflow-y: auto;
}

.modal-body-flush .data-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
}
.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 14px 20px;
    border-top: 1px solid #e5e7eb;
}

/* Scan placeholder dialog */
.scan-dialog-message {
    font-weight: 600;
    color: #111827;
    margin: 0 0 8px;
}

/* Danger outline button */
.btn-danger-outline {
    color: #dc2626;
    border-color: #fca5a5;
}
.btn-danger-outline:hover {
    background: #fef2f2;
    border-color: #dc2626;
}

/* Form hint text */
.form-hint {
    font-size: 0.6875rem;
    color: #9ca3af;
    margin-top: 4px;
}

/* File drop zone */
.file-drop-zone {
    position: relative;
    border: 2px dashed #d1d5db;
    border-radius: 8px;
    padding: 24px 16px;
    text-align: center;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}
.file-drop-zone:hover {
    border-color: #93c5fd;
    background: #eff6ff;
}
.file-drop-zone.dragover {
    border-color: #2563eb;
    background: #dbeafe;
}
.file-drop-zone.has-file {
    border-style: solid;
    border-color: #93c5fd;
    background: #f0f7ff;
    padding: 14px 16px;
}
.file-drop-zone input[type="file"] {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}
.file-drop-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    color: #6b7280;
    pointer-events: none;
}
.file-drop-placeholder svg {
    color: #9ca3af;
}
.file-drop-placeholder span {
    font-size: 0.8125rem;
    font-weight: 500;
}
.file-drop-placeholder small {
    font-size: 0.6875rem;
    color: #9ca3af;
}
.file-drop-selected {
    display: flex;
    align-items: center;
    gap: 10px;
    pointer-events: none;
    text-align: left;
}
.file-drop-selected svg {
    flex-shrink: 0;
    color: #2563eb;
}
.file-drop-name {
    font-size: 0.8125rem;
    font-weight: 500;
    color: #1f2937;
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.file-drop-size {
    font-size: 0.75rem;
    color: #6b7280;
    flex-shrink: 0;
}
.file-drop-remove {
    pointer-events: auto;
    background: none;
    border: none;
    font-size: 1.125rem;
    color: #9ca3af;
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
    flex-shrink: 0;
    z-index: 1;
}
.file-drop-remove:hover {
    color: #dc2626;
}

/* ============================================================
   Document Templating — Wizard, Template Cards, Preview, Verify
   ============================================================ */

/* Template selection grid */
.template-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: 16px;
}
.template-card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.template-card:hover {
    border-color: #93c5fd;
    box-shadow: 0 2px 8px rgba(37, 99, 235, 0.08);
}
.template-card-icon {
    color: #2563eb;
    flex-shrink: 0;
}
.template-card-body { flex: 1; }
.template-card-title {
    font-size: 0.9375rem;
    font-weight: 600;
    color: #111827;
    margin: 0 0 6px;
}
.template-card-desc {
    font-size: 0.8125rem;
    color: #6b7280;
    line-height: 1.4;
    margin: 0 0 10px;
}
.template-card-meta { display: flex; gap: 6px; flex-wrap: wrap; }
.template-card-action { margin-top: auto; }

/* Wizard progress bar */
.wizard-progress {
    display: flex;
    align-items: center;
    gap: 0;
    margin-bottom: 24px;
    padding: 16px 0;
    overflow-x: auto;
}
.wizard-step-indicator {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    min-width: 80px;
}
.wizard-step-number {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: #e5e7eb;
    color: #6b7280;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8125rem;
    font-weight: 600;
    transition: all 0.2s;
}
.wizard-step-indicator.active .wizard-step-number {
    background: #2563eb;
    color: #fff;
}
.wizard-step-indicator.completed .wizard-step-number {
    background: #059669;
    color: #fff;
}
.wizard-step-label {
    font-size: 0.6875rem;
    color: #9ca3af;
    text-align: center;
    white-space: nowrap;
}
.wizard-step-indicator.active .wizard-step-label { color: #2563eb; font-weight: 600; }
.wizard-step-indicator.completed .wizard-step-label { color: #059669; }
.wizard-step-connector {
    flex: 1;
    height: 2px;
    background: #e5e7eb;
    min-width: 20px;
    margin: 0 4px;
    margin-bottom: 18px;
}

/* Wizard step content */
.wizard-container { max-width: 800px; }
.wizard-step-content { display: none; }
.wizard-step-content.active { display: block; }

/* Wizard navigation */
.wizard-nav {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid #e5e7eb;
}

/* Info text in wizard (for cautions, declarations) */
.doc-info-text-preview {
    background: #f0f9ff;
    border-left: 3px solid #2563eb;
    padding: 12px 16px;
    font-size: 0.8125rem;
    color: #1e40af;
    line-height: 1.5;
    border-radius: 0 4px 4px 0;
    margin-bottom: 12px;
}

/* Repeating table in wizard */
.repeating-table-wrap { margin-top: 4px; }
.repeating-table input.form-input,
.repeating-table textarea.form-textarea {
    font-size: 0.8125rem;
    padding: 6px 8px;
}
.repeating-remove {
    font-size: 1rem;
    line-height: 1;
    padding: 2px 6px;
}

/* Preview page */
.preview-actions-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    background: #fffbeb;
    border: 1px solid #fcd34d;
    border-radius: 8px;
    padding: 12px 16px;
    margin-bottom: 20px;
}
.preview-notice {
    display: flex;
    align-items: center;
    gap: 8px;
    color: #92400e;
    font-size: 0.8125rem;
}
.preview-buttons { display: flex; gap: 8px; flex-wrap: wrap; }
.preview-frame-container {
    border: 1px solid #d1d5db;
    border-radius: 8px;
    overflow: hidden;
    background: #f3f4f6;
}
.preview-frame {
    width: 100%;
    min-height: 1200px;
    border: none;
    background: #fff;
}

/* Print view */
.print-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 16px 20px;
    margin-bottom: 20px;
}
.print-toolbar-info h2 {
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 4px;
}
.print-toolbar-meta { display: flex; gap: 8px; align-items: center; }
.print-toolbar-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.print-document-container {
    border: 1px solid #d1d5db;
    border-radius: 8px;
    overflow: hidden;
    background: #f3f4f6;
}
.print-frame {
    width: 100%;
    min-height: 1200px;
    border: none;
    background: #fff;
}

/* Verify page (minimal layout) */
.minimal-body {
    background: #f3f4f6;
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.minimal-container {
    max-width: 560px;
    width: 100%;
}
.verify-container {
    background: #fff;
    border-radius: 12px;
    padding: 40px 32px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.08);
    text-align: center;
}
.verify-logo { margin-bottom: 16px; }
.verify-title { font-size: 1.375rem; font-weight: 700; color: #111827; margin: 0 0 4px; }
.verify-subtitle { font-size: 0.8125rem; color: #6b7280; margin: 0 0 24px; }

.verify-result {
    padding: 20px;
    border-radius: 8px;
    margin-bottom: 24px;
}
.verify-valid { background: #ecfdf5; border: 1px solid #a7f3d0; }
.verify-invalid { background: #fef2f2; border: 1px solid #fecaca; }
.verify-icon { font-size: 2.25rem; margin-bottom: 8px; }
.verify-valid .verify-icon { color: #059669; }
.verify-invalid .verify-icon { color: #dc2626; }
.verify-result h2 { font-size: 1.125rem; margin: 0 0 6px; }
.verify-valid h2 { color: #065f46; }
.verify-invalid h2 { color: #991b1b; }
.verify-result p { font-size: 0.8125rem; margin: 0; }
.verify-valid p { color: #047857; }
.verify-invalid p { color: #b91c1c; }
.verify-note { margin-top: 8px !important; font-style: italic; }

.verify-details { text-align: left; margin-bottom: 24px; }
.verify-table { width: 100%; border-collapse: collapse; }
.verify-table th,
.verify-table td {
    padding: 8px 12px;
    border-bottom: 1px solid #e5e7eb;
    font-size: 0.8125rem;
}
.verify-table th { font-weight: 600; color: #374151; width: 40%; }
.verify-table td { color: #111827; }

.verify-status {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 600;
}
.verify-status-signed { background: #d1fae5; color: #065f46; }
.verify-status-draft { background: #fef3c7; color: #92400e; }
.verify-status-pending { background: #e0e7ff; color: #3730a3; }

.verify-footer {
    border-top: 1px solid #e5e7eb;
    padding-top: 16px;
    font-size: 0.75rem;
    color: #9ca3af;
}
.verify-disclaimer { margin-top: 8px; font-style: italic; }

/* Detail table (used in upload-signed) */
.detail-table { width: 100%; border-collapse: collapse; }
.detail-table th,
.detail-table td { padding: 8px 12px; border-bottom: 1px solid #f3f4f6; font-size: 0.8125rem; }
.detail-table th { font-weight: 600; color: #374151; width: 35%; text-align: left; }
.detail-table td { color: #111827; }

/* A heading inside a detail table: what the rows under it are about. It spans both
   columns, so it reads as a divider rather than as another label with no value. */
.detail-table .detail-section {
    width: auto;
    padding-top: 14px;
    color: #6b7280;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-bottom: 1px solid #e5e7eb;
}
.detail-table tr:first-child .detail-section { padding-top: 2px; }

/* Form checkbox label */
.form-checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.875rem;
    cursor: pointer;
}
.form-checkbox-label input[type="checkbox"] {
    width: 18px;
    height: 18px;
    accent-color: #2563eb;
}

/* Intel accordion records */
.intel-record-header:hover {
    background: #f3f4f6;
}
.intel-record:last-child {
    border-bottom: none;
}

/* ============================================================
   Tasks — Summary Bar, Filter Tabs, SLA Indicators
   ============================================================ */
/* ---- My Tasks: unread work, searching and ordering ---- */

/* Not opened yet: the row reads like unread mail. Cell classes such as
   .text-muted and .badge set a weight of their own, so the whole row is
   claimed back — otherwise only the step name looked unread. */
.task-row-new td,
.task-row-new td a,
.task-row-new td span,
.task-row-new td strong {
    font-weight: 700;
}
.task-row-new td {
    background: #fcfdff;
    color: #111827;
}
.task-row-new td.text-muted,
.task-row-new td .text-muted {
    color: #4b5563;
}
.task-new-icon {
    color: #1f3a5f;
    vertical-align: -2px;
    margin-right: 4px;
}
.badge-new {
    background: #1f3a5f;
    color: #fff;
    margin-left: 6px;
}

/* Setup → Organisation — an org chart drawn with nested lists.
   Each level is a row of cards; the elbows are borders on the list items, so the
   whole thing stays readable as an outline when styles do not load. */
.org-intro { max-width: 78ch; margin: 0 0 10px; }
.org-gaps { display: flex; flex-direction: column; gap: 4px; }
.org-chart-wrap {
    overflow-x: auto;
    padding: 8px 4px 4px;
}

.org-chart,
.org-chart ul {
    display: flex;
    justify-content: center;
    list-style: none;
    margin: 0;
    padding: 0;
}
.org-chart ul { padding-top: 20px; }
.org-chart li {
    position: relative;
    padding: 20px 8px 0;
    text-align: center;
}

/* The elbow up to the parent: half a line from each of two neighbours */
.org-chart li::before,
.org-chart li::after {
    content: '';
    position: absolute;
    top: 0;
    right: 50%;
    width: 50%;
    height: 20px;
    border-top: 1px solid #cbd5e1;
}
.org-chart li::after {
    right: auto;
    left: 50%;
    border-left: 1px solid #cbd5e1;
}
/* An only child needs a straight line, not an elbow */
.org-chart li:only-child::after { border-left: 1px solid #cbd5e1; }
.org-chart li:only-child::before { display: none; }
.org-chart li:only-child { padding-top: 20px; }
/* The ends of a row have nothing to reach towards */
.org-chart li:first-child::before,
.org-chart li:last-child::after { border: 0 none; }
.org-chart li:last-child::before { border-right: 1px solid #cbd5e1; border-radius: 0 6px 0 0; }
.org-chart li:first-child::after { border-radius: 6px 0 0 0; }

/* The line down from a card to the row beneath it */
.org-chart ul::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    height: 20px;
    border-left: 1px solid #cbd5e1;
}
.org-chart > li { padding-top: 0; }
.org-chart > li::before,
.org-chart > li::after { display: none; }

/* The card itself */
.org-node {
    display: inline-block;
    min-width: 168px;
    max-width: 210px;
    padding: 8px 10px;
    border: 1px solid #d7e0ee;
    border-radius: 8px;
    background: #fff;
    text-align: left;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}
.org-node-name { font-size: 0.8125rem; font-weight: 600; color: #111827; line-height: 1.25; }
.org-node-facts { margin-top: 2px; font-size: 0.6875rem; color: #6b7280; }
.org-node-load { color: #1d4ed8; font-weight: 600; }

/* The head of the unit, and anyone running a team, read differently */
.org-node.is-head {
    background: #1f3a5f;
    border-color: #1f3a5f;
    color: #fff;
}
.org-node.is-head .org-node-name { color: #fff; }
.org-node.is-head .org-node-facts { color: rgba(255, 255, 255, 0.75); }
.org-node.leads-team { border-color: #1d4ed8; border-top: 3px solid #1d4ed8; }
/* A line nobody has named: it follows the team, and says so quietly */
.org-node.is-inherited { border-style: dashed; }

/* Changing the line, where the line is drawn */
.org-node-edit { margin-top: 6px; }
.org-node-edit > summary {
    font-size: 0.6875rem;
    color: #6b7280;
    cursor: pointer;
    list-style: none;
}
.org-node-edit > summary::-webkit-details-marker { display: none; }
.org-node-edit > summary::before { content: '✎ '; }
.org-node-edit > summary:hover { color: #1d4ed8; }
.org-node.is-head .org-node-edit > summary { color: rgba(255, 255, 255, 0.75); }
.org-node-edit form {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 5px;
}
.org-node-edit .form-select { font-size: 0.75rem; max-width: 100%; }

/* Anyone whose line does not reach the top stands on their own */
.org-chart-loose { flex-wrap: wrap; gap: 10px; justify-content: flex-start; }
.org-chart-loose > li { padding: 0; }
.org-chart-loose > li::before,
.org-chart-loose > li::after { display: none; }
.org-chart-loose .org-node { border-color: #f59e0b; }

/* The case journey: every step it has been through, in order */
.journey { list-style: none; margin: 0; padding: 0; }
.journey-step { position: relative; padding-left: 26px; }
/* The line joining one step to the next, stopping at the last */
.journey-step::before {
    content: '';
    position: absolute;
    left: 8px;
    top: 20px;
    bottom: -2px;
    width: 2px;
    background: #e5e7eb;
}
.journey-step:last-child::before { display: none; }
.journey-link {
    display: flex;
    gap: 8px;
    padding: 7px 8px 7px 0;
    color: inherit;
    text-decoration: none;
    border-radius: 6px;
}
.journey-link:hover { background: #f5f8ff; }
.journey-mark {
    position: absolute;
    left: 0;
    top: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #e5e7eb;
    color: #6b7280;
}
.journey-step.is-done .journey-mark { background: #dcfce7; color: #15803d; }
.journey-step.is-open .journey-mark { background: #1f3a5f; color: #fff; }
.journey-body { display: flex; flex-direction: column; min-width: 0; }
.journey-name { font-size: 0.8125rem; font-weight: 600; color: #1f2937; }
.journey-step.is-open .journey-name { color: #1d4ed8; }
.journey-step.is-skipped .journey-name { color: #9ca3af; text-decoration: line-through; }
.journey-meta { font-size: 0.75rem; color: #6b7280; }
.journey-tag {
    font-style: normal;
    font-size: 0.6875rem;
    color: #4b5563;
    background: #f3f4f6;
    border-radius: 9px;
    padding: 0 6px;
    margin-left: 4px;
}
.journey-tag-late { background: #fee2e2; color: #b91c1c; }

/* ---- Cases Monitor ---- */
.monitor-intro { margin: 0 0 12px; }

/* Two ways of looking at the same work, as one control. A third would sit
   alongside without changing anything else. */
.monitor-views {
    display: inline-flex;
    margin-bottom: 10px;
    border: 1px solid #d1d5db;
    border-radius: 999px;
    background: #f3f4f6;
    padding: 3px;
    gap: 2px;
}
.monitor-view {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #4b5563;
    text-decoration: none;
}
.monitor-view:hover { color: #1f3a5f; }
.monitor-view.is-on {
    background: #1f3a5f;
    color: #fff;
    box-shadow: 0 1px 3px rgba(31, 58, 95, 0.3);
}
.monitor-tiles {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 14px;
}
.monitor-tile {
    flex: 1 1 140px;
    display: flex;
    flex-direction: column;
    padding: 10px 14px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    text-decoration: none;
    color: inherit;
}
.monitor-tile:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
.monitor-tile.active { border-color: #1f3a5f; box-shadow: inset 0 0 0 1px #1f3a5f; }
.monitor-tile-count { font-size: 1.375rem; font-weight: 700; line-height: 1.2; }
.monitor-tile-label { font-size: 0.75rem; color: #6b7280; }
.monitor-tile-late .monitor-tile-count  { color: #dc2626; }
.monitor-tile-quiet .monitor-tile-count { color: #f59e0b; }
.monitor-tile-hold .monitor-tile-count  { color: #6b7280; }
.monitor-tile-static { cursor: default; }

.monitor-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.monitor-layout-split { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); }
@media (max-width: 1100px) {
    .monitor-layout-split { grid-template-columns: minmax(0, 1fr); }
}
/* The chosen row is tinted; the pane is a shade deeper, so the eye follows
   from one to the other and the pane reads as the subject, not a sidebar. */
.monitor-row-open td {
    background: #eef3fb;
    box-shadow: inset 3px 0 0 #1f3a5f;
}
.monitor-detail {
    align-self: start;
    position: sticky;
    top: 12px;
    background: #f4f7fc;
    border-color: #d3dff0;
}
.monitor-detail > .card-header {
    background: #1f3a5f;
    color: #fff;
    border-bottom: none;
    font-size: 0.9375rem;
}
.monitor-detail > .card-header .text-muted { color: rgba(255,255,255,0.65) !important; }
.monitor-detail-title {
    margin: 0 0 12px;
    font-size: 0.875rem;
    color: #1f2937 !important;
}

/* Quiet rows, ruled off from each other. White boxes here read as form fields
   waiting to be filled in, which is what made the pane look like a form. */
.monitor-detail .monitor-detail-meta > div {
    padding: 5px 0;
    border-bottom: 1px solid #d7e0ee;
}

.monitor-section {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #4b5563;
    margin: 16px 0 8px;
    padding-bottom: 4px;
    border-bottom: 1px solid #c7d5ea;
}
.monitor-section:first-of-type { margin-top: 0; }

/* Open work: a list, and the name is plainly a link */
.monitor-work { list-style: none; margin: 0 0 4px; padding: 0; }
.monitor-work li {
    padding: 7px 0;
    border-bottom: 1px solid #d7e0ee;
}
.monitor-work li:last-child { border-bottom: none; }
.monitor-work-name {
    font-weight: 600;
    color: #1d4ed8;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.monitor-work-name::after {
    content: ' ›';
    text-decoration: none;
    color: #6b7280;
}
.monitor-work-name:hover { color: #14306b; }
.monitor-work-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 2px;
    font-size: 0.75rem;
    color: #6b7280;
}

/* Comment on file — a card that opens where it sits */
.comment-card { margin-top: 16px; }
.comment-card-open {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: 10px 12px;
    background: #fff;
    border: 1px dashed #9db3d1;
    border-radius: 8px;
    color: #1f3a5f;
    font-size: 0.875rem;
    font-weight: 600;
    cursor: pointer;
}
.comment-card-open:hover { background: #f5f8ff; border-color: #1f3a5f; }
.comment-card-chevron {
    margin-left: auto;
    display: inline-flex;
    transition: transform 0.15s ease;
}
.comment-card.is-open .comment-card-chevron { transform: rotate(180deg); }
.comment-card.is-open .comment-card-open {
    border-style: solid;
    border-bottom: none;
    border-radius: 8px 8px 0 0;
    background: #f5f8ff;
}
.comment-card.is-open .comment-form { border-radius: 0 0 8px 8px; }

.comment-form {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
    background: #fff;
    border: 1px solid #c7d5ea;
    border-radius: 8px;
}
.comment-form textarea { resize: vertical; }

/* Note or instruction, as two buttons rather than two radios */
.comment-kind { display: flex; gap: 0; }
.comment-kind-option {
    flex: 1;
    text-align: center;
    padding: 7px 10px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #4b5563;
    background: #f3f4f6;
    border: 1px solid #d1d5db;
    cursor: pointer;
}
.comment-kind-option:first-child { border-radius: 6px 0 0 6px; }
.comment-kind-option:last-child { border-radius: 0 6px 6px 0; border-left: none; }
.comment-kind-option input { position: absolute; opacity: 0; pointer-events: none; }
.comment-kind-option.is-on {
    background: #1f3a5f;
    border-color: #1f3a5f;
    color: #fff;
}

.comment-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.comment-field { display: flex; flex-direction: column; gap: 2px; flex: 1 1 160px; min-width: 0; }
.comment-field > span {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #6b7280;
}
.comment-check {
    display: flex;
    align-items: center;
    gap: 5px;
    padding-bottom: 7px;
    font-size: 0.8125rem;
    color: #374151;
}

/* Who to notify: a search and a set of checkboxes */
.comment-people { position: relative; }
.comment-people-button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    width: 100%;
    padding: 7px 10px;
    background: #fff;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    font-size: 0.8125rem;
    color: #111827;
    cursor: pointer;
    text-align: left;
}
.comment-people-button:hover { border-color: #9db3d1; }
.comment-people-panel {
    position: absolute;
    z-index: 30;
    top: calc(100% + 4px);
    left: 0;
    width: 280px;
    max-width: 90vw;
    padding: 8px;
    background: #fff;
    border: 1px solid #c7d5ea;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
.comment-people-search { margin-bottom: 6px; }
.comment-people-list { max-height: 210px; overflow-y: auto; }
.comment-people-option {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 5px 4px;
    font-size: 0.8125rem;
    border-radius: 4px;
    cursor: pointer;
}
.comment-people-option:hover { background: #f5f8ff; }
.comment-people-team {
    margin-left: auto;
    font-size: 0.6875rem;
    font-style: normal;
    color: #6b7280;
    background: #f3f4f6;
    border-radius: 9px;
    padding: 0 6px;
}

/* The same form opened as a dialog, from a task page.

   It sheds its card, because the dialog is already the box. And the people picker
   opens in place rather than hanging off its field: a modal body scrolls, so an
   absolutely positioned panel inside one is clipped by it. */
.comment-form-modal {
    border: none;
    padding: 0;
    background: transparent;
}
.comment-form-modal .comment-people-panel {
    position: static;
    width: 100%;
    margin-top: 6px;
    box-shadow: none;
}

/* Room to breathe before the thing that commits it */
.comment-actions {
    display: flex;
    gap: 8px;
    margin-top: 10px;
    padding-top: 12px;
    border-top: 1px solid #e5e7eb;
}
.monitor-detail-meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 8px 14px;
    margin: 0 0 14px;
}
.monitor-detail-meta dt { color: #6b7280; font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.03em; }
.monitor-detail-meta dd { margin: 1px 0 0; font-weight: 600; color: #111827; }
.monitor-work { margin-bottom: 12px; }
.monitor-detail-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0 0 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid #d3dff0;
}

/* Cases list: a long title belongs on one line, with the rest on hover.
   Truncation needs a width to work against, and a table cell will otherwise
   grow to fit the longest title and squeeze every other column. */
.data-table td .case-title,
.data-table td .case-stage {
    max-width: 460px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.case-stage {
    margin-top: 2px;
    color: #6b7280;
}
.case-stage-name {
    color: #1f3a5f;
    font-weight: 600;
}
@media (max-width: 1200px) {
    .data-table td .case-title,
    .data-table td .case-stage { max-width: 260px; }
}

/* Who sent a task: their post, under their name */
.task-sender-title {
    display: block;
    font-size: 0.75rem;
    color: #6b7280;
    font-weight: 400;
}
.task-row-new td .task-sender-title {
    color: #4b5563;
}

/* The number a tab carries */
.tab-count {
    display: inline-block;
    min-width: 18px;
    padding: 0 6px;
    margin-left: 4px;
    border-radius: 9px;
    background: #e5e7eb;
    color: #374151;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 18px;
    text-align: center;
}
.filter-tab.active .tab-count {
    background: #1f3a5f;
    color: #fff;
}
.tab-count-danger  { background: #fee2e2; color: #b91c1c; }
.tab-count-warning { background: #fef3c7; color: #92400e; }

/* Column headers double as sort controls */
.sort-link {
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}
.sort-link:hover {
    text-decoration: underline;
}

.task-search {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    margin-bottom: 12px;
}
.task-search .form-input {
    flex: 1 1 260px;
    min-width: 0;
    max-width: 420px;
}

.filter-tabs {
    display: flex;
    gap: 0;
    border-bottom: 2px solid #e5e7eb;
    margin-bottom: 16px;
}

/* ============================================================
   Searchable Checkbox Multi-Select Widget
   ============================================================ */
.ms-widget {
    position: relative;
}

.ms-trigger {
    width: 100%;
    padding: 8px 32px 8px 12px;
    border: 1px solid #d1d5db;
    border-radius: 4px;
    font-size: 0.875rem;
    font-family: inherit;
    color: #1f2937;
    background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right 10px center;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s, box-shadow 0.15s;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ms-trigger:focus,
.ms-trigger[aria-expanded="true"] {
    outline: none;
    border-color: #2563eb;
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

.ms-trigger .ms-trigger-placeholder {
    color: #9ca3af;
}

.ms-dropdown {
    display: none;
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 200;
    background: #fff;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
    overflow: hidden;
}

.ms-dropdown.is-open {
    display: block;
}

.ms-dropdown-header {
    padding: 8px 10px;
    border-bottom: 1px solid #e5e7eb;
    background: #f9fafb;
    display: flex;
    align-items: center;
    gap: 6px;
}

.ms-search {
    flex: 1;
    padding: 6px 10px;
    border: 1px solid #d1d5db;
    border-radius: 4px;
    font-size: 0.8125rem;
    font-family: inherit;
    color: #1f2937;
    background: #fff;
}

.ms-search:focus {
    outline: none;
    border-color: #2563eb;
    box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
}

.ms-dropdown-actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}

.ms-action-btn {
    padding: 4px 9px;
    font-size: 0.75rem;
    font-family: inherit;
    border: 1px solid #d1d5db;
    border-radius: 4px;
    background: #fff;
    color: #374151;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.1s, border-color 0.1s;
}

.ms-action-btn:hover {
    background: #f3f4f6;
    border-color: #9ca3af;
}

.ms-list {
    max-height: 220px;
    overflow-y: auto;
    padding: 4px 0;
}

/* A heading in a multi-select list: what sits under it is choosable, it is not. */
.ms-group {
    padding: 9px 12px 3px;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #6b7280;
    user-select: none;
}

.ms-group:not(:first-child) {
    border-top: 1px solid #e5e7eb;
    margin-top: 4px;
}

/* Indented, so it reads as belonging to the heading above it. */
.ms-item-child {
    padding-left: 24px;
}

/* An amount that shares the currency chosen beside it: the code, where its select
   would be, so the two figures line up and only one of them is a control. */
.amount-field-currency-fixed {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    color: #4b5563;
    background: #f9fafb;
    cursor: default;
}

.ms-item {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 7px 12px;
    cursor: pointer;
    transition: background 0.1s;
    user-select: none;
}

.ms-item:hover {
    background: #f0f4ff;
}

.ms-item.is-selected {
    background: #eff6ff;
}

.ms-item input[type="checkbox"] {
    margin-top: 2px;
    flex-shrink: 0;
    width: 15px;
    height: 15px;
    accent-color: #2563eb;
    cursor: pointer;
}

.ms-item-label {
    font-size: 0.8125rem;
    color: #1f2937;
    line-height: 1.4;
}

.ms-empty {
    padding: 12px;
    text-align: center;
    font-size: 0.8125rem;
    color: #9ca3af;
}

.ms-footer {
    padding: 6px 12px;
    border-top: 1px solid #e5e7eb;
    background: #f9fafb;
    font-size: 0.75rem;
    color: #6b7280;
}

.ms-tag-list {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    margin-top: 8px;
    min-height: 0;
}

.ms-tag {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    background: #dbeafe;
    color: #1e40af;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 500;
}

.ms-tag-remove {
    background: none;
    border: none;
    color: #3b82f6;
    cursor: pointer;
    font-size: 0.875rem;
    line-height: 1;
    padding: 0;
    display: flex;
    align-items: center;
}

.ms-tag-remove:hover {
    color: #1e40af;
}
.filter-tab {
    padding: 8px 16px;
    text-decoration: none;
    color: #6b7280;
    font-size: 0.8125rem;
    font-weight: 500;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    transition: color 0.15s, border-color 0.15s;
}
.filter-tab:hover { color: #1f2937; }
.filter-tab.active {
    color: #2563eb;
    border-bottom-color: #2563eb;
}

/* SLA indicator — left-border cell in table */
.sla-indicator-overdue { background: #dc2626 !important; }
.sla-indicator-due-soon { background: #f59e0b !important; }
.sla-indicator-on-track { background: #10b981 !important; }
.sla-indicator-none { background: #e5e7eb !important; }

/* Empty tasks state */
.empty-tasks {
    text-align: center;
    padding: 48px 16px;
    color: #6b7280;
}
.empty-tasks .empty-icon { margin-bottom: 12px; opacity: 0.4; }
.empty-tasks h3 { color: #374151; margin-bottom: 4px; }
.empty-tasks p { font-size: 0.8125rem; }

/* ============================================================
   CSS Tooltips (data-tooltip attribute)
   ============================================================ */
[data-tooltip] {
    position: relative;
    cursor: default;
}
[data-tooltip]::before,
[data-tooltip]::after {
    position: absolute;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 100;
}
/* Tooltip bubble */
[data-tooltip]::after {
    content: attr(data-tooltip);
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    background: #1f2937;
    color: #fff;
    font-size: 0.6875rem;
    font-weight: 500;
    line-height: 1.4;
    padding: 4px 8px;
    border-radius: 4px;
    /* `white-space: nowrap` together with `max-width` was contradictory: nowrap
     * won, so max-width never applied and the bubble grew to its full single-line
     * width. Because [data-tooltip] is position:relative, that absolutely
     * positioned pseudo-element counts toward the parent's scrollWidth even at
     * opacity:0 — a 208px tooltip inside a 107px KPI tile pushed .dash-header,
     * then .main-content, then the whole page into horizontal scroll.
     *
     * Allowing the text to wrap lets max-width do its job, so a long tooltip
     * becomes two short lines instead of one very wide one. */
    white-space: normal;
    max-width: 220px;
    width: max-content;
}
/* Arrow */
[data-tooltip]::before {
    content: '';
    bottom: calc(100% + 2px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    border: 4px solid transparent;
    border-top-color: #1f2937;
}
[data-tooltip]:hover::before,
[data-tooltip]:hover::after {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}
/* Bottom variant */
[data-tooltip-pos="bottom"]::after {
    bottom: auto;
    top: calc(100% + 6px);
    transform: translateX(-50%) translateY(-4px);
}
[data-tooltip-pos="bottom"]::before {
    bottom: auto;
    top: calc(100% + 2px);
    border-top-color: transparent;
    border-bottom-color: #1f2937;
    transform: translateX(-50%) translateY(-4px);
}
[data-tooltip-pos="bottom"]:hover::before,
[data-tooltip-pos="bottom"]:hover::after {
    transform: translateX(-50%) translateY(0);
}
/* Left-aligned variant (for items near right edge) */
[data-tooltip-align="left"]::after { left: 0; transform: translateX(0) translateY(4px); }
[data-tooltip-align="left"]::before { left: 12px; transform: translateX(0) translateY(4px); }
[data-tooltip-align="left"]:hover::after,
[data-tooltip-align="left"]:hover::before { transform: translateX(0) translateY(0); }

/* ============================================================
   Dashboard — Asymmetric Grid Layout & Widgets
   ============================================================ */

/* Header */
.dash-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-bottom: 20px;
    flex-wrap: wrap;
    gap: 12px;
}
.dash-header h1 { margin: 0; font-size: 1.5rem; color: #1f2937; }
.dash-subtitle { color: #6b7280; font-size: 0.8125rem; margin-top: 2px; }
/* The KPI strip is the sibling of the page title inside .dash-header, which is
 * a flex row. Without flex-wrap here and flex-shrink:0 on the tiles, the title
 * competed for space and squashed each tile to ~94px — narrower than its own
 * label ("TOTAL CASES", "SLA OVERDUE"). The text then spilled out of the tile,
 * out of .dash-header, out of .main-content, and scrolled the whole page.
 *
 * .dash-header already has flex-wrap: wrap, so once the tiles refuse to shrink
 * the strip drops onto its own line instead of overflowing. */
.dash-header-stats {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
    justify-content: flex-end;
}
.dash-kpi {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 6px 16px;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    flex-shrink: 0;   /* keep the natural width; wrap rather than squash */
}
.dash-kpi-value { font-size: 1.375rem; font-weight: 700; color: #1f2937; line-height: 1.2; }
.dash-kpi-danger { color: #dc2626; }
.dash-kpi-label {
    font-size: 0.6875rem;
    color: #6b7280;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    white-space: nowrap;   /* two-word labels must not break mid-tile */
}

/* Asymmetric Grid */
.dash-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: 16px;
}
.dash-card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    padding: 16px;
    min-width: 0;
}
/* Team pulse: the supervisor's first look. Deliberately the one coloured card
   on the dashboard — it answers "is the team keeping up" before anything else. */
.pulse-card {
    grid-column: span 4;
    /* No row span: it stands beside the case-status card, the same height as the
       rest of the row. Spanning two rows left it half empty and dominating. */
    background: #1f3a5f;
    border: none;
    color: #fff;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 16px 18px;
}
.pulse-head { display: flex; flex-direction: column; gap: 2px; }
.pulse-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}
.pulse-sub { font-size: 0.75rem; color: rgba(255, 255, 255, 0.7); }

.pulse-hero { display: flex; align-items: baseline; gap: 10px; margin-bottom: 2px; }
.pulse-number { font-size: 2.25rem; font-weight: 800; line-height: 1; }
.pulse-label { font-size: 0.75rem; color: rgba(255, 255, 255, 0.82); }
.pulse-trend { display: block; font-style: normal; font-size: 0.6875rem; margin-top: 2px; }
.pulse-trend-up   { color: #86efac; }
.pulse-trend-down { color: #fca5a5; }
.pulse-trend-flat { color: rgba(255, 255, 255, 0.6); }

.pulse-figures { display: flex; gap: 8px; }
.pulse-figure {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: 8px 10px;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.1);
    color: inherit;
    text-decoration: none;
}
a.pulse-figure:hover { background: rgba(255, 255, 255, 0.18); }
.pulse-figure-number { font-size: 1.125rem; font-weight: 700; line-height: 1.2; }
.pulse-figure-label { font-size: 0.6875rem; color: rgba(255, 255, 255, 0.72); }
.pulse-figure-late .pulse-figure-number { color: #fecaca; }

.pulse-load { display: flex; flex-direction: column; gap: 4px; margin-top: auto; }
.pulse-load-title {
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: rgba(255, 255, 255, 0.6);
}
.pulse-load-row { display: flex; align-items: center; gap: 8px; font-size: 0.75rem; }
.pulse-load-name {
    flex: 0 0 42%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: rgba(255, 255, 255, 0.92);
}
.pulse-load-bar {
    flex: 1;
    height: 6px;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.16);
    overflow: hidden;
}
.pulse-load-bar i { display: block; height: 100%; background: #7dd3fc; }
.pulse-load-count { flex: 0 0 auto; font-weight: 700; }
.pulse-load-note { font-size: 0.6875rem; color: rgba(255, 255, 255, 0.6); }

@media (max-width: 1100px) {
    .pulse-card { grid-column: span 12; grid-row: auto; }
}

.dash-card-full    { grid-column: span 12; }
.dash-card-wide    { grid-column: span 8; }
.dash-card-narrow  { grid-column: span 4; }
.dash-card-medium  { grid-column: span 6; }
.dash-card-small   { grid-column: span 3; }

@media (max-width: 1200px) {
    .dash-card-wide   { grid-column: span 7; }
    .dash-card-narrow { grid-column: span 5; }
    .dash-card-small  { grid-column: span 6; }
}
@media (max-width: 900px) {
    .dash-card-wide, .dash-card-narrow, .dash-card-medium, .dash-card-small {
        grid-column: span 12;
    }
}

.dash-card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
}
.dash-card-header h3 {
    font-size: 0.875rem;
    font-weight: 600;
    color: #374151;
    margin: 0;
    display: flex;
    align-items: center;
    gap: 6px;
}
.dash-empty {
    text-align: center;
    padding: 24px 12px;
    color: #9ca3af;
    font-size: 0.8125rem;
}

/* ── Donut Chart ── */
.dash-chart-row { display: flex; gap: 20px; align-items: center; }
.dash-donut-wrap { flex: 0 0 200px; }
.dash-donut { width: 100%; height: auto; }
.dash-donut-center-num { font-size: 1.75rem; font-weight: 700; fill: #1f2937; }
.dash-donut-center-label { font-size: 0.75rem; fill: #6b7280; }

.dash-legend { flex: 1; display: flex; flex-direction: column; gap: 4px; }
.dash-legend-item { display: flex; align-items: center; gap: 8px; font-size: 0.75rem; }
.dash-legend-dot {
    width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0;
    display: inline-block;
}
.dash-legend-label { flex: 1; color: #374151; }
.dash-legend-value { font-weight: 600; color: #1f2937; min-width: 20px; text-align: right; }

/* ── SLA Gauge ── */
.dash-gauge-wrap { text-align: center; margin-bottom: 12px; }
.dash-gauge-svg { width: 140px; height: auto; }
.dash-gauge-num { font-size: 1.375rem; font-weight: 700; fill: #1f2937; }
.dash-gauge-label { font-size: 0.5625rem; fill: #6b7280; text-transform: uppercase; letter-spacing: 0.5px; }

.dash-sla-pills { display: flex; flex-direction: column; gap: 6px; }
.dash-sla-pill {
    display: flex; align-items: center; justify-content: space-between;
    padding: 8px 12px; border-radius: 8px; font-size: 0.75rem;
}
.dash-sla-pill-num { font-weight: 700; font-size: 1.125rem; margin-right: 8px; }
.dash-sla-danger { background: #fef2f2; color: #dc2626; }
.dash-sla-warn   { background: #fffbeb; color: #d97706; }
.dash-sla-ok     { background: #ecfdf5; color: #059669; }

/* ── Bar Chart (Monthly Trends) ── */
.dash-bar-chart-body {
    display: flex;
    align-items: flex-end;
    gap: 6px;
    height: 160px;
    padding: 0 4px;
}
.dash-bar-group { flex: 1; display: flex; flex-direction: column; align-items: center; }
.dash-bar-col { display: flex; gap: 3px; align-items: flex-end; height: 140px; width: 100%; }
.dash-bar {
    flex: 1;
    border-radius: 3px 3px 0 0;
    position: relative;
    min-height: 2px;
    transition: height 0.3s;
    display: flex;
    align-items: flex-start;
    justify-content: center;
}
.dash-bar-opened { background: #3b82f6; }
.dash-bar-closed { background: #10b981; }
.dash-bar-val {
    font-size: 0.5625rem;
    font-weight: 600;
    color: #fff;
    padding-top: 2px;
}
.dash-bar-label { font-size: 0.625rem; color: #6b7280; margin-top: 4px; }
.dash-bar-legend {
    display: flex;
    gap: 16px;
    justify-content: center;
    margin-top: 8px;
    font-size: 0.75rem;
    color: #6b7280;
}
.dash-bar-legend span { display: flex; align-items: center; gap: 4px; }

/* ── Horizontal Bars (Team Workload) ── */
.dash-hbar-list { display: flex; flex-direction: column; gap: 8px; }
.dash-hbar-row { display: flex; align-items: center; gap: 8px; }
.dash-hbar-label { width: 120px; font-size: 0.75rem; color: #374151; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-hbar-track { flex: 1; height: 16px; background: #f3f4f6; border-radius: 8px; display: flex; overflow: hidden; }
.dash-hbar-fill { height: 100%; transition: width 0.3s; }
.dash-hbar-active { background: #3b82f6; }
.dash-hbar-closed { background: #10b981; }
.dash-hbar-value { font-size: 0.75rem; font-weight: 600; color: #1f2937; min-width: 24px; text-align: right; }

/* ── Mini Donut (Typology) ── */
.dash-mini-donut-wrap { text-align: center; margin-bottom: 8px; }
.dash-mini-donut { width: 100px; height: 100px; }
.dash-mini-legend { display: flex; flex-direction: column; gap: 4px; }

/* ── Risk Bars ── */
.dash-risk-bars { display: flex; flex-direction: column; gap: 10px; }
.dash-risk-row { display: flex; align-items: center; gap: 8px; }
.dash-risk-label { width: 60px; font-size: 0.75rem; color: #374151; }
.dash-risk-track { flex: 1; height: 12px; background: #f3f4f6; border-radius: 6px; overflow: hidden; }
.dash-risk-fill { height: 100%; border-radius: 6px; transition: width 0.3s; }
.dash-risk-value { font-size: 0.75rem; font-weight: 600; color: #1f2937; min-width: 20px; text-align: right; }

/* ── Financial Summary ── */
.dash-finance-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin-bottom: 14px;
}
.dash-finance-item {
    padding: 10px 12px;
    border-radius: 8px;
    border-left: 3px solid;
}
.dash-finance-proceeds { background: #f0f9ff; border-color: #3b82f6; }
.dash-finance-frozen   { background: #ecfdf5; border-color: #10b981; }
.dash-finance-seized   { background: #fffbeb; border-color: #f59e0b; }
.dash-finance-returned { background: #fef2f2; border-color: #dc2626; }
.dash-finance-label { font-size: 0.6875rem; color: #6b7280; text-transform: uppercase; letter-spacing: 0.3px; }
.dash-finance-value { font-size: 1.125rem; font-weight: 700; color: #1f2937; margin-top: 2px; }
.dash-finance-pct { font-size: 0.6875rem; color: #059669; margin-top: 2px; }

.dash-recovery { margin-top: 4px; }
.dash-recovery-header { display: flex; justify-content: space-between; font-size: 0.75rem; color: #374151; margin-bottom: 4px; }
.dash-recovery-track { height: 8px; background: #f3f4f6; border-radius: 4px; overflow: hidden; }
.dash-recovery-fill { height: 100%; background: linear-gradient(90deg, #10b981, #3b82f6); border-radius: 4px; transition: width 0.5s; }

/* ── Priority ── */
.dash-pri-list { display: flex; flex-direction: column; gap: 14px; }
.dash-pri-item {}
.dash-pri-header { display: flex; align-items: center; gap: 8px; font-size: 0.8125rem; color: #374151; margin-bottom: 4px; }
.dash-pri-header strong { margin-left: auto; font-size: 1.125rem; }
.dash-pri-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dash-pri-bar { height: 6px; background: #f3f4f6; border-radius: 3px; overflow: hidden; }
.dash-pri-fill { height: 100%; border-radius: 3px; transition: width 0.3s; }

/* ── Activity Feed ── */
.dash-activity-feed { display: flex; flex-direction: column; gap: 0; }
.dash-activity-item {
    display: flex;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid #f3f4f6;
}
.dash-activity-item:last-child { border-bottom: none; }
.dash-activity-icon { flex-shrink: 0; width: 28px; height: 28px; border-radius: 50%; background: #f9fafb; display: flex; align-items: center; justify-content: center; }
.dash-activity-content { flex: 1; min-width: 0; }
.dash-activity-text { font-size: 0.75rem; color: #374151; line-height: 1.4; }
.dash-activity-meta { font-size: 0.6875rem; color: #9ca3af; display: flex; gap: 4px; flex-wrap: wrap; margin-top: 2px; }
.dash-activity-meta a { color: #3b82f6; text-decoration: none; }

/* ── Admin Row ── */
.dash-admin-row { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.dash-admin-stat {
    text-align: center;
    padding: 8px 16px;
    background: #f9fafb;
    border-radius: 8px;
}
.dash-admin-stat.dash-admin-warn { background: #fef2f2; }
.dash-admin-num { display: block; font-size: 1.25rem; font-weight: 700; color: #1f2937; }
.dash-admin-warn .dash-admin-num { color: #dc2626; }
.dash-admin-label { font-size: 0.6875rem; color: #6b7280; }
.dash-admin-links { margin-left: auto; display: flex; gap: 6px; }

/* ── Dashboard Drilldown ────────────────────────────── */
.dash-drilldown { cursor: pointer; }
.dash-drilldown:hover { opacity: 0.8; }
.dash-legend-item.dash-drilldown:hover { background: #f3f4f6; border-radius: 4px; }
.dash-sla-pill.dash-drilldown:hover { filter: brightness(0.95); }
.dash-hbar-row.dash-drilldown:hover { background: #f9fafb; border-radius: 4px; }
.dash-risk-row.dash-drilldown:hover { background: #f9fafb; border-radius: 4px; }
.dash-finance-item.dash-drilldown:hover { filter: brightness(0.95); transform: translateY(-1px); }
.dash-pri-item.dash-drilldown:hover { background: #f9fafb; border-radius: 4px; }
.dash-kpi.dash-drilldown:hover { background: rgba(37, 99, 235, 0.06); border-radius: 8px; }

/* Drilldown modal table */
.drilldown-case-link { color: #2563eb; font-weight: 600; text-decoration: none; }
.drilldown-case-link:hover { text-decoration: underline; }
.drilldown-case-noaccess { color: #9ca3af; font-weight: 500; }

/* SVG circle drilldown hover */
circle.dash-drilldown:hover { opacity: 0.75; transition: opacity 0.15s; }

/* Compact table variant */
.data-table-compact td, .data-table-compact th { padding: 6px 10px; font-size: 0.8125rem; }

/* Version line on the login footer — quiet, small, below the org name. */
.auth-version {
    margin-top: 4px;
    font-size: 0.6875rem;
    color: #9ca3af;
    letter-spacing: 0.02em;
}


/* ============================================================
   Whole-row links (task and case lists)
   ============================================================ */
tr[data-href] { cursor: pointer; }
tr[data-href]:hover { background: #f8fafc; }
tr[data-href]:focus-visible { outline: 2px solid #1f3a5f; outline-offset: -2px; }

/* ============================================================
   Step page: what the step is on the left, what to do on the right
   ============================================================ */
.step-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
    gap: 16px;
    align-items: start;
}
.step-action-column { position: sticky; top: 12px; }
/* A sticky card taller than the window pins at the top, and everything below the
   fold is unreachable until the column beside it has scrolled past -- the right
   pane reads as frozen while the left one moves. app.js measures the card and sets
   this when it will not fit, so a tall card scrolls with the page like anything
   else. Without JS the card stays sticky, which is where it was before. */
.step-action-column.is-unstuck { position: static; }
/* What is being asked of you, lifted off the page. Blue, not amber: this is the
   ordinary business of the workflow, not a warning about it. */
.action-required-card {
    border: 1px solid #bfdbfe;
    background: #f8fbff;
    box-shadow: 0 6px 18px rgba(37, 99, 235, 0.13), 0 1px 3px rgba(37, 99, 235, 0.08);
}
.action-required-card > .card-header {
    background: #2563eb;
    color: #fff;
    border-bottom: 1px solid #1d4ed8;
    justify-content: flex-start;
    gap: 6px;
}
.action-required-card > .card-header svg { stroke: #fff; }
.action-hint { color: #6b7280; font-size: 0.8rem; margin: 0 0 10px; }

/* "Action required by you", wherever a record is shown that is waiting on the
   person reading it. Clicking goes to the step, not to a part of the page. */
.badge-action-required {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 11px;
    border-radius: 999px;
    background: #2563eb;
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    text-decoration: none;
    box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3);
}
.badge-action-required:hover { background: #1d4ed8; color: #fff; text-decoration: none; }
.badge-action-required svg { stroke: #fff; }
@media (max-width: 1000px) {
    .step-layout { grid-template-columns: minmax(0, 1fr); }
    .step-action-column { position: static; }
}

/* ── Workplan sheet ────────────────────────────────────────── */

.wp-sheet td,
.wp-sheet th { padding: 8px 10px; vertical-align: top; }

.wp-sheet .text-right { text-align: right; }

.wp-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 30px;
    height: 24px;
    padding: 0 6px;
    border-radius: 12px;
    background: #e5e7eb;
    color: #374151;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    cursor: default;
}

/* The Lead IO is the officer who answers for the file: marked out from the rest */
.wp-badge-lead {
    background: #1d4ed8;
    color: #fff;
}

.wp-dep {
    display: inline-block;
    min-width: 20px;
    margin: 0 2px 2px 0;
    padding: 1px 5px;
    border: 1px solid #fcd34d;
    border-radius: 4px;
    background: #fffbeb;
    color: #92400e;
    font-size: 0.75rem;
    text-align: center;
}

.wp-dep-done {
    border-color: #a7f3d0;
    background: #ecfdf5;
    color: #047857;
}

.wp-progress {
    height: 8px;
    border-radius: 4px;
    background: #e5e7eb;
    overflow: hidden;
}

.wp-progress-bar {
    height: 100%;
    background: #2563eb;
    transition: width 0.2s ease;
}

.wp-progress-done { background: #059669; }
.wp-progress-late { background: #dc2626; }

/* Tick lists: sub-files, what an activity waits on, the entities it engages.
   Equal columns with real spacing, so they read as a grid and not a jumble. */
.subfile-checkbox-grid,
.wp-waits-grid,
.wp-entity-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(210px, 100%), 1fr));
    gap: 8px;
}

.wp-waits-grid,
.wp-entity-grid {
    max-height: 190px;
    overflow-y: auto;
    padding-right: 4px;
}

.subfile-checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    background: #fff;
    font-size: 0.8125rem;
    line-height: 1.25;
    cursor: pointer;
}

.subfile-checkbox-label:hover { border-color: #93c5fd; background: #f8fafc; }
.subfile-checkbox-label:has(input:checked) { border-color: #2563eb; background: #eff6ff; }
.subfile-checkbox-label input { flex-shrink: 0; margin: 0; }

.subfile-checkbox-code {
    flex-shrink: 0;
    min-width: 22px;
    padding: 1px 5px;
    border-radius: 4px;
    background: #eef2ff;
    color: #3730a3;
    font-weight: 600;
    font-size: 0.75rem;
    text-align: center;
}

/* The attachment fields on a diary entry: out of the way until one is being filed. */
.wp-attach {
    margin-bottom: 14px;
    padding: 10px 12px;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    background: #f9fafb;
}

.wp-attach > summary {
    cursor: pointer;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #374151;
}

.wp-attach[open] > summary { margin-bottom: 4px; }

/* The sheet shows only the activity's title; everything else is a click away. */
.wp-activity-title {
    padding: 0;
    border: 0;
    background: none;
    color: #1d4ed8;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.wp-activity-title:hover { text-decoration: underline; }

/* The plan's own details, once saved: read at a glance, edited in a dialog. */
.wp-summary {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
    gap: 12px 24px;
    align-items: start;
}

.wp-summary dt {
    margin: 0 0 2px;
    color: #6b7280;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.wp-summary dd { margin: 0; font-size: 0.875rem; color: #1a2332; }
.wp-summary .wp-summary-wide { grid-column: 1 / -1; }

.wp-form-error {
    margin-bottom: 14px;
    padding: 10px 12px;
    border: 1px solid #fecaca;
    border-left: 3px solid #dc2626;
    border-radius: 4px;
    background: #fef2f2;
    color: #991b1b;
    font-size: 0.8125rem;
}

/* The minute a file arrived with, shown where the next minute is written so
   nobody repeats or contradicts it. */
.intake-minute {
    background: #f8fafc;
    border-left: 3px solid #cbd5e1;
    padding: 8px 10px;
    margin-bottom: 8px;
    font-size: 0.8125rem;
    color: #475569;
    white-space: pre-wrap;
    border-radius: 0 4px 4px 0;
}
.intake-minute-label {
    display: block;
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #94a3b8;
    margin-bottom: 3px;
}

/* What is already filed, named on the action card so the documents in the other
   column are not missed. */
.action-attached {
    font-size: 0.8rem;
    color: #475569;
    margin: 0 0 10px;
    line-height: 1.45;
}
.action-attached a {
    font-weight: 600;
    color: #2563eb;
    text-decoration: none;
    border-bottom: 1px solid #bfdbfe;
}
.action-attached a:hover { border-bottom-color: #2563eb; }

.action-attached a {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.action-attached a svg { stroke: #2563eb; }

/* ── Decision routes ────────────────────────────────────────────
   A route and what it carries, as one thing. The picker for the
   officer a route hands the work to sits inside that route, and
   shows only when the route is chosen — so the card says what each
   option means rather than listing every picker at once. */

.route-option {
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    margin-bottom: 6px;
    background: #fff;
    transition: border-color 0.12s, background 0.12s;
}

.route-option:hover { border-color: #93c5fd; }

.route-option:has(input:checked) {
    border-color: #2563eb;
    background: #f5f9ff;
}

.route-option-head {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 12px;
    cursor: pointer;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #1f2937;
    margin: 0;
}

.route-option-head input[type="radio"] {
    accent-color: #2563eb;
    margin: 0;
    flex-shrink: 0;
}

/* What the route carries: only for the one chosen */
.route-option-detail { display: none; }

.route-option:has(input:checked) .route-option-detail {
    display: block;
    padding: 0 12px 10px 33px;
    border-top: 1px solid #dbeafe;
    margin-top: -1px;
    padding-top: 10px;
}

.route-option-detail .form-group { margin-bottom: 0; }
.route-option-detail .form-label { font-weight: 500; }

/* A badge that opens something: the member count on the teams list. */
.badge-button {
    border: none;
    cursor: pointer;
    font: inherit;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 3px 10px;
}
.badge-button:hover { filter: brightness(0.93); }

/* ── Where a task came from, and where it has got to ────────────
   Plain labels: a task is read, not clicked. */

.action-provenance {
    margin: 0 0 10px;
    font-size: 0.8rem;
    color: #334155;
    line-height: 1.6;
}

.action-provenance strong { color: #1f2937; }

/* ── Forms a step sends you to ──────────────────────────────────
   Opened in a new tab: the application refuses to be framed, so
   there is no panel to show them in. */

.step-forms .step-form {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    margin-bottom: 5px;
    border: 1px solid #bfdbfe;
    border-radius: 5px;
    background: #f8fbff;
    color: #1e3a8a;
    font-size: 0.8125rem;
    font-weight: 600;
    text-decoration: none;
}

.step-forms .step-form:hover {
    border-color: #2563eb;
    background: #eff6ff;
    text-decoration: none;
}

.step-forms .step-form svg { stroke: #2563eb; flex-shrink: 0; }
.step-forms .step-form span { flex: 1; min-width: 0; }

.step-forms .step-form em {
    font-style: normal;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #2563eb;
    background: #dbeafe;
    padding: 2px 7px;
    border-radius: 999px;
}

/* A form that is filled in here rather than opened elsewhere: shut until
   it is wanted, and saying how much is inside. */

.step-forms .step-form-card {
    border: 1px solid #bfdbfe;
    border-radius: 5px;
    background: #f8fbff;
    margin-bottom: 5px;
}

.step-forms .step-form-card > summary {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    cursor: pointer;
    font-size: 0.8125rem;
    font-weight: 600;
    color: #1e3a8a;
    list-style: none;
}

.step-forms .step-form-card > summary::-webkit-details-marker { display: none; }



.step-forms .step-form-card > summary svg { stroke: #2563eb; flex-shrink: 0; }

.step-forms .step-form-card > summary > svg:last-child {
    transform: rotate(-90deg);
    transition: transform 0.15s;
}

.step-forms .step-form-card[open] > summary > svg:last-child { transform: rotate(0); }
.step-forms .step-form-card > summary span { flex: 1; min-width: 0; }

.step-forms .step-form-card > summary em {
    font-style: normal;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #2563eb;
    background: #dbeafe;
    padding: 2px 7px;
    border-radius: 999px;
}

.step-form-card-body {
    padding: 4px 10px 10px;
    border-top: 1px solid #dbeafe;
}

/* What a field asks of the officer, where it is not the plain red asterisk: a field
   that may be left alone, or one the system has already answered. Quiet on purpose -
   it qualifies the label, it is not a status of its own. */
.form-badge-soft {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 6px;
    border-radius: 9px;
    background: #f1f5f9;
    color: #64748b;
    font-size: 0.6875rem;
    font-weight: 500;
    vertical-align: middle;
}

/* The page a form points at, reachable from inside the card it belongs to. */
.step-form-link {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.75rem;
    font-weight: 600;
    color: #2563eb;
    text-decoration: none;
    margin-top: 4px;
}
.step-form-link:hover { text-decoration: underline; color: #1d4ed8; }
.step-form-link svg { stroke: #2563eb; }

/* The workplan sheet: fifteen activities, each heading the tasks beneath it. The heading
   spans the row because it is not a task — it is the group the tasks belong to. */
.wp-activity-row > td {
    background: #f8fafc;
    border-top: 2px solid #e2e8f0;
    padding-top: 10px;
    padding-bottom: 10px;
}
.wp-activity-seq {
    font-weight: 700;
    color: #64748b;
    text-align: right;
}
.wp-activity-skipped > td { opacity: 0.55; }
.wp-activity-skipped strong { text-decoration: line-through; }
.wp-task-row > td { vertical-align: top; }
.wp-task-meta { margin-top: 4px; display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }

/* Work held by a unit rather than by one of our officers. Marked, because nobody here can
   be told to do it — only to chase it. */
.wp-agency {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-weight: 600;
    color: #7c3aed;
}

.wp-version-picker .form-select {
    display: inline-block;
    width: auto;
    padding: 2px 24px 2px 8px;
    font-size: 0.75rem;
    font-weight: 600;
    vertical-align: middle;
}
.visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* The sheet keeps its bearings while it is scrolled. The column headings stay at the top;
   each activity heading sticks just beneath them until the next one pushes it away, so the
   tasks on screen always say which activity they belong to. */
.wp-sheet { border-collapse: separate; border-spacing: 0; }
.wp-sheet thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: #f8fafc;
    box-shadow: inset 0 -1px 0 #e2e8f0;
}
.wp-sheet .wp-activity-row > td {
    position: sticky;
    top: 38px;
    z-index: 2;
}
.wp-task-number {
    font-variant-numeric: tabular-nums;
    color: #64748b;
    font-size: 0.75rem;
    white-space: nowrap;
}
.wp-task-row { cursor: pointer; }
.wp-task-row:hover > td { background: #f8fafc; }
.wp-task-row:focus-visible { outline: 2px solid #2563eb; outline-offset: -2px; }
.wp-row-actions .topnav-dropdown-toggle { padding: 2px 8px; font-size: 0.75rem; }

/* Responsibility: an officer of ours, or a unit with one of ours answering for it. Only
   the half that is chosen is shown, so the form says one thing at a time. */
.wp-responsible { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 8px; }
.wp-radio { display: inline-flex; align-items: center; gap: 6px; font-size: 0.8125rem; cursor: pointer; }
.wp-responsible-pane { padding: 10px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; }

.wp-timeframe { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 0.8125rem; }
.wp-timeframe .form-input, .wp-timeframe .form-select { margin: 0; }

/* Twenty-one offences: searchable, because an officer knows the name and not the position
   in the list, and checkboxes because a task can concern more than one. */

/* -- The officers working alongside the one answerable ----------------------
   Two dozen names, so the grid gets a search box -- in the same bordered box
   the offence picker below it uses, because two searchable lists on one dialog
   should not look like two different kinds of control. */
/* -- What the plan is waiting for ------------------------------------------
   A draft plan looks finished, and the one step that gives its tasks out is a
   line inside a dropdown. The strip says which step, and names the menu. */
.wp-next-step {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 9px 16px;
    border-top: 1px solid #e5e7eb;
    font-size: 0.8125rem;
}
.wp-next-step-act { background: #fffbeb; border-top-color: #fde68a; }
.wp-next-step-wait { background: #f8fafc; }

/* A STATEMENT, NOT A CONTROL. As a filled pill it read as a button, and a
   button that cannot be pressed is worse than no button at all. No fill, no
   border, no padding: the words, an icon and a colour. */
.wp-next-step-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
}
.wp-next-step-act .wp-next-step-badge { color: #b45309; }
.wp-next-step-wait .wp-next-step-badge { color: #475569; }
.wp-next-step-badge svg { flex-shrink: 0; }

.wp-next-step-says { color: #475569; }
.wp-next-step-says strong { color: #1f3a5f; }

/* -- Edit mode, while it is on ----------------------------------------------
   It dashes the editable cells and opens a row for adding a task, which on a
   plan of one task is a change small enough to miss. This says what it did. */
.wp-editing-bar { display: none; }
body.wp-editing .wp-editing-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 9px 16px;
    background: #eef4ff;
    border-top: 1px solid #c7d5ea;
    font-size: 0.8125rem;
    color: #334155;
}
.wp-editing-bar-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-weight: 600;
    color: #1f3a5f;
    white-space: nowrap;
}
.wp-editing-bar-says { color: #475569; }
/* Underlined the way the cells themselves are, so the sentence points at
   something the officer can already see on the page. */
.wp-editing-bar-cell {
    border-bottom: 1px dashed #1f3a5f;
    padding-bottom: 1px;
}
body.wp-editing .wp-editing-bar .btn { margin-left: auto; }

/* -- The header's three buttons as one group --------------------------------
   They were three children of a space-between header, so the browser spread
   them across the whole width and they read as three unrelated controls. */
.wp-header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* -- What a time frame means, said back as it is typed ----------------------
   The row reads "Runs from week 3 to 4"; this line under it says what that
   comes to -- Week 3-4, in real dates, counted from the activation day. */
.wp-timeframe-echo {
    margin: 6px 0 2px;
    padding: 6px 10px;
    background: #f1f5f9;
    border-left: 3px solid #2563eb;
    border-radius: 0 4px 4px 0;
    font-size: 0.8125rem;
    color: #334155;
}
.wp-timeframe-echo:empty { display: none; }
.wp-timeframe-anchor { color: #64748b; }
/* The word between the two numbers in the small inline picker. */
.wp-picker-span-word { color: #64748b; font-size: 0.8125rem; }

.wp-officer-picker { border: 1px solid #e2e8f0; border-radius: 6px; overflow: hidden; }
.wp-officer-search { border: 0; border-bottom: 1px solid #e2e8f0; border-radius: 0; margin: 0; }
.wp-officer-list { padding: 6px; }
.wp-officer-empty { margin: 0; padding: 4px 8px 8px; }
/* Filtered out by the search. Shared with the other tick lists on this page so
   any of them can be made searchable without a second rule for it. */
.subfile-checkbox-label.is-hidden { display: none; }
/* Taken off the list because the dropdown above names them: they are answerable
   for the task, and "also working on it" means the others. */
.subfile-checkbox-label.is-responsible { display: none; }

.wp-offences { border: 1px solid #e2e8f0; border-radius: 6px; overflow: hidden; }
.wp-offence-search { border: 0; border-bottom: 1px solid #e2e8f0; border-radius: 0; margin: 0; }
.wp-offence-list { max-height: 190px; overflow-y: auto; padding: 6px; }
.wp-offence-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px;
    font-size: 0.8125rem;
    border-radius: 4px;
    cursor: pointer;
}
.wp-offence-option:hover { background: #f1f5f9; }
.wp-offence-option.is-hidden { display: none; }

/* ── An offence with offences under it ──────────────────────────────────────
   "Money Laundering (as predicate)" is a heading over ten. The heading is still
   tickable -- the unit records matters against money laundering generally as
   well as against a specific section -- so the +/- is a button of its own beside
   the box rather than the box doing two jobs. */
.wp-offence-group { }

/* The whole heading row is the control: there is no checkbox on it, so there is
   nothing else it could usefully do when clicked. */
.wp-offence-parent {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    border: 0;
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.wp-offence-label {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 1;
    cursor: pointer;
    min-width: 0;
}

/* Sized and placed where a checkbox would be, because that is where the eye looks:
   the + stands in the column of boxes and says this row opens instead of ticking. */
.wp-offence-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    border: 1px solid #cbd5e1;
    border-radius: 4px;
    background: #fff;
    color: #334155;
    font-size: 0.8125rem;
    font-weight: 700;
    line-height: 1;
}

.wp-offence-parent:hover .wp-offence-toggle { background: #e2e8f0; }

/* A heading is not a choice, so it is not set like one. */
.wp-offence-heading { font-weight: 600; color: #334155; }

/* Shut until asked for. Ten extra rows open on every picker would bury the other
   twenty-one offences under one of them. */
.wp-offence-child { display: none; }
.wp-offence-group.is-open .wp-offence-child { display: flex; }

/* Indented, and with a line down the left, so a child is plainly part of the
   heading above it and not another offence in its own right. */
.wp-offence-child {
    margin-left: 26px;
    padding-left: 10px;
    border-left: 2px solid #e2e8f0;
}

/* The search hides rows by class; that has to win over the group being open, or a
   search inside an open heading shows every child regardless of the term. */
.wp-offence-group.is-open .wp-offence-child.is-hidden { display: none; }

/* A Close button in a dialog footer is a button, not the x in the corner. Both carry
   .modal-close, because that is the class the dialog listens for, so the button has to
   win back the padding, size and border that the corner x strips away. */
.btn.modal-close {
    padding: 10px 20px;
    font-size: 0.875rem;
    font-weight: 600;
    line-height: 1.4;
    border-radius: 4px;
}
.btn-outline.modal-close {
    background: #fff;
    color: #374151;
    border: 1px solid #d1d5db;
}
.btn-outline.modal-close:hover {
    background: #f9fafb;
    border-color: #9ca3af;
    color: #374151;
}
.btn-sm.modal-close { padding: 6px 12px; font-size: 0.8125rem; }

/* ── My Calendar ──────────────────────────────────────────────────────
   An officer's own work by date. Colour says how close a thing is, not what it is:
   scanning a month, what is late matters before what it is about. */
.wp-cal-views { display: inline-flex; gap: 4px; }

.wp-cal-month { width: 100%; border-collapse: collapse; table-layout: fixed; }
.wp-cal-month th {
    padding: 8px 6px;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #64748b;
    text-align: left;
    border-bottom: 1px solid #e2e8f0;
}
.wp-cal-month td {
    vertical-align: top;
    height: 104px;
    padding: 4px;
    border: 1px solid #f1f5f9;
    /* Static, so a tooltip may cross into the next day rather than being covered
       by it; the hovered chip carries the z-index instead. */
    position: static;
}
.wp-cal-month td.is-outside { background: #fafafa; }
.wp-cal-month td.is-outside .wp-cal-daynum { color: #cbd5e1; }
.wp-cal-month td.is-today,
.wp-cal-month th.is-today { background: #eff6ff; }
.wp-cal-week td { height: 320px; }

.wp-cal-daynum {
    display: inline-block;
    margin-bottom: 4px;
    padding: 1px 5px;
    font-size: 0.75rem;
    font-weight: 700;
    color: #475569;
    text-decoration: none;
    border-radius: 10px;
}
.wp-cal-daynum:hover { background: #e2e8f0; }
.is-today > .wp-cal-daynum { background: #2563eb; color: #fff; }

.wp-cal-chip {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-bottom: 2px;
    padding: 2px 5px;
    border-radius: 3px;
    font-size: 0.6875rem;
    line-height: 1.35;
    text-decoration: none;
    border-left: 3px solid transparent;
}
/* The label is clipped to the chip; the tooltip beside it must not be */
.wp-cal-chip > .wp-cal-chip-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wp-cal-chip .icon { flex: 0 0 auto; }

/* What the entry is, on hover. The chip is too narrow to say much, and the
   browser's own tooltip takes a second and arrives as one grey run of text. */
.wp-cal-chip { position: relative; }
.wp-cal-tip {
    position: absolute;
    z-index: 80;
    bottom: calc(100% + 7px);
    left: 0;
    min-width: 170px;
    max-width: 260px;
    padding: 7px 9px;
    border-radius: 6px;
    background: #111827;
    color: #fff;
    text-align: left;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.22);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(3px);
    transition: opacity 0.12s ease, transform 0.12s ease, visibility 0s linear 0.12s;
}
/* The label is clipped to the chip's width; the tooltip is not */
.wp-cal-tip strong,
.wp-cal-tip em {
    display: block;
    overflow: visible;
    white-space: normal;
    text-overflow: clip;
}
.wp-cal-tip strong { font-size: 0.75rem; font-weight: 600; line-height: 1.3; }
.wp-cal-tip em {
    font-style: normal;
    font-size: 0.6875rem;
    color: rgba(255, 255, 255, 0.75);
    margin-top: 1px;
}
.wp-cal-tip::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 14px;
    border: 5px solid transparent;
    border-top-color: #111827;
}

/* Late in the week there is no room to the right, so it hangs off the other end */
.wp-cal-month td:nth-child(n+6) .wp-cal-tip,
.wp-cal-week td:nth-child(n+6) .wp-cal-tip { left: auto; right: 0; }
.wp-cal-month td:nth-child(n+6) .wp-cal-tip::after,
.wp-cal-week td:nth-child(n+6) .wp-cal-tip::after { left: auto; right: 14px; }

/* The first row of a month has nothing above it, so the tooltip drops below */
.wp-cal-month tbody tr:first-child .wp-cal-tip {
    bottom: auto;
    top: calc(100% + 7px);
    transform: translateY(-3px);
}
.wp-cal-month tbody tr:first-child .wp-cal-tip::after {
    top: auto;
    bottom: 100%;
    border-top-color: transparent;
    border-bottom-color: #111827;
}

.wp-cal-chip:hover .wp-cal-tip,
.wp-cal-chip:focus-visible .wp-cal-tip {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity 0.12s ease, transform 0.12s ease;
}

@media (prefers-reduced-motion: reduce) {
    .wp-cal-tip,
    .wp-cal-chip:hover .wp-cal-tip { transition: none; transform: none; }
}
/* The urgency bands are defined once, further down. */
/* A filter makes the chip its own stacking context, which trapped the tooltip
   inside it: chips further down the day, being later in the document, painted
   over it. Raising the hovered chip lifts its whole context above them. */
.wp-cal-chip:hover,
.wp-cal-chip:focus-within {
    filter: brightness(0.96);
    z-index: 90;
}

.wp-cal-more { display: block; font-size: 0.6875rem; color: #64748b; text-decoration: none; padding: 1px 5px; }
.wp-cal-more:hover { text-decoration: underline; }

.wp-cal-allday { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding-bottom: 10px; }

/* The day, by the hour. Only the working hours are drawn: a column of empty night is
   nothing to read. */
.wp-cal-hours { border-top: 1px solid #e2e8f0; }
.wp-cal-hour { display: grid; grid-template-columns: 62px minmax(0, 1fr); border-bottom: 1px solid #f1f5f9; }
.wp-cal-hour.has-work { background: #f8fafc; }
.wp-cal-hour-label {
    padding: 6px 10px;
    font-size: 0.6875rem;
    color: #94a3b8;
    font-variant-numeric: tabular-nums;
    border-right: 1px solid #f1f5f9;
}
.wp-cal-hour-body { padding: 4px 8px; min-height: 30px; }

/* How pressing a thing is, in colour. Four bands rather than two, because "not today and
   not late" covers everything from tomorrow to next month, and an officer can still do
   something about the next two days. */
.wp-cal-late  { background: #fee2e2; color: #991b1b; border-left-color: #dc2626; }
.wp-cal-today { background: #ffedd5; color: #9a3412; border-left-color: #ea580c; }
.wp-cal-soon  { background: #fef3c7; color: #92400e; border-left-color: #f59e0b; }
.wp-cal-ahead { background: #eff6ff; color: #1e40af; border-left-color: #3b82f6; }
.wp-cal-undated { background: #f1f5f9; color: #475569; border-left-color: #94a3b8; }

.wp-cal-legend {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    padding: 8px 16px;
    border-bottom: 1px solid #f1f5f9;
    font-size: 0.6875rem;
    color: #64748b;
}
.wp-cal-legend-gap { flex: 0 0 1px; height: 14px; background: #e2e8f0; }
.wp-cal-key { display: inline-flex; align-items: center; gap: 5px; }
.wp-cal-swatch {
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 2px;
    border-left: 3px solid;
}

/* ── Correcting a cell of the workplan where it stands ─────────────────────────

   Four plain columns, and only while edit mode is on. Off, a cell is ordinary text
   with nothing to suggest otherwise: the row click opens the task, and an underline
   inviting a click that does something else would be a lie. On, every editable cell
   says so and the row stops opening.                                            */

.wp-cell { display: inline-block; min-width: 1.5em; }
.wp-cell.is-empty { color: #9ca3af; }

body.wp-editing .wp-task-row { cursor: default; }
body.wp-editing .wp-cell {
    cursor: text;
    border-bottom: 1px dashed #b6c6de;
    border-radius: 2px;
    padding: 0 2px;
    margin: 0 -2px;
    transition: background 0.12s;
}
body.wp-editing .wp-cell:hover { background: #eef4ff; border-bottom-color: #1f3a5f; }

/* Being edited, saving, saved, refused — four states an officer can tell apart
   without reading anything. */
.wp-cell.is-editing { display: block; width: 100%; border-bottom: none; padding: 0; margin: 0; }
.wp-cell.is-saving { opacity: 0.55; }
.wp-cell.is-saved { background: #dcfce7; border-bottom-color: #16a34a; }
.wp-cell.is-error {
    background: #fee2e2;
    border-bottom: 1px solid #b91c1c;
    color: #7f1d1d;
    cursor: help;
}

.wp-cell-editor {
    width: 100%;
    min-height: 28px;
    padding: 4px 6px;
    font: inherit;
    color: #111827;
    background: #fff;
    border: 1px solid #1f3a5f;
    border-radius: 4px;
    resize: none;
    overflow: hidden;
    box-shadow: 0 0 0 3px rgba(31, 58, 95, 0.12);
}

/* ── The three columns of the workplan that are picked, not typed ─────────────

   Who answers for a task, what it concerns and how long it runs are each a choice
   from something, so each gets a small panel opened at its own cell rather than a
   dialog over the whole sheet. One panel of each kind, moved to wherever it is
   wanted — thirty-four tasks would otherwise mean a hundred hidden panels.      */

body.wp-editing .wp-choice {
    cursor: pointer;
    display: inline-block;
    border-bottom: 1px dashed #b6c6de;
    border-radius: 2px;
    padding: 0 2px;
    margin: 0 -2px;
}
body.wp-editing .wp-choice:hover { background: #eef4ff; border-bottom-color: #1f3a5f; }
.wp-choice.is-saving { opacity: 0.55; }
.wp-choice.is-saved { background: #dcfce7; }
.wp-choice.is-error { background: #fee2e2; color: #7f1d1d; cursor: help; }
.wp-choice-note { display: block; }

.wp-picker {
    position: absolute;
    z-index: 60;
    width: 300px;
    max-width: calc(100vw - 24px);
    background: #fff;
    border: 1px solid #c7d5ea;
    border-radius: 8px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.16);
}
.wp-picker-head {
    padding: 9px 12px;
    font-size: 0.8125rem;
    font-weight: 600;
    border-bottom: 1px solid #e5e7eb;
}
.wp-picker-body { padding: 10px 12px; }
.wp-picker-body .form-label { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.03em; color: #6b7280; }
.wp-picker-foot {
    display: flex;
    gap: 8px;
    padding: 9px 12px;
    border-top: 1px solid #e5e7eb;
    background: #f9fafb;
    border-radius: 0 0 8px 8px;
}

/* An officer or a unit, as two buttons rather than two radios */
.wp-picker-kind { display: flex; margin-bottom: 10px; }
.wp-picker-kind-option {
    flex: 1;
    text-align: center;
    padding: 6px 8px;
    font-size: 0.75rem;
    font-weight: 600;
    color: #4b5563;
    background: #f3f4f6;
    border: 1px solid #d1d5db;
    cursor: pointer;
}
.wp-picker-kind-option:first-child { border-radius: 6px 0 0 6px; }
.wp-picker-kind-option:last-child { border-radius: 0 6px 6px 0; border-left: none; }
.wp-picker-kind-option input { position: absolute; opacity: 0; pointer-events: none; }
.wp-picker-kind-option.is-on { background: #1f3a5f; border-color: #1f3a5f; color: #fff; }

.wp-picker-search { margin-bottom: 6px; }
.wp-picker-list { max-height: 220px; overflow-y: auto; }
.wp-picker-option {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 4px 3px;
    font-size: 0.8125rem;
    border-radius: 4px;
    cursor: pointer;
}
.wp-picker-option:hover { background: #f5f8ff; }

/* A number and the unit it counts in, side by side */
.wp-picker-span { display: flex; gap: 6px; }
.wp-picker-span input { flex: 0 0 90px; }
.wp-picker-span select { flex: 1; }

/* ── Adding a line to the sheet ────────────────────────────────────────────────

   One per activity, and only while edit mode is on: with it off the sheet is for
   reading, and a row inviting a click would be the same lie an underlined cell
   would be.                                                                     */

.wp-add-row { display: none; }
body.wp-editing .wp-add-row { display: table-row; }
body.wp-editing .wp-add-row > td { background: #fbfdff; border-top: 1px dashed #c7d5ea; }

.wp-add-row-button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    font-size: 0.75rem;
    font-weight: 600;
    color: #1f3a5f;
    background: none;
    border: 1px dashed #b6c6de;
    border-radius: 5px;
    cursor: pointer;
}
.wp-add-row-button:hover { background: #eef4ff; border-style: solid; }

/* The row just added, so the officer can see where they landed */
.wp-task-row.is-new > td { background: #fffbeb; }

/* ── A note against one step of the journey ───────────────────────────────────

   Small, quiet, and out of the way until wanted: the step itself is the thing
   being read, and the note is an aside. It sits at the top-right of the step
   rather than inside the link, because the link goes to the step and this does
   not. Only somebody who may file on the case ever sees it.                   */

.journey-note {
    position: absolute;
    top: 2px;
    right: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    color: #9db3d1;
    background: none;
    border: 1px solid transparent;
    border-radius: 5px;
    cursor: pointer;
    /* Faint rather than invisible: something you can see is there, before you
       know you want it. */
    opacity: 0.45;
    transition: opacity 0.12s, color 0.12s, background 0.12s, border-color 0.12s;
}
/* On the row, not just on the button. An icon that only announces itself once the
   pointer is already on it announces itself to nobody: by the time you have found
   it you did not need telling. Being on the step is enough. */
.journey-step:hover .journey-note {
    opacity: 1;
    color: #1f3a5f;
    border-color: #c7d5ea;
    background: #eef4ff;
}

/* Under the pointer it stops being a hint and becomes a button: solid, so there
   is no question what is about to happen. The keyboard gets the same, because an
   affordance nobody can reach is not an affordance. */
/* Written to outweigh the row rule above, which is two classes deep and would
   otherwise win and keep the icon merely tinted while the pointer is on it. */
.journey-step .journey-note:hover,
.journey-step .journey-note:focus,
.journey-note:focus-visible {
    opacity: 1;
    color: #fff;
    background: #1f3a5f;
    border-color: #1f3a5f;
    outline: none;
}
.journey-note:focus-visible { box-shadow: 0 0 0 3px rgba(31, 58, 95, 0.25); }

/* ── Looking for something in a register ──────────────────────────────────────

   One row of controls, not a panel that folds open. A register is a place people
   come to find a file, so the way to look for one is the first thing on the page
   rather than something to discover.                                           */

.register-search {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}
/* The words get the room; the narrowing controls take what they need */
.register-search-main { flex: 1 1 260px; min-width: 0; }
.register-search .form-select,
.register-search .form-input[type="date"] { flex: 0 0 auto; width: auto; }

/* A row that opens its own record says so under the pointer */
tr[data-row-href] { cursor: pointer; }
tr[data-row-href]:hover > td { background: #f5f8ff; }
tr[data-row-href]:focus-visible {
    outline: 2px solid #1f3a5f;
    outline-offset: -2px;
}
/* The links inside it still look and behave like links */
tr[data-row-href] a { position: relative; }

/* A value the system fills in rather than asks for: it sits where the input would,
   so the row still reads as a field, but nothing invites typing into it. */
.form-static {
    margin: 0;
    padding: 9px 0 0;
    font-size: 0.875rem;
    color: #111827;
}

/* ── Duplicate reference warning (Correspondence intake) ─────────────────────
   Not .alert: that is a toast — it floats, animates in and dismisses on click.
   This one sits in the form under the field it is about and stays until the
   reference changes. */
.dup-panel[hidden] { display: none; }

.dup-warning {
    background: #fffbeb;
    border: 1px solid #f59e0b;
    border-left: 4px solid #f59e0b;
    border-radius: 6px;
    padding: 12px 14px;
    color: #92400e;
    font-size: 0.875rem;
}

.dup-warning-title {
    margin: 0 0 8px;
    font-weight: 600;
}

.dup-warning-list {
    margin: 0 0 8px;
    padding-left: 18px;
    display: grid;
    gap: 6px;
}

.dup-warning-list a {
    font-weight: 600;
    color: #92400e;
    text-decoration: underline;
}

.dup-warning-subject {
    display: block;
    color: #78350f;
}

.dup-warning-meta {
    display: block;
    font-size: 0.8125rem;
    color: #a16207;
    margin: 2px 0 0;
}

.dup-warning-confirm {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid #fcd34d;
    cursor: pointer;
    font-weight: 500;
}

.dup-warning-confirm input { margin-top: 2px; }

/* ── Field help: the (?) beside a label on a case file ───────────────────────
   Uses the existing [data-tooltip] bubble. Only the mark itself is styled here:
   quiet until looked at, so a page of them does not read as a page of warnings. */
.field-help {
    display: inline-flex;
    align-items: center;
    margin-left: 4px;
    color: #9ca3af;
    vertical-align: middle;
    cursor: help;
    transition: color 0.12s ease;
}

.field-help:hover,
.field-help:focus-visible {
    color: #2563eb;
    outline: none;
}

.field-help svg {
    display: block;
}

/* These explanations are sentences, not labels, so they need more room than a
   KPI tooltip. Widened only here, where the extra width cannot push a dashboard
   tile into horizontal scroll. */
.field-help[data-tooltip]::after {
    max-width: 340px;
    text-align: left;
    font-weight: 400;
    line-height: 1.5;
    padding: 8px 10px;
    /* The labels these marks sit in are set in caps with letter-spacing, and a
       pseudo-element inherits both -- so without this the bubble SHOUTED A WHOLE
       SENTENCE AT THE OFFICER, spaced out, in a 220px column. */
    text-transform: none;
    letter-spacing: normal;
}

/* The same problem on a form, and worse: a form grid puts a label hard against the
   left edge of the page, so a centred bubble is cut off by the viewport rather than
   merely by a table. Every mark on a form label is anchored to the mark itself and
   opens rightwards, which cannot clip at the left edge whatever column it sits in.
   Narrower than the table variant so the rightmost column does not push the other way.

   .field-grid dt is the same situation on the reading side: the entry page lays its
   fields out in the same kind of grid, and its first column is just as hard against
   the left edge. */
.form-label .field-help[data-tooltip]::after,
.card-header .field-help[data-tooltip]::after,
.field-grid dt .field-help[data-tooltip]::after {
    left: 0;
    transform: translateY(4px);
    /* 220px, the same as every other tooltip in the application, and not the 340px the
       table variant allows. An absolutely positioned pseudo-element still counts toward
       its ancestor's scrollWidth, so a wider bubble on the last column of a form grid put
       the whole page into horizontal scroll - 67px of it at a 1024px viewport. A taller
       bubble is a smaller problem than a scrolling page. */
    max-width: 220px;
}

.form-label .field-help[data-tooltip]:hover::after,
.form-label .field-help[data-tooltip]:focus-visible::after,
.card-header .field-help[data-tooltip]:hover::after,
.card-header .field-help[data-tooltip]:focus-visible::after,
.field-grid dt .field-help[data-tooltip]:hover::after,
.field-grid dt .field-help[data-tooltip]:focus-visible::after {
    transform: translateY(0);
}

/* The arrow follows the bubble: centred under the mark, which is now the bubble's
   left edge rather than its middle. */
.form-label .field-help[data-tooltip]::before,
.card-header .field-help[data-tooltip]::before,
.field-grid dt .field-help[data-tooltip]::before {
    left: 6px;
}

/* A card header is set in the heading weight and the mark would be dragged into it;
   it is an aside, so it keeps its own size and sits beside the words. */
.card-header .field-help svg { display: block; }
.card-header .field-help { font-weight: 400; }

/* In a dialog's title bar the bubble opens DOWNWARD.
   A tooltip normally rises from the mark, and a dialog's header is at the top of a box
   that is itself near the top of the screen — so upward is off the viewport, where no
   amount of z-index helps. Down is into the dialog's own body, which has the room. */
.modal-header .field-help { font-weight: 400; }
.modal-header .field-help svg { display: block; }

.modal-header .field-help[data-tooltip]::after {
    bottom: auto;
    top: calc(100% + 6px);
    left: 0;
    transform: translateY(-4px);
    text-transform: none;
    letter-spacing: normal;
}

.modal-header .field-help[data-tooltip]::before {
    bottom: auto;
    top: calc(100% + 2px);
    left: 6px;
    border-top-color: transparent;
    border-bottom-color: #1f2937;
    transform: translateY(-4px);
}

.modal-header .field-help[data-tooltip]:hover::after,
.modal-header .field-help[data-tooltip]:focus-visible::after,
.modal-header .field-help[data-tooltip]:hover::before,
.modal-header .field-help[data-tooltip]:focus-visible::before {
    transform: translateY(0);
}

/* What a card is for, under its heading.
   Not a tooltip: a mark you have to hover explains the card to whoever already
   suspects they need explaining. Where a whole card is misread -- "Disposition" taken
   for "disposal" -- the words have to be in front of the person who does not know
   they are confused. Not .alert either: this is not a warning and must not look like
   one on every visit. */
.card-note {
    margin: 0 0 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid #f3f4f6;
    color: #6b7280;
    font-size: 0.8125rem;
    line-height: 1.5;
    max-width: 70ch;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .card-note {
        color: #9ca3af;
        border-bottom-color: #374151;
    }
}

:root[data-theme="dark"] .card-note { color: #9ca3af; border-bottom-color: #374151; }

/* A label in the first column has little room to its left, so a centred bubble
   would hang off the edge of the table. Anchored to the mark instead. */
.case-info-table th .field-help[data-tooltip]::after {
    left: 0;
    transform: translateX(-8px) translateY(4px);
}

.case-info-table th .field-help[data-tooltip]::before {
    left: 8px;
}

.case-info-table th .field-help[data-tooltip]:hover::after {
    transform: translateX(-8px) translateY(0);
}

/* ── Dashboard figures that open the list they counted ───────────────────────
   A KPI tile and a bar row become anchors. They keep the layout they had as a
   div, so nothing moves; only the affordance is added. */
a.dash-kpi-link {
    text-decoration: none;
    color: inherit;
    transition: background 0.12s ease, transform 0.12s ease;
}

a.dash-kpi-link:hover {
    background: rgba(37, 99, 235, 0.06);
    transform: translateY(-1px);
}

a.dash-hbar-link {
    display: flex;
    align-items: center;
    gap: 10px;
    text-decoration: none;
    color: inherit;
    padding: 2px 4px;
    margin: 0 -4px;
    border-radius: 4px;
    transition: background 0.12s ease;
}

a.dash-hbar-link:hover {
    background: rgba(37, 99, 235, 0.07);
}

/* A KPI tile that is a link, on the statistics report.
   .dash-kpi was written for a <div>, so as an <a> it arrived underlined and link-blue.
   Same treatment as the bar rows above: it reads as a tile and behaves as a link. */
a.dash-kpi {
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s, box-shadow 0.15s;
}
a.dash-kpi:hover {
    border-color: #93c5fd;
    box-shadow: 0 1px 3px rgba(37, 99, 235, 0.15);
}
a.dash-kpi:focus-visible {
    outline: 2px solid #2563eb;
    outline-offset: 2px;
}
a.dash-kpi .dash-kpi-value,
a.dash-kpi .dash-kpi-label { text-decoration: none; }

:root[data-theme="dark"] a.dash-kpi:hover { border-color: #3b82f6; }

a.dash-hbar-link:hover .dash-hbar-label {
    color: #2563eb;
}

a.dash-kpi-link:focus-visible,
a.dash-hbar-link:focus-visible {
    outline: 2px solid #2563eb;
    outline-offset: 2px;
}

/* A stat tile that is a link keeps the tile's layout; only the affordance is added. */
a.dash-admin-stat {
    text-decoration: none;
    color: inherit;
    border-radius: 4px;
    transition: background 0.12s ease;
}

a.dash-admin-stat:hover {
    background: rgba(37, 99, 235, 0.07);
}

a.dash-admin-stat:hover .dash-admin-num {
    color: #2563eb;
}

/* "Checked, nothing found" — quiet, because it is good news and the form should not
   celebrate it. Enough to show the check ran. */
.dup-clear {
    margin: 0;
    padding: 8px 10px;
    border-left: 3px solid #22c55e;
    background: #f0fdf4;
    color: #166534;
    font-size: 0.8125rem;
    border-radius: 4px;
}

/* Why a step cannot be completed. Sits above the disabled button, because the reason
   has to be visible without hovering anything. */
.step-blocked {
    margin: 4px 0 12px;
    padding: 12px 14px;
    border: 1px solid #f59e0b;
    border-left: 4px solid #f59e0b;
    border-radius: 6px;
    background: #fffbeb;
    color: #92400e;
    font-size: 0.875rem;
}

.step-blocked ul {
    margin: 8px 0;
    padding-left: 20px;
}

.step-blocked li { margin: 4px 0; }

/* Answered by a file chosen in the slots above, which has not been sent yet. Struck
   through rather than removed: the officer should see WHICH requirement their file
   settled, not watch a line disappear. */
.step-blocked li.is-covered,
.req-missing-list li.is-covered {
    color: #15803d;
    text-decoration: line-through;
}

/* The notice that replaces .step-blocked once every outstanding sub-file has a file
   waiting for it. Green, and deliberately quieter than the amber it replaces. */
.step-ready {
    margin: 4px 0 12px;
    padding: 12px 14px;
    border: 1px solid #22c55e;
    border-left: 4px solid #22c55e;
    border-radius: 6px;
    background: #f0fdf4;
    color: #166534;
    font-size: 0.875rem;
}

/* "That is our number, not theirs" — a correction, not a refusal, so it is blue rather
   than the amber a duplicate gets. */
.dup-ours {
    background: #eff6ff;
    border: 1px solid #60a5fa;
    border-left: 4px solid #2563eb;
    border-radius: 6px;
    padding: 12px 14px;
    color: #1e40af;
    font-size: 0.875rem;
    margin-bottom: 10px;
}

.dup-ours .dup-warning-title { color: #1e40af; }
.dup-ours .dup-warning-meta { color: #1d4ed8; }
.dup-ours a { color: #1e40af; font-weight: 600; text-decoration: underline; }

/* ── Field grid: a record's details, label above value ───────────────────────
   The register show pages laid details out as `auto 1fr` pairs — label and
   value side by side in four columns, styled identically. Ten of them wrapping
   across a card gave no way to tell which word was the label and which the
   answer.

   Label above value instead, the label small and set in caps so it reads as a
   heading rather than as content, and the value in the page's ordinary text.
   The same shape the edit form uses, so a field looks like itself whether it is
   being read or changed.

   minmax(min(220px, 100%), 1fr): a bare 220px floor refuses to shrink below it
   and pushes the card into horizontal scroll on a phone. */
.field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
    gap: 16px 24px;
    margin: 0;
}

.field-grid .field { min-width: 0; }

/* A value that needs the room — a subject, a citation — takes the whole row. */
.field-grid .field-wide { grid-column: 1 / -1; }

.field-grid dt {
    margin: 0 0 3px;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #6b7280;
}

.field-grid dd {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.45;
    color: #111827;
    overflow-wrap: anywhere;
}

.field-grid dd.text-mono { font-size: 0.875rem; }

/* ── A list of things, each its own thing ───────────────────────────────────
   Seven typology methods set as one comma-separated sentence wrapped over four
   lines, and the reader had to parse punctuation to find where one ended and the
   next began -- with the part that differs ("Structuring / Smurfing") buried
   after a category prefix repeated on every entry.

   A pill is not a badge. A badge is a status: one per thing, short, shouty, in a
   colour that means something. These are a set of equal values of ordinary
   length, so they are quiet, they wrap as a group, and they do not claim a
   meaning by colour. .badge is still used for the typology tags, which really
   are three-letter codes. */
.pill-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    /* The dd's own line-height would leave the first row sitting high. */
    margin-top: 2px;
}

.pill {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 3px 10px;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    background: #f9fafb;
    color: #374151;
    font-size: 0.8125rem;
    line-height: 1.45;
    /* Wraps inside the pill rather than overflowing: "Trade-based Money
       Laundering" does not fit a narrow column on one line, and nowrap would put
       the card into horizontal scroll on a phone. */
    white-space: normal;
}

/* The category that owns the method, as a mark inside the pill rather than the
   first half of its text, so the eye can group by it without reading. */
.pill-tag {
    flex: 0 0 auto;
    padding: 0 5px;
    border-radius: 8px;
    background: #e0e7ff;
    color: #3730a3;
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    cursor: help;
}

/* The bubble is the application's own [data-tooltip]. On a pill it opens from the
   left edge for the same reason a form label's does: these sit in a grid whose
   first column is hard against the side of the page, and a centred bubble is cut
   off by the viewport. */
.pill[data-tooltip]::after,
.pill-tag[data-tooltip]::after,
.badge[data-tooltip]::after {
    left: 0;
    transform: translateY(4px);
    text-transform: none;
    letter-spacing: normal;
}

.pill[data-tooltip]:hover::after,
.pill[data-tooltip]:focus-visible::after,
.pill-tag[data-tooltip]:hover::after,
.pill-tag[data-tooltip]:focus-visible::after,
.badge[data-tooltip]:hover::after,
.badge[data-tooltip]:focus-visible::after {
    transform: translateY(0);
}

.pill[data-tooltip]::before,
.pill-tag[data-tooltip]::before,
.badge[data-tooltip]::before {
    left: 10px;
}

/* A pill carrying an explanation says so, the way the (?) marks do. */
.pill[data-tooltip],
.badge[data-tooltip] {
    cursor: help;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .pill {
        background: #1f2937;
        border-color: #374151;
        color: #e5e7eb;
    }
    :root:not([data-theme="light"]) .pill-tag { background: #312e81; color: #c7d2fe; }
}

:root[data-theme="dark"] .pill {
    background: #1f2937;
    border-color: #374151;
    color: #e5e7eb;
}

:root[data-theme="dark"] .pill-tag { background: #312e81; color: #c7d2fe; }

/* Prose kept as typed: a subject runs to several lines and its breaks matter. */
.field-grid dd.field-prose { white-space: pre-wrap; }

.field-grid dd .text-muted { color: #9ca3af; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .field-grid dt { color: #9ca3af; }
    :root:not([data-theme="light"]) .field-grid dd { color: #e5e7eb; }
}

:root[data-theme="dark"] .field-grid dt { color: #9ca3af; }
:root[data-theme="dark"] .field-grid dd { color: #e5e7eb; }

/* ── The Correspondence Register ────────────────────────────────────────────
   One book holding what came in and what went out. */

/* A button that is also a choice of two. `details` opens on click and closes on
   Escape without a line of script; the summary is styled as the button itself. */
.btn-split { position: relative; display: inline-block; }
.btn-split > summary {
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
}
.btn-split > summary::-webkit-details-marker { display: none; }
.btn-split > summary svg { transition: transform 0.15s ease; }
.btn-split[open] > summary svg { transform: rotate(180deg); }

.btn-split-menu {
    position: absolute;
    right: 0;
    z-index: 30;
    margin-top: 4px;
    min-width: 260px;
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    overflow: hidden;
}
.btn-split-menu a {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 10px 12px;
    color: inherit;
    text-decoration: none;
}
.btn-split-menu a + a { border-top: 1px solid var(--color-border, #e5e7eb); }
.btn-split-menu a:hover,
.btn-split-menu a:focus-visible { background: var(--color-surface-alt, #f3f4f6); }

/* A menu item that opens a dialog rather than going somewhere is a button, and has to
   look the same as the links beside it. */
.btn-split-menu button {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    width: 100%;
    padding: 10px 12px;
    color: inherit;
    text-align: left;
    background: none;
    border: 0;
    font: inherit;
    cursor: pointer;
}
.btn-split-menu a + button,
.btn-split-menu button + button,
.btn-split-menu button + a { border-top: 1px solid var(--color-border, #e5e7eb); }
.btn-split-menu button:hover,
.btn-split-menu button:focus-visible { background: var(--color-surface-alt, #f3f4f6); }

/* A menu opened inside a scrolling table was being CUT OFF by the table rather than drawn
   under it, which no z-index can fix: a container that scrolls in one axis clips the other,
   so `overflow-x: auto` on the table wrapper clips vertically too, and an absolutely
   positioned child cannot leave it.
   The wrapper therefore stops clipping while one of its menus is open, and goes back to
   scrolling the moment it closes - so a wide table still scrolls sideways on a narrow
   screen, which is what the wrapper is there for. The class is put on by app.js and by the
   person dialog's own handler rather than by :has(), so this does not depend on how new the
   browser is. Both menu kinds use it: details.btn-split and .row-actions. */
.table-responsive.has-open-menu,
.table-wrap.has-open-menu {
    overflow: visible;
}

/* And the open row is lifted above the rows below it, which are drawn after it. */
.btn-split[open] {
    z-index: 40;
}
.btn-split-menu svg { flex: none; margin-top: 2px; color: var(--color-text-muted, #6b7280); }
.btn-split-menu small {
    display: block;
    margin-top: 1px;
    font-weight: 400;
    color: var(--color-text-muted, #6b7280);
}

/* IN or OUT, said as a word so it survives a printout and colour blindness. */
.dir-pill {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    border: 1px solid transparent;
}
.dir-in  { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
.dir-out { background: #f5f3ff; color: #6d28d9; border-color: #ddd6fe; }

.data-table .col-direction { width: 1%; white-space: nowrap; }
/* The subject is what people read, so it gets whatever the other columns leave. */
.data-table .col-subject { width: 40%; min-width: 220px; }
.subject-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 3px;
}

/* Two dates that are two ends of one thing, and now say so. */
.date-range {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.date-range-label,
.date-range-sep {
    font-size: 0.75rem;
    color: var(--color-text-muted, #6b7280);
    white-space: nowrap;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .dir-in  { background: #1e293b; color: #93c5fd; border-color: #1e40af; }
    :root:not([data-theme="light"]) .dir-out { background: #2a2140; color: #c4b5fd; border-color: #5b21b6; }
}
:root[data-theme="dark"] .dir-in  { background: #1e293b; color: #93c5fd; border-color: #1e40af; }
:root[data-theme="dark"] .dir-out { background: #2a2140; color: #c4b5fd; border-color: #5b21b6; }

/* ── A Dropdown With Its Own Filter ─────────────────────────────────────────
   Replaces a long select. The native field is still there and still submits; it is
   invisible but not display:none, so the browser can still point a validation message
   at it, and it is stretched over the button so that message lands in the right place. */
.combo { position: relative; }

.combo-native {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    pointer-events: none;
    -webkit-appearance: none;
    appearance: none;
    border: 0;
    padding: 0;
    margin: 0;
}

.combo-button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 9px 12px;
    font: inherit;
    text-align: left;
    color: var(--color-text, #111827);
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, #d1d5db);
    border-radius: 6px;
    cursor: pointer;
}
.combo-button.form-select-sm { padding: 5px 9px; font-size: 0.8125rem; }
.combo-button:hover { border-color: var(--color-border-strong, #9ca3af); }
.combo-button:focus-visible,
.combo.is-open .combo-button {
    outline: none;
    border-color: var(--color-primary, #2563eb);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
.combo-button.is-placeholder .combo-value { color: var(--color-text-muted, #6b7280); }
.combo-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.combo-caret {
    flex: none;
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid var(--color-text-muted, #6b7280);
    transition: transform 0.15s ease;
}
.combo.is-open .combo-caret { transform: rotate(180deg); }

.combo-pop {
    position: absolute;
    z-index: 40;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    min-width: 240px;
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, #d1d5db);
    border-radius: 8px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.14);
    overflow: hidden;
}

/* The filter sits inside the dropdown, which is the whole point of it. */
.combo-search {
    display: block;
    width: 100%;
    padding: 9px 12px;
    font: inherit;
    border: 0;
    border-bottom: 1px solid var(--color-border, #e5e7eb);
    outline: none;
    background: transparent;
    color: inherit;
}

.combo-list {
    margin: 0;
    padding: 4px;
    max-height: 260px;
    overflow-y: auto;
    list-style: none;
}
.combo-item {
    padding: 7px 10px;
    border-radius: 5px;
    cursor: pointer;
    font-size: 0.875rem;
}
.combo-item:hover,
.combo-item.is-active { background: var(--color-surface-alt, #f3f4f6); }
.combo-item.is-chosen { font-weight: 600; }
.combo-item.is-chosen::after { content: " ✓"; color: var(--color-primary, #2563eb); }

.combo-none {
    margin: 0;
    padding: 12px;
    font-size: 0.8125rem;
    color: var(--color-text-muted, #6b7280);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .combo-button,
    :root:not([data-theme="light"]) .combo-pop { background: #111827; border-color: #374151; }
    :root:not([data-theme="light"]) .combo-search { border-bottom-color: #374151; }
    :root:not([data-theme="light"]) .combo-item:hover,
    :root:not([data-theme="light"]) .combo-item.is-active { background: #1f2937; }
}
:root[data-theme="dark"] .combo-button,
:root[data-theme="dark"] .combo-pop { background: #111827; border-color: #374151; }
:root[data-theme="dark"] .combo-search { border-bottom-color: #374151; }
:root[data-theme="dark"] .combo-item:hover,
:root[data-theme="dark"] .combo-item.is-active { background: #1f2937; }


/* ── Classification legend ─────────────────────────────────────────────
   Under the Classification field on the correspondence register. The three
   levels escalate, so the dots do too: neutral, amber, red. Colour is never
   the only signal - each row is named in words beside it - because a legend
   that can only be read in colour is no legend for some readers. */
.class-legend {
    margin: 8px 0 0;
    padding: 10px 12px;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    background: #f9fafb;
    font-size: 0.8125rem;
    line-height: 1.45;
}

.class-legend-row {
    display: grid;
    grid-template-columns: minmax(0, 8.5rem) minmax(0, 1fr);
    gap: 4px 10px;
    align-items: start;
}

.class-legend-row + .class-legend-row {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid #eef0f3;
}

.class-legend dt {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    color: #111827;
}

.class-legend dd {
    margin: 0;
    color: #4b5563;
}

.class-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    flex: 0 0 auto;
}

.class-dot-routine      { background: #6b7280; }
.class-dot-confidential { background: #d97706; }
.class-dot-secret       { background: #dc2626; }

:root[data-theme="dark"] .class-legend {
    border-color: #374151;
    background: #111827;
}

:root[data-theme="dark"] .class-legend-row + .class-legend-row { border-top-color: #1f2937; }
:root[data-theme="dark"] .class-legend dt { color: #f3f4f6; }
:root[data-theme="dark"] .class-legend dd { color: #9ca3af; }

:root[data-theme="dark"] .class-dot-routine      { background: #9ca3af; }
:root[data-theme="dark"] .class-dot-confidential { background: #f59e0b; }
:root[data-theme="dark"] .class-dot-secret       { background: #ef4444; }

/* The two-column legend stacks on a narrow screen rather than squeezing the
   description into a column too thin to read. */
@media (max-width: 640px) {
    .class-legend-row { grid-template-columns: minmax(0, 1fr); }
}


/* ── A link that is really a button ────────────────────────────────────
   Used beside a field label to open the explanation for that field. A
   <button> rather than an <a href="#">: it does something on this page
   instead of going somewhere, which is what a button is for, and it keeps
   the keyboard and screen-reader behaviour right without extra roles.
   Lighter than the label so it reads as an aside, not part of the name. */
.link-button {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    margin-left: 8px;
    font: inherit;
    font-weight: 400;
    font-size: 0.8125rem;
    color: #2563eb;
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}

.link-button:hover { color: #1d4ed8; }

.link-button:focus-visible {
    outline: 2px solid #2563eb;
    outline-offset: 2px;
    border-radius: 2px;
}

:root[data-theme="dark"] .link-button { color: #60a5fa; }
:root[data-theme="dark"] .link-button:hover { color: #93c5fd; }
:root[data-theme="dark"] .link-button:focus-visible { outline-color: #60a5fa; }

/* ============================================================
   Accordion rows — a list whose entries expand in place
   ============================================================
   Built for the team list: clicking a syndicate shows who is on it without
   leaving the page. The chevron turns to say which state it is in, because a
   row that expands with no indication that it can looks like a dead click. */
.accordion-toggle {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    text-align: left;
}
.accordion-toggle:hover { color: #2563eb; }
.accordion-toggle:focus-visible {
    outline: 2px solid #2563eb;
    outline-offset: 2px;
    border-radius: 3px;
}
.accordion-toggle .icon-chevron {
    flex: 0 0 auto;
    transition: transform 0.15s ease;
    color: #9ca3af;
}
.accordion-toggle[aria-expanded="true"] .icon-chevron { transform: rotate(180deg); }

/* A whole row can be the expander. It needs to look like it. */
.accordion-row { cursor: pointer; }
.accordion-row:hover > td { background: #f3f6fb; }

/* The open row reads as the heading of what is beneath it, not as another record */
.accordion-row.is-expanded > td {
    background: #e8eef7;
    font-weight: 500;
    box-shadow: inset 3px 0 0 #2563eb;
}
.accordion-row.is-expanded > td:first-child { box-shadow: inset 3px 0 0 #2563eb; }

/* The expanded panel is a table row, so it must read as a different surface from the
   list it sits inside: a darker well, with the member table lifted off it in white. */
.accordion-panel > td {
    background: #dde5f0;
    border-top: 0;
    padding: 10px 16px 16px;
    box-shadow: inset 3px 0 0 #2563eb;
}
.accordion-panel .accordion-panel-inner { padding-top: 0; }
.accordion-panel .data-table {
    background: #fff;
    border: 1px solid #c7d2e3;
    border-radius: 6px;
    overflow: hidden;
}
/* The inner table's own header must not be mistaken for the outer list's */
.accordion-members thead th {
    background: #f1f5f9;
    font-size: 0.6875rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: #64748b;
}
.accordion-members tbody tr:last-child td { border-bottom: 0; }

:root[data-theme="dark"] .accordion-toggle:hover { color: #60a5fa; }
:root[data-theme="dark"] .accordion-toggle .icon-chevron { color: #6b7280; }
:root[data-theme="dark"] .accordion-row:hover > td { background: #1e293b; }
:root[data-theme="dark"] .accordion-row.is-expanded > td {
    background: #1e2a3d;
    box-shadow: inset 3px 0 0 #60a5fa;
}
:root[data-theme="dark"] .accordion-panel > td {
    background: #0f1724;
    box-shadow: inset 3px 0 0 #60a5fa;
}
:root[data-theme="dark"] .accordion-panel .data-table {
    background: #1f2937;
    border-color: #374151;
}
:root[data-theme="dark"] .accordion-members thead th {
    background: #263244;
    color: #94a3b8;
}

/* ============================================================
   Dashboard caseload table
   ============================================================
   Replaced the status donut. The list is as long as the caseload, so it
   scrolls inside its own frame rather than running the page down, and the
   header stays put while it does. */
.dash-table-scroll {
    /* Short enough that the cards below it are on the screen too, long enough that
       scrolling is worth doing: about eight rows. */
    max-height: 17rem;
    overflow-y: auto;
    overflow-x: auto;
    border-top: 1px solid #e5e7eb;
}
.dash-table-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: #f9fafb;
    box-shadow: inset 0 -1px 0 #e5e7eb;
}
.dash-case-table { margin: 0; }
.dash-case-table tbody tr { cursor: pointer; }

/* The syndicate's leader, under the syndicate's name */
.dash-case-sub {
    font-size: 0.6875rem;
    color: #6b7280;
    margin-top: 1px;
}

/* How long a case has been quiet, coloured so the column reads down at a glance:
   worked this week needs no thought, past twenty days needs somebody's attention
   whatever the status says. A case nobody has EVER touched reads red too, rather
   than sitting blank and going unnoticed. */
.dash-quiet {
    display: inline-block;
    min-width: 2.75rem;
    padding: 2px 7px;
    border-radius: 10px;
    font-size: 0.75rem;
    font-weight: 600;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.quiet-green  { background: #dcfce7; color: #166534; }
.quiet-yellow { background: #fef9c3; color: #854d0e; }
.quiet-orange { background: #ffedd5; color: #9a3412; }
.quiet-red    { background: #fee2e2; color: #991b1b; }
.quiet-never  { background: #fee2e2; color: #991b1b; font-style: italic; }

:root[data-theme="dark"] .dash-case-sub { color: #9ca3af; }
:root[data-theme="dark"] .quiet-green  { background: #14321f; color: #86efac; }
:root[data-theme="dark"] .quiet-yellow { background: #342c10; color: #fde047; }
:root[data-theme="dark"] .quiet-orange { background: #3a2412; color: #fdba74; }
:root[data-theme="dark"] .quiet-red,
:root[data-theme="dark"] .quiet-never  { background: #3b1518; color: #fca5a5; }

:root[data-theme="dark"] .dash-table-scroll { border-top-color: #374151; }
:root[data-theme="dark"] .dash-table-scroll thead th {
    background: #1f2937;
    box-shadow: inset 0 -1px 0 #374151;
}

/* ============================================================
   Document scanner
   ============================================================ */

/* The two ways in, offered side by side. An option that cannot be taken still
   appears, because "why can I not scan from the office scanner" is a question
   worth answering on the spot. */
.scan-option {
    display: block;
    padding: 14px 16px;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    margin-bottom: 10px;
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s, background 0.15s;
}
a.scan-option:hover { border-color: #2563eb; background: #eff6ff; }
a.scan-option:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
.scan-option.is-disabled { background: #f9fafb; color: #6b7280; cursor: not-allowed; }
.scan-option-name { display: block; font-weight: 600; margin-bottom: 3px; }
.scan-option-note { display: block; font-size: 0.8125rem; color: #6b7280; line-height: 1.45; }
.scan-option.is-disabled .scan-option-name { color: #6b7280; }

/* The capture page: camera beside the pages taken, the filing panel under both */
.scan-grid {
    display: grid;
    gap: 16px;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    align-items: start;
}
.scan-grid .scan-save { grid-column: 1 / -1; }
@media (max-width: 900px) {
    .scan-grid { grid-template-columns: minmax(0, 1fr); }
}

.scan-preview {
    position: relative;
    background: #111827;
    border-radius: 6px;
    overflow: hidden;
    aspect-ratio: 4 / 3;
    display: flex;
    align-items: center;
    justify-content: center;
}
.scan-preview video { width: 100%; height: 100%; object-fit: contain; display: block; }
.scan-preview-idle { color: #9ca3af; font-size: 0.875rem; margin: 0; }

.scan-status { font-size: 0.8125rem; margin: 10px 0 0; min-height: 1.2em; color: #6b7280; }
.scan-status-ok { color: #166534; }
.scan-status-error { color: #b91c1c; font-weight: 500; }

/* Pages taken so far, numbered in the order they were captured */
.scan-pages {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
    gap: 8px;
    max-height: 20rem;
    overflow-y: auto;
}
.scan-page {
    position: relative;
    border: 1px solid #e5e7eb;
    border-radius: 4px;
    overflow: hidden;
    background: #f9fafb;
    aspect-ratio: 3 / 4;
}
.scan-page img { width: 100%; height: 100%; object-fit: cover; display: block; }
.scan-page-num {
    position: absolute;
    left: 4px;
    bottom: 4px;
    background: rgba(17, 24, 39, 0.78);
    color: #fff;
    font-size: 0.6875rem;
    padding: 1px 6px;
    border-radius: 8px;
    font-variant-numeric: tabular-nums;
}
.scan-page-remove {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 20px;
    height: 20px;
    border: 0;
    border-radius: 50%;
    background: rgba(17, 24, 39, 0.78);
    color: #fff;
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.scan-page-remove:hover { background: #b91c1c; }

:root[data-theme="dark"] .scan-option { border-color: #374151; }
:root[data-theme="dark"] a.scan-option:hover { border-color: #3b82f6; background: #1e293b; }
:root[data-theme="dark"] .scan-option.is-disabled { background: #111827; }
:root[data-theme="dark"] .scan-page { border-color: #374151; background: #1f2937; }
:root[data-theme="dark"] .scan-status-ok { color: #86efac; }
:root[data-theme="dark"] .scan-status-error { color: #fca5a5; }

/* A blank preview is reported rather than left to guesswork, so the note has to read
   as instructions and not as another muted hint nobody finishes. */
/* The unnamed-camera hint sits under the picker and has to be read, so it is not left
   in the same muted grey as the help text it follows. */
.scan-help-unnamed {
    display: block;
    margin-top: 6px;
    color: #92400e;
}

:root[data-theme="dark"] .scan-help-unnamed { color: #fcd34d; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .scan-help-unnamed { color: #fcd34d; }
}

.scan-warn-blank {
    margin-top: 12px;
    padding: 12px 14px;
    border: 1px solid #f59e0b;
    border-left-width: 4px;
    border-radius: 6px;
    background: #fffbeb;
    color: #78350f;
    font-size: 0.85rem;
    line-height: 1.5;
}

.scan-warn-blank p { margin: 6px 0; }
.scan-warn-blank ol { margin: 6px 0 6px 20px; }
.scan-warn-blank li { margin-bottom: 6px; }
.scan-warn-blank strong { color: #7c2d12; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .scan-warn-blank {
        background: #2a1f07;
        color: #fde68a;
    }
    :root:not([data-theme="light"]) .scan-warn-blank strong { color: #fcd34d; }
}

:root[data-theme="dark"] .scan-warn-blank {
    background: #2a1f07;
    color: #fde68a;
}
:root[data-theme="dark"] .scan-warn-blank strong { color: #fcd34d; }

/* A password field with a reveal button sitting inside its right-hand edge. The button
   is inside the box rather than beside it so the field keeps the full width the rest of
   the form uses. */
.password-field { position: relative; }

.password-field input { width: 100%; padding-right: 64px; }

.password-reveal {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    border: 0;
    background: transparent;
    color: #11315c;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    padding: 4px 8px;
    border-radius: 4px;
    cursor: pointer;
}

.password-reveal:hover { background: rgba(17, 49, 92, 0.08); }
.password-reveal:focus-visible { outline: 2px solid #11315c; outline-offset: 1px; }

/* Acting under a second role. Amber, like the training banner, and for the same reason:
   it is a state the person needs to be able to notice they are in. */
.topnav-role-acting { color: #fcd34d !important; font-weight: 600; }

.topnav-dropdown-label {
    padding: 6px 14px 2px;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: #9ca3af;
}

.topnav-dropdown-item.is-current { font-weight: 600; }
.topnav-acting-tick { margin-left: auto; color: #10b981; }

/* Per-section picks on the permissions matrix, and starting from another role.
   Quiet until wanted: the section name stays the thing you read, and the actions sit
   at the other end of the row in small type rather than competing with it. */
/* A DIV inside the cell, never the cell itself: display:flex on a <td> drops it out of
   table layout, colspan stops applying, and the heading band covers part of the row
   instead of all of it. */
.module-header-inner {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
}
.module-name { flex: 1 1 auto; }

.module-actions { display: flex; gap: 4px; flex: 0 0 auto; }

.module-actions button {
    border: 1px solid transparent;
    background: transparent;
    color: #11315c;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 4px;
    cursor: pointer;
}

.module-actions button:hover { background: rgba(17, 49, 92, 0.1); border-color: rgba(17, 49, 92, 0.25); }
.module-actions button:focus-visible { outline: 2px solid #11315c; outline-offset: 1px; }

.perm-copy {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 12px;
    padding: 10px 14px;
    background: #f8fafc;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
}

.perm-copy label { font-size: 0.82rem; font-weight: 600; color: #11315c; }
.perm-copy .form-select { width: auto; min-width: 220px; }
.perm-copy-note { font-size: 0.78rem; color: #6b7280; }

/* ============================================================
   Environment banner
   What this installation is, said at the top of the page. Two
   tones, because the two jobs are opposites: a warning has to be
   impossible to miss, and a confirmation has to be impossible to
   mistake for a warning. A live system that shouts at its users
   all day teaches them to ignore the strip, and then the warning
   stops working too.
   ============================================================ */
:root { --env-banner-h: 44px; }
@media (max-width: 720px) { :root { --env-banner-h: 68px; } }

/* The live badge is small, so the nav sits closer under it. Declared on the body rather
   than :root so .topnav's `top: var(--env-banner-h)` picks the right one up by
   inheritance, without a second rule per tone. */
body.has-env-banner-live { --env-banner-h: 38px; }

.env-banner {
    position: sticky;
    top: 0;
    z-index: 1001;              /* .topnav is 1000 and sits below this */
    height: var(--env-banner-h);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    /* .auth-body and .minimal-body are centring flex containers, so on those pages the
       banner is a flex item and would otherwise be stretched or centred with the card. */
    width: 100%;
    flex: 0 0 var(--env-banner-h);
}

.env-banner-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    text-align: center;
    line-height: 1.2;
}

/* The height is FIXED because .topnav sticks below it at exactly this offset: a strip
   that grew when its text wrapped would let the nav slide under it on every scroll. */
body.has-env-banner .topnav { top: var(--env-banner-h); }

/* Stacking these two puts the strip on top, and margin:auto keeps the card centred in
   what is left rather than pushed under it. */
body.has-env-banner.auth-body,
body.has-env-banner.minimal-body {
    flex-direction: column;
    padding-top: 0;
}

body.has-env-banner.auth-body .auth-container,
body.has-env-banner.minimal-body .minimal-container { margin: auto; }

/* ── warning: hazard tape ───────────────────────────────────────────────────
   Loud on purpose. The first version was amber text on near-black at 0.8rem and it
   read as chrome, part of the furniture rather than a warning, so people looked
   straight past it. Not red: red is how this application reports an error, and a
   permanent red strip teaches people to read errors as decoration.

   The unit's gold and maroon landed here on 24 October, asked for by name. It is the
   one place in the application they appear, and it suits them: gold is where the amber
   already was, and maroon is a colour you can look at all day without reading it as an
   error the way a bright red would be.

   MAROON ON GOLD MEASURES 10.6:1, against the 9.1:1 the near-black-on-amber managed,
   so the swap made the strip slightly MORE readable rather than trading legibility for
   branding. Gold cannot carry light text -- white on it is 1.5:1, not a near miss but
   illegible -- which is why the text here is maroon, and why gold is not a candidate
   for a button anywhere else in the application. */
.env-banner--warning {
    background: var(--gold);
    color: var(--maroon);
    border-bottom: 3px solid var(--maroon);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
    font-size: 0.95rem;
    font-weight: 700;
}

.env-banner--warning::before,
.env-banner--warning::after {
    content: '';
    flex: 0 0 72px;
    align-self: stretch;
    background: repeating-linear-gradient(45deg,
        rgba(80, 0, 0, 0.85) 0 10px, transparent 10px 20px);
}

.env-banner--warning strong {
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
}

/* ── live: a small green badge ──────────────────────────────────────────────
   Quiet by design, and self-contained: the colour lives on the pill, not on the bar,
   so it reads the same above the sign-in card's dark gradient as it does on a white
   page behind sign-in. A full-width green bar would be a second thing competing with
   the warning for the same piece of screen. */
.env-banner--live {
    background: transparent;
    border-bottom: 0;
    box-shadow: none;
}

.env-banner--live .env-banner-mark {
    gap: 8px;
    padding: 5px 14px;
    border-radius: 999px;
    background: #047857;
    border: 1px solid #10b981;
    color: #ecfdf5;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}

.env-banner--live strong {
    text-transform: uppercase;
    letter-spacing: 0.08em;
    white-space: nowrap;
}

.env-banner--live span { font-weight: 400; opacity: 0.9; }

@media (max-width: 860px) {
    /* The stripes go first, then the label is allowed to wrap. Clipping words to keep
       an ornament would be the wrong way round. */
    .env-banner--warning::before,
    .env-banner--warning::after { display: none; }
}

@media (max-width: 720px) {
    .env-banner--warning { font-size: 0.85rem; }
    .env-banner--warning strong { white-space: normal; }
}

@media print {
    /* On paper it is the first thing that should be read, and it must not be mistaken
       for a page header, so it keeps its weight and loses the fill. */
    .env-banner {
        position: static;
        background: transparent;
        box-shadow: none;
    }
    .env-banner--warning {
        color: #000;
        border-bottom: 3px solid #000;
    }
    .env-banner--warning::before,
    .env-banner--warning::after { display: none; }
    .env-banner--live .env-banner-mark {
        background: transparent;
        color: #000;
        border-color: #000;
    }
}

/* Who the file goes to when this step is completed, named beside the button that
   hands it over. Sits directly above the action so it is read as part of pressing
   it, not as another notice further up the card. */
.step-recipients {
    background: #f0f9ff;
    border: 1px solid #bae6fd;
    border-radius: 6px;
    padding: 8px 10px;
    margin-bottom: 12px;
    font-size: 0.8125rem;
    color: #0c4a6e;
}
.step-recipients-label {
    display: block;
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #0284c7;
    margin-bottom: 3px;
}
.step-recipients ul {
    margin: 0;
    padding-left: 0;
    list-style: none;
}
.step-recipients li { margin: 2px 0; }

/* Inside a decision route the panel is already tinted, so the box would be a
   box inside a box. */
.route-option-detail .step-recipients {
    background: transparent;
    border: 0;
    padding: 0;
    margin-bottom: 8px;
}
/* Once the officer is actually named it stops being a placeholder. */
.step-recipients em.is-named {
    font-style: normal;
    font-weight: 600;
}

/* The shared address book, on the correspondence form. The office sits beside every
   name because two people share a surname far more often than they share a desk, and
   how long since the entry was touched sits beside that, because an address book that
   looks authoritative and is out of date is worse than a text box. */
.contact-picker { position: relative; }
.contact-suggestions {
    position: absolute;
    z-index: 30;
    left: 0;
    right: 0;
    margin-top: 2px;
    max-height: 260px;
    overflow-y: auto;
    background: #fff;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    box-shadow: 0 8px 20px rgba(17, 24, 39, 0.12);
}
.contact-suggestion {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    padding: 8px 11px;
    border: 0;
    border-bottom: 1px solid #f3f4f6;
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.contact-suggestion:last-child { border-bottom: 0; }
.contact-suggestion:hover,
.contact-suggestion:focus { background: #f3f4f6; }
.contact-suggestion-name { color: #1f2937; }
.contact-suggestion-age {
    flex: none;
    font-size: 0.75rem;
    color: #9ca3af;
    white-space: nowrap;
}
/* The empty state is the way out, not a dead end: the list sits over the help text
   that holds the "Add them" link, so a registrar told to add them below was reading
   the very thing covering it. */
.contact-suggestion.is-empty { color: #6b7280; font-size: 0.8125rem; }
.contact-suggestion-add {
    flex: none;
    color: #2563eb;
    font-weight: 600;
    font-size: 0.8125rem;
    white-space: nowrap;
}
.contact-suggestion.is-empty:hover .contact-suggestion-add { text-decoration: underline; }
.contact-chosen-label {
    display: inline-block;
    padding: 5px 10px;
    margin-right: 8px;
    background: #eff6ff;
    border: 1px solid #bfdbfe;
    border-radius: 999px;
    font-size: 0.8125rem;
    color: #1f2937;
}


/* ============================================================
   A button that has been pressed and is waiting
   ============================================================
   Asked for on 24 October: an officer presses Approve, nothing visibly happens
   while the server works, so they press it again -- and the second press is a
   second approval.

   THE PROTECTION IS NOT THIS STYLESHEET. Blocking the repeat submit is done in
   app.js; everything here is the telling-them part. A button that merely LOOKS
   busy while the second submit goes through is worse than no feedback at all,
   because it is reassuring and wrong.

   WHY NOT A PAGE OVERLAY. Most actions here finish in a few hundred milliseconds,
   and an overlay on every click would make a quick system feel like a slow one.
   An overlay that fails to clear also takes the whole page down with it, where a
   button that fails to clear costs one button. The busy state is held back ~150ms
   so the ordinary fast action never flickers at all.

   THE BUTTON IS NEVER `disabled`. A disabled submit button is not submitted, and
   this application has buttons that carry the decision itself -- name="decision"
   value="approve". Disabling one turns an approval into a POST with no decision
   in it, which is the exact silent failure this feature exists to prevent. */

.btn.is-busy {
    cursor: progress;
    /* Locked to the width it had, so a toolbar does not jump as the label changes.
       min-width rather than width: a longer label may still grow, but it can never
       collapse, and clipping the word "wait" to protect the layout is the wrong
       way round. */
    white-space: nowrap;
    opacity: 0.85;
}

.btn.is-busy::before {
    content: '';
    display: inline-block;
    width: 0.75em;
    height: 0.75em;
    margin-right: 0.5em;
    vertical-align: -0.08em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: btnSpin 0.6s linear infinite;
}

@keyframes btnSpin {
    to { transform: rotate(360deg); }
}

/* Movement is the part some people cannot use. The words still change, the spinner
   stops being a spinner and becomes a plain mark, and nothing is lost but the
   rotation. */
@media (prefers-reduced-motion: reduce) {
    .btn.is-busy::before {
        animation: none;
        border-right-color: currentColor;
        opacity: 0.6;
    }
}

/* An outline button's text is its colour, so currentColor gives the spinner the
   right one for free -- on primary, white; on outline, the blue. Nothing to add. */


/* ============================================================
   The investigation diary, on screen
   ============================================================
   Two columns, the same two the printed diary and the unit's own Word diaries
   use. The point of matching them is proofreading: an officer checking the file
   before a review should be reading the document they will later submit, not a
   different arrangement of the same facts. */

.diary-ledger td {
    vertical-align: top;
}

.diary-when {
    font-size: 0.8125rem;
    line-height: 1.5;
    white-space: nowrap;
}

/* Underlined because it is underlined on paper -- the place is the part of the
   left column an officer stated rather than the system recording itself. */
.diary-venue {
    text-decoration: underline;
}

.diary-activity p {
    margin: 0 0 6px;
}

.diary-activity p:last-child {
    margin-bottom: 0;
}

.diary-heading {
    font-weight: 700;
    text-decoration: underline;
}

/* Right, under the entry it closes, as it sits on paper. */
.diary-signature {
    text-align: right;
    text-decoration: underline;
    font-size: 0.8125rem;
}

/* ── A person, in full, without leaving the list ─────────────────────────────
   The Actions menu on a row, and the dialog it opens. The menu is a sibling of
   the button rather than inside it, so a click on an item is not also a click
   on the toggle that would close it again. */
.row-actions {
    position: relative;
    display: inline-block;
}

.row-actions-toggle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.row-actions-menu {
    display: none;
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    min-width: 160px;
    background: #fff;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
    /* Above the table and its sticky header. This alone does not free the menu from the
       scrolling wrapper - see .table-responsive.has-open-menu above, which is what stops
       the table cutting it off. */
    z-index: 50;
    overflow: hidden;
}

/* The row whose menu is open is lifted above the rows after it, which the table draws
   later and would otherwise paint on top. */
.row-actions.open {
    z-index: 40;
}

.row-actions.open .row-actions-menu {
    display: block;
}

.row-actions-menu button {
    display: block;
    width: 100%;
    padding: 8px 12px;
    border: 0;
    background: none;
    text-align: left;
    font: inherit;
    font-size: 0.8125rem;
    color: #1f2937;
    cursor: pointer;
}

.row-actions-menu button:hover {
    background: #f1f5f9;
}

/* The dialog's own body: label and value in two columns, wrapping to one when
   there is not room, so a long address does not squeeze the labels to nothing. */
.person-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 2px 20px;
}

.person-field {
    display: grid;
    grid-template-columns: 130px minmax(0, 1fr);
    gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid #f1f5f9;
    align-items: baseline;
}

.person-field-label {
    color: #64748b;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.person-field-value {
    font-size: 0.875rem;
    word-break: break-word;
}

.person-section {
    font-size: 0.875rem;
    font-weight: 600;
    color: #1f3a5f;
    margin: 18px 0 8px;
}

.person-appearances {
    margin: 0;
    padding-left: 18px;
    font-size: 0.875rem;
}

.person-appearances li {
    padding: 2px 0;
}


/* ============================================================
   The case status picker
   ============================================================
   Three levels, each revealed by the one above it. The child levels are
   indented and ruled on the left so they read as detail belonging to the
   status above rather than as three unrelated questions. */

.status-picker .status-picker-child {
    margin-left: 18px;
    padding-left: 12px;
    border-left: 2px solid #e2e8f0;
}

/* A level with nothing under it is removed rather than disabled: an empty
   dropdown an officer cannot use is a question the form should not be asking. */
.status-picker .status-picker-child.is-hidden {
    display: none;
}

.status-picker .status-picker-child-label {
    font-weight: 500;
    color: #475569;
}


/* ============================================================
   An amount and the currency it is in
   ============================================================
   One row: the code on the left, the figure beside it. The currency is
   narrow because a three-letter code needs no more, and the figure takes
   the rest -- the number is what is being read, the code is what qualifies
   it. */

.amount-field-row {
    display: flex;
    gap: 8px;
    align-items: stretch;
}

.amount-field-row .amount-field-currency {
    flex: 0 0 7.5rem;
}

.amount-field-row .amount-field-value {
    flex: 1 1 auto;
    min-width: 0;   /* a bare flex item refuses to shrink below its content */
}

@media (max-width: 480px) {
    /* Side by side, two controls in a 320px gutter leave the figure unreadable. */
    .amount-field-row { flex-wrap: wrap; }
    .amount-field-row .amount-field-currency { flex: 1 1 100%; }
}
