/* ======================================================================
   SmartAdmin theme adoption.

   Phase 1 put Bootstrap 5 and the SmartAdmin stylesheet underneath the app, but
   the theme's own rules target class names StaffMIS does not use (.panel-hdr,
   .panel-container, .panel-content, .form-label), so its LOOK never reached the
   markup. Measured on a real screen: of the 110 classes on the page, the theme
   stylesheet had rules for 38 and nothing at all for the other 72.

   This file closes that gap without touching markup, in two parts:

   1. It re-points the design tokens in staffmis-ui.css at SmartAdmin's values, so
      every structural rule already written there (form rows, two-column pairing,
      the panel title bar, the sidebar rail, the table kit) inherits the theme's
      colour, type and radius rather than the palette I had chosen.

   2. It maps StaffMIS's Bootstrap 3 components onto the theme's visual treatment,
      so a .panel-heading looks like a .panel-hdr without being renamed.

   Load order: AFTER staffmis-ui.css, because part 1 overrides its :root.
   ====================================================================== */

/* ----------------------------------------------------------------------
   1. Tokens, taken from the theme's own custom properties rather than guessed:
      --font-family "Inter", --app-content-background #fdfdfd, --bs-body-bg #fff,
      --bs-body-color #212529, --bs-border-color #dee2e6, --border-radius-uniform
      .375rem, --bs-body-font-size .875rem, and the panel shadow 0 0 13px #0000000d.

      Inter is NOT bundled with the theme and it declares no @font-face at all;
      dentbasket simply names it and falls back to the system stack. Same here, so
      this adds no external request and nothing to load on a poolside connection.
   ---------------------------------------------------------------------- */
.sm {
    --font:       'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
    --font-narrow:'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;

    --ink:        #212529;
    --ink-soft:   #6c757d;
    --ink-faint:  #8b949b;

    /* The theme's primary. StaffMIS's teal is one token if you want it back. */
    --pool:       #0d6efd;
    --pool-deep:  #0a58ca;
    --pool-wash:  #cfe2ff;

    --surface:    #fdfdfd;   /* --app-content-background */
    --card:       #ffffff;   /* --bs-body-bg */
    --line:       #dee2e6;   /* --bs-border-color */
    --line-soft:  #e9ecef;

    --r:          .375rem;   /* --border-radius-uniform */
    --shadow:     0 0 13px rgba(0, 0, 0, .05);

    /* Status colours move to the theme's semantic set. The washes are the theme's
       own -bg-subtle values, so alert and status rows stay legible against it. */
    --done:        #198754;  --done-wash:    #d1e7dd;
    --due:         #997404;  --due-wash:     #fff3cd;
    --overdue:     #dc3545;  --overdue-wash: #f8d7da;
    --idle:        #6c757d;  --idle-wash:    #e2e3e5;

    font-family: var(--font);
    /* The theme sets a 14px base; the previous reskin used 15px. Following the
       theme keeps its component paddings in proportion.

       It is a TOKEN rather than a literal because "larger text" has to move it.
       Scaling the root font-size does nothing here: this rule is absolute px, so
       it simply wins. Measured before this changed: the root went 16px to 18px
       while the body stayed stubbornly at 14px. */
    --base-font: 14px;
    font-size: var(--base-font);
}

/* ----------------------------------------------------------------------
   2. Components. StaffMIS's Bootstrap 3 vocabulary, given the theme's treatment.
   ---------------------------------------------------------------------- */

/* Panels. The theme's panel is a soft-shadowed card with no heavy border and a
   1.5rem gap beneath it; bs3-compat.css gave .panel a plain bordered box just to
   stop it collapsing, and this is what makes it look like the theme. */
.sm .panel {
    border: 0;
    box-shadow: var(--shadow);
    border-radius: var(--r);
    margin-bottom: 1.5rem;
    background: var(--card);
}
.sm .panel-heading {
    background: transparent;
    border-bottom: 1px solid var(--line);
    padding: .75rem 1.25rem;
    font-weight: 600;
}
.sm .panel-body { padding: 1.25rem; }   /* --content-padding */

/* The content panel gets the same treatment, so a screen built with
   content_header() and one built from a .panel look like the same product. */
.sm #main-container {
    border: 0;
    box-shadow: var(--shadow);
    border-radius: var(--r);
}

/* Tables. The theme uses .5rem cell padding and a subtle bottom rule rather than
   the boxed grid Bootstrap 3 drew. 349 of the app's 491 tables carry no .table
   class at all, so this has to reach bare <table> too. */
.sm table { border-collapse: collapse; }
.sm .table > :not(caption) > * > *,
.sm table > thead > tr > th,
.sm table > tbody > tr > td,
.sm table > tbody > tr > th { padding: .5rem; }
.sm table > thead > tr > th {
    font-family: var(--font);
    font-weight: 600;
    color: var(--ink-soft);
    border-bottom: 1px solid var(--line);
}
.sm table > tbody > tr > td { border-bottom: 1px solid var(--line-soft); }

/* Form controls, matched to the theme's field metrics. */
.sm .form-control,
.sm .form-select,
.sm select.form-control {
    border-radius: var(--r);
    border-color: var(--line);
    font-size: var(--base-font);
}
.sm .form-control:focus,
.sm .form-select:focus {
    border-color: var(--pool);
    box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);
}

/* Buttons.

   .btn-primary does NOT mean "primary action" in this app. template-app-ui.min.js
   adds "btn btn-primary" to EVERY submit, button and input-button on the page
   (everything except .close and .js-ignore), so a neutral Cancel arrives in the
   browser as "btn btn-default btn-primary" and a genuine primary arrives as
   "btn btn-primary". The class that actually carries meaning is .btn-default,
   which the PHP puts on neutral buttons and that script never removes.

   So .btn-default has to WIN when both are present, which is why it is written
   with the extra .btn qualifier: (0,3,0) beats .sm .btn-primary at (0,2,0).
   Ordering alone would be too fragile to rely on here. */
.sm .btn { border-radius: var(--r); font-weight: 500; }
.sm .btn-primary { background: var(--pool); border-color: var(--pool); color: #fff; }
.sm .btn-primary:hover { background: var(--pool-deep); border-color: var(--pool-deep); }
.sm .btn.btn-default { background: #fff; border-color: var(--line); color: var(--ink); }
.sm .btn.btn-default:hover { background: var(--surface); border-color: #ced4da; color: var(--ink); }

/* Input groups. Bootstrap 5 gives .input-group flex-wrap:wrap so validation text
   can drop below the field. With Bootstrap 3 markup that wraps the addon itself
   onto its own line, which is what broke the date picker's calendar button away
   from its input. These groups are always a single row. */
.sm .input-group { flex-wrap: nowrap; }
.sm .input-group > .form-control { width: auto; flex: 1 1 auto; min-width: 0; }

/* Tabs, in the theme's flatter style: no boxed tab, just a weighted underline. */
.sm .nav-tabs { border-bottom: 1px solid var(--line); }
.sm .nav-tabs > li > a { border: 0; border-bottom: 2px solid transparent; color: var(--ink-soft); }
.sm .nav-tabs > li > a:hover { border-color: transparent transparent var(--line); color: var(--ink); }
.sm .nav-tabs > li.active > a {
    background: transparent;
    border-bottom-color: var(--pool);
    color: var(--pool);
    font-weight: 600;
}

/* ======================================================================
   Top bar.

   The sidebar carries navigation. This carries what is about the PERSON rather
   than the page: who they are signed in as, and the display settings they need in
   order to read the screen at all.

   It is fixed and starts where the rail ends, so the sidebar keeps its logo and
   the bar never scrolls away from someone who needs the contrast toggle.
   ====================================================================== */
.sm { --topbar-h: 56px; }

.sm .sm-topbar {
    position: fixed;
    top: 0;
    left: var(--rail-w);      /* same token as the rail, so they cannot drift */
    right: 0;
    height: var(--topbar-h);
    z-index: 30;              /* above sticky page chrome, below modals */
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 16px;
    background: var(--card);
    border-bottom: 1px solid var(--line);
}
.sm .sm-topbar__title {
    font-family: var(--font-narrow);
    font-weight: 600;
    color: var(--ink-soft);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sm .sm-topbar__actions { margin-left: auto; display: flex; align-items: center; gap: 6px; }

.sm .sm-topbar__btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 40px;
    padding: 0 10px;
    border: 1px solid transparent;
    border-radius: var(--r);
    background: transparent;
    color: var(--ink-soft);
    cursor: pointer;
    list-style: none;
}
.sm .sm-topbar__btn::-webkit-details-marker { display: none; }
.sm .sm-topbar__btn:hover { background: var(--surface); color: var(--ink); }
.sm .sm-topbar__icon { width: 20px; height: 20px; stroke: currentColor; fill: none; stroke-width: 2; }
.sm .sm-topbar__name { font-weight: 600; color: var(--ink); }
.sm .sm-topbar__avatar {
    width: 28px; height: 28px; border-radius: 50%;
    background-size: cover; background-position: center;
    background-color: var(--line-soft);
}

/* The menus are <details> rather than scripted dropdowns, so they open, close and
   take keyboard focus with no JavaScript of their own. That matters here more than
   elsewhere: this is the menu holding the accessibility controls. */
.sm .sm-topbar__menu { position: relative; }
.sm .sm-topbar__panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 250px;
    padding: 12px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r);
    box-shadow: var(--shadow);
    z-index: 40;
}
.sm .sm-topbar__panel-title {
    margin: 0 0 8px;
    font-family: var(--font-narrow);
    font-size: 12px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-faint);
}
.sm .sm-topbar__opt {
    display: flex; align-items: center; gap: 10px;
    padding: 7px 2px; margin: 0; font-weight: 400; cursor: pointer;
}
.sm .sm-topbar__note { margin: 8px 0 0; font-size: 12px; color: var(--ink-faint); }
.sm .sm-topbar__who { margin: 0 0 8px; display: flex; flex-direction: column; }
.sm .sm-topbar__who span { font-size: 12px; color: var(--ink-faint); }
.sm .sm-topbar__link {
    display: block; padding: 8px 2px; color: var(--ink); text-decoration: none;
    border-top: 1px solid var(--line-soft);
}
.sm .sm-topbar__link:hover { color: var(--pool); }

/* Make room for the bar, and move the sticky page chrome down below it. Both
   offsets read the same variable as the bar height, so they cannot drift apart.

   The padding goes on #page-wrapper, NOT #content-wrapper. The site banners and the
   page header are SIBLINGS of #content-wrapper, not children, so padding that
   element pushed the content clear of the fixed bar and left the banner sitting
   underneath it at top: 0 -- visible, but with the bar swallowing every click on
   it. The "you have actions which require completing" banner was unclickable
   because of exactly this.

   #sidebar-wrapper is position:fixed, so it ignores this padding and the rail
   still starts at the top of the viewport. */
.sm #page-wrapper { padding-top: var(--topbar-h); }
.sm .page-header--actions { top: var(--topbar-h); }
.sm .sm-formtabs__nav { top: calc(var(--topbar-h) + var(--pagehead-h)); }

/* Larger text is a real accessibility need here: this is used on a poolside or a
   gym floor, often at arm length. Scaling the root lets every rem-based size in
   the theme follow, rather than patching individual components. */
.sm-big-text { font-size: 112.5%; }

/* The bar spans the full width only where the rail has stopped being a left column,
   which is below 768px (app-ui.css, staffmis-ui.css and bs3-compat's .visible-xs all
   switch there), not at 900px: with left:0 at 768-900px the bar (z-index 30) sat over
   the top of a rail (z-index 10) still on screen, logo link included. 767.98, not 767,
   because those rules are min-width:768 and a zoomed browser can report a fractional
   width between the two that would match neither. */
@media (max-width: 900px) {
    .sm .sm-topbar__name, .sm .sm-topbar__title { display: none; }
}
@media (max-width: 767.98px) {
    .sm .sm-topbar { left: 0; }
}

/* ======================================================================
   Accessibility modes reaching this app's own tokens.

   The theme implements high contrast and colourblind mode by overriding --bs-*
   variables. That is not enough here: smartadmin-theme.css points .sm at its own
   --ink and --line tokens, and those win, so switching high contrast on changed
   the Bootstrap variables and left every StaffMIS surface exactly as it was.
   Measured before this rule existed: body colour stayed #212529 with the mode on.

   So the modes are restated against the tokens the app actually reads.
   ====================================================================== */
.set-high-contrast-mode .sm,
.set-high-contrast-mode.sm {
    --ink:        #000;
    --ink-soft:   #000;
    --ink-faint:  #3a3a3a;
    --line:       #000;
    --line-soft:  #767676;   /* still a visible rule, not a hairline */
    --pool:       #0000EE;   /* the browser default link blue, highest familiarity */
    --pool-deep:  #000088;
    --surface:    #fff;
}
.set-high-contrast-mode .sm a { text-decoration: underline; }
.set-high-contrast-mode .sm .btn { border-width: 2px; }

/* Colourblind mode: status must not be carried by hue alone. The palette moves to
   a blue/orange pairing, which is separable under every common form of colour
   vision deficiency, and status text stops relying on red versus green. */
.set-colorblind-mode .sm,
.set-colorblind-mode.sm {
    --done:        #0072B2;  --done-wash:    #d6e9f5;
    --due:         #E69F00;  --due-wash:     #fdf1dc;
    --overdue:     #D55E00;  --overdue-wash: #fbe3d6;
    --pool:        #0072B2;
    --pool-deep:   #005486;
}

/* Larger text scales the root so every rem in the theme follows. The topbar is
   fixed in px on purpose: it must not grow so tall it eats the screen. */
.sm-big-text { font-size: 112.5%; }


/* ======================================================================
   Dark mode.

   Bootstrap 5.3 themes its OWN components from data-bs-theme, and the SmartAdmin
   sheet follows it, so form controls, dropdowns and tables adapt on their own.
   What did not adapt was everything StaffMIS-shaped, because this file points .sm
   at its own tokens and those had only light values. Measured before this block
   existed: switching dark mode changed the attribute and NOTHING else -- body
   colour stayed rgb(33,37,41) on rgb(253,253,253), the top bar stayed white.
   ====================================================================== */
[data-bs-theme="dark"] .sm,
[data-bs-theme="dark"].sm {
    --ink:        #e6e8ea;
    --ink-soft:   #a9b2ba;
    --ink-faint:  #7d868e;

    --surface:    #16191d;
    --card:       #1f2429;
    --line:       #363c43;
    --line-soft:  #2a2f35;

    --pool:       #5aa2ff;
    --pool-deep:  #7db4ff;
    --pool-wash:  #1b2b40;

    --done-wash:    #12301f;
    --due-wash:     #33280c;
    --overdue-wash: #3a1a1a;
    --idle-wash:    #24282c;

    --shadow: 0 0 13px rgba(0, 0, 0, .45);

    /* Deeper than the page, so the rail still reads as a separate plane rather
       than merging into the content behind it. */
    --rail:       #0d1013;
}

/* bs3-compat.css hardcodes #fff on the components Bootstrap 5 deleted, because at
   that point there was no theme to read. Those are the surfaces that stayed white
   in dark mode, so they are re-pointed at the token here. */
[data-bs-theme="dark"] .sm .panel,
[data-bs-theme="dark"] .sm .well,
[data-bs-theme="dark"] .sm .thumbnail,
[data-bs-theme="dark"] .sm #main-container,
[data-bs-theme="dark"] .sm .btn.btn-default,
[data-bs-theme="dark"] .sm .nav-tabs > li.active > a {
    background: var(--card);
    color: var(--ink);
    border-color: var(--line);
}
[data-bs-theme="dark"] .sm .panel-heading,
[data-bs-theme="dark"] .sm .page-header--actions,
[data-bs-theme="dark"] .sm .input-group-addon { background: var(--surface); color: var(--ink); }
[data-bs-theme="dark"] .sm .btn.btn-default:hover { background: #2a3037; }
[data-bs-theme="dark"] .sm .sm-formtabs__nav { background: var(--card); }

/* ======================================================================
   Larger text.

   Moves the base token rather than the root, for the reason given above, and
   restates the few sizes that are set in px on reading surfaces. Headings are
   already large and are deliberately left alone: this is about body text, which
   is what someone turning this on is struggling to read.
   ====================================================================== */
.sm-big-text .sm,
.sm-big-text.sm { --base-font: 16.5px; }

.sm-big-text .sm table,
.sm-big-text .sm td,
.sm-big-text .sm th,
.sm-big-text .sm input,
.sm-big-text .sm select,
.sm-big-text .sm textarea,
.sm-big-text .sm .btn,
.sm-big-text .sm .control-label,
.sm-big-text .sm label,
.sm-big-text .sm p,
.sm-big-text .sm li { font-size: var(--base-font); }

/* ======================================================================
   Colourblind mode.

   Be straight about what this can do. The theme implements it by adding stripe
   patterns to .bg-danger, .bg-success and friends, and StaffMIS barely uses those
   Bootstrap contextual classes, so on its own it changed almost nothing visible.

   What it can do here is stop meaning being carried by red-versus-green. The
   status tokens move to a blue/orange pairing, which stays separable under every
   common form of colour vision deficiency, and links gain an underline so they are
   identifiable without relying on hue at all.
   ====================================================================== */
.set-colorblind-mode .sm a:not(.btn),
.set-colorblind-mode.sm a:not(.btn) { text-decoration: underline; }

.set-colorblind-mode .sm .sm-topbar__btn { text-decoration: none; }

/* ======================================================================
   Navigation tree in the rail.

   Replaces a full-screen overlay of oversized tiles that hid the page, offered no
   search, made every section a drill-down and gave no sign of where you were.
   A tree costs one column of width and removes a click from every journey.

   Branches are <details>, so they open, close and take keyboard focus with no
   JavaScript. With scripting off this is still the complete menu, navigable.
   ====================================================================== */
.sm #sidebar-wrapper { overflow-y: auto; overflow-x: hidden; }

.sm .sm-nav { padding: 4px 0 24px; }

.sm .sm-nav__search-wrap { padding: 8px 12px 10px; }
.sm .sm-nav__search {
    width: 100%;
    min-height: 36px;
    padding: 0 10px;
    font-size: 13px;
    color: #fff;
    background: rgba(255,255,255,.07);
    border: 1px solid rgba(255,255,255,.14);
    border-radius: var(--r);
}
.sm .sm-nav__search::placeholder { color: rgba(255,255,255,.45); }
.sm .sm-nav__search:focus {
    outline: 2px solid rgba(255,255,255,.35);
    outline-offset: 1px;
    background: rgba(255,255,255,.12);
}

.sm .sm-nav__list { list-style: none; margin: 0; padding: 0; }
.sm .sm-nav__item { margin: 0; }

.sm .sm-nav__link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 12px;
    min-height: 36px;
    color: #C7D6DA;
    font-size: 13px;
    text-decoration: none;
    border-left: 3px solid transparent;
    cursor: pointer;
    list-style: none;
}
.sm .sm-nav__link::-webkit-details-marker { display: none; }
.sm .sm-nav__link:hover { background: rgba(255,255,255,.06); color: #fff; }
.sm .sm-nav__link--plain { cursor: default; color: rgba(255,255,255,.5); }
.sm .sm-nav__icon { width: 16px; flex: 0 0 16px; text-align: center; opacity: .85; }
.sm .sm-nav__text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A branch shows its state with a caret that rotates, rather than swapping glyphs,
   so nothing shifts position when it opens. */
.sm .sm-nav__link--branch::after {
    content: "";
    margin-left: auto;
    width: 0; height: 0;
    border-left: 4px solid currentColor;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    opacity: .6;
    transition: transform .12s ease;
}
.sm .sm-nav__branch[open] > .sm-nav__link--branch::after { transform: rotate(90deg); }
.sm .sm-nav__branch[open] > .sm-nav__link--branch { color: #fff; }

/* Indent by depth, so nesting is readable without drawing guide lines. */
.sm .sm-nav__list--d1 .sm-nav__link { padding-left: 30px; }
.sm .sm-nav__list--d2 .sm-nav__link { padding-left: 46px; }
.sm .sm-nav__list--d3 .sm-nav__link { padding-left: 62px; }

/* The page you are on, using the same edge marker as the icon items above. */
.sm .sm-nav__link[aria-current="page"] {
    background: rgba(255,255,255,.10);
    border-left-color: var(--pool);
    color: #fff;
    font-weight: 600;
}

.sm .sm-nav__empty { padding: 10px 12px; margin: 0; color: rgba(255,255,255,.5); font-size: 13px; }

/* On a phone the rail is a bottom bar, so a tall tree does not belong in it.

   767.98px, not 900px: that is where the shell actually turns the rail into a bottom
   bar (see the top bar above for the .98). At 768-900px the rail is still the
   full-height left column, and hiding the tree there left a tablet with a dark column
   holding a logo and an icon or two.

   Hidden is not gone. The Menu button in the top bar (app-ui.php) lifts the same rail
   into a drawer, and .sm-nav-open shows the tree inside it. */
.sm .sm-topbar__btn.sm-topbar__navtoggle { display: none; }
.sm .sm-nav-scrim { display: none; }
/* Focused by sm-nav.js when the drawer opens, as a place to start from, not as a
   control, so it does not need a ring of its own. */
.sm .sm-nav:focus { outline: none; }

@media (max-width: 767.98px) {
    .sm .sm-nav { display: none; }

    .sm .sm-topbar__btn.sm-topbar__navtoggle { display: inline-flex; }

    /* The drawer is the rail itself, lifted off the bottom edge. It starts BELOW the
       top bar so the Menu button stays visible to close it again, and sits above the
       sticky page chrome (z-index 20) but under the bar (30) and its menus (40). */
    .sm.sm-nav-open #sidebar-wrapper {
        top: var(--topbar-h);
        bottom: 0;
        left: 0;
        right: auto;
        width: var(--rail-w);
        max-width: 86vw;
        z-index: 29;
        border-top: 0;
        border-right: 1px solid rgba(255,255,255,.08);
        box-shadow: var(--shadow);
    }
    .sm.sm-nav-open .sm-nav { display: block; }

    /* 16px or iOS Safari zooms the whole page when the box is focused. It never
       appeared on a phone before the drawer, so this never came up. */
    .sm.sm-nav-open .sm-nav__search { font-size: 16px; }

    .sm.sm-nav-open .sm-nav-scrim {
        display: block;
        position: fixed;
        top: var(--topbar-h);
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 28;
        background: rgba(0, 0, 0, .45);
    }

    /* The same lock the old tile menu applied, so the page does not scroll away
       underneath the drawer. */
    .sm.sm-nav-open { overflow: hidden; }
}

/* Paper. A Menu button means nothing printed, and printing with the drawer open
   would otherwise keep the scroll lock above (cutting the print short in some
   browsers) and lay the scrim over the page. */
@media print {
    .sm .sm-topbar__btn.sm-topbar__navtoggle,
    .sm .sm-nav-scrim { display: none !important; }
    .sm.sm-nav-open { overflow: visible; }
}

/* ======================================================================
   Navigation grouping.

   The menu is mostly flat: on a real tenant it is 14 top-level entries of which
   only 3 have children. Rendering every row at the same weight made it a wall of
   equal items with nothing for the eye to skip, which is what made the rail hard
   to read even after the overlay went.

   The grouping is taken from the DATA rather than invented: an entry with children
   IS a section, so it is styled as one. Nothing is re-ordered and nothing is
   re-categorised, because the order is the tenant's own configuration and guessing
   at semantic groups would be wrong for every tenant that arranged it differently.
   ====================================================================== */

/* A branch reads as a section header: smaller, spaced, quieter than its contents. */
.sm .sm-nav__link--branch {
    font-family: var(--font-narrow);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #C7D6DA; /* the same as every other entry: a section is told apart by its type, not by being dimmer */
    margin-top: 6px;
}
.sm .sm-nav__branch[open] > .sm-nav__link--branch { color: #C7D6DA; }
.sm .sm-nav__link--branch:hover { background: transparent; color: #fff; }

/* Its contents sit closer to the header than to the next section, so the grouping
   is legible from spacing alone rather than relying on the caret. */
.sm .sm-nav__branch > .sm-nav__list { padding-bottom: 6px; }
.sm .sm-nav__branch[open] { border-left: 2px solid rgba(255,255,255,.07); }

/* The pinned zone above is a different kind of thing to the menu, so it gets a
   rule rather than just more spacing. */
.sm .sm-nav { border-top: 1px solid rgba(255,255,255,.09); margin-top: 6px; }

/* An entry with neither a link nor children. It is left visible rather than hidden,
   because it is the tenant's own menu data and dropping rows from that silently is
   how people lose things they configured -- but it must NOT be dressed as a section
   header. Styled that way it read as a group with nothing in it, which is worse than
   showing it plainly. It looks disabled, because that is what it is. */
.sm .sm-nav__link--plain {
    color: rgba(255,255,255,.32);
    cursor: default;
    font-style: italic;
}
.sm .sm-nav__link--plain:hover { background: transparent; }

/* A filled-in icon rather than one the tenant chose. Quieter, so it reads as a
   bullet keeping the labels aligned rather than as a claim about what the page is. */
.sm .sm-nav__icon--generic { font-size: 8px; }

/* ======================================================================
   The actions banner, as one section rather than three competing boxes.

   The markup reuses ONE class for both roles: the summary bar and each item
   inside it are all .site-banners__banner, separated only by a danger/info
   modifier. So the expanded state rendered as a stack of full alert boxes, each
   with its own background and border, wrapped in a 1px red box with no padding.
   Three borders competing at the same weight is what made it look broken.

   Treated as a disclosure instead: the bar is the header, the panel below is its
   body, and the items in it are rows. One accent down the left ties them together.
   ====================================================================== */

/* The header. Square off the bottom while open so it joins the panel rather than
   floating above it. */
.sm .site-banners__banner {
    border-radius: var(--r);
    text-decoration: none;
}
.sm .site-banners:has(.collapse.show) > .site-banners__banner,
.sm .site-banners:has(.collapsing) > .site-banners__banner {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

/* The panel. The 1px red box is the thing that looked wrong: it drew a second,
   thinner border around content that already sat inside the banner's own frame.
   It carries the accent down the left instead, so the section reads as continuous. */
/* The selector matches the shape of the rule it is overriding, rather than reaching
   for !important. basic_stylesheet.css:1583 says
   `.site-banners__banner.danger + #site-banner-actions`, which is (1,2,0); a plain
   `.sm #site-banner-actions` is (1,1,0) and quietly loses, which is exactly what
   happened -- the red box stayed and only the parts I had NOT collided with changed. */
.sm .site-banners__banner.danger + #site-banner-actions,
.sm #site-banner-actions {
    border: 0;
    border-left: 5px solid var(--overdue);
    border-radius: 0 0 var(--r) var(--r);
    background: var(--card);
    box-shadow: var(--shadow);
    padding: 4px 0;
    margin-top: -1px;
}

/* The items. Rows in a list, not alerts in a stack: no box of their own, a hairline
   between them, and the text starts where the header's text starts. */
.sm #site-banner-actions > .site-banners__banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    margin: 0;
    padding: 10px 16px;
    text-align: left;
    color: var(--ink);
    border-bottom: 1px solid var(--line-soft);
}
.sm #site-banner-actions > .site-banners__banner:last-child { border-bottom: 0; }
.sm #site-banner-actions > .site-banners__banner:hover {
    background: var(--pool-wash);
    color: var(--ink);
}

/* The dismiss control sits at the end of its row rather than floating over it. */
.sm #site-banner-actions > .site-banners__banner > .close {
    position: static;
    float: none;
    margin-left: auto;
    font-size: 1.1rem;
    line-height: 1;
    color: var(--ink-faint);
}
.sm #site-banner-actions > .site-banners__banner > .close:hover { color: var(--ink); }

/* Selectors 4 :has() is not everywhere. Without it the header simply keeps its
   rounded corners while open, which is a cosmetic difference, not a broken layout. */

/* ======================================================================
   Communications.

   Two problems, both about hierarchy rather than decoration.

   1. The filter column is TWO independent axes -- a folder (Inbox, Sent, Drafts...)
      and a type (All, Messages, Notices...) -- stacked as two unlabelled lists with
      identical styling. So it read as one list of fourteen with TWO items selected,
      which looks like a bug rather than two filters.

   2. In a message row the sender was as loud as the subject, and the badge louder
      than both, so the eye landed on "FORMS MESSAGE" and "From:" before the thing
      that says what the message is.
   ====================================================================== */

/* Name the two axes. Targeted on the push classes because that column has no class
   of its own; it is the same element the push/pull shim above puts back on the right. */
.sm .col-md-push-9 > div:nth-of-type(1)::before,
.sm .col-sm-push-8 > div:nth-of-type(1)::before { content: "Folder"; }
.sm .col-md-push-9 > div:nth-of-type(2)::before,
.sm .col-sm-push-8 > div:nth-of-type(2)::before { content: "Type"; }

.sm .col-md-push-9 > div::before,
.sm .col-sm-push-8 > div::before {
    display: block;
    padding: 0 2px 6px;
    font-family: var(--font-narrow);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-faint);
}
.sm .col-md-push-9 > div:nth-of-type(2),
.sm .col-sm-push-8 > div:nth-of-type(2) { margin-top: 18px; }

/* One selection reads as primary; the other is a refinement of it, so it is tinted
   rather than filled. Two solid blue bars implied two competing selections. */
.sm .col-md-push-9 .list-group-item.active,
.sm .col-sm-push-8 .list-group-item.active {
    background: var(--pool);
    border-color: var(--pool);
    color: #fff;
}
.sm .col-md-push-9 > div:nth-of-type(2) .list-group-item.active,
.sm .col-sm-push-8 > div:nth-of-type(2) .list-group-item.active {
    background: var(--pool-wash);
    border-color: var(--line);
    color: var(--ink);
    font-weight: 600;
}

/* Message rows: subject first, then sender, then preview. */
.sm .list-group-item .label {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .04em;
    background: var(--line-soft);
    color: var(--ink-soft);
}
.sm .list-group-item .text-primary { color: var(--ink-soft) !important; font-weight: 500; }
.sm .list-group-item b { font-weight: 600; }
/* The preview is context, not content: one line, quiet, and it stops the rows being
   different heights depending on how much text a sender happened to write. */
.sm .list-group-item .mt-05 {
    color: var(--ink-soft);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.sm .list-group-item--unread { border-left: 3px solid var(--pool); }
.sm .list-group-item--unread b { font-weight: 700; }

/* ---------------------------------------------------------------------------
   IMS / file library index

   The section list rendered as 11 to 19 separate cards, each with its own
   shadow and a 24px gap, so a plain list of section names filled several
   screens and read as 19 unrelated objects rather than one contents page.
   They are collapsed here into a single card with dividers -- the same
   information, roughly a third of the scroll.

   The headings are the accordion controls, so they are given the affordances
   of one: pointer and a hover tint. Nothing is added for the open/closed
   indicator -- the component swaps fa-chevron-down for fa-chevron-up itself
   (see chevronClass in the bundle), so it already reads correctly. A CSS
   rotation was written here first and removed: it keyed on aria-expanded,
   which this component never sets, so it did nothing.
   --------------------------------------------------------------------------- */
.sm .sm-search { max-width: 420px; }

.sm .sm-ims .panel {
    margin-bottom: 0;
    border-radius: 0;
    box-shadow: none;
    border: 0;
    border-top: 1px solid var(--line);
}
.sm .sm-ims > div > .panel:first-of-type { border-top: 0; }

/* the outer card that the panels now sit inside */
.sm .sm-ims {
    display: block;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.sm .sm-ims .panel-heading {
    padding: 11px 16px;
    background: transparent;
    border: 0;
    cursor: pointer;
    transition: background .12s ease;
}
.sm .sm-ims .panel-heading:hover { background: var(--surface); }

/*
   Let the toggle cover the row it is styled as.

   The component puts its click handler on the first cell of the title row, which
   is only as tall as its text -- 21px inside a 43px row -- so the heading padding
   above and below it was dead while the whole row lit up on hover. The negative
   margin is cancelled by equal padding, so the cell's MARGIN box is unchanged and
   .panel-title keeps its height: the absolutely positioned chevron, which is
   pinned to that box, does not move. Only the hit area grows.
*/
.sm .sm-ims .panel-title > div:first-child { margin: -11px 0; padding: 11px 0; }

.sm .sm-ims .panel-title { font-size: 14px; font-weight: 600; }

.sm .sm-ims .panel-body { padding: 4px 16px 16px 16px; }

/* ---------------------------------------------------------------------------
   Tasks: cards, and the board view

   The task rows are shared markup (print_packet_line, eight call sites including
   a PDF report), so nothing here changes what the server sends. sm-taskboard.js
   regroups the rendered rows into .sm-task cards; this styles them, and lays the
   five panes out side by side when the board is chosen.

   The five columns are the app's own statuses, computed server-side in
   show_taskbooks() and previously shown one tab at a time. The board shows the
   same groups at once -- a task is never in a column its status did not put it in.
   --------------------------------------------------------------------------- */
/*
   One panel around the whole thing.

   The page background and the cards were both near-white (--surface #fdfdfd
   against --card #ffffff), so nothing had an edge and the page read as loose
   text on a flat field. The panel gives the content a boundary; it uses the
   same fill, border and shadow as .sm .panel so it is the app's own card, not
   a second idiom.
*/
.sm .sm-taskboard {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r);
    box-shadow: var(--shadow);
    padding: 16px;
}

/* the filters and the view switch share the top line of the panel */
.sm .sm-taskboard__top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}
/*
   Name the two dropdowns, and put them on one line.

   They look identical and do entirely different things. The first is not a
   filter at all: packet_options is the page's ACTION MENU -- picking an entry
   rewrites the form's purpose and submits it, so "New Task", "Recurring Tasks",
   "Daily Tasks Report" and the rest are navigation. The second, packet_location,
   really is a filter on the list below. Unlabelled and stacked, the only clue
   which was which was reading the options.

   The labels are attached in sm-taskboard.js, not here: both selects arrive in
   ONE .col-sm-12, so there is no per-control element to hang a ::before on --
   and a <select> cannot carry one anyway. The script wraps each in .sm-taskboard__field
   with a real <label for>, which is also the first accessible name these
   controls have had.
*/
.sm .sm-taskboard__filters {
    flex: 1 1 340px;
    min-width: 260px;
}
.sm .sm-taskboard__filters .form-group {
    border-bottom: 0;
    padding: 0;
    margin: 0;
    display: block;
    /*
       width is load-bearing: the two-column pairing rule in staffmis-ui.css sets
       width: calc(50% - 12px) on every form-group above 1100px, which held these
       two selects to half the room they had and ran the location name under its
       own chevron. Pairing is for a column of fields; this is one row of two.
    */
    width: 100%;
    max-width: none;
}
.sm .sm-taskboard__filters .form-group > [class*="col-sm-"] {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    padding: 0;
    width: auto;
}

/*
   The action menu as a row of buttons.

   Its destinations are now visible instead of hidden behind a select that only
   ever displayed the page you were already on. The current page is marked the
   same way the view switch marks its own -- filled in the accent, through
   Bootstrap's properties, because SmartAdmin sets .btn.active backgrounds with
   !important.
*/
.sm .sm-taskboard__actions {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 14px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--line);
}

/*
   The old top row. Location and the view switch have moved up into the action row, so
   all that is left here is the hidden action select, which stays in the DOM because it
   is the control the form submits. Collapsed rather than removed for that reason.
*/
.sm .sm-taskboard__top--empty {
    display: none;
}

/*
   The tabs and the tools share one line: which tasks on the left, what to do with them on
   the right. Saves the row each used to take.

   align-items: flex-end so the tools sit on the tabs baseline rather than floating in the
   middle of a taller row.
*/
.sm .sm-taskboard__tabbar {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    /*
       The underline moves here from .nav-tabs. Once the list stops spanning the panel it
       only underlines itself, and the rule that separates the controls from the tasks
       would stop short under the search box.
    */
    border-bottom: 1px solid var(--line);
    margin-bottom: 12px;
}

.sm .sm-taskboard__tabbar > .nav-tabs {
    border-bottom: 0;
    margin-bottom: 0;
}

/* searching and exporting, on the tabs line */
.sm .sm-taskboard__tools {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    flex-wrap: wrap;
    margin: 0 0 8px;
}

/* the destinations */
.sm .sm-taskboard__actions-main {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    /*
       0, not 1: growing to fill the row left the location and view controls no width to
       sit in, so they wrapped to a line of their own and the bar was two rows again for
       three short buttons. Taking only what the buttons need lets the pair share the line.
    */
    flex: 0 1 auto;
}

/* searching and exporting: things you do here, not places you go */
.sm .sm-taskboard__actions-side {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 0 auto;
    /*
       margin-left, not the parent's justify-content: once the destinations wrap
       to a second line this group wraps with them, and space-between then has
       nothing to push it against, so it landed back on the left. auto keeps it
       at the right edge on whichever line it ends up.
    */
    margin-left: auto;
}

.sm .sm-taskboard__search { width: 230px; flex-wrap: nowrap; }
.sm .sm-taskboard__search .form-control { min-width: 0; }

/* the export menu opens below its button, aligned to the right edge of the bar */
.sm .sm-taskboard__export .dropdown-menu {
    margin-top: 4px;
    min-width: 240px;
}
.sm .sm-taskboard__export .dropdown-item { cursor: pointer; }
/*
   A page's own export moved in as a link (the Daily Tasks Report's PDF): the same as the
   menu's other items, not the app's link look. !important only because SmartAdmin
   underlines every a[target] with it (a[target]:not(.btn)), and this one opens a new tab.
*/
.sm .sm-taskboard__export a.dropdown-item,
.sm .sm-taskboard__export a.dropdown-item:visited {
    color: var(--bs-dropdown-link-color);
    font-weight: 400;
    text-decoration: none !important;
}
.sm .sm-taskboard__export a.dropdown-item:hover,
.sm .sm-taskboard__export a.dropdown-item:focus {
    color: var(--bs-dropdown-link-hover-color);
    text-decoration: none !important;
}
.sm .sm-taskboard__export a.dropdown-item .fa { margin-right: 6px; }
.sm .sm-taskboard__actions .btn.active {
    --bs-btn-active-bg: var(--pool);
    --bs-btn-active-border-color: var(--pool);
    --bs-btn-active-color: #fff;
}

/*
   The page being looked at, kept in its menu (sm-taskboard.js, add) so the menu says where
   you are: tinted in the accent with a bar down its edge and bold. SmartAdmin marks an
   active item with a 5% tint, which nobody would notice. Not a link, so no pointer.
*/
/*
   Hovering (or tabbing to) an item in the Task Book's menus -- New Task, Views, More,
   Export -- tints it lightly in the accent, so you can see what you are about to choose.
   Lighter than the current page's mark below, which it leaves alone. The first background
   is for a browser without color-mix().
*/
.sm .sm-taskboard .dropdown-menu .dropdown-item:not(.active):hover,
.sm .sm-taskboard .dropdown-menu .dropdown-item:not(.active):focus-visible {
    background: var(--line-soft);
    background: color-mix(in srgb, var(--pool) 10%, transparent);
    color: var(--ink);
}

.sm .sm-taskboard__actions .dropdown-item.active,
.sm .sm-taskboard__actions .dropdown-item.active:hover,
.sm .sm-taskboard__actions .dropdown-item.active:focus {
    background: var(--pool-wash);
    color: var(--pool-deep);
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--pool);
    cursor: default;
}

/* the select stays for the buttons to drive and the form to submit */
.sm .sm-taskboard__field--hidden { display: none; }

.sm .sm-taskboard__field { flex: 1 1 190px; min-width: 170px; }

/*
   The location filter inside the action row.

   Its <label> is the accessible name the script added -- these selects had none at all --
   so it is hidden from sight rather than removed: a stacked caps label cost a line of its
   own in a row of 34px buttons, and the chosen location already reads as a location.
*/
.sm .sm-taskboard__actions-side .sm-taskboard__field {
    flex: 0 1 200px;
    min-width: 140px;
}

.sm .sm-taskboard__actions-side .sm-taskboard__label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
.sm .sm-taskboard__label {
    display: block;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--ink-soft);
    margin: 0 0 4px 0;
}

/*
   One segmented control rather than two loose buttons: they are two states of
   the same choice, so they are joined, and the active one is filled in the
   app's own accent instead of merely looking pressed.
*/
.sm .sm-taskboard__views {
    display: inline-flex;
    flex: 0 0 auto;
    gap: 0;
    margin: 0;
}
.sm .sm-taskboard__views .btn {
    border-radius: 0;
    margin: 0;
    position: relative;
}
.sm .sm-taskboard__views .btn:first-child { border-radius: var(--r) 0 0 var(--r); }
.sm .sm-taskboard__views .btn:last-child { border-radius: 0 var(--r) var(--r) 0; }

/* one border between the two, not two sitting side by side */
.sm .sm-taskboard__views .btn + .btn { margin-left: -1px; }

/*
   Colour the active half through Bootstrap's own custom properties, not by
   setting background here.

   SmartAdmin styles .btn.active with "background-color: var(--bs-btn-active-bg)
   !important", so a plain background declaration loses however specific it is --
   and --bs-btn-active-bg is empty for btn-default, which is why the pressed half
   went transparent rather than merely uncoloured. Setting the properties makes
   that same rule paint the colour we want.
*/
.sm .sm-taskboard__views .btn.active {
    --bs-btn-active-bg: var(--pool);
    --bs-btn-active-border-color: var(--pool);
    --bs-btn-active-color: #fff;
    z-index: 1;
}

/* --- the card ------------------------------------------------------------- */
.sm .sm-task {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: 12px 14px;
    margin-bottom: 10px;
}
.sm .sm-task > table { width: 100%; }

/*
   No borders inside a card. These rows are ordinary table cells, so they pick up
   the app's table rule and drew a hairline under every line of a task -- title,
   location, description, schedule -- which read as six rules per card. The card
   edge is the only division a task needs.
*/
.sm .sm-task td { padding: 1px 0; vertical-align: top; border: 0; }
.sm .sm-task tr { border: 0; }

/* the separator the rows still carry: the card edge replaces it */
.sm .sm-task hr { display: none; }
.sm .sm-task tr:has(hr) { display: none; }

/* the title is the one thing to find when scanning a column */
.sm .sm-task a b { font-weight: 600; }
.sm .sm-task td[align="right"] { white-space: nowrap; color: var(--ink-soft); font-size: 12px; }

/* ======================================================================
   Loading feedback while the task book switches lists in place (sm-taskboard.js):
   the current list dims, a progress bar runs across the top of the window, and a
   "Loading tasks..." label appears under the top bar if it takes a moment.
   ====================================================================== */
/* Its own class: the app already has a global .is-loading (basic_stylesheet.css) that covers
   the element in white, which would hide the list instead of dimming it. */
.sm .sm-taskboard.sm-taskboard--loading { opacity: .5; pointer-events: none; transition: opacity .15s; }

/* Recurring Tasks: its Vue lists stay hidden until Vue has mounted them, rather than
   flashing up fully expanded (a switch in place runs their scripts after the markup lands) */
.sm .sm-taskboard [v-cloak] { display: none; }

/*
   The Daily Tasks Report's day bar (views/reports/daily_task_book/report.view.php): which
   day on the left, as one group of controls, and its PDF on the right. Its own markup, so
   none of this touches the rota's .week_navigation, which the page used to borrow.
*/
.sm .sm-daily {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}
.sm .sm-daily__date {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}
.sm .sm-daily__step {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
.sm .sm-daily__pick { font-weight: 600; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sm .sm-daily__pick .fa-calendar { margin-right: 4px; color: var(--ink-faint); }
.sm .sm-daily__pick .caret { margin-left: 4px; }
/* the short date only where the long one would not fit beside the arrows */
.sm .sm-daily__short { display: none; }
@media (max-width: 575px) {
    .sm .sm-daily__long { display: none; }
    .sm .sm-daily__short { display: inline; }
}
/*
   Add / Edit Task Groups (views/packets/edit_packet_groups.view.php): its Vue editor's
   list, a panel of list-group rows with the Create button in the footer, laid out like
   the task book's cards. The markup is the editor bundle's own (not rebuilt), so this
   only restyles it: each group is a card with its Edit link, and the editor's Create
   button is hidden -- the page's own, at the right-hand end of the action row, clicks it.
*/
.sm .sm-taskboard[data-sm-taskboard-scope="groups"] .panel {
    display: flex;
    flex-direction: column;
    border: 0;
    box-shadow: none;
    background: transparent;
    margin: 0;
}
.sm .sm-taskboard[data-sm-taskboard-scope="groups"] .panel-footer { display: none; }
.sm .sm-taskboard[data-sm-taskboard-scope="groups"] .list-group {
    border-radius: 0;
    margin: 0;
}
.sm .sm-taskboard[data-sm-taskboard-scope="groups"] .list-group-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    background: var(--card);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: 12px 14px;
    margin-bottom: 10px;
    font-weight: 600;
    /* a long name wraps rather than running out of the card */
    overflow-wrap: anywhere;
}
.sm .sm-taskboard[data-sm-taskboard-scope="groups"] .list-group-item + .list-group-item {
    border-top-width: 1px;
}
/* Edit comes first and floats right in the markup; the row puts it after the name instead */
.sm .sm-taskboard[data-sm-taskboard-scope="groups"] .list-group-item > a {
    order: 1;
    float: none;
    flex-shrink: 0;
    white-space: nowrap;
    margin: 0;
    font-weight: 400;
}

/*
   Printed, the report is every section under its own heading, as the page was before it
   had tabs, rather than just the tab that happened to be open. (Download PDF is the
   report's own printable form; this is for the browser's Print.)
*/
@media print {
    .sm .sm-taskboard[data-sm-taskboard-scope="daily"] .tab-content > .tab-pane {
        display: block !important;
        opacity: 1 !important;
    }
    .sm .sm-taskboard[data-sm-taskboard-scope="daily"] .sm-taskcol__head { display: block !important; }
    .sm .sm-taskboard[data-sm-taskboard-scope="daily"] .nav-tabs,
    .sm .sm-taskboard[data-sm-taskboard-scope="daily"] .sm-daily { display: none !important; }
}

/* The busy cursor goes on the page, not the dimmed list: pointer-events:none takes the
   list out of hit-testing, so a cursor set on it would never show. */
html.sm-busy body { cursor: progress; }

/* Fixed to the top of the WINDOW, above the top bar, so it is seen however far down
   the page someone is (paging is clicked at the foot of a long list). */
.sm-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    z-index: 2000;
    pointer-events: none;
    opacity: 0;
    transition: opacity .3s;
}
.sm-progress.is-active { opacity: 1; }
.sm-progress.is-done { opacity: 0; transition-delay: .15s; }

.sm-progress__fill {
    height: 100%;
    background: var(--pool, #0d6efd);
    box-shadow: 0 0 6px var(--pool, #0d6efd);
    transform: scaleX(0);
    transform-origin: 0 50%;
    transition: transform .25s ease;
}

/* The label sits under the top bar, centred over the content area (not the rail). */
.sm-loading {
    position: fixed;
    top: calc(var(--topbar-h, 56px) + 12px);
    left: calc(var(--rail-w, 260px) + (100% - var(--rail-w, 260px)) / 2);
    transform: translateX(-50%);
    /* Over the page and the top bar (30), but under the top bar's own menus (40), so an
       open settings or account menu is not covered while a list loads. */
    z-index: 35;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 14px;
    background: var(--card, #fff);
    color: var(--ink, #212529);
    border: 1px solid var(--line, #dee2e6);
    border-radius: 999px;
    box-shadow: 0 6px 20px rgba(15, 32, 39, .18);
    /* follows the theme's base size, so "larger text" makes it larger too */
    font-size: calc(var(--base-font, 14px) - 1px);
    font-weight: 600;
    pointer-events: none;
}
.sm-loading[hidden] { display: none; }
/* the phone menu drawer takes the space the label would sit in */
.sm-nav-open .sm-loading { display: none; }

.sm-loading__spinner {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid var(--line, #dee2e6);
    border-top-color: var(--pool, #0d6efd);
    animation: sm-spin .8s linear infinite;
}
@keyframes sm-spin { to { transform: rotate(360deg); } }

/* Below 768px there is no left rail, so centre on the window. */
@media (max-width: 767.98px) {
    .sm-loading { left: 50%; }
}

/* No creeping or spinning for people who have asked for less motion: the bar still
   appears and fills, the ring is still there, they just do not move. */
@media (prefers-reduced-motion: reduce) {
    .sm-progress__fill { transition: none; }
    .sm-loading__spinner { animation: none; }
}

/* Windows High Contrast replaces background colours and drops shadows, which would
   leave an invisible bar; draw it in the system highlight colour instead. */
@media (forced-colors: active) {
    .sm-progress__fill { forced-color-adjust: none; background: Highlight; box-shadow: none; }
    .sm-loading__spinner { border-top-color: Highlight; }
}

/* --- Sent Tasks paging (list_sent_tasks) ----------------------------------- */
.sm .sm-sent__range { margin: 0 0 8px; color: var(--ink-soft); font-size: 12px; }

.sm .sm-sent__pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
}
.sm .sm-sent__pager .btn.active {
    --bs-btn-active-bg: var(--pool);
    --bs-btn-active-border-color: var(--pool);
    --bs-btn-active-color: #fff;
}
.sm .sm-sent__gap { color: var(--ink-soft); padding: 0 2px; }

/* --- the board ------------------------------------------------------------ */
.sm .sm-taskboard[data-sm-taskview="board"] .nav-tabs { display: none; }

.sm .sm-taskboard[data-sm-taskview="board"] .tab-content {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    overflow-x: auto;
    padding-bottom: 8px;
}

/*
   Every pane is shown at once, overriding the tab plugin's own display rules,
   which is the whole difference between the two views.
*/
.sm .sm-taskboard[data-sm-taskview="board"] .tab-pane {
    display: block !important;
    opacity: 1 !important;
    /*
       The five columns are fixed and known, so they share the width rather than
       running off the edge: a board you have to scroll sideways to see the last
       column of defeats the point of showing the statuses together. min-width
       still forces a scroll when the window really is too narrow for five.
    */
    flex: 1 1 0;
    min-width: 195px;
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: 10px;
    max-height: 70vh;
    overflow-y: auto;
}

.sm .sm-taskcol__head {
    font-weight: 600;
    font-size: 13px;
    margin-bottom: 10px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--line);
}

/*
   The columns are statuses, so they are coloured with the status tokens the rest
   of the app already uses -- which also means they follow dark mode and the
   high-contrast and colour-blind palettes without a second set of colours here.
*/
.sm .sm-taskboard[data-sm-taskview="board"] #overdue { border-top: 3px solid var(--overdue); background: var(--overdue-wash); }
.sm .sm-taskboard[data-sm-taskview="board"] #current { border-top: 3px solid var(--due); background: var(--due-wash); }
.sm .sm-taskboard[data-sm-taskview="board"] #in_progress { border-top: 3px solid var(--pool); background: var(--pool-wash); }
.sm .sm-taskboard[data-sm-taskview="board"] #completed { border-top: 3px solid var(--done); background: var(--done-wash); }
.sm .sm-taskboard[data-sm-taskview="board"] #deleted { border-top: 3px solid var(--idle); background: var(--idle-wash); }

/*
   The wash carries the column, so the card sits on it in plain --card. Inside a
   white panel the previous --surface columns were invisible: #fdfdfd on #ffffff
   is not an edge. The -wash tokens are the same ones the rest of the app uses
   for these five states, so the tint follows dark mode and the high-contrast
   and colour-blind palettes rather than needing its own colours.
*/
.sm .sm-taskboard[data-sm-taskview="board"] .sm-task { background: var(--card); }

/* the column header only names a column, so it is noise in the list view */
.sm .sm-taskboard[data-sm-taskview="list"] .sm-taskcol__head { display: none; }

/* a narrow column cannot carry the wide two-column title/date row */
.sm .sm-taskboard[data-sm-taskview="board"] .sm-task table,
.sm .sm-taskboard[data-sm-taskview="board"] .sm-task tbody,
.sm .sm-taskboard[data-sm-taskview="board"] .sm-task tr { display: block; width: auto; }

/*
   Clamp each line to three in a column. A task's description is the tallest thing
   on the card and pushes the next task off the screen, which is the one thing a
   board is supposed to prevent. Nothing is lost that was not lost already: the
   server truncates these descriptions with an ellipsis, and the whole task opens
   on click. The list view is left unclamped, where there is width to read it.
*/
.sm .sm-taskboard[data-sm-taskview="board"] .sm-task td {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    width: auto;
    line-height: 1.35;
}
.sm .sm-taskboard[data-sm-taskview="board"] .sm-task td[align="right"] { text-align: left; margin-top: 2px; }
.sm .sm-taskboard[data-sm-taskview="board"] .sm-task { margin-bottom: 8px; font-size: 12.5px; padding: 9px 10px; }

@media (max-width: 900px) {
    /* side by side stops being readable long before the columns stop fitting */
    .sm .sm-taskboard[data-sm-taskview="board"] .tab-content { display: block; }
    .sm .sm-taskboard[data-sm-taskview="board"] .tab-pane { max-height: none; margin-bottom: 12px; }
}

/* ======================================================================
   Modals under Bootstrap 5.

   staffmis-ui.css caps every dialog at `max-width: calc(100% - 20px)`, written when
   Bootstrap 3 sized dialogs with `width` and a 900px .modal-lg overflowed a tablet.
   Bootstrap 5 sizes them with max-width instead (500px, .modal-sm 300px, .modal-lg
   800px, from --bs-modal-width), and the cap, being the more specific rule, replaced
   that: every confirm, notes box and form dialog stretched to the width of the page.
   From 576px up, where Bootstrap 5 starts centring a sized dialog, hand the width
   back to it; below that the phone cap still applies.
   ====================================================================== */
@media (min-width: 576px) {
    .sm .modal-dialog { max-width: var(--bs-modal-width); }
}

/* The x after the title, at the right edge (bs3-compat.css reorders it). The margin
   is needed here too because staffmis-ui.css sets this button's margins outright. */
.sm .modal-header .close { margin-left: auto; }
