/*!
 * theme-esafety.css - Camusat eSafety skin
 *
 * Loaded LAST (after styles/style.css and the inline block in layouts/css.blade.php)
 * so it wins ties without editing the 68K minified Homer stylesheet. Kept as a
 * separate override layer rather than patched into style.css because ~60 legacy
 * pages inherit from it: a bad rule here is removed by deleting one <link>,
 * whereas a bad edit inside style.css is unreviewable.
 *
 * Layer order inside this file:
 *   1. tokens            - the whole palette, one place to retune
 *   2. app shell         - #header / brand bar / top nav geometry
 *   3. legacy overrides  - keyed to Bootstrap 3 + Homer classes, scoped to
 *                          body.es-theme so pages on other layouts (auth, and
 *                          the public respond layout until it opts in) are untouched
 *   4. utilities         - new .es-* classes for the rebuilt NC screens; deliberately
 *                          NOT scoped, so any layout can use them
 */

/* ------------------------------------------------------------------ */
/* 1. Design tokens                                                     */
/* ------------------------------------------------------------------ */

:root {
    /* brand */
    --brand-red: #c1272d;          /* Camusat red - accents, active underline, destructive */
    --brand-red-dark: #a01f24;
    --navy: #1e3a6e;               /* primary UI navy */
    --navy-dark: #16294e;
    --navy-deep: #002060;          /* the colour legacy inline styles already use - kept as an
                                      alias so hard-coded #002060 in old blades still harmonises */
    --accent-blue: #2563c9;        /* links / secondary actions in the mockups */

    /* surfaces */
    --page-bg: #f3f5f9;
    --card-bg: #ffffff;
    --card-border: #e2e8f2;
    --field-bg: #f4f6fa;
    --field-border: #d8e0ee;

    /* ink */
    --ink: #1f2a3d;
    --ink-soft: #35486a;
    --muted: #5f6f7f;

    /* shape */
    --radius: 10px;
    --radius-sm: 8px;
    --radius-pill: 999px;
    /* Controls are squarer than the surfaces they sit on. Separate tokens
       rather than a smaller --radius, because the cards, panels and modals that
       also read --radius should stay as round as they are - only the things you
       click and type into were asked to sharpen. */
    --app-footer-h: 34px;
    --radius-btn: 6px;
    --radius-field: 4px;
    /* Stat tiles. Squarer than a card on purpose: a tile is a figure, not a
       panel, and a row of them reads as one band when the corners are quiet. */
    --radius-tile: 4px;
    /* Inputs are white with black text: the tinted fill made a field read as a
       disabled or read-only surface, and the disabled state (#eef1f7) needs to
       be the tinted one for that distinction to carry. The border keeps its
       existing colour, so the field is still visibly bounded. */
    --field-ink: #000;
    --shadow: 0 1px 3px rgba(16, 32, 64, .07);
    --shadow-lg: 0 14px 28px rgba(16, 32, 64, .12);

    /* status */
    --st-open: #d64545;
    --st-progress: #e8912d;
    --st-success: #3f9d58;
    --st-muted: #8b97a8;
    --st-info: #2563c9;

    /* shell geometry - the wrapper offset is derived from this, so the two can
       never drift apart the way the old fixed 90px/55px pair did */
    --brandbar-h: 60px;
    --navbar-h: 46px;
    /* +1px = the divider border between the two bars. Derived rather than typed so
       changing either bar cannot leave the page content offset by the difference. */
    --header-h: calc(var(--brandbar-h) + var(--navbar-h) + 1px);
}

/* ------------------------------------------------------------------ */
/* 2. App shell                                                         */
/* ------------------------------------------------------------------ */

body.es-theme {
    background: var(--page-bg);
    color: var(--ink);
}

/* style.css pins #header to 55px and layouts/css.blade.php to 60px, but the bar
   actually holds two rows. Letting it size itself and deriving #wrapper's offset
   from the same token is what stops the menu overlapping page content. */
body.es-theme #header {
    height: auto !important;
    min-height: var(--header-h);
    background: var(--card-bg);
    border: 0;
    box-shadow: 0 1px 0 var(--card-border), 0 4px 14px rgba(16, 32, 64, .06);
    z-index: 1030;
}

body.es-theme #header nav {
    background: var(--card-bg) !important;
    padding: 0 !important;
    margin: 0;
}

/* padding-top is the pre-JS estimate; esafety-ui.js replaces it with the header's
   measured height, because the menu can take a second row (long French labels, a
   narrow window) and a constant offset would then hide the top of the page. */
body.es-theme #wrapper {
    top: 0 !important;
    margin-left: 0 !important;
    padding-top: var(--header-h);
    background: var(--page-bg) !important;
    border-left: 0;
}

/* --- brand bar (logo + system name + language selector) --- */

.es-brandbar {
    display: flex;
    align-items: center;
    gap: 14px;
    height: var(--brandbar-h);
    padding: 0 22px;
}

.es-brandbar-logo {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    text-decoration: none;
}

.es-brandbar-logo img {
    max-height: 38px;
    width: auto;
}

.es-brandbar-name {
    margin: 0;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.15;
    color: var(--navy);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.es-brandbar-spacer {
    flex: 1 1 auto;
}

.es-brandbar .language-selector-form {
    margin: 0;
}

/*
 * The language control, wherever it appears.
 *
 * It was a plain .form-control in all three places it is included, so it
 * kept the operating system's own select rendering - a square box with a
 * native arrow - while everything around it was themed. The app header and
 * the public respond page each carried their own near-identical rule that
 * set a border and a radius and stopped short of the appearance, which is
 * the part that actually shows. Both now share this one.
 *
 * select.- rather than a bare class: bootstrap.css carries select.input-sm
 * (0-1-1), which outranks a single class. This sheet loads after bootstrap,
 * so an equal specificity wins on order.
 *
 * The login page keeps its own copy. That layout is self-contained by
 * design and paints from its own palette rather than these tokens.
 */
select.es-lang-select {
    height: 34px;
    min-width: 150px;
    padding: 0 32px 0 36px;
    border: 1px solid var(--field-border) !important;
    border-radius: var(--radius-field) !important;
    background-color: var(--card-bg);
    color: var(--field-ink);
    font-size: 14px;
    font-weight: 600;
    line-height: 32px;
    box-shadow: none !important;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'%3E%3Ccircle cx='8' cy='8' r='6.35' stroke='%231e3a6e' stroke-width='1.3'/%3E%3Cpath d='M1.65 8h12.7' stroke='%231e3a6e' stroke-width='1.3'/%3E%3Cpath d='M8 1.65c1.7 1.75 2.6 3.95 2.6 6.35S9.7 12.6 8 14.35C6.3 12.6 5.4 10.4 5.4 8S6.3 3.4 8 1.65Z' stroke='%231e3a6e' stroke-width='1.3'/%3E%3C/svg%3E"),
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.6 4.4 6 7.8l3.4-3.4' stroke='%231e3a6e' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat, no-repeat;
    background-position: left 11px center, right 11px center;
    background-size: 15px 15px, 11px 11px;
    transition: border-color .15s ease, box-shadow .15s ease;
}

select.es-lang-select::-ms-expand {
    display: none;
}

select.es-lang-select:hover {
    border-color: var(--accent-blue) !important;
}

select.es-lang-select:focus,
select.es-lang-select:focus-visible {
    border-color: var(--navy) !important;
    box-shadow: 0 0 0 3px rgba(30, 58, 110, .12) !important;
    outline: 0;
}

/* The list itself is drawn by the OS; only its own colours are ours to
   set, and only where the platform honours them. */
select.es-lang-select option {
    background: var(--card-bg);
    color: var(--field-ink);
}

/* --- top nav --- */

body.es-theme #topmenu {
    margin-top: 0 !important;
    padding: 0 !important;
    background: var(--card-bg) !important;
    border-top: 1px solid var(--card-border);
}

.es-nav-bar {
    display: flex;
    align-items: stretch;
    min-height: var(--navbar-h);
    padding: 0 12px;
}

/* The old nav clipped its own dropdowns: #topmenu-ul had overflow:hidden (to clear
   its floated children), which cuts off anything absolutely positioned inside it -
   hence the hard-coded `left: NNNpx !important` on every menu. Flex removes the
   need for both the float clearfix and the pixel offsets. */
#topmenu-ul.es-nav {
    display: flex;
    align-items: stretch;
    align-content: flex-start;
    flex: 1 1 auto;
    flex-wrap: wrap;             /* a long French menu takes a second row rather than
                                    pushing the user menu off the right edge */
    overflow: visible;
    list-style: none;
    margin: 0;
    padding: 0;
    border: 0;
    width: auto;
    box-shadow: none;
}

#topmenu-ul.es-nav > li {
    position: relative;          /* anchor for .dropdown-menu */
    float: none;
    margin: 0;
    min-height: var(--navbar-h);
    display: flex;
    align-items: stretch;
}

#topmenu-ul.es-nav > li > a {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 0 13px;
    font-size: 14px;
    font-weight: 600;
    line-height: 1;
    color: var(--ink-soft);
    text-align: left;
    text-decoration: none;
    background: none;
    border: 0;
    white-space: nowrap;
}

#topmenu-ul.es-nav > li > a:hover,
#topmenu-ul.es-nav > li > a:focus,
#topmenu-ul.es-nav > li.open > a {
    color: var(--navy);
    background: #f2f6fd;
}

/* Active section marker - inset shadow rather than border-bottom so the link box
   does not change height when a section becomes active. */
#topmenu-ul.es-nav > li.active > a {
    color: var(--navy);
    box-shadow: inset 0 -3px 0 var(--brand-red);
}

/* One CSS chevron replaces eleven copy-pasted inline SVGs. */
#topmenu-ul.es-nav > li.dropdown > a::after {
    content: "";
    width: 6px;
    height: 6px;
    margin-top: -3px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    opacity: .65;
}

#topmenu-ul.es-nav .dropdown-menu {
    left: 0;
    right: auto;
    top: 100%;
    min-width: 210px;
    margin: 0;
    padding: 6px 0;
    border: 1px solid var(--card-border);
    border-radius: var(--radius) !important;
    box-shadow: var(--shadow-lg);
    background: var(--card-bg);
}

#topmenu-ul.es-nav .dropdown-menu > li {
    float: none;
    padding: 0 !important;
    margin: 0;
    clear: both;
}

#topmenu-ul.es-nav .dropdown-menu > li > a {
    display: block;
    margin: 0;
    padding: 8px 16px;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--ink) !important;
    text-align: left;
    white-space: nowrap;
}

#topmenu-ul.es-nav .dropdown-menu > li > a:hover,
#topmenu-ul.es-nav .dropdown-menu > li > a:focus {
    background: #eef4ff;
    color: var(--navy) !important;
}

/* right-hand cluster: bell, gear, user. .es-nav-push marks the first of them and
   eats the free space, which is what right-aligns the group. */
#topmenu-ul.es-nav > li.es-nav-push {
    margin-left: auto;
}

#topmenu-ul.es-nav > li.es-nav-right > a {
    padding: 0 10px;
    color: var(--ink-soft);
}

.es-nav-icon {
    position: relative;
    display: inline-flex;
    align-items: center;
    font-size: 17px;
}

.es-nav-badge {
    position: absolute;
    top: -7px;
    right: -9px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: var(--radius-pill);
    background: var(--brand-red);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

/* Applied by esafety-ui.js to any menu whose left-aligned box would run past the
   right edge - which item that is depends on the width, the language and whether
   the bar wrapped, so it cannot be decided in CSS. */
#topmenu-ul.es-nav .dropdown-menu.es-dropdown-flip {
    left: auto;
    right: 0;
}

/* The same fix the page-head menus already carry, for the same reason: the
   theme pins every nav dropdown to left:0, which on the right-hand cluster runs
   the panel off the page. The bell was overflowing by 242px at 1385 wide - it
   was doing so at the old 340px too, just less. Right-hand items open
   right-aligned. */
#topmenu-ul.es-nav > li.es-nav-right > .dropdown-menu {
    left: auto;
    right: 0;
}

/* --- N/C phase stepper --------------------------------------------- */

/* Eight dots on a rail, drawn from NcPhaseService. The rail is one element
   behind the dots rather than a border on each: a per-dot border leaves a hairline
   gap at every join that reads as a dashed line at some zoom levels. */
.es-phase {
    padding: 12px 14px;
    border: 1px solid var(--card-border);
    border-radius: var(--radius);
    background: var(--card-bg);
}

.es-phase-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 14px;
}

.es-phase-title {
    color: var(--navy);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.es-phase-now {
    display: inline-flex;
    align-items: baseline;
    gap: 10px;
}

.es-phase-step {
    color: var(--muted);
    font-size: 12px;
}

.es-phase-pct {
    color: var(--navy);
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
}

.es-phase-rail {
    position: relative;
}

/* The unfilled track. Inset by half a dot at each end so it starts and stops
   under the first and last dots rather than running past them. */
.es-phase-rail::before {
    content: "";
    position: absolute;
    left: 7px;
    right: 7px;
    top: 6px;
    height: 2px;
    border-radius: 2px;
    background: var(--card-border);
}

.es-phase-fill {
    position: absolute;
    left: 7px;
    top: 6px;
    height: 2px;
    max-width: calc(100% - 14px);
    border-radius: 2px;
    background: var(--navy);
}

.es-phase-steps {
    position: relative;
    display: flex;
    justify-content: space-between;
    margin: 0;
    padding: 0;
    list-style: none;
}

.es-phase-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
}

.es-phase-dot {
    width: 14px;
    height: 14px;
    border: 2px solid var(--card-border);
    border-radius: 50%;
    background: var(--card-bg);
}

.es-phase-item.is-done .es-phase-dot {
    border-color: var(--navy);
    background: var(--navy);
}

/* A ring rather than a fill, so "where I am" is distinguishable from "done" at a
   glance and not only by position. */
.es-phase-item.is-current .es-phase-dot {
    border-color: var(--navy);
    background: var(--card-bg);
    box-shadow: 0 0 0 3px rgba(30, 58, 110, .16);
}

.es-phase-label {
    color: var(--muted);
    font-size: 10px;
    line-height: 1.3;
    hyphens: auto;
}

.es-phase-item.is-current .es-phase-label {
    color: var(--navy);
    font-weight: 700;
}

.es-phase-current {
    margin: 10px 0 0;
    color: var(--ink);
    font-size: 13px;
    font-weight: 600;
}

/* Compact, and every narrow screen: eight captions stack into a paragraph, and
   the current phase is named under the rail regardless. */
.es-phase.is-compact {
    padding: 10px 12px;
}

.es-phase.is-compact .es-phase-label {
    display: none;
}

@media (max-width: 900px) {
    .es-phase-label {
        display: none;
    }
}

/* The log's phase cell: the bar with its stage named underneath, narrow enough
   not to widen a register that already carries seventeen columns. */
.es-phase-cell {
    min-width: 140px;
}

.es-phase-cell-label {
    display: block;
    margin-top: 3px;
    color: var(--muted);
    font-size: 11px;
    line-height: 1.3;
}

/* --- the bell menu ---
   The panel scrolls its BODY, not itself, so the header and its Clear all stay
   put while a long list moves underneath. */
#topmenu-ul.es-nav .es-nav-notifications {
    width: 380px;
    padding: 0;
    overflow: hidden;
}

.es-notif-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 11px 14px;
    border-bottom: 1px solid var(--card-border);
    background: #f7f9fd;
}

.es-notif-title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--navy);
    font-size: 13px;
    font-weight: 700;
}

.es-notif-count {
    min-width: 20px;
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    background: var(--brand-red);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    text-align: center;
}

.es-notif-clear {
    padding: 3px 10px;
    border: 1px solid var(--card-border);
    border-radius: var(--radius-btn);
    background: #fff;
    color: var(--ink-soft);
    font-size: 11px;
    font-weight: 700;
}

.es-notif-clear:hover {
    border-color: #cfdcf0;
    color: var(--navy);
}

.es-notif-body {
    max-height: 62vh;
    overflow-y: auto;
    padding: 6px;
}

.es-notif {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 9px 10px;
    border-radius: var(--radius-sm);
    white-space: normal;
}

.es-notif:hover {
    background: #f4f7fc;
}

/* The kind, as a dot. These rows carry no type column - see the blade - so this
   is inferred from the text and stays deliberately quiet: a wrong guess should
   look like nothing, not like a wrong label. */
.es-notif-dot {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    margin-top: 6px;
    border-radius: 50%;
    background: var(--muted);
}

.es-notif[data-kind="flash"] .es-notif-dot { background: var(--brand-red); }
.es-notif[data-kind="approval"] .es-notif-dot { background: var(--accent-blue); }
.es-notif[data-kind="permit"] .es-notif-dot { background: #d98324; }

.es-notif-main {
    flex: 1 1 auto;
    min-width: 0;
}

.es-notif-text {
    margin: 0;
    color: var(--ink);
    font-size: 13px;
    font-weight: 600;
    line-height: 1.4;
}

.es-notif-sub {
    margin: 2px 0 0;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.4;
}

.es-notif-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-top: 4px;
    color: var(--muted);
    font-size: 11px;
}

.es-notif-meta a {
    color: var(--accent-blue);
    font-weight: 700;
}

/* Only on hover, so a row of crosses does not compete with the messages. */
.es-notif-x {
    flex: 0 0 auto;
    padding: 0 4px;
    border: 0;
    background: none;
    color: var(--muted);
    font-size: 17px;
    line-height: 1;
    opacity: 0;
}

.es-notif:hover .es-notif-x,
.es-notif-x:focus {
    opacity: 1;
}

.es-notif-x:hover {
    color: var(--brand-red);
}

.es-notif-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 26px 14px;
    color: var(--muted);
    font-size: 13px;
    white-space: normal;
}

.es-notif-empty .fa {
    font-size: 22px;
    opacity: .45;
}

.es-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--navy);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .5px;
}

.es-nav-username {
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* hamburger */
.es-nav-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 38px;
    padding: 0;
    margin-right: 4px;
    border: 0;
    background: none;
    color: var(--navy);
    font-size: 18px;
}

/* Compact tier. Eleven menu groups plus the utility cluster need ~1340px in English
   and ~1365px in French at the default sizing, so anything narrower than a 1440
   display tightens them and drops the user's name (the avatar still identifies the
   account) to keep the bar on one row. If it still does not fit - a longer
   translation, an extra menu group - .es-nav wraps and esafety-ui.js re-measures
   the header, so the page content is never hidden underneath it. */
@media (max-width: 1439px) {
    #topmenu-ul.es-nav > li > a {
        gap: 4px;
        padding: 0 7px;
        font-size: 13px;
    }

    #topmenu-ul.es-nav > li.es-nav-right > a {
        padding: 0 6px;
    }

    .es-nav-username {
        display: none;
    }
}

/* Tighter still, so the bar survives a 1024 tablet in French - the widest
   translation of the eleven groups plus the utility cluster. */
@media (max-width: 1099px) {
    #topmenu-ul.es-nav > li > a {
        padding: 0 5px;
        font-size: 12px;
    }

    #topmenu-ul.es-nav > li.es-nav-right > a {
        padding: 0 5px;
    }

    .es-avatar {
        width: 24px;
        height: 24px;
        font-size: 10px;
    }
}

@media (max-width: 991px) {
    /* --header-h is a calc() of these two, so it follows automatically */
    :root {
        --brandbar-h: 56px;
        --navbar-h: 44px;
    }

    .es-nav-toggle {
        display: inline-flex;
    }

    #topmenu-ul.es-nav {
        display: none;
        position: absolute;
        left: 0;
        right: 0;
        top: 100%;
        z-index: 1029;
        flex-direction: column;
        align-items: stretch;
        max-height: calc(100vh - var(--header-h));
        overflow-y: auto;
        padding: 6px 0;
        background: var(--card-bg);
        border-top: 1px solid var(--card-border);
        box-shadow: var(--shadow-lg);
    }

    #topmenu-ul.es-nav.is-open {
        display: flex;
    }

    #topmenu-ul.es-nav > li {
        display: block;
    }

    #topmenu-ul.es-nav > li > a {
        padding: 12px 18px;
        box-shadow: none;
    }

    #topmenu-ul.es-nav > li.active > a {
        box-shadow: inset 3px 0 0 var(--brand-red);
    }

    #topmenu-ul.es-nav > li.dropdown > a::after {
        margin-left: auto;
    }

    /* inline (accordion-style) submenus - absolute panels inside a scrolling
       column would be unreachable on a phone */
    #topmenu-ul.es-nav > li .dropdown-menu {
        position: static;
        float: none;
        width: auto;
        min-width: 0;
        border: 0;
        border-radius: 0 !important;
        box-shadow: none;
        background: #f7f9fd;
    }

    #topmenu-ul.es-nav > li.es-nav-right,
    #topmenu-ul.es-nav > li.es-nav-push {
        margin-left: 0;
    }

    /* the compact tier hides this to save a row; in the vertical menu there is room */
    .es-nav-username {
        display: inline;
    }

    #topmenu-ul.es-nav .es-nav-notifications {
        width: auto;
    }

    .es-brandbar {
        gap: 10px;
        padding: 0 12px;
    }
}

@media (max-width: 600px) {
    .es-brandbar-name {
        display: none;
    }

    .es-brandbar select {
        min-width: 104px;
    }
}

/* footer */
/* Pinned to the viewport, not to the end of the document.

   It used to sit in the flow after the page content, so on a long screen -
   the N/C log at 100 rows, the HSE dashboard - it scrolled out of sight and
   the attribution was only visible if you happened to reach the bottom. Fixed
   and on white so it reads as part of the chrome rather than as the last
   thing on the page.

   --app-footer-h is what #wrapper reserves at the bottom, so the last card is
   never underneath it. Keep the two in step if the padding here changes. */
.app-shell-footer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    height: var(--app-footer-h);
    padding: 0 24px;
    background: var(--card-bg);
    border-top: 1px solid var(--card-border);
    color: var(--muted);
    font-size: 11px;
    line-height: 1.2;
}

/* Room for it, so the foot of the page is not hidden behind the bar. */
body.es-theme #wrapper {
    padding-bottom: var(--app-footer-h);
}

.app-shell-footer strong {
    color: var(--ink-soft);
    font-weight: 600;
}

@media (max-width: 768px) {
    .app-shell-footer {
        padding: 0 12px;
    }
}

/* ------------------------------------------------------------------ */
/* 3. Legacy Bootstrap 3 / Homer overrides                              */
/*    Everything here is scoped to body.es-theme (set in layouts/master) */
/* ------------------------------------------------------------------ */

/* --- cards --- */


body.es-theme .panel,
body.es-theme .hpanel,
body.es-theme .card,
body.es-theme .modal-content,
body.es-theme .ibox {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--radius) !important;
    box-shadow: var(--shadow);
}

/* .hpanel is only a wrapper in Homer - its child .panel-body carries the surface,
   so a border on both draws a double outline */
body.es-theme .hpanel {
    border: 0;
    box-shadow: none;
    background: transparent;
}

/* Homer treats a bare .panel-body as a card in its own right, and plenty of
   legacy pages use it that way with no .panel wrapper at all - so the card
   treatment goes on .panel-body itself, not only on the nested case.

   Padding lives here too. layouts/css.blade.php used to carry
   .panel-body { padding: 0 !important }, which put every legacy card's content
   hard against its own border; that rule is gone and this replaces it. Surface
   and padding are deliberately one rule rather than two - they describe the same
   box, and a second .panel-body block is how the two drifted apart in the first
   place, one of them still claiming the padding was zeroed globally. */
body.es-theme .panel-body {
    padding: 18px 20px;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--radius) !important;
    box-shadow: var(--shadow);
    color: var(--ink);
}

/* A table is the exception to that padding: it is allowed to run to the card
   edge, because a wide table needs the width and its own cells already carry
   the inset.

   The width has to be stated as the container plus the two negative margins.
   It used to say `width: auto`, which on a table means shrink-to-fit: instead
   of bleeding past the padding, every such table collapsed to the width of its
   own longest row and left the rest of the card empty - most visibly on System
   Configurations > Project Type, where a six-column table stopped two thirds of
   the way across.

   max-width has to go with it. Bootstrap sets `.table { max-width: 100% }`,
   which would clamp the calc straight back to the content box and leave the
   table full-width but shifted 20px to the left. */
body.es-theme .panel-body > .table,
body.es-theme .panel-body > .table-responsive,
body.es-theme .panel-body > .dataTables_wrapper {
    margin-left: -20px;
    margin-right: -20px;
    width: calc(100% + 40px);
    max-width: none;
}

@media (max-width: 768px) {
    body.es-theme .panel-body {
        padding: 14px 12px;
    }

    body.es-theme .panel-body > .table,
    body.es-theme .panel-body > .table-responsive,
    body.es-theme .panel-body > .dataTables_wrapper {
        margin-left: -12px;
        margin-right: -12px;
        width: calc(100% + 24px);
    }
}

/* A .panel-body inside a .panel already sits on the panel's own surface */
body.es-theme .panel > .panel-body {
    border: 0;
    box-shadow: none;
}

body.es-theme .panel > .panel-heading,
body.es-theme .hpanel > .panel-heading {
    background: transparent;
    border-bottom: 1px solid var(--card-border);
    color: var(--navy);
    font-weight: 600;
}

body.es-theme .modal-header {
    padding: 18px 22px;
    background: var(--card-bg);
    border-bottom: 1px solid var(--card-border);
}

body.es-theme .modal-title {
    font-size: 18px;
    font-weight: 700;
    color: var(--navy);
}

body.es-theme .modal-body {
    padding: 20px 22px;
}

body.es-theme .modal-footer {
    background: var(--card-bg);
    border-top: 1px solid var(--card-border);
}

/* .normalheader is how 41 of the older screens print their page title, and it
   was landing 36px further in than the cards below it: the vendor rule gives it
   15px of padding and the heading inside carries .m-l-md/.m-r-md for another
   20px, while .content sets 24px. Three insets on one page is what made the
   titles look untethered from their own content.

   Aligned to .content's 24px, and given the ink, size and weight of
   .es-page-title so a legacy screen and a themed one read as one application. */
body.es-theme .normalheader {
    background: transparent;
    padding: 18px 24px 0;
}

body.es-theme .normalheader h1,
body.es-theme .normalheader h2,
body.es-theme .normalheader h3 {
    margin: 0 0 4px !important;
    color: var(--navy) !important;
    font-size: 22px !important;
    font-weight: 700 !important;
    line-height: 1.25;
}

/* These headings often carry a pull-right button; keep it on the title's
   baseline rather than floating above the cap height. */
body.es-theme .normalheader h1 .btn,
body.es-theme .normalheader h2 .btn,
body.es-theme .normalheader h3 .btn {
    margin-top: -4px;
}

@media (max-width: 768px) {
    body.es-theme .normalheader {
        padding: 14px 12px 0;
    }
}

/* --- buttons --- */

body.es-theme .btn {
    font-weight: 600;
    border-radius: var(--radius-btn) !important;
    transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

body.es-theme .btn-primary,
body.es-theme .btn-primary:focus {
    background-color: var(--navy) !important;
    border-color: var(--navy) !important;
    color: #fff !important;
}

body.es-theme .btn-primary:hover,
body.es-theme .btn-primary:active,
body.es-theme .btn-primary.active,
body.es-theme .open > .dropdown-toggle.btn-primary {
    background-color: var(--navy-dark) !important;
    border-color: var(--navy-dark) !important;
    color: #fff !important;
}

body.es-theme .btn-default {
    background-color: var(--card-bg) !important;
    border: 1px solid var(--field-border) !important;
    color: var(--ink-soft) !important;
}

body.es-theme .btn-default:hover,
body.es-theme .btn-default:focus {
    background-color: #eef2f9 !important;
    color: var(--navy) !important;
}

body.es-theme .btn-danger,
body.es-theme .btn-danger:focus {
    background-color: var(--brand-red) !important;
    border-color: var(--brand-red) !important;
    color: #fff !important;
}

body.es-theme .btn-danger:hover,
body.es-theme .btn-danger:active {
    background-color: var(--brand-red-dark) !important;
    border-color: var(--brand-red-dark) !important;
}

body.es-theme .btn-warning,
body.es-theme .btn-warning:focus {
    background-color: var(--st-progress) !important;
    border-color: var(--st-progress) !important;
    color: #fff !important;
}

body.es-theme .btn-success,
body.es-theme .btn-success:focus {
    background-color: var(--st-success) !important;
    border-color: var(--st-success) !important;
    color: #fff !important;
}

body.es-theme .btn-info,
body.es-theme .btn-info:focus {
    background-color: var(--st-info) !important;
    border-color: var(--st-info) !important;
    color: #fff !important;
}

body.es-theme .btn-link {
    color: var(--accent-blue);
    font-weight: 600;
}

/* --- forms --- */

body.es-theme .form-control {
    height: 38px;
    padding: 6px 12px;
    background-color: var(--card-bg);
    border: 1px solid var(--field-border) !important;
    border-radius: var(--radius-field) !important;
    box-shadow: none;
    color: var(--field-ink);
    font-size: 14px;
}

body.es-theme textarea.form-control {
    height: auto;
    min-height: 76px;
}

body.es-theme select.form-control {
    height: 38px;
}

body.es-theme .form-control:focus {
    background-color: var(--card-bg);
    border-color: var(--navy) !important;
    color: var(--field-ink);
    box-shadow: 0 0 0 3px rgba(30, 58, 110, .12);
    outline: 0;
}

body.es-theme .form-control[readonly],
body.es-theme .form-control[disabled] {
    background-color: #eef1f7;
    color: var(--muted);
}

body.es-theme .form-control::placeholder {
    color: #9aa7bb;
}

body.es-theme label,
body.es-theme label.control-label {
    margin-bottom: 6px;
    color: var(--navy);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .1px;
}

body.es-theme .input-group-addon {
    background: var(--field-bg);
    border: 1px solid var(--field-border);
    border-radius: var(--radius-sm);
    color: var(--muted);
}

body.es-theme .has-error .form-control {
    border-color: var(--brand-red) !important;
}

body.es-theme .help-block,
body.es-theme .text-muted {
    color: var(--muted);
}

/* --- tables --- */

body.es-theme .table {
    background: var(--card-bg);
    color: var(--ink);
}

/* Bootstrap tables get the same treatment as .es-table: a white header with
   navy text and a rule under it, rather than a filled navy band. Applied here
   too so the legacy screens - HR, projects, training, reports - match the
   themed ones instead of splitting into two table styles. */
body.es-theme .table > thead {
    background: var(--card-bg);
}

body.es-theme .table > thead > tr > th {
    border-bottom: 2px solid var(--card-border);
    color: var(--navy) !important;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .2px;
    vertical-align: middle;
}

body.es-theme .table > tbody > tr > td {
    border-top: 1px solid #edf1f7;
    font-size: 13px;
    vertical-align: middle;
}

body.es-theme .table-hover > tbody > tr:hover {
    background: #f6f9ff;
}

body.es-theme .table-striped > tbody > tr:nth-of-type(odd) {
    background: #fafbfe;
}

/* --- tabs -----------------------------------------------------------
   ONE tab treatment for the whole app.

   Every tabbed screen used to answer this question for itself. The project
   wizard and the staff profile each carried their own ~30 lines of .nav-tabs
   CSS in a page <style> block, the N/C dashboards carried a third, and the
   remaining eight tabbed screens - System Configurations, Personalization, the
   HSE/QA/Inspection overviews, HR documents, training events - carried none at
   all and fell through to the raw Homer default: borderless text links with a
   thin outlined box on the active one, which does not look like the rest of
   this application.

   So the treatment lives here, once, and the page blocks are gone. Specificity
   is the only trick involved: `body.es-theme .nav-tabs > li.active > a` is
   (0,3,3) against Homer's (0,2,2) and Bootstrap's (0,2,2), so it wins on weight
   alone and no !important is needed - which matters, because the page copies it
   replaces were built out of !important and could not be overridden by anything
   short of more !important. */
body.es-theme .nav-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 0 0 10px;
    margin-bottom: 0;
    border-bottom: 1px solid var(--card-border);
}

body.es-theme .nav-tabs > li {
    float: none;
    margin-bottom: 0;
}

body.es-theme .nav-tabs > li > a {
    margin-right: 0;
    padding: 9px 16px;
    border: 1px solid var(--card-border);
    border-radius: var(--radius-btn);
    background: var(--card-bg);
    color: var(--ink-soft);
    font-weight: 600;
    line-height: 1.4;
}

body.es-theme .nav-tabs > li > a:hover,
body.es-theme .nav-tabs > li > a:focus {
    background: #f2f6fd;
    border-color: #cfdcf0;
    color: var(--navy);
}

body.es-theme .nav-tabs > li.active > a,
body.es-theme .nav-tabs > li.active > a:hover,
body.es-theme .nav-tabs > li.active > a:focus {
    background: var(--navy-deep);
    border-color: var(--navy-deep);
    color: #fff;
}

/* The pane below the bar. Blades carry an inline
   `border: 0.5px solid ...; padding: 30px` on .tab-content; the border is
   dropped here because the bar already draws the line and two of them stack
   into a visible double rule. Inline padding still wins, which is deliberate -
   this is not the place to relitigate every pane's spacing. */
body.es-theme .tab-content {
    border: 0 !important;
}

/* Second level. A tabbed screen whose pane holds many sections of its own gets
   a nested bar; it is lighter and smaller than the first level so the hierarchy
   is legible rather than two identical bars stacked. */
body.es-theme .es-subtabs.nav-tabs {
    gap: 6px;
    padding-bottom: 8px;
    margin-bottom: 18px;
}

body.es-theme .es-subtabs.nav-tabs > li > a {
    padding: 6px 12px;
    border-radius: var(--radius-field);
    background: #f7f9fd;
    font-size: var(--fs-sm, 13px);
    font-weight: 600;
}

body.es-theme .es-subtabs.nav-tabs > li.active > a,
body.es-theme .es-subtabs.nav-tabs > li.active > a:hover,
body.es-theme .es-subtabs.nav-tabs > li.active > a:focus {
    background: var(--navy);
    border-color: var(--navy);
    color: #fff;
}

@media (max-width: 768px) {
    body.es-theme .nav-tabs > li > a {
        padding: 8px 12px;
        font-size: 13px;
    }
}

/* --- pagination --- */

body.es-theme .pagination > li > a,
body.es-theme .pagination > li > span {
    color: var(--ink-soft);
    border-color: var(--card-border);
}

body.es-theme .pagination > li:first-child > a,
body.es-theme .pagination > li:first-child > span {
    border-top-left-radius: var(--radius-sm);
    border-bottom-left-radius: var(--radius-sm);
}

body.es-theme .pagination > li:last-child > a,
body.es-theme .pagination > li:last-child > span {
    border-top-right-radius: var(--radius-sm);
    border-bottom-right-radius: var(--radius-sm);
}

body.es-theme .pagination > .active > a,
body.es-theme .pagination > .active > a:hover,
body.es-theme .pagination > .active > span {
    background: var(--navy);
    border-color: var(--navy);
    color: #fff;
}

/* --- DataTables chrome --- */

body.es-theme .dataTables_wrapper {
    padding: 0;
}

body.es-theme .dataTables_wrapper .dataTables_filter input,
body.es-theme .dataTables_wrapper .dataTables_length select {
    height: 34px;
    padding: 4px 10px;
    background: var(--card-bg);
    border: 1px solid var(--field-border);
    border-radius: var(--radius-field);
    color: var(--field-ink);
}

body.es-theme .dataTables_wrapper .dataTables_filter,
body.es-theme .dataTables_wrapper .dataTables_length,
body.es-theme .dataTables_wrapper .dataTables_info {
    color: var(--muted);
    font-size: 13px;
}

/* Buttons 1.1.1 with the bootstrap adapter renders .btn.btn-default, newer builds
   render .dt-button - match both so the toolbar looks the same either way. */
body.es-theme .dataTables_wrapper .dt-buttons .dt-button,
body.es-theme .dataTables_wrapper .dt-buttons > .btn {
    margin: 0 6px 6px 0;
    padding: 6px 14px;
    background: var(--card-bg) !important;
    border: 1px solid var(--field-border) !important;
    border-radius: var(--radius-sm) !important;
    box-shadow: none !important;
    color: var(--ink-soft) !important;
    font-size: 13px;
    font-weight: 600;
}

body.es-theme .dataTables_wrapper .dt-buttons .dt-button:hover,
body.es-theme .dataTables_wrapper .dt-buttons > .btn:hover {
    background: #eef4ff !important;
    color: var(--navy) !important;
}

body.es-theme .dataTables_wrapper .dataTables_paginate .paginate_button {
    border-radius: var(--radius-sm);
    color: var(--ink-soft) !important;
}

body.es-theme .dataTables_wrapper .dataTables_paginate .paginate_button.current {
    background: var(--navy) !important;
    border-color: var(--navy) !important;
    color: #fff !important;
}

/* --- select2 (vendored 4.1.0-rc.0) --- */

body.es-theme .select2-container--default .select2-selection--single,
body.es-theme .select2-container--default .select2-selection--multiple {
    min-height: 38px;
    background: var(--card-bg);
    border: 1px solid var(--field-border) !important;
    border-radius: var(--radius-field) !important;
}

body.es-theme .select2-container--default .select2-selection--single .select2-selection__rendered {
    padding-left: 12px;
    color: var(--field-ink);
    line-height: 36px;
}

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

body.es-theme .select2-container--default.select2-container--focus .select2-selection--single,
body.es-theme .select2-container--default.select2-container--focus .select2-selection--multiple,
body.es-theme .select2-container--default.select2-container--open .select2-selection--single {
    border-color: var(--navy) !important;
    box-shadow: 0 0 0 3px rgba(30, 58, 110, .12);
}

body.es-theme .select2-container--default .select2-selection--multiple .select2-selection__choice {
    background: #e7effc;
    border: 1px solid #cfdff8;
    border-radius: var(--radius-pill);
    color: var(--navy);
    padding: 1px 8px;
}

/* select2 renders its dropdown in a body-level portal, so it sits outside
   body.es-theme's subtree only in markup terms - the class is on <body>, so
   these still match. */
body.es-theme .select2-dropdown {
    border: 1px solid var(--card-border) !important;
    border-radius: var(--radius) !important;
    box-shadow: var(--shadow-lg);
}

body.es-theme .select2-container--default .select2-results__option--highlighted[aria-selected] {
    background: var(--navy);
}

body.es-theme .select2-search--dropdown .select2-search__field {
    border: 1px solid var(--field-border);
    border-radius: var(--radius-sm);
    padding: 6px 10px;
}

/* --- alerts / labels --- */

body.es-theme .alert {
    border-radius: var(--radius) !important;
    border: 1px solid transparent;
}

body.es-theme .alert-success {
    background: #eaf6ee;
    border-color: #cfe9d8;
    color: #276b3c;
}

body.es-theme .alert-danger {
    background: #fbeced;
    border-color: #f2ced0;
    color: #8f1d22;
}

body.es-theme .alert-warning {
    background: #fdf3e5;
    border-color: #f6e0bf;
    color: #8a5a13;
}

body.es-theme .alert-info {
    background: #eaf1fd;
    border-color: #cfdff8;
    color: #1c4796;
}

/* --- sweetalert2 (vendored v11) --- */

body.es-theme .swal2-popup {
    border-radius: var(--radius) !important;
    font-family: inherit;
}

body.es-theme .swal2-styled.swal2-confirm {
    background: var(--navy) !important;
    border-radius: var(--radius-sm) !important;
}

body.es-theme .swal2-styled.swal2-deny,
body.es-theme .swal2-styled.swal2-cancel {
    border-radius: var(--radius-sm) !important;
}

/* ------------------------------------------------------------------ */
/* 4. Utilities for the new screens (unscoped - usable on any layout)   */
/* ------------------------------------------------------------------ */

.es-card {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 18px 20px;
    margin-bottom: 18px;
}

.es-card-flush {
    padding: 0;
}

.es-card-title {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 14px;
    font-size: 15px;
    font-weight: 700;
    color: var(--navy);
}

.es-card-title .es-card-title-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 8px;
}

.es-card-subtitle {
    margin: -8px 0 14px;
    font-size: 12px;
    color: var(--muted);
}

.es-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-bottom: 14px;
}

.es-toolbar-spacer {
    margin-left: auto;
}

/* numbered field labels: "1. N/C ID No." - the number is printed by the blade so
   translations never carry ordinals */
.field-label {
    display: block;
    margin-bottom: 6px;
    color: var(--navy);
    font-size: 12px;
    font-weight: 700;
    line-height: 1.3;
}

.field-label .field-req {
    color: var(--brand-red);
    margin-left: 2px;
}

.pill {
    display: inline-block;
    padding: 3px 11px;
    border-radius: var(--radius-pill);
    background: #eef1f7;
    color: var(--ink-soft);
    font-size: 11px;
    font-weight: 700;
    line-height: 1.6;
    white-space: nowrap;
}

.pill-danger {
    background: rgba(214, 69, 69, .12);
    color: var(--st-open);
}

.pill-warning {
    background: rgba(232, 145, 45, .14);
    color: #a5620f;
}

.pill-success {
    background: rgba(63, 157, 88, .14);
    color: #2b7742;
}

.pill-info {
    background: rgba(37, 99, 201, .12);
    color: var(--st-info);
}

.pill-muted {
    background: #eef1f7;
    color: var(--st-muted);
}

.pill-solid-danger {
    background: var(--brand-red);
    color: #fff;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    padding: 4px 10px;
    margin: 0 6px 6px 0;
    border: 1px solid #cfdff8;
    border-radius: var(--radius-pill);
    background: #eaf1fd;
    color: var(--navy);
    font-size: 12px;
    font-weight: 600;
}

.chip .chip-remove {
    border: 0;
    background: none;
    padding: 0;
    color: var(--muted);
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
}

.chip .chip-remove:hover {
    color: var(--brand-red);
}

.chip-muted {
    background: #f1f3f8;
    border-color: #e0e5ef;
    color: var(--ink-soft);
}

.progress-slim {
    height: 8px;
    margin: 0;
    border-radius: var(--radius-pill);
    background: #e8edf6;
    overflow: hidden;
    box-shadow: none;
}

.progress-slim > .progress-bar {
    height: 8px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-pill);
    background: var(--st-info);
    text-indent: -9999px;   /* Homer prints the % inside the bar; too tall for 8px */
}

.progress-slim.is-complete > .progress-bar {
    background: var(--st-success);
}

.progress-slim.is-late > .progress-bar {
    background: var(--st-open);
}

.btn-brand-red,
.btn-brand-red:focus {
    background-color: var(--brand-red) !important;
    border-color: var(--brand-red) !important;
    color: #fff !important;
}

.btn-brand-red:hover,
.btn-brand-red:active {
    background-color: var(--brand-red-dark) !important;
    border-color: var(--brand-red-dark) !important;
    color: #fff !important;
}

/* --- multi_check_select (behaviour in public/scripts/esafety-ui.js) --- */

.es-multi {
    position: relative;
}

.es-multi-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    height: 38px;
    padding: 6px 12px;
    background: var(--card-bg);
    border: 1px solid var(--field-border);
    border-radius: var(--radius-field);
    color: var(--field-ink);
    font-size: 14px;
    text-align: left;
}

.es-multi.open .es-multi-toggle {
    border-color: var(--navy);
    box-shadow: 0 0 0 3px rgba(30, 58, 110, .12);
}

.es-multi-label {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.es-multi-label.is-placeholder {
    color: #9aa7bb;
}

.es-multi-toggle::after {
    content: "";
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    margin-top: -3px;
    border-right: 2px solid var(--muted);
    border-bottom: 2px solid var(--muted);
    transform: rotate(45deg);
}

.es-multi-menu {
    width: 100%;
    min-width: 240px;
    padding: 0;
    border: 1px solid var(--card-border);
    border-radius: var(--radius) !important;
    box-shadow: var(--shadow-lg);
}

.es-multi-search {
    padding: 8px;
    border-bottom: 1px solid var(--card-border);
}

.es-multi-list {
    list-style: none;
    max-height: 220px;
    margin: 0;
    padding: 6px 0;
    overflow-y: auto;
}

.es-multi-list > li > label {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 0;
    padding: 6px 12px;
    color: var(--ink);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
}

.es-multi-list > li > label:hover {
    background: #eef4ff;
}

.es-multi-list > li.is-hidden {
    display: none;
}

.es-multi-list input[type="checkbox"] {
    margin: 2px 0 0;
}

.es-multi-empty {
    padding: 12px;
    color: var(--muted);
    font-size: 12px;
    text-align: center;
}

.es-multi-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 8px;
    border-top: 1px solid var(--card-border);
}

/* --- character counter (behaviour in esafety-ui.js) --- */

.es-charcount {
    margin-top: 4px;
    color: var(--muted);
    font-size: 11px;
    text-align: right;
}

.es-charcount.is-limit {
    color: var(--brand-red);
    font-weight: 700;
}

/* ==================================================================== */
/* 5. N/C - CAPA screens                                                 */
/*                                                                       */
/*    Appended block, added with the rebuilt /nc, /nc/review, /nc/create  */
/*    and /nc/standards views. Nothing above this line was changed.       */
/*    Everything here is either an .es-* utility used only by those       */
/*    screens, or a small addition to the shared pill/chip families       */
/*    declared in section 4.                                              */
/* ==================================================================== */

/* --- page head: title, subtitle, right-hand actions ----------------- */

.es-page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px;
    margin: 18px 0 16px;
}

.es-page-head-main {
    flex: 1 1 320px;
    min-width: 0;
}

.es-page-title {
    margin: 0;
    color: var(--navy);
    font-size: 22px;
    font-weight: 700;
    line-height: 1.25;
}

.es-page-title .pill {
    position: relative;
    top: -2px;
    margin-left: 8px;
    font-size: 12px;
    padding: 4px 14px;
}

.es-page-subtitle {
    margin: 6px 0 0;
    color: var(--muted);
    font-size: 13px;
}

.es-page-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}

/* Bootstrap 3 puts .dropdown-menu at left:0 under the toggle; on a right-hand
   button cluster that runs the panel off the page, so the page-head menus open
   right-aligned. */
.es-page-actions .dropdown-menu,
.es-toolbar .es-menu-right + .dropdown-menu {
    left: auto;
    right: 0;
    border-radius: var(--radius) !important;
    box-shadow: var(--shadow-lg);
}

/* --- breadcrumb ----------------------------------------------------- */

.es-crumbs {
    margin: 16px 0 -4px;
    color: var(--muted);
    font-size: 12px;
}

.es-crumbs a {
    color: var(--accent-blue);
    font-weight: 600;
}

.es-crumbs .es-crumb-sep {
    margin: 0 6px;
    color: #b9c3d4;
}

/* --- field grid ----------------------------------------------------- */

/* auto-fit rather than Bootstrap columns: the review screen's four-per-row
   layout has to become two and then one without the caller restating the grid
   at three breakpoints, and a field that wraps must still fill its row. */
.es-fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
    gap: 14px 18px;
}

.es-fields-2 {
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

/* Three equal columns for the narrative fields at the foot of Review N/C.
   auto-fit would collapse them to two the moment the viewport tightened, which
   is the layout this replaced; 1fr each keeps the row of three and lets the
   media query below decide when to stack. */
.es-fields-3 {
    grid-template-columns: repeat(3, 1fr);
    margin-top: 18px;
}

@media (max-width: 992px) {
    .es-fields-3 {
        grid-template-columns: 1fr;
    }
}

/* Give a long-form box somewhere to grow. The reviewer can drag it taller;
   what it must not do is get shorter than the eight rows it is set to. */
.es-fields-text textarea.form-control {
    min-height: 180px;
    resize: vertical;
}

.es-field {
    min-width: 0;
}

.es-field-wide {
    grid-column: span 2;
}

@media (max-width: 767px) {
    .es-field-wide {
        grid-column: span 1;
    }
}

/* the "Assigned To + Position + Add" trio sits inside one grid cell */
.es-field-inline {
    display: flex;
    align-items: flex-end;
    gap: 8px;
}

.es-field-inline > .es-field {
    flex: 1 1 auto;
}

.es-field-inline > .btn {
    flex: 0 0 auto;
    height: 38px;
}

.es-field-help {
    margin: 4px 0 0;
    color: var(--muted);
    font-size: 11px;
}

/* --- read-only value shown where an input would be ------------------ */

.es-readonly {
    display: block;
    min-height: 38px;
    padding: 8px 12px;
    background: #eef1f7;
    border: 1px solid var(--field-border);
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    font-size: 14px;
    word-break: break-word;
}

.es-readonly.is-empty {
    color: #9aa7bb;
}

/* --- toolbar bits --------------------------------------------------- */

.es-toolbar .es-perpage {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--muted);
    font-size: 13px;
}

.es-toolbar .es-perpage select {
    width: auto;
    min-width: 78px;
}

/* --- charts --------------------------------------------------------- */

.es-chart-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 16px;
    margin-bottom: 18px;
}

.es-chart-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.es-chart-body {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    min-width: 0;
}

/* Chart.js sizes its canvas from the parent's width, so the parent needs a
   width of its own - a bare flex child would grow to the canvas's intrinsic
   size and never shrink back on a narrower window. */
.es-chart-canvas {
    position: relative;
    flex: 1 1 190px;
    min-width: 0;
}

.es-chart-canvas canvas {
    max-width: 100%;
}

.es-chart-wide {
    flex: 1 1 100%;
}

/* centred figure of the overall-progress doughnut - drawn as an overlay rather
   than a Chart.js plugin, which 2.5 has no stable hook for */
.es-doughnut-center {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    text-align: center;
}

.es-doughnut-value {
    color: var(--navy);
    font-size: 26px;
    font-weight: 700;
    line-height: 1.1;
}

.es-doughnut-label {
    color: var(--muted);
    font-size: 11px;
    font-weight: 600;
}

.es-chart-caption {
    margin: 10px 0 0;
    color: var(--muted);
    font-size: 11px;
    text-align: center;
}

.es-legend {
    flex: 0 1 auto;
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 12px;
}

.es-legend li {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 0;
    color: var(--ink-soft);
}

.es-legend-dot {
    flex: 0 0 auto;
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

.es-legend-total {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--card-border);
    color: var(--navy);
    font-weight: 700;
}

/* category panel: bars beside a No./% table */
.es-catlist {
    width: 100%;
    font-size: 12px;
}

.es-catlist td {
    padding: 4px 6px;
    vertical-align: middle;
}

.es-catlist .es-cat-label {
    color: var(--ink-soft);
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.es-catlist .es-cat-num,
.es-catlist .es-cat-pct {
    color: var(--navy);
    font-weight: 700;
    text-align: right;
    white-space: nowrap;
}

.es-catlist tfoot td {
    border-top: 1px solid var(--card-border);
    color: var(--navy);
    font-weight: 700;
}

/* --- filter card ---------------------------------------------------- */

.es-filter-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px 16px;
}

.es-filter-actions {
    display: flex;
    align-items: flex-end;
    gap: 8px;
}

.es-filter-actions .btn {
    height: 38px;
}

/* --- tables --------------------------------------------------------- */

/* The log has fourteen columns and will not fit a 1366 screen. Scrolling the
   table inside its own box keeps the PAGE from scrolling sideways, which is
   what breaks the fixed header and the sticky action bar. */
.es-table-scroll {
    width: 100%;
    max-width: 100%;
    /* The card is .es-card-flush (padding: 0) so the header row can run edge to
       edge; without an inset here the table's first and last columns sat hard
       against the card border. */
    padding: 0 14px 14px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

@media (max-width: 768px) {
    .es-table-scroll {
        padding: 0 8px 10px;
    }
}

.es-table-scroll > .table {
    margin-bottom: 0;
}

.es-table {
    width: 100%;
    border-collapse: collapse;
}

/* White header with navy text, rather than a navy band. The filled bar read as
   a second toolbar stacked under the real one; on white the header belongs to
   the data beneath it and the eye goes to the rows. The double rule under it is
   what separates header from body now that the fill does not. */
.es-table > thead > tr > th {
    padding: 10px 10px;
    background: var(--card-bg);
    color: var(--navy);
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .2px;
    white-space: nowrap;
    border-bottom: 2px solid var(--card-border);
}

.es-table > tbody > tr > td {
    padding: 10px;
    border-top: 1px solid #edf1f7;
    font-size: 13px;
    vertical-align: middle;
}

.es-table > tbody > tr:hover {
    background: #f6f9ff;
}

.es-table th:first-child,
.es-table td:first-child {
    padding-left: 14px;
}

.es-table th:last-child,
.es-table td:last-child {
    padding-right: 14px;
}

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

/* long free text in a wide table: readable without stretching the row */
.es-cell-text {
    display: block;
    max-width: 260px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The Manage NC/CA register's Project column (client request, 18 September):
   a project name rarely needs .es-cell-text's full 260px, and it was taking
   that much from every other column on the row. Narrower, still truncated
   with an ellipsis; the cell's title attribute carries the full name. */
.es-cell-text.es-cell-narrow-project {
    max-width: 130px;
}

.es-cell-wrap {
    display: block;
    min-width: 180px;
    max-width: 320px;
    white-space: normal;
    line-height: 1.45;
}

.es-cell-sub {
    display: block;
    margin-top: 2px;
    color: var(--muted);
    font-size: 11px;
}

.es-rownum {
    color: var(--muted);
    font-weight: 700;
}

.es-cell-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.es-table-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 14px 2px;
    color: var(--muted);
    font-size: 12px;
}

.es-table-footer .pagination {
    margin: 0;
}

/* --- editable row table (required actions) -------------------------- */

.es-edit-table > tbody > tr > td {
    padding: 8px 8px;
    vertical-align: top;
}

.es-edit-table .form-control {
    min-width: 90px;
}

.es-edit-table textarea.form-control {
    min-height: 62px;
    resize: vertical;
}

.es-edit-table .es-col-num {
    width: 44px;
    padding-top: 16px;
    color: var(--muted);
    font-weight: 700;
    text-align: center;
}

.es-edit-table .es-col-pct {
    width: 110px;
}

.es-edit-table .es-col-toggle {
    width: 130px;
    padding-top: 16px;
    text-align: center;
}

.es-edit-table .es-col-date {
    width: 170px;
}

.es-edit-table .es-col-act {
    width: 120px;
    padding-top: 12px;
    white-space: nowrap;
}

.es-edit-table .es-col-assignee {
    width: 200px;
}

.es-input-pct {
    position: relative;
}

.es-input-pct .form-control {
    padding-right: 34px;
}

.es-input-pct .es-input-suffix {
    position: absolute;
    top: 1px;
    right: 1px;
    bottom: 1px;
    display: flex;
    align-items: center;
    padding: 0 10px;
    border-left: 1px solid var(--field-border);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    background: #eef1f7;
    color: var(--muted);
    font-size: 12px;
    font-weight: 700;
}

/* --- toggle switch -------------------------------------------------- */

.es-switch {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 22px;
    margin: 0;
    vertical-align: middle;
}

.es-switch input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.es-switch .es-switch-track {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: var(--radius-pill);
    background: #cfd7e5;
    transition: background-color .15s ease;
    cursor: pointer;
}

.es-switch .es-switch-track::before {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 2px rgba(16, 32, 64, .3);
    transition: transform .15s ease;
}

.es-switch input:checked + .es-switch-track {
    background: var(--st-success);
}

.es-switch input:checked + .es-switch-track::before {
    transform: translateX(18px);
}

.es-switch input:focus + .es-switch-track {
    box-shadow: 0 0 0 3px rgba(30, 58, 110, .15);
}

.es-switch input:disabled + .es-switch-track {
    opacity: .55;
    cursor: not-allowed;
}

/* --- pills, chips, progress, days-left ------------------------------ */

.pill-sm {
    padding: 2px 8px;
    font-size: 10px;
}

.es-progress {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 110px;
}

.es-progress .progress-slim {
    flex: 1 1 auto;
    min-width: 60px;
}

.es-progress-value {
    flex: 0 0 auto;
    color: var(--ink-soft);
    font-size: 12px;
    font-weight: 700;
}

.es-daysleft {
    display: inline-flex;
    flex-direction: column;
    gap: 3px;
    align-items: flex-start;
}

.es-daysleft-date {
    color: var(--ink-soft);
    font-size: 12px;
    white-space: nowrap;
}

/* A row of evidence chips - the immediate action can carry several files, and
   .chip already brings its own bottom margin, so this only has to wrap. */
.es-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 6px;
}

.chip-evidence {
    font-weight: 500;
}

.chip-evidence a {
    color: var(--navy);
    text-decoration: none;
}

.chip-evidence a:hover {
    text-decoration: underline;
}

.chip-badge {
    padding: 1px 5px;
    border-radius: 4px;
    color: #fff;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .3px;
}

.chip-badge.is-pdf {
    background: var(--brand-red);
}

.chip-badge.is-img {
    background: var(--st-info);
}

.chip-size {
    color: var(--muted);
    font-size: 11px;
    font-weight: 500;
}

/* --- small helpers -------------------------------------------------- */

.es-empty {
    padding: 22px 14px;
    border: 1px dashed var(--card-border);
    border-radius: var(--radius);
    background: #fbfcfe;
    color: var(--muted);
    font-size: 13px;
    text-align: center;
}

.es-hint {
    color: var(--muted);
    font-size: 12px;
}

.es-info-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: #dfe6f3;
    color: var(--navy);
    font-size: 10px;
    font-weight: 700;
    cursor: help;
}

.es-stack {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.es-muted {
    color: var(--muted);
}

/* --- form action bar ------------------------------------------------ */

.es-formbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
    margin: 4px 0 24px;
}

.es-formbar .btn {
    min-width: 128px;
}

.es-formbar-spacer {
    margin-right: auto;
}

/* --- modals --------------------------------------------------------- */

.es-modal .modal-dialog {
    width: 560px;
    max-width: 94%;
}

.es-modal .modal-content {
    border: 0;
    border-radius: var(--radius) !important;
    box-shadow: var(--shadow-lg);
}

.es-modal .modal-header .close {
    margin-top: 2px;
    color: var(--muted);
    font-size: 22px;
    opacity: .8;
}

.es-modal .modal-body .es-fields {
    grid-template-columns: 1fr;
}

.es-modal-wide .modal-dialog {
    width: 760px;
}

/* --- responsive ----------------------------------------------------- */

@media (max-width: 991px) {
    .es-page-title {
        font-size: 19px;
    }

    .es-page-actions {
        margin-left: 0;
    }

    .es-formbar .btn {
        flex: 1 1 auto;
        min-width: 0;
    }
}

@media (max-width: 767px) {
    .es-fields,
    .es-filter-grid {
        grid-template-columns: 1fr;
    }

    .es-field-inline {
        flex-wrap: wrap;
    }

    .es-chart-grid {
        grid-template-columns: 1fr;
    }
}


/* ==========================================================================
   5. TYPOGRAPHY
   --------------------------------------------------------------------------
   Until now this application had no typeface at all. Nothing in this file set
   a font-family, and the "open sans" inherited from the legacy theme was never
   actually loaded - no webfont link, no local copy - so every screen has been
   rendering in whatever Arial-alike the browser fell back to. This is the first
   specified type in the product.

   Self-hosted rather than fetched from Google, for the same reason select2 and
   sweetalert2 are vendored here: sites on bad links have to keep working.

   ON WEIGHTS. Lato ships 100/300/400/700/900 only - there is no 500, no 600,
   and no variable axis. Asking for 500 and 600 gets synthetic bolding, which
   smears the letterforms Lato was picked for. The requested scale is mapped
   onto the weights that exist: 500 becomes 400 so navigation stays quiet, and
   600 becomes 700 so labels and buttons carry real weight.
   ========================================================================== */

@font-face {
    font-family: 'Lato';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/lato/lato-400-italic-ext.woff2') format('woff2');
    unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Lato';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/lato/lato-400-italic-latin.woff2') format('woff2');
    unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/lato/lato-400-normal-ext.woff2') format('woff2');
    unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/lato/lato-400-normal-latin.woff2') format('woff2');
    unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/lato/lato-700-normal-ext.woff2') format('woff2');
    unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Lato';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/lato/lato-700-normal-latin.woff2') format('woff2');
    unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
    --font-sans: 'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;

    /* Sizes as specified by the client; weights are Lato's real ones. */
    --fs-page-title: 26px;   --fw-page-title: 700;
    --fs-section:    17px;   --fw-section:    700;
    --fs-nav:        14px;   --fw-nav:        400;
    --fs-label:      13px;   --fw-label:      700;
    --fs-body:       14px;   --fw-body:       400;
    --fs-table:      13.5px;
    --fs-button:     13.5px; --fw-button:     700;
    --fs-small:      12px;
}

body.es-theme,
body.es-theme .form-control,
body.es-theme .btn,
body.es-theme table,
body.es-theme input,
body.es-theme select,
body.es-theme textarea,
body.es-theme .modal-content,
body.es-theme .select2-container {
    font-family: var(--font-sans);
}

:where(body.es-theme) :where(.page-title, h1) {
    font-size: var(--fs-page-title);
    font-weight: var(--fw-page-title);
    line-height: 1.25;
    color: var(--navy);
}

/* The legacy theme renders h4 lighter than the chart titles beneath it, so a
   container reads as subordinate to its own contents. Levelled here. */
:where(body.es-theme) :where(h2, h3, h4, .es-section-title, .panel-title) {
    font-size: var(--fs-section);
    font-weight: var(--fw-section);
    line-height: 1.3;
    color: var(--navy);
}

body.es-theme .es-nav > li > a { font-size: var(--fs-nav); font-weight: var(--fw-nav); }

:where(body.es-theme) :where(label, .control-label, .field-label) {
    font-size: var(--fs-label);
    font-weight: var(--fw-label);
    letter-spacing: .01em;
}

body.es-theme { font-size: var(--fs-body); font-weight: var(--fw-body); }
:where(body.es-theme) :where(.form-control) { font-size: var(--fs-body); font-weight: var(--fw-body); }

:where(body.es-theme) :where(table) { font-size: var(--fs-table); }
:where(body.es-theme) :where(.table > tbody > tr > td) { font-size: var(--fs-table); }
body.es-theme .table > thead > tr > th {
    font-size: var(--fs-small);
    font-weight: 700;
    letter-spacing: .02em;
}

:where(body.es-theme) :where(.btn) { font-size: var(--fs-button); font-weight: var(--fw-button); }

/* French runs 20-30 percent longer than English, so anything at the small end
   of the scale is given room to wrap rather than clip mid-word. */
body.es-theme .field-label,
body.es-theme .table > thead > tr > th { line-height: 1.35; }

/* ==========================================================================
   Dashboard KPI tiles + chart legibility
   --------------------------------------------------------------------------
   Added after a design review found the dashboard tiles painting sentiment by
   metric rather than by value: "Safety Audits" was rendered on success green
   whether it read 500 or 0, so the two worst numbers on the page (0 audits,
   0 inspections) were shown as good news.

   The rule this section encodes: the tile ground is always neutral, and the
   only coloured element is a small state indicator whose class is chosen from
   the VALUE at render time. A zero on a "more is better" metric therefore
   cannot come out green.

   The inks below are their own scale rather than the existing .pill-* ones
   because those do not clear WCAG AA at 11px: #d64545 on rgba(214,69,69,.12)
   measures 3.73:1 and .pill-warning measures 4.26:1. Every pair here was
   measured against its own tint and clears 4.5:1 - bad 6.38:1, warn 4.72:1,
   good 4.59:1, flat 6.14:1.
   ========================================================================== */

:root {
    --ind-bad-ink: #a01f24;
    --ind-bad-bg: #f8e5e6;
    --ind-warn-ink: #8a6411;
    --ind-warn-bg: #fceedf;
    --ind-good-ink: #2c7a45;
    --ind-good-bg: #e6f2e9;
    --ind-flat-ink: #4a5b70;
    --ind-flat-bg: #eef1f7;

    --fs-kpi: 28px;
    --fs-micro: 11px;
}

/* --- value-driven KPI tiles ----------------------------------------- */

/* 180px is chosen so a 1440px window fits six tiles on one row: the grid this
   replaced was a bootstrap col-md-4, which capped the dashboard at a three-up
   and left a literal empty <div class="col-md-6"></div> as a dead cell. */
.es-kpi-grid {
    display: grid;
    /* 180px meant nine tiles a row at 1900 and the thirteenth wrapped onto a
       third line. 128px fits the full set on one row on a wide screen and still
       wraps sensibly on a laptop - the count stays complete either way, which is
       the point: nothing is hidden to make it fit. */
    grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
    gap: 10px;
    margin: 0 0 16px;
}

.es-kpi-group-title {
    margin: 0 0 10px;
}

.es-kpi {
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
    padding: 11px 12px;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--radius-tile);
}

/* The tiles used to carry a 3px coloured left edge keyed to good/warn/bad. It
   has been removed: across a full dashboard it put a row of competing colours
   on chrome rather than on content, and the state it encoded is still said out
   loud by the note pill underneath the figure - which says it in words as well
   as colour, so nothing is lost by taking the stripe away.

   The rules that painted that edge are gone. The .is-good / .is-warn / .is-bad
   classes are still emitted on the tile, and deliberately so: every caller of
   components/stat_cards still passes state, the pill still reads it, and a
   future treatment that is not a coloured edge has a hook to attach to. */

.es-kpi-value {
    font-size: 22px;
    font-weight: 700;
    line-height: 1.05;
    color: var(--navy);
}

.es-kpi-label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .04em;
    line-height: 1.35;
    text-transform: uppercase;
    color: var(--muted);
}

.es-kpi-note {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    align-self: flex-start;
    max-width: 100%;
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    background: var(--ind-flat-bg);
    color: var(--ind-flat-ink);
    font-size: var(--fs-micro);
    font-weight: 700;
    line-height: 1.65;
}

.es-kpi-note::before {
    content: '';
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
}

.es-kpi.is-good .es-kpi-note { background: var(--ind-good-bg); color: var(--ind-good-ink); }
.es-kpi.is-warn .es-kpi-note { background: var(--ind-warn-bg); color: var(--ind-warn-ink); }
.es-kpi.is-bad  .es-kpi-note { background: var(--ind-bad-bg);  color: var(--ind-bad-ink); }

/* --- chart frames ---------------------------------------------------- */

/* Chart.js 2.5 with maintainAspectRatio:false sizes the canvas from its
   parent's box, so the parent must own a height. Without one the parent
   derives its height from the canvas and the pair collapses - which is what
   squashed the N/C log's line chart into a 40px smear and stacked its
   category labels on top of each other. */
.es-chart-frame {
    position: relative;
    height: 236px;
    min-width: 0;
}

.es-chart-frame.is-tall {
    height: 300px;
}

/* Flex column with a growing frame so two panels side by side end their plots
   on the same baseline even when one carries a sub-heading and the other does
   not; the min-height is what stops the frame and the canvas inside it from
   sizing off each other and collapsing. */
.es-chart-panel {
    display: flex;
    flex-direction: column;
    padding: 14px 16px 16px;
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--radius);
}

.es-chart-panel .es-chart-frame {
    flex: 1 1 auto;
    height: auto;
    min-height: 236px;
}

.es-chart-panel-title {
    margin: 0 0 4px;
}

.es-chart-panel-sub {
    margin: 0 0 12px;
    color: var(--muted);
    font-size: var(--fs-micro);
    line-height: 1.4;
}

/* Fixed two-up rather than auto-fit: the four analysis charts want to land as
   a 2x2, and an auto-fit track count of three would orphan the fourth. */
.es-chart-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
}

@media (max-width: 900px) {
    .es-chart-row {
        grid-template-columns: 1fr;
    }
}

/* Same collapse on the N/C log, whose canvases sit in .es-chart-canvas. */
.es-chart-canvas { height: 200px; }
.es-chart-wide { height: 226px; }

/* The centred figure used to be a percentage plus a repeat of the card title,
   which overflowed the doughnut hole and printed across the ring. Held inside
   the hole now, and the second line carries the fraction instead of the
   heading the reader has already got directly above the chart. */
.es-doughnut-center {
    width: 58%;
    left: 21%;
    right: 21%;
}

.es-doughnut-label {
    font-size: var(--fs-micro);
    font-weight: 400;
}

/* ======================================================================
   LOW-SCORING SCREENS PASS
   ----------------------------------------------------------------------
   Parts added for the redesign of the screens a design review scored
   lowest: the two Google-Maps pages, the Reports landing page, the
   approvals and deletion-request inboxes, the audit trail and the Start
   Project form. Everything here is built from the tokens declared at the
   top of this file - no new colours, no new type sizes, and no 500 or 600
   font weights, which Lato does not ship. Appended so the existing cascade
   is untouched.
   ====================================================================== */

/* --- hub of links (Reports landing page) ----------------------------- */

/* The Reports index has no data of its own; it exists to route somebody to
   the register they actually want. A grid of destinations, not a table. */
.es-linkgrid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 14px;
}

.es-linkcard {
    display: block;
    padding: 16px 18px;
    border: 1px solid var(--card-border);
    border-left: 4px solid var(--navy);
    border-radius: var(--radius);
    background: var(--card-bg);
    box-shadow: var(--shadow);
    color: var(--ink);
    text-decoration: none;
    transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease;
}

.es-linkcard:hover,
.es-linkcard:focus {
    border-left-color: var(--brand-red);
    box-shadow: var(--shadow-lg);
    color: var(--ink);
    text-decoration: none;
    transform: translateY(-1px);
}

.es-linkcard-title {
    display: block;
    margin: 0 0 4px;
    color: var(--navy);
    font-size: var(--fs-section);
    font-weight: var(--fw-section);
    line-height: 1.25;
}

.es-linkcard-desc {
    display: block;
    margin: 0;
    color: var(--muted);
    font-size: var(--fs-micro);
    line-height: 1.45;
}

.es-linkcard-icon {
    margin-right: 7px;
    color: var(--brand-red);
}

/* --- map framing ------------------------------------------------------ */

/* The two map screens were a bare 700px Google canvas and nothing else. When
   the API key is rejected, or when nothing in the result set carries
   coordinates, the whole page became a grey rectangle with no way forward.
   The canvas is framed, and a notice sits behind it that only shows through
   when Maps never paints. */
.es-map-frame {
    position: relative;
    min-height: 420px;
    border: 1px solid var(--card-border);
    border-radius: var(--radius-sm);
    background: var(--field-bg);
    overflow: hidden;
}

/* Matched on an explicit class, not on div[id]: the fallback below carries an
   id too (initMap needs to find it), and an attribute selector would have the
   higher specificity and quietly hand the fallback this rule's geometry. */
.es-map-frame > .es-map-canvas {
    position: relative;
    z-index: 0;
    width: 100%;
    height: 520px;
    background: transparent;
}

/* IN FRONT of the canvas, and hidden by initMap() the moment Maps actually
   calls back. Behind it was the obvious arrangement and it does not work:
   when the key is rejected the Maps script paints its own opaque "Oops!
   Something went wrong" panel into the canvas, which then covers the notice
   that would have told the reader where the data went. */
.es-map-fallback {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1;
    background: var(--field-bg);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 24px;
    text-align: center;
}

/* Maps said it will never load. There is no reason to keep reserving half a
   screen for a canvas that is not coming, so the frame collapses to the height
   of its notice and the register below moves up into view. */
.es-map-frame.is-unavailable {
    min-height: 0;
}

.es-map-frame.is-unavailable > .es-map-canvas {
    height: 200px;
}

/* No points at all: no canvas is created, so the notice is the whole panel
   and must not be taken out of the flow. */
.es-map-frame.is-empty {
    min-height: 240px;
}

.es-map-frame.is-empty .es-map-fallback {
    position: static;
}

.es-map-fallback-icon {
    color: var(--st-muted);
    font-size: 30px;
}

.es-map-fallback-title {
    color: var(--ink-soft);
    font-size: var(--fs-section);
    font-weight: var(--fw-section);
}

.es-map-fallback-note {
    max-width: 460px;
    color: var(--muted);
    font-size: var(--fs-micro);
    line-height: 1.5;
}

/* --- richer empty state ---------------------------------------------- */

/* .es-empty is one muted line. An inbox that is empty because there is
   genuinely nothing to do needs to say so, and say what would put something
   in it - otherwise the reader cannot tell it apart from a broken filter.
   It also replaces the alert-danger boxes these screens used, which painted
   "nothing to approve" - a good state - in the colour of a failure. */
.es-empty-rich {
    padding: 34px 22px;
    border: 1px dashed var(--card-border);
    border-radius: var(--radius);
    background: #fbfcfe;
    text-align: center;
}

.es-empty-rich .es-empty-icon {
    display: block;
    margin-bottom: 10px;
    color: var(--st-muted);
    font-size: 26px;
}

.es-empty-rich .es-empty-title {
    display: block;
    margin-bottom: 6px;
    color: var(--ink-soft);
    font-size: var(--fs-section);
    font-weight: var(--fw-section);
}

.es-empty-rich .es-empty-note {
    display: block;
    max-width: 520px;
    margin: 0 auto;
    color: var(--muted);
    font-size: var(--fs-body);
    line-height: 1.55;
}

.es-empty-rich .es-empty-actions {
    margin-top: 14px;
}

/* --- consequence callout --------------------------------------------- */

/* Used where a form or a button destroys something. Red edge, quiet fill:
   loud enough to stop, not so loud it reads as an error that has already
   happened. */
.es-callout {
    display: flex;
    gap: 12px;
    padding: 14px 16px;
    border: 1px solid var(--card-border);
    border-left: 4px solid var(--brand-red);
    border-radius: var(--radius-sm);
    background: #fdf6f6;
}

.es-callout > .fa {
    flex: 0 0 auto;
    margin-top: 2px;
    color: var(--brand-red);
    font-size: 16px;
}

.es-callout-title {
    margin: 0 0 4px;
    color: var(--ink);
    font-size: var(--fs-label);
    font-weight: var(--fw-label);
}

.es-callout p {
    margin: 0;
    color: var(--ink-soft);
    font-size: var(--fs-body);
    line-height: 1.55;
}

.es-callout ul {
    margin: 6px 0 0;
    padding-left: 18px;
    color: var(--ink-soft);
    font-size: var(--fs-body);
    line-height: 1.6;
}

/* --- evidence thumbnails in a table cell ------------------------------ */

/* The incident register printed each photo at 50x50 with no frame, so a
   missing file left the browser's broken-image glyph in the middle of the
   row. Fixed box, cropped fill, visible frame when the image does not load. */
.es-thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.es-thumbs a {
    display: block;
    width: 42px;
    height: 42px;
    border: 1px solid var(--card-border);
    border-radius: var(--radius-sm);
    background: var(--field-bg);
    overflow: hidden;
}

.es-thumbs img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* --- coordinate pair -------------------------------------------------- */

.es-coords {
    color: var(--accent-blue);
    font-size: var(--fs-micro);
    white-space: nowrap;
}

.es-coords:hover,
.es-coords:focus {
    color: var(--navy);
}

/* --- row actions ------------------------------------------------------ */

/* Two buttons per row were wrapping and doubling the height of every row in
   the incident register. Kept on one line; the column takes the width it
   needs and the table scrolls inside its own box. */
.es-rowbtns {
    display: flex;
    flex-wrap: nowrap;
    gap: 4px;
    white-space: nowrap;
}

/* For a register whose rows are already tall: stacking the buttons narrows the
   column instead of lengthening the row. */
.es-rowbtns-stack {
    flex-direction: column;
    align-items: stretch;
}

/* The incident narrative is the widest column in the safety register and the
   reason the Action column was being clipped at the right edge of the card.
   Three lines is enough to tell one incident from another; the full text is on
   the Review screen behind the button. */
.es-cell-wrap.es-cell-narrow {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    min-width: 170px;
    max-width: 215px;
    overflow: hidden;
}

/* Evidence file that no longer resolves: keep the frame, drop the browser's
   broken-image glyph, and mark it so it does not read as a real thumbnail. */
.es-thumbs a.is-missing {
    position: relative;
}

.es-thumbs a.is-missing::after {
    content: "03e";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--st-muted);
    font-family: FontAwesome;
    font-size: 16px;
}

/* --- Core Details grid on the Start Project form ---------------------- */

/* The form's own numbering ran 1,2,3,4,5,8,5,6,7,9,10,12,13 across a split
   two-column block, so the sequence the labels promised did not match the
   order the eye reads. One grid, one reading order. */
.es-form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 12px 16px;
}

.es-form-grid .form-group {
    margin-bottom: 0;
}

.es-form-grid .es-span-2 {
    grid-column: span 2;
}

.es-form-grid .es-span-full {
    grid-column: 1 / -1;
}

@media (max-width: 700px) {
    .es-form-grid .es-span-2 {
        grid-column: auto;
    }
}

/* A native colour input renders as a solid black slab at full control height
   before anything is picked, which read as a redaction bar in review. */
.es-form-grid input[type="color"] {
    height: 38px;
    padding: 3px;
    cursor: pointer;
}

/* Specificity note: the heading and control rules above are wrapped in :where()
   so they contribute ZERO specificity. As plain `body.es-theme h3` they scored
   0-1-2 and silently outranked every page's own title class - .home-hero__title
   is 0-1-0 - which collapsed page titles to section size across the screens that
   already had considered typography, and cost each of them a point in review.
   A type baseline should lose to a deliberate local decision, not beat it. */

/* ==========================================================================
   Dashboard project timeline
   --------------------------------------------------------------------------
   Replaces the dhtmlxgantt chart the /home "Projects On-going" panel used to
   draw. That chart was pulled from https://cdn.dhtmlx.com, which this app
   cannot rely on - the offline requirement is why select2, sweetalert2 and the
   DataTables buttons are all vendored - and the `edge` build it pinned to had
   drifted far enough that gantt.plugins({marker:true}) stopped defining
   gantt.addMarker, so the init threw and the panel rendered as ~500px of blank
   card claiming eleven projects.

   What replaces it is ordinary HTML laid out by the blade: the left and width
   of every bar are percentages of one shared date range computed in PHP, so
   there is no library, no CDN, no measurement pass, and nothing that can fail
   and leave an empty box behind. The only script left on the panel opens the
   summary modal.

   Colour comes from the --ind-* indicator scale defined above rather than the
   chart's own blue/amber/red, so the bars, the legend keys and the status text
   are one system and every pair clears 4.5:1 on its own tint.
   ========================================================================== */

.es-ptl {
    /* Below these widths the columns stop being readable, so the timeline
       scrolls inside itself rather than squeezing - and, crucially, rather than
       making the whole page scroll sideways. */
    --ptl-label: 250px;
    --ptl-pct: 112px;
    /* Wide enough that the month labels never touch. Seven of them at 11px need
       ~63px each once French turns "Sep" into "sept."; 520px puts 82px between
       their centres. Below this the timeline scrolls rather than crushing them
       into each other. */
    --ptl-track: 520px;
    --ptl-line: #e9eef7;

    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
}

.es-ptl:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: -2px;
}

.es-ptl__inner {
    min-width: calc(var(--ptl-label) + var(--ptl-track) + var(--ptl-pct));
}

.es-ptl__head,
.es-ptl__row {
    display: grid;
    grid-template-columns: var(--ptl-label) minmax(var(--ptl-track), 1fr) var(--ptl-pct);
    align-items: stretch;
}

.es-ptl__head {
    background: var(--card-bg);
    border-bottom: 1px solid var(--ptl-line);
}

.es-ptl__row {
    background: var(--card-bg);
    border-bottom: 1px solid var(--ptl-line);
}

.es-ptl__row:nth-child(even) {
    background: #f7f9fd;
}

.es-ptl__row:last-child {
    border-bottom: 0;
}

/* The label column stays put while the months scroll under it. Without this a
   scrolled timeline is a wall of anonymous bars. `inherit` picks up whichever
   zebra band the row is in, so the sticky column cannot show a seam. */
.es-ptl__label {
    position: sticky;
    left: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 3px;
    min-width: 0;
    padding: 9px 14px 9px 16px;
    background: inherit;
    border-right: 1px solid var(--ptl-line);
}

.es-ptl__head .es-ptl__label,
.es-ptl__head .es-ptl__pct {
    justify-content: center;
    color: var(--muted);
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
}

/* A button, not an anchor: it opens a dialog, it does not navigate. The reset
   is here because Bootstrap 3 gives a bare button its own grey chrome. */
.es-ptl__name {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    color: var(--ink);
    font: inherit;
    font-weight: 700;
    line-height: 1.3;
    text-align: left;
    cursor: pointer;
}

.es-ptl__name:hover,
.es-ptl__name:focus {
    color: var(--accent-blue);
    text-decoration: underline;
}

.es-ptl__sub {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 8px;
    color: var(--muted);
    font-size: var(--fs-micro);
    line-height: 1.35;
}

.es-ptl__code {
    font-weight: 700;
    color: var(--ink-soft);
}

/* --- the track -------------------------------------------------------- */

.es-ptl__track {
    position: relative;
    min-width: 0;
    padding: 12px 0;
}

/* Two rows deep: the "today" flag sits on the upper band and the month labels
   on the lower one. Sharing one band, the flag covered a month name outright
   once French widened it to AUJOURD'HUI. */
.es-ptl__axis {
    height: 48px;
    padding: 0;
}

.es-ptl__rule,
.es-ptl__tick {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--ptl-line);
}

/* Above the rules, and opaque: a label emitted before the next month's rule
   otherwise gets a hairline drawn straight through its last character. */
.es-ptl__tick-label {
    position: absolute;
    z-index: 1;
    bottom: 6px;
    transform: translateX(-50%);
    padding: 0 4px;
    background: var(--card-bg);
    white-space: nowrap;
    color: var(--muted);
    font-size: var(--fs-micro);
    font-weight: 400;
}

/* The end labels anchor inward. Centred, the first one lands half under the
   sticky project column and is read as ":2025". */
.es-ptl__tick-label.is-start { transform: translateX(0); }
.es-ptl__tick-label.is-end   { transform: translateX(-100%); }

/* Navy, not red: an overdue bar is already red, and a red "today" line beside
   it reads as part of the same signal. */
.es-ptl__today {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 0;
    border-left: 2px dashed var(--navy);
    opacity: .55;
}

.es-ptl__today-flag {
    position: absolute;
    top: 4px;
    transform: translateX(-50%);
    padding: 2px 7px;
    border-radius: var(--radius-pill);
    background: var(--navy);
    color: #ffffff;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    white-space: nowrap;
}

.es-ptl__bar {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 16px;
    min-width: 4px;
    border-radius: var(--radius-sm);
    border: 1px solid;
    overflow: hidden;
}

/* The tint is the whole span; the solid fill is the elapsed part of it. */
.es-ptl__fill {
    display: block;
    height: 100%;
    max-width: 100%;
    border-radius: 6px 0 0 6px;
}

.es-ptl__bar.is-normal  { background: var(--ind-good-bg); border-color: var(--ind-good-ink); }
.es-ptl__bar.is-pending { background: var(--ind-warn-bg); border-color: var(--ind-warn-ink); }
.es-ptl__bar.is-overdue { background: var(--ind-bad-bg);  border-color: var(--ind-bad-ink); }

.es-ptl__bar.is-normal  .es-ptl__fill { background: var(--ind-good-ink); }
.es-ptl__bar.is-pending .es-ptl__fill { background: var(--ind-warn-ink); }
.es-ptl__bar.is-overdue .es-ptl__fill { background: var(--ind-bad-ink); }

/* A project with no start or end date gets this instead of a bar. It is not
   dropped from the list and it is not drawn at position zero, either of which
   would say something about its schedule that is not true. */
.es-ptl__none {
    position: absolute;
    top: 50%;
    left: 0;
    transform: translateY(-50%);
    padding: 2px 10px;
    border: 1px dashed var(--field-border);
    border-radius: var(--radius-sm);
    background: var(--field-bg);
    color: var(--muted);
    font-size: var(--fs-micro);
    font-weight: 400;
    white-space: nowrap;
}

.es-ptl__row.is-unscheduled .es-ptl__dates {
    font-style: italic;
}

/* --- progress / status column ----------------------------------------- */

.es-ptl__pct {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    gap: 3px;
    padding: 9px 16px 9px 10px;
    text-align: right;
}

.es-ptl__pct-value {
    color: var(--ink);
    font-size: var(--fs-table);
    font-weight: 700;
    line-height: 1.2;
}

.es-ptl__pct-value.is-muted {
    color: var(--muted);
    font-weight: 400;
}

/* The state is spelled out, so the bar colour is a second cue rather than the
   only one carrying it. */
.es-ptl__state {
    font-size: var(--fs-micro);
    font-weight: 700;
    line-height: 1.25;
}

.es-ptl__state.is-normal  { color: var(--ind-good-ink); }
.es-ptl__state.is-pending { color: var(--ind-warn-ink); }
.es-ptl__state.is-overdue { color: var(--ind-bad-ink); }

/* --- legend ------------------------------------------------------------ */

.es-ptl-key {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 11px;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}

.es-ptl-key::before {
    content: "";
    width: 10px;
    height: 10px;
    border-radius: 3px;
    background: currentColor;
}

.es-ptl-key.is-normal  { background: var(--ind-good-bg); color: var(--ind-good-ink); border-color: var(--ind-good-ink); }
.es-ptl-key.is-pending { background: var(--ind-warn-bg); color: var(--ind-warn-ink); border-color: var(--ind-warn-ink); }
.es-ptl-key.is-overdue { background: var(--ind-bad-bg);  color: var(--ind-bad-ink);  border-color: var(--ind-bad-ink); }

@media (max-width: 1024px) {
    /* Narrower label and progress columns buy back ~76px before the scroll
       starts. The track keeps its full minimum: squeezing that is what makes
       month labels collide, and a scrollbar is the better trade. Past this
       point the timeline scrolls inside .es-ptl and the page still does not. */
    .es-ptl {
        --ptl-label: 190px;
        --ptl-pct: 96px;
    }
}

/* Second line of a chart caption: a related figure that is NOT the one the
   ring is drawing, so it has to read as subordinate rather than as a
   restatement of the number above it. */
.es-chart-caption-sub {
    display: block;
    margin-top: 2px;
    font-size: 11px;
    color: var(--muted);
}

/* Select-all row in a multi-check dropdown. Sits between the search box and
   the option list, and is ruled off from the options so it does not read as
   one of them. */
.es-multi-all {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 6px 12px 8px;
    border-bottom: 1px solid var(--card-border);
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-soft);
    cursor: pointer;
}

.es-multi-all input {
    margin: 0;
}

.es-multi-all input:disabled + span {
    opacity: .5;
}

/* Column chooser on the N/C log toolbar. A plain checkbox list - the menu is
   generated from the table headers, so it is as tall as the table is wide and
   needs its own scroll. */
.es-colvis-menu {
    min-width: 220px;
    padding: 6px 0;
}

.es-colvis-list {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 320px;
    overflow-y: auto;
}

.es-colvis-list label {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 5px 14px;
    font-weight: 400;
    font-size: 13px;
    cursor: pointer;
}

.es-colvis-list label:hover {
    background: var(--field-bg);
}

.es-colvis-footer {
    border-top: 1px solid var(--card-border);
    margin-top: 6px;
    padding: 8px 14px 4px;
}

/* A KPI tile that links to the rows behind it. The element is the anchor
   itself, not a wrapper, so it stays the grid item and keeps sharing a row
   height with the tiles beside it. Without these three rules it renders as an
   underlined UA-blue block and gives a keyboard user no focus ring on what is
   now the primary navigation of the screen. */
a.es-kpi,
a.es-kpi:hover,
a.es-kpi:focus {
    text-decoration: none;
    color: inherit;
}

a.es-kpi {
    transition: border-color .15s, box-shadow .15s, transform .15s;
}

a.es-kpi:hover {
    border-color: var(--accent-blue);
    box-shadow: var(--shadow-lg);
    transform: translateY(-1px);
}

a.es-kpi:focus-visible {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    a.es-kpi { transition: none; }
    a.es-kpi:hover { transform: none; }
}

/* Sortable table headers. The whole cell is the target, not just the text, so
   the click area matches what looks clickable. */
.es-table th.es-sortable {
    padding: 0;
}

.es-sort-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    padding: 10px 12px;
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}

.es-sort-link:hover,
.es-sort-link:focus {
    color: inherit;
    text-decoration: none;
    background: var(--field-bg);
}

.es-sort-link:focus-visible {
    outline: 2px solid var(--navy);
    outline-offset: -2px;
}

.es-sort-icon {
    display: inline-flex;
    flex: 0 0 auto;
}

/* The sorted column reads as chosen rather than merely hovered. */
.es-table th.es-sortable.is-sorted {
    background: var(--field-bg);
}

.es-table-sortnote {
    margin: 0;
    padding: 10px 16px 0;
    font-size: 13px;
    color: var(--muted);
}

/* ------------------------------------------------------------------ */
/* main content inset                                                   */
/* ------------------------------------------------------------------ */

/* The vendor theme gives .content padding: 25px 40px 40px, and every page
   also carries .m-l-md/.m-r-md for another 20px a side - 60px of gutter
   before any card starts, against a top navigation that begins at 12px. The
   page read as narrower than the chrome above it.

   Scoped to body.es-theme (0-2-1) so it beats both .content and the two
   margin utilities without editing the minified vendor sheet, and without
   changing what .m-l-md means anywhere else it is used. */
body.es-theme .content {
    margin-left: 0;
    margin-right: 0;
    padding: 20px 24px 32px;
}

@media (max-width: 768px) {
    body.es-theme .content {
        padding: 16px 14px 28px;
    }
}

/* ------------------------------------------------------------------ */
/* row action menus                                                     */
/* ------------------------------------------------------------------ */

/* A scrolling table clips its own dropdowns: .es-table-scroll and Bootstrap's
   .table-responsive both set overflow-x: auto, which establishes a clipping
   context, so a menu opened in the last column was cut off at the table's edge
   instead of overlaying the page. Fixed positioning takes it out of that
   context entirely; esafety-ui.js sets top/left from the button's own rect on
   open, and again on scroll and resize.

   Unscoped, because .es-rowmenu is only ever this control - the legacy .table
   screens need it as much as the themed ones. */
.es-rowmenu {
    position: static;
}

.es-rowmenu > .dropdown-menu {
    position: fixed;
    top: auto;
    left: auto;
    right: auto;
    z-index: 1060;
    margin: 0;
    min-width: 190px;
}

.es-rowmenu-btn {
    white-space: nowrap;
}

/* Search box on the table toolbar. Submits the same server-side `q` filter the
   Keyword field uses, so it searches the whole set rather than the page. */
.es-table-search {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
}

.es-table-search input[type=search] {
    width: 260px;
    max-width: 40vw;
}

@media (max-width: 768px) {
    .es-table-search input[type=search] {
        width: 100%;
        max-width: none;
    }
}

/* Destructive entries in a row menu. Red text rather than a red button: in a
   list of plain items the odd one out is the one to be careful with, and a
   filled red block inside a dropdown reads as the primary action. */
.es-rowmenu-danger,
.es-rowmenu-danger:hover,
.es-rowmenu-danger:focus {
    color: var(--brand-red) !important;
}

/* The legacy tables put their action cell last and often narrow; let the menu
   button keep its own line rather than squeezing the label. */
.es-table td .es-rowmenu,
body.es-theme .table td .es-rowmenu {
    display: inline-block;
}


/* ==========================================================================
   APK register (company profile > Other Mobile Apps)
   One card per app: the live build, its share link, the publish form with a
   drop zone and upload progress, and the release history.
   ========================================================================== */
.ma-card {
    padding: 0;
    overflow: hidden;
}

.ma-head {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 20px;
    border-bottom: 1px solid var(--card-border);
}

.ma-avatar {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-sm);
    background: #e8f4ec;
    color: var(--st-success);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
}

.ma-head-text {
    min-width: 0;
    flex: 1 1 auto;
}

.ma-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 16px;
    font-weight: 700;
    color: var(--navy);
}

.ma-sub {
    margin-top: 3px;
    font-size: 12px;
    color: var(--muted);
}

.ma-sub code,
.ma-drop-hint code {
    font-size: 11.5px;
}

.ma-dot {
    margin: 0 4px;
}

.ma-head-action {
    flex: 0 0 auto;
    margin: 0;
}

.ma-live {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
    gap: 1px;
    background: var(--card-border);
    border-bottom: 1px solid var(--card-border);
}

.ma-fact {
    background: #fbfcfe;
    padding: 14px 20px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    min-width: 0;
}

.ma-fact-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
}

.ma-fact-value {
    font-size: 15px;
    font-weight: 700;
    color: var(--ink);
    overflow-wrap: anywhere;
}

.ma-fact-note {
    display: block;
    margin-top: 1px;
    font-size: 12px;
    font-weight: 400;
    color: var(--muted);
}

.ma-fact-actions {
    align-items: flex-end;
}

.ma-share {
    padding: 16px 20px 4px;
}

.ma-share-row {
    display: flex;
    gap: 8px;
}

.ma-share-row .form-control {
    flex: 1 1 auto;
    min-width: 0;
    background: var(--field-bg);
}

.ma-share-row .btn {
    flex: 0 0 auto;
}

.ma-label {
    display: block;
    margin-bottom: 6px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--ink-soft);
}

.ma-optional {
    font-weight: 400;
    color: var(--muted);
}

.ma-empty {
    margin: 16px 20px 0;
}

.ma-section {
    padding: 18px 20px 20px;
    border-top: 1px solid var(--card-border);
}

.ma-share + .ma-section,
.ma-empty + .ma-section {
    margin-top: 12px;
}

.ma-section-title {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 14px;
    font-size: 14px;
    font-weight: 700;
    color: var(--navy);
}

.ma-count-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 20px;
    padding: 0 7px;
    border-radius: var(--radius-pill);
    background: #eef2f8;
    color: var(--ink-soft);
    font-size: 11.5px;
    font-weight: 700;
}

/* The drop zone is the file input's own <label>, so a click anywhere on it
   opens the picker and a drop lands on the same input. */
.ma-drop {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 0;
    padding: 26px 16px;
    border: 2px dashed var(--field-border);
    border-radius: var(--radius);
    background: #fbfcfe;
    text-align: center;
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

.ma-drop:hover,
.ma-drop.is-dragging {
    border-color: var(--accent-blue);
    background: #f2f7ff;
}

.ma-drop.is-ready {
    border-style: solid;
    border-color: var(--st-success);
    background: #f1f9f3;
}

.ma-drop.has-error {
    border-color: var(--st-open);
    background: #fff6f6;
}

/* Visually hidden but still focusable and still `required`, so the browser's
   own "choose a file" check keeps working when scripts are off. */
.ma-drop-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    overflow: hidden;
}

.ma-drop:focus-within {
    outline: 2px solid var(--accent-blue);
    outline-offset: 2px;
}

.ma-drop-icon {
    font-size: 28px;
    color: var(--accent-blue);
}

.ma-drop.is-ready .ma-drop-icon {
    color: var(--st-success);
}

.ma-drop.is-ready .ma-drop-icon::before {
    content: "\f00c"; /* fa-check */
}

.ma-drop-title {
    font-size: 14px;
    font-weight: 700;
    color: var(--ink);
    overflow-wrap: anywhere;
}

.ma-drop-hint {
    font-size: 12px;
    color: var(--muted);
}

.ma-link {
    color: var(--accent-blue);
    text-decoration: underline;
}

.ma-fields {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    margin-top: 16px;
}

.ma-field {
    min-width: 0;
}

.ma-upload > .ma-field {
    margin-top: 16px;
}

.ma-field .es-hint {
    margin: 5px 0 0;
}

.ma-field-error {
    margin: 6px 0 0;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--st-open);
}

.ma-count {
    text-align: right;
}

.ma-callout {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    margin-top: 14px;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    background: #fff7ea;
    border: 1px solid #f4dcb3;
    color: #7a4b0c;
    font-size: 12.5px;
    line-height: 1.5;
}

.ma-callout .fa {
    margin-top: 2px;
    color: var(--st-progress);
}

.ma-progress {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
}

.ma-progress[hidden] {
    display: none;
}

.ma-progress-track {
    flex: 1 1 auto;
    height: 8px;
    border-radius: var(--radius-pill);
    background: #e6ecf5;
    overflow: hidden;
}

.ma-progress-bar {
    display: block;
    width: 0;
    height: 100%;
    border-radius: inherit;
    background: var(--accent-blue);
    transition: width .2s ease;
}

.ma-progress-text {
    flex: 0 1 auto;
    min-width: 0;
    font-size: 12.5px;
    color: var(--ink-soft);
}

.ma-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 16px;
}

.ma-actions .btn {
    padding-left: 22px;
    padding-right: 22px;
}

.ma-history .ma-version {
    font-weight: 700;
    color: var(--ink);
}

.ma-history .ma-nowrap {
    white-space: nowrap;
}

.ma-history .ma-notes {
    max-width: 340px;
}

.ma-history .ma-notes span {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ma-history .ma-row-live > td {
    background: #f5fbf7;
}

@media (max-width: 767px) {
    .ma-head {
        flex-wrap: wrap;
    }

    .ma-head-action {
        width: 100%;
    }

    .ma-live {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .ma-fact-actions {
        align-items: flex-start;
    }

    .ma-fields {
        grid-template-columns: 1fr;
    }

    .ma-share-row {
        flex-direction: column;
    }

    /* Bar on its own line, the status under it: side by side on a phone the
       text squeezed the bar to nothing. */
    .ma-progress {
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
    }

    .ma-progress-track {
        flex: 0 0 8px;
    }
}
