/* ==========================================================================
   Tangaza Staff Portal - brand layer
   --------------------------------------------------------------------------
   The 154 views in this portal are built from Skote's Bootstrap 4 components -
   .card (366 uses), .table (488), .form-control (362), .btn-primary (106),
   .btn-danger (116), modals (107), select2 (35). None of them use the .tz-*
   classes that portal.css provides, so restyling the portal means restyling
   those components rather than adding new ones. That is what this file does:
   every page changes appearance without a single view being edited.

   Bootstrap 4 has no CSS custom properties to hook into, so the theme's own
   selectors are overridden directly. !important appears only where Skote or
   Bootstrap already used high specificity - not as a shortcut.

   Load order: bootstrap.min.css -> icons.min.css -> app.min.css -> portal.css
   -> this file.
   ========================================================================== */

:root {
    /* Official Tangaza palette. */
    --tz-crimson: #c52127;
    --tz-crimson-dark: #a41a1f;
    --tz-crimson-soft: #fdecec;
    --tz-gold: #d19c2c;
    --tz-gold-dark: #b0821f;
    --tz-gold-soft: #fdf6e7;
    --tz-purple: #51506e;
    --tz-purple-dark: #403f58;
    --tz-ink: #444444;

    /* Neutrals, pulled very slightly toward the purple so they sit with the brand
       rather than reading as generic grey. */
    --tz-canvas: #f5f5f8;
    --tz-surface: #ffffff;
    --tz-border: #e3e3ea;
    --tz-text: #3f3f4a;
    --tz-text-muted: #77778a;

    /* Semantic colours are kept distinct from the brand: crimson means "primary
       action" here, so it cannot also mean "danger" without the two blurring. */
    --tz-success: #2e7d32;
    --tz-success-soft: #e8f5e9;
    --tz-warn: #9a6100;
    --tz-warn-soft: #fff3e0;
    --tz-danger: #c62828;
    --tz-danger-soft: #fdecea;
    --tz-info: #1565c0;
    --tz-info-soft: #e8f1fb;

    /*  The sidebar is a dark panel, so it needs its own scale rather than the page
        neutrals above - those are all tuned for ink on white. These are the student
        portal's exact sidebar values (its CSS/shell.css), so the two portals read
        as one university. Brand gold measures 4.55:1 on this ground, which clears
        AA, so no substitute gold is needed here. */
    --tz-sidebar: #3a3a44;
    /*  Card and table headers share the sidebar's ground. Brand gold on it is
        4.55:1; on the lighter #444444 ink it is only 3.94:1, under AA. */
    --tz-header: #3a3a44;
    --tz-sidebar-deep: #32323b;
    --tz-sidebar-text: #d1d1d1;

    --tz-radius: 6px;
    --tz-radius-sm: 4px;
    --tz-shadow: 0 1px 3px rgba(16, 24, 40, .06), 0 1px 2px rgba(16, 24, 40, .04);
    --tz-shadow-lg: 0 4px 16px rgba(16, 24, 40, .10);
}

body {
    background-color: var(--tz-canvas);
    color: var(--tz-text);
}

/* ==========================================================================
   1. Topbar
   ========================================================================== */

#page-topbar {
    background: var(--tz-ink) !important;
    box-shadow: 0 2px 10px rgba(0, 0, 0, .3) !important;
    border-bottom: 3px solid var(--tz-gold) !important;
}

.navbar-brand-box {
    background: var(--tz-crimson) !important;
}

    /*  The crest is a transparent PNG and is mostly light - 52% of its opaque
        pixels are near-white, average #bdac9b - so it sits directly on the
        crimson brand box and reads perfectly well. It used to be given a white
        plate with a radius and a drop shadow here, which turned it into a
        sticker pasted onto the bar. */
    .navbar-brand-box .logo img {
        background: none;
        padding: 0;
        box-shadow: none;
        /*  A little lift so the darker fifth of the crest separates from the
            crimson without needing a panel behind it. */
        filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .35));
    }

#vertical-menu-btn,
#page-header-user-dropdown {
    color: #fff !important;
}

    #vertical-menu-btn:hover,
    #page-header-user-dropdown:hover,
    #page-header-user-dropdown:focus {
        background: rgba(255, 255, 255, .08) !important;
    }

.header-profile-user {
    border: 2px solid rgba(255, 255, 255, .35);
    object-fit: cover;
}

/*  The staff name. The markup carried style="color: wheat" inline, which is not a
    brand colour and could not be overridden from a stylesheet; that attribute has
    been removed from Sitemaster.cshtml in favour of this class. */
.tz-whoami-name {
    color: #fff;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: .01em;
    max-width: 26vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
}

/*  Identity chip in the top bar, ported from the student portal's .tz-header-sem.
    There it carries the current semester; here it carries the staff number, which
    is what staff are asked for on every form and phone call. Same 40px height as
    the user button, so the two sit on one line rather than stepping. */
.tz-header-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    background: rgba(255, 255, 255, .06);
    border: 1px solid rgba(255, 255, 255, .10);
    border-radius: 8px;
    height: 40px;
    padding: 0 13px;
    margin-right: 10px;
    color: rgba(255, 255, 255, .92);
    font-size: 12.5px;
    font-weight: 500;
    white-space: nowrap;
    line-height: 1;
}

    .tz-header-chip i {
        color: var(--tz-gold);
        font-size: 15px;
    }

    /*  Quiet label, so the value is not just a number floating in the bar. The
        student portal uses .5 alpha here; against this darker bar that measures
        3.82:1, so it is raised to .62 (4.94:1) for a 10px label. */
    .tz-header-chip .tz-chip-label {
        color: rgba(255, 255, 255, .62);
        font-size: 10px;
        font-weight: 600;
        letter-spacing: .09em;
        text-transform: uppercase;
    }

/* ==========================================================================
   2. Sidebar
   --------------------------------------------------------------------------
   This is the student portal's sidebar, ported. The values below are lifted
   from its CSS/shell.css so the two portals read as one university: a #3a3a44
   panel, gold section labels, gold icons, #d1d1d1 row labels, and a crimson
   pill with a gold rail for hover and for the page you are on.

   Every selector is prefixed with body[data-sidebar="dark"], which is
   deliberate rather than defensive. Sitemaster sets data-sidebar="dark" on the
   body, and Skote themes that state with selectors like

       body[data-sidebar=dark] #sidebar-menu ul li a   -> (1,1,4)

   An unprefixed `#sidebar-menu ul li a` is only (1,0,3), so it loses. An earlier
   version of this section was written unprefixed AND in page neutrals - ink
   #3f3f4a on a near-black panel - which produced a mongrel: Skote's blue-grey
   #a6b0cf links, this file's muted section labels, a 5%-crimson hover invisible
   on a dark ground, and Skote's flat white hover. Matching Skote's selectors
   exactly is enough to win, because this file loads after app.min.css.
   ========================================================================== */

body[data-sidebar="dark"] .vertical-menu {
    background: var(--tz-sidebar);
    box-shadow: 2px 0 10px rgba(0, 0, 0, .2);
    border-right: 0;
}

/*  Section labels in gold. Skote ships #6B6A03 here - a dark olive that all but
    disappears on the panel - and the base theme's #7f8387 is no better. */
body[data-sidebar="dark"] .menu-title,
body[data-sidebar="dark"] #sidebar-menu ul li.menu-title {
    color: var(--tz-gold);
    font-weight: 700;
    text-transform: uppercase;
    font-size: 11px;
    letter-spacing: 1.2px;
    padding: 20px 20px 8px 20px !important;
    margin: 0;
    opacity: .95;
}

    /*  A hairline above each section label. Eight sections run down this panel
        with nothing but whitespace between them, so where one group ends and the
        next begins is left to the reader to infer. The rule is drawn on a
        ::before rather than a border so it can be pulled up into the label's top
        padding and inset to the same 8px as the menu pills - a full-bleed line
        would cut across a panel whose whole rhythm is inset. */
    body[data-sidebar="dark"] #sidebar-menu ul li.menu-title::before {
        content: "";
        display: block;
        height: 1px;
        background: rgba(255, 255, 255, .10);
        margin: -10px -12px 14px -12px;
    }

    /*  The first section has nothing above it to be separated from. */
    body[data-sidebar="dark"] #sidebar-menu ul li.menu-title:first-child::before {
        display: none;
    }

/*  Rows are inset and rounded so the active state reads as a pill rather than a
    full-bleed band. The li carries position:relative for the gold rail below. */
body[data-sidebar="dark"] #sidebar-menu ul li {
    position: relative;
}

body[data-sidebar="dark"] #sidebar-menu ul li a {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    padding: 10px 15px;
    margin: 2px 8px;
    border-radius: 6px;
    color: var(--tz-sidebar-text);
    font-size: 13px;
    font-weight: 500;
    transition: all .2s ease-in-out;
}

    /*  Icons gold, held at their natural size - flex would otherwise shrink them
        when a label runs long. */
    body[data-sidebar="dark"] #sidebar-menu ul li a i {
        flex: 0 0 auto;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        margin-right: 12px;
        font-size: 16px;
        color: var(--tz-gold);
        transition: transform .2s ease, color .2s ease;
    }

    /*  The label takes the remaining width and ellipsises rather than wrapping to
        a second line - several of these are long ("Imprest Surrender", "Financial
        & Statutory Information"). */
    body[data-sidebar="dark"] #sidebar-menu ul li a span {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/*  Hover and the page you are on share one treatment: a crimson pill. Skote's
    default is a flat white text colour, which on this panel is nearly the same
    value as an ordinary row and gives no sense of place in a menu this long. */
/*  Note what is NOT in this list: a bare `li.mm-active > a`. metismenu and the
    current-page script both mark the list item, and a list item can legitimately
    hold more than one anchor - the Approvals block used to hold three - so
    styling every anchor under a marked li lit all three at once. The current page
    is identified on the anchor (.active); mm-active is only used for the parent
    row of an open submenu, which is always the .has-arrow anchor. */
body[data-sidebar="dark"] #sidebar-menu ul li a:hover,
body[data-sidebar="dark"] #sidebar-menu ul li > a.active,
body[data-sidebar="dark"] #sidebar-menu ul li.mm-active > a.has-arrow {
    background: linear-gradient(90deg, var(--tz-crimson) 0%, var(--tz-crimson-dark) 100%) !important;
    color: #fff !important;
    box-shadow: 0 3px 8px rgba(197, 33, 39, .25);
}

    body[data-sidebar="dark"] #sidebar-menu ul li a:hover i,
    body[data-sidebar="dark"] #sidebar-menu ul li > a.active i,
    body[data-sidebar="dark"] #sidebar-menu ul li.mm-active > a.has-arrow i {
        color: #fff !important;
        transform: scale(1.15);
    }

body[data-sidebar="dark"] #sidebar-menu ul li > a.active,
body[data-sidebar="dark"] #sidebar-menu ul li.mm-active > a.has-arrow {
    font-weight: 600;
}

    /*  Gold rail on the active row so it stays distinguishable from a hover -
        both are crimson, and without this the menu forgets where you are the
        moment the pointer moves. */
    body[data-sidebar="dark"] #sidebar-menu ul li > a.active::before {
        content: "";
        position: absolute;
        left: 8px;
        top: 6px;
        bottom: 6px;
        width: 3px;
        border-radius: 0 3px 3px 0;
        background: var(--tz-gold);
    }

/*  Skote sets .mm-active to white !important on the li, which cascades into the
    open parent of a submenu. */
body[data-sidebar="dark"] .mm-active,
body[data-sidebar="dark"] .mm-active .active {
    color: #fff !important;
}

/* --- Submenus ----------------------------------------------------------- */

body[data-sidebar="dark"] #sidebar-menu ul li ul.sub-menu {
    background: var(--tz-sidebar-deep);
    border-radius: 6px;
    margin: 2px 8px;
    padding: 4px 0;
}

body[data-sidebar="dark"] #sidebar-menu ul li ul.sub-menu li a {
    font-size: 12.5px;
    padding: 8px 15px 8px 34px;
    margin: 1px 4px;
    color: #b4b4b4;
}

    /*  Submenu rows sit inside an already-inset panel, so they take a flat tint
        rather than a second pill, and no rail. */
    body[data-sidebar="dark"] #sidebar-menu ul li ul.sub-menu li a:hover,
    body[data-sidebar="dark"] #sidebar-menu ul li ul.sub-menu li > a.active {
        background: rgba(255, 255, 255, .07) !important;
        color: #fff !important;
        box-shadow: none;
    }

    body[data-sidebar="dark"] #sidebar-menu ul li ul.sub-menu li > a.active::before {
        content: none;
    }

/*  The has-arrow chevron is drawn with an ::after glyph that inherits colour, so
    it only needs a tone of its own when the row is neither active nor hovered. */
body[data-sidebar="dark"] #sidebar-menu ul li a.has-arrow:after {
    color: var(--tz-gold);
    opacity: .7;
}

body[data-sidebar="dark"] #sidebar-menu ul li a.has-arrow:hover:after,
body[data-sidebar="dark"] #sidebar-menu ul li.mm-active > a.has-arrow:after {
    color: #fff;
    opacity: 1;
}

/* --- Collapsed rail ------------------------------------------------------
   Skote's own class name is .vertical-collpsed (its typo, kept because the JS
   toggles it). In this state the panel is icon-only and the submenu becomes a
   floating card, so it needs the panel ground rather than the page canvas. */

body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a {
    background: linear-gradient(90deg, var(--tz-crimson) 0%, var(--tz-crimson-dark) 100%);
    color: #fff;
}

    body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu > ul > li:hover > a i {
        color: #fff;
    }

body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu > ul ul {
    background: var(--tz-sidebar-deep);
}

body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu ul li.mm-active .active {
    color: #fff !important;
}

    body[data-sidebar="dark"].vertical-collpsed .vertical-menu #sidebar-menu ul li.mm-active .active i {
        color: #fff !important;
    }

/*  The brand box sits above the panel. Skote paints it pure black on a dark
    sidebar; crimson is the one place the primary colour carries the identity. */
body[data-sidebar="dark"] .navbar-brand-box {
    background: var(--tz-crimson) !important;
}

/* ==========================================================================
   2b. Page head, stat tiles and action rows
   --------------------------------------------------------------------------
   The student portal's dashboard language, ported so the two bodies match: a
   date line and greeting above the fold, a row of stat tiles, purple card
   headers with a gold icon, and action rows that read as a list with a chevron
   rather than a grid of loose boxes.
   ========================================================================== */

.tz-pagehead {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 16px;
    margin-bottom: 20px;
}

    .tz-pagehead > div:first-child {
        flex: 1 1 320px;
        min-width: 0;
    }

.tz-pagehead-date {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 12.5px;
    color: var(--tz-text-muted);
    margin-bottom: 6px;
}

    .tz-pagehead-date i {
        color: var(--tz-gold);
    }

.tz-pagehead h1 {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -.015em;
    color: var(--tz-ink);
    margin: 0 0 4px 0;
}

    .tz-pagehead h1 i {
        color: var(--tz-crimson);
        font-size: 20px;
    }

.tz-pagehead p {
    font-size: 13px;
    color: var(--tz-text-muted);
    margin: 0;
}

/* --- Stat tiles ---------------------------------------------------------- */

.tz-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 16px;
    margin-bottom: 22px;
}

.tz-stat {
    position: relative;
    overflow: hidden;
    border-radius: var(--tz-radius);
    padding: 18px 20px;
    box-shadow: var(--tz-shadow);
}

    .tz-stat .tz-stat-label {
        display: block;
        font-size: 11px;
        font-weight: 700;
        letter-spacing: .08em;
        text-transform: uppercase;
        margin-bottom: 8px;
    }

    .tz-stat .tz-stat-value {
        display: block;
        font-size: 30px;
        font-weight: 700;
        line-height: 1.05;
        font-variant-numeric: tabular-nums;
    }

    .tz-stat .tz-stat-sub {
        display: block;
        font-size: 12px;
        margin-top: 6px;
    }

    /*  The watermark icon is decorative, so it is kept faint and pushed behind
        the figures rather than competing with them. */
    .tz-stat > i {
        position: absolute;
        right: 14px;
        bottom: 12px;
        font-size: 42px;
        opacity: .16;
        pointer-events: none;
    }

.tz-stat-crimson {
    background: linear-gradient(135deg, var(--tz-crimson) 0%, var(--tz-crimson-dark) 100%);
    color: #fff;
}

/*  The gold tile carries dark type, not white. White on brand gold measures
    2.47:1 - it fails AA outright and is hard to read in daylight. Ink on gold is
    5.45:1. The gradient runs lighter rather than darker for the same reason: on a
    gold-to-gold-dark ramp the dark end drops ink to 3.88:1, so the ramp goes
    light-gold to brand gold and both ends clear. */
.tz-stat-gold {
    background: linear-gradient(135deg, #dcae44 0%, var(--tz-gold) 100%);
    color: #2e2e36;
}

    .tz-stat-crimson .tz-stat-label,
    .tz-stat-crimson .tz-stat-sub {
        color: rgba(255, 255, 255, .85);
    }

    .tz-stat-gold .tz-stat-label,
    .tz-stat-gold .tz-stat-sub {
        /* .62 measured 4.32:1 on the brand-gold end - just under AA. */
        color: rgba(0, 0, 0, .72);
    }

    .tz-stat-gold > i {
        opacity: .22;
    }

.tz-stat-plain {
    background: var(--tz-surface);
    border: 1px solid var(--tz-border);
    border-left: 4px solid var(--tz-gold);
    color: var(--tz-text);
}

    .tz-stat-plain .tz-stat-label {
        color: var(--tz-crimson);
    }

    .tz-stat-plain .tz-stat-value {
        color: var(--tz-ink);
    }

    .tz-stat-plain .tz-stat-sub {
        /* --tz-text-muted is 4.38:1 on white; this clears AA at 4.93:1. */
        color: #6f6f80;
    }

/* --- Action rows --------------------------------------------------------- */

.tz-actionlist {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.tz-actionrow {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    background: var(--tz-surface);
    border: 1px solid var(--tz-border);
    border-left: 3px solid var(--tz-crimson);
    border-radius: var(--tz-radius);
    color: var(--tz-text);
    font-size: 13px;
    font-weight: 500;
    text-decoration: none !important;
    transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}

    .tz-actionrow:hover,
    .tz-actionrow:focus-visible {
        border-left-color: var(--tz-gold);
        box-shadow: 0 4px 14px rgba(16, 24, 40, .08);
        transform: translateX(2px);
        color: var(--tz-crimson);
    }

    .tz-actionrow > i:first-child {
        flex: 0 0 auto;
        font-size: 17px;
        color: var(--tz-crimson);
    }

    .tz-actionrow span {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /*  Trailing chevron. Marked aria-hidden in the markup - it says "this opens
        something", which the link text already says to a screen reader. */
    .tz-actionrow > i:last-child {
        flex: 0 0 auto;
        font-size: 15px;
        color: var(--tz-text-muted);
    }

@media (max-width: 767px) {
    .tz-pagehead h1 {
        font-size: 18px;
    }

    .tz-stats {
        grid-template-columns: 1fr;
        gap: 12px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .tz-actionrow {
        transition: none;
    }

        .tz-actionrow:hover,
        .tz-actionrow:focus-visible {
            transform: none;
        }
}

/* ==========================================================================
   3. Page header
   ========================================================================== */

.page-title-box {
    padding-bottom: 18px;
}

    .page-title-box h4,
    .page-title-box .page-title {
        color: var(--tz-ink);
        font-size: 19px;
        font-weight: 600;
        letter-spacing: -.011em;
        text-transform: none;
    }

.breadcrumb {
    background: transparent;
    padding: 0;
    font-size: 12.5px;
}

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

    .breadcrumb-item a:hover {
        color: var(--tz-crimson);
    }

.breadcrumb-item.active {
    color: var(--tz-crimson);
    font-weight: 500;
}

/* ==========================================================================
   4. Cards
   The single biggest surface in the portal - 366 uses. Skote's card is a flat
   white box with a barely visible header; given every page is a stack of them,
   the header is where the structure has to come from.
   ========================================================================== */

.card {
    background: var(--tz-surface);
    border: 1px solid var(--tz-border);
    border-radius: var(--tz-radius);
    box-shadow: var(--tz-shadow);
    margin-bottom: 20px;
}

.card-header {
    background: var(--tz-header);
    border-bottom: none;
    border-radius: var(--tz-radius) var(--tz-radius) 0 0 !important;
    padding: 15px 25px;
    color: var(--tz-gold);
}

    /* Whatever the view puts in the header - h4, .card-title, a bare string - reads
       as one label rather than inheriting Bootstrap's dark body colour on purple. */
    .card-header,
    .card-header h1, .card-header h2, .card-header h3,
    .card-header h4, .card-header h5, .card-header h6,
    .card-header .card-title,
    .card-header label,
    .card-header b, .card-header strong {
        color: var(--tz-gold);
        font-size: 12.5px;
        font-weight: 600;
        letter-spacing: .06em;
        text-transform: uppercase;
        margin-bottom: 0;
    }

    .card-header i {
        color: var(--tz-gold);
        margin-right: 7px;
    }

    /*  Muted text inside a header. Several headers carry
        <i class="... text-muted"> for the collapse chevron, which is a grey
        intended for a white card - on the purple bar it all but disappears.
        Scoped so .text-muted keeps its normal meaning everywhere else. */
    .card-header .text-muted,
    .card-header small,
    .modal-header .text-muted {
        color: rgba(255, 255, 255, .75) !important;
    }

/*  Collapsible headers. The dashboard is built from accordion cards, but the header
    gave no sign it could be clicked - no cursor change, no hover. */
.card-header[data-toggle="collapse"],
.card-header[data-target],
.card-header a[data-toggle="collapse"] {
    cursor: pointer;
    user-select: none;
}

    .card-header[data-toggle="collapse"]:hover {
        background: #333240;
    }

    /*  The chevron points down when open and right when closed, so the header states
        its own state. Bootstrap sets aria-expanded on the toggle, which is the only
        reliable hook - .collapsed is not applied consistently across these views. */
    .card-header[data-toggle="collapse"] .fa-chevron-down,
    .card-header[data-toggle="collapse"] .mdi-chevron-down {
        transition: transform .18s ease;
    }

    .card-header[data-toggle="collapse"][aria-expanded="false"] .fa-chevron-down,
    .card-header[data-toggle="collapse"].collapsed .fa-chevron-down {
        transform: rotate(-90deg);
    }

    /* Controls dropped into a header still have to be legible on purple. */
    .card-header .btn-link,
    .card-header a:not(.btn) {
        color: #fff;
        text-decoration: underline;
    }

/* ==========================================================================
   3b. Accordion headers - the light variant
   --------------------------------------------------------------------------
   A purple bar is right for a card that heads a table or a form. It is wrong
   for an accordion, where six of them stack into a wall of purple and the
   page loses any sense of which section is open.

   Several views already knew that and gave their accordion a light header in
   a local <style> block. But `.accordion .card-header` (0,2,0) outranks the
   `.card-header` above (0,1,0), so those views won the *background* and left
   the *colour* behind - white text, meant for purple, sitting on a white bar.
   Invisible labels on the dashboard.

   Colour and ground have to travel together or exactly that happens, so the
   light variant is stated here in full: ground, label, icon and chevron.
   ========================================================================== */

.accordion > .card > .card-header,
.accordion .card-header {
    background: var(--tz-surface);
    border-bottom: 1px solid var(--tz-border);
    border-left: 3px solid transparent;
    padding: 13px 18px;
    transition: background .16s ease, border-color .16s ease;
}

    /* Every element a view might put the label in, so none of them inherits the
       white from the purple rule above. */
    .accordion .card-header,
    .accordion .card-header h1, .accordion .card-header h2,
    .accordion .card-header h3, .accordion .card-header h4,
    .accordion .card-header h5, .accordion .card-header h6,
    .accordion .card-header .card-title,
    .accordion .card-header label,
    .accordion .card-header b, .accordion .card-header strong {
        color: var(--tz-ink);
        font-size: 13px;
        letter-spacing: .01em;
        text-transform: none;
    }

    .accordion .card-header i {
        color: var(--tz-crimson);
    }

    /* The purple rule forces muted text to near-white with !important, which on a
       light bar hides the collapse chevron completely. */
    .accordion .card-header .text-muted,
    .accordion .card-header small {
        color: var(--tz-text-muted) !important;
    }

    .accordion .card-header:hover {
        background: var(--tz-canvas);
    }

    /*  The open section is marked by a gold rail and a warm ground, so which one
        is open reads at a glance instead of only from the chevron. Bootstrap sets
        aria-expanded on the toggle; .collapsed is not applied consistently across
        these views, so both hooks are used. */
    .accordion .card-header[aria-expanded="true"],
    .accordion .card-header:not(.collapsed) {
        background: var(--tz-gold-soft);
        border-left-color: var(--tz-gold);
    }

        .accordion .card-header[aria-expanded="true"] i,
        .accordion .card-header:not(.collapsed) i {
            color: var(--tz-gold-dark);
        }

/*  Spacing between accordion cards. Without this each section is a separate
    floating card and the group reads as six unrelated things. */
.accordion .card {
    margin-bottom: 10px;
    border: 1px solid var(--tz-border);
    box-shadow: none;
}

    .accordion .card:last-child {
        margin-bottom: 0;
    }

.card-body {
    padding: 18px;
    font-size: 13.5px;
}

.card-title {
    color: var(--tz-ink);
    font-size: 14px;
    font-weight: 600;
}

.card-title-desc {
    color: var(--tz-text-muted);
    font-size: 12.5px;
}

/*  Skote's soft-tint utilities, recoloured. They are used on dashboard tiles (24
    occurrences), where the stock blue and teal read as a different product. */
.bg-soft-primary {
    background-color: var(--tz-crimson-soft) !important;
    color: var(--tz-crimson) !important;
}

.bg-soft-secondary {
    background-color: #eeeef3 !important;
    color: var(--tz-purple) !important;
}

.bg-soft-success {
    background-color: var(--tz-success-soft) !important;
    color: var(--tz-success) !important;
}

.bg-soft-warning {
    background-color: var(--tz-gold-soft) !important;
    color: var(--tz-warn) !important;
}

.bg-soft-danger {
    background-color: var(--tz-danger-soft) !important;
    color: var(--tz-danger) !important;
}

.bg-soft-info {
    background-color: var(--tz-info-soft) !important;
    color: var(--tz-info) !important;
}

/* ==========================================================================
   5. Tables
   488 uses. These are the portal's real content: approval queues, unit lists,
   ledgers. Dense, scannable, and readable at a glance is what matters.
   ========================================================================== */

.table {
    color: var(--tz-text);
    font-size: 13px;
    margin-bottom: 0;
}

    .table thead th {
        background: var(--tz-header);
        color: var(--tz-gold);
        border-bottom: none !important;
        border-top: none !important;
        padding: 13px 14px;
        font-size: 11px;
        font-weight: 600;
        letter-spacing: .06em;
        text-transform: uppercase;
        white-space: nowrap;
        vertical-align: middle;
    }

    .table tbody td {
        border-top: 1px solid var(--tz-border);
        padding: 9px 12px;
        vertical-align: middle;
    }

    .table tbody tr:hover {
        background-color: var(--tz-gold-soft);
    }

    /* Digits in a column line up only with tabular figures; without this a table of
       amounts reads as ragged even when it is right-aligned. */
    .table td.text-right,
    .table th.text-right,
    .table td.text-end,
    .table th.text-end {
        font-variant-numeric: tabular-nums;
    }

.table-bordered,
.table-bordered td,
.table-bordered th {
    border-color: var(--tz-border);
}

.table-striped tbody tr:nth-of-type(odd) {
    background-color: #fafafc;
}

/*  Wide tables scroll inside their own container rather than pushing the page
    sideways. Several of these have a dozen columns. */
.table-responsive {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* DataTables chrome */
div.dataTables_wrapper div.dataTables_filter input,
div.dataTables_wrapper div.dataTables_length select {
    border: 1px solid #cfcfd9;
    border-radius: var(--tz-radius-sm);
    padding: 5px 9px;
    font-size: 12.5px;
}

.page-item.active .page-link {
    background-color: var(--tz-crimson);
    border-color: var(--tz-crimson);
    color: #fff;
}

.page-link {
    color: var(--tz-text);
    font-size: 12.5px;
}

    .page-link:hover {
        color: var(--tz-crimson);
        background-color: var(--tz-crimson-soft);
        border-color: var(--tz-border);
    }

/* ==========================================================================
   6. Buttons
   ========================================================================== */

.btn {
    border-radius: var(--tz-radius-sm);
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: .01em;
    padding: 8px 16px;
    transition: background-color .14s ease, border-color .14s ease, box-shadow .14s ease;
}

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

    .btn-primary:hover,
    .btn-primary:focus,
    .btn-primary:active,
    .btn-primary:not(:disabled):not(.disabled):active,
    .btn-primary:not(:disabled):not(.disabled).active,
    .show > .btn-primary.dropdown-toggle {
        background-color: var(--tz-crimson-dark) !important;
        border-color: var(--tz-crimson-dark) !important;
        color: #fff;
    }

    .btn-primary:focus,
    .btn-primary.focus {
        box-shadow: 0 0 0 .18rem rgba(197, 33, 39, .3) !important;
    }

/*  Gold is the secondary brand colour, so .btn-secondary carries it rather than
    Bootstrap's grey - it is the natural "other action" next to a crimson primary. */
.btn-secondary {
    background-color: var(--tz-gold);
    border-color: var(--tz-gold);
    color: #3d2c05;
}

    .btn-secondary:hover,
    .btn-secondary:focus,
    .btn-secondary:not(:disabled):not(.disabled):active {
        background-color: var(--tz-gold-dark) !important;
        border-color: var(--tz-gold-dark) !important;
        color: #fff;
    }

/*  .btn-danger is used more than .btn-primary here (116 vs 106), overwhelmingly for
    Reject and Delete. It stays a true red, distinct from brand crimson, or a
    destructive action would look identical to a routine one. */
.btn-danger {
    background-color: var(--tz-danger);
    border-color: var(--tz-danger);
}

    .btn-danger:hover,
    .btn-danger:not(:disabled):not(.disabled):active {
        background-color: #a02020 !important;
        border-color: #a02020 !important;
    }

.btn-success {
    background-color: var(--tz-success);
    border-color: var(--tz-success);
}

    .btn-success:hover,
    .btn-success:not(:disabled):not(.disabled):active {
        background-color: #24632a !important;
        border-color: #24632a !important;
    }

.btn-info {
    background-color: var(--tz-purple);
    border-color: var(--tz-purple);
}

    .btn-info:hover,
    .btn-info:not(:disabled):not(.disabled):active {
        background-color: var(--tz-purple-dark) !important;
        border-color: var(--tz-purple-dark) !important;
    }

.btn-outline-primary {
    color: var(--tz-crimson);
    border-color: var(--tz-crimson);
}

    .btn-outline-primary:hover,
    .btn-outline-primary:not(:disabled):not(.disabled):active {
        background-color: var(--tz-crimson) !important;
        border-color: var(--tz-crimson) !important;
        color: #fff;
    }

.btn-light {
    background-color: #f1f1f5;
    border-color: var(--tz-border);
    color: var(--tz-text);
}

.btn-sm {
    padding: 5px 11px;
    font-size: 11.5px;
}

/* ==========================================================================
   7. Forms
   362 .form-control uses. Most data entry in this portal happens in a modal.
   ========================================================================== */

label {
    color: var(--tz-text);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .02em;
    margin-bottom: 5px;
}

.form-control,
.custom-select {
    border: 1px solid #cfcfd9;
    border-radius: var(--tz-radius-sm);
    color: var(--tz-text);
    font-size: 13px;
    padding: 8px 11px;
    height: auto;
    transition: border-color .14s ease, box-shadow .14s ease;
}

    .form-control:focus,
    .custom-select:focus {
        border-color: var(--tz-crimson);
        box-shadow: 0 0 0 .18rem rgba(197, 33, 39, .14);
    }

    .form-control:disabled,
    .form-control[readonly] {
        background-color: #f4f4f7;
        color: var(--tz-text-muted);
    }

.form-control::placeholder {
    color: #a6a6b8;
}

.is-invalid,
.form-control.is-invalid {
    border-color: var(--tz-danger);
}

.invalid-feedback {
    color: var(--tz-danger);
    font-size: 11.5px;
}

/* select2, used on 35 screens, ships its own markup and ignores .form-control. */
.select2-container--default .select2-selection--single,
.select2-container--default .select2-selection--multiple {
    border: 1px solid #cfcfd9 !important;
    border-radius: var(--tz-radius-sm) !important;
    min-height: 38px;
}

.select2-container--default.select2-container--focus .select2-selection--multiple,
.select2-container--default.select2-container--open .select2-selection--single {
    border-color: var(--tz-crimson) !important;
    box-shadow: 0 0 0 .18rem rgba(197, 33, 39, .14);
}

.select2-container--default .select2-selection--single .select2-selection__rendered {
    line-height: 36px;
    color: var(--tz-text);
    font-size: 13px;
}

.select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 36px;
}

.select2-container--default .select2-results__option--highlighted[aria-selected] {
    background-color: var(--tz-crimson) !important;
}

.select2-container--default .select2-selection--multiple .select2-selection__choice {
    background-color: var(--tz-crimson-soft) !important;
    border-color: rgba(197, 33, 39, .3) !important;
    color: var(--tz-crimson) !important;
}

/* Focus rings. Skote strips these from several controls; keyboard users need them. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
.page-link:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid var(--tz-gold);
    outline-offset: 2px;
}

/* ==========================================================================
   8. Modals
   107 header/footer uses - this is where most of the portal's work is done.
   ========================================================================== */

.modal-content {
    border: none;
    border-radius: var(--tz-radius);
    box-shadow: 0 12px 40px rgba(16, 24, 40, .22);
}

.modal-header {
    background: var(--tz-purple);
    border-bottom: none;
    border-radius: var(--tz-radius) var(--tz-radius) 0 0;
    padding: 13px 18px;
}

    .modal-header,
    .modal-header .modal-title,
    .modal-header h4,
    .modal-header h5 {
        color: #fff;
        font-size: 13.5px;
        font-weight: 600;
        letter-spacing: .03em;
    }

    /* Bootstrap's close button is a black "x"; on purple it is invisible. */
    .modal-header .close {
        color: #fff;
        opacity: .85;
        text-shadow: none;
    }

        .modal-header .close:hover {
            color: #fff;
            opacity: 1;
        }

.modal-body {
    padding: 18px;
    font-size: 13.5px;
}

.modal-footer {
    background: #fafafc;
    border-top: 1px solid var(--tz-border);
    border-radius: 0 0 var(--tz-radius) var(--tz-radius);
    padding: 12px 18px;
}

/* ==========================================================================
   9. Badges, alerts, tabs
   ========================================================================== */

.badge {
    border-radius: 999px;
    padding: 4px 10px;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .04em;
}

.badge-primary {
    background-color: var(--tz-crimson);
}

.badge-secondary {
    background-color: var(--tz-purple);
}

.badge-success {
    background-color: var(--tz-success);
}

.badge-danger {
    background-color: var(--tz-danger);
}

.badge-warning {
    background-color: var(--tz-gold);
    color: #3d2c05;
}

.badge-info {
    background-color: var(--tz-info);
}

.alert {
    border: none;
    border-left: 3px solid transparent;
    border-radius: var(--tz-radius-sm);
    font-size: 13px;
    padding: 12px 16px;
}

.alert-primary {
    background-color: var(--tz-crimson-soft);
    border-left-color: var(--tz-crimson);
    color: var(--tz-crimson-dark);
}

.alert-success {
    background-color: var(--tz-success-soft);
    border-left-color: var(--tz-success);
    color: #1b5e20;
}

.alert-warning {
    background-color: var(--tz-gold-soft);
    border-left-color: var(--tz-gold);
    color: var(--tz-warn);
}

.alert-danger {
    background-color: var(--tz-danger-soft);
    border-left-color: var(--tz-danger);
    color: #8e1f1f;
}

.alert-info {
    background-color: var(--tz-info-soft);
    border-left-color: var(--tz-info);
    color: #0d47a1;
}

.text-primary {
    color: var(--tz-crimson) !important;
}

.bg-primary {
    background-color: var(--tz-crimson) !important;
}

a {
    color: var(--tz-crimson);
}

    a:hover {
        color: var(--tz-crimson-dark);
    }

.nav-tabs .nav-link {
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--tz-text-muted);
    font-size: 13px;
    font-weight: 600;
}

    .nav-tabs .nav-link:hover {
        border-bottom-color: var(--tz-border);
        color: var(--tz-text);
    }

    .nav-tabs .nav-link.active {
        background: transparent;
        border-bottom-color: var(--tz-crimson);
        color: var(--tz-crimson);
    }

.progress-bar {
    background-color: var(--tz-crimson);
}

.dropdown-item:active,
.dropdown-item.active {
    background-color: var(--tz-crimson);
}

.dropdown-item:hover {
    background-color: var(--tz-crimson-soft);
    color: var(--tz-crimson);
}

/* SweetAlert2 - the portal's confirm and result dialogs. */
.swal2-styled.swal2-confirm {
    background-color: var(--tz-crimson) !important;
}

.swal2-styled.swal2-cancel {
    background-color: var(--tz-text-muted) !important;
}

.swal2-popup {
    border-radius: var(--tz-radius) !important;
    font-size: 14px !important;
}

/* ==========================================================================
   9b. Theme residue
   --------------------------------------------------------------------------
   Restyling the components above leaves Skote's own blue (#556ee6) alive in 64
   further selectors. Most never appear in these views, but some do, and a stray
   blue check box or date picker undoes the work everywhere else. Counted against
   the actual markup, these are the ones that matter.
   ========================================================================== */

/*  Date picker - 43 uses, the largest remaining surface. Selecting a date is one
    of the most common actions in this portal (leave, imprest, claims) and the
    selected day was still Skote blue. */
.datepicker table tr td.active,
.datepicker table tr td.active:hover,
.datepicker table tr td.active.disabled,
.datepicker table tr td.active.disabled:hover,
.datepicker table tr td.selected,
.datepicker table tr td.selected:hover,
.datepicker table tr td.selected.disabled,
.datepicker table tr td.selected.disabled:hover {
    background-color: var(--tz-crimson) !important;
    background-image: none !important;
    border-color: var(--tz-crimson) !important;
    color: #fff !important;
    text-shadow: none !important;
}

/*  Today is a hint, not a selection - gold keeps the two distinguishable. */
.datepicker table tr td.today,
.datepicker table tr td.today:hover,
.datepicker table tr td.today.disabled,
.datepicker table tr td.today.disabled:hover {
    background-color: var(--tz-gold-soft) !important;
    background-image: none !important;
    border-color: var(--tz-gold) !important;
    color: var(--tz-warn) !important;
}

.datepicker table tr td.day:hover,
.datepicker table tr td.focused {
    background: var(--tz-crimson-soft) !important;
    color: var(--tz-crimson) !important;
}

.datepicker table tr td span.active,
.datepicker table tr td span.active:hover {
    background-color: var(--tz-crimson) !important;
    background-image: none !important;
    border-color: var(--tz-crimson) !important;
}

/*  Check boxes, radios and switches. Bootstrap's custom controls hide the real
    input and colour a pseudo-element, so the tick is invisible to a normal
    background override. */
.custom-control-input:checked ~ .custom-control-label::before {
    background-color: var(--tz-crimson);
    border-color: var(--tz-crimson);
}

.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before {
    background-color: var(--tz-crimson);
    border-color: var(--tz-crimson);
}

.custom-control-input:focus ~ .custom-control-label::before {
    box-shadow: 0 0 0 .18rem rgba(197, 33, 39, .2);
}

.custom-control-input:focus:not(:checked) ~ .custom-control-label::before {
    border-color: var(--tz-crimson);
}

input[switch]:checked + label,
input[switch="primary"]:checked + label {
    background-color: var(--tz-crimson) !important;
}

.custom-range::-webkit-slider-thumb {
    background-color: var(--tz-crimson);
}

.custom-range::-moz-range-thumb {
    background-color: var(--tz-crimson);
}

.custom-range::-ms-thumb {
    background-color: var(--tz-crimson);
}

/* Soft badges - Skote's tinted variants, used on status columns. */
.badge-soft-primary {
    background-color: var(--tz-crimson-soft);
    color: var(--tz-crimson);
}

.badge-soft-secondary {
    background-color: #eeeef3;
    color: var(--tz-purple);
}

.badge-soft-success {
    background-color: var(--tz-success-soft);
    color: var(--tz-success);
}

.badge-soft-warning {
    background-color: var(--tz-gold-soft);
    color: var(--tz-warn);
}

.badge-soft-danger {
    background-color: var(--tz-danger-soft);
    color: var(--tz-danger);
}

.badge-soft-info {
    background-color: var(--tz-info-soft);
    color: var(--tz-info);
}

/* Dashboard tiles and list groups. */
.avatar-title {
    background-color: var(--tz-crimson);
    color: #fff;
}

.list-group-item.active {
    background-color: var(--tz-crimson);
    border-color: var(--tz-crimson);
}

.border-primary {
    border-color: var(--tz-crimson) !important;
}

/*  .text-info and .bg-info map to purple, matching .btn-info above - keeping the
    three "info" surfaces consistent rather than two purple and one blue. */
.text-info {
    color: var(--tz-purple) !important;
}

.bg-info {
    background-color: var(--tz-purple) !important;
}

/* Disabled states inherit the theme blue unless named explicitly. */
.btn-primary.disabled,
.btn-primary:disabled {
    background-color: var(--tz-crimson);
    border-color: var(--tz-crimson);
    opacity: .55;
}

.btn-outline-primary.disabled,
.btn-outline-primary:disabled {
    color: var(--tz-crimson);
    border-color: var(--tz-crimson);
}

.btn-outline-primary:not(:disabled):not(.disabled).active,
.show > .btn-outline-primary.dropdown-toggle {
    background-color: var(--tz-crimson) !important;
    border-color: var(--tz-crimson) !important;
}

/* Multi-step forms and timelines. */
.wizard > .steps .done a .number,
.wizard > .steps .done a:hover .number,
.wizard > .steps .done a:active .number {
    background-color: var(--tz-crimson);
}

.wizard > .steps .current a .number {
    background-color: var(--tz-gold);
    color: #3d2c05;
}

.verti-timeline .event-list.active .event-timeline-dot {
    color: var(--tz-crimson);
}

.select2-container--default .select2-results__option[aria-selected="true"],
.select2-container--default .select2-results__option[aria-selected="true"]:hover {
    background-color: var(--tz-crimson-soft) !important;
    color: var(--tz-crimson) !important;
}

.table-rep-plugin .btn-group .btn-default.btn-primary,
.table-rep-plugin .checkbox-row input[type="checkbox"]:checked + label::before {
    background-color: var(--tz-crimson) !important;
    border-color: var(--tz-crimson) !important;
}

/*  The responsive-table plugin clones the header into a sticky bar. It has to
    match the real one, which is now the dark header ground, not purple. */
.table-rep-plugin .fixed-solution .sticky-table-header {
    background-color: var(--tz-header) !important;
}

    .table-rep-plugin .fixed-solution .sticky-table-header th {
        color: var(--tz-gold) !important;
    }

/*  The sidebar rules that used to sit here have moved into section 2, where they
    are scoped to body[data-sidebar="dark"] and use the --tz-sidebar-* scale.

    They are not merely relocated - they were wrong here. Both carried !important
    in page colours: crimson on the active icon, and .crimson-soft (#fdecec, all
    but white) as the hover ground of the collapsed flyout. On a dark panel that
    read as a white band, and the !important meant it outranked the correctly
    scoped rule no matter where that rule was placed. */

/*  Chart labels. app.min.css sets these to Poppins with !important - the only
    place in the theme that forces a face - so they need the same weight to move
    onto Inter. Poppins is not loaded anywhere, so they were rendering in the
    browser default while the rest of the page moved to Inter. */
.apex-charts text,
.apexcharts-tooltip-text,
.apexcharts-tooltip-title,
.apexcharts-legend-text,
.apexcharts-xaxis text,
.apexcharts-yaxis text,
.jqsfield {
    font-family: var(--tz-font) !important;
}

/*  Belt and braces on the document face. portal.css already sets this on body and
    wins on load order, but tangaza.css is the last stylesheet in the document, so
    a future theme update cannot quietly take the typography back. */
body {
    font-family: var(--tz-font);
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: var(--tz-font);
    letter-spacing: -.011em;
}

.btn,
.form-control,
.custom-select,
input,
select,
textarea,
.select2-container {
    font-family: var(--tz-font);
}

/* ==========================================================================
   10. Motion
   Page-level motion lives in portal.css, including its prefers-reduced-motion
   block. These are the chrome and component pieces.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
    .dropdown-menu.show {
        animation: tz-drop .16s ease-out both;
    }

    /*  Cards settle in on load. Deliberately not applied to content injected by
        AJAX later - most of these screens reload a partial into a div, and
        re-running the animation on every refresh reads as a flicker. */
    .page-content .card {
        animation: tz-rise .34s ease-out both;
    }

    .modal.show .modal-dialog {
        animation: tz-rise .22s ease-out both;
    }

    .table tbody tr {
        transition: background-color .12s ease;
    }

    .card {
        transition: box-shadow .18s ease;
    }

        .card:hover {
            box-shadow: var(--tz-shadow-lg);
        }
}

@keyframes tz-drop {
    from {
        opacity: 0;
        transform: translateY(-6px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes tz-rise {
    from {
        opacity: 0;
        transform: translateY(8px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/*  Anything that animates must still be usable for someone who has asked the OS to
    stop animations - vestibular disorders, motion sickness. */
@media (prefers-reduced-motion: reduce) {
    .dropdown-menu.show,
    .page-content .card,
    .modal.show .modal-dialog {
        animation: none !important;
    }

    /*  The padding-left reset that used to be here existed to cancel a hover rule
        that shifted the row 6px to the right. That shift is gone - hover is now
        marked by a border colour and a ground, neither of which moves anything -
        so forcing a padding here would only fight Skote's own spacing. */
    body[data-sidebar="dark"] #sidebar-menu ul li a,
    body[data-sidebar="dark"] #sidebar-menu ul li a:hover {
        transition: none !important;
    }

    .card,
    .btn,
    .form-control,
    .table tbody tr {
        transition: none !important;
    }
}

/* ==========================================================================
   11. Small screens
   ========================================================================== */

@media (max-width: 1199.98px) {
    /*  The staff name was "d-none d-xl-inline-block", so it only appeared at 1200px
        and up - invisible on every phone and every tablet. The markup now says
        d-none d-sm-inline-block; this caps the width so a long name truncates
        instead of widening the bar. */
    .tz-whoami-name {
        max-width: 30vw;
    }
}

@media (max-width: 767.98px) {
    .page-content {
        padding-left: 12px;
        padding-right: 12px;
    }

    .card-body,
    .modal-body {
        padding: 14px;
    }

    .page-title-box h4,
    .page-title-box .page-title {
        font-size: 16px;
    }

    /*  A twelve-column approval table cannot be made to fit a phone, so it has to
        scroll inside its own container. Without that the PAGE scrolls sideways and
        the whole layout shifts under the reader's thumb.

        Only 10 of the 68 tables in these views sit in a .table-responsive wrapper,
        so relying on the wrapper would leave 58 of them breaking the page. Every
        table is given the behaviour here instead - a CSS fix rather than 58 view
        edits. display:block is what makes overflow-x apply to a <table>. */
    .table-responsive,
    .card-body table,
    .modal-body table,
    .page-content table {
        display: block;
        width: 100%;
        max-width: 100%;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

        /*  display:block on the table detaches thead/tbody from the table layout
            algorithm, so the header cells stop tracking the body columns. Restoring
            table layout on the inner element keeps the columns aligned while the
            outer box scrolls. */
        .card-body table > thead,
        .card-body table > tbody,
        .modal-body table > thead,
        .modal-body table > tbody,
        .page-content table > thead,
        .page-content table > tbody {
            display: table;
            width: 100%;
            table-layout: auto;
        }

    .btn {
        padding: 7px 13px;
    }
}

@media (max-width: 575.98px) {
    /* Below this the avatar is the control on its own; the name is still in the
       dropdown and on the button's title attribute. */
    .tz-whoami-name {
        display: none !important;
    }

    .navbar-brand-box {
        width: auto !important;
        min-width: 0;
        padding: 0 12px !important;
    }

    #page-topbar .navbar-header {
        padding-left: 0;
        padding-right: 4px;
    }

    /* Buttons in a modal footer stack rather than crowding onto one line. */
    .modal-footer {
        flex-direction: column-reverse;
        align-items: stretch;
    }

        .modal-footer > .btn {
            margin: 3px 0;
            width: 100%;
        }
}

/* ==========================================================================
   14. Shared list-page language
   --------------------------------------------------------------------------
   The Leave Requisition list is the pattern the portal is standardising on:
   a row of stat cards with a coloured top edge, one main card with a dark
   gold-titled header, a toolbar of coloured action buttons, a dark table head
   and soft status pills.

   Those styles were written inline in that one view, so no other page got
   them. They are defined here instead, on the same class names, so every
   list page picks the language up with no markup change. A view that still
   declares its own copy simply overrides this - same names, later cascade -
   so nothing that already looks right changes.
   ========================================================================== */

.dashboard-container {
    padding: 25px;
}

.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 15px;
    margin-bottom: 26px;
}

.stat-card {
    background: var(--tz-surface);
    border: 1px solid var(--tz-border);
    border-radius: 12px;
    padding: 20px;
    box-shadow: 0 4px 15px rgba(16, 24, 40, .05);
    border-top: 5px solid var(--tz-border);
    text-align: center;
    transition: transform .25s ease, box-shadow .25s ease;
}

    .stat-card:hover {
        transform: translateY(-3px);
        box-shadow: 0 10px 24px rgba(16, 24, 40, .10);
    }

    .stat-card h3 {
        font-size: 11px;
        color: var(--tz-text-muted);
        font-weight: 700;
        letter-spacing: .04em;
        text-transform: none !important;
        margin-bottom: 8px;
    }

    .stat-card p {
        font-size: 26px;
        font-weight: 800;
        color: var(--tz-ink);
        font-variant-numeric: tabular-nums;
        margin: 0;
    }

    /*  Status colours on the top edge. These are semantic, not brand: they have
        to mean open / waiting / good / done / stopped at a glance. */
    .stat-card.total { border-top-color: var(--tz-ink); }
    .stat-card.open { border-top-color: var(--tz-gold); }
    .stat-card.pending { border-top-color: #ef6c00; }
    .stat-card.approved { border-top-color: var(--tz-success); }
    .stat-card.posted { border-top-color: #0277bd; }
    .stat-card.canceled,
    .stat-card.rejected { border-top-color: var(--tz-danger); }

/* --- The main card ------------------------------------------------------- */

.main-card {
    border: none;
    border-radius: 14px;
    box-shadow: 0 10px 40px rgba(16, 24, 40, .10);
    background: var(--tz-surface);
    overflow: hidden;
}

.card-header-custom {
    background: var(--tz-header);
    color: var(--tz-gold);
    padding: 15px 25px;
    border-radius: 14px 14px 0 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    font-size: 14px;
    font-weight: 600;
}

    .card-header-custom i {
        margin-right: 8px;
    }

/* --- Toolbar buttons ----------------------------------------------------- */

.btn-modern {
    border-radius: 8px;
    padding: 8px 18px;
    font-size: 13px;
    font-weight: 600;
    border: none;
    color: #fff;
    transition: opacity .2s ease, transform .2s ease;
}

/*  A .btn-modern that brings no colour of its own still needs a ground.

    The base class above sets white text but no background, on the assumption
    that something else - an id rule, .btn-new, a Bootstrap colour class - would
    supply one. Where nothing did, the only background came from .disabled, so
    the button was legible while inactive and turned white-on-white the instant
    the page enabled it. That is exactly what happened to the allocated-units
    toolbar: `$(".BtnPadding").removeClass("disabled")` on row select made all
    three vanish.

    The :not() chain excludes anything that already carries a colour, so this is
    a floor rather than an override. */
.btn-modern:not(.btn-new):not(.btn-primary):not(.btn-secondary):not(.btn-success):not(.btn-danger):not(.btn-warning):not(.btn-info):not(.btn-light):not(.btn-dark):not([class*="btn-outline"]) {
    background-color: var(--tz-crimson);
}

    .btn-modern:hover:not(.disabled):not(:disabled) {
        opacity: .88;
        transform: translateY(-1px);
        color: #fff;
    }

    /*  Disabled toolbar buttons stay readable. A greyed-out control that cannot
        be read is worse than one that is simply obviously inactive. */
    .btn-modern.disabled,
    .btn-modern:disabled {
        background-color: #e2e6ea !important;
        color: #52525e !important;
        font-weight: 700 !important;
        cursor: not-allowed;
        opacity: 1;
    }

/*  Action colours are semantic - view / send / cancel / history - so they stay
    distinct from the brand rather than all becoming crimson.

    Every one is scoped to .btn-modern. They were bare id selectors, which in a
    shared stylesheet is the wrong tool entirely: an id beats every class the
    page uses, so a view that styles the same button with .btn-outline-dark got
    this blue ground underneath its own dark text and the label vanished. Scoped
    like this they apply only where a page has opted in by using .btn-modern. */
.btn-modern#ViewDoc { background-color: #0d47a1; }
.btn-modern#SendDocAppr { background-color: var(--tz-success); }
.btn-modern#CancelDocAppr { background-color: var(--tz-danger); }
.btn-modern#AppTrail { background-color: #455a64; }

.btn-new {
    background: var(--tz-crimson);
    color: #fff;
}

    .btn-new:hover {
        background: var(--tz-crimson-dark);
        color: #fff;
    }

/* --- Status pills -------------------------------------------------------- */

.badge-status {
    display: inline-block;
    padding: 5px 11px;
    border-radius: 15px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .03em;
    white-space: nowrap;
}

.status-open { background: #fff3e0; color: #b35400; }
.status-pending { background: #e3f2fd; color: #12508f; }
.status-approved { background: var(--tz-success-soft); color: var(--tz-success); }
.status-posted { background: #e1f5fe; color: #01579b; }
.status-canceled,
.status-rejected { background: var(--tz-danger-soft); color: var(--tz-danger); }

/*  The row you picked. A tint alone is easy to lose on a long list, so it also
    takes a rail - the same device the sidebar uses for the current page.

    The text colour is stated here as well as the ground, and that is the whole
    point: 15 views used to set `background:#74788d; color:white` on this class.
    Overriding only the background left the white behind, and the selected row
    became white text on a near-white tint. Ground and colour travel together.
    Cells that set their own colour - status pills, the Select button - keep it,
    because this sets the td rather than everything inside it. */
.selectedTableRow,
tr.selectedTableRow,
tr.selectedTableRow > td,
tr.selectedTableRow > th {
    background-color: var(--tz-gold-soft) !important;
    color: var(--tz-text) !important;
}

tr.selectedTableRow > td:first-child {
    box-shadow: inset 4px 0 0 0 var(--tz-gold);
}

/* ==========================================================================
   15. Spacing
   --------------------------------------------------------------------------
   Skote gives .page-content only calc(24px / 2) = 12px of side gutter, so any
   page that does not wrap itself in a container of its own sits almost against
   the sidebar. Some views compensate with their own .dashboard-container
   padding and some do not, which is why the gutter changes width as you move
   around the portal.

   The gutter is set here once, on .page-content, so every page gets it. Views
   that already wrap in .dashboard-container have their horizontal padding
   zeroed - this selector is (0,2,0) against their (0,1,0), so it wins without
   !important - leaving one gutter rather than two stacked.
   ========================================================================== */

.page-content {
    padding-left: 24px;
    padding-right: 24px;
}

.page-content .dashboard-container {
    padding-left: 0;
    padding-right: 0;
}

/*  Breathing room inside the panels themselves. */
.card-body {
    padding: 22px 25px;
}

.table td {
    padding: 12px 14px;
    vertical-align: middle;
}

.table th {
    vertical-align: middle;
}

/*  Bootstrap's .table-sm is used on dense lists; keep it dense but not cramped. */
.table-sm td,
.table-sm th {
    padding: 8px 10px;
}

.modal-header {
    padding: 15px 25px;
}

.modal-body {
    padding: 22px 25px;
}

.modal-footer {
    padding: 14px 25px;
}

/*  Toolbars above a table. Several views lay these out with plain margins on
    each button, which double up when the row wraps on a narrow screen. */
.btn-toolbar,
.tz-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 20px;
}

    .btn-toolbar > .btn,
    .tz-toolbar > .btn {
        margin-right: 0;
        margin-bottom: 0;
    }

.form-group {
    margin-bottom: 18px;
}

@media (max-width: 767px) {
    .page-content {
        padding-left: 14px;
        padding-right: 14px;
    }

    .card-body {
        padding: 16px 15px;
    }

    .modal-header,
    .modal-body,
    .modal-footer {
        padding-left: 16px;
        padding-right: 16px;
    }

    .stats-grid {
        grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
        gap: 10px;
    }

    .stat-card {
        padding: 14px 10px;
    }

        .stat-card p {
            font-size: 21px;
        }

    .card-header,
    .card-header-custom {
        padding: 13px 16px;
    }
}

/* ==========================================================================
   16. Form pages, footer and stray Bootstrap
   --------------------------------------------------------------------------
   The list pages had a pattern to copy; the form pages never did. They are a
   bare .card with a floating .card-title, <hr> rules for structure and empty
   grid columns for spacing. This section gives them the same header, spacing
   and field treatment as everything else, without editing their markup.
   ========================================================================== */

/*  A .card-title sitting directly inside .card is being used as the card's
    heading - 13 views do this - but nothing styled it as one, so it read as
    a loose line of text above a rule. Scoped to a direct first child so the
    ordinary .card-title inside a .card-body is untouched. */
.card > .card-title:first-child {
    display: block;
    background: var(--tz-header);
    color: var(--tz-gold);
    padding: 15px 25px;
    border-radius: var(--tz-radius) var(--tz-radius) 0 0;
    margin: 0;
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
}

    .card > .card-title:first-child + .card-body > hr:first-child {
        display: none;
    }

/*  Bootstrap 4 kept .pre-scrollable as overflow-y:scroll but dropped the
    max-height that made it mean anything. The result on 66 views is a card
    that permanently draws a scrollbar track with nothing to scroll - the grey
    gutter down the right of every one of those pages. `auto` shows it only
    when the content actually overflows. */
.pre-scrollable {
    overflow-y: auto !important;
}

/* --- Fields ------------------------------------------------------------- */

.form-group > label,
.control-label {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--tz-text-muted);
    margin-bottom: 6px;
}

.form-control:focus,
.custom-select:focus {
    border-color: var(--tz-gold);
    box-shadow: 0 0 0 3px rgba(209, 156, 44, .18);
}

select.form-control:not([size]):not([multiple]) {
    height: auto;
    padding: 8px 11px;
}

.form-control:disabled,
.form-control[readonly] {
    background: #f4f5f7;
    color: var(--tz-text-muted);
}

/*  Several form pages use <hr> between field rows. Bootstrap's default is a
    hard black-ish rule; this makes it a hairline that separates without
    shouting, and gives it the spacing the markup assumes. */
.card-body hr {
    border: 0;
    border-top: 1px solid var(--tz-border);
    margin: 20px 0;
}

/*  Empty grid columns used as spacers collapse to nothing on small screens
    anyway; this stops them adding height on their own. */
.card-body .row > [class^="col"]:empty {
    padding: 0;
}

/* --- Footer -------------------------------------------------------------
   Was inline style="color:#051936; background-color:#c52127" - navy on
   crimson, 3.02:1, which is why the credit line was barely readable. A
   full-bleed crimson bar also competed with the topbar for attention. It is
   a quiet closing rule now, with the gold hairline picking up the topbar. */

.footer {
    background: var(--tz-surface);
    color: var(--tz-text-muted);
    border-top: 1px solid var(--tz-border);
    box-shadow: inset 0 3px 0 0 rgba(209, 156, 44, .35);
    font-size: 12px;
}

    .footer a {
        color: var(--tz-crimson);
        font-weight: 600;
    }

        .footer a:hover {
            color: var(--tz-crimson-dark);
            text-decoration: underline;
        }
/*  Intro line and action row for form pages. Several of these pages jump
    straight from a heading to a pair of dropdowns with no indication of what
    submitting will do, and put the button in a centred grid column. */
.tz-form-intro {
    font-size: 13px;
    color: var(--tz-text-muted);
    margin: 0 0 20px 0;
    max-width: 68ch;
}

.tz-form-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    margin-top: 6px;
    padding-top: 18px;
    border-top: 1px solid var(--tz-border);
}

    .tz-form-actions .btn i {
        margin-right: 6px;
    }

/* ==========================================================================
   17. Two patterns copied into dozens of views
   ========================================================================== */

/*  .BtnPadding is declared as `padding: 1px` in 39 views. It crushes every
    Bootstrap button it touches into a label-sized chip - the row of buttons at
    the top of the allocated-units page is the clearest example. The class is
    kept (the markup uses it everywhere) but given a real button padding.
    `.btn.BtnPadding` is (0,2,0) against the views' (0,1,0), so it wins without
    !important, and a view that genuinely wants something tighter can still say
    so with its own two-class selector. */
.btn.BtnPadding {
    padding: 7px 14px;
    font-size: 12.5px;
    line-height: 1.2;
}

    .btn.BtnPadding.btn-sm {
        padding: 5px 11px;
        font-size: 11.5px;
    }

/*  Empty tables. 52 views end their tbody with a single cell spanning the row
    and a line like "No Records Found", styled as ordinary body text so it reads
    as data rather than as the absence of it. A spanning cell in a tbody is a
    reliable hook for that, because a real data row never spans. */
.table tbody td[colspan] {
    padding: 34px 18px;
    text-align: center;
    color: var(--tz-text-muted);
    font-size: 13px;
    background: var(--tz-surface);
}

    /*  Several views colour the message red, which reads as an error - an empty
        list is a normal state, not a failure. */
    .table tbody td[colspan] .text-danger,
    .table tbody td[colspan][class*="text-danger"] {
        color: var(--tz-text-muted) !important;
    }

    .table tbody td[colspan]::before {
        content: "\f119";
        font-family: "Font Awesome 5 Free", "boxicons", sans-serif;
        display: block;
        font-size: 22px;
        opacity: .35;
        margin-bottom: 8px;
    }

/*  A toolbar of plain anchors sitting straight on the page background, with no
    card and no spacing, is the other repeated shape. */
.tz-pagebar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-bottom: 18px;
}
/*  Bootstrap's .btn-dark is #343a40, four points off the header ground this
    portal uses everywhere else. Same colour family, but matching it exactly
    keeps a dark button and a dark header from reading as two different darks. */
.btn-dark,
.btn-dark:not(:disabled):not(.disabled):active {
    background-color: var(--tz-header);
    border-color: var(--tz-header);
    color: #fff;
}

    .btn-dark:hover:not(:disabled):not(.disabled) {
        background-color: #2f2e3b;
        border-color: #2f2e3b;
        color: #fff;
    }

/* ==========================================================================
   18. Mark entry
   --------------------------------------------------------------------------
   The score sheet is the densest data-entry screen in the portal and the one
   where a mistake matters most, so the marks themselves get the emphasis and
   everything around them stays quiet.
   ========================================================================== */

/*  Context chips: programme, unit, semester and the maximum for each component.
    The maximum used to be a run-on line ("| CAT = 40 | EXAM = 60 |") above the
    table; it belongs beside the thing it constrains. */
.tz-marks-context {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 18px;
}

.tz-ctx {
    display: inline-flex;
    align-items: baseline;
    gap: 7px;
    background: var(--tz-canvas);
    border: 1px solid var(--tz-border);
    border-radius: 999px;
    padding: 6px 14px;
    font-size: 13px;
    font-weight: 600;
    color: var(--tz-ink);
}

    .tz-ctx .tz-ctx-label {
        font-size: 10px;
        font-weight: 700;
        letter-spacing: .07em;
        text-transform: uppercase;
        color: var(--tz-text-muted);
    }

    /*  Bootstrap gives a bare <label> a bottom margin; inside a chip it has to
        sit on the baseline with the label. */
    .tz-ctx label {
        margin: 0;
        font-weight: 600;
    }

.tz-ctx-wide {
    max-width: 42ch;
}

/*  The maximum score is a limit, so it reads as one - gold, like every other
    threshold in the portal. */
.tz-ctx-max {
    background: var(--tz-gold-soft);
    border-color: rgba(209, 156, 44, .45);
}

/* --- The mark boxes ------------------------------------------------------ */

.tz-mark {
    width: 68px;
    padding: 6px 8px;
    text-align: center;
    font-size: 14px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--tz-ink);
}

    /*  A mark box is where the work happens, so focus is unmistakable rather
        than the usual hairline. */
    .tz-mark:focus {
        border-color: var(--tz-crimson);
        box-shadow: 0 0 0 3px rgba(197, 33, 39, .16);
        background: #fff;
    }

    /*  An empty box is a mark not yet entered, which is worth seeing at a glance
        down a column of 40 students. */
    .tz-mark:placeholder-shown,
    .tz-mark:not([value]):not(:focus) {
        background: var(--tz-canvas);
    }

/*  Total column: not editable, so it reads as a result rather than a field. */
.tz-marks .table td:last-child {
    text-align: center;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--tz-ink);
    background: var(--tz-canvas);
}

/* --- Action bar ---------------------------------------------------------- */

.tz-marks-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-top: 20px;
    padding-top: 18px;
    border-top: 1px solid var(--tz-border);
}

/*  Pushes everything after it to the right, so saving sits apart from the
    secondary upload and print actions. */
.tz-marks-sep {
    flex: 1 1 auto;
    min-width: 12px;
}

/*  The file input renders as an unstyled browser control that never matches
    anything around it. The real input stays in the DOM - the upload handler
    reads #UploadedFile - it is just wrapped in a label that can be styled. */
.tz-file {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 7px 14px;
    border: 1px dashed #c9cfd9;
    border-radius: 8px;
    background: var(--tz-surface);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--tz-text-muted);
    cursor: pointer;
    max-width: 100%;
}

    .tz-file:hover {
        border-color: var(--tz-gold);
        color: var(--tz-ink);
    }

    .tz-file i {
        font-size: 15px;
        color: var(--tz-gold);
    }

    .tz-file input[type="file"] {
        max-width: 168px;
        font-size: 11.5px;
        color: var(--tz-text-muted);
    }

@media (max-width: 767px) {
    .tz-marks-sep {
        display: none;
    }

    .tz-marks-actions .btn,
    .tz-file {
        width: 100%;
        justify-content: center;
    }
}

/* ==========================================================================
   19. Change password
   ========================================================================== */

/*  The rule list is shared with the sign-in reset page (.tz-pwrules in
    portal.css). Here it sits beside the fields rather than under them, so it
    stays in view while typing - it used to be in the card footer, below the
    submit button, with a red line at the top of the form telling you to go
    and look for it. */
.tz-pwpage .tz-pwrules {
    margin-top: 34px;
    padding: 16px 18px;
    font-size: 12.5px;
}

.tz-pwrules-head {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--tz-text-muted);
    margin-bottom: 10px;
}

.tz-pwrules .rule {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
    transition: color .16s ease;
}

    .tz-pwrules .rule i {
        font-size: 15px;
        width: 16px;
        flex: 0 0 auto;
        text-align: center;
    }

/*  Confirmation feedback. Saying nothing until submit meant a mistyped
    confirmation was only discovered after the button was pressed. */
.tz-match {
    color: var(--tz-success);
    font-weight: 600;
}

.tz-mismatch {
    color: var(--tz-danger);
    font-weight: 600;
}

/*  A password field does not need the full width of a card. The cap goes on the
    wrapper rather than the input, so the reveal button - which is positioned
    from the wrapper's right edge - stays inside the field instead of drifting
    to the far side of the column. */
.tz-pwpage .tz-field {
    max-width: 420px;
}

@media (max-width: 991px) {
    .tz-pwpage .tz-pwrules {
        margin-top: 4px;
    }

    .tz-pwpage .tz-field {
        max-width: 100%;
    }
}
