/* ==========================================================================
   Tangaza University Student Portal - shared design system
   --------------------------------------------------------------------------
   Every page in the portal is built from the components in this file. Before
   adding a <style> block to a view, check whether the thing you need is
   already here - the point of this file is that a table on the Fee Statement
   looks like a table on the Results page without anybody having to remember
   the hex codes.

   Palette is the official Tangaza University website palette:

       Primary          #c52127   red      - primary actions, active nav, links
       Secondary        #d19c2c   gold     - accents, rails, icons on dark
       Secondary Purple #51506E            - card and table headers
       Secondary Black  #444444            - chrome, body text

   Prefix is tz- so nothing collides with Bootstrap 4 or the pcoded theme.
   Change a colour here and it changes everywhere; do not hard-code hex values
   in a view.
   ========================================================================== */

:root {
    /* Brand - primary red */
    --tz-crimson: #c52127;
    --tz-crimson-dark: #a41a1f;
    --tz-crimson-soft: #fbeaeb;

    /* Brand - secondary gold */
    --tz-gold: #d19c2c;
    --tz-gold-dark: #b08222;
    --tz-gold-soft: #fbf3e3;

    /* Brand - secondary purple, used for headers */
    --tz-purple: #51506E;
    --tz-purple-dark: #414058;
    --tz-purple-soft: #eeeef3;

    /* Brand - secondary black */
    --tz-ink: #444444;
    --tz-ink-deep: #333333;
    --tz-header: #444444;

    /* Neutrals */
    --tz-text: #2f3337;
    --tz-text-muted: #6b7280;
    --tz-text-faint: #98a0ab;
    --tz-border: #e3e6ec;
    --tz-border-soft: #edeff3;
    --tz-surface: #ffffff;
    --tz-surface-alt: #fafbfc;
    --tz-canvas: #f4f6f9;

    /* Semantic */
    --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;

    --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);

    /* Typeface. Linked from Google Fonts in SiteMaster and LoginMaster.
       The fallback stack is load-bearing, not decoration: if fonts.googleapis.com is
       blocked or slow the page renders in the platform UI face instead of dropping to
       an arbitrary serif. Do not add "feather" or "FontAwesome" here - those are icon
       fonts and the theme sets them per-element. */
    --tz-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
}

/* ==========================================================================
   0b. Typography
   The pcoded theme asks for "open sans" on body and "quicksand" on headings, the
   header and the sidebar, but never loaded either - both silently fell back to the
   browser default. These rules replace all four with Inter.
   portal.css is the last stylesheet in the document, so it wins on equal specificity;
   the selectors below match the theme's own so no !important is needed except where
   the theme used a heavier hand.
   ========================================================================== */

body,
.pcoded .pcoded-header,
.pcoded .pcoded-navbar {
    font-family: var(--tz-font);
    /* Inter ships contextual alternates that tighten spacing around punctuation. */
    -webkit-font-feature-settings: "cv05", "cv11";
    font-feature-settings: "cv05", "cv11";
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--tz-font);
    /* Inter runs optically larger than Quicksand at the same size, so headings need a
       tighter fit to keep the vertical rhythm the cards were spaced for. */
    letter-spacing: -.011em;
    text-wrap: balance;
}

/* Form controls do not inherit the document face on any browser. */
input, select, textarea, button, .form-control, .btn {
    font-family: inherit;
}

/* --- File-type icons -----------------------------------------------------
   Used by the Important Documents table. Font Awesome 4.7 glyphs, coloured by
   type so the list is scannable without reading the Type column. These replace
   img/pdf.png and img/word.png, which the markup referenced but which have
   never existed in the project. */

.tz-fileicon {
    font-size: 21px;
    line-height: 1;
    vertical-align: middle;
    color: var(--tz-text-muted);
}

.tz-fileicon-pdf {
    color: #c52127;
}

.tz-fileicon-word {
    color: #2b579a;
}

.tz-fileicon-excel {
    color: #217346;
}

.tz-fileicon-ppt {
    color: #c55a11;
}

.tz-fileicon-image {
    color: #51506e;
}

.tz-fileicon-archive {
    color: #b07d16;
}

.tz-fileicon-other {
    color: #6b7280;
}

/* The icon is the download control, so it needs a visible affordance. */
.tz-table a:hover .tz-fileicon,
.tz-table a:focus-visible .tz-fileicon {
    opacity: .72;
}

/* ==========================================================================
   1. Page shell
   ========================================================================== */

.tz-page {
    padding: 22px 26px 60px 26px;
    background: var(--tz-canvas);
    min-height: calc(100vh - 70px);
    color: var(--tz-text);
    font-size: 13.5px;
}

/* Page title bar. Sits at the top of every page, above the first card. */
.tz-page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 20px;
}

    .tz-page-head h1 {
        margin: 0;
        font-size: 21px;
        font-weight: 600;
        letter-spacing: .2px;
        color: var(--tz-ink);
        line-height: 1.25;
    }

        .tz-page-head h1 i {
            color: var(--tz-crimson);
            margin-right: 9px;
            vertical-align: -2px;
        }

    .tz-page-head .tz-sub {
        margin: 5px 0 0 0;
        font-size: 13px;
        color: var(--tz-text-muted);
    }

    .tz-page-head .tz-page-actions {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        align-items: center;
    }

/* Dark identity banner - student number, name, programme, semester. */
.tz-banner {
    background: linear-gradient(135deg, var(--tz-purple) 0%, var(--tz-purple-dark) 100%);
    border-left: 4px solid var(--tz-gold);
    color: #fff;
    border-radius: var(--tz-radius);
    padding: 18px 22px;
    margin-bottom: 22px;
    box-shadow: var(--tz-shadow);
}

.tz-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 30px;
}

.tz-fact .k {
    display: block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .9px;
    text-transform: uppercase;
    color: var(--tz-gold);
    margin-bottom: 3px;
}

.tz-fact .v {
    display: block;
    font-size: 13.5px;
    font-weight: 600;
    color: #fff;
    word-break: break-word;
}

/* ==========================================================================
   2. Cards
   ========================================================================== */

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

.tz-card-head {
    background: var(--tz-purple);
    color: #fff;
    padding: 12px 18px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
}

    .tz-card-head h2,
    .tz-card-head .tz-card-title {
        margin: 0;
        font-size: 13px;
        font-weight: 600;
        letter-spacing: .5px;
        text-transform: uppercase;
        color: #fff;
        display: flex;
        align-items: center;
    }

        .tz-card-head h2 i,
        .tz-card-head .tz-card-title i {
            color: var(--tz-gold);
            margin-right: 8px;
        }

.tz-card-body {
    padding: 18px;
}

    .tz-card-body > :last-child {
        margin-bottom: 0;
    }

/* Numbered step marker used on multi-stage pages (course registration). */
.tz-step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--tz-gold);
    color: var(--tz-ink);
    font-weight: 700;
    font-size: 11.5px;
    margin-right: 10px;
    flex: 0 0 auto;
}

/* Small count chip that follows a card title. */
.tz-count {
    display: inline-block;
    background: var(--tz-crimson);
    color: #fff;
    border-radius: 20px;
    padding: 1px 10px;
    font-size: 11px;
    font-weight: 700;
    margin-left: 9px;
}

.tz-count-zero {
    background: #6d6d6d;
}

/* Chip in a dark card header, e.g. the current semester. */
.tz-chip {
    background: rgba(255,255,255,.10);
    border: 1px solid rgba(229,169,59,.45);
    border-radius: 20px;
    padding: 3px 14px;
    font-size: 11.5px;
    font-weight: 600;
    color: #fff;
    white-space: nowrap;
}

    .tz-chip i {
        color: var(--tz-gold);
        margin-right: 5px;
    }

/* ==========================================================================
   3. Tables
   ========================================================================== */

.tz-scroll {
    max-height: 420px;
    overflow: auto;
    border: 1px solid var(--tz-border);
    border-radius: var(--tz-radius-sm);
    background: var(--tz-surface);
}

.tz-scroll-tall {
    max-height: 620px;
}

.tz-scroll-auto {
    max-height: none;
    overflow-x: auto;
}

.tz-table {
    width: 100%;
    margin: 0;
    font-size: 12.5px;
    border-collapse: separate;
    border-spacing: 0;
    background: var(--tz-surface);
}

    .tz-table thead th {
        position: sticky;
        top: 0;
        z-index: 2;
        background: var(--tz-purple);
        color: #fff;
        font-size: 10.5px;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: .6px;
        padding: 10px 12px;
        border: 0;
        white-space: nowrap;
        text-align: left;
    }

    /* A header carrying .tz-num or .tz-center has to beat ".tz-table thead th" above,
       which is more specific than the bare .tz-num / .tz-center utilities. Without these
       the heading sat left while its numbers sat right, so every numeric column looked
       shifted against its own title. */
    .tz-table thead th.tz-num {
        text-align: right;
    }

    .tz-table thead th.tz-center {
        text-align: center;
    }

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

    .tz-table tbody tr:nth-child(even) {
        background: var(--tz-surface-alt);
    }

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

    .tz-table tfoot td {
        background: var(--tz-purple-dark);
        color: var(--tz-gold);
        font-weight: 700;
        padding: 10px 12px;
        border: 0;
    }

    /* Row emphasis */
    .tz-table tr.tz-row-fail td {
        background: var(--tz-danger-soft);
    }

    .tz-table tr.tz-row-total td {
        font-weight: 700;
        background: #f1f3f7;
    }

.tz-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.tz-code {
    font-weight: 600;
    color: var(--tz-ink);
    white-space: nowrap;
}

.tz-nowrap {
    white-space: nowrap;
}

/* ==========================================================================
   4. Pills / status badges
   ========================================================================== */

.tz-pill {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 20px;
    font-size: 10.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .4px;
    white-space: nowrap;
    line-height: 1.6;
}

    .tz-pill i {
        font-size: 11px;
        margin-right: 4px;
        vertical-align: -1px;
    }

.tz-pill-neutral {
    background: #eceff3;
    color: #4a5158;
}

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

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

.tz-pill-warn {
    background: var(--tz-warn-soft);
    color: var(--tz-warn);
}

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

.tz-pill-gold {
    background: var(--tz-gold-soft);
    color: var(--tz-gold-dark);
}

/* ==========================================================================
   5. Buttons
   ========================================================================== */

.tz-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border: 1px solid transparent;
    border-radius: var(--tz-radius-sm);
    padding: 9px 17px;
    font-size: 12.5px;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    text-decoration: none;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
    white-space: nowrap;
}

    .tz-btn:focus {
        outline: 2px solid var(--tz-gold);
        outline-offset: 2px;
    }

    .tz-btn:disabled,
    .tz-btn.tz-btn-disabled {
        opacity: .45;
        cursor: not-allowed;
    }

    .tz-btn i {
        font-size: 14px;
    }

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

    .tz-btn-primary:hover:not(:disabled) {
        background: var(--tz-crimson-dark);
        color: #fff;
        text-decoration: none;
    }

.tz-btn-gold {
    background: var(--tz-gold);
    color: var(--tz-ink);
}

    .tz-btn-gold:hover:not(:disabled) {
        background: var(--tz-gold-dark);
        color: var(--tz-ink);
        text-decoration: none;
    }

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

    .tz-btn-dark:hover:not(:disabled) {
        background: #333;
        color: #fff;
        text-decoration: none;
    }

.tz-btn-ghost {
    background: var(--tz-surface);
    color: var(--tz-ink);
    border-color: #c9cfd9;
}

    .tz-btn-ghost:hover:not(:disabled) {
        background: #f1f3f7;
        color: var(--tz-ink);
        text-decoration: none;
    }

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

.tz-btn-block {
    width: 100%;
    justify-content: center;
}

.tz-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 9px;
    align-items: center;
}

/* Inline table links */
.tz-link {
    color: var(--tz-crimson);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}

    .tz-link:hover {
        color: var(--tz-crimson-dark);
        text-decoration: underline;
    }

.tz-link-muted {
    color: var(--tz-text-muted);
    font-weight: 600;
    text-decoration: none;
}

    .tz-link-muted:hover {
        color: var(--tz-ink);
        text-decoration: underline;
    }

/* ==========================================================================
   6. Callouts and empty states
   ========================================================================== */

.tz-hint {
    background: var(--tz-gold-soft);
    border-left: 3px solid var(--tz-gold);
    border-radius: var(--tz-radius-sm);
    padding: 12px 16px;
    margin-bottom: 18px;
    font-size: 12.5px;
    color: #5c4a1e;
}

    .tz-hint ol,
    .tz-hint ul {
        margin: 0;
        padding-left: 18px;
    }

    .tz-hint li {
        margin-bottom: 3px;
    }

        .tz-hint li:last-child {
            margin-bottom: 0;
        }

.tz-note {
    background: var(--tz-info-soft);
    border-left: 3px solid var(--tz-info);
    color: #14406e;
}

.tz-warning {
    background: var(--tz-warn-soft);
    border-left: 3px solid #ef9a00;
    color: #6d4500;
}

.tz-alert {
    background: var(--tz-danger-soft);
    border-left: 3px solid var(--tz-danger);
    color: #8c1d18;
}

.tz-empty {
    text-align: center;
    padding: 38px 18px;
    color: var(--tz-text-faint);
    font-size: 13px;
}

    .tz-empty i {
        font-size: 32px;
        display: block;
        margin-bottom: 10px;
        opacity: .45;
    }

    .tz-empty strong {
        color: var(--tz-text-muted);
    }

/* ==========================================================================
   7. Stat tiles (dashboard)
   ========================================================================== */

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

.tz-stat {
    background: var(--tz-surface);
    border: 1px solid var(--tz-border);
    border-left: 4px solid var(--tz-crimson);
    border-radius: var(--tz-radius);
    padding: 16px 18px;
    box-shadow: var(--tz-shadow);
}

.tz-stat-gold {
    border-left-color: var(--tz-gold);
}

.tz-stat-success {
    border-left-color: var(--tz-success);
}

.tz-stat-info {
    border-left-color: var(--tz-info);
}

.tz-stat .tz-stat-label {
    display: block;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .8px;
    text-transform: uppercase;
    color: var(--tz-text-muted);
    margin-bottom: 6px;
}

.tz-stat .tz-stat-value {
    display: block;
    font-size: 23px;
    font-weight: 700;
    color: var(--tz-ink);
    font-variant-numeric: tabular-nums;
    line-height: 1.15;
}

.tz-stat .tz-stat-foot {
    display: block;
    font-size: 11.5px;
    color: var(--tz-text-faint);
    margin-top: 5px;
}

/* ==========================================================================
   7b. Profile photo
   ========================================================================== */

.tz-avatar-row {
    display: flex;
    align-items: center;
    gap: 16px;
    padding-bottom: 16px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--tz-border-soft);
}

.tz-avatar {
    width: 78px;
    height: 78px;
    border-radius: 50%;
    object-fit: cover;
    border: 3px solid var(--tz-gold);
    background: var(--tz-surface-alt);
    flex: 0 0 auto;
}

.tz-avatar-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--tz-text-faint);
    font-size: 30px;
}

.tz-avatar-actions {
    min-width: 0;
}

    .tz-avatar-actions .tz-file {
        display: none;
    }

    .tz-avatar-actions label.tz-btn {
        margin: 0;
    }

/* ==========================================================================
   7c. Dashboard: hero tiles, quick actions, identity grid
   ========================================================================== */

/* Greeting strip above the page title. */
.tz-greeting {
    font-size: 13px;
    color: var(--tz-text-muted);
    margin: 0 0 2px 0;
}

    .tz-greeting strong {
        color: var(--tz-ink);
    }

    .tz-greeting i {
        margin-right: 5px;
        color: var(--tz-gold-dark);
    }

/* Dismissible banner. */
.tz-hint {
    position: relative;
}

.tz-dismiss {
    position: absolute;
    top: 8px;
    right: 10px;
    background: none;
    border: 0;
    padding: 2px 6px;
    line-height: 1;
    font-size: 18px;
    color: inherit;
    opacity: .45;
    cursor: pointer;
}

    .tz-dismiss:hover {
        opacity: 1;
    }

/* Filled headline tiles for the two unit counts. */
.tz-hero {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 16px;
    margin-bottom: 22px;
    align-items: stretch;
}

.tz-hero-tile {
    border-radius: var(--tz-radius);
    padding: 18px 20px;
    color: #fff;
    box-shadow: var(--tz-shadow);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 104px;
}

.tz-hero-red {
    background: linear-gradient(135deg, var(--tz-crimson) 0%, var(--tz-crimson-dark) 100%);
}

.tz-hero-gold {
    background: linear-gradient(135deg, var(--tz-gold) 0%, var(--tz-gold-dark) 100%);
}

.tz-hero-tile .tz-hero-label {
    display: block;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .9px;
    text-transform: uppercase;
    opacity: .92;
    margin-bottom: 6px;
}

.tz-hero-tile .tz-hero-value {
    display: block;
    font-size: 34px;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.tz-hero-tile .tz-hero-foot {
    display: block;
    font-size: 11.5px;
    opacity: .9;
    margin-top: 5px;
}

.tz-hero-tile > i {
    font-size: 30px;
    opacity: .35;
    flex: 0 0 auto;
}

/*  The fee tile. Same shape as its two siblings - label, figure, footnote, icon -
    but on a white surface with a gold edge, because it is the one tile that is a
    link rather than a statistic. It used to be a wide panel spanning two grid
    columns with three figures in it; with one figure that left a lot of empty
    tile for very little information. */
.tz-hero-fee {
    background: var(--tz-surface);
    border: 1px solid var(--tz-border);
    border-left: 4px solid var(--tz-gold);
    color: var(--tz-text);
    text-decoration: none;
}

    .tz-hero-fee:hover,
    .tz-hero-fee:focus {
        text-decoration: none;
        border-left-color: var(--tz-crimson);
    }

    .tz-hero-fee .tz-hero-label {
        color: var(--tz-crimson);
        opacity: 1;
    }

    .tz-hero-fee .tz-hero-value.owing {
        color: var(--tz-crimson);
    }

    .tz-hero-fee .tz-hero-value.credit {
        color: var(--tz-success);
    }

    .tz-hero-fee .tz-hero-foot {
        color: var(--tz-text-muted);
        opacity: 1;
    }

    .tz-hero-fee > i {
        color: var(--tz-gold);
        opacity: .5;
    }

    /*  Keyboard focus has to be visible - this is a link, not a panel. */
    .tz-hero-fee:focus-visible {
        outline: 2px solid var(--tz-gold);
        outline-offset: 2px;
    }

/* Fee summary tile: three figures side by side on a white card. */
.tz-fee-tile {
    grid-column: span 2;
    background: var(--tz-surface);
    border: 1px solid var(--tz-border);
    border-left: 4px solid var(--tz-gold);
    border-radius: var(--tz-radius);
    padding: 16px 20px;
    box-shadow: var(--tz-shadow);
    min-height: 104px;
}

    .tz-fee-tile h3 {
        margin: 0 0 12px 0;
        font-size: 10.5px;
        font-weight: 700;
        letter-spacing: .9px;
        text-transform: uppercase;
        color: var(--tz-crimson);
        text-align: center;
    }

.tz-fee-split {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

    .tz-fee-split > div {
        flex: 1 1 110px;
        text-align: center;
    }

    .tz-fee-split .k {
        display: block;
        font-size: 11px;
        color: var(--tz-text-muted);
        margin-bottom: 3px;
    }

    .tz-fee-split .v {
        display: block;
        font-size: 18px;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        color: var(--tz-ink);
    }

    .tz-fee-split .v.paid {
        color: var(--tz-success);
    }

    .tz-fee-split .v.owing {
        color: var(--tz-crimson);
    }

    .tz-fee-split .v.credit {
        color: var(--tz-success);
    }

/*  Single-value variant of the fee tile. The tile used to carry Total Billed and
    Total Paid alongside the balance; with one figure it gets the room to be read
    at a glance, which is the point - the balance is the number a student acts on. */
.tz-fee-one {
    text-align: center;
}

    .tz-fee-one .k {
        display: block;
        font-size: 11px;
        color: var(--tz-text-muted);
        margin-bottom: 4px;
    }

    .tz-fee-one .v {
        display: block;
        font-size: 30px;
        font-weight: 700;
        line-height: 1.05;
        font-variant-numeric: tabular-nums;
        color: var(--tz-ink);
    }

        .tz-fee-one .v.owing {
            color: var(--tz-crimson);
        }

        .tz-fee-one .v.credit {
            color: var(--tz-success);
        }

.tz-fee-note {
    display: block;
    margin-top: 6px;
    font-size: 11.5px;
    color: var(--tz-text-muted);
}

@media (max-width: 700px) {
    .tz-fee-tile {
        grid-column: span 1;
    }
}

/* Two-column dashboard body: content left, quick actions right. */
.tz-dash-split {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}

@media (max-width: 1100px) {
    .tz-dash-split {
        grid-template-columns: 1fr;
    }
}

/* Identity grid: labelled value tiles with an icon. */
.tz-info-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 12px;
}

.tz-info-item {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    border: 1px solid var(--tz-border);
    border-radius: var(--tz-radius-sm);
    padding: 11px 13px;
    background: var(--tz-surface);
    min-width: 0;
}

    .tz-info-item > i {
        color: var(--tz-crimson);
        font-size: 16px;
        margin-top: 2px;
        flex: 0 0 auto;
    }

    .tz-info-item .k {
        display: block;
        font-size: 10px;
        font-weight: 700;
        letter-spacing: .7px;
        text-transform: uppercase;
        color: var(--tz-text-muted);
        margin-bottom: 3px;
    }

    .tz-info-item .v {
        display: block;
        font-size: 13px;
        font-weight: 600;
        color: var(--tz-ink);
        word-break: break-word;
    }

        .tz-info-item .v.ok {
            color: var(--tz-success);
        }

/* Quick actions: a stack of tappable rows. */
.tz-quick {
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.tz-quick-item {
    display: flex;
    align-items: center;
    gap: 12px;
    border: 1px solid var(--tz-border);
    border-left: 3px solid var(--tz-crimson);
    border-radius: var(--tz-radius-sm);
    padding: 12px 14px;
    background: var(--tz-surface);
    color: var(--tz-ink);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: background .15s ease, border-color .15s ease, transform .15s ease;
}

    .tz-quick-item:hover {
        background: var(--tz-gold-soft);
        border-left-color: var(--tz-gold);
        color: var(--tz-ink);
        text-decoration: none;
        transform: translateX(2px);
    }

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

    .tz-quick-item .tz-quick-label {
        flex: 1 1 auto;
        min-width: 0;
    }

    .tz-quick-item .tz-quick-go {
        color: var(--tz-text-faint);
        font-size: 15px;
        flex: 0 0 auto;
    }

/* Reg-no chip under the student's name. */
.tz-regchip {
    display: inline-block;
    background: var(--tz-ink);
    color: #fff;
    border-radius: var(--tz-radius-sm);
    padding: 3px 11px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .3px;
}

/* ==========================================================================
   8. Forms
   ========================================================================== */

.tz-label {
    display: block;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .5px;
    color: var(--tz-text-muted);
    margin-bottom: 5px;
}

    .tz-label .tz-req {
        color: var(--tz-crimson);
        margin-left: 3px;
    }

.tz-field {
    margin-bottom: 16px;
}

.tz-input,
.tz-select,
.tz-textarea {
    width: 100%;
    border: 1px solid #c9cfd9;
    border-radius: var(--tz-radius-sm);
    padding: 9px 12px;
    font-size: 13px;
    color: var(--tz-text);
    background: var(--tz-surface);
}

    .tz-input:focus,
    .tz-select:focus,
    .tz-textarea:focus {
        border-color: var(--tz-gold);
        outline: none;
        box-shadow: 0 0 0 3px rgba(229,169,59,.18);
    }

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

.tz-help {
    font-size: 11.5px;
    color: var(--tz-text-faint);
    margin-top: 4px;
}

.tz-error-text {
    font-size: 11.5px;
    color: var(--tz-danger);
    margin-top: 4px;
}

/* ==========================================================================
   9. Utilities
   ========================================================================== */

.tz-grid-2 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 18px;
}

.tz-grid-3 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 18px;
}

.tz-mt-0 {
    margin-top: 0;
}

.tz-mb-0 {
    margin-bottom: 0 !important;
}

.tz-mb-16 {
    margin-bottom: 16px;
}

.tz-mt-16 {
    margin-top: 16px;
}

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

.tz-faint {
    color: var(--tz-text-faint);
}

.tz-strong {
    font-weight: 700;
}

.tz-center {
    text-align: center;
}

.tz-right {
    text-align: right;
}

/* Embedded PDF viewer body used by the document modals. */
.tz-pdf {
    width: 100%;
    height: 460px;
    background: #f4f5f7;
    border-radius: var(--tz-radius-sm);
}

/* ==========================================================================
   9b. Classes the existing markup still references
   --------------------------------------------------------------------------
   These were each redefined in a per-view <style> block. Their definitions were
   identical everywhere they appeared, so they live here once instead. Prefer the
   tz- components above for anything new.
   ========================================================================== */

/* Larger tick target for unit-selection tables. */
.checkboxClass {
    width: 18px;
    height: 18px;
    padding: 0;
    cursor: pointer;
    accent-color: var(--tz-crimson);
    vertical-align: middle;
}

/* Compact in-table buttons. Note .BtnPadding and .btnPadding are two different
   classes - CSS is case-sensitive and both spellings are used in the views. */
.BtnPadding,
.btnPadding,
.btnClass {
    padding: 5px 11px;
    font-size: 11.5px;
    line-height: 1.2;
    border-radius: var(--tz-radius-sm);
}

/* Section heading inside partials loaded into a modal. */
.spanClass {
    font-size: 15px;
    font-weight: 600;
    color: var(--tz-ink);
}

/* Row the user has clicked in a pick-list. */
.selectedTableRow,
.tz-table tbody tr.selectedTableRow,
.tz-table tbody tr.selectedTableRow:hover {
    background: var(--tz-purple) !important;
    color: #fff !important;
}

    .selectedTableRow td {
        color: #fff !important;
    }

/* ==========================================================================
   10. Modals - align the Bootstrap modal with the card look
   ========================================================================== */

.tz-modal .modal-header {
    background: var(--tz-purple);
    color: #fff;
    border-bottom: 3px solid var(--tz-gold);
    padding: 13px 18px;
    align-items: center;
}

    .tz-modal .modal-header .modal-title {
        font-size: 14px;
        font-weight: 600;
        letter-spacing: .4px;
        text-transform: uppercase;
        color: #fff;
        margin: 0;
    }

    .tz-modal .modal-header .close {
        color: #fff;
        opacity: .8;
        text-shadow: none;
        font-size: 26px;
        line-height: 1;
    }

        .tz-modal .modal-header .close:hover {
            opacity: 1;
            color: var(--tz-gold);
        }

.tz-modal .modal-body {
    padding: 18px;
}

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

/* ==========================================================================
   10b. Sign-in pages (Login, Forgot Password, Reset Password)
   ========================================================================== */

.tz-auth-body {
    background: #2b2b33 url('../img/login-bg2.jpg') center / cover no-repeat fixed;
    min-height: 100vh;
    margin: 0;
}

    /* Darken the photo so white text on it stays readable whatever the image is. */
    .tz-auth-body::before {
        content: "";
        position: fixed;
        inset: 0;
        background: linear-gradient(135deg, rgba(30,30,36,.82) 0%, rgba(30,30,36,.62) 100%);
        z-index: 0;
    }

.tz-auth-wrap {
    position: relative;
    z-index: 1;
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 30px 16px;
}

.tz-auth-card {
    width: 100%;
    max-width: 410px;
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 18px 50px rgba(0,0,0,.35);
    overflow: hidden;
}

.tz-auth-head {
    /*  Crimson is held through the top half - where the crest sits - before the
        ramp to gold. Same two brand colours and the same warmth as before; it
        just no longer puts a pale crest on a pale ground. */
    background: linear-gradient(160deg, var(--tz-crimson) 0%, var(--tz-crimson) 52%, var(--tz-gold) 100%);
    padding: 26px 26px 22px 26px;
    text-align: center;
}

    /*  No white plate behind the crest. Logo2.png is a transparent PNG, so the
        plate was turning it into a sticker plaqued onto the header.

        It does mean the crest has to sit on a ground it can be seen against, and
        it cannot sit on the gold end of the ramp: 52% of its opaque pixels are
        near-white (it averages #bdac9b) and light-on-gold measures 1.12:1, so
        half the crest would simply vanish. That is why .tz-auth-head below holds
        crimson for the top portion and only turns to gold underneath. */
    .tz-auth-head img {
        max-height: 74px;
        width: auto;
        background: none;
        padding: 0;
        filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .35));
    }

    .tz-auth-head h1 {
        margin: 14px 0 0 0;
        font-size: 16px;
        font-weight: 700;
        letter-spacing: 1.4px;
        text-transform: uppercase;
        color: #fff;
    }

    .tz-auth-head p {
        margin: 5px 0 0 0;
        font-size: 12.5px;
        color: rgba(255,255,255,.9);
    }

.tz-auth-body-inner {
    padding: 26px;
}

.tz-auth-foot {
    padding: 14px 26px 22px 26px;
    text-align: center;
    font-size: 12px;
    color: var(--tz-text-faint);
}

/* Separated from the sign-in options above by a rule, so an external destination does not read
   as another way of getting into the portal. */
.tz-auth-alt {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--tz-border);
}

.tz-auth-alt-label {
    display: block;
    margin-bottom: 8px;
    font-size: 11.5px;
    color: var(--tz-text-faint);
}

    .tz-auth-foot a {
        color: var(--tz-crimson);
        font-weight: 600;
        text-decoration: none;
    }

        .tz-auth-foot a:hover {
            text-decoration: underline;
        }

/* "or" separator between the password and magic-link sign-in options */
.tz-auth-divider {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 18px 0 14px 0;
    color: var(--tz-text-faint);
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: .8px;
}

    .tz-auth-divider::before,
    .tz-auth-divider::after {
        content: "";
        flex: 1 1 auto;
        height: 1px;
        background: var(--tz-border);
    }

/* Password field with a reveal toggle */
.tz-password-wrap {
    position: relative;
}

    .tz-password-wrap .tz-input {
        padding-right: 40px;
    }

.tz-toggle-password {
    position: absolute;
    right: 12px;
    bottom: 9px;
    cursor: pointer;
    color: var(--tz-text-faint);
    z-index: 5;
    background: none;
    border: 0;
    padding: 0;
    line-height: 1;
}

    .tz-toggle-password:hover {
        color: var(--tz-ink);
    }

/* Live password-rule checklist on the reset page. The .valid / .invalid class
   names are set by that page's script, so they are kept as-is. */
.tz-pwrules {
    background: var(--tz-surface-alt);
    border: 1px solid var(--tz-border);
    border-radius: var(--tz-radius-sm);
    padding: 12px 14px;
    margin-bottom: 16px;
    font-size: 12px;
}

    .tz-pwrules div {
        padding: 2px 0;
    }

    .tz-pwrules i {
        margin-right: 8px;
        width: 13px;
        display: inline-block;
        text-align: center;
    }

    .tz-pwrules .valid {
        color: var(--tz-success) !important;
        font-weight: 600;
    }

    .tz-pwrules .invalid {
        color: var(--tz-text-faint);
    }

/* Text inputs must stay selectable - a previous rule elsewhere disabled it. */
.tz-auth-card input {
    -webkit-user-select: text !important;
    -moz-user-select: text !important;
    -ms-user-select: text !important;
    user-select: text !important;
    pointer-events: auto !important;
}

/* ==========================================================================
   10c. Motion and polish
   --------------------------------------------------------------------------
   Everything here hangs off class names the views already use, so no view needs
   editing to pick it up. Keep it restrained - this is a records system students
   use under deadline pressure, not a marketing site. Movement should tell them
   something arrived or responded, never decorate.

   The whole section is switched off under prefers-reduced-motion at the end.
   ========================================================================== */

@keyframes tz-fade-up {
    from {
        opacity: 0;
        transform: translateY(10px);
    }

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

@keyframes tz-fade-in {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

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

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

@keyframes tz-shimmer {
    from {
        background-position: -420px 0;
    }

    to {
        background-position: 420px 0;
    }
}

@keyframes tz-pop {
    0% {
        transform: scale(.94);
        opacity: 0;
    }

    60% {
        transform: scale(1.02);
    }

    100% {
        transform: scale(1);
        opacity: 1;
    }
}

/* --- Page entrance ------------------------------------------------------- */

.tz-page-head {
    animation: tz-slide-down .32s ease-out both;
}

.tz-banner {
    animation: tz-fade-up .38s ease-out both;
}

/* Cards arrive in sequence rather than all at once. Capped at six so a long
   page never leaves the reader waiting on the last one. */
.tz-card {
    animation: tz-fade-up .38s ease-out both;
}

    .tz-card:nth-of-type(1) {
        animation-delay: .02s;
    }

    .tz-card:nth-of-type(2) {
        animation-delay: .07s;
    }

    .tz-card:nth-of-type(3) {
        animation-delay: .12s;
    }

    .tz-card:nth-of-type(4) {
        animation-delay: .17s;
    }

    .tz-card:nth-of-type(5) {
        animation-delay: .22s;
    }

    .tz-card:nth-of-type(n+6) {
        animation-delay: .26s;
    }

.tz-stat,
.tz-hero-tile,
.tz-fee-tile {
    animation: tz-fade-up .34s ease-out both;
}

.tz-stats .tz-stat:nth-child(2),
.tz-hero > *:nth-child(2) {
    animation-delay: .06s;
}

.tz-stats .tz-stat:nth-child(3),
.tz-hero > *:nth-child(3) {
    animation-delay: .12s;
}

.tz-stats .tz-stat:nth-child(4) {
    animation-delay: .18s;
}

.tz-stats .tz-stat:nth-child(5) {
    animation-delay: .24s;
}

/* Callouts slide in - they usually appear in response to something. */
.tz-hint {
    animation: tz-slide-down .3s ease-out both;
}

/* Quick-action rows cascade down the panel. */
.tz-quick-item {
    animation: tz-fade-up .3s ease-out both;
}

    .tz-quick-item:nth-child(1) {
        animation-delay: .04s;
    }

    .tz-quick-item:nth-child(2) {
        animation-delay: .08s;
    }

    .tz-quick-item:nth-child(3) {
        animation-delay: .12s;
    }

    .tz-quick-item:nth-child(4) {
        animation-delay: .16s;
    }

    .tz-quick-item:nth-child(5) {
        animation-delay: .20s;
    }

    .tz-quick-item:nth-child(6) {
        animation-delay: .24s;
    }

    .tz-quick-item:nth-child(7) {
        animation-delay: .28s;
    }

    .tz-quick-item:nth-child(n+8) {
        animation-delay: .32s;
    }

/* Empty states and the sign-in card get a gentler treatment. */
.tz-empty {
    animation: tz-fade-in .4s ease-out both;
}

.tz-auth-card {
    animation: tz-pop .34s cubic-bezier(.2, .8, .3, 1) both;
}

/* --- Response to touch --------------------------------------------------- */

.tz-card {
    transition: box-shadow .2s ease, transform .2s ease;
}

.tz-stat,
.tz-info-item {
    transition: box-shadow .18s ease, transform .18s ease, border-color .18s ease;
}

    .tz-stat:hover,
    .tz-info-item:hover {
        transform: translateY(-2px);
        box-shadow: var(--tz-shadow-lg);
    }

.tz-hero-tile {
    transition: transform .18s ease, box-shadow .18s ease;
}

    .tz-hero-tile:hover {
        transform: translateY(-3px);
        box-shadow: 0 10px 24px rgba(16, 24, 40, .18);
    }

.tz-btn {
    transform: translateZ(0);
}

    .tz-btn:hover:not(:disabled) {
        box-shadow: 0 4px 10px rgba(16, 24, 40, .12);
    }

    .tz-btn:active:not(:disabled) {
        transform: translateY(1px);
        box-shadow: none;
    }

/* Table rows settle rather than snap. */
.tz-table tbody tr {
    transition: background .15s ease;
}

/* Pills pop when they first render - they are the thing the eye should find.
   Not inside tables: a results table can hold hundreds of them, and animating
   every one at once stutters badly on the low-end machines students use. */
.tz-pill {
    animation: tz-pop .26s ease-out both;
}

.tz-table .tz-pill {
    animation: none;
}

/* Photo: hint that it can be replaced. */
.tz-avatar {
    transition: transform .2s ease, border-color .2s ease;
}

.tz-avatar-row:hover .tz-avatar {
    transform: scale(1.04);
    border-color: var(--tz-crimson);
}

/* --- Keyboard focus ------------------------------------------------------
   Visible focus is not decoration. Anyone navigating by keyboard needs to see
   where they are, and the browser default is nearly invisible on dark chrome. */

.tz-btn:focus-visible,
.tz-quick-item:focus-visible,
.tz-link:focus-visible,
.tz-input:focus-visible,
.tz-select:focus-visible,
.tz-nav-link:focus-visible {
    outline: 2px solid var(--tz-gold);
    outline-offset: 2px;
    border-radius: var(--tz-radius-sm);
}

/* --- Loading placeholder -------------------------------------------------
   Add class="tz-skeleton" to a block being filled by AJAX so the space is
   visibly reserved instead of collapsing and then jumping. */

.tz-skeleton {
    min-height: 90px;
    border-radius: var(--tz-radius-sm);
    background: linear-gradient(90deg, #f2f4f7 25%, #e9ecf2 37%, #f2f4f7 63%);
    background-size: 840px 100%;
    animation: tz-shimmer 1.3s linear infinite;
}

/* --- Loading overlay -----------------------------------------------------
   Overrides CSS/Loader.css, which is loaded before this file. The original was
   a black 80% sheet behind a 300x100 white box with a 5px light-blue border and
   an animated GIF, positioned by JavaScript arithmetic on every show. This is
   the same two elements, restyled and centred by CSS. */

.modalLoader {
    background: rgba(28, 28, 34, .55) !important;
    opacity: 1 !important;
    filter: none !important;
    backdrop-filter: blur(2px);
    animation: tz-fade-in .15s ease-out both;
}

.loading {
    width: auto !important;
    height: auto !important;
    min-width: 168px;
    border: 0 !important;
    border-top: 3px solid var(--tz-gold) !important;
    border-radius: var(--tz-radius) !important;
    background: #fff !important;
    box-shadow: 0 12px 34px rgba(0,0,0,.28) !important;
    padding: 22px 26px !important;
    font-family: inherit !important;
    font-size: 12.5px !important;
    color: var(--tz-text-muted);
    text-align: center;
    /* Centred here rather than by the inline top/left the script used to set. */
    top: 50% !important;
    left: 50% !important;
    transform: translate(-50%, -50%);
}

.tz-spinner {
    width: 34px;
    height: 34px;
    margin: 0 auto 10px auto;
    border: 3px solid var(--tz-border);
    border-top-color: var(--tz-crimson);
    border-right-color: var(--tz-gold);
    border-radius: 50%;
    animation: tz-spin .7s linear infinite;
}

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

/* --- Reduced motion ------------------------------------------------------
   Honour the operating-system setting. Some people get motion sickness or
   migraines from movement on screen; for them everything below simply appears. */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }

        .tz-card,
        .tz-stat,
        .tz-hero-tile,
        .tz-fee-tile,
        .tz-hint,
        .tz-quick-item,
        .tz-pill,
        .tz-auth-card,
        .tz-page-head,
        .tz-banner,
        .tz-empty {
            animation: none !important;
            opacity: 1 !important;
            transform: none !important;
        }

        .tz-stat:hover,
        .tz-info-item:hover,
        .tz-hero-tile:hover,
        .tz-btn:active:not(:disabled) {
            transform: none;
        }
}

/* ==========================================================================
   11. Print
   ========================================================================== */

@media print {
    .pcoded-navbar,
    .pcoded-header,
    .tz-page-actions,
    .tz-btn,
    #styleSelector {
        display: none !important;
    }

    .tz-page {
        background: #fff;
        padding: 0;
    }

    .tz-card {
        box-shadow: none;
        border: 1px solid #999;
        break-inside: avoid;
    }

    .tz-scroll {
        max-height: none;
        overflow: visible;
        border: 0;
    }

    .tz-card-head {
        background: #fff !important;
        color: #000 !important;
        border-bottom: 2px solid #000;
    }

        .tz-card-head h2,
        .tz-card-head .tz-card-title {
            color: #000 !important;
        }

    .tz-table thead th {
        background: #ddd !important;
        color: #000 !important;
        position: static;
    }
}

/* ==========================================================================
   12. Small screens
   ========================================================================== */

@media (max-width: 768px) {
    /*  Containment guard. The theme puts overflow-x: hidden on <body>, which suppresses the
        sideways scrollbar but does not stop content being laid out wider than the screen - it
        just clips it, so cards lose their right-hand edge with no way to scroll to it. These
        caps stop the layout exceeding the viewport in the first place. */
    .pcoded-main-container,
    .pcoded-content,
    .pcoded-inner-content,
    .tz-page {
        max-width: 100%;
    }

    .tz-page {
        padding: 16px 14px 50px 14px;
    }

    .tz-page-head h1 {
        font-size: 18px;
    }

    .tz-facts {
        gap: 10px 18px;
    }

    .tz-card-body {
        padding: 14px;
    }

    .tz-btn {
        padding: 8px 13px;
        font-size: 12px;
    }

    .tz-stat .tz-stat-value {
        font-size: 20px;
    }
}

/* ==========================================================================
   Unit picker (Course Registration dialog)
   ========================================================================== */

.tz-units-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}

.tz-units-title {
    display: block;
    font-size: 14px;
    font-weight: 700;
    color: var(--tz-ink);
}

.tz-units-sub {
    display: block;
    font-size: 12px;
    color: var(--tz-text-muted);
}

/*  The credit budget. It used to be invisible until you exceeded it and got a
    warning; showing it while choosing is the whole point. */
.tz-credit-meter {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 7px 14px;
    border-radius: 999px;
    background: var(--tz-gold-soft);
    border: 1px solid rgba(209, 156, 44, .45);
    white-space: nowrap;
}

    .tz-credit-meter .tz-credit-count {
        font-size: 15px;
        font-weight: 700;
        color: var(--tz-ink);
        font-variant-numeric: tabular-nums;
    }

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

    /*  At the ceiling. Not an error - a full basket is a normal, correct state -
        so this reads as "done", not "wrong". */
    .tz-credit-meter.tz-credit-full {
        background: var(--tz-success-soft);
        border-color: rgba(46, 125, 50, .4);
    }

        .tz-credit-meter.tz-credit-full .tz-credit-count {
            color: var(--tz-success);
        }

/* --- The table ---------------------------------------------------------- */

.tz-units-table .tz-pick-col {
    width: 56px;
    text-align: center;
    vertical-align: middle;
}

.tz-units-table input[type="checkbox"] {
    width: 16px;
    height: 16px;
    cursor: pointer;
    accent-color: var(--tz-crimson);
}

.tz-units-table .tz-code {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.tz-units-table .tz-num {
    text-align: center;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

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

/*  A unit already sitting in the basket. Left visible rather than filtered out,
    so the list still matches what the student expects to see, but it cannot be
    picked twice. */
.tz-units-table tbody tr.tz-already {
    opacity: .55;
}

    .tz-units-table tbody tr.tz-already:hover {
        background: transparent;
    }

.tz-already-tag {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--tz-success-soft);
    color: var(--tz-success);
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
}

.tz-units-table .tz-stream {
    min-width: 110px;
}

/* --- Action row ---------------------------------------------------------- */

.tz-units-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--tz-border);
}

.tz-units-status {
    font-size: 12.5px;
    color: var(--tz-text-muted);
}

.tz-units-actions .tz-btn:disabled {
    opacity: .45;
    cursor: not-allowed;
}

@media (max-width: 575px) {
    .tz-units-head,
    .tz-units-actions {
        flex-direction: column;
        align-items: stretch;
    }

        .tz-units-actions .tz-btn {
            width: 100%;
            justify-content: center;
        }
}

/* ==========================================================================
   Empty / unavailable states
   --------------------------------------------------------------------------
   A panel for "this is not available to you", as distinct from "something
   broke". Most reasons a form is withheld are ordinary - not yet graduating,
   window not open - and reporting those as errors tells a student the portal
   is broken when it is working exactly as intended.
   ========================================================================== */

.tz-state {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 22px 24px;
    border-radius: var(--tz-radius);
    border: 1px solid var(--tz-border);
    border-left: 4px solid var(--tz-gold);
    background: var(--tz-surface);
}

.tz-state-icon {
    flex: 0 0 auto;
    width: 42px;
    height: 42px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--tz-gold-soft);
    color: var(--tz-gold-dark);
    font-size: 20px;
}

.tz-state-body {
    min-width: 0;
}

    .tz-state-body h3 {
        margin: 2px 0 6px 0;
        font-size: 15px;
        font-weight: 700;
        color: var(--tz-ink);
    }

    .tz-state-body p {
        margin: 0 0 6px 0;
        font-size: 13px;
        line-height: 1.55;
        color: var(--tz-text);
        max-width: 70ch;
    }

    .tz-state-body .tz-state-next {
        color: var(--tz-text-muted);
        margin-bottom: 0;
    }

/*  The error treatment, for when something genuinely did go wrong. */
.tz-state-error {
    border-left-color: var(--tz-danger);
}

    .tz-state-error .tz-state-icon {
        background: var(--tz-danger-soft);
        color: var(--tz-danger);
    }
