/* ---------------------------------------------------------------------------
   Additions for the Razor Pages build. site.css holds the original theme
   untouched; everything new to this rewrite belongs here.
   --------------------------------------------------------------------------- */

/* --- login page ---------------------------------------------------------- */

.login-page-body {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--bg-color) 0%, #dce6ea 100%);
    padding: 1rem;
}

.login-container {
    width: 100%;
    max-width: 420px;
    background: #fff;
    border-radius: 14px;
    padding: 2.25rem 2rem;
    box-shadow: 0 10px 40px rgba(0, 100, 125, .12);
}

.login-logo {
    height: 64px;
    width: auto;
    margin-bottom: .75rem;
}

/* --- mobile bottom navigation -------------------------------------------
   New in this build: the legacy UI simply hid the sidebar on small screens
   and left only a hamburger. The bar is fixed to the bottom and mirrors the
   sidebar's items, so the primary actions stay one tap away on a phone.      */

.bottom-nav {
    display: none;
}

@media (max-width: 991.98px) {
    .bottom-nav {
        display: flex;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 1030;
        background: #fff;
        border-top: 1px solid #e2e8f0;
        box-shadow: 0 -2px 12px rgba(0, 0, 0, .06);
        /* Clear the iOS home indicator. */
        padding-bottom: env(safe-area-inset-bottom, 0);
    }

    .bottom-nav__item {
        flex: 1 1 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        padding: .5rem .25rem;
        font-size: .68rem;
        line-height: 1.1;
        color: #64748b;
        text-decoration: none;
        border: 0;
        background: none;
        /* Comfortable tap target. */
        min-height: 56px;
    }

    .bottom-nav__item i {
        font-size: 1.2rem;
    }

    .bottom-nav__item.active {
        color: var(--primary-color);
        font-weight: 600;
    }

    .bottom-nav__item .badge {
        position: absolute;
        transform: translate(14px, -10px);
        font-size: .6rem;
    }

    /* Stop the bar covering the end of the page. !important because the
       element also carries Bootstrap's .py-4 utility, which is itself
       !important and would otherwise win. */
    .app-content {
        padding-bottom: 84px !important;
    }
}

/* --- open-ticket chooser -------------------------------------------------- */

.link-choice-head {
    background: linear-gradient(180deg, var(--bg-color) 0%, #fff 100%);
}

.link-choice-icon {
    width: 56px;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: #fff;
    color: var(--primary-color);
    font-size: 1.5rem;
    box-shadow: 0 2px 10px rgba(0, 100, 125, .15);
}

.link-choice-remember {
    background: var(--bg-color);
    cursor: pointer;
}

.link-choice-remember:hover {
    background: #e6edf0;
}

#linkChoiceSubtitle {
    word-break: break-all;
    font-size: .78rem;
}

/* --- forced password change ---------------------------------------------- */

.password-requirements {
    font-size: .82rem;
    color: #64748b;
}

.password-requirements li.met {
    color: var(--success-color);
}

.password-requirements li.met::marker {
    content: "✓ ";
}

/* --- System Configuration on small screens -------------------------------
   Ten tabs will not fit on a phone. Rather than wrapping into an unreadable
   stack, the tab strip scrolls horizontally and the tables inside each pane
   scroll independently.                                                      */

.config-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
}

.config-tabs::-webkit-scrollbar {
    height: 3px;
}

.config-tabs .nav-link {
    white-space: nowrap;
}

@media (max-width: 767.98px) {
    .config-tabs .nav-link {
        font-size: .82rem;
        padding: .5rem .65rem;
    }

    /* Config tables carry 5-7 columns; let them scroll rather than crush. */
    .tab-content .table-responsive {
        -webkit-overflow-scrolling: touch;
    }

    .tab-content .table td,
    .tab-content .table th {
        white-space: nowrap;
    }

    /* The e-mail template editor is unusable in two columns on a phone. */
    #tab-templates .row > [class*="col-"] {
        width: 100%;
        flex: 0 0 100%;
        max-width: 100%;
    }

    /* !important: the element carries an inline max-height for the desktop
       two-column layout, which would otherwise win here. */
    #templateList {
        max-height: 220px !important;
    }

    .note-editor .note-toolbar {
        overflow-x: auto;
        flex-wrap: nowrap;
    }
}

/* --- e-mail message viewer ------------------------------------------------
   The iframe owns the scrolling. Wrapping it in a scrollable modal body means
   two nested scroll containers, which on touch devices routinely traps the
   gesture and leaves the message unreadable.                                 */

.email-view-frame {
    width: 100%;
    border: 0;
    /* Fills whatever the flex column leaves after header, meta and footer. */
    flex: 1 1 auto;
    min-height: 0;
    background: #f0f4f6;
    /* Momentum scrolling inside the frame on iOS. */
    -webkit-overflow-scrolling: touch;
}

@media (min-width: 992px) {
    .email-view-dialog .modal-content {
        height: 82vh;
    }
}

@media (max-width: 991.98px) {
    /* Full-screen: the dialog is the viewport, so the frame gets all of it. */
    .email-view-dialog .modal-content {
        height: 100%;
    }

    #emailViewMeta {
        /* Recipient lists get long; keep them from eating the message. */
        max-height: 28vh;
        overflow-y: auto;
        word-break: break-word;
    }
}

/* --- misc ---------------------------------------------------------------- */

.table-responsive-sticky thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: #fff;
}

[hidden] {
    display: none !important;
}

/* --- profile photos ------------------------------------------------------ */
/*
   Every avatar is <img src="/avatars/{id}"> — the server returns the photo or
   generated initials, so there is no empty state to style here. Square source
   (256px, centre-cropped in the browser), so object-fit only matters for the
   initials SVG, which is square anyway.
*/

.avatar {
    border-radius: 50%;
    object-fit: cover;
    flex: 0 0 auto;
    background: #dee2e6;
}

.avatar-xs { width: 24px; height: 24px; }
.avatar-sm { width: 32px; height: 32px; }
.avatar-md { width: 44px; height: 44px; }
.avatar-lg { width: 120px; height: 120px; }

/* On the teal navbar a plain circle reads as a hole; the ring separates it. */
.navbar .avatar {
    box-shadow: 0 0 0 2px rgba(255, 255, 255, .65);
}

/* The photo card on My Profile: image and its controls side by side, stacking
   on a phone where 120px plus buttons will not fit on one line. */
.avatar-edit {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
}

.avatar-edit__preview {
    position: relative;
    line-height: 0;
}

/* Shown over the preview while an upload is in flight. */
.avatar-edit__busy {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(255, 255, 255, .7);
}

/* --- welcome card ---------------------------------------------------------
   Shown once per sign-in on the dashboard. Built on Bootstrap's modal so the
   backdrop, focus handling and Escape key are the browser's problem and not
   ours — the mockup this came from declared aria-modal on a plain div, which
   claims a behaviour it did not have.

   Colours come from the brand tokens in site.css. Hardcoding the palette here
   is how two teals end up in one product.
---------------------------------------------------------------------------- */

.welcome-card {
    border: none;
    border-radius: 24px;
    overflow: hidden;
}

.welcome-card__body {
    display: flex;
    align-items: stretch;
}

.welcome-card__avatar {
    flex: 0 0 140px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem 1rem;
    background: var(--bg-color, #F0F4F6);
    position: relative;
}

/* Tinted by the time of day — set from script, since only the browser knows
   what o'clock it is where the user is sitting. */
.welcome-card__avatar::after {
    content: '';
    position: absolute;
    inset: 0;
    opacity: .18;
    background: var(--welcome-tint, transparent);
    pointer-events: none;
}

.welcome-card__avatar img {
    width: 104px;
    height: 104px;
    border-radius: 50%;
    object-fit: cover;
    background: #fff;
    box-shadow: 0 6px 16px rgba(0, 0, 0, .10), 0 0 0 3px #fff;
    position: relative;
    z-index: 1;
}

.welcome-card__content {
    flex: 1;
    padding: 1.5rem 1.6rem;
    min-width: 0;
}

.welcome-card__greeting {
    font-size: 1.4rem;
    font-weight: 600;
    letter-spacing: -.02em;
    line-height: 1.25;
}

.welcome-card__role {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .4px;
}

/* The figures. Each is a link to the list it describes — the card is a way
   into the work, not an ornament. */
.welcome-stats {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    margin: 1rem 0 .25rem;
}

.welcome-stat {
    flex: 1 1 0;
    min-width: 7.5rem;
    display: block;
    padding: .6rem .8rem;
    border-radius: 12px;
    background: #f6f8fa;
    border: 1px solid #e6ebf0;
    text-decoration: none;
    color: inherit;
    transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}

.welcome-stat:hover {
    transform: translateY(-2px);
    border-color: var(--primary-color);
    box-shadow: 0 6px 14px rgba(0, 0, 0, .08);
    color: inherit;
}

.welcome-stat__value {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
    color: var(--primary-color);
}

.welcome-stat__label {
    font-size: .74rem;
    color: #5b6f82;
    margin-top: .2rem;
    line-height: 1.3;
}

.welcome-stat--warn .welcome-stat__value { color: var(--warning-color); }
.welcome-stat--urgent .welcome-stat__value { color: var(--danger-color); }

/* Zero is good news on these two, so it should not shout. */
.welcome-stat--quiet .welcome-stat__value { color: var(--success-color); }

.welcome-card__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 1rem;
}

.welcome-card__timer {
    font-size: .78rem;
    color: #5b6f82;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}

.welcome-card__track {
    height: 4px;
    background: #e9edf2;
    border-radius: 20px;
    overflow: hidden;
    margin-top: 1rem;
}

.welcome-card__fill {
    height: 100%;
    width: 100%;
    border-radius: 20px;
    background: linear-gradient(90deg, var(--primary-color), var(--success-color));
    transition: width .25s linear;
}

@media (max-width: 575.98px) {
    .welcome-card__body { flex-direction: column; }

    .welcome-card__avatar {
        flex: 0 0 auto;
        padding: 1.4rem 1rem .6rem;
    }

    .welcome-card__avatar img { width: 84px; height: 84px; }
    .welcome-card__content { padding: .8rem 1.2rem 1.4rem; }
    .welcome-card__greeting { font-size: 1.2rem; }
    .welcome-stat { flex: 1 1 100%; }
}

/* --- employee detail popup ------------------------------------------------
   The tabs hold very different amounts: a profile of thirty fields, or an
   empty telecom list. Left alone the dialog jumps in height on every tab
   click and the mouse ends up over the wrong control. A floor plus a ceiling
   keeps it still, and the body scrolls when a list is long.
--------------------------------------------------------------------------- */

/* A fixed height, not a min and a max: with a range the profile still opened
   at 640px and the telecom tab at 416px, so the dialog jumped and the mouse
   ended up over the wrong control. One height for every tab, and the body
   scrolls inside it. The cost is empty space under a short list, which is the
   cheaper of the two problems. */
#viewEmployeeModal .modal-body {
    height: min(68vh, 38rem);
    overflow-y: auto;
}

/* Profile: a header strip over two columns of labelled cards.
   Values sit in their own column beside the labels — the previous field grid
   spread pairs across the full width, leaving values floating mid-screen with
   nothing to line up against. */

.emp-head {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: .9rem 1rem;
    border-radius: 12px;
    background: #f6f8fa;
    border: 1px solid #e6ebf0;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

.emp-head__main { flex: 1 1 16rem; min-width: 0; }
.emp-head__name { font-size: 1.05rem; font-weight: 700; line-height: 1.25; }

.emp-head__meta {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem .9rem;
    font-size: .8rem;
    color: #5b6f82;
    margin-top: .15rem;
}

.emp-head__code { font-weight: 700; color: var(--primary-color); }
.emp-head__side { text-align: right; }
.emp-head__joined { font-size: .75rem; color: #5b6f82; margin-top: .25rem; }

/* Stand-in when the employee has no login, and therefore no photo. */
.emp-head__nophoto {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: #dee2e6;
    color: #6c757d;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.3rem;
    flex: 0 0 auto;
}

.emp-card {
    border: 1px solid #e6ebf0;
    border-radius: 12px;
    overflow: hidden;
    margin-bottom: 1rem;
    background: #fff;
}

.emp-card__header {
    padding: .55rem .9rem;
    background: #f6f8fa;
    border-bottom: 1px solid #e6ebf0;
    font-size: .8rem;
    font-weight: 700;
    color: #1e2a36;
}

.emp-card__header i { color: var(--primary-color); }
.emp-card__body { padding: .35rem .9rem .6rem; }

.emp-row {
    display: flex;
    gap: 1rem;
    padding: .35rem 0;
    border-bottom: 1px solid #f2f5f8;
}

.emp-row:last-child { border-bottom: none; }

.emp-row__label {
    flex: 0 0 42%;
    font-size: .8rem;
    color: #6b7c8d;
}

.emp-row__value {
    flex: 1 1 auto;
    font-size: .8rem;
    font-weight: 600;
    color: #1e2a36;
    overflow-wrap: anywhere;
}

.emp-row__value--empty { font-weight: 400; color: #b3bec9; }

/* ---------------------------------------------------------------------------
   Unassigned tickets in the list.

   A ticket with nobody on it is the one state in the grid that needs somebody
   to act, so it is the one row that is allowed to shout. The amber matches the
   SLA-warning badge already used in the same table rather than introducing a
   third colour.

   The tint carries the signal on its own because the Assigned column is hidden
   below the lg breakpoint — on a phone the row colour is the only thing left.

   !important is needed for the background alone: Bootstrap's .table sets cell
   backgrounds through --bs-table-bg on the <td>, which would otherwise paint
   over anything set on the <tr>.
   --------------------------------------------------------------------------- */

.ticket-unassigned > td {
    background-color: #FFF8E6 !important;
}

/* The bar sits on the first cell so it reads as a marker down the left edge of
   the row without a border on every cell. */
.ticket-unassigned > td:first-child {
    box-shadow: inset 3px 0 0 0 var(--warning-color);
}

.table-hover > tbody > tr.ticket-unassigned:hover > td {
    background-color: #FDEFC9 !important;
}


/* ---------------------------------------------------------------------------
   Ticket taxonomy tree (System Configuration -> Categories)

   A parent/child table rather than a strip of chips: with ~100 sub-categories
   the chips wrapped into a wall that could not be scanned, and there was nowhere
   to put a sub-category's own order, ticket count or SLA override.
   --------------------------------------------------------------------------- */
.tax-row-cat > td            { background: var(--bs-tertiary-bg, #f4f7f8); }
.tax-row-cat                 { border-top: 2px solid #dee2e6; }
.tax-name-cat                { font-weight: 600; }

/* The indent rail: one continuous line down the children of a category, so the
   eye can follow which parent a row belongs to without counting pixels. */
.tax-row-sub .tax-name-sub   { position: relative; padding-left: 2.15rem; }
.tax-row-sub .tax-name-sub::before {
    content: ''; position: absolute; left: 1rem; top: -0.55rem; bottom: 50%;
    border-left: 1px solid #ced4da; border-bottom: 1px solid #ced4da;
    width: 0.7rem; border-bottom-left-radius: 3px;
}
.tax-row-sub.tax-not-last .tax-name-sub::after {
    content: ''; position: absolute; left: 1rem; top: 50%; bottom: -0.55rem;
    border-left: 1px solid #ced4da;
}
.tax-row-sub.tax-off td      { opacity: .5; }

.tax-toggle                  { border: 0; background: none; padding: .1rem .3rem;
                               color: #6c757d; line-height: 1; }
.tax-toggle:hover            { color: var(--bs-primary, #0d7a74); }
.tax-toggle .bi              { transition: transform .15s ease; display: inline-block; }
.tax-toggle.tax-open .bi     { transform: rotate(90deg); }

.tax-dot                     { width: 10px; height: 10px; border-radius: 50%;
                               display: inline-block; flex: 0 0 auto; }
.tax-flag                    { font-size: .68rem; padding: .1rem .4rem; border-radius: 3px;
                               border: 1px solid transparent; white-space: nowrap; }
.tax-flag-sla                { background: #e7f5f7; color: #0b5d68; border-color: #b8dde3; }
.tax-flag-catch              { background: #f3eefa; color: #59349b; border-color: #dccdf0; }
.tax-flag-pri                { background: #fff4e0; color: #8a5a00; border-color: #f3ddb3; }
.tax-empty                   { font-size: .78rem; color: #8a96a0; font-style: italic; }

/* --- ticket filter bar ----------------------------------------------------

   Two rows: everyone's filters, then the IT team's plus the actions. The labels
   are set once here rather than on each column so a filter added later lines up
   with the rest without anyone remembering to copy the classes. */

.ticket-filters .form-label {
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
}

/* The multi-selects render their own button; this keeps them the same height as
   the search box beside them, which they were not. */
.ticket-filters .dropdown-toggle,
.ticket-filters .form-select,
.ticket-filters .form-control {
    font-size: .82rem;
}

/* Checked state for the SLA toggle needs to survive .btn-check, which only
   styles the label when the input is checked. */
.ticket-filters .btn-check:checked + .btn-outline-danger {
    color: #fff;
}

/* --- sticky sidebar -------------------------------------------------------

   The navigation used to scroll away with the page, so on a long ticket list
   you had to scroll back to the top to go anywhere. It now stays put under the
   header.

   --app-header-h is measured and published by layout.js rather than assumed:
   the brand wraps at some widths and the logo is configurable, so the 56px the
   old rule hard-coded was right on exactly one screen. The fallback matters only
   for the moment before the script runs.

   Only from lg up, because below that the sidebar is display:none and the mobile
   bottom bar does this job instead. */

@media (min-width: 992px) {
    .sidebar {
        position: sticky;
        top: var(--app-header-h, 56px);

        /* Its own scrollbar, for when the navigation is taller than the space
           left under the header. overscroll-behavior stops a scroll that reaches
           the end of this list from carrying on into the page behind it. */
        height: calc(100vh - var(--app-header-h, 56px));
        overflow-y: auto;
        overscroll-behavior: contain;

        /* min-height would fight the height above and win, which would push the
           bottom of the navigation below the fold again. */
        min-height: 0;
    }

    /* A quieter scrollbar than the platform default, which is heavy for a
       column this narrow. */
    .sidebar::-webkit-scrollbar { width: 6px; }
    .sidebar::-webkit-scrollbar-thumb {
        background: #cbd5e1;
        border-radius: 3px;
    }
    .sidebar { scrollbar-width: thin; }
}

/* --- the sidebar as a mobile drawer ---------------------------------------

   Bootstrap's offcanvas is 400px wide by default, which is wider than a 375px
   phone: the panel covers the screen edge to edge with nothing of the page left
   showing behind it, so there is no visual cue that tapping away closes it.
   Leaving a strip of backdrop visible is what makes it read as a drawer. */

.sidebar.offcanvas-lg {
    --bs-offcanvas-width: min(19rem, 82vw);
}

/* The offcanvas header is the only chrome the drawer needs; at lg and up the
   panel is a plain column again and the header is hidden by d-lg-none. */
.sidebar.offcanvas-lg .offcanvas-header {
    border-bottom: 1px solid #ccfbf1;
}

/* .offcanvas-body adds its own padding, which would double the column padding
   the aside already carries at desktop. */
@media (min-width: 992px) {
    .sidebar.offcanvas-lg .offcanvas-body { padding: 0; overflow: visible; }
}

/* Plan benefits in a grid cell: two lines, the rest in the tooltip. */
.ois-benefits {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-width: 160px;
    max-width: 280px;
    white-space: normal;
    font-size: .75rem;
    color: var(--bs-secondary-color);
}

/* --- busy popup (busy.js) ------------------------------------------------ */

.ois-busy {
    position: fixed;
    inset: 0;
    z-index: 2000; /* above Bootstrap modals (1055) and toasts (1080) */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(0, 40, 52, .38);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    opacity: 0;
    visibility: hidden;
    transition: opacity .18s ease, visibility 0s linear .18s;
    outline: none;
}

.ois-busy.is-visible {
    opacity: 1;
    visibility: visible;
    transition: opacity .18s ease;
}

body.ois-busy-open { overflow: hidden; }

.ois-busy__card {
    width: 100%;
    max-width: 380px;
    background: #fff;
    border-radius: 16px;
    padding: 28px 28px 22px;
    text-align: center;
    box-shadow: 0 24px 60px rgba(0, 40, 52, .28);
    border-top: 4px solid var(--primary-color, #00647D);
    transform: translateY(8px) scale(.98);
    transition: transform .2s ease;
}

.ois-busy.is-visible .ois-busy__card { transform: none; }

.ois-busy__ring {
    position: relative;
    width: 64px;
    height: 64px;
    margin: 0 auto 16px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ois-busy__ring::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 4px solid #e3eef1;
    border-top-color: var(--primary-color, #00647D);
    border-right-color: var(--secondary-color, #D4960A);
    animation: ois-busy-spin .9s linear infinite;
}

.ois-busy__icon {
    font-size: 1.35rem;
    color: var(--primary-color, #00647D);
}

.ois-busy__title {
    font-weight: 600;
    font-size: 1.05rem;
    color: #12303a;
}

.ois-busy__detail {
    margin-top: 4px;
    font-size: .85rem;
    color: #5b6b73;
    word-break: break-word;
}

.ois-busy__bar {
    position: relative;
    height: 4px;
    margin: 18px 0 10px;
    border-radius: 4px;
    background: #e3eef1;
    overflow: hidden;
}

.ois-busy__bar span {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 35%;
    border-radius: 4px;
    background: linear-gradient(90deg, var(--primary-color, #00647D), var(--secondary-color, #D4960A));
    animation: ois-busy-slide 1.4s ease-in-out infinite;
}

.ois-busy__elapsed {
    min-height: 1.2em;
    font-size: .8rem;
    font-variant-numeric: tabular-nums;
    color: var(--primary-color, #00647D);
}

.ois-busy__hint {
    font-size: .78rem;
    color: #7a8990;
}

.ois-busy__hint:not(:empty) { margin-top: 4px; }

.ois-busy__bar.is-determinate span {
    left: 0;
    width: 0;
    animation: none;
    transition: width .5s ease;
}

.ois-busy__away { margin-top: 14px; }

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

@keyframes ois-busy-slide {
    0%   { left: -35%; }
    100% { left: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    .ois-busy__ring::before { animation-duration: 2.4s; }
    .ois-busy__bar span { animation: none; left: 0; width: 100%; opacity: .5; }
}

/* ---------------------------------------------------------------------------
   OISSelect — the searchable dropdown every <select> is upgraded to.

   Omran, 18 Sep 2026: one dropdown control across the whole system, searchable,
   and a checkbox list when it takes more than one value.

   The button deliberately wears Bootstrap's own .form-select, so an upgraded
   field is the same height, border and caret as the text inputs beside it; the
   colours below only add the states a native select has no way to show.

   The panel is portaled to the enclosing .modal (or to <body>), which is why it
   is position:fixed and why it carries a z-index above the modal itself.
   --------------------------------------------------------------------------- */

.oss-wrap { position: relative; display: block; }
.oss-wrap--auto { display: inline-block; width: auto; vertical-align: middle; }
.oss-wrap--auto .oss-btn { width: auto; }

/* Still in the form, still posted, still validated — just not seen. Not
   display:none: the browser anchors its "please select an item" bubble to it. */
.oss-native {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    pointer-events: none;
    z-index: -1;
}

.oss-btn {
    display: flex;
    align-items: center;
    text-align: left;
    cursor: pointer;
    overflow: hidden;
}

.oss-btn .oss-label {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.oss-btn.oss-empty .oss-label { color: #9aa5ab; }
.oss-btn:hover:not(:disabled) { border-color: var(--primary-color, #00647D); }

.oss-btn.oss-active {
    border-color: var(--primary-color, #00647D);
    box-shadow: 0 0 0 .2rem rgba(0, 100, 125, .15);
}

.oss-btn:disabled { background-color: #e9ecef; cursor: not-allowed; opacity: 1; }

.oss-panel {
    position: fixed;
    z-index: 1090;                      /* over .modal (1055) and .ms-dropdown (1080) */
    display: none;
    flex-direction: column;
    min-width: 180px;
    background: #fff;
    border: 1px solid #dee2e6;
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .15);
    overflow: hidden;
}

.oss-panel.oss-show { display: flex; }

.oss-search-wrap { position: relative; padding: 8px; border-bottom: 1px solid #f0f0f0; }

.oss-search-icon {
    position: absolute;
    left: 17px;
    top: 50%;
    transform: translateY(-50%);
    font-size: .8rem;
    color: #9aa5ab;
    pointer-events: none;
}

.oss-search {
    width: 100%;
    padding: 5px 9px 5px 29px;
    font-size: .84rem;
    border: 1px solid #dee2e6;
    border-radius: 5px;
    outline: none;
}

.oss-search:focus { border-color: var(--primary-color, #00647D); }

.oss-actions {
    display: flex;
    gap: 10px;
    padding: 6px 10px;
    border-bottom: 1px solid #f0f0f0;
}

.oss-action {
    padding: 0;
    font-size: .78rem;
    color: var(--primary-color, #00647D);
    background: none;
    border: none;
    text-decoration: underline;
    cursor: pointer;
}

.oss-action:hover { color: #003C50; }

.oss-list { flex: 1; overflow-y: auto; padding: 4px 0; }

.oss-group {
    padding: 6px 12px 3px;
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: #9aa5ab;
}

.oss-item {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 12px;
    font-size: .875rem;
    cursor: pointer;
}

.oss-item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Hover and keyboard share one highlight, so the two never disagree about
   what Enter is about to pick. */
.oss-item.oss-active { background: #f0fdfa; }
.oss-item.oss-selected { font-weight: 600; color: var(--primary-color, #00647D); }
.oss-item.oss-placeholder { color: #9aa5ab; font-style: italic; }
.oss-item.oss-disabled { color: #c3cace; cursor: not-allowed; }
.oss-tick { font-size: .9rem; color: var(--primary-color, #00647D); }

.oss-check {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    border: 1px solid #c3cace;
    border-radius: 4px;
    background: #fff;
    color: #fff;
    font-size: .7rem;
}

.oss-check .bi { visibility: hidden; }

.oss-item.oss-selected .oss-check {
    background: var(--primary-color, #00647D);
    border-color: var(--primary-color, #00647D);
}

.oss-item.oss-selected .oss-check .bi { visibility: visible; }

.oss-empty-msg { padding: 14px; text-align: center; font-size: .85rem; color: #9aa5ab; }

@media (max-width: 575.98px) {
    .oss-panel { max-width: calc(100vw - 16px); }
}
