/* Reset all link colors */
a, a:link, a:visited, a:hover, a:active {
    color: inherit !important;
    text-decoration: none !important;
}

/* !!! ===============================================================================================================*/
/* !!! FONT_IMPORT*/
/* ===================================================================================================================*/

@font-face {
    font-family: 'GT-Pressura-Standard-Black';
    src: url('/assets/GT-Pressura-Standard-Black.woff2') format('woff2'),
         url('/assets/GT-Pressura-Standard-Black.woff') format('woff'),
         url('/assets/GT-Pressura-Standard-Black.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Standard-Bold';
    src: url('/assets/GT-Pressura-Standard-Bold.woff2') format('woff2'),
         url('/assets/GT-Pressura-Standard-Bold.woff') format('woff'),
         url('/assets/GT-Pressura-Standard-Bold.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Standard-Medium';
    src: url('/assets/GT-Pressura-Standard-Medium.woff2') format('woff2'),
         url('/assets/GT-Pressura-Standard-Medium.woff') format('woff'),
         url('/assets/GT-Pressura-Standard-Medium.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Standard-Regular';
    src: url('/assets/GT-Pressura-Standard-Regular.woff2') format('woff2'),
         url('/assets/GT-Pressura-Standard-Regular.woff') format('woff'),
         url('/assets/GT-Pressura-Standard-Regular.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Standard-Light';
    src: url('/assets/GT-Pressura-Standard-Light.woff2') format('woff2'),
         url('/assets/GT-Pressura-Standard-Light.woff') format('woff'),
         url('/assets/GT-Pressura-Standard-Light.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Mono-Light';
    src: url('/assets/GT-Pressura-Mono-Light.woff2') format('woff2'),
         url('/assets/GT-Pressura-Mono-Light.woff') format('woff'),
         url('/assets/GT-Pressura-Mono-Light.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Mono-Regular';
    src: url('/assets/GT-Pressura-Mono-Regular.woff2') format('woff2'),
         url('/assets/GT-Pressura-Mono-Regular.woff') format('woff'),
         url('/assets/GT-Pressura-Mono-Regular.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Mono-Bold';
    src: url('/assets/GT-Pressura-Mono-Bold.woff2') format('woff2'),
         url('/assets/GT-Pressura-Mono-Bold.woff') format('woff'),
         url('/assets/GT-Pressura-Mono-Bold.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Extended-Bold';
    src: url('/assets/GT-Pressura-Extended-Bold.woff2') format('woff2'),
         url('/assets/GT-Pressura-Extended-Bold.woff') format('woff'),
         url('/assets/GT-Pressura-Extended-Bold.otf') format('opentype');
    font-display: swap;
}
@font-face {
    font-family: 'GT-Pressura-Standard-Light-Italic';
    src: url('/assets/GT-Pressura-Standard-Light-Italic.woff2') format('woff2'),
         url('/assets/GT-Pressura-Standard-Light-Italic.woff') format('woff'),
         url('/assets/GT-Pressura-Standard-Light-Italic.otf') format('opentype');
    font-display: swap;
}

/* !!! ===============================================================================================================*/
/* !!! VARIABLES */
/* ===================================================================================================================*/

/* All GT-Pressura faces carry their own intrinsic weight (Bold, Medium, Light,
   etc.), so emphasis is expressed via font-family, not font-weight. Keep the
   document at a neutral baseline and let <b>, <strong>, headings inherit. */
body {
    font-weight: normal;
}

b, strong, h1, h2, h3, h4, h5, h6 {
    font-weight: inherit;
}

:root {
/* !!! ________Fonts
   Each token bakes in the `sans-serif` fallback so consumers can use
   `font-family: var(--textfont)` without repeating `, sans-serif`. */

    --headingfont: 'GT-Pressura-Standard-Bold', sans-serif;
    --textfont: 'GT-Pressura-Standard-Light', sans-serif;

/* !!! ________Control sizing
   One shared footprint for the app's interactive controls — dropdowns
   (.Select-control), text inputs (.input2 etc.), nav-card buttons,
   segmented controls, and single-line multiselects — so stacked
   controls always line up. Change the height/radius here, not in the
   per-control rules. --control-inner is the line box inside the 1px
   borders. */
    --control-height: 30px;
    --control-inner: calc(var(--control-height) - 2px);
    --control-radius: 0.5rem;
    /* Hover radius for every button: just past half the height of the
       tallest control (back-to-top is 40px), so the browser clamps it to
       a pill at whatever size the button happens to be. Keep this near
       the visual pill size — interpolating to 999px would finish the
       visible morph in the first few percent of the duration. */
    --pill-radius-max: 24px;
    --textfont_italic: 'GT-Pressura-Standard-Light-Italic', sans-serif;
    --tablefont: 'GT-Pressura-Standard-Regular', sans-serif;
    --tablefont_bold: 'GT-Pressura-Standard-Bold', sans-serif;
    --tablefont_mono: 'GT-Pressura-Mono-Regular', monospace;
    --tablefont_mono_bold: 'GT-Pressura-Mono-Bold', monospace;
    --tablefont_mono_light: 'GT-Pressura-Mono-Light', monospace;
    --buttonfont: 'GT-Pressura-Standard-Bold', sans-serif;
    --mediumfont: 'GT-Pressura-Standard-Medium', sans-serif;

/* !!! ________Type_Scale
   SINGLE em-based scale. All font-size declarations in this stylesheet use
   one of these tokens — no more hardcoded px/rem/em literals, no parallel
   rem scale. Because every token is em (parent-relative) and the root
   html { font-size: clamp(...) } is fluid, every text in the app scales
   smoothly with viewport width AND inherits its container's context.

   Naming: smaller number = larger size. Suffix letters (A, B, C) are
   intermediate stops — use them when the base step is too big a jump.

        Token            em      ~px*  Intended role
        ─────────────────────────────────────────────────────────────
        --font_em_1      2.5em   40    Display / hero
        --font_em_2      2em     32    H1, marquee heading
        --font_em_2A     1.75em  28    H2
        --font_em_2B     1.5em   24    H3, large section heading
        --font_em_2C     1.25em  20    H4, small section heading
        --font_em_3      1em     16    Body (default)
        --font_em_3A     0.875em 14    Body, reduced
        --font_em_4      0.8em   12.8  UI small (buttons, form labels)
        --font_em_4A     0.75em  12    Compact label, dense UI
        --font_em_5      0.65em  10.4  Caption, legend, meta
        --font_em_5A     0.6em   9.6   Small caption, table footnote
        --font_em_6      0.5em   8     Tiny / micro

        * Approximate resolved pixel size assuming parent is at body-size
          (~16px). Real values breathe with the html clamp(). */

    --font_em_1:  2.5em;
    --font_em_2:  2em;
    --font_em_2A: 1.75em;
    --font_em_2B: 1.5em;
    --font_em_2C: 1.25em;
    --font_em_3:  1em;
    --font_em_3A: 0.875em;
    --font_em_4:  0.8em;
    --font_em_4A: 0.75em;
    --font_em_5:  0.65em;
    --font_em_5A: 0.6em;
    --font_em_6:  0.5em;

    --sManual_leftMargin_1: 0;
    --sManual_leftMargin_2: 1.5rem;
    --sManual_leftMargin_3: calc(var(--sManual_leftMargin_2)*1.7);
    --sManual_leftMargin_4: calc(var(--sManual_leftMargin_3)*1.4);
    --sManual_leftMargin_5: calc(var(--sManual_leftMargin_4)*1.3);
    --sManual_leftMargin_6: calc(var(--sManual_leftMargin_5)*1.2);

    --light_transparent_blue: hsla(200, 50%, 20%, .1);
    --light_transparent_blue_lighter: hsla(200, 50%, 20%, .05);

    --light_transparent_gray: hsla(0, 0%, 50%, 0.1);

    --sManual_yellow_highlight: #fcffcb;
    /* --warning_color_dark and --warning_color_light have been removed.
       All warning / "latest-assignment" accents now share --monconred so
       the app has a single red token with matching tint/ink/line
       derivatives in the monconred family. */

    --sManual_border_thick: 2px;
    /* Alt palette: dotted green accent (was dotted purple) */
    --sManual_link_bottom_border: 2px dotted var(--pt-accent-light);
    --sManual_link_bottom_border_2: var(--sManual_border_thick) dotted var(--pt-accent-light);
    --sManual_link_bottom_border_3: var(--sManual_border_thick) dotted var(--pt-accent-dark);
    --sManual_link_bottom_border_4: var(--sManual_border_thick) dotted var(--orange);

    --sManual_link_bottom_border_highlight: var(--sManual_border_thick) solid var(--gray-900);

    --sManual_link_transition: var(--button-link-transition);

    /* Alt palette: flat UI, no drop shadows */
    --sManual_box_shadow: none;

    --sManual_new_text_highlight_color: #D35400;

    /* Alt palette: accent uses medium text tone */
    --sManual_accent_color: var(--pt-text-medium);

/* !!! ________Ops_Chart */

    --opsChart_PX_color: rgba(251, 251, 239, 1);
    --opsChart_PM_color: rgba(240, 248, 230, 1);
    --opsChart_SU_color: rgba(233, 229, 243, 1);
    --opsChart_ME_color: rgba(251, 244, 237, 1);
    --opsChart_PC_color: rgba(230, 242, 251, 1);

/* !!! ________Design_tokens (pt-*) — alt palette core */
    /* Light shell — #f3f3f3 until Sept 2026, then darkened so the white
       cards stand off the page more; settled an eighth of the way to
       the full 10% step (#dbdbdb) after three rounds of tuning. */
    --pt-body: #f0f0f0;
    --pt-body-medium: #e8e8e8;
    --pt-body-light: #ffffff;
    --pt-text: #1e2124;
    --pt-text-medium: #636363;
    --pt-accent-light: rgb(48, 48, 80);
    --pt-accent-light-05: rgba(43, 89, 69, 0.05);

    /* Dark block tokens — navbar strip + selective surfaces */
    --pt-body-dark: #1e2124;
    --pt-accent-dark: #4e8af7;

    --pt-border: var(--gray-800);
    --pt-border-soft: #e8e8e8;
    /* Height a make_table body cell occupies once a pill sits in it: the
       14px table line-height plus the pill's 1px border and 1px margin on
       each edge. Used as the row-height floor for every cell in a table
       that renders pills, so pill and plain rows measure the same. */
    --pt-pill-row-height: 18px;
    /* Shared multi-property transition used by every hover-able surface
       (cards, chips, pills, nav tiles). Always references the single
       --button-link-transition-duration token so the whole app animates
       at the same slow, smooth speed. Includes border-radius and
       transform so card hovers morph instead of snap. */
    --pt-transition:
        color var(--button-link-transition-duration) ease-in-out,
        background-color var(--button-link-transition-duration) ease-in-out,
        border-color var(--button-link-transition-duration) ease-in-out,
        border-radius var(--button-link-transition-duration) ease-in-out,
        box-shadow var(--button-link-transition-duration) ease-in-out,
        transform var(--button-link-transition-duration) ease-in-out,
        opacity var(--button-link-transition-duration) ease-in-out;

    /* ---------------------------------------------------------------------- */
    /* Navbar color controls — change these in ONE place (applies to regular  */
    /* AND landing variants; both rules consume these tokens below).          */
    /* ---------------------------------------------------------------------- */
    --pt-nav-bg: rgba(20, 20, 22, 0.08);
    /* --pt-nav-bg-hover: rgba(95, 95, 95, 0.55); */
    --pt-nav-bg-landing: rgba(24, 26, 27, 0.78);
    --pt-nav-bg-landing-hover: rgba(24, 26, 27, 0.83);

    /* Menu pills inside the navbar (text + button surfaces) */
    --pt-nav-pill-bg: #ffffff;
    --pt-nav-pill-bg-hover: #ececec;

/* !!! ________Colors */

    --monconred: #ed2037;
    /* Derived red tokens — keep usage scarce and intentional. Consume these
       (not raw --monconred) when you need a softened red for tints, hairlines,
       or focus rings. Using color-mix() ties every derivative to the single
       source of truth above — change --monconred and everything follows. */
    --monconred-ink:   color-mix(in srgb, var(--monconred) 85%, #1e2124);
    --monconred-tint:  color-mix(in srgb, var(--monconred) 8%,  #ffffff);
    --monconred-line:  color-mix(in srgb, var(--monconred) 60%, #ffffff);
    --monconred-focus: color-mix(in srgb, var(--monconred) 40%, transparent);
    --orange: #FF7153;
    --lightyellow: #fcffcb;
    --lightblue: #e6faff;
    --lightpurple: #f2eafe;

    /* Outbuild Styles */
    --mist: #d6ddd9;
    --bedrock: #c5cdc9;

    /* Gray ramp: dark grays for shadow/badge usage; surfaces read light */
    --gray-900: #1e2124;
    --gray-800: #3a3c3f;
    --gray-750: #4a4d51;
    --gray-700: #5c5f63;
    --gray-600: #6b6f73;
    --gray-500: #8a8d91;
    --gray-400: #b0b3b6;
    --gray-300: #d0d2d4;
    --gray-200: #e0e2e4;
    --gray-150: #eceeef;
    --gray-100: #f3f4f5;
    --gray-060: #f7f8f8;
    --gray-050: #fbfbfb;
    --gray-025: #ffffff;

/* The two chip fills the app's status pills use, matching Python's
   ``pillgray_dark`` / ``pillgray_light`` in utils/functions.py. Off the gray
   ramp above on purpose: neither value sits on it (--gray-600 is #6b6f73 and
   --gray-500 is #8a8d91), and a pill has to read the same here as it does in
   a make_table pill or a PDF export, which take their fills from Python. */
    --pillgray-dark: #77777A;
    --pillgray-light: #DDDDE0;

    /* Text colors (semantic) */
    --text_color_dark: var(--gray-025);
    --button_color_dark: var(--gray-750);
    --text_dark: var(--gray-800);

/* !!! ________Disabled / Inactive state tokens
   Unified colors for any card/element shown as disabled, inactive, superseded,
   or otherwise deemphasized. Edit ONCE here to change every disabled surface
   in the app (cards, pills, staff/project chart cards, image overlays, etc.). */
    --pt-disabled-bg:      var(--gray-200);   /* surface fill          */
    --pt-disabled-border:  var(--gray-400);   /* 1px solid/dashed line */
    --pt-disabled-text:    var(--gray-500);   /* all text + headings   */
    --pt-disabled-overlay: rgba(200, 200, 200, 0.65); /* image overlay */

/* !!! ________Borders_and_Lines */

    --lw-1: solid 1px var(--pt-border);

/* !!! ________Layout_and_breakpoints */
    --content_max_width: 1700px;

    --nav-width: 200px;
    --gap: 24px;
    --top-offset: 4em;

    /* Center column: clamp means side margins absorb all shrinkage first (until they hit 0),
       then the center itself compresses. Both .main-container and .PT_navbar_main read the
       same resolved value, so navbar and page content always align at every viewport width. */
    --main-col-min: 1000px;
    --main-col: clamp(var(--main-col-min), 80vw, var(--content_max_width));

/* !!! ________Transitions */

    /* Shared easing curves */
    --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-pill: cubic-bezier(0.45, 0.05, 0.2, 1);

    /* Unified button/link transition — every button and link in the app should
       reference this token (or one of the derived tokens below) so their hover
       animations share a single slow speed that's controlled in one place. */
    --button-link-transition-duration: 1.2s;
    --button-link-transition: all var(--button-link-transition-duration) var(--ease-standard);

    /* Slow "sharp -> rounded" pill morph used across .button1, .PT_navbar pills, etc.
       Duration is driven by the shared button/link token so it matches every
       other button/link animation. */
    --pill-morph-transition:
        border-radius var(--button-link-transition-duration) var(--ease-pill),
        background-color var(--button-link-transition-duration) var(--ease-pill),
        border-color var(--button-link-transition-duration) var(--ease-pill),
        color var(--button-link-transition-duration) ease;

    /* Generic soft hover shadow used on buttons, links, tiles, pills */
    --shadow-hover-soft: 0 2px 10px rgba(0, 0, 0, 0.1);

    /* sManual micro-interactions share the same duration so link/card hovers
       match every other button/link in the app. */
    --sManual_transition_duration: var(--button-link-transition-duration);

/* !!! ________Patterns */

    --safety_hatch: repeating-linear-gradient(
        -45deg,
        var(--pt-body-light) 0 14px,
        rgba(43, 89, 69, 0.06) 14px 28px
    );

}

/* !!! ===============================================================================================================*/
/* !!! SCROLLBAR  */
/* ===================================================================================================================*/

::-webkit-scrollbar {
    background-color: var(--pt-body-medium);
    border-radius: 5px;
    width: .5em;
    height: 7px;
}

::-webkit-scrollbar-track {
    border-radius: 5px;
    background-color: var(--pt-body-light);
}

::-webkit-scrollbar-thumb {
    background-color: var(--gray-400);
    border-radius: 5px;
}

.div-login {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* !!! ===============================================================================================================*/
/* !!! LOGIN_STUFF  */
/* ===================================================================================================================*/

.login-header {
    font-family: var(--headingfont);
    font-size: var(--font_em_2);
    color: var(--gray-025) !important;
    margin-bottom: 0.5rem;
    text-align: center;
    letter-spacing: 0.02em;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

.input2.login-input {
    border: 1px solid rgba(255, 255, 255, 0.35) !important;
    color: var(--gray-025) !important;
    background-color: rgba(255, 255, 255, 0.08) !important;
    height: 32px;
    padding: 4px 10px;
    border-radius: 8px;
}

.input2.login-input::placeholder {
    color: rgba(255, 255, 255, 0.6);
    opacity: 1;
}

.input2.login-input:focus {
    border-color: rgba(255, 255, 255, 0.6) !important;
    background-color: rgba(255, 255, 255, 0.14) !important;
    box-shadow: none;
    outline: none;
}

.button1.login-button {
    border-color: rgba(255, 255, 255, 0.45);
    background-color: rgba(255, 255, 255, 0.08);
    color: var(--gray-025) !important;
    transition: var(--button-link-transition) !important;
    width: 50%;

}

.button1.login-button.credential {
    border-color: rgba(255, 255, 255, 0.3);
    background-color: transparent;
    color: rgba(255, 255, 255, 0.75) !important;

}

.button1.login-button:hover {
    color: var(--gray-025) !important;
    border-color: rgba(255, 255, 255, 0.75);
    background-color: rgba(255, 255, 255, 0.16);
}

/*   */
.forbidden_landing{
    text-decoration: underline !important;
}

#users-table tbody tr td,
#roles-table tbody tr td {
    padding: 6px 5px !important;
}

#users-table thead tr th,
#roles-table thead tr th {
    padding: 6px 6px !important;
}

#users-table thead tr th span,
#roles-table thead tr th span {
    float: left !important;
}

#users-table tbody tr td:nth-child(6) {
    display: flex;
    justify-content: left;
}

/* !!! ===============================================================================================================*/
/* !!! BUTTONS_AND_LINKS  */
/* ===================================================================================================================*/

/* !!! ________Pill-morph utility
   Opt-in class that packages the app-wide "sharp at rest → round on hover,
   with a soft hover shadow and slow eased transition" pattern. Components
   that need this look can adopt the class and override `--pill-radius-rest`
   / `--pill-radius-hover` inline or in a more specific rule. Existing
   button / link rules intentionally keep their own hover radii, so this is
   not applied retroactively. */
.pill-morph {
    border-radius: var(--pill-radius-rest, 2px);
    transition: var(--pill-morph-transition);
}

.pill-morph:hover {
    border-radius: var(--pill-radius-hover, 16px);
    box-shadow: var(--shadow-hover-soft);
    cursor: pointer;
}

/* !!! ________Hover pill-morph, every button
   One answer to a hover for every button in the app: the corners round
   out to a full pill. --pill-radius-max is just past half the tallest
   button, because CSS clamps a border-radius to half the shorter side —
   so the morph sizes itself to the control and no button needs a number
   of its own. A 13px row button lands at ~6px, a 30px nav-card button
   at 15px, a 36px card button at 18px. The value stays small so the
   2px → pill interpolation can use the full transition duration.

   !important, and one flat list, because the resting radius gets set in
   a lot of places — the --control-radius footprint on nav-card buttons,
   the red title band's own treatment, per-page overrides — and each of
   those out-specifies the per-class :hover rules further down this
   file. That's how most of the app's buttons had quietly stopped
   morphing while a few (the Master Scope row buttons, the navbar) kept
   doing it. Anything added here inherits the behavior for good.

   Buttons whose own rules already animate border-radius (via
   --pill-morph-transition, --pt-transition or --button-link-transition)
   need nothing else; the two Buyout Tracker buttons declared no
   transition at all, so they get one below, and the back-to-top square
   has border-radius added to its own transition list.

   Left out on purpose: .landing_card and the other card tiles (not
   buttons, and they have their own gentler radius), and the Buyout
   Tracker's .bo-sub-pill-btn, which is already a pill at rest. */
:is(
    .button1,
    .button4,
    .button-download,
    .button-menu.pt-btn,
    .export,
    .show-hide,
    .tablebutton,
    .doc_link,
    .bo-trade-name-btn,
    .bo-timeline-sub-btn,
    .mantine-SegmentedControl-label,
    .ms-scope-sel-label,
    .back-to-top-btn
):hover {
    border-radius: var(--pill-radius-max) !important;
}

.bo-trade-name-btn,
.bo-timeline-sub-btn {
    transition: var(--pill-morph-transition);
}

/* !!! ________Button1 */
.button1, .export, .show-hide {
    background-color: transparent;
    color: var(--text_dark);
    padding: 5px 10px;
    border-radius: 2px;
    border: 1px solid var(--pt-text);
    text-align: center;
    text-decoration: none;
    display: block;
    font-size: var(--font_em_5A);
    font-family: var(--buttonfont);
    transition: var(--pill-morph-transition);
    margin-top: 6px;
    margin-bottom: 6px;
    margin-right: 4px;
}

.button1:hover, .export:hover, .show-hide:hover {
    cursor: pointer;
    border-radius: 16px;
    background-color: var(--pt-accent-light-05);
    border-color: var(--pt-accent-light);
    color: var(--text_dark);
}

/* Buttons inside nav cards share the app's control footprint (see the
   --control-* tokens) with dropdowns, text inputs, and segmented
   controls, so stacked controls in the settings column line up. The
   resting radius matches the other controls too; the hover pill-morph
   to 16px still applies. */
.card.nav .button1,
.card.nav .export,
.card.nav .show-hide {
    box-sizing: border-box;
    height: var(--control-height);
    padding-top: 0;
    padding-bottom: 0;
    line-height: var(--control-inner);
    border-radius: var(--control-radius);
}

/* !!! ________Button4 */
.button4 {
    position: absolute;
    top: 0;
    right: 0;
    padding: 5px 10px;
    background: var(--button_color_dark) !important;
    text-align: center;
    height: 36px;
    color: var(--text_color_dark) !important;
    border-radius: 2px;
    margin: 12px;
    font-family: var(--buttonfont);
    transition: var(--pt-transition);
    border: none !important;
}

.button4:hover {
    border-radius: 18px;
    cursor: pointer;
    filter: brightness(1.05);
}

.card nav.button4 {
    font-size: var(--font_em_3);
    position: unset !important;
}

/* !!! ________Button_download */
.button-download {
    background-color: var(--button_color_dark) !important;
    color: var(--text_color_dark) !important;
    padding: 6px 12px;
    border-radius: 2px;
    text-align: center;
    text-decoration: none;
    display: block;
    font-size: var(--font_em_4A);
    font-family: var(--buttonfont);
    transition: var(--button-link-transition);
    margin-top: 6px;
    margin-bottom: 6px;
    margin-right: 0;
    white-space: nowrap;
    border: 0 solid var(--pt-border);
    width: auto;
    min-width: 120px;
}

.button-download:hover {
    cursor: pointer;
    border-radius: 18px;
    border: 0 solid var(--pt-border);
}

/* !!! ________Button_menu */
.button-menu.pt-btn {
    font-size: var(--font_em_5);
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 6rem;
    width: auto;
    padding: 4px 8px;
    border: 1px solid var(--pt-border);
    border-radius: 2px;
    background-color: transparent;
    color: var(--text_dark);
    text-decoration: none;
    font-family: var(--mediumfont);
    transition: var(--button-link-transition);
    cursor: pointer;
    margin: 6px 12px 6px 0;
    box-sizing: border-box;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    will-change: border-radius, background-color;
}

.PT_navbar.PT_navbar_landing .PT_navbar_nav_items {
    display: none;
}

.section_nav_container .button-menu.pt-btn {
    width: 100%;
    /*border: none;*/
    margin-bottom: 0.5em;
}

#sManual_nav_buttons_container .button-menu {
    margin: 0;
    margin-bottom: 0.25em;
    padding: 0.2em;
}

#sManual_nav_buttons_container .button-menu.disabled {
    color: var(--gray-300);
    border-color: var(--gray-300);
    animation: none;
    transition: none;
    pointer-events: none;
    cursor: not-allowed;
}

.button-menu.pt-btn:hover {
    border-radius: 18px;
}

/* Ensure all child elements use the EXACT same transition timing */
.pt-btn__label,
.pt-btn__circle {
    transition: var(--button-link-transition);
    will-change: transform, opacity;
}

.pt-btn__label {
    position: relative;
    z-index: 0;
    /* No transition here - it's defined above */
}

.button-menu.pt-btn:hover .pt-btn__label {
    transform: translateX(-14px);
    /* No transition here - it inherits from the class above */
}

.pt-btn__circle {
    position: absolute;
    top: 50%;
    right: 6px;
    height: 24px;
    width: 24px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transform: translateY(-50%) scale(0.5) translateX(12px);
    /* No transition here - it's defined above */
    font-size: var(--font_em_4A);
    color: var(--text_dark);
    background-color: transparent;
}

.button-menu.pt-btn:hover .pt-btn__circle {
    opacity: 1;
    background-color: transparent; /* Or any color you want */
    transform: translateY(-50%) scale(1) translateX(0);
    /* No transition here - it inherits from the class above */
}

.holder {
    background: var(--pt-body-medium) !important;
    width: 100%;
}

.pt-btn__icon {
    width: 16px;
    height: 16px;
    filter: invert(0%); /* Adjust this for different colors */
}

/* Dark variant of the animated button */
.button-menu.pt-btn.dark {
    background-color: var(--button_color_dark);
    color: var(--pt-body-medium) !important;
    margin-right: 0 !important;
}

/* !!! ________Tablebutton */

.tablebutton {
    background: var(--pt-text-medium) !important;
    height: 18px !important;
    line-height: 18px !important;
    color: var(--text_dark) !important;
    padding: 0 8px !important;
    border-radius: 2px !important;
    border: 1px solid var(--pt-border) !important;
    text-align: center !important;
    text-decoration: none !important;
    display: block !important;
    font-size: var(--font_em_5A) !important;
    font-Family: var(--buttonfont) !important;
    transition-duration: var(--button-link-transition-duration) !important;
    margin-top: 2px !important;
    margin-bottom: 2px !important;
}

.tablebutton:hover {
    /*background-color: transparent !important;*/
    /*background: none !important;*/
    /*color: var(--text_color) !important;*/
    border-radius: 12px !important;
    cursor: pointer !important;
}

/* !!! ===============================================================================================================*/
/* !!! LANDING_PAGE_STUFF  */
/* ===================================================================================================================*/

.landing_page_container {
    font-size: var(--font_em_3);
    width: 100%;
    position: relative;
    color: var(--text_dark);
    /*padding-right: 2em;*/
    padding-left: 6px;

}
.landing_column_title {
    font-family: var(--headingfont);
    font-size: var(--font_em_4A);
    letter-spacing: -0.02em;
    text-transform: uppercase;
    color: var(--text_dark) !important;
    margin-top: 0;
    margin-bottom: 0.75em;
}

.login_container,
.login_card {
    border: none !important;
    border-radius: 0;
    box-shadow: none !important;
    display: flex;
    align-items: center;
}

.login_container {
    background-color: transparent !important;
    justify-content: center;
    height: fit-content;
    margin-top: 10em;
}

.login_card {
    flex-direction: column;
    background-color: rgba(255, 255, 255, 0.18) !important;
    border: 1px solid rgba(255, 255, 255, 0.28) !important;
    border-radius: 14px;
    box-shadow:
        0 8px 32px rgba(0, 0, 0, 0.18),
        inset 0 1px 0 rgba(255, 255, 255, 0.35) !important;
    backdrop-filter: blur(18px) saturate(1.2);
    -webkit-backdrop-filter: blur(18px) saturate(1.2);
    margin-bottom: 0.5em;
    transition: all var(--button-link-transition-duration) var(--ease-standard);
    padding: 1.5em 1.75em;
    max-width: 400px;
    min-width: 400px;
    margin-left: auto;
    margin-right: auto;
}

/* Non-landing home grids: flat gray tiles */
.landing_card {
    display: flex;
    flex-direction: column;
    gap: 0.25em;
    padding: 0.6em 0.7em 0.7em;
    min-height: 3.5em;
    height: auto;
    border: none !important;
    color: var(--text_dark);
    font-family: var(--textfont);
    background-color: var(--pt-body-medium) !important;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(10px);
    border-radius: 0;
    box-shadow: none !important;
    margin-bottom: 0.45em;
    transition: var(--button-link-transition);
    overflow-wrap: break-word;
    text-decoration: none;
    cursor: pointer;
}

.landing_card:hover {
    background-color: var(--gray-200) !important;
    border: none !important;
    border-radius: 14px;
    color: var(--text_dark);
}

/* Disabled landing tile (user lacks permission for the page).
   Tile is still rendered so the user sees the option, but it is inert and
   visually dimmed. The :hover rule is duplicated to defeat the active-state
   restyle above. */
.landing_card.disabled,
.landing_card.disabled:hover {
    cursor: not-allowed;
    opacity: 0.45;
    pointer-events: none;
    background-color: var(--pt-body-medium) !important;
    border-radius: 0;
    color: var(--text_dark);
}

.landing_card.disabled .landing_card_title,
.landing_card.disabled .landing_card_text {
    color: var(--text_dark) !important;
    text-decoration: line-through;
}

.landing_card_title {
    font-size: var(--font_em_4A);
    line-height: 1.2;
    font-family: var(--headingfont);
    color: var(--text_dark) !important;
    letter-spacing: -0.02em;
    margin: 0;
    /* Single-line truncation — never wraps */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.landing_card_text {
    font-size: var(--font_em_4A);
    line-height: 1.45;
    font-family: var(--tablefont);
    color: var(--text_dark) !important;
    margin: 0;
    overflow-wrap: break-word;
}

.landing_tile_badge {
    color: var(--text_dark);
    padding: 0.3em 0.8em;
    border: 1px solid var(--gray-900);
    border-radius: 12px;  /* Increased from 9px for more roundness */
    font-family: var(--mediumfont);

    font-size: var(--font_em_6);
    text-align: center;  /* Centers text */
    display: inline-block;  /* Makes it behave like a badge */
    box-sizing: border-box;  /* Ensures padding is included in size */
    cursor: pointer;
    vertical-align: middle;
    background-color: var(--sManual_yellow_highlight);
}

/* !!! ===============================================================================================================*/
/* !!! LANDING_TABS  */
/* ===================================================================================================================*/
/* Tabbed landing: one category active at a time, dense responsive grid below.
   Tabs sit over the dark hero photo, so the inactive/active color contrast is
   tuned for that surface (light text on dark image). The single red hairline
   under the active tab uses --monconred so it threads with the rest of the
   app's filet-rouge accent (h2::before, etc.). */

.landing_tabs_strip {
    display: flex;
    flex-wrap: wrap;
    gap: 0.15em;
    align-items: flex-end;
    margin-bottom: 1.25em;
    padding-bottom: 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.landing_tab {
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 0.5em 0.9em 0.55em;
    margin: 0;
    color: rgba(230, 230, 230, 0.55);
    font-family: var(--headingfont);
    font-size: var(--font_em_4A);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    cursor: pointer;
    display: inline-flex;
    align-items: baseline;
    gap: 0.45em;
    line-height: 1.1;
    transition:
        color var(--button-link-transition-duration) ease-in-out,
        border-color var(--button-link-transition-duration) ease-in-out,
        background-color var(--button-link-transition-duration) ease-in-out;
    margin-bottom: -1px; /* overlap parent border so active hairline sits on it */
}

.landing_tab:hover {
    color: rgba(255, 255, 255, 0.95);
    background: rgba(255, 255, 255, 0.06);
}

.landing_tab.active {
    color: var(--text_color_dark);
    border-bottom-color: var(--monconred);
}

.landing_tab_count {
    font-family: var(--tablefont_mono);
    font-size: var(--font_em_5A);
    color: rgba(230, 230, 230, 0.55);
    letter-spacing: 0;
}

.landing_tab.active .landing_tab_count {
    color: var(--monconred);
}

.landing_tab:hover .landing_tab_count {
    color: rgba(255, 255, 255, 0.85);
}

.landing_grids_container {
    width: 100%;
}

/* Dense responsive grid: cells morph from 5 cols on wide screens down to 2 on
   narrow ones. minmax(180px, 1fr) keeps tiles legible without tiny stragglers. */
.landing_grid {
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 8px;
    width: 100%;
}

/* !!! ===============================================================================================================*/
/* !!! TEXT_ELEMENTS  */
/* ===================================================================================================================*/

/* !!! ________H1_THRU_H6 */

h1, h2, h3, h4, h5, h6 {
    text-align: left;
    margin-top: 0.75em;
    margin-bottom: 0;
    font-Family: var(--headingfont);
    color: var(--text_dark);
}

h1 {
    font-size: var(--font_em_1);
    background-clip: text;
    color: var(--text_dark);
    margin-top: 0.5em;
}

#v3_manual_div h1 {
    margin-top: 0;
}

#manual_div_legacy h1 {
    margin-top: 0;
}

.card.title h1 {
    margin-top: 0.25em !important;
    margin-bottom: 0.25em !important;
    letter-spacing: -0.02em;
    color: var(--text_dark) !important;
}

h2 {
    font-size: var(--font_em_2);
}

/* Red hairline above page-level H2s — the "filet rouge" that threads brand
   through every section without adding chrome. Scoped to page content so
   navbar/drawer/card H2s stay clean (cards already have their own heading
   treatments, and stacking rails inside warning/disabled cards would muddle
   those semantic states). */
#page-content h2::before,
.main-container h2::before {
    content: "";
    display: block;
    width: 32px;
    height: 2px;
    background-color: var(--monconred);
    border-radius: 1px;
    margin-bottom: 0.4em;
}

.card h2::before,
.card-dashed h2::before,
.card.warning h2::before,
.card.disabled h2::before,
.card.title h2::before,
.card.nav h2::before,
.PT_navbar h2::before,
.modal h2::before,
.mantine-Drawer h2::before,
.section-nav-fab-root h2::before,
.fixed-section-nav h2::before {
    content: none;
}

/* Master Scope section headings opt out of the filet rouge. The ID-
   prefixed selectors match the specificity of the page-level rule
   above, which otherwise beats the class-only card exclusions. */
#page-content h2.ms-section-heading::before,
.main-container h2.ms-section-heading::before {
    content: none;
}

h4 {
    font-size: var(--font_em_3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-bottom: 0.85em;
    color: var(--text_dark);
}

.card.warning h4 {
    color: var(--monconred);
}

h5 {
    font-size: var(--font_em_4);
    margin-bottom: 0.4em;
    color: var(--text_dark);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sManual_doc_links_container h5 {
    margin-bottom: 0;
    margin-top: 0.25em;
}

h6 {
    font-size: var(--font_em_5);
    margin-bottom: 0;
}

/* !!! ________P */

P {
    font-size: var(--font_em_5);
    font-family: var(--textfont);
    word-break: normal;
    margin: 0;
    margin-bottom: 0.2em;
    padding: 0;
}

P.mono {
    font-family: var(--tablefont_mono);
    font-size: var(--font_em_5);
}

/* !!! ________span_1_thru_span_2 */

.span_1 {
    font-size: var(--font_em_4A);
    font-family: var(--textfont);
    color: var(--text_dark);
    margin: 1px 0 0 0;
    padding: 2px 0 1px;
    display: inline-block;
}

.card.warning .span_1 {
    color: var(--monconred);
}

.span_2 {
    font-size: var(--font_em_4A);
    font-family: var(--headingfont);
    color: var(--text_dark);
    margin: 1px 0 0 0;
    padding: 2px 0 1px;
    display: inline-block;
}

.card.warning .span_2 {
    color: var(--monconred);
}

.span_3 {
    display: block;
}

/* !!! ________Info_grid */

.info_grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
}

.info_row {
    display: grid;
    grid-template-columns: 50% auto;
    align-items: center;
    margin-bottom: 0.15em;
}

.grid_label {
    font-family: var(--headingfont);
    font-size: var(--font_em_5);
    color: var(--text_dark) !important;
    letter-spacing: 0.04em;
    text-align: left;
    padding-right: 1em;
    display: inline-block;  /* Need this for width to work on span */
    max-width: 150px;       /* Adjust to your preference */
    overflow: hidden;
    white-space: nowrap;    /* Prevents text wrapping */
    text-overflow: ellipsis; /* Optional: adds ... when text is cut */
}

.grid_value {
    font-family: var(--textfont);
    font-size: var(--font_em_5);
    color: var(--text_dark) !important;
    text-align: left;
}

/* !!! ________list_grid */

/* Sole owner of this section's type, so the values inside are plain grid
   items — nesting another em-sized class (.span_1) inside multiplied the two
   sizes together. Row gap matches .info_row's margin-bottom so the experience
   lists keep the same vertical rhythm as the info grids above them. */
.list_grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.15em 0;
    font-family: var(--textfont);
    font-size: var(--font_em_5);
    overflow: hidden;
    white-space: nowrap;    /* Prevents text wrapping */
    text-overflow: ellipsis; /* Optional: adds ... when text is cut */
    color: var(--text_dark);
    padding-right: 0.5em;

}

/* !!! ________Misc */

.nav_menu_title {
    /* color: var(--text_dark); */
    color: var(--monconred);
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    margin-bottom: 0.1em;
}

.modal-title {
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    color: var(--text_dark);
}

B {
    font-family: var(--headingfont);
}

.list-group-item {
    font-family: var(--textfont);
    color: var(--text_dark) !important;
    background-color: transparent !important;
    border-color: var(--pt-border-soft) !important;
    font-size: var(--font_em_5A);
    word-break: normal;
}

/* !!! ________Revision_Date */

.revision_date {
    color: var(--gray-300);
    padding: 0;
    font-family: var(--textfont);
    font-size: var(--font_em_6);
    cursor: pointer;
    margin-bottom: 1em;
}
.revision_date:hover {
    cursor: default;
}

.sManual_doc_links_container .revision_date {
    margin-bottom: 0;
}

/* !!! ===============================================================================================================*/
/* !!! TOOLTIP  */
/* ===================================================================================================================*/

.tooltip1 {
    background-color: var(--gray-750);
    color: var(--text_color_dark);
    font-family: var(--tablefont);

    font-size: var(--font_em_4);
    padding: 1em;
    border-radius: 5px;
    z-index: 9999;
}

/* !!! ===============================================================================================================*/
/* !!! CARDS  */
/* ===================================================================================================================*/

.card {
    font-size: var(--font_em_3);
    position: relative;
    text-align: left;
    min-width: 100px;
    overflow-wrap: break-word;
    overflow: hidden;
    word-wrap: break-word;
    word-break: break-all;
    white-space: pre-wrap;
    margin-bottom: 1em;
    padding: 0 0.8em 1.2em;
    background-color: var(--pt-body);
    border-radius: 0.7em;
    /* Alt palette: flat UI, no drop shadows */
    box-shadow: none;
    color: var(--text_dark);
    display: flow-root;
}

.card.level2 {
    background-color: var(--gray-060);
    box-shadow: none;

}

/* Nav cards: flat light-gray fill */
.card.nav,
.card.level2.nav {
    font-size: var(--font_em_3A);
    margin-bottom: 1em;
    background-color: var(--pt-body-light) !important;
    border: none !important;
    border-radius: 8px !important;
    box-shadow: none !important;
}

/* Regular cards (non-nav, non-warning): match nav card fill, no border */
.card:not(.nav):not(.warning),
.card.level2:not(.nav):not(.warning) {
    background-color: var(--pt-body-light) !important;
    border: none !important;
    border-radius: 8px !important;
    box-shadow: none !important;
}

.card.warning {
    font-size: var(--font_em_3A);
    margin-bottom: 1em;
}

/* Dashed cards: keep dashed cue, but colors come from the unified
   disabled-state tokens so these always match .card.disabled and
   the .NOTACTIVE ops-chart surfaces. */
.card-dashed {
    background-color: var(--pt-disabled-bg) !important;
    border: 1px dashed var(--pt-disabled-border) !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    color: var(--pt-disabled-text) !important;
}

.card-dashed h4,
.card-dashed .grid_label,
.card-dashed .grid_value {
    color: var(--pt-disabled-text) !important;
}

/* !!! ===============================================================================================================*/
/* !!! DOC_LINKS  */
/* ===================================================================================================================*/

.doc_link {
    font-size: var(--font_em_4A);
    font-family: var(--mediumfont);
    display: inline-flex;
    text-align: left;
    justify-content: left;
    height: 10em;
    width: 8em;
    padding: 0.5em;
    margin: 0.5em;
    background-color: var(--gray-050);
    border: 1px solid var(--pt-border);
    border-radius: 0.5em;
    text-decoration: none;
    transition-duration: var(--sManual_transition_duration) !important;
    overflow: hidden;
    text-overflow: ellipsis;
    word-break: normal;
    cursor: default;
}

.doc_link:visited {
    text-decoration: none !important;
    border-radius: 18px;
    cursor: pointer;
}

.doc_link:hover {
    border-radius: 16px !important;
    cursor: pointer !important;
    background-color: var(--gray-050);
    box-shadow: var(--shadow-hover-soft);
    transition-duration: var(--sManual_transition_duration) !important;
}

a.doc_link {
    text-decoration: none !important;
}

.doc_link_container {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 10px;
}

/* SOP page only (scoped to .card.sop so the Site Response doc tiles are
   untouched): center the attachment tile on the line and let its
   filename wrap + shrink a touch instead of clipping with an ellipsis. */
.card.sop .doc_links_container {
    display: flex;
    justify-content: center;
    margin-left: 0;
}

.card.sop .doc_link {
    font-size: var(--font_em_5);
    text-align: center;
    justify-content: center;
    align-items: center;
    white-space: normal;
    word-break: break-word;
    overflow-wrap: anywhere;
    text-overflow: clip;
}

/* !!! ===============================================================================================================*/
/* !!! SAFETY_MANUAL  */
/* ===================================================================================================================*/

/* Styling for TOC */
.toc-children {
    padding-left: 20px;
    transition: all var(--button-link-transition-duration) ease;
}

/* Chevron styling */
.toc-chevron {
    display: inline-block;
    width: 16px;
    text-align: center;
    transition: transform var(--button-link-transition-duration) ease;
}

.fa-caret-down {
    transform: rotate(90deg);
}

/*-----------------Cards-----------------*/
.card.sManual {
    padding-top: 1em;
    padding-bottom: 1.5em;
    color: var(--text_dark) !important;
}

.card.sManual h4 {
    font-size: var(--font_em_3);
    margin-top: 0;
    margin-bottom: 0;
}

.card.sManual.toc {
    transition: all var(--button-link-transition-duration) ease !important;
}

/*Common styles for all TOC links */
.tocLink {
    text-decoration: none !important;
    cursor: pointer;
    color: var(--text_dark) !important;
    transition: var(--button-link-transition);
    font-size: var(--font_em_5A);
}

/* Prevents color changes for visited links */
.tocLink:visited {
    text-decoration: none !important;
    color: var(--text_dark) !important;
}

/*-------------ToolTip---------------*/

.sManual_tooltip {
    font-family: var(--textfont);

    margin: 1rem;
    font-size: var(--font_em_4A);
    padding: 0.5rem;
}

/* Target the inner content where your text actually lives */
.sManual_tooltip .tooltip-inner {
    background-color: var(--gray-025) !important;
    color: var(--text_dark) !important;
    backdrop-filter: blur(10px);
    border: 1px solid var(--pt-border);

    /* Add these to fix the sizing issue */
    max-width: 300px !important;
    width: max-content !important;
    white-space: normal !important;
    word-wrap: break-word !important;
    text-align: left !important;

    /* Ensure proper padding */
    padding: 8px 12px !important;
    border-radius: 6px !important;
    box-shadow: var(--sManual_box_shadow);
    margin-left: 50%;

}

/* !!! ________Badges */

.sManual_badges_container {
    display: inline-block;
}

.sManual_badge {
    font-size: var(--font_em_5A) !important;
    padding: 1px 5px !important;
    border-radius: 10px !important;
    color: var(--text_dark) !important;
    display: inline-block !important;
    background-color: var(--gray-050);
    text-align: center !important;
    white-space: nowrap !important;
    vertical-align: middle !important;
    margin-left: 3px !important;
    margin-bottom: 0 !important;
    border: 0.5px solid var(--gray-500) !important;
    font-family: var(--tablefont) !important;
}

.sManual_badge.source {
    background-color: var(--sManual_yellow_highlight);
}
.sManual_badge.source.Old_Manual {
    background-color: var(--mist);
}

.sManual.highlight {
    background-color: var(--pt-accent-light);
}

.highlight {
    background-color: var(--pt-accent-light);
    font-family: var(--headingfont);
}

.sManual_modal_text {
    font-size: var(--font_em_3);
    font-family: var(--textfont);

}

.sManual_flex_row {
    display: flex;
    align-items: flex-start;
    width: 100%;
}

/* !!! ________Numbers */

.sManual_number {
    font-family: var(--textfont);
    color: var(--gray-400);
    letter-spacing: -0.10em;
}
.sManual_number.type1 {
    color: var(--text_dark);
}
.sManual_number.type2 {
    color: var(--text_dark);
}
.sManual_number.type3 {
    color: var(--text_dark);
}
.formatted-numerical-code {
    white-space: nowrap;
    font-family: var(--textfont);
}

/* Number parts of the code */
.code-number-part.type1, .code-number-part.type2, .code-number-part.type3 {
    font-family: var(--tablefont_mono_bold) !important;
    color: var(--text_dark);
}
.code-number-part.type4, .code-number-part.type5, .code-number-part.type6 {
    font-family: var(--tablefont_mono_light) !important;
    color: var(--gray-300);
}

.sManual_toc_num.type1 {
    font-family: var(--tablefont_mono_bold);
}

.sManual_toc_num.type2 {
    font-family: var(--tablefont_mono) !important;
}

/* Periods in the code */
.code-period {
    margin: 0 -0.05em;
    font-family: var(--textfont);
    color: var(--gray-400);
}

/* !!! ________Special_text */

.definition_highlight {
    color: var(--text_dark);
    font-family: var(--mediumfont);
    border-bottom: var(--sManual_link_bottom_border_2);
}

.legend_definition {
    border-bottom: var(--sManual_link_bottom_border_2);
}

.topic_highlight {
    font-family: var(--mediumfont);
}

.direct_quote_highlight {
    font-family: var(--textfont_italic);
}

/*--------------Legend----------------------*/
.legend_content {
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
    margin-bottom: 1rem;
}

/* !!! ________Internal_Links*/

.sManual_uuid_link {
    background-color: transparent;
    display: inline-block;
    transition: var(--button-link-transition) !important;
    margin-left: 5px;
    font-family: var(--textfont);
    text-decoration: none;
    border-bottom: var(--sManual_link_bottom_border_3);
    height: auto !important;
    padding-bottom: 0;
    line-height: 1.0 !important;
}

.legend_uuid_link {
    border-bottom: var(--sManual_link_bottom_border_3);
}

.sManual_uuid_link:hover {
    cursor: pointer;
    background-color: var(--gray-100);
    transition: var(--sManual_link_transition);
    border-bottom: var(--sManual_link_bottom_border_highlight);
}

/* !!! ________Rows */

.sManual_content_row {
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
    padding-right: 3px;
}

.sManual_content_row.not_in_scopes {
    background-color: var(--sManual_yellow_highlight) !important;
}

.sManual_content_row.bulletpoint {
    margin-top: 0 !important;
}
.sManual_content_row.type1 {
    font-family: var(--headingfont);
    font-size: var(--font_em_2);
}

.sManual_content_row.type2 {
    margin-left: var(--sManual_leftMargin_2);
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    margin-top: 1.2rem;
    border-bottom: 1px solid var(--pt-border);
}

.sManual_content_row.type3 {
    margin-left: var(--sManual_leftMargin_3);
    font-family: var(--headingfont);
    font-size: var(--font_em_4);
    margin-top: 0.7rem;
}

.sManual_content_row.type4 {
    margin-left: var(--sManual_leftMargin_4);
    font-size: var(--font_em_4);
    margin-top: 0.45rem;
}

.sManual_content_row.type5 {
    margin-left: var(--sManual_leftMargin_5);
    font-size: var(--font_em_4);
    margin-top: 0.45rem;
}

.sManual_content_row.type6 {
    margin-left: var(--sManual_leftMargin_6);
    font-size: var(--font_em_4);
    margin-top: 0.45rem;
}
.sManual_content_row.type2.summary_card_modifier {
    margin-left: var(--sManual_leftMargin_1);
}
.sManual_content_row.type3.summary_card_modifier {
    margin-left: var(--sManual_leftMargin_1);
}
.sManual_content_row.type4.summary_card_modifier {
    margin-left: var(--sManual_leftMargin_2);
}
.sManual_content_row.type5.summary_card_modifier {
    margin-left: var(--sManual_leftMargin_3);
}
.sManual_content_row.type6.summary_card_modifier {
    margin-left: var(--sManual_leftMargin_4);
}

.sManual_text_line, .siteRespo_text_line {
    display: grid;
    grid-template-columns: auto 1fr; /* First column auto-sized, second takes remaining space */
    gap: 2px;
}

.sManual_row_content_wrapper {
    hyphens: auto;
    word-break: normal;
}

.sManual_content {
    line-height: 1.0rem !important;
}

.sManual_error {
    color: var(--monconred) !important;
}

.sManual_internal_note {
    color: var(--monconred);
    margin-left: 6.0rem;
    font-family: var(--tablefont);
    border-left: 6px solid var(--monconred);
    padding-left: 0.5rem;
    margin-top: 0.25rem;
}

.type1.InternalNote, .type2.InternalNote, .type3.InternalNote, .type4.InternalNote, .type5.InternalNote {
    margin-top: 3px !important;
}

.GRID {
    display: grid;
    column-gap: 4px;
    row-gap: 2px;
    align-items: start;
}

.GRID.sManual_inspection {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}
.GRID.sManual_permit {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}
.GRID.doclinks_1 {
    grid-template-columns: repeat(1, minmax(0, 1fr));
    row-gap: 4px;
}
.GRID.doclinks_2 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    row-gap: 4px;
}

/* !!! ________Search */

.sManual_search_highlight {
    background-color: var(--lightyellow);
}

.sManual_search_content {
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
}

.sManual_search_header {
    font-family: var(--headingfont);
    font-size: var(--font_em_2B);
}

.sManual_search_link {
    font-family: var(--headingfont);
    font-size: var(--font_em_4A);
}

/* !!! ________Flags */

.sManual_flag_container {
    position: absolute;
    left: 1rem;
}

.sManual_flag {
    width: 30px;
    height: 30px;
    transform: translateY(-0.5rem);
}

.sManual_flag_mci {
    font-family: var(--headingfont);
}

/* !!! ________TOC */

.sManual_toc_row {
  margin-right: 18px;
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100%;
  border-bottom: 1px dashed var(--gray-400);
  height: 20px;
  min-height: 18px;
  max-height: 24px;
    font-size: var(--font_em_5A);
  overflow: hidden;
}

.sManual_toc_row.type1:hover {
    background-color: var(--gray-100);
}

.sManual_toc_row.type2:hover {
    background-color: var(--gray-050);
}

.sManual_toc_link {
    flex: 1;
    min-width: 25rem !important;
    white-space: nowrap !important;
    display: inline-block;
}

.sManual_toc_link.type1 {
    font-family: var(--headingfont);
    margin-left: var(--sManual_leftMargin_2);
    font-size: var(--font_em_4A);
}

.sManual_toc_link.type2 {
    font-family: var(--tablefont);
    margin-left: var(--sManual_leftMargin_3);
    font-size: var(--font_em_4A);
}

/* SOP-only: section titles in the Table of Contents are slightly larger than
   the shared safety-manual TOC sizing. */
.sop.toc .sManual_toc_link.type1 {
    font-size: var(--font_em_4);
}

.sManual_toc_link.type2.special {
    color: var(--bedrock) !important;
}

.sManual_toc_link.type3 {
    font-family: var(--textfont);
    margin-left: var(--sManual_leftMargin_4);
    font-size: var(--font_em_4A);
}

.sManual_toc_date {
    width: 200px;
    text-align: left;
    color: var(--text_dark);
    font-family: var(--tablefont_mono);
}

.sManual_toc_container {
    margin-left: 36px;
    margin-right: 24px;
}

.sManual_status_container {
    width: 20rem !important;
    min-width: 20rem !important;
    display: inline-block;
    text-align: left;
}

.sManual_horizontal_spacer {
    width: 5rem !important;
    min-width: 5rem !important;
    display: inline-block !important;
}

.sManual_status {
    font-family: var(--textfont);

    border: 1px solid var(--pt-border);
    border-radius: 8px;
    padding: 1px 6px;
    display: inline-block;
    font-size: var(--font_em_5A);
}

.sManual_status.Review {
    background-color: var(--gray-900);
    color: var(--text_color_dark);
}

.sManual_status.In.Progress {
    background-color: var(--gray-100);
}

.sManual_status.Gabi {
    background-color: var(--lightblue);
}
.sManual_status.Gulay {
    background-color: var(--lightpurple);
}
.sManual_status.Alphonse {
    background-color: var(--mist);
}

.btn.btn-primary.sManual_backtotoc_button,
.btn.btn-primary.ml-auto {
    font-size: var(--font_em_4A);
    font-family: var(--headingfont);
    padding: 2px 6px;
    border-radius: 8px;
    border: 1px solid var(--pt-border);
    color: var(--text_color_dark) !important;
    background-color: var(--button_color_dark);
    transition: var(--button-link-transition);
    margin-top: 1rem;
}

.btn.btn-primary.sManual_backtotoc_button:hover,
.btn.btn-primary.ml-auto:hover {
    color: var(--text_dark) !important;
    cursor: pointer;
    border-radius: 16px;
    box-shadow: var(--shadow-hover-soft);
    background-color: transparent !important;
    border: 1px solid var(--pt-border);
}

/* !!! ________Photos */

.sManual_photo {
    height: 200px;
    max-width: 50%;
    object-fit: contain;
    margin-right: 6px;
    margin-left: 6px;
}

.sManual_photo.large {
    height: 300px;
    max-width: 50%;
}

.sManual_photo.medium {
    height: 200px;
    max-width: 50%;
}

.sManual_photo.small {
    height: 150px !important;
    max-width: 50%;
}

.sManual_photo_row {
    margin-bottom: 12px;
    margin-top: 12px;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: nowrap;
    overflow-x: auto;
}

/* !!! ________Definition_Links*/

/* Enhanced CSS for Definition Links */
.sManual_definition_link {
    border-bottom: var(--sManual_link_bottom_border);
    transition: var(--sManual_link_transition);
    margin-left: 0 !important;
    height: auto;
}

.legend_definition_link {
    border-bottom: var(--sManual_link_bottom_border);
}

.sManual_definition_link_to_original {
    border-bottom: var(--sManual_link_bottom_border_4);
    transition: var(--sManual_link_transition);
    margin-left: 6px !important;
    height: auto;
}

.link_to_original {
    border-bottom: var(--sManual_link_bottom_border_4);

}

.sManual_definition_link:hover {
    border-bottom: var(--sManual_link_bottom_border_highlight);
    background-color: var(--gray-100);
    transition: var(--sManual_link_transition);
}

.sManual_definition_reference_link {
    border-bottom: var(--sManual_link_bottom_border);
    transition: var(--sManual_link_transition);
}

.sManual_definition_reference_link:hover {
    border-bottom: var(--sManual_link_bottom_border_highlight);
    background-color: var(--gray-100);
    transition: var(--sManual_link_transition);
}
.sManual_content_row:has(.sManual_inserted_definition) {
    border-right: var(--sManual_border_thick) dotted var(--gray-900) !important;
}

.sManual_definition_link_to_original:hover {
    border-bottom: var(--sManual_link_bottom_border_highlight);
    background-color: var(--gray-100);
    transition: var(--sManual_link_transition);
}

/* Animated highlight effect when jumping to a definition */
:target + .sManual_content_row {
    animation: definition-target-fade 4s ease;
}

@keyframes definition-target-fade {
    0%, 10%, 30% {
        background-color: var(--sManual_yellow_highlight);
    }
    70%, 100% {
        background-color: transparent;
        box-shadow: none;
    }
}

/* Make the definition highlight stronger when it's the target */
:target + .sManual_content_row .definition_highlight {
    background-color:  var(--sManual_yellow_highlight);
    border-bottom: 1px solid var(--gray-900);
    animation: definition-text-pulse 4s ease;
}

@keyframes definition-text-pulse {
    0%, 10%, 30% {
        background-color:  var(--sManual_yellow_highlight);
    }
    70%, 100% {
        background-color: var(--sManual_yellow_highlight);
        box-shadow: none;
    }
}

/* Add a little animation to make it clear when a user has followed a link */
.sManual_content_row:target {
    animation: highlight-fade 2s ease;
}

@keyframes highlight-fade {
    0% {
        background-color:  var(--sManual_yellow_highlight);
    }
    100% {
        background-color: transparent;
    }
}

/* !!! ________Warnings */

.sManual_warning_header {
    color: var(--monconred);
    margin: 0 0 12px 0;
    font-size: var(--font_em_3);
    padding-top: 0.5em
}

.sManual_warning_item {
    font-family: var(--textfont);
    font-size: var(--font_em_4);
    margin-bottom: 0.35rem;
}

.sManual_warning_section_link {
    text-decoration: none;
    padding: 2px 6px;
    border-radius: 3px;
    border: 1px solid var(--monconred);
    transition: var(--button-link-transition);
    margin: 0 4px;
}

.sManual_warning_section_link:hover {
    border-radius: 16px;
    box-shadow: var(--shadow-hover-soft);
}

.link-separator {
    color: var(--monconred);
}

.sManual_duplicate_warning {
    background-color: var(--monconred-tint);
    color: var(--monconred);
    font-size: var(--font_em_3A);
    padding: 4px 8px;
    margin-top: 10px;
    border-radius: 4px;
    border-left: 3px solid var(--monconred);
    display: flex;
    align-items: center;
}

/* Style the warning card at the top — red border + red text, all tied to --monconred */
.card.warning {
    border: 1px solid var(--monconred) !important;
    background: var(--pt-body-light) !important;
    color: var(--monconred) !important;
    border-radius: 8px !important;
    word-break: normal;
    font-size: var(--font_em_4A);
}

.card.warning,
.card.warning h1,
.card.warning h2,
.card.warning h3,
.card.warning h4,
.card.warning h5,
.card.warning h6,
.card.warning p,
.card.warning span,
.card.warning label,
.card.warning li,
.card.warning a,
.card.warning div {
    color: var(--monconred) !important;
}

/* Improve linking to duplicates */
.sManual_content_row.has-duplicate-warning:target + .sManual_content_row {
    animation: duplicate-definition-flash 4s ease;
}

@keyframes duplicate-definition-flash {
    0%, 15%, 30% {
        background-color: rgba(212, 53, 28, 0.15);
    }
    70%, 100% {
        background-color: transparent;
    }
}

/* !!! ________Doc_Links */

.sManual_doc_link_new {
    display: flex;
    text-align: left;
    margin: 0;
    height: 2.5em;
    text-decoration: none !important;
    color: var(--text_dark);
    background-color: var(--gray-100);
    font-family: var(--headingfont);
    font-size: var(--font_em_5A);
    cursor: default;
    transition-duration: var(--sManual_transition_duration) !important;
    border: 1px solid var(--sManual_accent_color);
    border-radius: 6px;
    padding: 0.45em;
    word-break: normal;
}
.sManual_doc_link_new.spanish_modifier::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    width: 12px;  /* Adjust size as needed */
    height: 12px; /* Adjust size as needed */
    background-color: var(--sManual_accent_color); /* Choose your color */
    clip-path: polygon(100% 0%, 0% 0%, 100% 100%);
    border-top-right-radius: 6px; /* Match the parent's border-radius */
    transition-duration: var(--sManual_transition_duration) !important;
}

.sManual_doc_link:visited {
    text-decoration: none !important;
    border-radius: 18px;
    cursor: pointer;
}

.sManual_doc_link_new:hover {
    border-radius: 16px !important;
    cursor: pointer !important;
    background-color: var(--gray-050);
    box-shadow: var(--shadow-hover-soft);
    transition-duration: var(--sManual_transition_duration) !important;
}

.sManual_doc_link_new.spanish_modifier:hover::after {
    border-top-right-radius: 16px; /* Match the hover border-radius */
    transition-duration: var(--sManual_transition_duration) !important;
}

a.sManual_doc_link {
    text-decoration: none !important;
}

.sManual_doc_icon_container {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: auto;
    margin: auto;
    overflow: hidden;
}

.sManual_doc_link_group_container {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    margin-top: 0.50rem;
}

.sManual_doc_link_group_container.type3 {
    margin-left: var(--sManual_leftMargin_3);
}
.sManual_doc_link_group_container.type4 {
    margin-left: var(--sManual_leftMargin_4);
}
.sManual_doc_link_group_container.type5 {
    margin-left: var(--sManual_leftMargin_5);
}
.sManual_doc_link_group_container.type6 {
    margin-left: var(--sManual_leftMargin_6);
}
.sManual_doc_link_container {
    display: inline-block;
    margin-left: 1rem;
    margin-bottom: 0.75rem;
}

.sManual_doc_link_container_new {
    display: inline-block;
    margin-left: 0;
    margin-bottom: 0;
}

.doc_icon {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.sManual_doc_text {
    height: 2.25rem;
    font-family: var(--mediumfont);

}

.sManual_doc_text_new {
    display: inline-block;
}

.sManual_doc_links_container {
    margin-right: 0;
    background-color: var(--gray-060);
    padding-left: 0.5em;
    padding-right: 0.5em;
    padding-bottom: 0.5em;
    border-radius: 12px;
    position: relative;
}

/* !!! ________Personnel_Links */

.sManual_personnel_link {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-height: 16em; /* Changed from height to min-height */
    margin-left: 0;
    margin-bottom: .2em;
    text-align: center;
    text-decoration: none !important;
    color: var(--text_dark);
    font-family: var(--headingfont);
    font-size: var(--font_em_5A);
    cursor: default;
    transition-duration: var(--sManual_transition_duration) !important;
    word-break: keep-all;
    position: relative;
    z-index: 0;
    isolation: isolate;
}

.sManual_personnel_image_container {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    max-width: 100%;
    margin: 0 auto;
    border-radius: 12px;
    transition-duration: var(--sManual_transition_duration) !important;
    overflow: hidden; /* Prevent image overflow */
    position: relative;
    z-index: 0;
    isolation: isolate;
    border: 1px solid var(--sManual_accent_color);
}

.sManual_personnel_image_container:hover {
    cursor: pointer !important;
    background-color: var(--gray-050);
    box-shadow: var(--shadow-hover-soft);
    transition-duration: var(--sManual_transition_duration) !important;
}

.sManual_personnel_image_container.ghosted {
    overflow: visible;
}

/* Ghosts */
.sManual_personnel_image_container.ghosted::before,
.sManual_personnel_image_container.ghosted::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border-right: 1px solid var(--pt-border);
  border-bottom: 1px solid var(--pt-border);
  z-index: -3;
  pointer-events: none;
  opacity: .35;
}

.sManual_personnel_image_container.ghosted::before { transform: translate(5px,5px); opacity:.5; }
.sManual_personnel_image_container.ghosted::after  { transform: translate(9px,9px); }

/* Default for horizontal images */
.sManual_personnel_image {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
    margin: 0;
    position: relative;
    z-index: 2;
    background-color: var(--gray-100);
    border-radius: 12px;
    transition-duration: var(--sManual_transition_duration) !important;
}
.sManual_personnel_image:hover {
    background-color: var(--gray-025);
    transition-duration: var(--sManual_transition_duration) !important;
}
.sManual_personnel_image_cover1 {
  position: relative;
  background-color: var(--gray-025);  /* solid bg */
  border-radius: inherit;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  z-index: 1; /* above ghosts, below the img */
}

.sManual_personnel_text_new {
    margin-top: 0.8em;
    font-size: var(--font_em_2C);
    min-height: 2em;
    line-height: 1.2;
    display: flex;
    align-items: center;
    justify-content: center;
}

.sManual_image_content:hover {
    pointer-events: none !important;
}

.sManual_image_content.within_modal {
    width: 200px !important;
    margin-left: auto !important;
    margin-right: auto !important;
}

.sManual_external_link_new {
    border: 1px solid var(--sManual_accent_color);
    border-radius: 8px;
    padding: 2px 6px;
    background-color: var(--gray-100);
    transition-duration: var(--sManual_transition_duration) !important;
    font-family: var(--mediumfont);
    font-size: var(--font_em_5);
    margin-bottom: 0.5em;
}

.sManual_external_link_new:hover {
    border-radius: 12px;
    box-shadow: var(--shadow-hover-soft);
    border: 1px solid var(--pt-border);
    background-color: var(--gray-050);
}

/* !!! ________Grid_Tables */

.sManual_gridtable_item {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    background-color: var(--gray-060);
    color: var(--text_dark);
    margin-left: 0;
    margin-bottom: 0.25em;
    font-family: var(--textfont);
    font-size: var(--font_em_5A);
    border-radius: 6px;
    padding: 0.45em;
    word-break: normal;
    height: 3.5em;
}

.sManual_gridtable_item.main {
    background-color: var(--gray-100);
    font-family: var(--headingfont);
    border: 1px solid var(--sManual_accent_color);
    transition-duration: var(--sManual_transition_duration) !important;
}

.sManual_gridtable_item.main.link:hover {
    border-radius: 12px;
    box-shadow: var(--shadow-hover-soft);
    border: 1px solid var(--sManual_accent_color);
    cursor: pointer !important;
    background-color: var(--gray-050);
    transition-duration: var(--sManual_transition_duration) !important;
}

.sManual_gridtable_item.header {
    background-color: transparent;
    font-family: var(--headingfont);
    font-size: var(--font_em_5A);
    margin-bottom: 0.4em;
    padding-top: 0;
    color: var(--text_dark);
    border-bottom: 1px solid var(--pt-border);
    border-radius: 0;
    height: unset;
}

.sManual_inspection_type_text {
    font-family: var(--textfont);
}

.sManual_inspection_type_text.bold {
    font-family: var(--headingfont) !important;
}

/* Safety Manual Top 10 */
/*------------------------------------------------------------------------------*/

.sManual_top10_content_wrapper {
    display: flex !important;
    align-items: flex-start;
    width: 100%;
    font-family: var(--textfont);

}

.sManual_top10_content_wrapper.nolinks {
    font-size: var(--font_em_4A);
}

.sManual_top10_line {
    display: flex !important;
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
    margin-bottom: 1em;
    width: 100%;
    word-break: normal;
}

.sManual_top10_number {
    margin-right: 0.5em;
    font-family: var(--tablefont_mono_bold);
    flex-shrink: 0;
}

/* The div containing the line spans needs to allow inline flow */
.sManual_top10_line > div:last-child {
    display: inline;
}

/* Keep spans inline */
.sManual_top10_content,
.topic_highlight_ss,
.definition_highlight,
.direct_quote_highlight {
    display: inline !important; /* Change from inline-block to inline */
}

.topic_highlight_ss {
    font-family: var(--mediumfont);
}

.sManual_link_container {
    display: flex;
    flex-direction: column !important;
}

.PILL {
    font-family: var(--textfont);
    display: inline-block;
    margin-bottom: 2px;
    margin-right: 4px;
    border: 1px solid var(--gray-400);
    border-radius: 12px;
    hyphens: auto;
    word-break: normal;
    transition-duration: var(--sManual_transition_duration) !important;
    text-overflow: ellipsis;
    height: 0.6rem;
    overflow: hidden;
    white-space: nowrap;
    max-width: 100%;
    font-size: var(--font_em_6) !important;
    padding: 2px 8px 2px 8px !important;
    line-height: 0.6rem !important;
}

.PILL.doclink {
    color: var(--text_dark);
    border: 1px solid var(--sManual_accent_color);
}

.PILL.doclink:hover {
    border-radius: 16px !important;
    cursor: pointer !important;
    background-color: var(--gray-050);
    box-shadow: var(--shadow-hover-soft);
    border: 1px solid var(--sManual_accent_color);
}

.PILL.log {
    background-color: var(--opsChart_PM_color);
}
.PILL.tag {
    background-color: var(--opsChart_SU_color);
}

.doccard {
    position: relative;
}

.doccard.emphasis {
    border: 3px solid var(--pt-border);
}

.sManual_summarycard_title {
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    color: var(--text_dark);
    margin-top: 0;
    margin-bottom: 0;
    hyphens: auto;
    word-break: break-word; /* Optional: breaks long words if needed */
    overflow-wrap: break-word; /* Optional: modern alternative to word-wrap */
}
.sManual_summarycard_subtitle_line {
    display: inline-flex;
    margin-top: 0.5em;
    margin-bottom: 1em;
    align-content: center;
}

.sManual_summarycard_subtitle_1 {
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    color: var(--text_dark);
    hyphens: auto;
    word-break: break-word; /* Optional: breaks long words if needed */
    overflow-wrap: break-word; /* Optional: modern alternative to word-wrap */
    display: inline-flex;
}
.sManual_summarycard_subtitle_2 {
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    color: var(--text_dark);
    hyphens: auto;
    word-break: break-word; /* Optional: breaks long words if needed */
    overflow-wrap: break-word; /* Optional: modern alternative to word-wrap */
    display: inline-flex;
}

/* Safety Manual Card Rev Date */
/*------------------------------------------------------------------------------*/

.sManual_doctype_section_icon {
    height: calc(100% - 1rem); /* Full height minus margin */
    max-height: 5em;
    max-width: calc(100% - 1rem); /* Prevent horizontal overflow */
    position: absolute;
    right: 0.5rem;
    top: 50%; /* Center vertically */
    transform: translateY(-50%); /* Offset by half the element's height */
    object-fit: contain; /* Maintain aspect ratio while fitting */
    box-sizing: border-box;
}

.smaller_grid_container {
    max-width: 75%;
    padding-right: 24px;
}

.accent_text1 {
    font-family: var(--headingfont);
    font-size: var(--font_em_5);
    color: var(--text_dark);
    display: block;
    text-align: right;
}

.tabletext1 {
    font-family: var(--tablefont);
    font-size: var(--font_em_6);
    text-align: left;
    display: inline;
    color: var(--text_dark);
}

/* !!! ===============================================================================================================*/
/* !!! INPUTS  */
/* ===================================================================================================================*/

/* !!! ________Input2 */

/* Text inputs share the dropdown's visual language (see .Select-control
   and its companion rules below): same height, hairline border, radius,
   transparent fill, typography, placeholder tone, and focus ring — so a
   dcc.Input next to a dcc.Dropdown reads as the same family of control. */
.input2 {
    box-sizing: border-box; /* like .Select-control: height includes the border */
    height: var(--control-height);
    line-height: var(--control-inner);
    text-align: left;
    color: var(--text_dark);
    font-size: var(--font_em_5A);
    font-family: var(--textfont);
    padding: 0 8px 0 10px;
    border-radius: var(--control-radius);
    border: 1px solid var(--pt-border);
    margin-left: 0;
    margin-right: 0;
    margin-Top: 4px;
    transition: all var(--button-link-transition-duration) ease-in-out;
    background-color: transparent;
}

.input2::placeholder {
    color: var(--text_dark);
    opacity: 1;
}

/* Focus mirrors .is-focused .Select-control: hairline ring, no browser
   outline. */
.input2:focus {
    outline: none;
    border-color: var(--pt-border);
    box-shadow: 0 0 0 1px var(--pt-border);
}

.dropdown1.has-options .Select-control {
    background-color: transparent !important;
}

.dash-input.input2:focus {
    background-color: transparent !important;
}
.dash-input.input2:not([value=""]) {
    background-color: transparent !important;
}
/* For inputs with values */
.dash-input.input2[value]:not([value=""]) {
    background-color: transparent !important;
}

/* !!! ________Input_tpb_jobname */

.input_tpb_jobname {
    box-sizing: border-box;
    height: var(--control-height);
    line-height: var(--control-inner);
    color: var(--text_dark);
    font-size: var(--font_em_5A);
    font-family: var(--textfont);
    padding: 0 0 0 5px;
    border-radius: var(--control-radius);
    border: 1px solid var(--pt-border);
    margin-left: 0;
    margin-right: 0;
    margin-Top: 4px;
    transition: all var(--button-link-transition-duration) ease-in-out;
    background-color: transparent;
    float: right;
    width: 140px;
}

/* !!! ________Input4 */

.input4 {
    height: 16px;
    text-align: right;
    color: var(--text_dark);
    font-size: var(--font_em_5A);
    font-family: var(--textfont);
    padding: 1px 2px;
    border-radius: 5px;
    border: 2px solid var(--pt-border);
    margin: 2px 0;
    display: inline-flex;
    background-color: transparent;
}

.dash-dropdown {
    border-radius: 8px;
}

/* !!! ===============================================================================================================*/
/* !!! SLIDER  */
/* ===================================================================================================================*/

.mantine-Slider-root {
    margin-bottom: 20px;
}

.mantine-Slider-track {
    background-color: rgba(30, 33, 36, 0.12) !important;
}

.mantine-Slider-bar {
    background-color: var(--button_color_dark) !important;
}

.mantine-Slider-thumb {
    border-color: var(--button_color_dark) !important;
    border-width: var(--lw-1);
    background-color: var(--pt-text) !important;
}

.mantine-Slider-mark {
    border-color: var(--pt-border);
}

/* !!! ===============================================================================================================*/
/* !!! DATEPICKER  */
/* ===================================================================================================================*/

.DateInput, .DateInput_1 {
    border-radius: 4px 0 0 4px !important;
}

.DateInput_input, .DateInput_input_1 {
    Height: 34px !important;
    Width: 100% !important;
}

.SingleDatePickerInput {
    border-radius: 4px 0 0 4px;
    width: 100% !important;
}

.SingleDatePicker_1 {
    width: 100% !important;
}

/* !!! ===============================================================================================================*/
/* !!! DATE_RANGE_PICKER  */
/* ===================================================================================================================*/

.SingleDatePickerInput {
    border: 0 solid;
    background-color: transparent;
}

.DateRangePicker {
    color: var(--text_dark);
    background-color: transparent;
}

.DateRangePickerInput {
    color: var(--text_dark);
    border: solid 0;
}

.DateRangePicker.DateInput_1 {
    background-color: transparent;
}

.DateInput_input {
    border: solid 1px var(--pt-border);
    border-radius: 6px;
    margin-bottom: 4px;
    height: 36px;
    color: var(--text_dark);
    font-size: var(--font_em_5);
    font-family: var(--textfont);
    background-color: transparent;
}

.DateInput.DateInput_1 {
    border-radius: 14px;
    color: var(--text_dark);
    background-color: transparent;
}

.DateInput_input.DateInput_input_1 {
    background-color: transparent;
}

/* !!! ===============================================================================================================*/
/* !!! SEGMENTED_CONTROL  */
/* ===================================================================================================================*/

/* Segmented controls share the app's control footprint (--control-*
   tokens) — the same border-box height as dropdowns (.Select-control)
   and text inputs (.input2), so the control types line up when placed
   together. Mantine injects its own root/label padding at runtime
   after this stylesheet, hence the !important on the squashed values.
   The active highlight rides on labelActive (the sliding .-active
   indicator is transparent), so resizing is safe. */
.mantine-SegmentedControl-root {
    border: solid 1px var(--pt-border);
    border-radius: var(--control-radius);
    color: var(--text_color_dark);
    background-color: transparent !important;
    box-sizing: border-box;
    height: var(--control-height);
    /* 3px inset so the active pill floats inside the frame instead of
       touching the border */
    padding: 3px !important;
    margin-bottom: 4px;
    margin-top: 0;
    align-items: center;
    max-width: 100%;
}

.mantine-SegmentedControl-active {
    background-color: transparent;
}

.mantine-SegmentedControl-label {
    /* Includes border-radius, so the shared hover pill-morph eases in
       instead of snapping (the active label gets its own transition
       below, but the inactive ones had none). */
    transition: var(--pill-morph-transition);
    color: var(--text_dark);
    font-family: var(--tablefont);

    font-size: var(--font_em_6);
    background-color: transparent;
    /* control height − 2px border − 6px inset padding = pill line box */
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    line-height: calc(var(--control-height) - 8px) !important;
    /* pill corners track the control's outer radius minus the inset */
    border-radius: calc(var(--control-radius) - 3px);
}

/* Active segment: shared dark button token */
.mantine-SegmentedControl-labelActive {
    background-color: var(--button_color_dark) !important;
    color: var(--text_color_dark) !important;
    font-family: var(--buttonfont);

    transition: var(--pt-transition);
}

.card .mantine-SegmentedControl-labelActive {
    color: var(--text_color_dark) !important;
}

.mantine-SegmentedControl-labelActive:not(:hover) {
    background-color: var(--button_color_dark) !important;
    color: var(--text_color_dark) !important;
    font-family: var(--buttonfont);

}

.card .mantine-SegmentedControl-labelActive:not(:hover) {
    color: var(--text_color_dark) !important;
}

/* !!! ===============================================================================================================*/
/* !!! DATATABLE_CHECKBOX  */
/* ===================================================================================================================*/

.dash-select-cell input[type="checkbox"] {
    appearance: none;
    width: 15px !important;
    height: 15px !important;
    margin: 1px !important;
    border-radius: 3px !important;
    outline: none !important;
    cursor: pointer !important;
    position: relative !important;
    background-color: transparent !important;
}

.dash-select-cell input[type="checkbox"]:checked {
    color: var(--text_dark) !important;
    background-color: var(--text_dark) !important;
    border: solid 2px var(--pt-border) !important;
    transform: translateX(0em) translateY(0em) !important;
    box-shadow: 0 0 0 var(--gray-900) !important;
}

.dash-select-cell input[type="checkbox"]:checked::after {
    content: '';
    position: absolute;
    left: 4px;
    top: 1px;
    width: 5px;
    height: 10px;
    border: solid var(--gray-025);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

.dash-select-cell input[type="checkbox"]:hover {
    transform: translateX(-0.15em) translateY(-0.15em) !important;
    transition: all var(--button-link-transition-duration) ease-in-out !important;
    box-shadow: 3px 3px 0 var(--gray-900) !important;
    border: solid 2px var(--pt-border) !important;
}

.dash-select-cell input[type="checkbox"]:focus {
    box-shadow: none !important;
}

/* !!! ===============================================================================================================*/
/* !!! MANTINE_CHECKBOX  */
/* ===================================================================================================================*/

.mantine-Checkbox-root {
    display: inline-flex;
    margin-left: 2px;
}

.mantine-Checkbox-input {
    border: solid 2px var(--pt-border);
    background-color: transparent;
}

.mantine-Checkbox-input:hover {
    transform: translateX(-0.15em) translateY(-0.15em);
    transition: all var(--button-link-transition-duration) ease-in-out;
    box-shadow: 3px 3px 0 var(--gray-900);
    border: solid 2px var(--pt-border);
}

.mantine-Checkbox-input:checked,
.mantine-Checkbox-input:checked:hover {
    color: var(--text_dark);
    background-color: var(--text_dark);
    border: solid 2px var(--pt-border);
    transform: translateX(0em) translateY(0em);
    box-shadow: 0 0 0 var(--gray-900);
}

.mantine-Checkbox-input:checked:hover {
    transition: all var(--button-link-transition-duration) ease-in-out;
}

/* Project Summary: the per-card PDF-include checkbox on muted
   (not-yet-started) cards should read lighter gray so it matches the
   rest of that card's greyed-out treatment instead of the full-strength
   dark checkbox used on live cards. */
.card-dashed .mantine-Checkbox-input {
    border-color: var(--pt-disabled-text);
}

.card-dashed .mantine-Checkbox-input:checked,
.card-dashed .mantine-Checkbox-input:checked:hover {
    background-color: var(--pt-disabled-text);
    border-color: var(--pt-disabled-text);
}

/* Project Summary include checkboxes: kill the global checkbox hover
   nudge/shadow animation so the per-card toggle stays put on hover. */
#project_photo_grid .mantine-Checkbox-input,
#project_photo_grid .mantine-Checkbox-input:hover,
#project_photo_grid .mantine-Checkbox-input:checked:hover {
    transform: none;
    box-shadow: none;
    transition: none;
    cursor: pointer;
}

/* The clickable hit-area for the include toggle includes the Mantine
   label wrapper, so give the whole control a pointer cursor on hover. */
#project_photo_grid .mantine-Checkbox-root,
#project_photo_grid .mantine-Checkbox-labelWrapper,
#project_photo_grid .mantine-Checkbox-label {
    cursor: pointer;
}

/* !!! ===============================================================================================================*/
/* !!! CHECKLIST  */
/* ===================================================================================================================*/

.cklst {
    color: var(--text_dark);
    font-size: var(--font_em_5A);
    font-family: var(--textfont);
    margin: 2px 0;
    accent-color: var(--text_dark);
}

/* Modifier: lay the checklist's labels out as a 2-column CSS multi-column
   flow inside its container so long trade lists wrap horizontally instead
   of stacking into one tall single column. break-inside: avoid keeps each
   labelled checkbox row whole rather than getting split across columns. */
.cklst.cklst-2col {
    column-count: 2;
    column-gap: 12px;
}
.cklst.cklst-2col > label {
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    page-break-inside: avoid;
}

/* !!! ===============================================================================================================*/
/* !!! DROPDOWN  */
/* ===================================================================================================================*/

/* dcc injects react-select's own stylesheet at runtime — after this
   file — so any sizing that must beat its 36px-control defaults needs
   !important (the height here, and the 34px inner line boxes below).
   The height/radius come from the shared --control-* tokens (.input2,
   nav-card buttons, segmented controls). Width stays at react-select's
   100%-of-container default. */
.Select-control {
    border-radius: var(--control-radius);
    border: 1px solid var(--pt-border) !important;
    background-color: transparent !important;
    color: var(--text_dark) !important;
    height: var(--control-height) !important;
    max-width: 100%;
    z-index: 1000;
}

/* Inner single-value elements assume a 36px control (line-height /
   height 34px in the injected defaults) — re-center them in the
   control's inner box. */
.Select-placeholder,
.Select--single > .Select-control .Select-value {
    line-height: var(--control-inner) !important;
}

.Select-input {
    height: var(--control-inner) !important;
}

.Select-input > input {
    padding: 0 !important;
    line-height: var(--control-inner);
}

/* Multi-selects: the control matches the shared height while a single
   row of value chips fits, and only grows when chips wrap. Injected
   defaults give chips a 5px top margin sized for the 36px control. */
.Select--multi .Select-control {
    height: auto !important;
    min-height: var(--control-height);
}

.Select--multi .Select-value {
    margin-top: 2px !important;
    margin-bottom: 2px !important;
}

.is-focused .Select-control {
    border-color: var(--pt-border) !important;
    box-shadow: 0 0 0 1px var(--pt-border) !important;
}

.is-pseudo-focused .Select-control {
    border-color: var(--pt-border) !important;
    box-shadow: 0 0 0 1px var(--pt-border) !important;
}

.Select-control:hover {
    cursor: pointer;
}

.Select-placeholder, .Select-menu, .Select-value, .Select-input {
    font-family: var(--textfont);
    font-size: var(--font_em_5A);
}

.Select-menu-outer {
    border-radius: 0.5rem;
    border: 1px solid var(--pt-border) !important;
    background-color: var(--pt-body) !important;
    position: absolute !important;
    z-index: 9999 !important;
}

.card .Select-menu-outer {
    background-color: var(--pt-body);
}

.Select-menu-outer.is-open {
    max-height: 600px !important;
}

.dash-dropdown .Select {
    position: relative !important;
}

/* !!! ===============================================================================================================*/
/* !!! MULTISELECT  */
/* ===================================================================================================================*/

.mantine-MultiSelect-root {
    font-family: var(--textfont);

    font-size: var(--font_em_4A) !important;
    max-width: 200px !important;
}

.card,
.card.nav,
.nav-sidebar,
.sidebar,
.mantine-MultiSelect-wrapper {
    overflow: visible !important;
}
.mantine-MultiSelect-dropdown {
    background-color: var(--pt-body-medium);
    border-color: var(--pt-border);
    z-index: 9999 !important;
}

/* The input matches the shared control height while one row of chips
   fits, and grows only when chips wrap. Mantine's injected min-heights
   (input and inner values wrapper) are sized for its stock 36px
   control, hence the !important overrides; chips are capped so one
   row sits inside the shared height. */
.mantine-MultiSelect-input {
    border: 1px solid var(--pt-border) !important;
    border-radius: var(--control-radius);
    background-color: transparent !important;
    color: var(--text_dark) !important;
    box-sizing: border-box;
    min-height: var(--control-height) !important;
    padding-left: 0.25em !important;
    padding-top: 1px !important;
    padding-bottom: 1px !important;
}

.mantine-MultiSelect-values {
    min-height: calc(var(--control-height) - 4px) !important;
}

.mantine-MultiSelect-value {
    height: calc(var(--control-height) - 6px) !important;
    margin-top: 1px !important;
    margin-bottom: 1px !important;
}

.mantine-MultiSelect-searchInput {
    height: calc(var(--control-height) - 6px) !important;
}

/* The field the placeholder and any typing appear in. Mantine sets its own
   theme font on it, so an empty select drew its placeholder in a face and
   size that appear nowhere else in the app — the selected chips and the
   dropdown list were right and only the empty state was wrong.

   Inherited rather than restated from the tokens, because the tokens are
   relative: --font_em_4A is 0.75em, and .mantine-MultiSelect-root has already
   applied it, so naming it again here would compound to 0.75 of 0.75.
   Inheriting takes the size the root computed. !important for the same reason
   the rest of this block needs it — Mantine injects its styles at runtime,
   after this sheet has loaded. Height is pinned above, so this cannot change
   the control's size. */
.mantine-MultiSelect-searchInput,
.mantine-MultiSelect-searchInput::placeholder {
    font-family: inherit !important;
    font-size: inherit !important;
}

/* A single selection always stays one row high, however narrow the column
   gets. Mantine lays the chips out in a wrapping flex row and gives the
   search field `flex: 1; min-width: 60px`, so once the control is narrower
   than chip + 60px the field drops to a second line and the control doubles
   in height — which is what every filter card did as the window shrank.
   With one chip there's nothing to wrap *to*, so hold the row and let the
   chip give up width instead; Mantine's own label already carries
   text-overflow: ellipsis, so it truncates cleanly. Two or more chips still
   wrap, since there the extra rows are showing real selections.
   `:only-of-type` reads "the lone chip <div> beside the search <input>". */
.mantine-MultiSelect-values:has(> .mantine-MultiSelect-value:only-of-type) {
    flex-wrap: nowrap !important;
    overflow: hidden;
}

.mantine-MultiSelect-values:has(> .mantine-MultiSelect-value:only-of-type)
.mantine-MultiSelect-value {
    min-width: 0 !important;
}

.mantine-MultiSelect-values:has(> .mantine-MultiSelect-value:only-of-type)
.mantine-MultiSelect-defaultValueRemove {
    flex-shrink: 0;
}

/* A select that isn't searchable hides its field (Mantine zeroes the width)
   but the 60px minimum still holds a sixth of the control hostage. Give it
   back to the chip; searchable selects keep the room to type in. */
.mantine-MultiSelect-searchInput.mantine-MultiSelect-searchInputInputHidden {
    min-width: 0 !important;
}

/* Selected tags: shared dark button token */
.mantine-MultiSelect-value {
    background-color: var(--button_color_dark) !important;
    color: var(--text_color_dark) !important;
    font-family: var(--buttonfont);

    font-size: var(--font_em_5) !important;
    padding-left: 1em !important;
    padding-right: 0.5em !important;
}

.card .mantine-MultiSelect-value {
    color: var(--text_color_dark) !important;
}

.mantine-MultiSelect-defaultValueRemove {
    color: var(--text_color_dark) !important;
}

/* !!! ===============================================================================================================*/
/* !!! CALENDAR_WIDGET (react-dates / airbnb) */
/* ===================================================================================================================*/

.CalendarMonth_caption.CalendarMonth_caption_1 {
    color: var(--text_dark);
    font-family: var(--textfont);

    z-index: 9999;
}

.CalendarDay.CalendarDay_1 {
    background-color: var(--text_dark);
    color: var(--text_color_dark);
    border: 1px solid var(--pt-border);
    z-index: 9999;
}

/* !!! ===============================================================================================================*/
/* !!! LISTS  */
/* ===================================================================================================================*/

ul {
    margin-top: 0;
    margin-bottom: 0;
    color: var(--text_dark);
    font-family: var(--textfont);
    padding-left: 2em;
    font-size: var(--font_em_4);

}

li {
    margin-top: 0;
    margin-bottom: 0;
    color: var(--text_dark);
    font-family: var(--textfont);
    word-break: normal;
    hyphens: auto;
}

/* !!! ===============================================================================================================*/
/* !!! TABLE  */
/* ===================================================================================================================*/

.special-font {
    font-family: var(--tablefont_mono);
}

.table-scroll-container {
    overflow-x: auto;
    width: 100%;
    display: block;
}

table {
    font-size: var(--font_em_5A);
    font-family: var(--tablefont);
    border-collapse: collapse;
    text-align: left;
    vertical-align: middle;
    line-height: 14px;
    width: 100%;
    color: var(--text_dark);
}

td.last-row-bold {
    font-family: var(--tablefont_mono_bold) !important; /* Corrected variable usage */
}

th {
    border-bottom: 1px solid var(--pt-border);
    font-family: var(--headingfont);
    padding: 0;
}

td, th {
    white-space: nowrap;
    text-overflow: ellipsis;
    vertical-align: middle;
    overflow: hidden;
}

td {
    padding: 0;
}

/* Columns breathe: every cell but a row's last keeps a small right
   gutter, so two columns' values (and their headers) can never touch —
   a right-aligned figure beside a chip column used to sit flush against
   it. The zeroes above used to carry !important, which also silently
   defeated every per-table padding rule in this sheet; with them gone,
   those rules apply again, and any table wanting other spacing simply
   says so (equal or higher specificity wins as usual). */
td:not(:last-child),
th:not(:last-child) {
    padding-right: 0.6em;
}

/* make_table adds .pill-rows when at least one cell in the table drew a pill.
   A pill's border and margin make its cell taller than a plain-text cell, so
   without this the rows carrying pills stand taller than the rest. `height` on
   a table cell behaves as a minimum, so this only lifts the shorter rows and
   still lets a taller cell (nested table, wrapped text) expand its row. */
table.pill-rows tbody td {
    height: var(--pt-pill-row-height);
}

.table tr {
    vertical-align: middle;
    padding: 0;
    margin: 0;
}

.table tr:nth-child(odd) td {
    background-color: var(--gray-150);
}

table.hover tbody tr:nth-child(odd) td {
  background-color: var(--gray-150);
}

.botrackertable table {
    table-layout: auto; /* remove fixed layout to allow text wrapping */
    vertical-align: top;
}

.botrackertable td {
    white-space: normal; /* allow text wrapping */
    vertical-align: top;
}

/* Buyout Tracker — cross-highlight matching sub names on hover.
   The pill bg/color/border come from inline styles in the builder, so
   the override has to be !important to win over inline. Driven by
   utils/assets/buyout_sub_hover.js, which toggles .sub-name-highlight
   on every [data-sub-name] element with the same value. */
.sub-name-highlight {
    background-color: var(--monconred) !important;
    color: #ffffff !important;
    border-color: var(--monconred-ink) !important;
    transition: background-color 80ms ease-in, color 80ms ease-in;
}

/* Buyout Tracker — overdue-buyout flag. Empty (unbought) cells whose trade
   should already be bought by now (per the Schedule Milestones buyout-timing
   analysis) get a red pill-shaped marker. It mirrors the sub-name pills'
   shape (same 15px radius / full-width-within-gutter) and sits inside the
   cell's 6px gutter with a small vertical margin, so adjacent overdue
   highlights stay visually separated instead of butting edge-to-edge. */
.bo-overdue-pill {
    display: block;
    box-sizing: border-box;
    width: 100%;
    /* Match the sub-name pill height (see PILL_MIN_HEIGHT / PILL_LINE_HEIGHT
       in buyout_tracker.py) so an overdue flag never makes a row taller than
       a normal single-pill row. */
    line-height: 16px;
    min-height: 18px;
    margin: 1px 0;
    border-radius: 15px;
    background-color: color-mix(in srgb, var(--monconred) 24%, #ffffff);
    border: 1px solid color-mix(in srgb, var(--monconred) 45%, #ffffff);
}

/* Buyout Tracker — trade Name cell is a clickable pill button that opens the
   per-trade buyout-history modal. Styled to match the sub-name pills (see
   pill_base_style / .bo-sub-pill-btn in buyout_tracker.py): gray fill, rounded
   border, ellipsis truncation, same box metrics so rows stay uniform. */
.bo-trade-name-btn {
    display: block;
    box-sizing: border-box;
    width: 100%;
    font: inherit;
    color: var(--text_dark);
    background-color: transparent;
    border: 1px solid var(--gray-800);
    border-radius: 15px;
    padding: 0 6px;
    margin: 1px 0;
    line-height: 16px;
    min-height: 18px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: left;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

.bo-trade-name-btn:hover {
    filter: brightness(0.97);
}

/* Buyout Tracker — target buyout date pill. Shown inside a cell (under any
   sub pills) when "Show Target Dates" is on, the buyout log has a Target date
   for that project/trade, and no contractor is assigned yet. Light-blue +
   mono so it reads clearly apart from the yellow date cell values. Matches
   the sub-name pill box metrics (PILL_MIN_HEIGHT / PILL_LINE_HEIGHT) for
   uniform row heights. */
.bo-target-date-pill {
    display: block;
    box-sizing: border-box;
    width: 100%;
    line-height: 16px;
    min-height: 18px;
    margin: 1px 0;
    padding: 0 6px;
    border-radius: 15px;
    border: 1px solid color-mix(in srgb, #3843D0 35%, #ffffff);
    background-color: #e6faff;
    color: var(--text_dark);
    font-family: var(--tablefont_mono);
    font-size: 0.9em;
    text-align: center;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Buyout Tracker — "Buyout Plan Missing" header flag. Sits under a project's
   column header when that project has fewer than the expected number of
   commitment-log rows (i.e. it hasn't really been bought out yet). A compact
   red-bordered pill; the label wraps within the narrow column. */
.bo-missing-plan-pill {
    display: block;
    box-sizing: border-box;
    margin: 4px auto 0;
    padding: 1px 6px;
    border-radius: 15px;
    border: 1px solid var(--monconred);
    background-color: var(--monconred);
    color: #ffffff;
    font-family: var(--tablefont);
    font-weight: bold;
    font-size: 0.65em;
    line-height: 1.15;
    text-align: center;
    /* Wrap only at spaces — never hyphenate or split a word mid-character. */
    white-space: normal;
    overflow-wrap: normal;
    word-break: keep-all;
    hyphens: none;
}

/* Labor-type pill in the Sub Commitment Log job headers. Shares the geometry
   of .bo-missing-plan-pill so it lines up vertically with the other header
   chips; a neutral blue distinguishes it from the (red) "Buyout Plan Missing"
   flag. The --empty variant keeps the slot's height so every column's pills
   stay vertically aligned even when a project has no labor type recorded. */
.bo-labor-pill {
    display: block;
    box-sizing: border-box;
    margin: 4px auto 0;
    padding: 1px 6px;
    border-radius: 15px;
    border: 1px solid var(--pt-accent-dark);
    background-color: color-mix(in srgb, var(--pt-accent-dark) 12%, #ffffff);
    color: var(--pt-accent-dark);
    font-family: var(--tablefont);
    font-weight: bold;
    font-size: 0.65em;
    line-height: 1.15;
    text-align: center;
    white-space: normal;
    overflow-wrap: normal;
    word-break: keep-all;
    hyphens: none;
}

/* Labor-status variants — match the site-wide pill language: union family
   (U/PW, U, PW) on the dark-gray chip, non-union (NU) on the light-gray chip,
   anything else on a neutral mid-gray. The two fills come from --pillgray-dark
   and --pillgray-light in the :root block, which is where Python's
   ``pillgray_dark`` / ``pillgray_light`` are mirrored; these were the last two
   places in the sheet still spelling those values out as raw hex. */
.bo-labor-pill--upw {
    border-color: var(--pillgray-dark);
    background-color: var(--pillgray-dark);
    color: #ffffff;
}

.bo-labor-pill--nu {
    border-color: #c9c9cc;
    background-color: var(--pillgray-light);
    color: var(--text_dark);
}

.bo-labor-pill--mixed {
    border-color: #a3a3a6;
    background-color: #B0B3B6;
    color: var(--text_dark);
}

.bo-labor-pill--empty {
    border-color: transparent;
    background: transparent;
    color: transparent;
}

/* Buyout Tracker — subcontractor pills are <button>s so they can open the
   per-sub project modal. Reset the native button chrome so they keep reading
   as pills; the per-pill inline style still supplies fill/border/radius. */
.bo-sub-pill-btn {
    width: 100%;
    font: inherit;
    line-height: inherit;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

.bo-sub-pill-btn:hover {
    filter: brightness(0.97);
}

/* Buyout Tracker — Awarded Subcontractor Timeline pills are also <button>s
   that open the per-sub modal. Reset native button chrome but DON'T force
   full width (unlike .bo-sub-pill-btn): the timeline pill must stay sized to
   its label so the spine layout reads correctly. The pill's fill/border/
   radius still come from .bo-timeline-sub. */
.bo-timeline-sub-btn {
    font: inherit;
    line-height: inherit;
    /* !important so the pointer always wins over the UA button cursor and any
       lower-priority rule that might otherwise leave it as the default arrow. */
    cursor: pointer !important;
    -webkit-appearance: none;
    appearance: none;
}

.bo-timeline-sub-btn:hover {
    filter: brightness(0.97);
}

/* Buyout Tracker — a subcontractor's FIRST chronological appearance in the
   table just recolors the pill's existing 1px border to red (same
   thickness). !important to beat the inline border set by the builder. */
.bo-first-instance {
    border-color: var(--monconred) !important;
}

/* Buyout Tracker — cell whose source value is "N/A"/"NA" (no sub). A muted,
   hatched ghost chip so it reads clearly as not-applicable rather than as a
   subcontractor literally named "N/A". Non-clickable. */
.bo-na-pill {
    display: block;
    text-align: center;
    border-radius: 15px;
    padding: 0 6px;
    margin: 1px 2px;
    /* Match the sub-name pill height (PILL_MIN_HEIGHT / PILL_LINE_HEIGHT in
       buyout_tracker.py) so an N/A chip is the same height as a real sub
       pill and single-pill rows stay uniform. */
    box-sizing: border-box;
    line-height: 16px;
    min-height: 18px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--gray-500);
    font-style: italic;
    border: 1px dashed var(--gray-400);
    background: repeating-linear-gradient(
        45deg,
        var(--gray-150),
        var(--gray-150) 3px,
        transparent 3px,
        transparent 7px
    );
}

/* Buyout Tracker — "Not Req'd" cell marker. The source value '-----' means
   the trade isn't required for that project; rendered as a centered em-dash
   (mirroring the PDF export) so the cell reads as "not required" rather
   than as a blank/unbought gap. Dark + bold so the mark stays clearly
   visible against the surrounding pills instead of fading into the empty
   cells. Matches the sub-name pill height (PILL_MIN_HEIGHT /
   PILL_LINE_HEIGHT in buyout_tracker.py) so rows stay uniform. */
.bo-notreq-mark {
    display: block;
    box-sizing: border-box;
    text-align: center;
    line-height: 16px;
    min-height: 18px;
    padding: 0 6px;
    color: var(--gray-700);
    font-weight: 700;
}

/* Buyout Tracker — Awarded Subcontractor vertical timeline. A single spine
   (the items' shared left border) keeps every dot in-line; each dot is
   colored by subcontractor via an inline style from the builder. */
.bo-timeline {
    list-style: none;
    margin: 0;
    padding: 0 0 0 6px;
}

.bo-timeline-item {
    position: relative;
    padding: 6px 0 6px 22px;
    border-left: 2px solid var(--gray-300);
    margin-left: 5px;
    display: flex;
    align-items: baseline;
    gap: 12px;
    font-size: var(--font_em_4);
    color: var(--text_dark);
}

.bo-timeline-item:last-child {
    /* keep the spine flush through the final dot */
    border-left-color: var(--gray-300);
}

.bo-timeline-dot {
    position: absolute;
    left: -7px;
    top: 9px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 1px solid var(--gray-800);
}

.bo-timeline-date {
    font-family: var(--tablefont_mono);
    color: var(--gray-500);
    min-width: 62px;
    flex: 0 0 auto;
}

.bo-timeline-sub {
    font-family: var(--headingfont);
    flex: 0 0 auto;
    /* Colored pill matching the timeline dot; background is set inline
       per-item from the subcontractor color map. */
    display: inline-block;
    padding: 0 8px;
    border-radius: 15px;
    border: 1px solid var(--gray-800);
    color: var(--text_dark);
}

.bo-timeline-proj {
    color: var(--gray-500);
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Project Executive (PX) badge, shown in brackets on the right of each row. */
/* The contract value on a timeline entry, from the contracts database.
   The PX's quiet monospace treatment, in a fixed right-aligned slot so the
   figures line up down the timeline: the auto margin here (rather than on
   the PX) pulls both spans to the right edge, and each keeps a minimum
   width so a short PX or a missing CV cannot stagger its neighbours. The
   span renders empty where there is no value, which is what holds the
   slot. */
.bo-timeline-cv {
    font-family: var(--tablefont_mono);
    color: var(--gray-500);
    flex: 0 0 auto;
    margin-left: auto;
    min-width: 9em;
    text-align: right;
    padding-left: 8px;
    white-space: nowrap;
}

/* Record Commitments (admin): one row per trade — code, trade name, and
   the two committed-sub dropdowns, on a shared grid so they line up. */
.bo-scl-comrow {
    display: grid;
    grid-template-columns: 6em minmax(12em, 18em) 1fr 1fr;
    gap: 8px;
    align-items: center;
    padding: 2px 0;
}

.bo-scl-comrow .bo-scl-com-code {
    font-family: var(--tablefont_mono);
    white-space: nowrap;
}

.bo-scl-comhead {
    font-weight: 600;
    border-bottom: 1px solid var(--pt-border);
    padding: 4px 0;
    margin-top: 6px;
}

.bo-scl-comrow .Select-control,
.bo-scl-comrow .Select-menu-outer {
    font-size: var(--font_em_1, 0.85em);
}

.bo-timeline-px {
    font-family: var(--tablefont_mono);
    color: var(--gray-500);
    flex: 0 0 auto;
    min-width: 12em;
    text-align: right;
    padding-left: 8px;
    white-space: nowrap;
}

/* !!! ===============================================================================================================*/
/* !!! DASH_DATATABLE  */
/* ===================================================================================================================*/

.dash-header,
.dash-spreadsheet th {
    color: var(--text_dark) !important;
    background-color: var(--pt-body-medium) !important;
    font-family: var(--headingfont);
    font-size: var(--font_em_5A);
    text-align: left !important;
    border-left: none !important;
    border-right: none !important;
    border-top: none !important;
    border-bottom: 1px solid var(--pt-border-soft) !important;
}

.dash-cell,
.dash-spreadsheet td {
    color: var(--text_dark) !important;
    background-color: var(--pt-body) !important;
    font-family: var(--tablefont_mono);
    font-size: var(--font_em_5A);
    text-align: left !important;
    border: none !important;
    border-color: var(--pt-border-soft) !important;
    padding: 0 !important;
}

.dash-select-cell {
    border: none !important;
    background-color: transparent !important;
    text-align: left !important;
}

.dash-select-header {
    border: none !important;
    background-color: transparent !important;
}

#est_model2_input_table .tr {
    line-height: 12px !important;
}

input.input-active.unfocused.selectable.dash-cell-value {
    border: 1px solid var(--pt-border) !important;
    border-radius: 6px !important;
    padding: 0.3em 0.6em !important;
    margin: 0 !important;
    width: 100%;
    color: green !important;
}

.dash-cell-value-container {
    box-sizing: border-box !important;
    height: 100% !important;
    padding: 0.3em 0.6em !important;
    margin: 0 !important;
    text-align: right !important;
}

.dash-cell.column-6:hover {
    cursor: pointer;
}

.dash-spreadsheet tbody tr {
    background-color: transparent !important;
}

.dash-spreadsheet tr {
    height: 6px !important;
}
.dash-spreadsheet tbody tr:nth-child(even) {
    background-color: var(--pt-body-medium) !important;
}

/* !!! ===============================================================================================================*/
/* !!! MATHJAX  */
/* ===================================================================================================================*/

.mjx-chtml {
    font-size: var(--font_em_2) !important;
}

/* !!! ===============================================================================================================*/
/* !!! MODAL  */
/* ===================================================================================================================*/
/* ONE set of rules governs every dbc.Modal in the app. All modals:
   - fill the viewport and center their dialog (no top-anchored variants),
   - share the same dialog width (90% of viewport, capped at 1200px — the
     widest treatment the project-info / staff / buyout modals used to own),
   - carry symmetric 2rem gutters on all four sides of the content box,
   - float the close X in the top-right corner *gutter* (absolutely
     positioned) so it never shoves the title band or body content over.
   Do NOT re-introduce per-modal width/positioning classes; if a modal needs
   to look different, that difference belongs here, stated globally. */

.modal {
    position: fixed !important;
    top: 0 !important;
    left: 0 !important;
    width: 100% !important;
    height: 100% !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    transform: none !important;
    margin: 0 !important;
    overflow: visible !important;
    outline: 0;
}

.modal-dialog {
    position: relative;
    width: 90%;
    max-width: 1200px;
    margin: 0;
    pointer-events: none;
}

.modal.fade .modal-dialog {
    transition: transform 0.3s ease-out;
    transform: translate(0, -50px);
}

@media (prefers-reduced-motion: reduce) {
    .modal.fade .modal-dialog {
        transition: none;
    }
}

.modal.show .modal-dialog {
    transform: none;
}

.modal.modal-static .modal-dialog {
    transform: scale(1.02);
}

.modal-dialog-centered {
    display: flex;
    align-items: center;
}

/* The content box scrolls as a whole (header included) once it exceeds
   80vh — the behavior the project-info modal established. `scrollable=True`
   on individual dbc.Modal components is therefore a no-op by design. */
.modal-content {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-height: 80vh;
    overflow-y: auto;
    pointer-events: auto;
    background: var(--gray-025);
    box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
    border-radius: 7px;
    /* Symmetric gutters: sides + bottom here, top via .modal-header. */
    padding: 0 2rem 2rem;
    text-align: left;
}

/* Header supplies the top gutter (2rem, matching the side/bottom padding
   of .modal-content) so the title band's top red hairline sits the same
   distance from the modal's top edge as the body does from its sides.
   No font-size is set here — the pt-red-title-band inside resets to 1rem
   so its typography matches the page-level bands exactly. */
.modal-header {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: space-between;
    padding: 2rem 0 0.5rem;
    font-family: var(--headingfont);
    color: var(--text_dark);
}

/* First child of the header (the title band) owns the full width; the
   close X is lifted out of the flex flow below so it can't compress it. */
.modal-header > :first-child {
    flex: 1 1 auto;
    min-width: 0;
}

/* Close X: absolutely positioned in the top-right corner gutter of
   .modal-content (the nearest positioned ancestor), clear of the title
   band which starts 2rem down. Bootstrap's CSS (not loaded here) normally
   paints the X as a background-image, so we draw our own glyph. */
.modal-header .btn-close {
    position: absolute;
    top: 0.45rem;
    right: 0.55rem;
    width: 1.4rem;
    height: 1.4rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    margin: 0;
    border: none;
    background: transparent;
    border-radius: 4px;
    cursor: pointer;
    z-index: 10;
}

.modal-header .btn-close::before {
    content: '\00d7';
    font-family: var(--textfont);
    font-size: 1.35rem;
    line-height: 1;
    color: var(--gray-500);
}

.modal-header .btn-close:hover::before {
    color: var(--monconred);
}

.modal-title {
    margin-bottom: 0;
}

.modal-footer {
    display: flex;
    flex-shrink: 0;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
}

/* !!! ________Modal_pdf_export_options
   Small confirm-style dialog that stacks on top of a report modal (the staff
   resume) to collect export toggles before the PDF is built. The global
   .modal-dialog sizing above is tuned for content modals, so it is narrowed
   here rather than letting a two-checkbox prompt span 1200px. */
.pdf-options-modal .modal-dialog {
    width: auto;
    max-width: 440px;
}

.pdf-options-modal .modal-content {
    padding: 0 1.5rem 1.25rem;
}

.pdf-options-modal .modal-header {
    padding-top: 1.5rem;
}

.pdf-options-modal .cklst > label {
    align-items: center;
    gap: 8px;
    padding: 4px 0;
    cursor: pointer;
}

.pdf-options-modal .modal-footer {
    gap: 10px;
    padding-top: 1rem;
}

.pdf-options-note {
    margin: 10px 0 0;
    font-family: var(--textfont);
    font-size: var(--font_em_5);
    line-height: 1.45;
    color: var(--gray-600);
}

/* Muted counterpart to .button-download, for the non-committal half of a
   button pair (Cancel next to Download). */
.button-download.button-secondary {
    background-color: transparent !important;
    color: var(--gray-600) !important;
    border: 1px solid var(--gray-300) !important;
}

.button-download.button-secondary:hover {
    color: var(--text_dark) !important;
    border-color: var(--gray-500) !important;
}

/* !!! ===============================================================================================================*/
/* !!! SAFETY_SCOPE_PAGE */
/* ===================================================================================================================*/

.safetyscope {
    font-size: var(--font_em_3);
    color: var(--text_dark);
    margin-bottom: 0;
    margin-left: 0;
    margin-top: 0.25em;
    font-family: var(--textfont);
}

.safetyscope.type1 {
    font-family: var(--headingfont);
    font-size: var(--font_em_2);
    margin-top: 0.5em;
    border-bottom: 1px solid var(--pt-border);
}
.safetyscope.type2 {
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    margin-top: 1em;
    margin-left: 2em;
}
.safetyscope.type3 {
    font-size: var(--font_em_4);
    font-family: var(--headingfont);
    margin-left: 4em;
}
.safetyscope.type4 {
    font-size: var(--font_em_4);
    margin-left: 6em;
}
.safetyscope.type5 {
    font-size: var(--font_em_4);
    margin-left: 8em;
}
.safetyscope.type6 {
    font-size: var(--font_em_4);
    margin-left: 8em;
}

/* !!! ________Numbers */

.code-number-part.scope {
    color: var(--text_dark);
}

.code-number-part.scope.type3 {
    font-family: var(--tablefont_mono);
}

.code-number-part.scope.type1 {
    font-family: var(--headingfont) !important;
}

.code-number-part.scope.type3, .code-number-part.scope.type4, .code-number-part.scope.type5, .code-number-part.scope.type6 {
    color: var(--gray-300);
}

/* Master Scope page: numbers and their separating periods keep the
   same color as their line's text instead of the lighter grays used
   on Safety Scope (--gray-300 digits, --gray-400 periods). The ID
   scope beats the class-only gray rules. */
#master-scope-content .code-number-part.scope,
#master-scope-content .code-period {
    color: var(--text_dark);
}

/* Master Scope page: the shared classes give type5 and type6 the same
   8em indent, which flattens the two deepest levels into one column.
   Step type6 in so every level reads one step deeper than its parent. */
#master-scope-content .safetyscope.type6 {
    margin-left: 10em;
}

/* Master Scope page: rebalance the card's interior space. The stock
   .card has no top padding and only 0.8em at the sides, which — with
   the section H2's large 0.75em top margin and no filet rouge — reads
   as a tall empty band up top and text crowding the side edges. */
#master-scope-content {
    padding: 0 1.2em;
}

#master-scope-content .ms-section-heading {
    margin-top: 0.35em;
}

/* Alternates block: lines set to Alt drop out of their place in the
   division and collect here at the end, keeping their own numbers. The
   block is always in the DOM — the delegated handler moves rows in and
   out without a re-render — so it collapses to nothing while empty
   rather than leaving a stray heading behind. */
#master-scope-content .ms-alt-heading {
    font-family: var(--headingfont);
    font-size: var(--font_em_4);
    color: var(--text_dark);
    margin: 1.4em 0 0.4em;
    padding-top: 0.5em;
    border-top: 1px solid var(--pt-border);
}

#master-scope-content .ms-alt-block-empty {
    display: none;
}

/* Master Scope page: the scope rows are denser than a settings card,
   so the shared control tokens are re-scoped smaller here — every
   control-height consumer inside the main card (the row segmented
   controls, the inline edit input) compacts to row scale. The nav
   cards sit outside this element and keep the app-wide size. */
#master-scope-content {
    --control-height: 20px;
}

/* Master Scope page: each scope line is a flex row — the existing
   number/text/badge spans live in .ms-row-text on the left, and the
   App/NA/Alt/Excl segmented control forms an aligned column on the
   right. The type1..type6 margin-left indents still apply to the row,
   so the controls share one right edge while the text steps in.
   Centering (not flex-start) keeps text, Edit/Del buttons, and the
   segmented control on one visual midline. */
#master-scope-content .ms-row {
    display: flex;
    align-items: center;
    gap: 0.75em;
}

/* Text never wraps: rows keep a uniform single-line height, and long
   lines truncate with an ellipsis. Only the on-screen rendering is
   clipped — the full text still lives in the stores/template and goes
   out intact in the Excel export. min-width: 0 is what lets a flex
   child actually shrink below its content width so the clip engages. */
#master-scope-content .ms-row-text {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

#master-scope-content .ms-row .ms-scope-sel {
    flex: 0 0 auto;
}

/* Master Scope page: the nav card's View filter carries its own gap
   above. Segmented controls sit flush by default (margin-top: 0)
   because they normally follow an H5 label; this one sits straight
   under the section dropdown, so without it the two controls touch.
   6px is the gap the other stacked nav-card controls use. */
#ms-view-filter {
    margin-top: 6px;
    margin-bottom: 0;
}

/* A single class on the container hides the rows the current view
   leaves out, keyed to the ms-row-na class the server render and the
   delegated selection handler both maintain. Deliberately a plain descendant selector
   rather than :has() — a trade section runs to 500 rows and pays for
   any row-level :has() on every restyle. Hidden rows stay in the DOM
   so the NA cascade still reaches them. */
#master-scope-content.ms-view-notna .ms-row.ms-row-na,
#master-scope-content.ms-view-na .ms-row:not(.ms-row-na) {
    display: none;
}

/* The view filter's row count belongs on its own line under the
   control: the shared small-text class is display:inline, which
   otherwise flows it around the segmented control and breaks it
   mid-sentence. Collapses to nothing when the view shows everything. */
#ms-view-count {
    display: block;
    margin: 4px 0 0;
}

#ms-view-count:empty {
    display: none;
}

/* Empty state for a view that filters everything out (text supplied by
   the same handler). Empty by default, so it takes up no room. */
#master-scope-content .ms-view-empty:not(:empty) {
    color: var(--text_dark);
    font-family: var(--tablefont);
    font-size: var(--font_em_4A);
    padding: 8px 0 4px;
}

/* A line's text opens its detail modal, so it reads as clickable on
   hover. Underline rather than a color change: the text's own color
   already carries meaning (blue for edited, gray struck for NA). */
#master-scope-content .ms-row-text {
    cursor: pointer;
}

#master-scope-content .ms-row:hover .ms-row-text {
    text-decoration-line: underline;
    text-decoration-color: var(--pt-border);
    text-underline-offset: 2px;
}

/* Struck-through rows keep their strike and take the underline too. */
#master-scope-content .ms-row:hover .ms-row-text.ms-na,
#master-scope-content .ms-row:hover .ms-row-text.ms-excl {
    text-decoration-line: line-through underline;
}

/* Row detail modal: its five sections are level-2 sub-cards (the idiom
   from Moncon Stats and Precon Staffing). Inside a modal the page's
   figure/ground inverts — a page is gray with white cards, a modal is
   white — so the cards take the gray fill .card.level2 declares for
   itself, which the app-wide white-card rule would otherwise win. */
#ms-detail-modal .card.level2 {
    background-color: var(--gray-060) !important;
    padding: 0.2em 1em 1em;
    margin-bottom: 0.8em;
}

/* Row detail modal: label/value lines, then the same audit tables the
   history modal uses. The shared small-text class is display:inline, so
   each fact has to be made a block to sit on its own line. */
#ms-detail-modal .ms-detail-fact {
    display: block;
    margin: 0 0 3px;
}

/* Labels share a column so the values line up as a readable list. */
#ms-detail-modal .ms-detail-label {
    display: inline-block;
    min-width: 140px;
    font-family: var(--headingfont);
    color: var(--text_dark);
}

/* The line's own wording is the subject of the modal, so it's set
   larger than the facts around it and in the app's italic face — the
   same treatment .direct_quote_highlight gives quoted text. */
#ms-detail-modal .ms-detail-reads {
    font-family: var(--textfont_italic);
    font-size: var(--font_em_3A);
    margin: 2px 0 10px;
}

#ms-detail-modal .ms-detail-edit-input {
    width: 100%;
}

#ms-detail-modal h5 {
    margin-top: 14px;
}

#ms-detail-modal .ms-history-table {
    margin-bottom: 4px;
}

/* Master Scope page: hovering a line tints the whole flex row — text,
   Edit button, and segmented control alike — for easy tracking across
   the wide gap between text and controls. */
#master-scope-content .ms-row:hover {
    background-color: var(--gray-150);
    border-radius: 4px;
}

/* Master Scope page: the App/NA/Alt/Excl picker is four plain spans
   dressed as a chromeless segmented control — no border, no padding,
   no bottom margin — so it blends into the row while keeping the
   shared 20px control height. A framework segmented control, or even
   a real radio group, is too heavy here: a big trade section mounts
   one per row, so the markup is a bare div > span and the selection
   lives in the group's data-val attribute (see MS_SELECTION_JS in
   utils/subapps/master_scope.py). */
#master-scope-content .ms-scope-sel {
    display: inline-flex;
    align-items: center;
    height: var(--control-height);
    padding: 0;
    margin: 0;
    border: none;
}

/* Master Scope page: slightly smaller body text than the shared
   safetyscope sizing (one font token down per level) to keep the rows
   compact alongside the segmented controls. The control labels get a
   compensating bump so they hold their current visual size instead of
   shrinking with the row font. */
#master-scope-content .safetyscope.type2 {
    font-size: var(--font_em_3A);
}

#master-scope-content .safetyscope.type3,
#master-scope-content .safetyscope.type4,
#master-scope-content .safetyscope.type5,
#master-scope-content .safetyscope.type6 {
    font-size: var(--font_em_4A);
}

#master-scope-content .ms-scope-sel-label {
    color: var(--text_dark);
    font-family: var(--tablefont);
    font-size: 0.55em;
    /* The chromeless control has no border or inset, so the pill gets
       a 16px line box inside the 20px row control (the framed variant
       elsewhere subtracts 8px for its border and inset). */
    line-height: calc(var(--control-height) - 4px);
    padding: 0 10px;
    border-radius: calc(var(--control-radius) - 3px);
    white-space: nowrap;
    cursor: pointer;
    transition: var(--pt-transition);
}

#master-scope-content .ms-scope-sel-label[aria-checked="false"]:hover {
    background-color: var(--gray-200);
}

#master-scope-content .ms-scope-sel-label:focus-visible {
    outline: 2px solid var(--pt-accent-dark);
    outline-offset: 1px;
}

/* The section-title row (type2) carries a selection control too, but
   its row font is one token larger than the body rows (font_em_3A
   0.875em vs font_em_4A 0.75em) — so the em-based label size above
   would render its control ~17% bigger and push it out of column.
   Compensate: 0.55 × (0.75 / 0.875) ≈ 0.4714em lands the title row's
   labels at exactly the body rows' pixel size. */
#master-scope-content .safetyscope.type2 .ms-scope-sel-label {
    font-size: 0.4714em;
}

/* Master Scope page: the checked pill reads as a filled button, and
   its color says which selection is active. Semantic mapping — dark
   gray = applicable, light gray = N/A (two ramp steps apart so they
   read differently at a glance), amber = alternate, red = excluded.
   Amber has no palette token yet, so it's set literally here.

   Keyed to the pill's own aria-checked and its value, so the color
   follows the selection with no callback and no :has() — worth caring
   about at 500 rows per section, where either one costs real
   style-recalc time on every click. Keyed by value rather than by
   position, so adding an option or reordering SELECTION_OPTIONS
   (utils/subapps/master_scope.py) can't reshuffle the colors. */
#master-scope-content .ms-scope-sel-label[aria-checked="true"] {
    color: var(--text_color_dark);
    font-family: var(--buttonfont);
}

#master-scope-content .ms-scope-sel-label[data-v="App"][aria-checked="true"] {
    background-color: var(--gray-800);
}

#master-scope-content .ms-scope-sel-label[data-v="NA"][aria-checked="true"] {
    background-color: var(--gray-400);
}

#master-scope-content .ms-scope-sel-label[data-v="Alt"][aria-checked="true"] {
    background-color: #d97706;  /* alternate amber */
}

#master-scope-content .ms-scope-sel-label[data-v="Excl"][aria-checked="true"] {
    background-color: var(--monconred);
}

/* Blank: no decision recorded (imported projects carry this where the
   old sheet left a line unanswered). Reads as an outline rather than a
   fill — nothing has been chosen, and the line itself renders plainly. */
#master-scope-content .ms-scope-sel-label[data-v="Blank"][aria-checked="true"] {
    background-color: transparent;
    color: var(--text_dark);
    box-shadow: inset 0 0 0 1px var(--pt-border);
}

/* Read-only rows (project checked out by someone else): the control
   still shows the selection, muted, and stops inviting clicks. */
#master-scope-content .ms-scope-sel[data-ro="1"] .ms-scope-sel-label {
    cursor: default;
}

#master-scope-content .ms-scope-sel[data-ro="1"] .ms-scope-sel-label:hover {
    background-color: transparent;
}

#master-scope-content .ms-scope-sel[data-ro="1"] .ms-scope-sel-label[aria-checked="true"] {
    background-color: var(--pt-disabled-text);
}

/* Master Scope page: lines marked NA read as struck-out light gray.
   The inner spans (digits, periods, badges) carry their own color
   rules, so they're overridden explicitly alongside the wrapper. */
#master-scope-content .ms-row-text.ms-na,
#master-scope-content .ms-row-text.ms-na span,
#master-scope-content .ms-row-text.ms-na a {
    color: var(--gray-300);
    text-decoration: line-through;
}

/* Master Scope page: lines set to Alt read in italics. font-style on
   the wrapper inherits into every child span (numbers included); the
   body text picks a synthesized oblique of the GT-Pressura webfonts,
   which is close enough to the dedicated italic cut for this hint. */
#master-scope-content .ms-row-text.ms-alt {
    font-style: italic;
}

/* Master Scope page: lines marked Excl strike through the original
   text at full color and reveal the " - EXCLUDE" suffix. Decoration
   set on the wrapper propagates across its plain inline spans; the
   suffix and the annotation badges escape it because inline-blocks
   don't inherit ancestor text decoration. */
#master-scope-content .ms-excl-suffix {
    display: none;
}

#master-scope-content .ms-row-text.ms-excl {
    text-decoration: line-through;
}

#master-scope-content .ms-row-text.ms-excl .ms-excl-suffix {
    display: inline-block;
    text-decoration: none;
    margin-left: 0.4em;
    font-family: var(--headingfont);
}

/* An alternate leaves a pointer where it was: the line struck through
   like an exclusion, with "- See Alternates" escaping the strike, and
   no controls (those travel with the line into the Alternates block).
   Same strike/suffix mechanics as ms-excl above. */
#master-scope-content .ms-alt-ref .ms-row-text {
    text-decoration: line-through;
    color: var(--text_dark);
}

#master-scope-content .ms-alt-suffix {
    display: inline-block;
    text-decoration: none;
    margin-left: 0.4em;
    font-family: var(--headingfont);
}

/* Master Scope page: line editing. The Edit button is the app's
   standard .button1 outline pill, compacted to row height (its stock
   padding/margins are sized for card actions, not inline rows);
   session-edited text renders in the brand red; the inline input
   inherits the row's typography so editing feels in-place. */
#master-scope-content .ms-edit-btn {
    flex: 0 0 auto;
    padding: 1px 0.6em;
    margin: 0;
    font-size: 0.55em;
    line-height: 1.4;
}

/* The '+' is a glyph, not a word, and at the row buttons' 0.55em it
   reads as a speck. Scaling the type alone would grow the button with
   it (its height is font-size x line-height), so the larger glyph is
   paired with a line-height that gives the box back: same footprint as
   Edit / Del beside it, a plus you can actually see and hit. */
#master-scope-content .ms-add-btn {
    font-size: 1.05em;
    line-height: 0.65;
    padding: 1px 0.19em 2px;
}

/* User-modified content — edited template text and added lines —
   reads in the app's blue accent. Internal notes and Specify flags
   are the exceptions and stay red (see their rules below). */
#master-scope-content .ms-edited,
#master-scope-content .ms-added {
    color: var(--pt-accent-dark);
}

/* Del sits leftmost in the row's control cluster (see master_scope.py:
   it's prepended to the buttons list) so the Edit / '+' / segmented
   control columns stay put whether or not a row is deletable. */
#master-scope-content .ms-del-btn {
    color: var(--monconred);
    border-color: var(--monconred-line);
}

/* Master Scope nav card: the new-project name input sits between the
   project dropdown and its Create button. */
.card.nav .ms-new-project-input {
    display: block;
    width: 100%;       /* same footprint as the dropdown above it */
    box-sizing: border-box;
    margin-top: 0.5em;
}

/* Master Scope "Specify" flag: plain red inline text (no pill) after
   the row text, at the row's own font size so it sits on the same
   baseline. */
#master-scope-content .ms-specify-flag {
    color: var(--monconred);
    margin-left: 0.5em;
}

/* The flag marks an *unresolved* fill-in line, so it disappears once
   the row is resolved by deselection — NA or Excl (the ms-na/ms-excl
   classes are toggled live clientside, so the flag hides instantly
   with the strikethrough). Resolution by text edit is handled
   server-side in the render callback. */
#master-scope-content .ms-row-text.ms-na .ms-specify-flag,
#master-scope-content .ms-row-text.ms-excl .ms-specify-flag {
    display: none;
}

/* Master Scope internal notes: user-added lines classified as internal
   in the add-line modal. Un-numbered, with a light blue highlight
   hugging the text and a bold INTERNAL NOTE tag up front. Internal
   notes stay red — the exception to the blue user-modified text
   above. */
#master-scope-content .ms-internal-note {
    background-color: var(--lightblue);
    padding: 0 5px;
    border-radius: 3px;
}

#master-scope-content .ms-internal-note .ms-added {
    color: var(--monconred);
}

#master-scope-content .ms-internal-tag {
    font-weight: 700;
    color: var(--monconred);
}

/* Add-line modal (opened by the rows' '+' buttons): full-width text
   input over the External/Internal picker. */
#ms-add-modal .ms-add-modal-text {
    width: 100%;
    margin-bottom: 10px;
}

/* Commit-to-master slot, present on every editable row and filled only
   where there's an edit to promote (see master_button_children). The
   row is a flex line with a gap, so an empty slot has to generate no
   box at all or every unedited row would carry a phantom column. */
#master-scope-content .ms-row-master:empty {
    display: none;
}

#master-scope-content .ms-row-master {
    flex: 0 0 auto;
    display: inline-flex;
}

/* Commit-to-master modal (opened by an edited line's 'Master' button):
   the template's current wording beside the text about to replace it,
   then the password gate. Both are shown in the scope table's own face
   so they read exactly as they will on the page — the replacement in
   the accent that marks user-modified text. */
#ms-master-modal .ms-master-old,
#ms-master-modal .ms-master-new {
    font-family: var(--tablefont);
    font-size: var(--font_em_5A);
    margin: 0 0 10px;
}

#ms-master-modal .ms-master-old {
    color: var(--text_dark);
}

#ms-master-modal .ms-master-new {
    color: var(--pt-accent-dark);
}

/* A password is short — sized like an ordinary field rather than
   stretched across the modal. */
#ms-master-modal .ms-master-password {
    width: 220px;
    max-width: 100%;
    margin-bottom: 6px;
}

/* The shared small-text class is display:inline, which would otherwise
   tuck this note alongside the password field. */
#ms-master-modal .ms-master-note {
    display: block;
    margin: 2px 0 0;
}

/* Prior commits to the line, in the same audit-table treatment as the
   project change history. Collapses to nothing for a line still on its
   original wording, and scrolls rather than growing the modal for a
   line that's been rewritten many times. */
#ms-master-modal .ms-master-history:not(:empty) {
    margin-top: 10px;
    max-height: 160px;
    overflow-y: auto;
}

/* Wrong password / failed write. Empty until then, so it takes up no
   room in the modal. */
#ms-master-modal .ms-master-msg:not(:empty) {
    font-family: var(--tablefont);
    font-size: var(--font_em_5A);
    color: var(--monconred);
    margin: 6px 0 0;
}

/* Master Scope change-history modal: a compact audit-trail table
   (when / user / section / row / action / from / to). */
.ms-history-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--font_em_5A);
}

.ms-history-table th {
    text-align: left;
    font-family: var(--headingfont);
    border-bottom: 2px solid var(--gray-900);
    padding: 4px 8px;
    white-space: nowrap;
}

.ms-history-table td {
    border-bottom: 1px solid var(--gray-300);
    padding: 4px 8px;
    vertical-align: top;
}

/* Master Scope page: user-added lines get a vertical marker bar in
   the left margin, matching their text color — blue for external
   added lines, red for internal notes. Drawn absolutely so it
   doesn't shift the row's text alignment. */
#master-scope-content .ms-row-added {
    position: relative;
}

#master-scope-content .ms-row-added::before {
    content: '';
    position: absolute;
    left: -0.75em;
    top: 2px;
    bottom: 2px;
    width: 3px;
    border-radius: 2px;
    background-color: var(--pt-accent-dark);
}

#master-scope-content .ms-row-internal::before {
    background-color: var(--monconred);
}

/* Editing happens in place, so the input wears none of the shared
   .input2 chrome: no frame, no fill, no radius, and the same box as the
   text it replaces. Without this the line gained a full-width rounded
   border, the row grew from 16px to 24px, and the words shifted right
   by the input's padding the moment Edit was clicked. */
#master-scope-content .ms-edit-input {
    width: 100%;
    font-size: inherit;
    font-family: inherit;
    color: var(--pt-accent-dark);
    border: none;
    border-radius: 0;
    background-color: transparent;
    box-shadow: none;
    height: auto;
    line-height: inherit;
    padding: 0;
    margin: 0;
}

/* !!! ________Other */

[class^="level"] .highlight {
    font-size: inherit;
    color: inherit;
}

.before-Pipe {
    font-Family: 'GT-Pressura-Mono-Regular', sans-serif;
}

.topic_highlight_ss {
    font-family: var(--mediumfont);
}

/* !!! ===============================================================================================================*/
/* !!! DISABLED_ELEMENTS  */
/* ===================================================================================================================*/

/* !!! ________Card */

.card.disabled,
.card.disabled > * {
    background-color: var(--pt-disabled-bg) !important;
}

.card.disabled,
.card.disabled *:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) {
    color: var(--pt-disabled-text);
}

.card.disabled h1,
.card.disabled h2,
.card.disabled h3,
.card.disabled h4,
.card.disabled h5,
.card.disabled h6,
.card.disabled p,
.card.disabled span,
.card.disabled label {
    color: var(--pt-disabled-text) !important;
}

/* !!! ________Slider */

.card.disabled .mantine-Slider-bar {
    background-color: var(--pt-disabled-border);
}

.card.disabled .mantine-Slider-thumb {
    background-color: var(--pt-disabled-text);
    border-color: var(--pt-border-soft);
}

.card.disabled .mantine-Slider-track {
    background-color: var(--gray-200);
}

/* !!! ________Segmented_Control */

.card.disabled .mantine-SegmentedControl-labelActive {
    background-color: var(--pt-disabled-text) !important;
    color: var(--text_color_dark) !important;
}

.card.disabled .mantine-SegmentedControl-root {
    border-color: var(--pt-disabled-text) !important;
}

/* !!! ===============================================================================================================*/
/* !!! PT_DROPDOWN_LINK */
/* ===================================================================================================================*/

/* Drawer dropdown items: sized to match .PT_navbar pills — small text, tight
   padding, so the drawer feels consistent with the top nav.
   The only hover affordance is the border-radius morph — no arrow slide. */
.PT_dropdownLink.pt-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    text-decoration: none !important;
    color: var(--text_dark) !important;
    background-color: transparent;
    text-align: left;
    margin: 0;
    padding: 3px 10px;
    font-family: var(--textfont);
    font-size: var(--font_em_5);
    line-height: 1.35;
    transition:
        border-radius var(--button-link-transition-duration) var(--ease-standard),
        background-color var(--button-link-transition-duration) var(--ease-standard),
        color var(--button-link-transition-duration) ease;
    white-space: nowrap;
    box-sizing: border-box;
    overflow: hidden;
    text-overflow: ellipsis;
    border: 1px solid var(--pt-border) !important;
    border-radius: 2px;
    will-change: border-radius, background-color;
    cursor: pointer;
}

/* Inner <a> fills the pill so the whole area is clickable. */
.PT_dropdownLink-inner,
.PT_dropdownLink-inner:visited,
.PT_dropdownLink-inner:hover,
.PT_dropdownLink-inner:active {
    color: var(--text_dark) !important;
    text-decoration: none !important;
    display: flex;
    align-items: center;
    width: 100%;
    padding: 0;
}

.PT_dropdownLink.pt-btn:hover {
    border-radius: 18px;
}

.PT_dropdownLink .pt-btn__label {
    position: relative;
    z-index: 1;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Any stray arrow markup inside a drawer item is hidden and the label does not
   translate on hover — border-radius morph is the only hover affordance. */
.PT_dropdownLink .pt-btn__circle,
.PT_dropdownLink .pt-btn__arrow {
    display: none !important;
}

.PT_dropdownLink.pt-btn:hover .pt-btn__label {
    transform: none !important;
}

.card.nav .pt-btn {
    width: 100%;
}

/* !!! ===============================================================================================================*/
/* !!! DROPDOWN_DRAWER */
/* ===================================================================================================================*/

/* Header: withCloseButton=False means Mantine v5 renders no header at all,
   so this rule only matters if a header ever comes back — keep it flat. */
.mantine-Drawer-header {
    height: 3em !important;
    border-bottom: none !important;
}

/* Drawer surface: frosted glass matching the .PT_navbar recipe (same
   --pt-nav-bg tint token), with a stronger blur than the navbar because the
   drawer sits over arbitrary page content and its links need to stay
   legible. Bottom edge divider marks where the glass panel ends. */
.mantine-Drawer-drawer {
    border: none !important;
    border-bottom: 1px solid var(--pt-border-soft) !important;
    background-color: var(--pt-nav-bg) !important;
    border-radius: 0 !important;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12) !important;
    -webkit-backdrop-filter: blur(16px) saturate(1.2) brightness(1.02) !important;
    backdrop-filter: blur(16px) saturate(1.2) brightness(1.02) !important;
}

/* No backdrop darkening for the nav drawer: the overlay element must stay
   mounted (it is what makes click-outside close the drawer) but paints
   nothing. Both class names cover the Mantine v5 (Overlay-root) and v7
   (Drawer-overlay) DOM shapes. */
.mantine-Drawer-root .mantine-Overlay-root,
.mantine-Drawer-overlay {
    background-color: transparent !important;
    opacity: 1 !important;
}

/* Body: simple centered container. No text-level overrides here — those belong
   on the items themselves, not on the body. Top padding carries the offset the
   (now unrendered) 3em header used to provide, clearing the navbar strip so
   the section title is never hidden behind the main menu elements. */
.mantine-Drawer-body {
    padding: 4.5rem 2rem 2rem !important;
    color: var(--text_dark);
    display: flex;
    justify-content: center;
}

.mantine-Paper-root {
    border-radius: 0 !important;
    padding: 0 !important;
    box-shadow: none !important;
}

/* Mantine modal surfaces — flat */
.mantine-Modal-content,
.mantine-Modal-inner {
    box-shadow: none !important;
}

/* Inner wrapper: caps at main column but never exceeds available drawer width,
   so the grid always fits on screen regardless of viewport size. */
.drawer_inner_wrapper {
    width: 100%;
    max-width: min(100%, var(--main-col));
    display: flex;
    flex-direction: column;
    gap: 1rem;
    padding-left: 1em;
}

/* Nav-link grid: fixed 3 columns, tight-but-readable spacing, breathing room below */
.drawer_dropdown_grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.3rem 1rem;
    max-height: 60vh;
    overflow: auto;
    padding-bottom: 1.5rem;
}

/* Drawer items take the navbar-pill visual language: filled bg, no border,
   radius morphs on hover. Scoped to the drawer so the base .PT_dropdownLink
   styling used elsewhere (e.g. safety_scope section nav) is untouched. */
.drawer_dropdown_grid .PT_dropdownLink.pt-btn {
    width: 100%;
    margin: 0;
    padding: 5px 12px;
    font-family: var(--textfont);
    font-size: var(--font_em_5);
    line-height: 1.4;
    color: var(--text_dark) !important;
    background-color: var(--pt-nav-pill-bg) !important;
    border: none !important;
    border-radius: 0 !important;
    transition: var(--pill-morph-transition) !important;
}

.drawer_dropdown_grid .PT_dropdownLink.pt-btn:hover {
    background-color: var(--pt-nav-pill-bg-hover) !important;
    border-radius: 18px !important;
}

/* Disabled drawer items: shown so users know the page exists, but inert.
   No hover affordance, no pointer cursor, dimmed label. Scoped to the
   drawer grid so the base .PT_dropdownLink.disabled rule below covers other
   surfaces (e.g. fixed-section-nav). */
.drawer_dropdown_grid .PT_dropdownLink.pt-btn.disabled,
.drawer_dropdown_grid .PT_dropdownLink.pt-btn.disabled:hover {
    background-color: var(--pt-nav-pill-bg) !important;
    border-radius: 0 !important;
    cursor: not-allowed;
    opacity: 0.45;
    pointer-events: none;
}

.drawer_dropdown_grid .PT_dropdownLink.pt-btn.disabled .pt-btn__label,
.drawer_dropdown_grid .PT_dropdownLink.pt-btn.disabled .PT_dropdownLink-inner {
    color: var(--text_dark) !important;
    text-decoration: line-through;
}

/* Generic disabled drawer pill — applies wherever a disabled PT_dropdownLink
   is rendered (covers any future surface that reuses the class). */
.PT_dropdownLink.pt-btn.disabled,
.PT_dropdownLink.pt-btn.disabled:hover {
    cursor: not-allowed;
    opacity: 0.45;
    pointer-events: none;
}

/* !!! ===============================================================================================================*/
/* !!! DASH_AG_GRID */
/* ===================================================================================================================*/

/* Essential structural elements */
.custom-grid-theme .ag-root-wrapper {
    border: none;
    font-family: var(--tablefont);

    color: var(--text_dark) !important;
    background-color: var(--pt-body) !important;
    font-size: var(--font_em_5);
}

.custom-grid-theme .ag-header {
    font-family: var(--headingfont);
    background-color: var(--pt-body-medium) !important;
    border-bottom: 1px solid var(--pt-border) !important;
}

.custom-grid-theme .ag-header-cell {
    padding-left: 3px;
    padding-right: 3px;
}

.custom-grid-theme .ag-row {
    line-height: 16px;
}

.custom-grid-theme .ag-row-odd {
    background-color: var(--pt-body-light) !important;
}

.custom-grid-theme .ag-row-even {
    background-color: var(--pt-body) !important;
}

.custom-grid-theme .ag-cell {
    overflow: hidden;
    text-overflow: ellipsis;
    padding-left: 3px;
    padding-right: 3px;
}

.ag-cell.mono-font {
    font-family: var(--tablefont_mono) !important;
}

/* Right-aligned numeric cells */
.custom-grid-theme .ag-numeric-cell {
    text-align: right;
}

/* Your custom modifications */
.custom-grid-theme .monospace-cell {
    font-family: var(--tablefont_mono);
}

.right-aligned-header .ag-header-cell-label {
    justify-content: flex-end !important;
}

/* !!! ===============================================================================================================*/
/* !!! MAIN_LAYOUT_ELEMENTS */
/* ===================================================================================================================*/

/* !!! ________Html / Body */

/* scroll-padding-top reserves space for the sticky navbar when :target jumps
   to an anchor, so the destination isn't hidden behind the bar.

   font-size here is the SINGLE fluid anchor for the whole app's type scale.
   Every --font_em_* token is em-based and ultimately cascades from body's
   1rem, so every text in the app breathes with viewport width because of
   this one clamp(). The preferred value is in rem so users who bump their
   browser's default size still get a proportional boost.

   Resolved values (assuming browser default 16px):
     800px  viewport → ~15.2px   (just above 15px floor)
     1366px viewport → ~16.0px   (current look, unchanged)
     1700px viewport → ~16.6px
     2560px viewport →   17px    (clamped ceiling) */
html {
    font-size: clamp(0.9375rem, 0.875rem + 0.15vw, 1.0625rem);
    scroll-padding-top: 200px;
}

body {
    background-color: var(--pt-body) !important;
    color: var(--text_dark);
    background-size: cover;
    background-position: center;
    overflow-y: auto;
    overflow-x: auto;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    padding: 0;
    margin: 0;
}

/* DO NOT set overflow on html — it breaks position: sticky on the navbar. */

/* !!! ________Wrapper */

.wrapper {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-height: 100vh;
    align-items: stretch;
}

/* Remove dense grid background on non-landing pages; open light fields */
.wrapper:not(.landing-page-active) {
    background-color: var(--pt-body);
    background-image: none;
}

/* Full-width app row (avoids narrow “shrink-to-content” column under align-items: center). */
.wrapper > .PT_navbar_wrapper,
.wrapper > .page,
.PT_navbar_wrapper > .PT_navbar {
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
}

/* Let .page grow to fill remaining wrapper height so the footer chain can reach the bottom. */
.wrapper > .page {
    flex-grow: 1;
}

/* create_layout footer wrapper: stretch like the rest of the page column. */
.layout-with-footer {
    display: flex;
    flex-direction: column;
    width: 100%;
    box-sizing: border-box;
    flex-grow: 1;
}

/* Push main content to grow, keeping footer pinned to the bottom of the viewport. */
.layout-with-footer > :first-child {
    flex-grow: 1;
}

/* background-attachment: fixed is avoided here for two reasons:
   1. It conflicts with backdrop-filter on the navbar (which creates a new stacking context),
      causing the image to only appear behind the header on many browsers.
   2. It is completely broken on iOS Safari.
   Instead, the image is painted as a position:fixed pseudo-element so it always covers
   the full viewport regardless of scroll depth, without any stacking-context conflicts.
   The background-color is a dark fallback shown instantly while the image loads.
   The hero photo lives in S3 (moncon-app-assets) so it does not bloat the repo;
   if you need to swap it, run `bin/add_static_asset IMG_0081.jpg --source <new>` and
   bump the ?v= cache buster below to the new version reported by the script. */
.wrapper.landing-page-active {
    background-color: var(--pt-body-dark);
    isolation: isolate;
}

.wrapper.landing-page-active::before {
    content: '';
    position: fixed;
    inset: 0;
    background-image: url('https://moncon-app-assets.s3.us-east-2.amazonaws.com/static/IMG_0081.jpg?v=1563580f');
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    z-index: -1;
    pointer-events: none;
    /* Alt palette: softer overlay, still readable */
    filter: brightness(0.55) saturate(0.9);
}

/* !!! ________Page */

/* Side tracks (1fr) absorb all free space; center column tracks --main-col whose clamp()
   holds the minimum, so sides compress to zero before the center shrinks. */
.page {
  display: grid;
  grid-template-columns:
    minmax(0, 1fr)
    minmax(0, min(100%, var(--main-col)))
    minmax(0, 1fr);
  column-gap: var(--gap);
  align-items: start;
}

/* !!! ________Navigation_Column */

.navigation_column {
    font-size: var(--font_em_3A);
    grid-column: 1;
    justify-self: end;
    width: var(--nav-width);
    position: sticky;
    top: var(--top-offset);
    z-index: 1000;
    padding-top: 1rem;
    padding-left: 0.5rem;
}

/* Collapse left column when it has no content — rightcol is always None in current layout. */
.navigation_column:empty {
    display: none;
    width: 0;
    padding: 0;
}

/* Also hide via hard-pixel media query (CSS variables are not valid in @media conditions). */
@media (max-width: 1120px) {
    .navigation_column {
        display: none;
        width: 0;
        padding: 0;
    }
}

/* Hide the Sections FAB on narrow screens where it overlaps content. */
@media (max-width: 800px) {
    .section-nav-fab-root {
        display: none;
    }
}

/* !!! ________Main_container */

.main-container {
  grid-column: 2;
  width: 100%;
  max-width: var(--main-col);
  margin: 0;
  margin-inline: auto;
  box-sizing: border-box;
  font-size: var(--font_em_3);
  padding-left: 2px;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  color: var(--text_dark);
}

#page-content {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
}

/* !!! ________Section */

/* Alt palette: match page background (no alternating band) */
.section.even_section {
    --full-width: calc(50vw - 50%);
    margin-left: calc(-1 * var(--full-width));
    margin-right: calc(-1 * var(--full-width));
    padding-left: var(--full-width);
    padding-right: var(--full-width);
    padding-top: 1em;
    background-color: var(--pt-body) !important;
}

/* !!! ________Content Container */

.content_container {
    display: flex;
    flex-direction: row;
    width: 100%;
    gap: 1.25em;
    margin-top: 1em;
}

/* !!! ________Content */

.content {
    flex: 1; /* Takes up all available space */
    min-width: 0; /* Prevents overflow issues */
}

/* !!! ________Content_Settings */

.content_settings {
    flex: 0 1 auto;
    min-width: 0;
    flex-basis: 15%;
    max-width: 25%;
}

/* !!! ________PT_navbar */

/* Sit below top edge and slightly in from sides — content behind stays visible */
#PT_navbar_wrapper.PT_navbar_wrapper,
.PT_navbar_wrapper {
    font-size: var(--font_em_3A);
    position: sticky !important;
    top: 0.25rem !important;
    display: flex;
    flex-direction: column;
    width: 100%;
    align-items: stretch;
    z-index: 99999;
    padding: 0.325rem 1.125rem 0 !important;
    box-sizing: border-box !important;

}

/* Full-width bar — no grid here. Content centering is delegated to .PT_navbar_main
   using the same max-width + margin-inline: auto as .main-container, so the two
   always stay in sync regardless of scrollbars or sticky-positioning quirks. */
/* Frosted-glass strip: token-driven background, rounded lip */
.PT_navbar {
    position: sticky !important;
    top: 0 !important;
    z-index: 9999 !important;
    display: block;
    width: 100%;
    background: var(--pt-nav-bg) !important;
    backdrop-filter: blur(6px) saturate(1.12) brightness(1.02) !important;
    -webkit-backdrop-filter: blur(8px) saturate(1.12) brightness(1.02) !important;
    border: none !important;
    border-bottom: none !important;
    /* Only the top bar is rounded; cards / controls elsewhere stay square */
    border-radius: 12px !important;
    overflow: hidden;
    color: var(--text_dark);
    transition:
        background-color var(--button-link-transition-duration) ease-in-out,
        backdrop-filter var(--button-link-transition-duration) ease-in-out,
        box-shadow var(--button-link-transition-duration) ease-in-out;
}

/* Landing pages (/, /home, /login, /landing) — two-class selectors are more specific */
.PT_navbar_landing.PT_navbar,
.PT_navbar.PT_navbar_landing {
    background: var(--pt-nav-bg-landing) !important;
    backdrop-filter: blur(4px) saturate(1.12) brightness(1.05) !important;
    -webkit-backdrop-filter: blur(4px) saturate(1.12) brightness(1.05) !important;
    border-bottom: none !important;
}

.PT_navbar:hover {
    box-shadow: 0 0 0 1px var(--pt-border) !important;
}

.PT_navbar_landing.PT_navbar:hover {
    background: var(--pt-nav-bg-landing-hover) !important;
}

/* While a top drawer is open (Mantine mounts .mantine-Drawer-root only when
   opened), the navbar goes fully transparent so the drawer surface reads as
   one continuous panel with the nav strip. */
body:has(.mantine-Drawer-root) .PT_navbar,
body:has(.mantine-Drawer-root) .PT_navbar.PT_navbar_landing,
body:has(.mantine-Drawer-root) .PT_navbar:hover,
body:has(.mantine-Drawer-root) .PT_navbar.PT_navbar_landing:hover {
    background: transparent !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    box-shadow: none !important;
}

.PT_navbar_section_nav::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: linear-gradient(to bottom,
    hsla(100, 15%, 85%, .05),
    hsla(100, 10%, 80%, .05));
    border-radius: 10px;
    pointer-events: none;
}

.PT_navbar > * {
    display: flex;
    align-items: center;
    height: 100%;
}

/* Mirrors .main-container's centering exactly: same max-width + margin-inline: auto.
   This guarantees the logo left edge and logout right edge are always flush with
   the page content below, at every viewport width. */
.PT_navbar > .PT_navbar_main {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    width: 100%;
    max-width: var(--main-col);
    margin: 0;
    margin-inline: auto;
    min-width: 0;
    box-sizing: border-box;
    column-gap: 0.35rem;
    padding-left: 2px;
}

.PT_navbar.scrolled .title {
    opacity: 0;
}

.PT_navbar_leftcontent {
    flex: 0 0 auto;
    margin-right: auto;
    align-items: center;
    min-width: 0;
}

.PT_navbar_rightcontent {
    flex: 1 1 0;
    margin-left: 0;
    min-width: 0;
    max-width: 100%;
    text-align: right;
    justify-content: flex-end;
}

.PT_navbar_menu_wrapper {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: flex-end;
    align-items: center;
    text-align: right;
    padding: 0;
    margin: 0;
    min-width: 0;
    flex: 1 1 auto;
    max-width: 100%;
    column-gap: 6px;
}

/* Scroll category buttons inside the bar; logout stays pinned to the right edge of the main column. */
.PT_navbar_nav_items {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    min-width: 0;
    flex: 1 1 auto;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    padding-bottom: 2px;
}

.PT_navbar_nav_items::-webkit-scrollbar {
    height: 4px;
}

.PT_navbar_nav_items::-webkit-scrollbar-thumb {
    background: rgba(30, 33, 36, 0.35);
    border-radius: 4px;
}

/* Navbar pills: slightly tighter than app-wide .button-menu defaults so more fit before scroll.
   font-size uses the --font_em_5 token (0.65em). Because it's em and the root html font-size
   is fluid (clamp()), pill text scales smoothly with viewport width — no per-breakpoint
   font-size overrides needed. */
/* Lighter GT Pressura cut for nav labels (--textfont = Standard Light) */
.PT_navbar .button-menu.pt-btn {
    min-width: 0;
    max-width: 12rem;
    margin: 4px 6px 4px 0;
    padding: 3px 10px 3px 10px;
    height: auto;
    font-size: var(--font_em_5);
    font-family: var(--textfont) !important;
}

.PT_navbar .button-menu.pt-btn .pt-btn__label {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Tighten spacing and pill width when the main column gets crowded. Font size already handled
   by the clamp() above — no font-size override needed here. */
@media (max-width: 1500px) {
    .PT_navbar .button-menu.pt-btn {
        max-width: 9rem;
        padding: 2px 5px 2px 7px;
        margin-right: 1px;
    }
    .PT_navbar_nav_items {
        gap: 2px;
    }
}

@media (max-width: 1280px) {
    .PT_navbar .button-menu.pt-btn {
        max-width: 7rem;
    }
}

/* Top menu: no sliding-arrow animation (avoids overlap on narrow pills); simple hover only. */
.PT_navbar .button-menu.pt-btn .pt-btn__circle {
    display: none !important;
}

.PT_navbar .button-menu.pt-btn:hover .pt-btn__label {
    transform: none !important;
}

.PT_navbar .button-menu.pt-btn:not(.dark) {
    border: none !important;
    color: var(--text_dark) !important;
    background-color: var(--pt-nav-pill-bg) !important;
    border-radius: 0 !important;
    transition: var(--pill-morph-transition) !important;
}

.PT_navbar .button-menu.pt-btn:not(.dark):hover {
    background-color: var(--pt-nav-pill-bg-hover) !important;
    border: none !important;
    color: var(--text_dark) !important;
    border-radius: 18px !important;
}

/* Logout / secondary: same pill language + hover radius */
.PT_navbar .button-menu.pt-btn.dark {
    background-color: var(--pt-nav-pill-bg) !important;
    color: var(--text_dark) !important;
    border: none !important;
    border-radius: 0 !important;
    transition: var(--pill-morph-transition) !important;
}

.PT_navbar .button-menu.pt-btn.dark:hover {
    background-color: var(--pt-nav-pill-bg-hover) !important;
    filter: none;
    color: var(--text_dark) !important;
    border-radius: 18px !important;
}

/* When the navbar itself is hovered, every pill flips to the dark button
   surface with light label text. The existing color/background transitions
   on each pill carry the animation. */
.PT_navbar:hover .button-menu.pt-btn,
.PT_navbar:hover .button-menu.pt-btn.dark,
.PT_navbar:hover .button-menu.pt-btn:not(.dark),
.PT_navbar:hover .button-menu.pt-btn:hover,
.PT_navbar:hover .button-menu.pt-btn.dark:hover,
.PT_navbar:hover .button-menu.pt-btn:not(.dark):hover {
    background-color: var(--button_color_dark) !important;
    color: var(--text_color_dark) !important;
}

.PT_navbar:hover .button-menu.pt-btn .pt-btn__label {
    color: var(--text_color_dark) !important;
}

/* Keep the arrow/logout icons legible against the dark fill during navbar hover */
.PT_navbar:hover .button-menu.pt-btn .pt-btn__icon,
.PT_navbar:hover .button-menu.pt-btn.dark .pt-btn__icon {
    filter: brightness(0) invert(1);
    opacity: 0.85;
}

/* Navbar logo: paint the shape via mask + background-color so the color is
   transitionable. The <img src="/assets/logo.svg"> normally blocks CSS from
   reaching the SVG's inner <path fill>, so we neutralize the img's own pixels
   with a transparent SVG of the same viewBox (preserves intrinsic aspect /
   40px layout height set in main_layout.py) and let background-color fill the
   masked shape. Default is the logo's original gray (#4a4d51); on navbar hover
   this lerps to MonCon red. Applies to both regular and landing variants. */
.PT_navbar #navbar-logo {
    content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 150.92 47'/>");
    background-color: #4a4d51;
    -webkit-mask: url('/assets/logo.svg') no-repeat center / contain;
            mask: url('/assets/logo.svg') no-repeat center / contain;
    filter: none;
    opacity: 1;
    transition: background-color var(--button-link-transition-duration) ease-in-out;
    cursor: pointer;
}

/* The logo is wrapped in <a href="/login"> (see main_layout.py). The
   content:url() replacement above plus overflow:hidden on .logo-container can
   suppress the default anchor pointer in some browsers, so set it explicitly
   on the container and its anchor child. */
.logo-container,
.logo-container > a,
.logo-container > a > img {
    cursor: pointer;
}

.PT_navbar:hover #navbar-logo,
body:has(.section-nav-fab-details > summary.section-nav-fab-toggle:hover) .PT_navbar #navbar-logo {
    background-color: var(--monconred);
}

/* Arrows in pills: dark on light gray */
.PT_navbar .pt-btn__icon {
    filter: none;
    opacity: 0.75;
}

/* Logout uses white SVG — invert to dark on light-gray pill */
.PT_navbar .button-menu.pt-btn.dark .pt-btn__icon {
    filter: brightness(0);
    opacity: 0.65;
}

/* Logout block stays pinned to the right; category buttons live in the scrollable region.
   display:flex + align-items:center prevents the invisible Dash Location/redirect divs
   inside the logout wrapper from adding phantom height that misaligns the button. */
.PT_navbar_menu_wrapper > div:not(.PT_navbar_nav_items) {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
}

.PT_navbar_nav_items > div {
    flex: 0 0 auto;
}

/* !!! ________Footer */

.footer_section {
    background-color: var(--gray-700);
    margin-top: 3em;
    width: 100vw;
    position: relative;
    left: 50%;
    right: 50%;
    margin-left: -50vw;
    margin-right: -50vw;
    box-sizing: border-box;
}

.footer_container {
    width: min(100%, var(--main-col));
    max-width: 100%;
    margin-inline: auto;
    margin: 0 auto;
    display: flex;
    flex-direction: row;
    gap: 20px;
    padding-bottom: 3em;
    box-sizing: border-box;
}

.footer_container h4,
#page-content .footer_container h4,
.main-container .footer_container h4 {
    margin-top: 2em;
    /* Force light text — ID-qualified variant beats the #page-content / .main-container h4
       rule later in this file, which also carries !important. */
    color: var(--text_color_dark) !important;
}
.footer_section .span_1,
.footer_section .span_2 {
    color: var(--text_color_dark);
}

.footer-meta-item {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.footer-meta-item .footer-meta-date {
    margin-top: auto;
}

/* Footer columns: metadata on the left grows to fill available width; the
   user-types column on the right stays compact since it's just a vertical
   list. ``.footer_container`` is already ``display: flex; flex-direction:
   row;`` (see above), so the two ``.content`` children are flex siblings.

   We can't add classes to the inner ``.content`` divs without changing
   create_layout's signature, so we target the wrappers around the known
   inner blocks (``.dataframe_status_div`` for metadata,
   ``.footer-access-col`` for user types) and lift the flex sizing onto
   their parent ``.content`` via :has(). */
.footer_container > .content:has(> .dataframe_status_div:not(.footer-access-col)) {
    flex: 1 1 auto;
    min-width: 0;
}

.footer_container > .content:has(> .footer-access-col) {
    flex: 0 0 auto;
}

.footer-access-col {
    min-width: 12em;
}

.footer-access-list {
    list-style: disc;
    padding-left: 1.25em;
    margin: 0;
}

.footer-access-list li {
    margin: 2px 0;
}

.footer-access-empty {
    margin-top: 6px;
}

.col, [class^="col-"], [class*=" col-"] {
    transition: none;
}

/* !!! ________Side_Navbar */

.fixed-section-nav {
    padding: 0 0.75em 0.75em;
    max-height: calc(100vh - 40px);
    scrollbar-width: none;
    -ms-overflow-style: none;
    backdrop-filter: blur(10px);
    background-color: var(--light_transparent_gray);
    border-radius: 10px;
    position: relative;
    overflow-x: hidden;
    transition: all var(--button-link-transition-duration) ease-in-out;
}

.fixed-section-nav:hover {
    background-color: var(--gray-025);
}

.section_nav_container {
    display: flex;
    flex-direction: column;
    gap: 3px;
    position: relative;
}

.fixed-section-nav .PT_dropdownLink.active {
    font-family: var(--headingfont);
}

/* Active-item rail: a 3px red bar hugging the left edge of the active link.
   Host is already position:relative (see .PT_dropdownLink.pt-btn) so the
   pseudo anchors cleanly without disturbing padding or the 1px border. */
.fixed-section-nav .PT_dropdownLink.active::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 4px;
    bottom: 4px;
    width: 3px;
    background-color: var(--monconred);
    border-radius: 2px;
    pointer-events: none;
}

/* --- Section navigation: floating <details> TOC (see _build_section_nav_drawer) --- */

/* Fixed pill at bottom-left; expands a panel upward when clicked. */
.section-nav-fab-root {
    position: fixed;
    bottom: 4rem;
    left: 1.75rem;
    z-index: 2000;
}

.section-nav-fab-details {
    /* override .fixed-section-nav defaults so they don't interfere */
    position: static;
    max-height: none;
    overflow: visible;
    background: transparent;
    backdrop-filter: none;
    border-radius: 0;
    padding: 0;
}

/* The summary row is the visible "Sections" pill. Idle surface mirrors the
   .PT_navbar frosted-glass look (same --pt-nav-bg + backdrop-filter + radius,
   no border). Hover adds the same 1px ring as .PT_navbar:hover instead of a
   background shift. */
.section-nav-fab-details > summary.section-nav-fab-toggle {
    display: inline-flex;
    align-items: center;
    padding: 0.3rem 0.75rem;
    font-size: var(--font_em_4A);
    font-family: var(--headingfont);
    color: var(--text_dark);
    background: var(--pt-nav-bg);
    backdrop-filter: blur(6px) saturate(1.12) brightness(1.02);
    -webkit-backdrop-filter: blur(8px) saturate(1.12) brightness(1.02);
    border: none;
    border-radius: 12px;
    cursor: pointer;
    user-select: none;
    list-style: none;
    transition:
        background-color var(--button-link-transition-duration) ease-in-out,
        backdrop-filter var(--button-link-transition-duration) ease-in-out,
        box-shadow var(--button-link-transition-duration) ease-in-out;
}

.section-nav-fab-details > summary.section-nav-fab-toggle::-webkit-details-marker { display: none; }
.section-nav-fab-details > summary.section-nav-fab-toggle::marker { display: none; }

/* Paired hover: hovering either the PT_navbar OR the Sections pill puts the
   1px outline ring on BOTH (cross-linked via :has()). Self-hover is also
   covered here so the ring shows regardless of :has() support. */
.section-nav-fab-details > summary.section-nav-fab-toggle:hover,
body:has(.PT_navbar:hover) .section-nav-fab-details > summary.section-nav-fab-toggle {
    box-shadow: 0 0 0 1px var(--pt-border);
}

body:has(.section-nav-fab-details > summary.section-nav-fab-toggle:hover) .PT_navbar {
    box-shadow: 0 0 0 1px var(--pt-border) !important;
}

/* Panel appears above the pill when open. */
.section-nav-fab-panel {
    position: absolute;
    bottom: calc(100% + 0.5rem);
    left: 0;
    min-width: 13rem;
    max-width: min(20rem, 90vw);
    max-height: 60vh;
    overflow-y: auto;
    background: var(--pt-body);
    border: 1px solid var(--gray-200);
    border-radius: 10px;
    padding: 0.6rem 0.75rem 0.5rem;
    box-shadow: 2px 6px 24px rgba(0,0,0,0.13);
    display: none;
}

.section-nav-fab-details[open] .section-nav-fab-panel {
    display: block;
}

.section-nav-fab-panel-title {
    display: block;
    font-family: var(--headingfont);
    font-size: var(--font_em_4);
    color: var(--text_dark);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 0.4rem;
}

.section-nav-fab-back {
    display: block;
    margin-top: 0.5rem;
    cursor: pointer;
}

/* Section link list — styled to match the top dropdown drawer items
   (.PT_dropdownLink.pt-btn): small text, thin border, radius-morph hover. */
.section-nav-drawer-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.section-nav-drawer-list li {
    margin: 0;
}

.section-nav-drawer-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    width: 100%;
    text-align: left;
    margin: 0;
    padding: 3px 10px;
    font-family: var(--textfont);
    font-size: var(--font_em_5);
    line-height: 1.35;
    color: var(--text_dark) !important;
    background-color: transparent;
    text-decoration: none !important;
    border: 1px solid var(--pt-border);
    border-radius: 2px;
    white-space: nowrap;
    box-sizing: border-box;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    will-change: border-radius, background-color;
    transition:
        border-radius var(--button-link-transition-duration) var(--ease-standard),
        background-color var(--button-link-transition-duration) var(--ease-standard),
        color var(--button-link-transition-duration) ease;
}

.section-nav-drawer-link:hover {
    border-radius: 18px;
    background-color: transparent;
}

.section-nav-drawer-link.active {
    font-family: var(--headingfont);
    border-color: var(--pt-border);
}

.section-nav-drawer-link.active::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 4px;
    bottom: 4px;
    width: 3px;
    background-color: var(--monconred);
    border-radius: 2px;
    pointer-events: none;
}

.section-nav-override-inner .section_nav_container {
    flex-direction: column;
}

/* !!! ===============================================================================================================*/
/* !!! MISC  */
/* ===================================================================================================================*/

.collapse_symbol {
    margin-left: 8px;
    margin-bottom: 4px;
    font-size: var(--font_em_4);
    transition: transform var(--button-link-transition-duration) ease-in-out;
}

.checkbox-wrapper {
    position: absolute;
    top: 0;
    right: 0;
    padding: 5px;
}

.dash-delete-cell {
    height: 12px;
}

.fa,
.fas {
    margin: 0;
    padding: 0;
}

#howto-md img {
    max-width: 100%;
}

/* !!! ________Logo_entry_animation */

.logo-container {
    overflow: hidden;
    align-items: center;
    padding: 0;
    margin: 4px;
}

.rising-logo {
    animation: rise 1.5s ease-out forwards;
    position: relative;
    align-items: center;
}

.img {
    align-items: center;
}

@keyframes rise {
    0% {
        transform: translateY(100%);
        opacity: 0;
    }
    100% {
        transform: translateY(0);
        opacity: 1;
    }
}

/* !!! ===============================================================================================================*/
/* !!! JOB_CALENDAR (milestones grid) */
/* ===================================================================================================================*/

.calendar-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
    background-color: var(--pt-body-light);
}

.calendar-header {
    background: var(--pt-body-light);
    color: var(--text_dark);
    padding: 10px;
    text-align: center;
    font-family: var(--headingfont);
}

.calendar-day {
    background: var(--pt-body-light);
    min-height: 175px;
    padding: 5px;
    border: 1px solid var(--gray-100);
    position: relative;
    font-size: var(--font_em_4A);
    background-color: var(--gray-025);
    margin: 3px;
    border-radius: 8px;
}

.calendar-day.today {
    border: 2px solid var(--gray-800);
}

.calendar-day.empty {
    background-color: var(--gray-050);
}

.calendar-date {
    font-family: var(--headingfont);
    color: var(--text_dark);
}

.calendar-event {
    background: var(--gray-100);
    border: 1px solid var(--pt-border);
    margin: 2px 0;
    padding: 2px 4px;
    border-radius: 6px;
    font-size: var(--font_em_4A);
}

.calendar-event.TCO {
    background: var(--lightyellow);
}

.calendar_jobname {
    font-family: var(--headingfont);
    font-size: var(--font_em_5);
    color: var(--text_dark);
}

.calendar_milestone_type {
    font-family: var(--tablefont);
    font-size: var(--font_em_5A);
    color: var(--text_dark);
    margin: 2px 0;
}

.calendar_title {
    font-family: var(--headingfont);
    color: var(--text_dark);
    font-size: var(--font_em_2);
    margin-bottom: 4px;
}

/* ===================================================================================================================*/
/* !!! PROJECT_SUMMARY */
/* ===================================================================================================================*/

.projSum_image_container {
    position: relative;
}

.projSum_image_container:hover {
    cursor: pointer;
}

/* Condense the per-card info rows so each project card reads as a
   tight block. The generic .info_row / .grid_label / .grid_value
   styles are shared with other pages (ops chart, CSI cost model,
   project info modal, etc.), so we scope these overrides to the
   Project Summary grid container and avoid touching the base
   styles. */
#project_photo_grid .info_row {
    margin-bottom: 0;
}

#project_photo_grid .grid_label,
#project_photo_grid .grid_value {
    line-height: 1.15;
}

/* Project Summary cards must stay a fixed-height, single-line-per-row
   block so the 4-up grid lines up cleanly. Force every value onto one
   line and truncate with an ellipsis rather than letting long owners /
   architects / neighborhoods wrap and blow out the card height. The
   min-width:0 on both grid tracks lets the truncation actually engage
   inside the info_row grid. */
#project_photo_grid .info_row {
    grid-template-columns: 50% minmax(0, 1fr);
}

#project_photo_grid .grid_label,
#project_photo_grid .grid_value {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* ===================================================================================================================*/
/* !!! PRECON_STAFFING — compact, outlined project sub-cards
/* ---------------------------------------------------------------------
/* Scoped to the Precon Staffing Chart page. Shrinks the shared Project
/* Summary sub-card (.card.level2) into a tight, outlined tile and renders
/* the project photo in black & white. Reuses the existing card / info_grid
/* markup; only sizing, outline, and a grayscale filter are added here. */
/* ===================================================================================================================*/

/* Even padding on all sides of the personnel cards. The base `.card` uses
   `padding: 0 0.8em 1.2em` (no top), which makes the top/bottom look uneven
   against the round photo; set an explicit symmetric box here. */
.precon_staffing .card:not(.level2) {
    padding: 1em !important;
}

/* Personnel-card header: circular staff photo to the LEFT of the name +
   summary info grid. Plain flexbox so it reuses the existing H4 / info_grid
   type. */
.precon_staffing .precon_staff_header {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 1em;
    margin-bottom: 0.75em;
}

.precon_staffing .precon_staff_photo {
    flex: 0 0 auto;
    width: 80px;
    height: 80px;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--pt-border-soft);
}

.precon_staffing .precon_staff_photo_empty {
    background-color: var(--gray-300);
}

.precon_staffing .precon_staff_meta {
    min-width: 0;
    flex: 1 1 auto;
}

.precon_staffing .precon_staff_meta h4 {
    margin-bottom: 0.25em;
}

/* Outline + full-bleed photo. We mirror the `:not(.nav):not(.warning)`
   qualifiers from the shared `.card.level2` reset so this selector has equal-
   or-higher specificity and our border/radius actually win over the
   `border: none !important` reset. Padding is zeroed so the photo bleeds to
   the card edges; text padding lives on `.precon_card_body`. The base `.card`
   already sets `overflow: hidden`, so the photo clips to the rounded corners. */
.precon_staffing .card.level2:not(.nav):not(.warning) {
    border: 1px solid var(--gray-300) !important;
    border-radius: 6px !important;
    padding: 0 !important;
    margin-bottom: 0 !important;
    font-size: 0.72em;
}

.precon_staffing .precon_card_body {
    padding: 0.4em 0.5em 0.5em;
}

.precon_staffing .card.level2 h5 {
    font-size: 1.05em;
    margin: 0 0 0.2em;
}

/* Round the photo's top corners to match the card's 6px radius (bottom stays
   square against the card body). Same `overflow:hidden` + `line-height:0`
   approach used by the PT Dashboard mini-card image container. */
.precon_staffing .projSum_image_container {
    border-radius: 6px 6px 0 0;
    overflow: hidden;
    line-height: 0;
}

/* The shared `.projSum_image_container` is clickable on the Project Summary
   page; these cards aren't interactive yet, so drop the pointer cursor. */
.precon_staffing .projSum_image_container:hover {
    cursor: default;
}

/* Black & white + darkened project photos. dmc.Image renders an <img>; the
   height is set via the Python `height` prop, so we only restyle. Darkening
   lets the light-gray job-number overlay read clearly. */
.precon_staffing .projSum_image_container img {
    filter: grayscale(100%) brightness(0.55);
}

/* Fallback for projects with no photo: a dark gray filled box matching the
   photo height instead of a broken/empty image. */
.precon_staffing .precon_no_photo {
    height: 80px;
    background-color: var(--gray-500);
}

/* Job number overlaid on the (darkened) photo in light-gray text. */
.precon_staffing .precon_job_overlay {
    position: absolute;
    bottom: 8px;
    left: 6px;
    z-index: 1;
    font-family: var(--tablefont_mono_bold);
    font-weight: bold;
    font-size: 0.85em;
    color: var(--gray-200);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
    pointer-events: none;
}

/* Inactive (non-active) assignments: a simple bullet list at the bottom of
   the staff card instead of full project photo cards. */
.precon_staffing .precon_inactive_list {
    margin-top: 0.75em;
}

.precon_staffing .precon_inactive_list h5 {
    margin-bottom: 0.25em;
}

/* Trim the browser-default ~40px <ul> indent so the bullet list lines up with
   the rest of the card content instead of looking left-offset. */
.precon_staffing .precon_inactive_list ul {
    margin: 0;
    padding-left: 1.2em;
}

/* ===================================================================================================================*/
/* !!! PT_DASHBOARD — mini project cards
/* ---------------------------------------------------------------------
/* Compact variant of the Project Summary card: photo + name + a small
/* %-complete badge overlaid on the photo. Each card is clickable and
/* fires the standard project-info modal. Sized to fit ~6–8 per row on
/* desktop so the strip reads as a quick portfolio scanner rather than
/* a full card grid. */
/* ===================================================================================================================*/

.pt_dash_mini_card {
    display: flex;
    flex-direction: column;
    cursor: pointer;
    border-radius: 6px;
    padding: 4px;
    background-color: var(--pt-body-light, #ffffff);
    transition: var(--pt-transition);
}

.pt_dash_mini_card:hover {
    background-color: var(--pt-accent-light-05, rgba(43, 89, 69, 0.05));
    transform: translateY(-1px);
}

.pt_dash_mini_image_container {
    position: relative;
    border-radius: 4px;
    overflow: hidden;
    line-height: 0;
}

/* Render every mini-card project photo in black & white *and* ghost it
   back to roughly half opacity, so the progress overlay below + the
   project name above can carry the visual weight of the card. The
   selector targets the actual <img> dmc.Image renders inside this
   container — sibling absolutely-positioned children (the overlay +
   the %-badge) are unaffected and keep their full chroma/contrast. */
.pt_dash_mini_image_container img {
    filter: grayscale(100%);
    opacity: 0.55;
}

.pt_dash_mini_comp_pct {
    position: absolute;
    bottom: 4px;
    left: 4px;
    color: var(--gray-025, #ffffff);
    font-family: var(--headingfont);
    font-size: var(--font_em_4);
    line-height: 1;
    padding: 2px 6px;
    background-color: rgba(0, 0, 0, 0.45);
    border-radius: 4px;
    text-shadow: 0 0 6px rgba(0, 0, 0, 0.85);
    pointer-events: none;
    z-index: 2;
}

/* Vertical progress fill drawn over the mini-card photo. Anchored to
   the bottom and sized inline (Python sets height in px from the
   project's latest Comp%) so the strip reads like a vertical progress
   chart layered on the photos themselves. z-index sits below the
   %-complete badge (z-index: 2) so the number stays crisp regardless
   of how full the fill is.

   Color routing (layered, top-down):
   * Waterline (border-top): rgba of --monconred (#ed2037 →
     237,32,55) at 90% alpha, 1.5px so the only solid chroma on the
     card sits in this thin accent line marking the exact Comp%
     level.
   * Red glow (background-image): a vertical linear-gradient that
     starts at the waterline with ~30% monconred and fades to fully
     transparent ~30px below, so the red feels like it "bleeds" out
     of the waterline into the gray fill below. Uses a pixel stop
     (not a percentage) so the glow band is the same size regardless
     of how tall the overlay is — short progress fills (low %)
     render mostly as glow, tall fills (high %) carry the glow at
     the top with the gray fill dominating below.
   * Gray fill (background-color): rgba of --gray-800 (#3a3c3f →
     58,60,63) at 45% alpha. A calm neutral that visibly darkens the
     bottom of the (already ghosted) photo without using brand color.

   CSS variables can't carry per-property alpha directly, so the rgba
   triplets are hardcoded; if either token changes hue, update the
   rgba() literals here to match. */
.pt_dash_mini_progress_overlay {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(58, 60, 63, 0.45);
    background-image: linear-gradient(
        to bottom,
        rgba(237, 32, 55, 0.30),
        rgba(237, 32, 55, 0.00) 30px
    );
    border-top: 1.5px solid rgba(237, 32, 55, 0.90);
    pointer-events: none;
    z-index: 1;
    transition: height var(--button-link-transition-duration) ease-in-out;
}

/* Suppress the red waterline + glow on near-complete (>= 97.5%)
   cards. Python opts each card in by adding this modifier class
   whenever ``_comp_pct_show_accent(...)`` returns False. The gray
   fill remains via the base rule above — only the chroma accent is
   removed, so the card reads as effectively "done" rather than as
   "still has work above the red line". */
.pt_dash_mini_progress_overlay--no-accent {
    background-image: none;
    border-top: 0;
}

.pt_dash_mini_name {
    font-family: var(--headingfont);
    font-size: var(--font_em_5);
    color: var(--text_dark);
    margin-top: 4px;
    line-height: 1.15;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    word-break: break-word;
}

/* Next-milestone pill at the bottom of each mini card. Stacks the
   milestone label over the date so longer phase names ("Superstructure
   Topout" etc.) wrap cleanly without spilling outside the card width. */
.pt_dash_mini_next_pill {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    margin-top: 4px;
    padding: 2px 6px;
    border-radius: 10px;
    background-color: var(--pt-body, #f3f3f3);
    border: 1px solid var(--pt-body-medium, #e8e8e8);
    line-height: 1.1;
    max-width: 100%;
}

.pt_dash_mini_pill_label {
    font-family: var(--headingfont);
    font-size: var(--font_em_6);
    color: var(--text_dark);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

.pt_dash_mini_pill_date {
    font-family: var(--tablefont);
    font-size: var(--font_em_6);
    color: var(--pt-text-medium, #636363);
}

/* ===================================================================================================================*/
/* !!! OPS_CHART */
/* ===================================================================================================================*/

.opsChart_proj_card {
    border-radius: 4px;
    padding: 0;
    display: flex;
    flex-direction: column;
    width: 100%;
    /* Card height tuned so a 2-card column (natural stack, ~210px) and
       a 3-card smart-overlap column (~188px container) both sit inside
       the card after the header takes its natural ~65–70px. */
    height: 256px;
    overflow: visible !important;
    position: relative;
}

.opsChart_proj_card.NOTACTIVE {
    border: 1px solid var(--pt-disabled-border) !important;
    background-color: var(--pt-disabled-bg);
}

/* When the project is completed/inactive, card header text (project name,
   start date, TCO date, contract value) uses the unified disabled text
   color. Image overlays (jobno, comp%) keep their white-on-shadow look
   since they sit atop the gray image overlay. */
.opsChart_proj_card.NOTACTIVE .opsChart_proj_name,
.opsChart_proj_card.NOTACTIVE .opsChart_proj_info,
.opsChart_proj_card.NOTACTIVE .opsChart_role_type_stats {
    color: var(--pt-disabled-text) !important;
}

/* Project header containing the project name */
.opsChart_proj_header {
    width: 100%;
    margin: 0 0 2px;
    padding-bottom: 1px;
    display: inline-block;
    position: relative;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    z-index: 100;
}

.opsChart_proj_name {
    font-family: var(--headingfont);
    font-size: var(--font_em_4);
    color: var(--text_dark);
    margin: 0 3px;
    display: inline-block;
}

.opsChart_proj_info {
    font-family: var(--textfont);
    font-size: var(--font_em_5);
    color: var(--text_dark);
    margin: 0;
    margin-left: 0.15em;
    display: inline-block;
}

/* Main content row that contains everything except the project name.
   Uses flex:1 + min-height:0 (instead of height:100%) so it takes
   exactly the space left over by the project header inside the
   flex-column project card. height:100% in that context triggers a
   flex-shrink tug-of-war with the header and lets the stacked staff
   cards bleed a few pixels past the card's bottom border. */
.opsChart_content_row {
    display: flex;
    width: 100%;
    align-items: flex-start;
    margin: 0;
    flex: 1;
    min-height: 0;
    padding-bottom: 6px;
    box-sizing: border-box;
}

/* Staff columns - each takes equal space of remaining width */
.opsChart_staff_column {
    flex: 1;
    min-width: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    margin: 1px;
    height: 100%;
    gap: 0.15em;
}

/* !!! ________Staff_Card */

/* Role-tinted staff-card backgrounds, image overlays, title tints, and
   years-badge tints have all been eliminated. Cards read on a neutral
   light-gray surface; the "latest assignment" signal is carried by the
   red border + red staff-name, and superseded assignments recede to a
   plain gray outline. The --opsChart_*_color tokens remain defined at
   :root because other views (e.g. .PILL.log / .PILL.tag in the safety
   manual) still reference them. */
.opsChart_staff_card {
    font-family: var(--tablefont);
    display: block;
    position: relative;
    align-items: center;
    border: 1px solid var(--monconred);
    border-radius: 5px;
    margin: 0.1em;
    padding: 0.1em 0.2em;
    box-shadow: var(--shadow-hover-soft);
    color: var(--text_dark);
    /* Solid light-gray fill (not transparent) so the 3+ staff card
       overlap in create_smart_staff_column reads cleanly — the upper
       card fully covers the card beneath it at the overlap area. */
    background-color: var(--gray-100);
    transition: var(--pt-transition);
    cursor: pointer;
}

.opsChart_staff_card.Future {
    border: 1px dashed var(--gray-300) !important;
    color: rgba(0,0,0,0) !important;
    box-shadow: None !important;
}

/* Superseded assignment: light-gray outline plus grayed-out text so
   the card visually recedes next to the red-bordered latest-assignment
   cards. The staff image is desaturated via the matching .NOTACTIVE
   rule on the image container below. All three (border, text, photo)
   use the same lighter gray so the card reads as uniformly dimmed. */
.opsChart_staff_card.NOTACTIVE {
    border: 1px solid var(--gray-300);
    color: var(--gray-300);
}

.opsChart_staff_card.NOTACTIVE .opsChart_staff_name {
    color: var(--gray-300) !important;
}

.opsChart_staff_card.Assign {
    color: var(--monconred) !important;
    border: 1px var(--monconred) solid;
}

.opsChart_staff_card.PRELIM {
    background-color: var(--lightyellow);
    border: 1px var(--monconred) solid;
}

.opsChart_staff_name.PRELIM {
    color: var(--monconred) !important;
}

.opsChart_staff_card:hover {
    border-radius: 12px;
    cursor: default;
    font-family: var(--headingfont) !important;
    z-index: 1000 !important;
}

.opsChart_staff_name {
    font-size: var(--font_em_5);
    font-family: var(--tablefont);
    margin: 0;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap;
    width: 100%;
    transition: var(--pt-transition);
}

.opsChart_staff_name:hover {
    cursor: pointer;
}

.opsChart_staff_card:hover .opsChart_staff_name {
    font-family: var(--headingfont) !important;
}

/* Latest-assignment cards get red staff-name text to reinforce the red
   border, plus a slightly heavier GT-Pressura Medium face (one step above
   the Regular --tablefont base, well short of Bold) so the active name
   reads a touch stronger than superseded ones. Superseded (.NOTACTIVE)
   cards keep the dark-text + regular-weight treatment so they visually
   recede. The title over the photo stays white. */
.opsChart_staff_card:not(.NOTACTIVE) .opsChart_staff_name {
    color: var(--monconred);
    font-family: var(--mediumfont);
}

/* !!! ________Staff_Images */

.opsChart_staff_image_container {
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
    position: relative;
    border-radius: 4px;
    margin-bottom: 2px;
    border: none;
}

.opsChart_staff_image {
    border: None !important;
    width: 100%;
    height: 5rem;
    object-fit: cover;
    display: block;
    cursor: pointer;
    object-position: center;
}

/* No-photo fallback on Ops Chart staff cards: plain gray box filling the
   same footprint as the photo (.opsChart_staff_image sets width/height)
   instead of a broken-image icon. Mirrors .precon_staff_photo_empty and
   .projinfo_hours_staff_photo_empty. */
.opsChart_staff_photo_empty {
    background-color: var(--gray-400);
}

/* Superseded staff image: partially desaturate and fade so the photo
   visually recedes in sync with the grayed card text/border. Latest-
   assignment cards (no .NOTACTIVE) keep their full-color photo. */
.opsChart_staff_image_container.NOTACTIVE .opsChart_staff_image {
    filter: grayscale(100%) brightness(1.15) contrast(0.75);
    opacity: 0.4;
}

.opsChart_staff_title {
    font-family: var(--headingfont) !important;
    font-size: var(--font_em_5);
    position: absolute;
    left: .5em;
    bottom: 0.25em;
    color: var(--gray-025);
    text-shadow: 0 0 12px rgba(0, 0, 0, 1) !important;
    overflow: hidden;
}

.opsChart_staff_title.NOTACTIVE {
    text-shadow: 0 0 10px rgba(0, 0, 0, 0.3) !important;
}
.opsChart_staff_title.NOTACTIVE.Future,
.opsChart_staff_title.Assign {
    text-shadow: None !important;
}

.opsChart_staff_years {
    font-family: var(--headingfont);
    font-size: var(--font_em_6);
    /* Pinned rather than inherited so this badge and the license pill below it
       have identical, predictable heights: the pill's stacked offset is derived
       from this line-height. */
    line-height: 1.2;
    color: var(--text_dark);
    position: absolute;
    right: 4px;
    top: 6px;
    padding: 0.2em 0.4em;
    min-width: 2em;
    background-color: var(--gray-025);
    border: 1px solid var(--gray-500);
    border-radius: 12px;
    text-align: center;
    display: inline-block;
    box-sizing: border-box;
    cursor: pointer;
    vertical-align: middle;
}

/* Latest-assignment cards: years badge text + border pick up --monconred
   to match the card's red border and red staff-name treatment. */
.opsChart_staff_card:not(.NOTACTIVE) .opsChart_staff_years {
    color: var(--monconred);
    border-color: var(--monconred);
}

/* Superseded-assignment cards: years badge keeps its own --text_dark from
   the base rule above; align the numeral with the muted .NOTACTIVE name.
   Also lighten the badge border so it reads as uniformly dimmed alongside
   the card's own --gray-300 border. */
.opsChart_staff_card.NOTACTIVE .opsChart_staff_years {
    color: var(--gray-300);
    border-color: var(--gray-300);
}

/* Active Construction Superintendent license marker: a red pill carrying a
   white "S". It borrows the years badge's font size, line-height, padding,
   min-width, border-radius, and right edge so the two read as one corner
   column. Hover title carries the credential detail one letter can't. */
.opsChart_staff_license {
    font-family: var(--headingfont);
    font-size: var(--font_em_6);
    line-height: 1.2;
    color: var(--gray-025);
    background-color: var(--monconred);
    border: 1px solid var(--monconred);
    border-radius: 12px;
    padding: 0.2em 0.4em;
    min-width: 2em;
    text-align: center;
    position: absolute;
    right: 4px;
    top: 6px;
    z-index: 8;
    box-sizing: border-box;
    cursor: help;
}

/* Stacked directly under the years badge when the card renders one. Both
   badges are 1.6em + 2px tall (1.2 line-height + 0.4em padding + 1px borders)
   and start at top: 6px, so 6px + 1.6em + 2px clears the badge above and the
   extra 2px is the gap between them. */
.opsChart_staff_license--stacked {
    top: calc(10px + 1.6em);
}

/* Superseded assignment: the license pill dims in step with the card's
   grayed border, name, and years badge. */
.opsChart_staff_card.NOTACTIVE .opsChart_staff_license {
    background-color: var(--gray-300);
    border-color: var(--gray-300);
}

/* !!! ________SafetyClerk_Site_Verification */
/* Check chip on a staff card whose person the turnstiles saw badge onto
   this project within the last 14 days. Bottom-right corner — opposite
   the years/license badge stack at top-right, and clear of the role
   title pinned bottom-left. Soft green is deliberate: it's the same
   "confirmed" green the contract-status Executed pill uses, and no
   palette token exists for it yet, so it's set literally here. */
.opsChart_staff_verified {
    font-family: var(--headingfont);
    font-size: var(--font_em_6);
    line-height: 1.2;
    color: var(--gray-900);
    background-color: #c9e7c9;
    border: 1px solid color-mix(in srgb, #c9e7c9 60%, var(--gray-900));
    border-radius: 12px;
    padding: 0.2em 0.4em;
    text-align: center;
    position: absolute;
    right: 4px;
    bottom: 4px;
    z-index: 8;
    box-sizing: border-box;
    cursor: help;
}

/* The tick itself: two straight strokes (an L rotated 45°) so it reads
   angular rather than the font's curvy check-mark glyph. Sized in em so
   it scales with the chip's font token. */
.opsChart_staff_verified_tick {
    display: inline-block;
    width: 0.34em;
    height: 0.68em;
    border-right: 0.14em solid var(--gray-900);
    border-bottom: 0.14em solid var(--gray-900);
    transform: rotate(45deg);
    margin: 0 0.1em 0.08em;
}

/* Dimmed in step with a superseded card, like the other corner badges. */
.opsChart_staff_card.NOTACTIVE .opsChart_staff_verified {
    background-color: var(--gray-100);
    border-color: var(--gray-300);
    color: var(--gray-300);
}

.opsChart_staff_card.NOTACTIVE .opsChart_staff_verified_tick {
    border-color: var(--gray-300);
}

/* ── Data Manager — Job Name Verification ─────────────────────────────
   The tables themselves come from make_table (the app's standard look);
   these style the pieces embedded in the cells — the editable ALJobNo
   field, the undo chip, and the verdict byline. */
.dm-jl-section { margin-top: 1.2em; }

.dm-jl-mono { font-family: var(--tablefont_mono); }

.dm-jl-btn {
    font: inherit;
    line-height: 1.2;
    padding: 0 6px;
    margin: 0 2px;
    border: 1px solid var(--gray-500);
    border-radius: 10px;
    background: var(--gray-025);
    color: var(--text_dark);
    cursor: pointer;
    transition: var(--button-link-transition);
}

.dm-jl-btn:hover { border-radius: 12px; border-color: var(--gray-900); }

.dm-jl-status {
    color: var(--gray-500);
    font-size: var(--font_em_5);
    margin-right: 4px;
    white-space: nowrap;
}

/* The mapping fields reuse .sp-jobalias-inline — the same inline ALJobNo
   input the bidder modal's history table carries — so no input style of
   this page's own. Comma-run multi-job values need a little more room
   than the modal's single-number fields. */
.dm-jl-section .sp-jobalias-inline {
    width: 14em;
}

/* Bidder modal — duplicate-contract warning under the Bidding History
   table. Red-inked and red-edged like the app's other data warnings
   (.sManual_duplicate_warning), because it names money counted twice. */
/* Source-attribution pills at the foot of a committed-work project card:
   the muted gray family the rest of the app uses for source text. */
.sp-card-sources {
    display: flex;
    flex-wrap: wrap;
    gap: 3px;
    margin-top: 6px;
}

/* Committed Work grid: every card the same height as its row, laid out
   as a column so the source pills pin to the card's foot. Scoped here
   because .staff-history-proj-card also serves the staff modal. */
.sp-commit-grid .staff-history-proj-card {
    height: 100%;
    display: flex;
    flex-direction: column;
    /* A hairline edge, so each card ends where it ends: the fill alone
       was too close to the page behind it to separate one row from the
       next. */
    border: 1px solid var(--gray-300);
}

.sp-commit-grid .sp-card-sources {
    margin-top: auto;
    padding-top: 6px;
}
/* The chips here are the Spellings list's tags; the flex gap spaces them. */
.sp-card-sources .sp-alias-tag {
    margin-left: 0;
}

/* Two lines' room for every title, so a wrapped name on one card does
   not push its rows out of line with its neighbors'. */
.sp-commit-grid .staff-history-proj-card h5 {
    min-height: 2.5em;
    margin-bottom: 0.2em;
}

.sp-note.sp-dup-warning {
    color: var(--monconred);
    background-color: var(--monconred-tint);
    border-left: 3px solid var(--monconred);
    border-radius: 4px;
    padding: 4px 8px;
}

/* Alert card: someone the turnstiles saw on this site more than two of
   the last five working days who holds no staff card on the project.
   Red-dashed border + red tint so the gap in the chart is unmissable. */
.opsChart_staff_card.SCALERT {
    border: 2px dashed var(--monconred);
    background-color: var(--monconred-tint);
}

.opsChart_staff_card.SCALERT .opsChart_staff_name {
    color: var(--monconred);
    font-family: var(--mediumfont);
}

/* Overlaid as a red pill in the top-right corner — the slot the years
   badge occupies on regular cards (alert cards carry none) — so the
   alert card measures exactly like its neighbors instead of growing a
   text row below the image. Mirrors the license pill's geometry. */
.opsChart_sc_alert_label {
    font-family: var(--headingfont);
    font-size: var(--font_em_6);
    line-height: 1.2;
    color: var(--gray-025);
    background-color: var(--monconred);
    border: 1px solid var(--monconred);
    border-radius: 12px;
    padding: 0.2em 0.4em;
    position: absolute;
    right: 4px;
    top: 6px;
    white-space: nowrap;
    z-index: 8;
    box-sizing: border-box;
}

/* !!! ________ProjInfo_Modal_Subheads */
/* Red hairline beneath every section subheading in the project info
   modal body (Basic Info, A/E Team, Design, Project Schedule, Trade
   Payment Breakdown, Subcontractor Commitments, Staff with 300+ Hours
   Logged, etc.). Mirrors the PDF export's section bands so every heading
   reads the same way — heading text, then a red rule — across web + PDF.
   Scoped to ``.modal-body`` so the modal-header title band (which already
   has its own ``pt-red-title-band`` treatment) is left untouched. */
.opsChart_proj_modal .modal-body h4 {
    border-bottom: 2px solid var(--monconred);
    padding-bottom: 0.28em;
    margin-bottom: 0.6em;
}

/* !!! ________ProjInfo_Hours_Staff */
/* Staff-card grid used in the project info modal to show everyone who
   logged 300+ hours on a job. Reuses the .opsChart_staff_card look but
   lays the cards out in a wrapping flex row (they are display-only, so
   the hover/pointer affordance from the interactive cards is removed)
   and gives each card a fixed width since it isn't inside the flex-sized
   opsChart_staff_column. The corner badge (.opsChart_staff_years) carries
   the hours figure instead of a role title. */
.projinfo_hours_staff_grid {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4em;
    margin-top: 0.4em;
}

.projinfo_hours_staff_card {
    width: 4.5rem;
    flex: 0 0 auto;
    cursor: default;
}

/* Shrink the photo so each card reads as a compact, roughly-square tile
   (like the dense Ops Chart staff cards) instead of the tall/elongated
   portrait the base .opsChart_staff_image 5rem height produced here. */
.projinfo_hours_staff_card .opsChart_staff_image {
    height: 3.5rem;
}

/* These cards are display-only, so suppress the interactive hover
   affordances the base .opsChart_staff_card carries (corner-radius grow,
   heading-font swap, z-index lift) and keep the resting appearance on
   hover. Cursor stays the default arrow everywhere on the card. */
.projinfo_hours_staff_card:hover {
    border-radius: 5px;
    font-family: var(--tablefont) !important;
    z-index: auto !important;
}

.projinfo_hours_staff_card:hover .opsChart_staff_name {
    font-family: var(--mediumfont) !important;
}

.projinfo_hours_staff_card,
.projinfo_hours_staff_card:hover,
.projinfo_hours_staff_card .opsChart_staff_name,
.projinfo_hours_staff_card .opsChart_staff_name:hover,
.projinfo_hours_staff_card .opsChart_staff_image {
    cursor: default;
}

button.projinfo_hours_staff_card--clickable {
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.projinfo_hours_staff_card--clickable,
.projinfo_hours_staff_card--clickable:hover,
.projinfo_hours_staff_card--clickable .opsChart_staff_name,
.projinfo_hours_staff_card--clickable .opsChart_staff_name:hover,
.projinfo_hours_staff_card--clickable .opsChart_staff_image {
    cursor: pointer;
}

.projinfo_hours_staff_card--clickable:hover {
    border-radius: 12px;
    font-family: var(--headingfont) !important;
    z-index: 1000 !important;
}

.projinfo_hours_staff_card--clickable:hover .opsChart_staff_name {
    font-family: var(--headingfont) !important;
}

/* No-photo fallback: a plain gray box filling the same footprint as the
   staff photo (the .opsChart_staff_image rule sets the width/height) so
   photoless staff read as a neutral placeholder rather than a broken
   image. Mirrors the .precon_staff_photo_empty treatment. */
.projinfo_hours_staff_photo_empty {
    background-color: var(--gray-300);
}

/* !!! ________Contract_Log_MWBE */
/* The 'likely direct CV' totals under the Contract Status Log
   (utils/project_mwbe.py). The label is the caveat — 'Likely direct CV —
   MBE (State)' — so it is never cut to an ellipsis the way .grid_label's
   150px cap would cut it. */
.projinfo-mwbe-totals .grid_label {
    max-width: none;
}

/* !!! ________Hours_Data_Currency_Warning */
/* Small muted caveat shown beneath every staff logged-hours display
   (project info modal, staff modal, Hours Stats tables, Management Time
   analysis) noting the date through which payroll hours are complete. */
.hours-data-warning {
    font-family: var(--tablefont);
    font-size: var(--font_em_5);
    font-style: italic;
    color: var(--gray-500);
    margin: 0.15em 0 0.5em;
    line-height: 1.3;
}

.transparentPhoto {
    opacity: 0 !important;
}

.opsChart_px_card_title {
    font-family: var(--headingfont);
    font-size: var(--font_em_2C);
    margin-bottom: 2px;
}

.opsChart_staff_temp_NOTACTIVE {
    position: absolute;
    top: 45%;
    left: 25%;
    transform: rotate(-45deg);
    font-family: var(--headingfont);
    color: var(--pt-disabled-text);
    text-shadow: 0 0 10px rgba(255, 255, 255, 1) !important;
}

.opsChart_staff_temp_ {
    position: absolute;
    top: 45%;
    left: 25%;
    transform: rotate(-45deg);
    font-family: var(--headingfont);
    color: var(--text_color_dark);
    text-shadow: 0 0 10px rgba(0, 0, 0, 1) !important;
}

/* Wrapper for card with image */
.opsChart_card_with_image {
    display: flex;
    flex-direction: row;
    width: 100%;
    margin: 0;
    padding: 0;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .05);
    border-radius: 4px;
    align-items: stretch;
    background-color: var(--gray-025) !important;
}

/* !!! ________Project_Images */

.opsChart_proj_img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    position: absolute;
    top: 0;
    left: 0;
    z-index: 6;
    border-radius: 4px 0 0 4px !important;
    filter: grayscale(100%) contrast(0.75) brightness(1.05);
    /* Ghost the photo back to ~half opacity over the white card
       background so the gray progress overlay (drawn on top, below
       the badge layer) reads as the dominant visual signal on the
       card. Applied uniformly to every photo regardless of project
       state — the active vs inactive distinction is now carried by
       the .NOTACTIVE modifier on the container, not by the photo
       itself. Mirrors the PT Dashboard mini-card photo treatment
       (.pt_dash_mini_image_container img). */
    opacity: 0.55;
}

.staff_modal_project_photo {
    width: 100%;
    height: 120px;
    object-fit: cover;
    object-position: center;
}

/* Modal title bands reuse the app-wide pt-red-title-band idiom
 * (emitted by ``make_modal_title_band`` / ``make_modal_header``) and are
 * deliberately styled to be *identical* to the page-level bands built by
 * ``create_layout``: same heading size, same caption, same red-outline
 * Download PDF pill. The only work done here is:
 *   1. reset font-size to 1rem so the band's em-based typography computes
 *      exactly as it does on a page (immune to any .modal-header sizing),
 *   2. zero the page-level band's outer margins (the modal-header supplies
 *      the gutters), and
 *   3. let the modal's H4 title render at the page band's H1 size, wrapping
 *      instead of ellipsizing (the global h4 rule nowraps + ellipsizes). */
.modal-header .pt-red-title-band {
    margin: 0;
    width: 100%;
    font-size: 1rem;
}

.modal-header .pt-red-title-band__main {
    min-width: 0;
}

.modal-header .pt-red-title-band h4 {
    font-size: var(--font_em_1);
    line-height: 1.05;
    margin: 0;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

/* Style for the image container */
.opsChart_image_container {
    width: 100px;
    min-width: 5.5rem;
    margin: 0;
    padding: 0;
    border-radius: 4px 0 0 4px !important;
    border: 1px solid var(--gray-500);
    border-right: none;
    display: block;
    position: relative;
    z-index: 1;
    box-sizing: border-box;
}

.opsChart_image_container.NOTACTIVE {
    border-left: 1px solid var(--pt-disabled-border) !important;
    border-top: 1px solid var(--pt-disabled-border) !important;
    border-bottom: 1px solid var(--pt-disabled-border) !important;
    border-radius: 4px 0 0 4px !important;
    z-index: 6;
}

.opsChart_image_container.NOTACTIVE::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: var(--pt-disabled-overlay);
    pointer-events: none;
    z-index: 7;
    border-radius: 4px 0 0 4px !important;
}

/* Overlay for projects that haven't started */
.opsChart_no_image_fallback {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--gray-100);
    color: var(--text_dark);
    font-family: var(--headingfont);
    font-size: var(--font_em_4A);
    border-radius: 4px 0 0 4px;
}

.opsChart_card_with_image .opsChart_proj_card {
    border-radius: 0 4px 4px 0;
    width: calc(100% - 5rem);
    box-sizing: border-box;
    border: 1px solid var(--gray-500);
    border-left: none;
    margin: 0;
}

.custom-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-gap: 10px;
    width: 100%;
}

.opsChart_comp_percent {
    position: absolute;
    bottom: 0;
    left: 3px;
    color: var(--text_color_dark);
    font-family: var(--headingfont);
    font-size: var(--font_em_2B);
    z-index: 7;
    text-shadow: 0 0 12px rgba(0, 0, 0, 1) !important;
    padding: 2px 6px;
    cursor: pointer;
    transition: var(--pt-transition);
}

.opsChart_jobno {
    position: absolute;
    top: 3px;
    left: 3px;
    color: var(--text_color_dark);
    font-family: var(--headingfont);
    font-size: var(--font_em_4);
    z-index: 7;
    pointer-events: none;
    text-shadow: 0 0 12px rgba(0, 0, 0, 1) !important;
}

/* Vertical progress fill drawn over the project photo on the
   Operational Chart. Mirrors the PT Dashboard mini-card overlay
   (.pt_dash_mini_progress_overlay) — see that rule for the full
   design rationale of the layered color stack. Same recipe here:
   * Waterline (border-top): --monconred at 90% alpha, 1.5px so the
     only solid chroma marks the exact Comp% level.
   * Red glow (background-image): linear-gradient bleeding from the
     waterline down ~30px, monconred → transparent, so the red feels
     like it fades out of the waterline rather than ending abruptly.
   * Gray fill (background-color): --gray-800 at 45% alpha to
     visibly darken the bottom of the photo without using brand
     color across the whole fill.
   z-index 6 sits above the photo (also z-index 6, drawn earlier in
   DOM order) and below the comp% badge / job-number (z-index 7) so
   those text overlays stay legible. ``top`` is set inline by Python
   from row['Comp%'], so the overlay always anchors flush to the
   bottom regardless of the flex-stretched container height. */
.opsChart_progress_overlay {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(58, 60, 63, 0.45);
    background-image: linear-gradient(
        to bottom,
        rgba(237, 32, 55, 0.30),
        rgba(237, 32, 55, 0.00) 30px
    );
    border-top: 1.5px solid rgba(237, 32, 55, 0.90);
    pointer-events: none;
    z-index: 6;
    transition: top var(--button-link-transition-duration) ease-in-out;
    /* Rounded bottom-left to match the parent .opsChart_image_container's
       4px 0 0 4px radius. The top corners stay square because the
       overlay's top edge is mid-photo (or, at very high Comp%, gets
       masked by the NOTACTIVE wash that has its own border-radius). */
    border-radius: 0 0 0 4px;
}

/* Suppress the red waterline + glow on near-complete (>= 97.5%)
   cards. Python opts each card in by adding this modifier class
   whenever row['Comp%'] >= _OPSCHART_PROGRESS_ACCENT_THRESHOLD.
   The gray fill remains via the base rule above. */
.opsChart_progress_overlay--no-accent {
    background-image: none;
    border-top: 0;
}

.opsChart_modal_button {
    cursor: pointer;
    transition: background-color var(--button-link-transition-duration) ease;
}

.opsChart_modal_button:hover {
    background-color: rgba(0, 0, 0, 0.1);
}

.opsChart_role_type_stats {
    line-height: 0.75;
}

.card h4 + .opsChart_role_type_stats {
    margin-bottom: 3px !important;
}

.staff-project-card > div {
    white-space: nowrap;
    overflow: hidden;
}

/* Modal backdrop + z-index fixes. Positioning/sizing for every modal
   dialog lives in the single !!! MODAL block above — no per-modal
   overrides here.

   The app loads NO Bootstrap stylesheet, so Bootstrap's base
   `.modal-backdrop { position: fixed; inset: 0; width: 100vw;
   height: 100vh }` rule is absent. Without it the backdrop div dbc
   injects is a static, zero-height element — its background-color and
   backdrop-filter painted nothing, so modals opened over a page at full
   brightness. The fixed full-viewport geometry below is what makes the
   dim + blur actually render. The alpha lives in the background-color;
   the element itself fades 0 -> 1 as dbc toggles `.show` (dbc adds the
   node with `fade`, then `show` a tick later), so it never flashes. */
.modal-backdrop {
    position: fixed !important;
    top: 0 !important;
    left: 0 !important;
    width: 100vw !important;
    height: 100vh !important;
    z-index: 9000 !important;
    background-color: rgba(0, 0, 0, 0.4875) !important;
    backdrop-filter: blur(7px) !important;
    -webkit-backdrop-filter: blur(7px) !important;
    opacity: 0;
    transition: opacity 0.15s linear;
}
.modal-backdrop.show {
    opacity: 1 !important;
}
.modal {
  z-index: 9001 !important;
}

/* backdrop-filter only blurs what is painted BEHIND the backdrop, so any
   fixed/sticky chrome stacked above 9000 stays crisp over a dimmed page.
   The navbar wrapper (99999, kept above the nav drawers at 10000) and the
   back-to-top button (10001) are the two that do; while a modal is open
   they drop under the backdrop so they dim and blur with everything else.
   Scoped to the open state rather than lowered outright because the nav
   strip has to paint over its own drawers. react-bootstrap puts
   .modal-open on <body>; :has() covers the case where it doesn't. */
body.modal-open .PT_navbar_wrapper,
body:has(.modal-backdrop) .PT_navbar_wrapper,
body.modal-open .back-to-top-btn,
body:has(.modal-backdrop) .back-to-top-btn {
    z-index: 1030 !important;
}

.modal-dialog {
    z-index: 9002 !important;
}

/* Project info card opened from a Staff Modal history tile sits above
   the staff card (9001) without replacing it. */
.modal.opsChart_stacked_modal {
    z-index: 9101 !important;
}
.modal-backdrop.opsChart_stacked_modal_backdrop {
    z-index: 9100 !important;
}

/* Staff card opened from a project-modal hours chip sits above the
   project card (9101). */
.modal.opsChart_stacked_staff_modal {
    z-index: 9201 !important;
}
.modal-backdrop.opsChart_stacked_staff_modal_backdrop {
    z-index: 9200 !important;
}

/* A person's name editor, opened from the bidder profile's Associated
   Individuals list, sits above the profile modal the same way, and so
   does an entity's card, opened from its tile. Narrower than the shared
   dialog width: the editor holds a short list of spellings and one field,
   the card is about as wide as one was when two sat across the profile,
   and at 1200px either would be mostly margin. */
.modal.sp-person-modal {
    z-index: 9101 !important;
}
.modal-backdrop.sp-person-modal-backdrop {
    z-index: 9100 !important;
}
.modal.sp-person-modal .modal-dialog {
    max-width: 680px;
}
/* A GC's subs (sub_profile._gc_subs_body) are Bidder List tables, which
   need about four fifths of the profile's width rather than the editor's. */
.modal.sp-person-modal.sp-person-modal--wide .modal-dialog {
    max-width: 960px;
}

.ml-auto {
    position: absolute;
    top: 6px;
    right: 6px;
    padding: 5px 10px;
    background: var(--button_color_dark) !important;
    text-align: center;
    color: var(--text_dark);
    border-radius: 6px;
    margin: 12px;
    font-family: var(--buttonfont);
    transition: var(--pt-transition);
}

.ml-auto:hover {
    border-radius: 12px;
}

.opsChart_role_type_stats .span_1,
.opsChart_role_type_stats .span_2 {
    font-size: var(--font_em_5);
    color: var(--text_dark);
    margin-bottom: 0;
    margin-top: 0;
    padding: 0;
}

/* !!! ________Staff_History_Modal_Stuff */
.staff-history-proj-card {
    background-color: var(--pt-body-medium);
    padding: 0.4rem;
    border-radius: 0.25rem;
}

button.staff-history-proj-card {
    display: block;
    width: 100%;
    border: none;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

/* When a project-card value wraps, keep its label pinned to the first line
   instead of vertically centring it against the taller value cell. */
.staff-history-proj-card .info_row {
    align-items: start;
}

.staff-project-card {
    background-color: var(--pt-body-medium);
    padding: 0.4rem;
    border-radius: 0.25rem;
}

/* ===================================================================================================================*/
/* !!! DESIGN DATA */
/* ===================================================================================================================*/

/* Category Explorer — three ranks, no new furniture.  Rank reads off type
   size and the page's existing marks rather than a stack of rules:

     Section         <h2>, carrying the standard page filet rouge
     Subsection      <h3> at three-quarters the size with a count chip,
                     separated by whitespace alone
     Sub-subsection  the in-grid hairline + small uppercase mono label

   That is one horizontal rule and one red mark in the whole body. */

/* ── Rank 1: Section (the selected category) ──────────────────────────── */

/* Deliberately unstyled apart from its margins: as a page-content H2 it
   inherits the app's H2 size and the red filet from
   #page-content h2::before, which is the mark every other page uses. */
.dd_cat_title {
    margin: 0 0 1.5em 0;
}

/* ── Rank 2: Subsection (SubCat1) ─────────────────────────────────────── */

.dd_sections {
    display: flex;
    flex-direction: column;
    gap: 2.75em;
}

.dd_section_block {
    /* Anchor target for the side-nav links; the offset keeps the heading
       visible below the sticky top bar when jumped to. */
    scroll-margin-top: var(--top-offset);
}

.dd_section_title_row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.65em;
    margin-bottom: 1em;
}

.dd_section_title_row h3.dd_section_title {
    font-size: var(--font_em_2B);
    line-height: 1.15;
    margin: 0;
    flex: 0 1 auto;
}

/* Small mono count chip on the H3's baseline, in the same neutral pt-body
   fill the landing tab counts use. */
.dd_section_count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.75em;
    height: 1.5em;
    padding: 0 0.55em;
    border-radius: 999px;
    background-color: var(--pt-body);
    color: var(--gray-700);
    font-family: var(--tablefont_mono);
    font-size: var(--font_em_5);
    line-height: 1;
    flex: 0 0 auto;
}

/* ── Rank 3: Sub-subsection (SubCat2) ─────────────────────────────────── */

/* In-grid divider — spans every column of the dmc.SimpleGrid via
   grid-column: 1 / -1.  The top margin is several times the grid's own
   'xs' gap, so the label sits with the cards it introduces rather than
   floating between two groups. */
.dd_sc2_divider {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 0.7em;
    margin: 1.35em 0 0;
}

.dd_sc2_divider:first-child {
    margin-top: 0;
}

.dd_sc2_divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background-color: var(--gray-200);
}

.dd_sc2_divider_label {
    font-family: var(--tablefont_mono);
    font-size: var(--font_em_5);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--gray-700);
    white-space: nowrap;
}

/* Side-nav: tiny mono ordinal before the SubCat1 label inside each nav
   button, numbering the links in page order. */
.dd_nav_num {
    font-family: var(--tablefont_mono);
    font-size: var(--font_em_5A);
    color: var(--gray-500);
    margin-right: 0.6em;
    letter-spacing: 0;
}

.button-menu.pt-btn:hover .dd_nav_num {
    color: var(--pt-accent-light);
}

/* Multi-regression card — pin button to bottom */
.card.mr-card {
    display: flex;
    flex-direction: column;
}
.mr-card-button-row {
    position: absolute;
    bottom: 1.2em;
    left: 0.8em;
    width: 50%;
}
/* Multi-regression equation — allow natural wrapping */
.mr-equation {
    font-size: var(--font_em_3A);
    line-height: 1.6;
    word-wrap: break-word;
}
.mr-equation .mr-eq-fn {
    font-style: italic;
}
.mr-equation .mr-eq-var {
    font-style: italic;
}
.mr-equation .mr-eq-coef {
    font-family: 'Courier New', monospace;
}
.mr-equation .mr-eq-op {
    padding: 0 3px;
}
.dd_title {
    margin-bottom: 0 !important;
}

.dd_subtitle {
    margin-top: 0 !important;
    color: var(--gray-400);
    margin-bottom: 0 !important;
}

.dd_units {
    font-family: var(--textfont);
}

/* Interactive chart copy inside each card's "More" modal — capped width and
   centered so the taller figure doesn't stretch edge-to-edge in the modal. */
.dd_modal_chart {
    max-width: 560px;
    margin: 0 auto 1.25em auto;
}

/* Project-highlight dropdown — sits under the interactive chart copy inside
   each card's "More" modal; kept visually quiet so the chart stays primary. */
.dd_highlight_dropdown {
    margin-top: 0.4em;
    font-size: var(--font_em_5);
}

/* ===================================================================================================================*/
/* !!! DESIGN_RECS */
/* ===================================================================================================================*/

.card.designrecs {
    padding-left: 1em;
    padding-right: 3em;
    padding-bottom: 1em;
}

.designrecs_content {
    line-height: 0.7em;
    word-break: normal;
}

.designrecs_content_row {
    font-family: var(--textfont);
    margin-bottom: 0;
    margin-top: 0.5em;
}

.designrecs_content_row.type1 {
    font-family: var(--headingfont);
    font-size: var(--font_em_2);
}
.designrecs_content_row.type2 {
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    margin-left: 2em;
    margin-top: 1em;
    border-bottom: 1px solid var(--pt-border);
}
.designrecs_content_row.type3 {
    font-size: var(--font_em_4);
    margin-left: 4em;
}
.designrecs_content_row.type4 {
    font-size: var(--font_em_4);
    margin-left: 6em;
}
.designrecs_content_row.type5 {
    font-size: var(--font_em_4);
    margin-left: 8em;
}
.designrecs_content_row.type6 {
    font-size: var(--font_em_4);
    margin-left: 10em;
}

.designrecs_content_row.bulletpoint {
    margin-top: 0;
    /* Nudge bullet rows slightly to the right of the parent paragraph's
       body-text x-position. ``padding-left`` (rather than ``margin-left``)
       keeps the row's outer ``typeN`` margin intact — which is what
       anchors the bullet to its parent level — and just shifts the
       row's content (invisible-number placeholder + bullet glyph +
       text) inward by the indent step. */
    padding-left: 1.5em;
}

/* Numerical-code spans (the ``01.01.02 | `` prefix on every body
   row) are partially monospace on the Design Recs / SOP pages so
   the digit column stays uniformly wide and bullets line up at
   exactly the parent paragraph's body-text x-position. Only the
   digit groups (``.code-number-part``) and their wrapper
   (``.formatted-numerical-code``) get monospace. The dots
   (``.code-period``) and the trailing ``" | "`` separator
   (``.sManual_number``) intentionally fall through to the global
   ``--textfont`` proportional rules so they take their naturally
   narrower advance — a monospace ``.`` or ``|`` carries the full
   digit advance, which makes the prefix column read as obviously
   over-spaced.

   Alignment is preserved because every row at the same hierarchy
   depth uses the same dot / pipe / space count: the proportional
   advance of those glyphs applies uniformly across the column, so
   row-to-row x-positions still line up exactly. Bullet rows use
   their parent's ``No.`` (same dot count) for the hidden
   placeholder, so their hang-point matches the parent's body-text
   x-position as well. */
.card.designrecs .formatted-numerical-code,
.card.designrecs .code-number-part {
    font-family: var(--tablefont_mono) !important;
}

.card.designrecs .code-number-part.type1,
.card.designrecs .code-number-part.type2 {
    font-family: var(--tablefont_mono_bold) !important;
}

.designrecs_container_wrapper {
    /* Plain block flow — the table aligns with its parent
       paragraph's left edge (via ``parent-typeN`` margin on the
       container below) and runs flush to the right margin. */
}

/* !!! ________Tables */

.designrecs_table_container {
    font-size: inherit;
    margin-top: 1rem;
    margin-bottom: 1rem;
    /* Width is implicitly ``parent-width minus margin-left``;
       the inner ``.designrecs_table`` keeps ``width: 100%`` so it
       fills whatever space the container leaves. */
}

/* Left-align tables with the parent paragraph's *body text*
   (not its number prefix). Each value is the parent row's
   ``margin-left`` (matching ``.designrecs_content_row.typeN``)
   plus an estimate of the level's number-prefix width — i.e.
   the rendered width of ``01.01.05 | `` and so on. The wider
   the number, the bigger the offset. Eyeball-tuned in ``em``
   so the table's left edge sits under the body text rather
   than under the number column. */
.designrecs_table_container.parent-type1 { margin-left: 3em;  }
.designrecs_table_container.parent-type2 { margin-left: 5.5em; }
.designrecs_table_container.parent-type3 { margin-left: 8em;  }
.designrecs_table_container.parent-type4 { margin-left: 11em; }
.designrecs_table_container.parent-type5 { margin-left: 14em; }
.designrecs_table_container.parent-type6 { margin-left: 17em; }

.designrecs_table {
    width: 100%;
    max-width: 100%;
    /* ``auto`` lets columns size to content, but combined with the
       cells' ``white-space: normal`` below, long cells wrap rather
       than push the table past its container's right edge. The
       container's effective width is ``card_width - left_padding -
       right_padding - parent-typeN.margin-left``, so the table's
       right edge always lands at the card's right padding. */
    table-layout: auto;
    font-family: var(--textfont);
}

.designrecs_table_data {
    vertical-align: top !important;
    padding: 6px 2px !important;
    box-sizing: border-box;
    /* Allow cell content to wrap onto multiple lines so a long
       sentence in one cell doesn't push the table off the right
       edge of the card. ``word-wrap: break-word`` is the
       belt-and-suspenders fallback for pathological cases (e.g. a
       single unbroken URL or hyphenated chemical name) where the
       browser otherwise refuses to break. */
    white-space: normal;
    word-wrap: break-word;
    overflow-wrap: break-word;
    width: auto;
}

.designrecs_header {
    font-family: var(--mediumfont) !important;
    padding: 2px !important;
    white-space: normal;
    word-wrap: break-word;
    overflow-wrap: break-word;
    width: auto;
}

.sManual_row_content_wrapper.docket {
    color: var(--monconred) !important;
}

.docket {
    color: var(--monconred) !important;
    font-size: var(--font_em_4);
}

.mpm {
    border-bottom: var(--sManual_link_bottom_border_2) !important;
}

.designrecs_toc_modifier {
    font-family: var(--tablefont);
}

/* TOC link sizing — the shared ``sManual_toc_link.typeN`` rules
   (around line 1763) set every TOC link to ``--font_em_4A``
   (0.75em), which reads as undersized on the Design Recs page
   where the surrounding section body is rendered at the much
   larger ``--font_em_2`` heading and ``--font_em_4`` body sizes.
   The Design Recs TOC container is emitted as ``card sManual toc``
   (see design_recs.py), NOT ``card designrecs toc``, so we scope
   via ``:has(.designRecs_toc_modifier)`` — a marker that only the
   Design Recs TOC rows carry — to bump the font while leaving the
   Safety Manual TOC (same container class) untouched. The TOC date
   column is intentionally NOT bumped — it sits at the right edge in
   a monospaced face and reads correctly at the smaller size. */
.card.sManual.toc:has(.designRecs_toc_modifier) .sManual_toc_link.type1,
.card.sManual.toc:has(.designRecs_toc_modifier) .sManual_toc_link.type2,
.card.sManual.toc:has(.designRecs_toc_modifier) .sManual_toc_link.type3 {
    font-size: var(--font_em_3);
}

/* ``##term##`` inline markup renders as ``<span class="topic_highlight">``
   in ``process_special_text_design_recs``. The shared
   ``.topic_highlight`` rule (around line 1490) uses ``--mediumfont``,
   which reads as a semibold weight on Pressura. On the Design Recs
   and SOP pages the user wants those spans to match the full
   heading weight (``--headingfont`` = ``GT-Pressura-Standard-Bold``)
   so the emphasis lands more decisively. Scope to ``.card.designrecs``
   so Site Response / Safety Manual keep the medium-weight default. */
.card.designrecs .topic_highlight {
    font-family: var(--headingfont);
}

/* ===================================================================================================================*/
/* !!! SOP */
/* The SOP page (utils/subapps/sop.py) is intentionally a visual twin of
   Design Recommendations. Its content rows reuse ``designrecs_content_row``
   wholesale via an additional ``sop_content_row`` marker class so any
   page-specific tweaks (e.g. the editorial-note line) can be scoped
   without affecting Design Recs. */
/* ===================================================================================================================*/

/* The outer card uses ``card designrecs sop`` so it inherits every
   ``card.designrecs`` rule above; this block exists only for SOP-only
   additions. */
.card.sop {
    /* placeholder: intentionally empty so SOP can diverge later without
       touching Design Recs styles. */
}

/* Editorial note: free-form ``Flag`` annotation, rendered as a small
   muted italic line hung under the parent row. Only appears when the
   on-screen ``Show Editorial Notes = Yes`` toggle is on. */
.sop_editorial_note {
    font-family: var(--textfont);
    font-style: italic;
    font-size: var(--font_em_5);
    color: var(--gray-600, #6b6f73);
    margin-top: 0.15em;
    margin-bottom: 0.35em;
    margin-left: 1.5em;
    line-height: 1.25;
}

/* Recent-edit highlight: rows whose ``ModDate`` equals the max
   ``ModDate`` in the dataset light up yellow when the user flips
   the ``Highlight Recent Edits`` toggle on. Reuses the same
   ``--sManual_yellow_highlight`` token the Safety Manual and TPB
   reports use for the on-screen yellow band so the visual language
   stays consistent. The rule covers both plain paragraph rows
   (``sop_content_row``) and individual table rows (``Tr``s tagged
   with the same modifier) — see ``utils/subapps/sop_functions.py``. */
.sop_recent_edit {
    background-color: var(--sManual_yellow_highlight) !important;
}

/* ``Internal Note`` column: free-form editorial annotation from the
   source author about a specific line (e.g. "this might belong
   elsewhere"). Rendered inline as red italic text immediately after
   the row's main content so the comment sits with the line it
   annotates. */
.sop_internal_note {
    color: var(--monconred);
    font-style: italic;
}

/* "Has internal note" marker: a small monconred dot anchored just
   inside the card's right padding so the reader can scan a long
   document and immediately spot which lines carry an editorial
   annotation from the source author. The dot is rendered regardless
   of whether the ``Show Internal Notes`` toggle is on — when off the
   dot is the only surface area of the annotation, telling the reader
   "there's a note here, flip the toggle to see it"; when on, it
   keeps the visual rhythm aligned across rows. Anchored ``right:
   -1.5em`` so the dot sits in the card's 3em right-padding zone
   instead of overlapping body text or wrapping anchors. */
.designrecs_content_row.sop_has_internal_note {
    position: relative;
}
.designrecs_content_row.sop_has_internal_note::after {
    content: "";
    position: absolute;
    top: 0.55em;
    right: -1.5em;
    width: 0.55em;
    height: 0.55em;
    border-radius: 50%;
    background-color: var(--monconred);
    pointer-events: none;
}

/* "Important change" flag: rows whose source ``Flag`` cell contains
   ``!!!`` hang a small bold-red ``!!!`` glyph in the card's left
   margin, vertically aligned with the start of the row's content.
   Reads like an icon so a reader scanning the document immediately
   spots an important new change. The marker is a real ``<span>``
   (see ``utils/subapps/sop_functions.py``) absolutely positioned
   against the row (which gets ``position: relative`` via the
   ``sop_flag_important`` class), so it floats left of the body text
   without taking part in the line's flow. */
.designrecs_content_row.sop_flag_important {
    position: relative;
}
.sop_flag_marker {
    position: absolute;
    left: -1.6em;
    top: 0;
    color: var(--monconred);
    font-family: var(--headingfont);
    font-weight: bold;
    font-size: var(--font_em_3);
    letter-spacing: -0.06em;
    line-height: 1;
    pointer-events: none;
    user-select: none;
}

/* Per-row ModDate pill — uses the shared ``make_inline_pill`` helper
   (``utils/functions.py``) so the styling matches every other pill on
   the site. Toggled on/off by the ``Show Mod Dates`` segmented
   control in ``utils/subapps/sop.py``. No dedicated CSS class —
   ``make_inline_pill`` carries its styling inline so we don't
   accumulate page-specific pill rules. */

/* "Latest Revision: MM/DD/YY" sub-heading rendered directly under
   the section's H1 (``type1`` row). The same date also appears in
   the TOC's date column for the matching section, so a reader
   scanning either index can immediately see when each section was
   last touched. Sized between the H1 and body type so it reads
   as a caption rather than a sibling heading. */
.sop_section_revdate {
    font-family: var(--textfont);
    font-size: var(--font_em_3A);
    color: var(--gray-600, #6b6f73);
    margin-left: 0;
    margin-top: -0.2em;
    margin-bottom: 0.6em;
    letter-spacing: 0.01em;
}

/* ===================================================================================================================*/
/* !!! BUDGET_SIMULATOR */
/* ===================================================================================================================*/

#budsim-table-top {
    scroll-margin-top: var(--top-offset);
}

.bidSim_trade_filter_card {
    background-color: var(--gray-025);
    border-radius: 0.7em;
    padding: 1em !important;
    margin-bottom: 1em;
    box-shadow: 2px 4px 12px #00000014;
    scroll-margin-top: var(--top-offset);
}

/* Unselected trade-filter cards share the unified disabled tokens. */
.bidSim_trade_filter_card_disabled {
    background-color: var(--pt-disabled-bg);
    border: 1px solid var(--pt-disabled-border);
    border-radius: 0.7em;
    padding: 1em !important;
    margin-bottom: 1em;
    box-shadow: none;
    color: var(--pt-disabled-text);
}

.bidSim_trade_filter_card_disabled .budSim_trade_filter_header,
.bidSim_trade_filter_card_disabled .budSim_filter_title {
    color: var(--pt-disabled-text) !important;
}

.budSim_filter_div {
    background-color: var(--gray-060);
    border-radius: 1em;
    padding: 0.5rem;
    min-height: 6em;
}

.budSim_trade_filter_header {
    font-family: var(--headingfont);
    font-size: var(--font_em_3A);
    color: var(--text_dark);
    margin-bottom: 0;
    margin-top: 0;
    margin-left: 0.5em;
    scroll-margin-top: var(--top-offset);
}

.budSim_trade_filter_header_row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75em;
    margin-bottom: 0.25em;
}

.budsim-return-top {
    display: inline-block;
    flex-shrink: 0;
    margin: 0;
    padding: 2px 10px;
    height: auto;
    line-height: 1.2;
    font-size: var(--font_em_5A);
}

.budSim_filter_title {
    font-family: var(--headingfont);
    font-size: var(--font_em_5);
    color: var(--text_dark);
    margin-bottom: 0.25rem;
    margin-top: 0;
}

.budSim_var_row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75em;
    margin-bottom: 1em;
}

/* Data + regression plot beside the variable picker on each trade card. It
   fills the grid row, whose height comes from the variable / pass-through /
   equation column next to it; the minimum keeps the plot usable on a trade
   whose column is short. */
.budSim_scatter {
    background-color: var(--gray-060);
    border-radius: 1em;
    padding: 0.5rem;
    overflow: hidden;
    height: 100%;
    min-height: 17rem;
}

/* Scroll target for the table's trade-name links, which swap the card in. */
#budsim-filters-top {
    scroll-margin-top: var(--top-offset);
}

/* Left column of a trade card: variable picker, pass-through, equation. */
.budSim_var_col {
    display: flex;
    flex-direction: column;
    gap: 0.6em;
}

.budSim_card_eq {
    font-family: var(--tablefont_mono);
    font-size: var(--font_em_4A);
    color: var(--text_dark);
    line-height: 1.5;
}

.budSim_card_eq_result {
    font-family: var(--tablefont_mono_bold);
    color: var(--monconred);
}

.bidSim_trade_filter_card_disabled .budSim_card_eq,
.bidSim_trade_filter_card_disabled .budSim_card_eq_result {
    color: var(--pt-disabled-text);
}

/* Numerator / denominator sit side by side inside one subsection. */
.budSim_var_pair {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 0.4em;
    align-items: center;
}

.budSim_var_divider {
    font-family: var(--tablefont_mono);
    font-size: var(--font_em_3A);
    color: var(--text_dark);
    text-align: center;
}

.bidSim_trade_filter_card_disabled .budSim_var_divider {
    color: var(--pt-disabled-text);
}

#budsim_coeff_table .budsim-var-key,
#budsim_coeff_table .budsim-hidden-params {
    display: none;
}

#budsim_coeff_table th,
#budsim_coeff_table td {
    padding: 0 0.4em 0 0 !important;
    vertical-align: middle;
    line-height: 14px;
}

#budsim_coeff_table th {
    font-family: var(--headingfont);
}

#budsim_coeff_table th.budsim-num {
    text-align: right;
    font-family: var(--headingfont);
}

#budsim_coeff_table td.budsim-num {
    text-align: right;
    font-family: var(--tablefont_mono);
}

#budsim_coeff_table .budsim-code {
    font-family: var(--tablefont_mono);
}

#budsim_coeff_table .budsim-trade-link {
    cursor: pointer;
}

#budsim_coeff_table .budsim-trade-link:hover {
    font-family: var(--headingfont);
}

#budsim_coeff_table .budsim-sel-cell {
    text-align: center;
    width: 1.4em;
    padding-right: 0.3em !important;
}

#budsim_coeff_table .budsim-formula-cell {
    white-space: nowrap;
    overflow: visible;
    position: relative;
    z-index: 1;
    text-align: right;
}

#budsim_coeff_table th.budsim-formula-cell {
    font-family: var(--headingfont);
}

#budsim_coeff_table tbody tr:focus-within .budsim-formula-cell {
    z-index: 30;
}

#budsim_coeff_table .budsim-formula {
    display: inline-flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 0;
    margin: 0;
    padding: 0;
    white-space: nowrap;
    font-family: var(--tablefont_mono);
}

#budsim_coeff_table .budsim-eq-op,
#budsim_coeff_table .budsim-eq-qty,
#budsim_coeff_table .budsim-eq-unit {
    font-family: var(--tablefont_mono);
    white-space: pre;
}

/* Unit picker sits in the equation as text, not as a control. The monospace
   family has to be declared here too: its width is set in ch, and Mantine's
   root would otherwise resolve that against the proportional UI font and
   leave a gap after the label.

   The negative margin reclaims the caret space the field reserves at its
   right edge (see _budsim_var_select_width). That strip is always empty, so
   overlapping it with the following character costs nothing and keeps the
   closing parenthesis against the label. */
#budsim_coeff_table .budsim-eq-dropdown {
    display: inline-block;
    flex: 0 0 auto;
    width: auto;
    vertical-align: baseline;
    font-family: var(--tablefont_mono);
    margin-right: -4px;
}

#budsim_coeff_table .budsim-eq-dropdown .mantine-Select-root,
#budsim_coeff_table .budsim-eq-dropdown .mantine-Select-wrapper {
    display: inline-block;
    width: 100%;
    min-height: 0;
    margin: 0;
}

#budsim_coeff_table .budsim-eq-dropdown .mantine-Select-input,
#budsim_coeff_table .budsim-eq-dropdown input {
    min-height: 0 !important;
    height: auto !important;
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
    border-radius: 0 !important;
    background-color: transparent !important;
    box-shadow: none !important;
    font-family: var(--tablefont_mono) !important;
    font-size: inherit !important;
    line-height: inherit !important;
    color: inherit !important;
    cursor: pointer;
}

#budsim_coeff_table .budsim-eq-dropdown input:focus {
    outline: none !important;
    box-shadow: none !important;
    background-color: var(--lightyellow) !important;
}

#budsim_coeff_table .budsim-eq-dropdown .mantine-Select-rightSection {
    display: none !important;
    width: 0 !important;
}

/* Naked in-cell field (same idea as .ms-edit-input): no .input2 chrome,
   so the row stays at ordinary table height. */
#budsim_coeff_table .budsim-cell-input {
    display: block;
    width: 100%;
    box-sizing: border-box;
    height: auto;
    min-height: 0;
    margin: 0;
    padding: 0;
    border: none;
    border-radius: 0;
    outline: none;
    box-shadow: none;
    background-color: transparent;
    font-size: inherit;
    font-family: inherit;
    line-height: inherit;
    text-align: right;
    color: inherit;
    appearance: none;
    -moz-appearance: textfield;
}

#budsim_coeff_table .budsim-cell-input::-webkit-outer-spin-button,
#budsim_coeff_table .budsim-cell-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* Width comes from the value's own length (set inline, in ch, against this
   monospace font) so the equation reads as continuous text instead of numbers
   right-aligned inside oversized boxes. Editing gets room to breathe. */
#budsim_coeff_table .budsim-eq-input {
    display: inline-block;
    width: auto;
    min-width: 2ch;
    font-family: var(--tablefont_mono);
    vertical-align: baseline;
}

#budsim_coeff_table .budsim-eq-input:focus {
    min-width: 10ch;
}

#budsim_coeff_table .budsim-cell-input:focus {
    outline: none;
    box-shadow: none;
    background-color: var(--lightyellow);
}

/* Rows switched off read as struck-through and faded, leaving the table's
   alternating row shading untouched. */
#budsim_coeff_table .budsim-row-off td {
    color: var(--gray-400);
    text-decoration: line-through;
}

#budsim_coeff_table .budsim-row-off .budsim-trade-link {
    color: var(--gray-400);
    text-decoration: line-through;
}

/* Per-row constant toggle: standard .button1 look and hover, just sized
   down to table-row height (same approach as .budsim-return-top). */
#budsim_coeff_table .budsim-zero-btn {
    display: inline-block;
    margin: 0;
    padding: 1px 6px;
    height: auto;
    line-height: 1.2;
    font-size: var(--font_em_5A);
    white-space: nowrap;
}

/* Banner over the histogram when the shown results predate current inputs. */
.budsim-stale-warning {
    background-color: var(--monconred-tint);
    color: var(--monconred);
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
    padding: 4px 8px;
    margin-bottom: 0.5em;
    border-radius: 4px;
    border-left: 3px solid var(--monconred);
}

/* Says why a row reads the way it does: the equation's own result was
   negative and a trade cannot cost less than nothing, or a field holds
   something that isn't a number. Empty for every other row, so it takes no
   space until it has something to say.

   On its own line under the trade name rather than beside it — these
   messages run longer than the column is wide, and widening the column
   would push Total / GSF / DU off the right edge of the scroll box. */
#budsim_coeff_table .budsim-row-warning:not(:empty) {
    display: block;
    color: var(--monconred);
}

/* General Conditions is carried in its own tbody after the trade subtotal, so
   the app-wide zebra rule counts it as row one and always tints it. It reads
   as a standalone line rather than part of the striped trade list, so leave it
   plain. */
#budsim_coeff_table #budsim_gc_tbody tr td {
    background-color: transparent;
}

/* Every summary line — trade subtotal, the running subtotals between the
   markups, and the bottom line — shares one treatment: bold, standard text
   color, hairline above, and no zebra fill. */
#budsim_coeff_table .budsim-total-row td,
#budsim_coeff_table .budsim-subtotal-row td,
#budsim_coeff_table .budsim-bottom-row td {
    font-family: var(--tablefont_bold);
    color: var(--text_dark);
    border-top: 1px solid var(--pt-border);
    background-color: transparent !important;
}

#budsim_coeff_table .budsim-total-row td.budsim-num,
#budsim_coeff_table .budsim-subtotal-row td.budsim-num,
#budsim_coeff_table .budsim-bottom-row td.budsim-num {
    font-family: var(--tablefont_mono_bold);
}

/* A coefficient or constant moved off the regression's own value reads red
   until a refit puts the fitted number back. */
#budsim_coeff_table .budsim-eq-edited {
    color: var(--monconred);
}

/* Row actions sit side by side in one narrow cell. */
#budsim_coeff_table .budsim-actions-cell {
    white-space: nowrap;
}

#budsim_coeff_table .budsim-add-btn {
    padding: 1px 5px;
    margin-left: 3px;
}

/* Added trade lines: code / name are typed, so give them visible fields. */
#budsim_coeff_table .budsim-custom-code-input {
    text-align: left;
    font-family: var(--tablefont_mono);
}

#budsim_coeff_table .budsim-custom-name-input {
    text-align: left;
}

#budsim_coeff_table .budsim-custom-code-input::placeholder,
#budsim_coeff_table .budsim-custom-name-input::placeholder {
    color: var(--gray-400);
}

/* Markup lines read lighter than the subtotals they sit between. */
#budsim_coeff_table .budsim-markup-row td {
    background-color: transparent !important;
}

#budsim_coeff_table .budsim-markup-row td.budsim-num {
    font-family: var(--tablefont_mono);
}

/* Editable markup percentage, right-aligned under the Formula column so the
   rate sits directly above/below the equations it marks up. */
#budsim_coeff_table .budsim-pct-wrap {
    display: inline-flex;
    align-items: baseline;
    justify-content: flex-end;
    font-family: var(--tablefont_mono);
}

#budsim_coeff_table .budsim-pct-input {
    display: inline-block;
    width: 4.5em;
    font-family: var(--tablefont_mono);
}

#budsim_coeff_table .budsim-pct-sign {
    font-family: var(--tablefont_mono);
    padding-left: 1px;
}

#budsim_coeff_table .budsim-row-off td.budsim-num > *,
#budsim_coeff_table .budsim-row-off td.budsim-formula-cell > * {
    visibility: hidden;
}

#budsim_coeff_table .mantine-Checkbox-root {
    margin: 0;
}

#budsim_coeff_table .mantine-Checkbox-inner,
#budsim_coeff_table .mantine-Checkbox-input {
    width: 12px;
    height: 12px;
}

#budsim_coeff_table .mantine-Checkbox-input,
#budsim_coeff_table .mantine-Checkbox-input:hover,
#budsim_coeff_table .mantine-Checkbox-input:checked:hover {
    transform: none;
    box-shadow: none;
}

#budsim_coeff_table input[type='number']::-webkit-inner-spin-button,
#budsim_coeff_table input[type='number']::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* ===================================================================================================================*/
/* !!! SITE_RESPONSE */
/* ===================================================================================================================*/

.card.siteResponse {
    font-family: var(--textfont);
    padding-top: 1em;
    padding-bottom: 3em;
    color: var(--text_dark);
}

.card.siteResponse h4 {
    font-family: var(--headingfont);
    font-size: var(--font_em_2) !important;
    margin-bottom: .2rem;
    margin-top: 0 !important;
}

.card.siteResponse h4::before {
  content: "";
  display: block;
  height: 0.75em;
  background: var(--safety_hatch);
  border-radius: 3px;
}

.card.siteResponse .code-number-part {
    font-family: var(--mediumfont) !important;
}

.card.siteResponse .code-number-part.type1 {
    font-family: var(--headingfont) !important;
}

.siteRespo_content {
    overflow-wrap: normal;
    word-break: normal;
    line-height: .7em;
}

.siteRespo_content_row {
    margin-bottom: 0;
    margin-top: 0.25em;
    font-family: var(--textfont);
}

.siteRespo_content_row.type1 {
    font-family: var(--headingfont);
    font-size: var(--font_em_3);
    margin-bottom: 0.1em;
    margin-top: 1em;
    margin-left: 0;
}

.siteRespo_content_row.type2 {
    font-size: var(--font_em_4);
    margin-left: 2em;
}
.doc_links_container.type2 {
    margin-left: 4em;
}

.siteRespo_content_row.type3 {
    font-size: var(--font_em_4);
    margin-left: 4em;
}
.doc_links_container.type3 {
    margin-left: 6em;
}

.siteRespo_content_row.type4 {
    font-size: var(--font_em_4);
    margin-left: 6em;
}
.doc_links_container.type4 {
    margin-left: 8em;
}

.siteRespo_content_row.type5 {
    font-size: var(--font_em_4);
    margin-left: 8em;
}
.doc_links_container.type5 {
    margin-left: 10em;
}

.siteRespo_content_row.bulletpoint {
    margin-top: 0;
}

.card.siteResponse .topic_highlight {
    font-family: var(--mediumfont) !important;
    background-color: var(--lightyellow);
    word-break: normal;
}

.cc_grid_container {
    display: grid;
    grid-template-columns: 0.75fr 2fr 2fr 0.5fr;
    gap: 0;
    font-family: var(--textfont);
    font-size: var(--font_em_4);
}

.cc_grid_row {
    display: contents;
    position: relative;
}

.cc_grid_row:hover {
    font-family: var(--headingfont);
}

.cc_grid_item{
    padding: 0;
    border: none;
    white-space: nowrap;
    overflow: hidden;
}
.cc_grid_item.monobold {
    font-family: var(--tablefont_mono_bold);
}

.cc_grid_header {
    font-family: var(--headingfont);
    border-bottom: 1px solid var(--gray-750);
}

.deprecated {
    background-color: var(--pt-body-medium);
    color: var(--gray-400);
    text-decoration: line-through;

}

.update {
    background-color: var(--lightyellow);
}

.ccip_cost {
    background-color: var(--lightblue);
    color: var(--gray-400);
    text-decoration: line-through;
}

/* !!! ===============================================================================================================*/
/* !!! LEGEND  */
/* ===================================================================================================================*/

.legend_goal_value {
    background-color: var(--gray-100);
}

.legend_certified_value {
    background-color: var(--lightyellow);
}

/* !!! ===============================================================================================================*/
/* !!! ESTIMATE MODELS  */
/* ===================================================================================================================*/

.best_model_badge {
    position: absolute;
    top: -10px;
    right: -10px;
    width: 50px;
    height: 50px;
    background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
    clip-path: polygon(
        50% 0%,
        61% 35%,
        98% 35%,
        68% 57%,
        79% 91%,
        50% 70%,
        21% 91%,
        32% 57%,
        2% 35%,
        39% 35%
    );
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 8px rgba(255, 165, 0, 0.4);
    border: 1px solid var(--gray-750);
}

/* !!! ===============================================================================================================*/
/* !!! COST MODEL  */
/* ===================================================================================================================*/

:root { --cm_table_fontsize: 10px; }

/* --- Audit Table --- */
.cm-audit-table        { width: 100%; border-collapse: collapse; }

.cm-th                 { padding: 3px 0; font-family: var(--headingfont);   border-bottom: 2px solid var(--pt-border);white-space: nowrap;
                         font-size: var(--font_em_2C);
                        }

.cm-td                 { vertical-align: top; border-bottom: 1px solid var(--gray-500);
                         font-family: var(--tablefont) !important;
                        }
table.cm-audit-table td { padding: 3px 0 !important; }

.cm-td-mono            { padding: 5px 0; border-bottom: 1px solid var(--pt-border);
                         text-align: right; vertical-align: middle;
                         font-family: var(--tablefont_mono) !important;}

/* Zebra on the per-section input / adjustments tables. Mix the gray-050
   token with 10% white so the banding is a touch lighter than the raw
   token — subtle stripes that read on dense rows without feeling heavy. */
table.cm-audit-table tbody tr:nth-child(even) td {
    background-color: color-mix(in srgb, var(--gray-050) 90%, #fff 10%);
}

/* Total Cost Model's large data table (make_table output inside
   #oc_table) gets the same 10%-lighter treatment, scoped to that table
   only so the CSI Cost Model summary table and other table.hover
   instances across the app keep their existing zebra. */
#oc_table table.hover tbody tr:nth-child(odd) td {
    background-color: color-mix(in srgb, var(--gray-150) 90%, #fff 10%);
}

.cm-td-middle          { vertical-align: middle; }
.cm-td-center          { text-align: center; }
.cm-td-right           { text-align: right; }

.cm-col-36             { width: 36px; }
.cm-col-44             { width: 44px; }
.cm-col-60             { width: 60px; }
.cm-col-72             { width: 72px; }
.cm-col-90             { width: 90px; }
.cm-col-115            { width: 115px; }
.cm-col-120            { width: 120px; }

.cm-dir                { margin-right: 3px; flex-shrink: 0; }
.cm-dir-minus          { color: #e05555; }
.cm-dir-plus           { color: #4a9e6b; }
.cm-dir-pm             { color: var(--gray-500); }

.cm-adj-lbl            { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; max-width: 110px;
                         font-family: var(--tablefont) !important;
}

.cm-delta              { font-family: var(--tablefont_mono) !important;}
.cm-unit               { margin-left: 2px; white-space: nowrap;
                         flex-shrink: 0;
                        }

.cm-row-h              {
                        height: 17px;
                        display: flex; align-items: center;
                        vertical-align: middle; line-height: 1;
                        margin-bottom: 2px;
                        }
.cm-row-h-center       {
                        height: 17px;
                        display: flex; align-items: center; justify-content: center; vertical-align: middle; }
.cm-row-h-right        {
                        height: 17px;
                        display: flex; align-items: center; justify-content: flex-end;
                        vertical-align: middle; line-height: 1;
                        }
.cm-implied-val        { white-space: nowrap; }

.cm-pred-auto          { font-style: italic; }
.cm-fac-input          { width: 68px; height: 15px; padding: 0 3px; flex-shrink: 0;vertical-align: middle; }
.cm-switch-no-mb       { margin-bottom: 0; }

/* --- N Count Rows (stacked per sub-adjustment) --- */
.cm-n-row              {
                        height: 17px;
                        display: flex; align-items: center; justify-content: flex-end;vertical-align: middle;
                        }

/* Subtle N=0 indicator: light red pill on the value only. */
.cm-n-zero-pill {
    color: var(--monconred);
    font-weight: 600;
}

/* ── Back-to-top button — flat alt palette ──────────────────────────────── */
.back-to-top-btn {
    position: fixed;
    bottom: 2rem;
    left: 50%;
    transform: translateX(-50%) translateY(16px);
    width: 40px;
    height: 40px;
    border-radius: 0;
    background-color: var(--pt-body-medium) !important;
    color: var(--text_dark) !important;
    border: none !important;
    box-shadow: none !important;
    font-size: var(--font_em_2C);
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition:
        opacity var(--button-link-transition-duration) ease,
        transform var(--button-link-transition-duration) ease,
        background var(--button-link-transition-duration) ease,
        /* square at rest, circle on hover, like every other button */
        border-radius var(--button-link-transition-duration) var(--ease-pill);
    pointer-events: none;
    z-index: 10001;
    display: flex;
    align-items: center;
    justify-content: center;
}
.back-to-top-btn.btt-visible {
    opacity: 0.3;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
}
.back-to-top-btn.btt-visible:hover {
    opacity: 1;
    background: var(--gray-900);
}

/* !!! ===============================================================================================================*/
/* !!! MERGED ALT THEME RULES (no base-file equivalent)                                                                */
/* ===================================================================================================================*/
/* These rules originated in style-alt-overrides.css and have no direct counterpart in the base stylesheet. They still
   carry !important conservatively to beat library defaults (Bootstrap, Mantine, Plotly, react-select, AG Grid). */

/* -------------------------------------------------------------------------- */
/* Section H4 tone — match section H1 tone (--gray-750)                       */
/* -------------------------------------------------------------------------- */
#page-content h4,
.main-container h4 {
    color: var(--text_dark) !important;
}

/* Warning cards: header text must stay in warning red. This beats the
   #page-content / .main-container h4 ID-specificity rule above. */
#page-content .card.warning h4,
#page-content .card.warning h1,
#page-content .card.warning h2,
#page-content .card.warning h3,
#page-content .card.warning h5,
#page-content .card.warning h6,
.main-container .card.warning h4,
.main-container .card.warning h1,
.main-container .card.warning h2,
.main-container .card.warning h3,
.main-container .card.warning h5,
.main-container .card.warning h6 {
    color: var(--monconred) !important;
}

/* Disabled / inactive cards (.card.disabled used by Curves, .card-dashed used
   by Project Summary for not-yet-started projects): all header levels must
   render in the unified disabled text color. This beats the #page-content /
   .main-container h4 ID-specificity rule above. */
#page-content .card.disabled h1,
#page-content .card.disabled h2,
#page-content .card.disabled h3,
#page-content .card.disabled h4,
#page-content .card.disabled h5,
#page-content .card.disabled h6,
#page-content .card-dashed h1,
#page-content .card-dashed h2,
#page-content .card-dashed h3,
#page-content .card-dashed h4,
#page-content .card-dashed h5,
#page-content .card-dashed h6,
.main-container .card.disabled h1,
.main-container .card.disabled h2,
.main-container .card.disabled h3,
.main-container .card.disabled h4,
.main-container .card.disabled h5,
.main-container .card.disabled h6,
.main-container .card-dashed h1,
.main-container .card-dashed h2,
.main-container .card-dashed h3,
.main-container .card-dashed h4,
.main-container .card-dashed h5,
.main-container .card-dashed h6 {
    color: var(--pt-disabled-text) !important;
}

/* -------------------------------------------------------------------------- */
/* Landing hero: column labels + cards sit over dark photo                   */
/* -------------------------------------------------------------------------- */
.wrapper.landing-page-active .landing_column_title {
    color: rgba(230, 230, 230, 0.88) !important;
}

/* Landing grid only: frosted tiles over hero */
.wrapper.landing-page-active .landing_card {
    background: rgba(255, 255, 255, 0.1) !important;
    backdrop-filter: blur(14px) saturate(1.25) !important;
    -webkit-backdrop-filter: blur(14px) saturate(1.25) !important;
    border: 1px solid rgba(255, 255, 255, 0.16) !important;
    border-radius: 0;
    color: rgba(255, 255, 255, 0.95);
    box-shadow: none !important;

    /* Uniform card height + stacked title/description for hover swap.
       Geometry is fully locked (box-sizing, height, min/max-height, fixed
       padding) so hovering NEVER changes tile size and siblings cannot be
       pushed down when the title↔description crossfade runs. */
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: 1fr;
    align-items: start;
    box-sizing: border-box;
    /* Card geometry — sized so the longest 3-line description fits without
       clipping when hover swaps title -> text. Locked top/bottom so the
       crossfade NEVER changes tile height (would shove neighbors). */
    height: 5.75rem;
    min-height: 5.75rem;
    max-height: 5.75rem;
    padding: 0.55em 0.8em;
    gap: 0;
    overflow: hidden;
    transition:
        background 260ms ease,
        border-color 260ms ease,
        border-radius 260ms ease;
}

/* When the card sits inside the new tabbed .landing_grid, the parent gap
   handles spacing between tiles — clear the legacy margin so columns and
   rows align cleanly. */
.wrapper.landing-page-active .landing_grid .landing_card {
    margin-bottom: 0;
}

.wrapper.landing-page-active .landing_card:hover {
    background: rgba(255, 255, 255, 0.18) !important;
    border-color: rgba(255, 255, 255, 0.24) !important;
    border-radius: 14px;
    /* Padding intentionally unchanged on hover — changing it would shift
       tile geometry and push neighboring tiles in the column. */
}

/* Disabled hero-landing tile: keep the frosted geometry so the grid layout
   stays uniform, but dim it and disable hover/interaction. The unauthorized
   user still sees the tile (so they know the page exists) but cannot navigate
   to it. The title↔description crossfade is suppressed via opacity overrides
   on hover so the dimmed state stays stable. */
.wrapper.landing-page-active .landing_card.disabled,
.wrapper.landing-page-active .landing_card.disabled:hover {
    background: rgba(255, 255, 255, 0.06) !important;
    border-color: rgba(255, 255, 255, 0.1) !important;
    border-radius: 0;
    cursor: not-allowed;
    opacity: 0.45;
    pointer-events: none;
}

.wrapper.landing-page-active .landing_card.disabled .landing_card_title {
    text-decoration: line-through;
}

.wrapper.landing-page-active .landing_card.disabled:hover .landing_card_title {
    opacity: 1;
    transform: translateY(0);
}

.wrapper.landing-page-active .landing_card.disabled:hover .landing_card_text {
    opacity: 0;
    transform: translateY(4px);
}

/* Stack title and description in the same grid cell so they can crossfade.
   min-height/min-width: 0 prevents the grid track from expanding to the
   intrinsic content size (default `auto`), which would otherwise push the
   tile taller and shove sibling tiles in the column. */
.wrapper.landing-page-active .landing_card_title,
.wrapper.landing-page-active .landing_card_text {
    grid-column: 1 / 2;
    grid-row: 1 / 2;
    margin: 0;
    min-height: 0;
    min-width: 0;
    transition:
        opacity 420ms cubic-bezier(0.2, 0.8, 0.2, 1),
        transform 420ms cubic-bezier(0.2, 0.8, 0.2, 1);
    will-change: opacity, transform;
    pointer-events: none;
}

.wrapper.landing-page-active .landing_card_title {
    color: var(--text_color_dark) !important;
    letter-spacing: -0.02em;
    /* Allow 2-line wrapping instead of single-line ellipsis */
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.15;
    opacity: 1;
    transform: translateY(0);
}

.wrapper.landing-page-active .landing_card_text {
    color: rgba(255, 255, 255, 0.78) !important;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    line-height: 1.3;
    opacity: 0;
    transform: translateY(4px);
}

.wrapper.landing-page-active .landing_card:hover .landing_card_title {
    opacity: 0;
    transform: translateY(-4px);
}

.wrapper.landing-page-active .landing_card:hover .landing_card_text {
    opacity: 1;
    transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
    .wrapper.landing-page-active .landing_card_title,
    .wrapper.landing-page-active .landing_card_text {
        transition: opacity 120ms linear;
        transform: none !important;
    }
}

/* -------------------------------------------------------------------------- */
/* Dash DataTable — even-row td tint (overrides the td bg in .dash-cell)     */
/* -------------------------------------------------------------------------- */
.dash-spreadsheet tbody tr:nth-child(even) td {
    background-color: var(--pt-body-light) !important;
}

.dash-filter input {
    background-color: transparent !important;
    color: var(--text_dark) !important;
    border: 1px solid var(--pt-border) !important;
    border-radius: 2px;
}

/* -------------------------------------------------------------------------- */
/* react-select — extra inner elements not styled by base                    */
/* -------------------------------------------------------------------------- */
.Select-placeholder,
.Select-value-label,
.Select-input > input {
    color: var(--text_dark) !important;
}

.Select-option.is-focused {
    background-color: var(--pt-accent-light-05) !important;
}

/* -------------------------------------------------------------------------- */
/* Mantine inputs — TextInput / NumberInput / Textarea / Input not in base   */
/* -------------------------------------------------------------------------- */
.mantine-Input-input,
.mantine-TextInput-input,
.mantine-NumberInput-input,
.mantine-Textarea-input {
    background-color: transparent !important;
    color: var(--text_dark) !important;
    border: 1px solid var(--pt-border) !important;
    border-radius: 0.5rem;
}

/* -------------------------------------------------------------------------- */
/* Plotly                                                                    */
/* -------------------------------------------------------------------------- */
.js-plotly-plot .plotly .main-svg {
    border-radius: 2px;
}

/* Keep the modebar tray transparent until interaction (Plotly fades in on hover) */
.js-plotly-plot .plotly .modebar {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
}

.js-plotly-plot .plotly .modebar-btn {
    color: var(--text_dark) !important;
}

/* -------------------------------------------------------------------------- */
/* Scroll-driven H1 scramble reveal (per-char spans applied by                */
/* alt-heading-reveal.js). Chars show random glyphs and settle left-to-right */
/* into the real text when the heading enters the viewport. All timing lives */
/* in the JS; this CSS only keeps the churning glyphs from shifting layout   */
/* (each span's width is locked inline by the JS to its real glyph's width). */
/* -------------------------------------------------------------------------- */
#page-content .alt-heading-reveal .ahc,
.main-container .alt-heading-reveal .ahc {
    display: inline-block;
    text-align: center;
    white-space: pre;
    will-change: contents;
}

/* -------------------------------------------------------------------------- */
/* Kinetic red: content-change flash for any element tagged                   */
/* .pt-kinetic-number. pt-kinetic-number.js watches for text mutations and    */
/* re-applies .pt-kinetic-flash--on to retrigger the animation, giving KPI    */
/* values, counters, and live totals the same red→settle motion vocabulary   */
/* as the H1 typewriter reveal.                                               */
/* -------------------------------------------------------------------------- */
@keyframes pt-kinetic-flash {
    0%   { color: var(--monconred); }
    100% { color: var(--text_dark); }
}

.pt-kinetic-number.pt-kinetic-flash--on {
    animation: pt-kinetic-flash 900ms ease forwards;
}

@media (prefers-reduced-motion: reduce) {
    .pt-kinetic-number.pt-kinetic-flash--on {
        animation: none;
        color: var(--text_dark);
    }
}

/* -------------------------------------------------------------------------- */
/* Keyboard focus ring: single red accent reserved for :focus-visible so      */
/* mouse users never see it, but keyboard/accessibility users get a clear     */
/* brand-consistent indicator. :where() keeps specificity at 0 so any         */
/* component-specific focus style still wins.                                 */
/*                                                                            */
/* IMPORTANT: every selector below excludes descendants of Mantine components */
/* (`.mantine-* *`, plus the root elements themselves). Mantine v6 ships its  */
/* own accessible focus ring and — critically — dmc.MultiSelect's dropdown    */
/* closes as soon as focus lands on any of its internal descendants that      */
/* isn't part of its Popover tree. When we painted a bright red outline on    */
/* the tag remove-buttons and the internal search <input> we were (a)         */
/* showing phantom red halos inside the select, and (b) causing the menu to   */
/* flash open and immediately dismiss. Leaving Mantine to manage its own      */
/* focus rings fixes both symptoms.                                           */
/* -------------------------------------------------------------------------- */
:where(
    a,
    button,
    [role="button"],
    [tabindex]:not([tabindex="-1"]),
    input:not([type="checkbox"]):not([type="radio"]),
    select,
    textarea,
    summary,
    .pt-btn,
    .PT_dropdownLink,
    .section-nav-drawer-link
):focus-visible {
    outline: 2px solid var(--monconred-focus);
    outline-offset: 2px;
    border-radius: inherit;
}

/* Opt Mantine-component internals OUT of the app-wide red focus ring.
   Mantine v6 ships its own accessible focus ring; when we painted our
   red outline on the MultiSelect's internal search <input> and its tag
   remove-buttons (class names like .mantine-MultiSelect-searchInput,
   .mantine-MultiSelect-defaultValueRemove, .mantine-CloseButton, etc.)
   two things broke:
     1. Phantom red halos appeared inside the select — the outline is
        offset 2px so on tiny remove-X buttons it reads as loose red
        speckle, not an intentional focus mark.
     2. dmc.MultiSelect's Popover treats focus moving to any of those
        descendants as "focus left the input", which causes the dropdown
        menu to flash open and immediately dismiss. End-user symptom:
        "the menu won't open."
   Reverting outline/outline-offset here restores Mantine's own focus
   ring, which is already brand-neutral and accessible. :where() keeps
   specificity at 0 so any deliberate component override still wins. */
:where([class*="mantine-"]):focus-visible,
:where([class*="mantine-"] *):focus-visible {
    outline: revert;
    outline-offset: revert;
}

/* Nav-drawer links are app components that merely *live inside* a Mantine
   Drawer, so the blanket Mantine opt-out above would hand them the browser's
   default (blue) focus outline. Re-assert the app-wide red :focus-visible
   ring for them so a blue ring can never appear in the drawer. The drawer's
   inner wrapper carries tabIndex=-1 + data-autofocus (see main_layout.py) so
   Mantine's focus trap lands there on open — no link gets auto-focused — and
   the wrapper itself must never paint a ring. */
.mantine-Drawer-drawer .drawer_inner_wrapper:focus,
.mantine-Drawer-drawer .drawer_inner_wrapper:focus-visible {
    outline: none;
}
.mantine-Drawer-drawer .PT_dropdownLink:focus-visible {
    outline: 2px solid var(--monconred-focus);
    outline-offset: 2px;
    border-radius: inherit;
}

/* ========================================================================== */
/* !!! RED_GRAPHIC_SYSTEM                                                     */
/* -------------------------------------------------------------------------- */
/* Opt-in utility classes that give authors a shared graphic vocabulary for   */
/* --monconred. Every class is inert until applied, so adding them anywhere   */
/* in the app does NOT increase global red density — scarcity is enforced by  */
/* the author, not the stylesheet. All consume the derived tokens (or the    */
/* raw --monconred where full saturation is required for the graphic mark).  */
/* ========================================================================== */


/* -------------------------------------------------------------------------- */
/* 1. EDITORIAL / SWISS TYPOGRAPHIC MARKS                                     */
/*    Micro-glyphs that earn red its "signal character" status one mark       */
/*    at a time. Apply to <span>, or to a parent where noted.                 */
/* -------------------------------------------------------------------------- */

/* Leading numeral before a section heading: "01 · Overview"
   Usage: <h2><span class="pt-red-numeral">01</span> Overview</h2> */
.pt-red-numeral {
    color: var(--monconred);
    font-family: var(--headingfont);
    font-variant-numeric: tabular-nums;
    margin-right: 0.45em;
}

/* Red drop-cap on the first paragraph of an intro block.
   Usage: <p class="pt-red-dropcap">Lorem ipsum dolor…</p> */
.pt-red-dropcap::first-letter {
    float: left;
    font-family: var(--headingfont);
    font-size: 3.2em;
    line-height: 0.85;
    color: var(--monconred);
    padding: 0.05em 0.12em 0 0;
}

/* Pilcrow / section / number-sign lead-ins. Used BEFORE the content of the
   tagged inline element: <span class="pt-red-pilcrow">Note text</span> */
.pt-red-pilcrow::before { content: "¶ "; color: var(--monconred); }
.pt-red-section::before { content: "§ "; color: var(--monconred); }
.pt-red-numero::before  { content: "№ "; color: var(--monconred); }

/* Leading symbol in a KPI value: only the $/€/% glyph is red, digits stay
   in --text_dark. Usage: <span class="pt-red-symbol">$</span>1,240,000 */
.pt-red-symbol {
    color: var(--monconred);
    font-family: var(--headingfont);
    margin-right: 0.05em;
}

/* Red decimal point in a headline number.
   Usage: $1,240,000<span class="pt-red-decimal">.</span>00 */
.pt-red-decimal {
    color: var(--monconred);
    font-family: var(--headingfont);
}

/* Footnote marker (†, ‡, *) — superscripted, subtle.
   Usage: 12.4%<sup class="pt-red-foot">†</sup> */
.pt-red-foot {
    color: var(--monconred);
    font-size: 0.7em;
    vertical-align: super;
    line-height: 0;
    padding-left: 0.15em;
}

/* Red em-dash used as metadata separator.
   Usage: Project A <span class="pt-red-sep">—</span> Q3 2026 */
.pt-red-sep {
    color: var(--monconred);
    padding: 0 0.35em;
}

/* Red folio line: "— 14 —" style with red flanking dashes. Set the page
   number via data-folio: <span class="pt-red-folio" data-folio="14"></span> */
.pt-red-folio {
    display: inline-block;
    font-family: var(--headingfont);
    font-size: 0.72em;
    letter-spacing: 0.12em;
    color: var(--text_dark);
}
.pt-red-folio::before,
.pt-red-folio::after {
    content: "—";
    color: var(--monconred);
    padding: 0 0.4em;
}
.pt-red-folio::before { content: "— "; }
.pt-red-folio::after  { content: attr(data-folio) " —"; color: var(--monconred); }


/* -------------------------------------------------------------------------- */
/* 2. STRUCTURAL HAIRLINES — extended filet rouge                             */
/*    Thin red rules used as architectural dividers and leader lines.         */
/* -------------------------------------------------------------------------- */

/* Thin red vertical rule between columns. Place as a flex/grid child,
   or use inside a flex row. */
.pt-red-vrule {
    align-self: stretch;
    flex: 0 0 1px;
    width: 1px;
    background: var(--monconred-line);
    margin: 0 1rem;
}

/* Dimension line: horizontal hairline with 6px tick marks at each end
   (├────┤). Place directly under a number as its "measurement bar". */
.pt-red-dimline {
    position: relative;
    height: 8px;
    margin-top: 0.25em;
}
.pt-red-dimline::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 1px;
    background: var(--monconred);
}
.pt-red-dimline::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    border-left: 1px solid var(--monconred);
    border-right: 1px solid var(--monconred);
}

/* Leader line: hairline with a 5px red dot on the LEFT end, pointing away
   from an annotation toward the referenced element. */
.pt-red-leader {
    position: relative;
    height: 1px;
    background: var(--monconred);
    margin: 0.4em 0;
}
.pt-red-leader::before {
    content: "";
    position: absolute;
    left: -1px;
    top: 50%;
    width: 6px;
    height: 6px;
    transform: translateY(-50%);
    background: var(--monconred);
    border-radius: 50%;
}

/* Corner tab: a 3px × 24px red bar pinned to the top-right of a card.
   Mirrors the left-rail pattern used for active nav items, so "primary"
   cards and "active" nav share one visual language. */
.pt-red-tab {
    position: relative;
}
.pt-red-tab::after {
    content: "";
    position: absolute;
    top: 10px;
    right: 0;
    width: 3px;
    height: 24px;
    background: var(--monconred);
    border-radius: 2px 0 0 2px;
    pointer-events: none;
}


/* -------------------------------------------------------------------------- */
/* 3. BRUTALIST-MODERN BLOCK MOVES                                            */
/*    Larger graphic gestures — still opt-in, still rare by design.           */
/* -------------------------------------------------------------------------- */

/* Oversized red-tint numeral living BEHIND a section as a folio mark.
   Usage: <section class="pt-red-bignum" data-bignum="03">…</section>
   The numeral never shifts layout (absolute + z-index:-1). */
.pt-red-bignum {
    position: relative;
    isolation: isolate;
}
.pt-red-bignum::before {
    content: attr(data-bignum);
    position: absolute;
    top: -0.15em;
    left: -0.1em;
    font-family: var(--headingfont);
    font-size: 8em;
    line-height: 1;
    color: var(--monconred-tint);
    letter-spacing: -0.04em;
    pointer-events: none;
    user-select: none;
    z-index: -1;
}

/* Title band: top + bottom hairlines framing a section heading.
   The inline alternative to crop marks — brackets sit in the page
   rhythm rather than hugging the corners of the whole content area.
   Wrap the label strip + heading together inside one band.

   The hairlines and the band's buttons are the app's regular dark gray
   (--pt-border) rather than the brand red the class is named for; the
   'red' in pt-red-title-band survives only in the class names, the label
   strip and the caption, which keep the brand color. Renaming the idiom
   across every page wasn't worth losing the grep trail.

   Usage:
     <div class="pt-red-title-band">
       <div class="pt-red-labelstrip">Section 01 · Cash Balance</div>
       <h4>01 Cash Flow Reporting</h4>
     </div>

   Spacing rationale:
   - The baseline `margin-top` keeps a clear gap above the top hairline
     so it reads as a deliberate bracket, not a border glued to whatever
     precedes it (card bottom edge, prior section, etc.).
   - `.section.first-section > .pt-red-title-band` gets extra top margin so
     the first band on a page sits well below the sticky frosted navbar's
     footprint instead of being kissed by its translucent lower edge on
     initial page load. The `first-section` class is stamped on the first
     rendered section by `create_layout()` — more reliable than any CSS
     sibling pseudo-class because anchor/nav-drawer <div>s can appear
     before the first <div class="section">. */
.pt-red-title-band {
    border-top: 1px solid var(--pt-border);
    border-bottom: 1px solid var(--pt-border);
    padding: 0 0 0.25em;
    margin: 1.25em 0 0.8em;

    /* Two-child flex row: the ``__main`` wrapper (H1 + caption stack) on
       the left, the optional ``__action`` slot (usually a thin outline
       button like "Download PDF") flush-right. ``align-items: center``
       sits the button optically on the H1's cap-height instead of the
       caption's baseline, so the hairlines read as a single bracket.
       ``gap`` leaves breathing room between a long title and its action
       button without requiring per-button margins. */
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1em;
}

/* Extra clearance for the very first section's band — pushes the top
   hairline below the navbar's frosted-glass footprint on initial load. */
.section.first-section > .pt-red-title-band {
    margin-top: 2.25em;
}

/* Left side of the band: the heading + caption stack. Keeping this in its
   own wrapper preserves the pre-flex vertical stacking rules (and makes
   ``first-child`` / ``last-child`` margin zeroing predictable). */
.pt-red-title-band__main {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;   /* so long titles can truncate / wrap without pushing the action off-page */
}
.pt-red-title-band__main > :first-child { margin-top: 0; }
.pt-red-title-band__main > :last-child  { margin-bottom: 0; }
.pt-red-title-band__main h1,
.pt-red-title-band__main h2,
.pt-red-title-band__main h3,
.pt-red-title-band__main h4 {
    margin-top: 0;
    margin-bottom: 0;
    line-height: 1.05;
}

/* Right side of the band: the action slot. ``flex: 0 0 auto`` keeps the
   button its natural width instead of stretching, and the slot is offset
   off the paper's right edge by the band's own right padding (zero) so it
   sits aligned with the hairlines on either end. */
.pt-red-title-band__action {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    /* Bands with two actions (e.g. the bidder modal's Merge and Download PDF)
       would otherwise butt the buttons together and read as one control. */
    gap: 8px;
}

/* Thin outline button used inside a section title band (e.g. the
   "Download PDF" button on reports). Transparent fill, dark-gray border +
   text at rest — the same --pt-border gray as the band's hairlines —
   inverting to solid dark gray on hover. Small padding so it sits
   comfortably between the two hairlines without ballooning the band. The
   bidder modal's Other GCs and Entities buttons are the same control, in a
   wrapping row of the profile body (sub_profile._other_gcs_block,
   _entities_block). */
.pt-red-title-band__action .button-download,
.pt-red-title-band__action button,
.sp-profile-body .sp-assoc-link-controls .button-download {
    background-color: transparent !important;
    color: var(--pt-border) !important;
    border: 1px solid var(--pt-border) !important;
    border-radius: 6px;
    padding: 4px 10px;
    margin: 0;
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
    line-height: 1.3;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    cursor: pointer;
    white-space: nowrap;
    transition: var(--button-link-transition);
}
.pt-red-title-band__action .button-download:hover,
.pt-red-title-band__action button:hover,
.sp-profile-body .sp-assoc-link-controls .button-download:hover {
    background-color: var(--pt-border) !important;
    color: #ffffff !important;
}

/* Input + Download-PDF pair living inside the title band (e.g. the
   Curves view's "Project name" field next to its Download button).
   Keeps the two controls flush-right between the hairlines with a
   small gap. The input mirrors the Download button's exact box model
   (box-sizing, padding, border, border-radius, font-size, line-height,
   letter-spacing) so the two controls render at identical heights and
   share the same thin outline shape — only their content width
   differs. Set ``box-sizing: border-box`` on both so border + padding
   are included in the computed height, guaranteeing pixel parity
   regardless of the viewport font-size scale. */
.pt-red-title-band__action .pt-title-band-input-group {
    display: flex;
    align-items: stretch;
    gap: 8px;
}
.pt-red-title-band__action .pt-title-band-input-group .button-download,
.pt-red-title-band__action .pt-title-band-input-group input {
    box-sizing: border-box;
}
.pt-red-title-band__action .pt-title-band-input-group input {
    /* Every box-model token below (padding, border, border-radius, font,
       line-height, letter-spacing) is pulled verbatim from the
       Download button rule above — do not diverge these values or the
       input and button will render at different heights. */
    padding: 4px 10px;
    margin: 0;
    border: 1px solid var(--pt-border) !important;
    border-radius: 6px;
    background-color: transparent !important;
    color: var(--pt-border) !important;
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
    line-height: 1.3;
    letter-spacing: 0.04em;
    cursor: text;
    white-space: nowrap;
    transition: var(--button-link-transition);
    /* Same visual width as the Download button so the two controls
       read as a matched pair. Narrow enough for short project names;
       the browser lets the user keep typing past the visible width
       (the caret scrolls) so longer names aren't truncated in the
       payload. */
    width: 140px;
}
.pt-red-title-band__action .pt-title-band-input-group input::placeholder {
    color: var(--pt-border) !important;
    opacity: 0.55;
    letter-spacing: 0.04em;
}
.pt-red-title-band__action .pt-title-band-input-group input:focus {
    outline: none;
    /* rgba of --pt-border (#3a3c3f), the gray twin of the old red tint. */
    background-color: rgba(58, 60, 63, 0.06) !important;
    color: var(--text_dark) !important;
}

/* Decorative label strip above a heading: a 28px red rule + small all-caps
   label. Usage: <div class="pt-red-labelstrip">Section 03 / Variance</div> */
.pt-red-labelstrip {
    display: flex;
    align-items: center;
    gap: 0.6em;
    font-family: var(--headingfont);
    font-size: 0.72em;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--monconred);
    margin-bottom: 0.35em;
}
.pt-red-labelstrip::before {
    content: "";
    display: inline-block;
    height: 2px;
    width: 28px;
    background: var(--monconred);
}

/* Byline caption beneath a title-band heading. Uses the light text
   face (--textfont) instead of the bold heading face so it reads as
   editorial metadata rather than chrome. Uppercase + modest letter-
   spacing keeps the strip legible at small sizes. Black like the band's
   hairlines and buttons ('red' survives in the class name only, same as
   pt-red-title-band).
   Usage: <div class="pt-red-caption">Section 01 · Cash Balance — file.py · Rev. 2026-04-19</div> */
.pt-red-caption {
    font-family: var(--textfont);
    font-size: 0.7em;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text_dark);
    margin: 0.1em 0 0;   /* ~2px more breathing room below the H1 */
    line-height: 1.2;
}

/* Red box fill behind a single word in a heading — the "one word that
   matters". Use sparingly: max one per page.
   Usage: <h1>Budget <span class="pt-red-fill">Variance</span></h1> */
.pt-red-fill {
    display: inline-block;
    padding: 0 0.22em;
    background: var(--monconred);
    color: var(--gray-025);
    font-family: var(--headingfont);
    border-radius: 2px;
    line-height: 1.15;
}

/* Meta strip across the top of a report page: top/bottom red hairlines,
   small uppercase text, red bullet separators between children.
   Usage: <div class="pt-red-metastrip"><span>…</span><span>…</span></div> */
.pt-red-metastrip {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    font-family: var(--textfont);
    font-size: 0.72em;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text_dark);
    border-top: 1px solid var(--monconred);
    border-bottom: 1px solid var(--monconred);
    padding: 0.4em 0;
    margin-bottom: 1.25rem;
}
.pt-red-metastrip > :not(:first-child)::before {
    content: "•";
    color: var(--monconred);
    margin: 0 0.6em;
    display: inline-block;
}


/* -------------------------------------------------------------------------- */
/* 4. CROP MARKS / REGISTRATION MARKS                                         */
/*    Print-production signature marks. Authored-object feel, almost free.    */
/* -------------------------------------------------------------------------- */

/* Four red L-shaped crop marks in the corners of the tagged element,
   offset 8px from the edges. Applied via a single ::before pseudo using
   a composite multi-stop background — no extra markup required.           */
.pt-red-cropmarks {
    position: relative;
}
.pt-red-cropmarks::before {
    content: "";
    position: absolute;
    inset: 8px;
    pointer-events: none;
    background-repeat: no-repeat;
    background-size:
        16px 1px, 1px 16px,
        16px 1px, 1px 16px,
        16px 1px, 1px 16px,
        16px 1px, 1px 16px;
    background-position:
        top left, top left,
        top right, top right,
        bottom left, bottom left,
        bottom right, bottom right;
    background-image:
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred));
}

/* Corner brackets — same mechanic as crop marks, but hugging the edges
   (inset 0) with 12px arms. Use to frame an "active" or "selected" region. */
.pt-red-brackets {
    position: relative;
}
.pt-red-brackets::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-repeat: no-repeat;
    background-size:
        12px 1px, 1px 12px,
        12px 1px, 1px 12px,
        12px 1px, 1px 12px,
        12px 1px, 1px 12px;
    background-position:
        top left, top left,
        top right, top right,
        bottom left, bottom left,
        bottom right, bottom right;
    background-image:
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred)),
        linear-gradient(var(--monconred), var(--monconred));
}

/* Registration target (concentric circles + crosshair). Inline SVG so it
   scales crisply at any size. Reserve for ONE occurrence per page — it's
   a signature mark, not an icon. */
.pt-red-regmark {
    display: inline-block;
    width: 20px;
    height: 20px;
    background: no-repeat center / contain
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23ed2037' stroke-width='1'><circle cx='10' cy='10' r='8'/><circle cx='10' cy='10' r='3'/><line x1='0' y1='10' x2='20' y2='10'/><line x1='10' y1='0' x2='10' y2='20'/></svg>");
}


/* -------------------------------------------------------------------------- */
/* 7. LIST & CALLOUT ORNAMENT                                                 */
/*    Replaces default browser bullets with disciplined red marks.            */
/* -------------------------------------------------------------------------- */

/* Red square bullet list. <ul class="pt-red-list">…</ul> */
.pt-red-list {
    list-style: none;
    padding-left: 1.2em;
    margin: 0.5em 0;
}
.pt-red-list > li {
    position: relative;
    padding-left: 0;
    margin-bottom: 0.25em;
    font-size: var(--font_em_4);
}
.pt-red-list > li::before {
    content: "";
    position: absolute;
    left: -1em;
    /* Vertically center the bullet on the first line of text. ``0.5lh``
       is "halfway down one line-height"; ``translateY(-50%)`` then
       shifts the 6px square so its own center sits exactly there.
       Robust across whatever font-size / line-height the surrounding
       text inherits, so the bullet never drifts above or below the
       cap-height as it did with the old fixed ``top: 0.55em`` rule. */
    top: 0.5lh;
    transform: translateY(-50%);
    width: 6px;
    height: 6px;
    background: var(--monconred);
}

/* Triangle variant — for items that imply expansion or a next step.
   <ul class="pt-red-list pt-red-list--tri">…</ul> */
.pt-red-list.pt-red-list--tri > li::before {
    content: "";
    width: 0;
    height: 0;
    background: transparent;
    border-left: 6px solid var(--monconred);
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    /* Same centering recipe as the square bullet — half a line-height
       down, then shifted up by half the triangle's height (8px / 2) so
       the marker sits visually on the first text line. */
    top: 0.5lh;
    transform: translateY(-50%);
}

/* Red numbered list with tabular, leading-zero numerals.
   <ol class="pt-red-olist">…</ol> */
.pt-red-olist {
    list-style: none;
    counter-reset: pt-red-olist;
    padding-left: 2.4em;
    margin: 0.5em 0;
}
.pt-red-olist > li {
    position: relative;
    counter-increment: pt-red-olist;
    margin-bottom: 0.25em;
}
.pt-red-olist > li::before {
    content: counter(pt-red-olist, decimal-leading-zero) ".";
    position: absolute;
    left: -2.2em;
    top: 0;
    width: 2em;
    color: var(--monconred);
    font-family: var(--headingfont);
    font-variant-numeric: tabular-nums;
    text-align: right;
    padding-right: 0.4em;
}

/* Callout / note block: 2px red left border + optional red lead word.
   Usage:
     <div class="pt-red-callout">
       <span class="pt-red-callout-lead">Note —</span>
       Rest of the note text in normal color.
     </div> */
.pt-red-callout {
    border-left: 2px solid var(--monconred);
    padding: 0.35em 0 0.35em 0.85em;
    margin: 0.75em 0;
    background: var(--monconred-tint);
}
.pt-red-callout-lead {
    color: var(--monconred);
    font-family: var(--headingfont);
    margin-right: 0.3em;
}


/* -------------------------------------------------------------------------- */
/* 8. GANTT-BAR TABLE CELLS                                                   */
/*    Year-column cells in tables that approximate a Gantt timeline render    */
/*    as filled bar segments instead of 'X' marks. Adjacent active cells     */
/*    form a single continuous bar — there's no horizontal padding or gap    */
/*    between cells, so a contiguous run reads as one rectangle.             */
/*    Used by the Inflation Calculator's observation-type table.             */
/* -------------------------------------------------------------------------- */

.gantt-cell {
    padding: 0 !important;
    width: 18px;
    min-width: 18px;
    box-sizing: border-box;
    /* line-height: 0 keeps the gantt cells from adding their own
       baseline contribution, so row height is set entirely by the
       text-bearing cells (Type, Date_min, etc.). The bar height
       below is intentionally a hair under that natural row height. */
    line-height: 0;
}

.gantt-cell .gantt-bar {
    height: 1em;
    width: 100%;
    background-color: transparent;
}

.gantt-cell--active .gantt-bar {
    background-color: var(--gray-600);
}

/* Rounded ends only at the actual start/end of a contiguous run, so the
   bar reads as one chip across multiple cells. */
.gantt-cell--start .gantt-bar {
    border-top-left-radius: 2px;
    border-bottom-left-radius: 2px;
}

.gantt-cell--end .gantt-bar {
    border-top-right-radius: 2px;
    border-bottom-right-radius: 2px;
}


/* -------------------------------------------------------------------------- */
/* 9. COLOPHON / BRAND SIGNATURE                                              */
/*    Footer "signed document" block + brand-wordmark underline.              */
/* -------------------------------------------------------------------------- */

/* Colophon strip at the bottom of a report page.
   Usage:
     <footer class="pt-red-colophon">
       <span class="pt-red-colophon-mark">Construction Curves</span>
       <span>Generated 2026-04-19 · v1.4</span>
     </footer> */
.pt-red-colophon {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1em;
    border-top: 1px solid var(--monconred);
    padding: 0.8em 0 0;
    margin-top: 2rem;
    font-family: var(--textfont);
    font-size: 0.72em;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text_dark);
}
.pt-red-colophon-mark {
    color: var(--monconred);
    font-family: var(--headingfont);
    letter-spacing: 0.05em;
}

/* Red 1px underline beneath the brand wordmark / logo, for the active page
   heraldic "you are here" moment. */
.pt-red-brand-underline {
    position: relative;
    display: inline-block;
}
.pt-red-brand-underline::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -0.18em;
    height: 1px;
    background: var(--monconred);
}

/* Generic red inline glyph — convenience wrapper when none of the more
   specific classes fit (e.g. a standalone &, @, or № in brand display). */
.pt-red-glyph {
    color: var(--monconred);
    font-family: var(--headingfont);
}
/* ========================================================================== */
/* !!! END RED_GRAPHIC_SYSTEM                                                 */
/* ========================================================================== */


/* ========================================================================== */
/* !!! PRINT_STYLES_OPSCHART                                                  */
/*                                                                            */
/* Secondary affordance: if a user invokes the browser's native print dialog  */
/* (Cmd+P / Ctrl+P) on the Operational Chart page these rules produce a       */
/* readable print. The primary "Download PDF" export is server-rendered via   */
/* ReportLab (see utils/functions_opschart_pdf.py) and does NOT rely on any   */
/* of the CSS below. Screen rendering is unaffected — rules are all scoped    */
/* inside @media print.                                                       */
/* ========================================================================== */

@media print {
    /* Force Chrome/Safari to honor background colors, borders, and custom    */
    /* fills that are otherwise stripped out of printed output by default.    */
    *,
    *::before,
    *::after {
        -webkit-print-color-adjust: exact !important;
        print-color-adjust: exact !important;
        color-adjust: exact !important;
    }

    /* Letter landscape fits the 2-column project grid comfortably at native */
    /* scale; the user can still change paper size in the print dialog.      */
    @page {
        size: letter landscape;
        margin: 0.35in 0.3in;
    }

    html,
    body {
        background: #ffffff !important;
        margin: 0 !important;
        padding: 0 !important;
    }
}

/* ---- Hide app chrome -------------------------------------------------- */
@media print {
    .PT_navbar_wrapper,
    #PT_navbar_wrapper,
    .PT_navbar,
    .navigation_column,
    #nav_column,
    .section-nav-fab-root,
    .section-nav-drawer,
    .back-to-top-btn,
    .footer_section,
    .pagecontent,
    #page-content1,
    #page-content2,
    .content_settings,
    .dash-debug-menu,
    .dash-debug-menu__outer,
    #debug-console,
    .opsChart_modal_button:not(.opsChart_image_container) {
        display: none !important;
    }
}

/* ---- Expand the main content column to the full printable area -------- */
@media print {
    .wrapper,
    .page,
    .main-container,
    .content_container,
    .content,
    .layout-with-footer,
    #page-content {
        display: block !important;
        grid-template-columns: none !important;
        max-width: 100% !important;
        width: 100% !important;
        margin: 0 !important;
        padding: 0 !important;
        box-sizing: border-box !important;
        overflow: visible !important;
        gap: 0 !important;
    }

    .section {
        padding: 0 !important;
        margin: 0 0 0.2in 0 !important;
        background: transparent !important;
        page-break-before: auto;
    }

    /* The "even" sections use negative side margins for a full-bleed band    */
    /* on screen — kill that in print so nothing bleeds off the page.         */
    .section.even_section {
        margin-left: 0 !important;
        margin-right: 0 !important;
        padding-left: 0 !important;
        padding-right: 0 !important;
        background: transparent !important;
    }

    .section > h1 {
        font-size: 14pt !important;
        line-height: 1.2 !important;
        margin: 0 0 0.1in 0 !important;
        padding: 0 !important;
        page-break-after: avoid;
        break-after: avoid-page;
    }
}

/* ---- Disable motion / glow that degrades raster fidelity in PDFs ------ */
@media print {
    *,
    *::before,
    *::after {
        transition: none !important;
        animation: none !important;
        cursor: default !important;
    }

    /* Soften (don't kill) the shadowed overlay labels so they stay legible  */
    /* against project photos while not blurring the vector snapshot.       */
    .opsChart_comp_percent,
    .opsChart_jobno {
        text-shadow: 0 0 3px rgba(0, 0, 0, 0.9) !important;
    }

    img {
        image-rendering: -webkit-optimize-contrast;
        max-width: 100% !important;
    }
}

/* ---- Ops-Chart grid + cards: keep visual density, avoid split cards --- */
@media print {
    .custom-grid {
        display: grid !important;
        grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
        gap: 6pt !important;
        width: 100% !important;
    }

    .opsChart_card_with_image,
    .opsChart_proj_card,
    .opsChart_px_div > *,
    .opsChart_staff_card,
    .staff-history-proj-card,
    .staff-project-card {
        break-inside: avoid !important;
        page-break-inside: avoid !important;
    }

    .opsChart_px_card_title {
        break-after: avoid !important;
        page-break-after: avoid !important;
    }

    /* Drop the shadow-based card elevation — prints as a muddy gray box     */
    /* and contributes nothing useful to a presentation PDF.                 */
    .opsChart_card_with_image,
    .opsChart_proj_card,
    .card {
        box-shadow: none !important;
    }

    /* Keep modals + toasts out of the printed output regardless of state. */
    .modal,
    .modal-backdrop,
    .dbc-modal,
    .opsChart_staff_modal,
    #modal-container,
    #staff-modal-container {
        display: none !important;
    }
}

/* ========================================================================== */
/* !!! END PRINT_STYLES_OPSCHART                                              */
/* ========================================================================== */


/* ========================================================================== */
/* !!! CSI_COST_MODEL · ACCURACY_KPIS                                         */
/* -------------------------------------------------------------------------- */
/* Out-of-sample MAPE + LOOCV R² surfaced as plain red text inline with the  */
/* Adjustments card header, placed directly before the LOOCV Backtest button */
/* so the readout reads as the button's caption. No border, no background,  */
/* no padding — monconred ink is the entire visual signal, and the text     */
/* stays smaller than the H4 card title so it never upstages it.            */
/* ========================================================================== */

.csi-accuracy-kpi {
    display: inline-flex;
    align-items: baseline;
    color: var(--text_dark);
    /* Match the section total's .span_2 sizing so the red readout sits on
       the same typographic baseline as the dollar total next to it. */
    font-size: var(--font_em_4A);
    line-height: 1.2;
    white-space: nowrap;
}

.csi-accuracy-kpi__label {
    font-family: var(--textfont);
    font-weight: 400;
    letter-spacing: 0.04em;
    margin-right: 0.3em;
}

.csi-accuracy-kpi__value {
    font-family: var(--headingfont);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.csi-accuracy-kpi__sep {
    opacity: 0.55;
    margin: 0 0.15em;
}


/* ======================================================================
   Bid Matrix

   Follows the Master Scope conventions: one card per trade headed by an H2
   that opts out of the filet rouge, and per-row controls that are inert
   markup driven by a delegated click handler (see BM_ROWS_JS) rather than
   Dash-managed components.
   ====================================================================== */

/* The trade cards remain plain '.card's. The container-scoped rules only
   supply their jump-target offset and align the multi-control heading row. */
#bid-matrix-content,
#bid-matrix-content > .card {
    scroll-margin-top: var(--top-offset);
}

/* Give the whole heading row the card's standard 0.8em inset. This is
   deliberately tighter than the H4's former 1.33em top margin: the heading,
   segmented control and Top button align at their top edges, while the larger
   breathing room belongs below the row before the table. */
#bid-matrix-content > .card {
    padding-top: 0.8em;
}

.bm-trade-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.65em;
    margin-bottom: 1em;
}

/* The heading and the note beneath it, as one column against the controls on
   the right. Its basis is generous but its min-width is not, so on a card too
   narrow for both the row's own flex-wrap drops the controls to their own line
   rather than crushing the trade's name.

   `min-width` is what makes the note wrap instead of widening this column: a
   flex item's floor is otherwise its content's min-content width, and one long
   sentence would take the whole row and push the controls off it. */
.bm-trade-headline {
    display: flex;
    flex-direction: column;
    flex: 1 1 22em;
    min-width: 12em;
}

/* A fifth larger than the app's card h4 (--font_em_3): these headings name
   whole divisions rather than one card's topic, and forty near-identical
   cards down a page need the section breaks to read at a glance. Scoped by
   class, so every other page's h4 keeps the shared size. */
.bm-trade-head h4.bm-trade-heading {
    flex: 0 1 auto;
    margin: 0;
    font-size: calc(var(--font_em_3) * 1.2);
}

/* The two filters, the sub-category picker and the sort, kept together at the
   top right. `flex: 0 0 auto` is the half that matters: unable to shrink, they
   hold their size and the note wraps in the space they leave, which is the
   whole point of boxing them. They wrap among themselves only once the row has
   dropped them onto a line of their own. */
.bm-trade-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: flex-end;
    gap: 0.65em;
    flex: 0 0 auto;
    margin-left: auto;
}

/* The segmented control's own 4px bottom margin would offset it against the
   heading by half that once the row is centred, so it goes. */
.bm-trade-head .mantine-SegmentedControl-root {
    margin-bottom: 0;
}

/* The sub-category filter is a multi-select rather than a segmented control,
   because it is the one filter a reader wants two of at once. Its height,
   border and radius all come from the shared .mantine-MultiSelect-* block near
   the top of this sheet, which is what makes it a peer of the segmented
   controls beside it.

   Type size is the one thing that block gets wrong in this row. Its root sets
   --font_em_4A (0.75em) where a segmented control's labels are --font_em_6
   (0.5em), so the placeholder sat half again larger than every other word
   beside it. Set on the root rather than on the placeholder, because sizes
   inside a multi-select are relative to the root — naming --font_em_6 on the
   input itself would compound to 0.5 of 0.75. The control's height is pinned
   in px, so none of this moves it. */
.bm-trade-head .bm-subcat-select {
    flex: 0 1 auto;
    margin-bottom: 0;
    font-size: var(--font_em_6) !important;
}

/* Setting the root is necessary but not sufficient: Mantine sizes the field
   itself in absolute pixels off its own theme, and those styles land on the
   same element as .mantine-MultiSelect-input. So the root computed to 8.2px
   here while the box inside it stayed at Mantine's 14px, and the shared
   block's `font-size: inherit` on the placeholder faithfully inherited the
   14px — the placeholder came out 71% larger than the segmented label beside
   it, which is exactly what it looked like.

   Each step of the chain from the box down to the placeholder is handed back
   to inheritance, so all of it lands on the root's size. The chips are in the
   same list for a second reason: theirs is 0.65em, which came out level with
   the segmented labels against the old 0.75em root and would shrink to two
   thirds of them against this one. */
.bm-trade-head .bm-subcat-select .mantine-MultiSelect-input,
.bm-trade-head .bm-subcat-select .mantine-MultiSelect-values,
.bm-trade-head .bm-subcat-select .mantine-MultiSelect-searchInput,
.bm-trade-head .bm-subcat-select .mantine-MultiSelect-searchInput::placeholder,
.bm-trade-head .bm-subcat-select .mantine-MultiSelect-value {
    font-size: inherit !important;
}

/* The Top button sits beside a segmented control in this row, so it takes the
   shared control height and radius rather than .button1's own 2px corners and
   padding-derived height — otherwise the two read as different-sized controls.
   Values come from the same tokens .mantine-SegmentedControl-root uses. All
   margins are zeroed: the card's padding sets the distance to its edges, so
   any margin here would put the button somewhere the heading is not. Scoped to
   the heading row, so .button1 is untouched everywhere else in the app. */
.bm-trade-head .button1 {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    height: var(--control-height);
    border: 1px solid var(--pt-border);
    border-radius: var(--control-radius);
    margin: 0;
}

/* Restated because the rule above has the same specificity as .button1:hover
   but comes later, which would otherwise cancel the radius morph every other
   button in the app gets on hover. */
.bm-trade-head .button1:hover {
    border-radius: var(--pill-radius-max);
}

/* --- the section's standing remark --------------------------------------
   One sentence about the trade rather than about any bidder in it — 'union
   only on school work', 'ask for the Local 79 rate' — sitting immediately
   under the card's heading, in the heading's own column. See _trade_note_box.

   Only a top margin: the gap to the table below is the heading row's, so a
   bottom margin here would be spent inside the row and open it up for nothing.

   Collapsed when it holds nothing, which for a reader without the edit
   permission is every section that has no note. Without this an empty box
   would still spend that top margin on all forty cards. */
.bm-trade-note-box {
    margin: 0.35em 0 0;
}

.bm-trade-note-box:empty {
    display: none;
}

/* Ordinary inline flow, not a flex row, because this is a sentence: the note,
   its byline and its pencil belong in one run of text that wraps where it
   runs out of column. Made a flex row, each would have been a block, and the
   byline would have dropped to its own line instead of following the words.

   Words break where they must — an unbroken run, a pasted URL most likely,
   would otherwise widen the column and push the controls off the row. */
.bm-trade-note {
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
    line-height: 1.5;
    overflow-wrap: break-word;
}

/* Plain text. The note first wore the app's highlight yellow to set 'how to
   bid this trade' apart from the names underneath, but a standing
   instruction lit up like a starred contact read as an alert on every card;
   its place under the heading and the byline after it are enough to say
   what it is. */
.bm-trade-note-text {
    color: var(--text_dark);
}

/* Who left it and when. Worth showing for a standing instruction, because a
   reader deciding whether it still applies wants to know how old it is.
   Quieter than the note, like every other byline in the app. */
.bm-trade-note-by {
    color: var(--gray-500);
    font-size: var(--font_em_5);
}

/* Stands in for the note where a section has none, and only for a reader who
   can do something about it: an admin should be able to see that a section is
   unannotated, where for everybody else it is not information. */
.bm-trade-note-empty {
    color: var(--gray-500);
    font-style: italic;
}

/* Borrows .sp-alias-remove's borderless sizing, like the modal's inline
   pencils, and changes only the hover colour: writing a note is an edit
   rather than a deletion, so it does not go red. */
.bm-trade-note-pencil {
    padding: 0;
    border: 0;
    background: none;
    color: var(--gray-500);
    font-family: var(--buttonfont);
    font-size: inherit;
    line-height: 1;
    cursor: pointer;
    /* Its own margin now the run is inline and there is no flex gap to space
       it off the words in front of it. */
    margin-left: 0.4em;
}

.bm-trade-note-pencil:hover {
    color: var(--pt-accent-dark);
}

/* The editor the pencil reveals. `display: flex` here rather than in the
   toggle: the form is rendered carrying `display: none` inline, and the
   clientside callback clears the inline style rather than replacing it, so
   this is what it opens to. */
.bm-trade-note-form {
    display: flex;
    align-items: flex-start;
    gap: 0.5em;
    margin-top: 0.5em;
}

/* .input2 is a block sized for a nav card, so in a flex row it has no parent
   width to grow into and has to state its own — the same fix
   .sp-alias-input makes in the modal. Held to two lines because the note is
   meant to be short, and a field that grew with its content would invite a
   paragraph nobody reads above a table. */
.bm-trade-note-input {
    flex: 1 1 auto;
    max-width: 40em;
    height: 3.4em;
    margin: 0;
    resize: vertical;
}

.bm-trade-note-notice {
    margin-top: 0.4em;
    color: var(--monconred);
    font-family: var(--textfont);
    font-size: var(--font_em_5);
}

/* --- tick boxes ---------------------------------------------------------
   Inert spans rather than real inputs, for the same reason Master Scope's
   selection pills are spans: the page mounts one per row across ~2,500 rows,
   and any Dash-managed control there costs a wildcard callback on every
   click. The checked state lives in aria-checked, which the CSS reads. */
.bm-check-cell {
    width: 2.2em;
    text-align: center;
    padding-right: 0;
}

.bm-check {
    display: inline-block;
    box-sizing: border-box;
    width: 13px;
    height: 13px;
    border: 1px solid var(--gray-400);
    border-radius: 3px;
    background-color: var(--pt-body-light);
    cursor: pointer;
    vertical-align: middle;
    transition: var(--pt-transition);
}

.bm-check:hover {
    border-color: var(--gray-600);
}

.bm-check:focus-visible {
    outline: 2px solid var(--pt-accent-dark);
    outline-offset: 1px;
}

.bm-check[aria-checked="true"] {
    border-color: var(--gray-800);
    background-color: var(--gray-800);
}

/* The tick itself — a rotated pseudo-element check, so no icon font or SVG. */
.bm-check[aria-checked="true"]::after {
    content: '';
    display: block;
    width: 3px;
    height: 7px;
    margin: 0 auto;
    border: solid var(--pt-body-light);
    border-width: 0 1.5px 1.5px 0;
    transform: translateY(-1px) rotate(45deg);
}

/* Selecting a row deliberately does NOT re-shade it for now — the box itself
   is the only state cue. .bm-row-checked is still set on the row (by the server
   render and by the delegated handler) so a fill can be restored here later
   without touching either. */

/* --- uniform column widths ----------------------------------------------
   Fixed layout, so the declared widths govern instead of each section's own
   longest bidder name. Every trade card is the same table width, so with the
   name column pinned the sub-category chips start at the same x down the whole
   page and read as one column rather than a ragged edge per section. */
.bm-table {
    table-layout: fixed;
    width: 100%;
    /* A fifth larger than the app's tables. Non-standard on purpose: these
       are the tables people read down for an hour picking a bid list, not a
       report glanced at once, and the standard size was tiring at that use.
       The line-height moves with it — the base table rule fixes it in px —
       and everything else in the row (row height, pills, column widths) is
       in em and follows the font. */
    font-size: calc(var(--font_em_5A) * 1.2);
    line-height: calc(14px * 1.2);
}

/* --- column alignment ---------------------------------------------------
   A class per alignment rather than an inline style on each cell, following
   .cm-td-center / .cm-td-right further up. The alignment is constant per
   column, and the table mounts ~18,500 body cells, so one dict per cell was a
   fifth of this page's payload on its own. Deliberately no width classes to
   go with them: .bm-table above is fixed-layout, so the width declared on the
   <th> is what sizes the column and repeating it per cell did nothing. */
.bm-td-left            { text-align: left; }
.bm-td-center          { text-align: center; }
.bm-td-right           { text-align: right; }

/* --- uniform row height -------------------------------------------------
   The bid-count pill carries a border and padding, so a row holding one would
   otherwise stand taller than a row whose bidder never bid. Fixing the height
   on every cell keeps the whole table on one rhythm regardless of which rows
   have pills, and the pill is sized to sit inside that height. */
.bm-table .bm-row > td,
.bm-table .bm-outreach-row > td,
.bm-table thead th {
    height: 1.75em;
    padding-top: 0;
    padding-bottom: 0;
}

/* --- one-line header on the trade tables ---------------------------------
   Every title is a single word or two ('Bidder', 'Labor', 'Invites', 'CV'),
   so the header row is the same 1.75em as a body row (the uniform-height
   rule above) and needs no height of its own. It was three lines tall while
   the count headers spelled out 'Confirmed Min. … (All Divs)' on lines of
   their own; that qualification now rides each header's tooltip
   (HEADER_HINTS in bid_matrix.py), and the exports still print it in full.
   nowrap stays so a title never wraps and grows the row. */
.bm-table.bm-trade-table thead th {
    white-space: nowrap;
}

/* A header whose <th> carries a tooltip (the Bidder and the three count
   columns) wraps its word in .bm-th-hint. The span is a hook only: the
   dotted underline and help cursor it once carried read as clutter (the
   cursor's question mark was taken for the tooltip itself), so the header
   looks like every other and the description comes up on a plain hover. */
.bm-table thead th .bm-th-hint {
    text-decoration: none;
    cursor: inherit;
}

/* The certification cell keeps the table's single-line rule on purpose: it
   briefly wrapped so every chip would show, and the double-height rows broke
   the rhythm the fixed height above exists to hold. The column is sized for
   four chips (see BODY_COLUMNS), and a cell that still overruns clips — a
   steady table beats the tail of the rarest row. Stated here rather than
   inherited, because the column is now tight enough that the rule matters. */
.bm-table td.bm-cert-cell {
    white-space: nowrap;
    overflow: hidden;
}

/* --- whole-row hover ------------------------------------------------------
   The full row tints under the pointer, not just the bidder name: these are
   wide rows read across many columns, and the fill is what carries the eye
   from the tick box to the note at the far end.

   One shade of cool, neon-leaning yellow on striped and white rows alike:
   the same fill under the pointer wherever it sits reads as a single live
   cue, and the zebra keeps carrying row-parity on its own. Same
   green-leaning family as the app's --sManual_yellow_highlight (#fcffcb)
   but hotter, so the hover reads as live rather than as the
   project-highlight mark that yellow puts on a bidder's name
   (.bm-row-highlight). The selector's three classes outweigh the zebra
   rule (`table.hover tbody tr:nth-child(odd) td`) on the striped rows.

   The Potential Outreach rows (.bm-outreach-row) take the same tint: their
   rows are ticked and their names clicked exactly like the bidder rows above
   them now, so the hover cue should say so. Other table.hover instances keep
   their behavior. Removed rows are .bm-row too and tint like the rest —
   their history is why anyone reads them. The bid-count pill's fill is
   inline on a span, so it rides on top untouched. */
/* A row the per-card filters hid. A class rather than the inline display
   the filter JS used to write, so the stripe rules below can see it. */
.bm-table tbody tr.bm-row-off {
    display: none;
}

/* The bidder tables re-stripe over what the filters leave visible: the
   generic zebra (`table.hover tbody tr:nth-child(odd) td`) counts hidden
   rows and drifted out of step the moment a filter hid one. The first rule
   cancels it inside these tables; the second stripes with the of-syntax,
   which counts only the rows still shown — and recounts by itself after
   the per-card sort reorders them. A browser too old for the of-syntax
   (pre-2023) shows these tables unstriped, which is the agreed fallback. */
.bm-table.hover tbody tr:nth-child(odd) > td {
    background-color: transparent;
}

.bm-table.hover tbody tr:nth-child(odd of tr:not(.bm-row-off)) > td {
    background-color: var(--gray-150);
}

/* The :not(.bm-row-off) here is for specificity, not selection (a hidden
   row cannot hover anyway): the of-syntax stripe above counts its :not()
   argument's classes, landing at (0,4,4), and a plain tr.bm-row:hover
   selector's (0,4,3) loses to it — which left the shaded rows dead under
   the pointer while the white rows lit. Matching the :not() lifts the
   hover to (0,5,3), so both parities tint alike. */
.bm-table.hover tbody tr.bm-row:not(.bm-row-off):hover > td,
.bm-table.hover tbody tr.bm-outreach-row:not(.bm-row-off):hover > td {
    background-color: #fafeb4;
}

/* Graduated bid-count pill. Geometry only — the fill is data-driven and comes
   in as an inline background-color (see _pill_fill). Mirrors make_table's
   graduated pill: 15px radius, gray-800 hairline, centered figures. */
.bm-bid-pill {
    display: inline-block;
    box-sizing: border-box;
    min-width: 2.1em;
    padding: 0 0.4em;
    border: 1px solid var(--gray-800);
    border-radius: 15px;
    line-height: 1.25;
    text-align: center;
    vertical-align: middle;
}

/* Removed marker, the two labor markers and the two data-cleaning ticks.
   Shared geometry, because each is a chip in a fixed-height row and any
   difference in their box would show up as two row heights down the page. */
.bm-removed-pill,
.bm-union-pill,
.bm-openshop-pill,
.bm-acct-pill,
.bm-vendid-pill,
.bm-records-pill,
.bm-suggest-pill,
.bm-cert-pill {
    display: inline-block;
    box-sizing: border-box;
    min-width: 1.6em;
    padding: 0 0.4em;
    border-radius: 15px;
    color: #ffffff;
    font-family: var(--tablefont);
    line-height: 1.25;
    text-align: center;
    vertical-align: middle;
}

/* The whole row is light gray, which would leave a bare 'R' all but
   invisible, so it gets the dark chip — same fill and white text as
   .bo-labor-pill--upw (mirrors pillgray_dark). It is the one thing on a
   removed row that keeps its fill: every other chip there is emptied out (see
   .bm-row-removed), and this is what is left to find the row by. */
.bm-removed-pill {
    border: 1px solid var(--pillgray-dark);
    background-color: var(--pillgray-dark);
}

/* The union family's chip everywhere else in the app is the dark gray one, so
   'U' takes it here too (see .bo-labor-pill--upw). It reads the same as the
   'R' chip by design: both are statuses to respect rather than fix, and their
   own columns tell them apart. */
.bm-union-pill {
    border: 1px solid var(--pillgray-dark);
    background-color: var(--pillgray-dark);
}

/* Open shop takes the non-union light chip with dark text, the other half of
   the app's labor pill pair (see .bo-labor-pill--nu). Against the dark union
   chip beside it the two read as a scale rather than two unrelated marks. */
.bm-openshop-pill {
    border: 1px solid #c9c9cc;
    background-color: var(--pillgray-light);
    color: var(--text_dark);
}

/* A bidder can hold both chips, so they need to be told apart without the
   cell looking like one wide badge. */
.bm-union-pill + .bm-openshop-pill,
.bm-openshop-pill + .bm-union-pill {
    margin-left: 3px;
}

/* The two ID ticks say a record is present, so they take the neutral dark chip
   rather than a red flag: what they mark is coverage, not something to act on.
   One rule for both, because the pair is meant to read the same way. */
.bm-acct-pill,
.bm-vendid-pill {
    border: 1px solid var(--pillgray-dark);
    background-color: var(--pillgray-dark);
}

/* The Bidder List's search results: a card at the top of the main column
   (the box itself is the nav column's first card, sized by .bm-list-name)
   that only exists while the search callback has filled it. */
#bm-search-results:empty {
    display: none;
}

/* The results' name column sits off the table edge a little, header and
   cells alike. */
#bm-search-results td.bm-name-cell,
#bm-search-results th:first-child {
    padding-left: 0.6em;
}

/* The CV column: right-aligned figures were sitting flush against the
   column's outer edge; this eases them off it (cells and header alike). */
.bm-table td.bm-cv-cell,
.bm-table th.bm-cv-cell {
    padding-right: 1.4em;
}

/* Linked Sources chips: one per system holding a confirmed record on the
   bidder. Same geometry as the row's other chips (fixed-height rows). All
   filled alike: everything in this column is a confirmed link, and a hollow
   variant read as 'unverified' rather than 'public registry' — the split
   between our systems and the public's is carried by order alone (ours
   first; see _refresh_linked_sources). The .bm-linked-own class still
   arrives on the platform chips should the two ever need to differ again. */
.bm-linked-pill {
    display: inline-block;
    box-sizing: border-box;
    padding: 0 0.5em;
    border-radius: 15px;
    border: 1px solid var(--pillgray-dark);
    background-color: var(--pillgray-dark);
    color: #ffffff;
    font-family: var(--tablefont);
    line-height: 1.25;
    text-align: center;
    vertical-align: middle;
}

.bm-linked-pill + .bm-linked-pill {
    margin-left: 3px;
}

/* A linked record carrying a finding — debarment, a DOL violation, HPD
   disqualification, a SAM exclusion. The tooltip names which. */
.bm-linked-pill.bm-linked-flag {
    border-color: var(--monconred);
    background-color: var(--monconred);
}

/* Like the cert cell: single-line on purpose, so a bidder linked everywhere
   cannot double the row's height. Whatever overruns clips; the modal holds
   the full story. */
.bm-table td.bm-linked-cell {
    white-space: nowrap;
    overflow: hidden;
}

/* The Manpower page's SafetyClerk section: the per-site charts two
   across, so a dozen sites read as a page rather than a scroll. */
.manpower-sc-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
}

@media (max-width: 900px) {
    .manpower-sc-grid {
        grid-template-columns: 1fr;
    }
}

/* The project modal's Contract Status Log: a band per TPB division with
   the consolidated bidder rows beneath it, and the closing total. Its own
   table class rather than the shared 'hover', so the rows keep a steady
   white — the division bands carry the visual rhythm here, and stripes
   underneath them read as noise. */
.sp-log-table {
    width: 100%;
    border-collapse: collapse;
}

.sp-log-table th,
.sp-log-table td {
    padding: 2px 6px;
}

.sp-log-table thead th {
    border-bottom: 1px solid var(--gray-800);
}

.sp-division-row > td {
    border-top: 1px solid var(--gray-400);
    padding: 4px 6px;
    font-weight: bold;
}

/* The taller step above each heading rides the row BEFORE it, so the
   air sits above the heading's rule rather than between the rule and
   its text. The :has() selector is within the browser floor the striped
   tables' of-syntax already set. */
.sp-log-table tbody tr:has(+ .sp-division-row) > td {
    padding-bottom: 12px;
}

.sp-division-cell .sp-division-note {
    margin-left: 1em;
    font-weight: normal;
}

.sp-division-empty {
    padding-left: 1.5em;
}

/* The engagements under a division heading, stepped in far enough that
   the headers unmistakably own them. */
.sp-log-table td.sp-log-indent {
    padding-left: 2.6em;
}

.sp-division-total > td {
    border-top: 2px solid var(--gray-800);
    padding-top: 4px;
}

/* One status chip, filled by tier (the color arrives inline). */
.sp-status-pill {
    display: inline-block;
    box-sizing: border-box;
    padding: 0 0.6em;
    border-radius: 15px;
    border: 1px solid var(--gray-800);
    font-family: var(--tablefont);
    font-size: 0.85em;
    line-height: 1.4;
    white-space: nowrap;
}

/* The note under the Bidding History table (the linked-files disclaimer):
   set off the table's bottom edge rather than flush against it. Doubled-up
   selector on purpose — .sp-note-tight's margin shorthand sits later in
   this sheet and outdrew the single class at equal specificity, which left
   the note flush against the table it qualifies. */
.sp-note.sp-bidhist-note {
    margin-top: 0.8em;
}

/* The inline ALJobNo input on an unnumbered Bidding History row: sized to
   the numbers around it and held inside the row's own height, so a table
   with three of these keeps the same rhythm as one with none. Monospace
   like the column it sits in. */
.sp-jobalias-inline {
    width: 9em;
    box-sizing: border-box;
    padding: 0 0.3em;
    border: 1px solid var(--gray-300);
    border-radius: 4px;
    font-family: var(--codefont, monospace);
    font-size: inherit;
    line-height: 1.4;
    background-color: transparent;
}

.sp-jobalias-inline:focus {
    outline: none;
    border-color: var(--gray-500);
}

/* The paperclips on Bidding History rows — one per file submitted with the
   BuildingConnected bid. Plain glyphs, no underline; a hair of air between
   two on one job. */
.sp-bid-file {
    text-decoration: none;
    margin-right: 0.25em;
}

/* MBE, WBE and SDVOB share one chip. The column says a bidder is certified
   and under which programme; three colours would imply a ranking between the
   programmes that does not exist. Takes the table's neutral dark chip, the
   same as the union and ID marks: a certification is a fact about the bidder
   rather than something to act on, so it reads as one of the row's data
   chips. Wider than those because the label is a word, and they pair, so they
   need the gap between them. */
.bm-cert-pill {
    border: 1px solid var(--pillgray-dark);
    background-color: var(--pillgray-dark);
    padding: 0 0.5em;
    /* Breathing room between lines when a heavily-certified firm's chips
       wrap — the cell is left-aligned and wraps rather than widening. */
    margin-top: 1px;
    margin-bottom: 1px;
}

/* Coloured by the body that issued it, because a firm can hold the same
   programme from both and the pair is read as 'city and state' rather than
   as two MBEs. The programme itself stays in the text: colouring by
   programme would imply a ranking between them that does not exist. */
/* Pale neon fills — mint, sky, lavender — quiet enough to sit back in the
   row, with the body's own dark ink instead of the base pill's white,
   which these fills are far too light to carry. */
.bm-cert-city {
    border-color: #b5f5d2;
    background-color: #b5f5d2;
    color: var(--text_dark);
}

.bm-cert-state {
    border-color: #bfe3ff;
    background-color: #bfe3ff;
    color: var(--text_dark);
}

/* The veteran certification, which only the state awards — so it takes the
   programme's own colour rather than the state's, and is the one chip here
   read for what it is rather than for who issued it. */
.bm-cert-veteran {
    border-color: #e3ccfb;
    background-color: #e3ccfb;
    color: var(--text_dark);
}

/* A certification riding on a suggested match nobody has answered yet.
   Hollow, because a filled chip is this page's word for
   'confirmed' and these are exactly not that — the record naming the
   certification is still waiting in the bidder's review queue. The text and
   outline take a readable mid-tone of the same hue the confirmed chip fills
   with (mint, sky, lavender), so a pending chip reads as that certification
   arriving rather than as the gray of a removed row. */
.bm-cert-pill.bm-cert-pending {
    border-style: solid;
    background-color: transparent;
    border-color: var(--gray-500);
    color: var(--gray-500);
}

.bm-cert-pending.bm-cert-city {
    background-color: transparent;
    border-color: #2fbf7d;
    color: #2fbf7d;
}

.bm-cert-pending.bm-cert-state {
    background-color: transparent;
    border-color: #4d9fe6;
    color: #4d9fe6;
}

.bm-cert-pending.bm-cert-veteran {
    background-color: transparent;
    border-color: #a678e6;
    color: #a678e6;
}

/* A Procore directory record waiting in the bidder's review queue. The same
   pre-verified language as the hollow certification chips — outlined means
   suggested, filled means confirmed — in Procore's own orange, so the mark
   says where the suggestion came from without a word. */
.bm-procore-pending-pill,
.bm-tradetapp-pending-pill,
.bm-bc-pending-pill {
    display: inline-block;
    box-sizing: border-box;
    min-width: 1.6em;
    padding: 0 0.4em;
    border-radius: 15px;
    border: 1px solid #e8703d;
    background-color: transparent;
    color: #e8703d;
    font-family: var(--tablefont);
    line-height: 1.25;
    text-align: center;
    vertical-align: middle;
}

/* TradeTapp's mark wears teal and BuildingConnected's blue where Procore's
   wears orange, so the own-platform suggestions tell apart at a glance.
   The Local Law 44 marks ('LL44') wear BuildingConnected's. */
.bm-tradetapp-pending-pill {
    border-color: #1f9e8e;
    color: #1f9e8e;
}

.bm-bc-pending-pill {
    border-color: #2f6db5;
    color: #2f6db5;
}

.bm-cert-pill + .bm-cert-pill {
    margin-left: 3px;
}

/* The saved-bid-list card's name field and its pair of buttons. The field
   takes the nav card's own input width the way Master Scope's new-project
   box does; the buttons sit on one row and split it, so neither reads as the
   primary action. */
/* Shared with the "One Page" Budget's saved-configuration card, which is the
   same control group — picker, name field, Save / Delete — so it reads the
   same on both pages rather than being restyled from scratch. */
.card.nav .bm-list-name,
.card.nav .budsim-config-name {
    width: 100%;
    margin: 0.4em 0;
}

.bm-list-buttons {
    display: flex;
    gap: 6px;
}

.bm-list-buttons .bm-state-btn {
    flex: 1 1 0;
}

/* Three buttons, not the Bid Matrix's two, so an even split can squeeze
   'Delete' narrower than the word — hence the content floor, and the wrap
   that lets the row take a second line rather than clip. */
.budsim-config-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.budsim-config-buttons .budsim-config-btn {
    flex: 1 1 auto;
    min-width: max-content;
}

/* Somebody has flagged this record as wrong. Amber rather than the brand
   red the public-record disagreement uses: both ask for attention, and one
   is a registry contradicting us while this is a colleague saying so, which
   is a different errand. Outlined like the star beside it, since both are
   marks about the bidder rather than data chips. */
.bm-review-flag {
    display: inline-block;
    box-sizing: border-box;
    margin-left: 5px;
    padding: 0 0.35em;
    border: 1px solid var(--pillgray-dark);
    border-radius: 15px;
    background-color: #f6a609;
    color: #ffffff;
    font-family: var(--tablefont);
    line-height: 1.25;
    vertical-align: middle;
}

/* The note box in the profile modal. A textarea rather than the one-line
   input the other add fields use, because a note is a sentence or three. */
.sp-profile-body .sp-note-input {
    display: block;
    width: 100%;
    min-height: 4em;
    resize: vertical;
}

/* A bidder somebody has asked to be considered on the next suitable job.
   A star rather than another lettered pill: the marks beside it are queue
   items in the table's grays and reds, and this is a recommendation, not
   work to do. Yellow carries that on its own, and the dark border is what
   keeps it legible against the row's white and the highlight yellow a
   project selection paints behind it. */
.bm-priority-star {
    display: inline-block;
    box-sizing: border-box;
    margin-left: 5px;
    padding: 0 0.35em;
    border: 1px solid var(--pillgray-dark);
    border-radius: 15px;
    background-color: #ffd23f;
    color: var(--pillgray-dark);
    font-family: var(--tablefont);
    line-height: 1.25;
    vertical-align: middle;
}

/* The two public-record marks, and the only chips on this table that ask for
   something to be done rather than reporting a fact. Both sit right after the
   name, with the gap the labor chips use between themselves.

   '?' is an unreviewed suggested match — thousands of them, so it takes the
   same neutral gray as the rest of the table's chips and reads as a queue.
   '!' is a registry contradicting a certification we hold — a handful, and
   the only thing here worth the brand red. If both were red the handful would
   be lost among the thousands, which is the whole reason they differ. */
.bm-suggest-pill {
    border: 1px solid var(--pillgray-dark);
    background-color: transparent;
    color: var(--pillgray-dark);
    margin-left: 4px;
}

.bm-records-pill {
    border: 1px solid var(--monconred);
    background-color: var(--monconred);
    margin-left: 4px;
}

/* The table's sub-category chip shares its rule with the modal's (see
   .sp-subcat-pill, further down). Nothing extra is needed here: at 9px it
   stays inside the row's line box, so it cannot restripe the table the way a
   taller chip would. */

/* --- removed bidders ----------------------------------------------------
   Firms marked 'R' in the source sheet are off the bidder list. They stay on
   screen so a dropped firm reads as dropped rather than silently vanishing,
   and the whole row recedes rather than the name alone: a row whose name was
   gray but whose chips were still in full colour read as half-live, and the
   colour won. Follows .ms-row-text.ms-na on Master Scope but a step darker
   than its gray-300, which was too faint to read here.

   The one exception is the 'R' chip itself, further down. It is what says the
   row is dropped, so it keeps its fill; greying the marker along with what it
   marks would leave nothing to find the row by. */
.bm-row-removed td {
    color: var(--gray-400);
}

/* Struck through as well as gray, because the name is the thing being
   withdrawn. */
.bm-row-removed .bm-sub-name {
    text-decoration: line-through;
}

/* Every chip on the row becomes an outline: gray text inside a gray border
   with no fill. A filled chip is the page's way of saying 'this is live and
   confirmed', which is the opposite of what a dropped row means — so the
   chips keep saying *what* they said (certified MBE, union, an accounting ID
   on record) while giving up the emphasis.

   None of them are struck through. The border already reads as emptied out,
   and a line through a word inside a chip is just noise. */
.bm-row-removed .bm-subcat-pill,
.bm-row-removed .bm-cert-pill,
.bm-row-removed .bm-union-pill,
.bm-row-removed .bm-openshop-pill,
.bm-row-removed .bm-acct-pill,
.bm-row-removed .bm-vendid-pill,
.bm-row-removed .bm-linked-pill,
.bm-row-removed .bm-bid-pill,
.bm-row-removed .bm-suggest-pill,
.bm-row-removed .bm-records-pill,
.bm-row-removed .bm-review-flag,
.bm-row-removed .bm-procore-pending-pill,
.bm-row-removed .bm-tradetapp-pending-pill,
.bm-row-removed .bm-bc-pending-pill,
.bm-row-removed .bm-priority-star {
    border-color: var(--gray-300);
    background-color: transparent;
    color: var(--gray-400);
}

/* Read-only tick box: still occupies the column so rows stay aligned, but
   reads as unavailable and stops inviting clicks. data-ro is the same marker
   Master Scope puts on a checked-out row's control. */
.bm-check[data-ro="1"] {
    border-color: var(--gray-200);
    background-color: var(--gray-100);
    cursor: default;
}

.bm-check[data-ro="1"]:hover {
    border-color: var(--gray-200);
}

/* The name still opens the modal, so it darkens further on hover — the
   history is why you'd look at a dropped firm. */
.bm-row-removed:hover .bm-sub-name {
    color: var(--gray-600);
}

/* --- bidder name -------------------------------------------------------
   Opens the bidder's modal, so it reads as clickable on hover. The weight
   steps up to the heavier heading face — the same hover cue .cc_grid_row,
   .budsim-trade-link and .opsChart_staff_name use — rather than an
   underline or a color change, since the row's own color already carries
   meaning (gray struck for a removed bidder). No transition: a font-family
   swap can't be animated, which is why the rules above don't declare one. */
.bm-sub-name {
    cursor: pointer;
}

/* One uniform gap for the marks that follow a bidder's name (R, the star,
   the flag, ? / !, the platform pending chips). Each mark class used to
   carry its own margin — 5px here, 4px there, none on the platform pills —
   so a row's spacing depended on which marks it happened to hold. Stated
   once, scoped to the name cell, and at higher specificity than the
   per-class margins, so it wins over all of them: every mark stands the
   same 0.3em off whatever precedes it, the name included. */
.bm-name-cell .bm-sub-name ~ * {
    margin-left: 0.3em;
}

.bm-row:hover .bm-sub-name {
    font-family: var(--headingfont);
}

/* No width here: the column carries it (see BODY_COLUMNS) and the table is
   fixed-layout, so a second declaration would just be a number to keep in
   sync. These three are what turn the overflow into an ellipsis. */
.bm-name-cell {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The optional Note column, switched on from Controls. Same three properties
   as the name cell above, and for the same reason: the rows on this table are
   held to one height, so a remark too long for its column has to end in an
   ellipsis rather than wrap and grow the row. The whole text is on the cell's
   tooltip.

   No colour of its own, deliberately. Setting one here put the note on a
   different grey from the line it belongs to and, being a class on the <td>,
   fought `.bm-row-removed td` over which grey a dropped bidder's note should
   be. Inheriting means one rule decides: a note reads in the row's own colour,
   and greys with the row when the bidder is removed. */
.bm-note-cell {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- potential outreach bidders ---------------------------------------
   The second table a trade card can carry (see bid_matrix._outreach_table):
   certified firms that are not ours. Set off from the bidder table above by
   a rule and a smaller heading, so it reads as an appendix to the section
   rather than as more of the same list. */
.bm-outreach {
    margin-top: 1.2em;
    padding-top: 0.8em;
    border-top: 1px solid var(--gray-300);
}

.bm-outreach h5.bm-outreach-heading {
    margin: 0 0 0.2em 0;
}

/* Opens the firm's outreach modal, so it wears the same hover cue as the
   bidder names above it (.bm-sub-name): the weight steps up to the heading
   face on row hover, no underline and no color change. */
.bm-outreach-name {
    cursor: pointer;
}

.bm-outreach-row:hover .bm-outreach-name {
    font-family: var(--headingfont);
}

/* --- project highlight --------------------------------------------------
   The app's shared highlight yellow (Safety Manual, SOP recent edits and the
   TPB reports all use this token), marking a bidder who bid or was awarded the
   project chosen in the Controls card.

   The class lands on the row and the fill is painted through it onto the name,
   which is where the inline style this replaced used to sit. That split is the
   point: the browser owns this mark now (see BM_HIGHLIGHT_JS), and setting one
   class on a <tr> is the whole of its work, where re-rendering 2,637 rows
   server-side to change a background colour cost ~395 ms and re-mounted 30,000
   React components. Nothing here touches display or order, so the mark
   survives the per-card sort and both filters. */
.bm-row-highlight .bm-sub-name {
    background-color: var(--sManual_yellow_highlight);
}

/* ======================================================================
   SHARED SUBCONTRACTOR PROFILE MODAL

   One modal, mounted by both the Buyout Tracker and the Bid Matrix and
   built by utils/sub_profile.py, so these rules are the only home for its
   look. The 'sp-' prefix marks them as belonging to the shared profile
   rather than to either page.
   ====================================================================== */

/* ----------------------------------------------------------------------
   SIMPLE SETTINGS FOR THE BIDDER MODAL — START HERE

   If you only want to change how the bidder modal looks, change the values
   in this one block and nothing else. Each line is

       --name-of-the-setting: value;

   Change what comes AFTER the colon. Leave the name alone, keep the
   semicolon, and save the file — the app picks it up on the next page load.

   Sizes are in 'em', which means 'times the normal text size':
       1em = normal text   0.875em = a little smaller   0.75em = three quarters
   Colours can be a hex code like #333333, a word like darkred, or one of the
   app's own colours written var(--gray-500) — the full palette is in the
   :root block at the top of this file.

   The rules further down this section READ these values; you should not
   need to touch them. If you do want to go further, the WHAT IS WHAT list
   after this block says which class name draws which part of the modal.
   ---------------------------------------------------------------------- */
:root {
    /* SECTION TITLES — the six chapters of the modal: 'Bidder Identity',
       'Notes', 'Entities', 'Committed Work', 'Bidding History',
       'Documents' (and 'Public records' while something is waiting).
       30% over the app's card h4, but held under the modal title's size. */
    --sp-section-title-size: calc(var(--font_em_3) * 1.3);
    --sp-section-title-color: var(--text_dark);

    /* TILE HEADINGS inside Bidder Identity — 'Bidder', 'Spellings',
       'Associated Addresses', 'Bidder Source' and the rest. The body's own
       dark gray rather than the brand red: the tiles now carry a card fill,
       so the heading no longer needs a colour to mark where a tile starts. */
    --sp-heading-size: var(--font_em_3A);
    --sp-heading-color: var(--text_dark);

    /* IDENTITY TILES — the card-like boxes of the Bidder Identity grid. */
    --sp-tile-bg: var(--gray-060);
    --sp-tile-radius: 8px;

    /* ORDINARY TEXT — every 'Label: value' line and bullet list. */
    --sp-text-size: var(--font_em_4A);
    --sp-text-color: var(--text_dark);
    --sp-text-line-height: 1.6;

    /* GREY ASIDES — 'None yet.', 'No projects recorded.', the notice after
       an edit. */
    --sp-note-color: var(--gray-600);

    /* THE QUIETEST TEXT — the small line under a bullet naming the registries
       it came from, a value that is not recorded, the CONTACT / PUBLIC DATA
       labels inside an entity card. */
    --sp-quiet-color: var(--gray-500);

    /* GAP between one section and the next (Notes → Entities). */
    --sp-section-gap: 25px;

    /* ENTITY CARDS — the grey boxes under 'Entities'. */
    --sp-entity-card-bg: var(--gray-060);
    --sp-entity-title-color: var(--monconred);   /* 'Legal Entity' in red */
    --sp-entity-label-width: 12.5em;             /* label column, so the
                                                    values line up */

    /* SMALL-CAPS GROUP LABELS inside an entity card — CONTACT, PUBLIC DATA. */
    --sp-tier-size: var(--font_em_5);
    --sp-tier-rule-color: var(--gray-200);       /* hairline above each */

    /* HIGHLIGHTS — the yellow behind the bidder's name and the primary
       contact, and the gold star on that contact. */
    --sp-highlight-bg: var(--sManual_yellow_highlight);
    --sp-star-color: #d29a00;

    /* THE SMALL CONTROLS — the '×' beside a list entry, the pencil beside a
       name, and their colour when the mouse is over them. */
    --sp-control-color: var(--gray-500);
    --sp-control-hover-color: var(--monconred);
}

/* ----------------------------------------------------------------------
   WHAT IS WHAT — which class name draws which part of the modal

   To find the rule for a part, search this file for the class name below.
   Every class starts with 'sp-' (short for 'sub profile').

     The red title band and its buttons ..... .pt-red-title-band (shared with
                                              every page; not in this section)
     Bidder's name in the title band ........ .sp-profile-title
     A section title ('Notes') .............. .sp-section-title
     A tile heading in Bidder Identity ...... .sp-profile-body h5
     Heading + its '+' or pencil on one line  .sp-group-head
     One section (title and its content) .... .sp-section
     A 'Label: value' line .................. .sp-fact   (label: .sp-fact-label)
     A label with several values ............ .sp-fact-multi
     Grey aside / empty state ............... .sp-note
     Muted value on a fact line ............. .sp-note-inline
     Registry line under a bullet ........... .sp-assoc-source
     Yellow highlight on a name ............. .sp-primary-name
     Gold star on the primary contact ....... .sp-primary-star
     Entity or GC button (opens its card) ... .button-download in .sp-assoc-link-controls
     Entity card, in the modal it opens ..... .sp-entity-card
       its title ('Legal Entity') ........... .sp-entity-card h6
       CONTACT / PUBLIC DATA labels ......... .sp-subhead, .sp-general-subhead
       a person's licence box inside it ..... .sp-person-card
       a red warning line at the bottom ..... .sp-entity-flag
       outlined card for a provisional one .. .sp-entity-card--provisional
     Tag in the Spellings list .............. .sp-alias-tag
     Sub-category pills on a trade .......... .sp-subcat-pill
     The '+' that opens an add form ......... .sp-alias-add
     The '×' that removes a list entry ...... .sp-alias-remove
     The pencil beside a name ............... .sp-name-edit
     The add form (field + Save) ............ .sp-alias-form
     Merge picker ........................... .sp-merge-form
     Award mover (moving a job to a trade) .. .sp-award-block
     PDF drop zone under 'Documents' ........ .sp-doc-upload
     Link to an attached PDF ................ .sp-doc-link
   ---------------------------------------------------------------------- */

/* One section of the modal — its heading and everything under it. The gap
   between sections lives here, so it is one setting rather than a number
   typed into the Python between every pair of sections. flow-root keeps a
   list's own bottom margin inside its section instead of merging it into
   the gap, so the gap is always the full setting. */
.sp-section {
    display: flow-root;
}

.sp-section + .sp-section {
    margin-top: var(--sp-section-gap);
}

/* A section with nothing to show yet keeps its container in the body — an
   edit redraws a section through that container (see _section_id in
   utils/sub_profile.py), and the Change Log is empty exactly until the
   first edit writes to it — but takes no room and leaves no gap. */
.sp-section.sp-section-empty {
    display: none;
}

/* A section title: one of the modal's chapters. The app's card-heading h4,
   so the modal's chapters sit at the level a card's heading does on a
   page. */
.sp-profile-body .sp-section-title {
    font-size: var(--sp-section-title-size);
    color: var(--sp-section-title-color);
}

/* The tile headings inside Bidder Identity run a step above the app's
   default h5 so they lead the facts underneath them clearly, a step under
   the section title above the grid. Scoped to the profile body, so h5s
   everywhere else keep the app's size. */
.sp-profile-body h5 {
    font-size: var(--sp-heading-size);
    color: var(--sp-heading-color);
}

/* Every run of non-table text in the profile — the 'Label: value' lines and
   the bullet lists — sits at one size, and that size is below the h5 section
   headings so the headings still lead. It matches .sp-note, so facts, lists
   and asides all read as one level.

   Light, not the Regular --tablefont: the profile pairs bold labels with
   light values, and Regular between them reads as a third weight that means
   nothing. */
.sp-fact {
    font-family: var(--textfont);
    font-size: var(--sp-text-size);
    color: var(--sp-text-color);
    line-height: var(--sp-text-line-height);
}

.sp-fact-label {
    font-family: var(--headingfont);
}

/* A fact with more than one value — a company with two phone numbers, three
   people named across its registries. The label sits once in the first
   column and each value takes a row of the second, so the second value lines
   up under the first rather than running on after it. A single value renders
   exactly as a plain .sp-fact does. */
.sp-fact-multi {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    /* A grid cell is a block, so the space after the colon is stripped; the
       gap puts back the width of one. */
    column-gap: 0.3em;
}

.sp-fact-multi .sp-fact-label {
    grid-column: 1;
    white-space: nowrap;
}

.sp-fact-multi .sp-fact-value {
    grid-column: 2;
    overflow-wrap: anywhere;
}

/* Inside an entity card the labels form a column, so the values line up
   down the card like a table's second column instead of starting wherever
   each label happens to end. Done as a hanging indent — the row is padded by
   the column width and the label is pulled back into the padding — rather
   than as a grid, so the line stays one run of inline text: it copies as
   'Name: Citibrix', and a long value wraps under itself, not under the label.
   The multi-value grid takes the same column width so its rows align with
   the rest. The person card's heading is a name, not a label, and is left
   out; so are lines without a label, such as the consolidated-from list. */
.sp-profile-body {
    --sp-fact-label-w: var(--sp-entity-label-width);
}

/* The app-wide .card rule breaks words anywhere (word-break: break-all), and
   in a column of facts that split 'Licenses' and 'Prequalified' across
   lines. Words break at spaces here, and only a run that cannot fit at all —
   a pasted URL — breaks inside itself. */
.sp-profile-body .card {
    word-break: normal;
    overflow-wrap: anywhere;
}

.sp-profile-body .sp-entity-card .sp-fact:has(> .sp-fact-label):not(.sp-fact-multi):not(.sp-person-head) {
    padding-left: var(--sp-fact-label-w);
}

.sp-profile-body .sp-entity-card .sp-fact:has(> .sp-fact-label):not(.sp-fact-multi):not(.sp-person-head) > .sp-fact-label {
    display: inline-block;
    width: var(--sp-fact-label-w);
    margin-left: calc(-1 * var(--sp-fact-label-w));
    vertical-align: top;
}

.sp-profile-body .sp-entity-card .sp-fact-multi {
    grid-template-columns: var(--sp-fact-label-w) minmax(0, 1fr);
    column-gap: 0;
}

.sp-profile-body .sp-entity-card .sp-fact-multi .sp-fact-label {
    white-space: normal;
}

/* --- entity card grid ----------------------------------------------------
   Two cards across, with their rows kept level through subgrid: the parent
   grid owns the row tracks, each card is a subgrid spanning as many of them
   as it has rows (the span is set inline by _entity_card, which is what
   counted the rows), and so a wrapped address in one card makes the same row
   taller in both. The canonical tier renders every heading and label on
   every card (general_groups' `complete`), so track N is the same field in
   each — and everything of unpredictable height (licence cards, the record
   summary, public data) is bundled into one .sp-entity-tail track at the
   foot, where the cards are allowed to differ.

   row-gap 0 on both: a parent row-gap would be inherited between every fact
   line inside the cards. The gap between stacked cards is the card's own
   margin-bottom. In a browser without subgrid the declaration drops and the
   card is an ordinary one-column grid — same reading order, no shared rows. */
.sp-profile-body .sp-entity-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 10px;   /* dmc 'xs', what the SimpleGrid this replaced used */
    row-gap: 0;
}

.sp-profile-body .sp-entity-grid--single {
    grid-template-columns: minmax(0, 1fr);
}

@media (max-width: 900px) {
    .sp-profile-body .sp-entity-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

.sp-profile-body .sp-entity-grid > .sp-entity-card {
    display: grid;
    grid-template-rows: subgrid;
    row-gap: 0;
    align-content: start;
}

/* The canonical tier's wrapper dissolves so each subhead and fact line is a
   row of the card's subgrid; the tail stays one box, one track. */
.sp-profile-body .sp-entity-card .sp-entity-ours {
    display: contents;
}

/* Each legal identity gets its own stacked sub-card, the .card.level2 idiom
   the Master Scope detail modal and Precon Staffing already use. Inside a
   modal the figure/ground inverts — a page is gray with white cards, a modal
   is white — so the gray fill has to be restated over the app-wide white-card
   rule, which would otherwise win. */
.sp-profile-body .card.level2.sp-entity-card {
    background-color: var(--sp-entity-card-bg) !important;
    padding: 0.5em 0.7em;
    margin-bottom: 0.5em;
}

/* The card's own name — 'Accounting Entity', 'Legal Entity', 'Provisional
   Entity'. In the brand red rather than the body's near-black: a bidder with
   several identities stacks several of these cards, and at h6 in the same ink
   as the facts beneath it the title read as one more fact rather than as the
   thing that says which company the next few lines belong to. Red is already
   this modal's structural accent (the title band, the merge control), so it
   marks a boundary here rather than introducing a new colour. */
.sp-profile-body .sp-entity-card h6 {
    margin: 0 0 0.2em;
    color: var(--sp-entity-title-color);
    font-weight: 600;
}

/* The tier headings inside an identity card: 'Consolidated from 2 public
   records', 'Public data'. Deliberately the quietest text in the
   card — smaller than the facts, gray, letter-spaced small caps — because
   each one labels a group of lines that matter more than the label does.
   The first attempt used .sp-fact-label, which is the same size as a field
   name and made the section heading shout over the fields under it.

   The rule above is what actually separates the tiers; the words only say
   what the next few lines are. */
.sp-profile-body .sp-subhead {
    margin: 0.7em 0 0.25em;
    padding-top: 0.5em;
    border-top: 1px solid var(--sp-tier-rule-color);
    font-family: var(--headingfont);
    font-size: var(--sp-tier-size);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--sp-quiet-color);
}

/* A struck associated entry: somebody marked it defunct or incorrect (see
   sub_contact_flag). The value stays legible under its line — the point is
   'this is wrong', not 'this never existed' — and recedes to the muted
   gray the removed bidder rows use. */
.sp-defunct {
    text-decoration: line-through;
    text-decoration-color: var(--gray-500);
    color: var(--gray-500);
}

/* Its byline: who called it, when, and why — italic under the sources so
   the provenance still reads first. */
.sp-defunct-note {
    font-style: italic;
}

/* The ✗ that strikes an entry and the ↺ that restores one, sized and
   placed like the '×' and pencil they sit among. */
.sp-defunct-mark:hover {
    color: var(--monconred);
}

/* The struck value read back in the strike form — shown, not editable. */
.sp-defunct-value {
    color: var(--gray-500);
}

/* The editing-rules line under the identity tiles: a footnote to the
   section, set off from the tiles above it. Two classes for the same
   reason as .sp-note.sp-bidhist-note — .sp-note-tight's margin shorthand
   sits later in the sheet and outdraws a single class. */
.sp-note.sp-editing-rules {
    margin-top: 12px;
}

/* The contract-name spelling is underlined as well as chipped. The chip
   names the mark once you are reading the line; the underline is what finds
   it in a list of twelve spellings without reading any of them. Offset so it
   clears the descenders. */
.sp-alias-contract {
    text-decoration: underline;
    text-decoration-color: var(--pillgray-dark);
    text-underline-offset: 0.18em;
}

/* Marks who writes a company under a given spelling, in the Spellings list:
   the bidder name, the accounting name, the contract name. Filled, and cut
   to the same shape and size as the Bidder tile's sub-category pills next
   door — the tags used to be outlines, which made them read as that tile's
   'off' (unassigned) state when the two cards sit side by side. The dark
   neutral fill is the same one the informational chips wear elsewhere
   (the R marker, the linked-source pills), which is what these are.

   One spelling can carry two or three of these at once, so they wrap with
   the line rather than pushing it wide. */
.sp-alias-tag {
    display: inline-block;
    box-sizing: border-box;
    margin-left: 0.5em;
    padding: 0 5px;
    border: 1px solid var(--pillgray-dark);
    border-radius: 8px;
    background-color: var(--pillgray-dark);
    color: #ffffff;
    font-family: var(--textfont);
    font-size: 9px;
    line-height: 1.2;
    white-space: nowrap;
    vertical-align: middle;
}

/* A bestowed role on an associated entry — Primary Owner, Primary
   Estimating, For ITBs. Shown only where held, as the ordinary filled tag;
   a button for a user who may edit, and it clicks the role off. The roles
   not held appear only while the star's pick is open on that line, as
   outline chips after a quiet 'mark as', and click the role on. Button
   reset first, since the tag rule above was written for a span. */
button.sp-desig-tag {
    cursor: pointer;
    font: inherit;
    font-family: var(--textfont);
    font-size: 9px;
    line-height: 1.2;
    margin-left: 0.35em;
}
/* A held role wears the highlight yellow — the same token as the starred
   name beside it — rather than the source chips' gray: it is our mark, not
   a system's, and the two should read as one thing. */
.sp-desig-tag {
    background-color: var(--sp-highlight-bg);
    border-color: var(--sp-highlight-bg);
    color: var(--sp-text-color);
}
.sp-desig-tag--off {
    background-color: transparent;
    border-color: var(--sp-star-color);
    color: var(--sp-text-color);
}
.sp-desig-tag--off:hover {
    background-color: var(--sp-highlight-bg);
    border-color: var(--sp-highlight-bg);
}
.sp-desig-prompt {
    margin-left: 0.5em;
    color: var(--sp-quiet-color);
    font-size: 0.85em;
}

/* A person in the Associated Individuals list: three lines, none wrapping.
   Name (with chips and controls), then title, then sources — set a step
   smaller than the body so the column stays even, and clipped with an
   ellipsis rather than folding, so every person is exactly three lines tall
   and the names fall at one rhythm down the list. The role line is kept
   even when empty, for the same reason. The name is set in the heading
   face so it stands off the title under it; the title and the sources
   share one indent, in pixels, so the two lines start flush whatever
   their sizes. */
.sp-profile-body li.sp-assoc-person {
    font-size: 0.92em;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-bottom: 0.45em;
}
.sp-profile-body li.sp-assoc-person > .sp-assoc-name {
    display: inline-block;
    max-width: 62%;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: bottom;
    font-family: var(--headingfont);
}
/* The name as a button, for a reader with controls: it opens the person's
   name editor. Dressed as the text it replaces — same face, size and
   colour, no box — so the list reads the same whether or not the names
   are live; the hover says they are. */
.sp-profile-body button.sp-assoc-name-btn {
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-family: var(--headingfont);
    line-height: inherit;
    text-align: left;
    cursor: pointer;
}
.sp-profile-body button.sp-assoc-name-btn.sp-primary-name {
    background-color: var(--sp-highlight-bg);
    padding: 0 0.25em;
}
.sp-profile-body button.sp-assoc-name-btn:hover {
    color: var(--pt-accent-dark);
    text-decoration: underline dotted;
    text-underline-offset: 2px;
}
.sp-profile-body li.sp-assoc-person .sp-assoc-role-line,
.sp-profile-body li.sp-assoc-person .sp-assoc-source {
    padding-left: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.3;
}
.sp-profile-body li.sp-assoc-person .sp-assoc-role-line {
    color: var(--gray-700);
}

/* A struck person (sp-assoc-person--struck, set alongside .sp-defunct on
   the name — see _associated_li_class). The whole bullet recedes as one:
   name, role and sources all go to the same light gray as the line through
   the name, where before the name button kept the body colour it inherits
   and the role kept its own darker gray under the strike. The gray is the
   one the app's disabled text and the removed bidder rows use — light, and
   still legible, since the point is 'this is wrong', not 'this is gone'.
   The strike itself is coloured explicitly: text-decoration-color does not
   follow a colour set on a descendant rule. Sits after the role-line rule
   above on purpose — same specificity, so order decides. */
.sp-profile-body li.sp-assoc-person--struck .sp-assoc-name,
.sp-profile-body li.sp-assoc-person--struck .sp-assoc-role-line,
.sp-profile-body li.sp-assoc-person--struck .sp-assoc-source,
.sp-profile-body li.sp-assoc-person--struck .sp-defunct-note {
    color: var(--gray-500);
    text-decoration-color: var(--gray-500);
}
/* The name as a button: the inherited colour and the blue hover give way
   to the gray. Still a control, so the hover still underlines — the strike
   stays on under it rather than being swapped out by the shorthand. The
   yellow 'primary' highlight is muted: a struck name should not be the
   brightest thing in the list. */
.sp-profile-body li.sp-assoc-person--struck button.sp-assoc-name-btn,
.sp-profile-body li.sp-assoc-person--struck .sp-assoc-name.sp-primary-name {
    color: var(--gray-500);
    background-color: transparent;
}
.sp-profile-body li.sp-assoc-person--struck button.sp-assoc-name-btn:hover {
    color: var(--gray-500);
    text-decoration-line: underline line-through;
    text-decoration-style: solid;
    text-decoration-color: var(--gray-500);
    text-underline-offset: 2px;
}

/* The fold-together control (⤴) on a listed person, address, phone, email
   or website, its undo (⤵) on a folded-in spelling, and the picker it
   opens under the line. One class for the control whichever list it is
   on (sub_profile._merge_person_button / _merge_contact_button), so the
   glyph reads the same everywhere; the link control (☍, below) takes the
   same size. The picker is the award mover's form; a person's line is
   clipped to one line (see .sp-assoc-person), so the form has to be
   allowed to wrap and breathe again. */
.sp-assoc-merge,
.sp-assoc-unmerge,
.sp-assoc-link {
    font-size: 0.95em;
}
.sp-profile-body li.sp-assoc-person .sp-assoc-merge-form {
    white-space: normal;
    overflow: visible;
    padding-left: 12px;
    margin-top: 0.3em;
}

/* Un-clipping the form was not enough: the picker's menu is absolutely
   positioned below the control, so it is clipped by the nearest ancestor
   with overflow: hidden, and that was the bullet itself — six options came
   out as one. The bullet holding the open picker (sp_profile.py sets the
   modifier from merge_open) drops the clip; the name span keeps its own
   ellipsis rule above, so a long name still shortens. Any other bullet
   holding an open picker (sp-assoc-link-open) drops it the same way, and
   so does the GC modal's form row, whose cell clips like every td. */
.sp-profile-body li.sp-assoc-person.sp-assoc-person--open,
.sp-profile-body li.sp-assoc-link-open,
.sp-profile-body td.sp-assoc-link-open {
    overflow: visible;
    white-space: normal;
    text-overflow: clip;
}

/* The menu scrolls inside itself (the list is virtualized and scrolls on
   its own) rather than running past the bottom of the modal on a bidder
   with a long list of people; the app-wide .is-open rule allows 600px. */
.sp-profile-body .sp-assoc-merge-form .Select-menu-outer {
    max-height: 220px !important;
    overflow-y: auto;
}

/* Whose a phone number or email address is (sub_profile._link_person_*).
   The control sits with the star, the ✗ and the pencil on the entry; lit
   in the accent once a link is held, the way the star goes gold. The
   picker it opens is the merge form above (same classes) indented under
   the entry, with the Link and Unlink buttons side by side under it. */
.sp-assoc-link.sp-assoc-link--on {
    color: var(--pt-accent-dark);
}
.sp-profile-body .sp-assoc-link-form {
    padding-left: 1.1em;
}
.sp-profile-body .sp-assoc-link-controls {
    display: flex;
    gap: 0.5em;
    flex-wrap: wrap;
}

/* The competent persons from the site logs, folded under a heading at the
   foot of the Individuals list. The toggle is the collapsible card's (same
   ids, same callback), and it looks like one: a subhead with the arrow
   after it, as the Read Me card's heading is, one level down from the
   card's own h5. No bullet on the line; the list it opens keeps them. */
.sp-profile-body li.sp-assoc-fold {
    list-style: none;
    /* Back out the list's own indent (2em of its size), so the heading
       starts flush with the card's title above rather than with the
       bullets' text. */
    margin-left: -2em;
    margin-top: 0.5em;
}
.sp-profile-body .sp-assoc-fold-toggle {
    cursor: pointer;
    user-select: none;
}
.sp-profile-body .sp-assoc-fold-head {
    margin: 0;
    font-size: 0.95em;
}
.sp-profile-body .sp-assoc-fold-count {
    font-family: var(--textfont);
    color: var(--sp-quiet-color);
}
.sp-profile-body .sp-assoc-fold-head .collapse_symbol {
    margin-left: 6px;
    margin-bottom: 0;
    font-size: 0.7em;
}
/* The unfolded people, set exactly as the ones above the fold: the list
   inherits the size and leading rather than restating them (.sp-fact's
   em-based size compounded here and came out a step smaller), keeps the
   disc rather than a nested list's circle, and indents by the outer
   list's 2em so the bullets fall in the same column — the fold line itself
   backed that indent out (margin-left above). */
.sp-profile-body li.sp-assoc-fold ul.sp-assoc-fold-list {
    margin: 0.3em 0 0;
    padding-left: 2em;
    list-style: disc;
    font-family: var(--textfont);
    font-size: inherit;
    line-height: inherit;
    color: var(--sp-text-color);
}

/* The name editor's body (see _person_editor_body): the explanation, the
   spellings as .sp-assoc-person lines, then the add field. The lines
   borrow the profile list's three-line set, so only the spacing between
   the blocks is stated here. */
.sp-person-editor .sp-person-editor-intro {
    margin: 0.5em 0 0.9em;
}
.sp-person-editor ul.sp-person-spellings {
    margin-bottom: 0.9em;
}
.sp-person-editor .sp-person-spelling-form {
    display: flex;
    margin-left: 0;
    margin-bottom: 0.6em;
}

/* --- one-line entries: the controls never wrap ---------------------------
   An associated entry (sub_profile._associated_editor — the Individuals,
   Addresses, Phone Numbers and Emails tiles, the Websites list, and the
   people under the fold) and a spelling (_alias_editor; the name editor's
   _person_editor_body) are each one <li> whose children lie flat, with
   no wrapper round the first line: the fact itself (.sp-assoc-name, or a
   bare span for a spelling), then its chips (.sp-alias-tag), a phone or
   address's ' — role' span, then the run of controls — every one of them
   a .sp-alias-remove: star, ✗, ✎, ⤴, ☍, × — and after those the block
   lines under the entry (role, contacts, owner, sources, an open picker).
   On a long name in a narrow tile the controls fell to a second line, or
   on a person line were clipped away by the bullet's own overflow.

   The bullet becomes a flex row that wraps, with the block lines under it
   pushed onto rows of their own by a 100% basis. The text items are given
   a zero basis — flex breaks lines on the basis, not on the content, so
   nothing with a zero basis ever starts a new row — and then grow back
   toward their own width (max-width: max-content) out of whatever the
   controls leave. When that is not enough, the grow weights say who gives
   first, and the order is the one an ellipsis on the whole line would
   have given — from the right: the ' — role' first, then the chips, and
   the name last, because the name is what the entry *is*, and a line that
   keeps 'Pablo Perrone' and loses the end of 'Primary Owner' still names
   its person where the other way round names nobody. A cut chip keeps
   its colour and its title, so it still says that a mark is held and,
   on hover, which. The ratios are only an ordering. Whatever is cut ends
   in an ellipsis.

   A flex box is not a list item, so the disc goes with it; it is drawn
   back with ::before, ending at the content edge the way the browser
   places an outside marker (the .pt-red-list recipe above). The person
   lines get a disc back with it that they had lost: the overflow: hidden
   on .sp-assoc-person clipped the browser's marker away, so the
   Individuals tile stood bulletless beside four tiles that were not.
   Only bullets holding a control are touched — 'None recorded.', the
   folded-people line and the print render keep their native marker — and
   the trade bullets in the Bidder tile, which carry a × too, are left out
   by the 'R' switch only they carry. */
:is(.sp-profile-body .sp-ident-tile ul,
    .sp-person-editor ul.sp-person-spellings)
    > li:has(> .sp-alias-remove):not(:has(> .sp-removed-toggle)) {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    /* The person bullet clipped itself to one line; each text item now
       clips its own, and a clip here would take the drawn bullet too. */
    overflow: visible;
    text-overflow: clip;
}
:is(.sp-profile-body .sp-ident-tile ul,
    .sp-person-editor ul.sp-person-spellings)
    > li:has(> .sp-alias-remove):not(:has(> .sp-removed-toggle))::before {
    content: '';
    position: absolute;
    /* The browser's disc, measured: a third of an em across, its right
       edge just under an em before the text, centred on the first line.
       Drawn as a shape rather than set as a '•', which comes out smaller
       and closer in than the marker on the line above it. */
    right: calc(100% + 0.95em);
    top: 0.5lh;
    width: 0.33em;
    height: 0.33em;
    border-radius: 50%;
    background: currentColor;
    transform: translateY(-50%);
}
/* The fact: first in every one of these bullets (_associated_head puts
   the name first; _alias_line the spelling). Overrides the person line's
   fixed 62% share, which clipped the controls whenever the chips took
   more than the rest. */
:is(.sp-profile-body .sp-ident-tile ul,
    .sp-person-editor ul.sp-person-spellings)
    > li:has(> .sp-alias-remove):not(:has(> .sp-removed-toggle)) > :first-child {
    flex: 100 1 0;
    max-width: max-content;
    min-width: 0;
    white-space: nowrap;
    /* clip rather than hidden, so the clip edge can be let out: the
       name button's dotted hover underline sits 2px under the baseline,
       and at this leading that is past the bottom of the box. The
       ellipsis still draws under clip. */
    overflow: clip;
    overflow-clip-margin: 0.3em;
    text-overflow: ellipsis;
}
/* The chips, and the 'mark as' prompt the role picker opens with. Centred
   on the line as vertical-align: middle had them, since a flex item takes
   no vertical-align. */
:is(.sp-profile-body .sp-ident-tile ul,
    .sp-person-editor ul.sp-person-spellings)
    > li:has(> .sp-alias-remove):not(:has(> .sp-removed-toggle)) > :is(.sp-alias-tag, .sp-desig-prompt) {
    flex: 10 1 0;
    max-width: max-content;
    min-width: 0;
    align-self: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* The exception: while the role picker is open on a line, the roles on
   offer (and the 'mark as' before them) are what the reader is choosing
   between, and 'Primary O…' against 'Primary Es…' is no choice. They
   outrank the name for the moment the picker is open. */
:is(.sp-profile-body .sp-ident-tile ul,
    .sp-person-editor ul.sp-person-spellings)
    > li:has(> .sp-alias-remove):not(:has(> .sp-removed-toggle)) > :is(.sp-desig-tag--off, .sp-desig-prompt) {
    flex-grow: 1000;
}
/* A phone or address's ' — role', the one text item after the fact that
   is not a chip. Its leading space goes when it becomes a box of its own
   (space at the start of a line is dropped), so the gap is restated. */
:is(.sp-profile-body .sp-ident-tile ul,
    .sp-person-editor ul.sp-person-spellings)
    > li:has(> .sp-alias-remove):not(:has(> .sp-removed-toggle)) > span:not(:first-child):not(.sp-alias-tag):not(.sp-desig-prompt) {
    flex: 1 1 0;
    max-width: max-content;
    min-width: 0;
    margin-left: 0.3em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
:is(.sp-profile-body .sp-ident-tile ul,
    .sp-person-editor ul.sp-person-spellings)
    > li:has(> .sp-alias-remove):not(:has(> .sp-removed-toggle)) > .sp-alias-remove {
    flex: none;
}
/* The lines under the entry, each a row of its own at the full width;
   they wrap or clip as their own rules say. */
:is(.sp-profile-body .sp-ident-tile ul,
    .sp-person-editor ul.sp-person-spellings)
    > li:has(> .sp-alias-remove):not(:has(> .sp-removed-toggle)) > div {
    flex: 0 0 100%;
    min-width: 0;
}

/* Project Commitments: the firms holding one trade on one job, wrapped as
   chips rather than stacked, because most trades have one or two and a
   column of single-item lists would be mostly white space. Indented under
   the trade name above them. */
.bm-commit-names {
    display: flex;
    flex-wrap: wrap;
    gap: 0.15em 1.2em;
    margin-left: 1em;
}

.bm-commit-picker {
    max-width: 34em;
}

/* The bidder's name in the modal's title band, held to one line. The band
   sizes itself to its contents and a two-line name made a header twice the
   height of every other modal's, moving the body down as the user paged
   between bidders. Overflows to an ellipsis; the full name is in the
   tooltip and, unabbreviated, in the Names field below.

   The padding/negative-margin pair is descender room. The span inherits the
   band's 1.05 line-height, and overflow: hidden clips at the padding edge —
   without the padding, the heading face's j/p/g/y tails fall outside the
   line box and get sliced flat. The negative margin gives the room back so
   the header stays the same height as every other modal's. */
.sp-profile-title {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding-bottom: 0.18em;
    margin-bottom: -0.18em;
}

/* The star that marks the contact to call first. Takes the geometry of the
   '×' and the pencil beside it so the three sit on one line, and goes gold
   when set, which is the one place in this list colour is used. */
.sp-primary-star {
    color: var(--sp-control-color);
}

.sp-primary-star.sp-primary-on {
    color: var(--sp-star-color);
}

/* The starred entry in an associated list, which is also sorted to the top.
   Set in the heading face at the body's own size rather than enlarged: it is
   the same kind of fact as the lines under it and only needs to be found
   first. Weight is carried by the face, not by font-weight — every
   GT-Pressura cut is its own family (see the note above :root). The yellow is
   the app's shared highlight token, the one the Safety Manual and the bidder
   rows already use. */
.sp-profile-body .sp-primary-name,
.bm-scope-rules .sp-primary-name {
    font-family: var(--headingfont);
    background-color: var(--sp-highlight-bg);
    padding: 0 0.25em;
}

/* The headings inside an identity's top tier — Name/ID, Contact, People,
   Certifications, Work Type, Geo Range. Same face as a subhead, but no rule
   above and a tighter margin: they divide one tier, not the card. */
.sp-profile-body .sp-general-subhead {
    margin: 0.55em 0 0.1em;
    padding-top: 0;
    border-top: none;
}
.sp-profile-body .sp-general-subhead:first-child {
    margin-top: 0;
}

/* A licence held by a person, inside the identity it was issued under. No
   card dress of its own any more — one step in is enough to read as
   belonging to the card it sits in rather than as a peer of it. */
.sp-profile-body .sp-person-card {
    margin: 0.35em 0 0 0.8em;
}

/* One folded-in record: which registry, then the name and id it holds
   there. The registry is the part a reader is looking for, so it keeps the
   body colour while the rest of the line recedes. */
.sp-profile-body .sp-consolidated-line {
    padding-left: 0.8em;
    text-indent: -0.8em;
}

.sp-profile-body .sp-source-name {
    font-family: var(--headingfont);
    /* The text carries a real space after it; this only widens it a little. */
    margin-right: 0.15em;
}

/* A record that has stopped being published, or otherwise needs saying.
   Last in the card and set apart, because it qualifies everything above
   it. */
.sp-profile-body .sp-entity-flag {
    margin-top: 0.5em;
    color: var(--monconred);
}

.sp-profile-body .sp-compliance-subhead {
    color: var(--monconred);
}

/* The second line of an associated bullet: where that fact came from.
   Indented under its content and lighter than it, so a column of bullets
   can be read for the addresses alone and the sources are there when
   wanted. */
.sp-profile-body .sp-assoc-source,
.bm-scope-rules .sp-assoc-source {
    padding-left: 1.1em;
    color: var(--sp-quiet-color);
    line-height: 1.35;
}

/* A provisional identity holds a labor status or a certification for a bidder
   with no legal or accounting record yet, so it is drawn as an outline rather
   than a filled card: it is a slot to be filled, not a company on file. */
.sp-profile-body .card.level2.sp-entity-card--provisional {
    background-color: transparent !important;
    border: 1px dashed var(--gray-300);
}

/* --- Data Inspection duplicate tables -----------------------------------
   Hand-built rather than make_table's output, because each row carries a
   Review button. Matches the divisional tables' hairline and row rhythm so
   the two read as the same page. */
.bm-pair-table {
    width: 100%;
    border-collapse: collapse;
}

.bm-pair-table td,
.bm-pair-table th {
    padding: 0.15em 0.5em;
    border-bottom: 1px solid var(--gray-150);
    /* Top, not middle: with wrapping cells a row is as tall as its longest
       column, and centring the short ones against it reads as misaligned. */
    vertical-align: top;
}

/* Headings stay on one line; they are short, and a wrapped header above a
   wrapped cell makes the column boundary hard to see. */
.bm-pair-table th {
    white-space: nowrap;
}

/* The trade columns are the evidence, so they wrap to fit the card instead of
   running off it. Two lines of room on every row, which is what most of them
   need; a longer list still grows its own row rather than being clipped. */
.bm-pair-table tbody td {
    height: 3.8em;
    white-space: normal;
}

/* Sized down and to its label: one sits on every row, and a full-height
   button on each would double the table. */
.bm-review-btn {
    padding: 0 0.5em;
    font-size: 0.75em;
    line-height: 1.5;
}

/* Each control has its own column and is sized to its label, so no row can be
   made taller by a button wrapping. Overrides the wrapping rule above, which
   is scoped to the cells carrying data. */
.bm-pair-table .bm-pair-controls {
    width: 1%;
    white-space: nowrap;
}

/* Merging from the table. Outlined red at rest, because it is the one control
   here that retires a record; filled once armed, so a row waiting on its
   second click is obvious among 250 others. */
.bm-merge-now-btn {
    color: var(--monconred);
    border-color: var(--monconred);
}

.bm-merge-now-btn.armed {
    background-color: var(--monconred);
    color: #ffffff;
    border-color: var(--monconred);
}

/* Ruling a pair out is the destructive-sounding option but the safe one, so
   it reads as secondary: muted until hovered, where it takes the brand red to
   confirm it is a decision being recorded. Deleting a saved configuration is
   the same shape of action — destructive wording, recoverable consequence —
   so it borrows the treatment. */
.bm-reject-btn,
.budsim-config-del {
    color: var(--gray-600);
    border-color: var(--gray-300);
}

.bm-reject-btn:hover,
.budsim-config-del:hover {
    color: var(--monconred);
    border-color: var(--monconred);
}

/* --- section heading with an add control ---------------------------------
   The '+' sits on the heading line rather than trailing the list, so the list
   below stays a clean run of entries. Baseline-aligned to the heading text and
   with the heading's own margin kept, so adding the control does not shift the
   column relative to its neighbours. */
.sp-group-head {
    display: flex;
    align-items: baseline;
    gap: 0.4em;
}

.sp-profile-body .sp-group-head h5,
.sp-profile-body .sp-group-head h4 {
    margin-bottom: 0;
}

/* --- Bidder Identity tiles ------------------------------------------------
   Each tile of the identity grid (Bidder, Trades, Spellings, Bidder Source)
   wears the app's basic-card dress — light gray, rounded — with spacing cut
   to the tile's scale: the .card padding rhythm, and the heading given the
   same breathing room an h4 gets on a page card. */
.sp-profile-body .sp-ident-tile {
    background-color: var(--sp-tile-bg);
    border-radius: var(--sp-tile-radius);
    padding: 0.5em 0.8em 0.7em;
}

/* Both forms of a tile's first heading: wrapped in a .sp-group-head row
   when the group has a '+' control, bare when it does not (the Bidder
   tile). Without the bare selectors the h5 kept its default top margin
   and that one tile sat lower than its neighbours. The Bidder tile's sits
   a level down, in the container its redraws write — the websites under
   it have a container of their own (_identity_block). */
.sp-profile-body .sp-ident-tile .sp-group-head h5,
.sp-profile-body .sp-ident-tile > h5:first-child,
.sp-profile-body .sp-ident-tile > :first-child > h5:first-child {
    margin-top: 0;
    margin-bottom: 0.4em;
}

/* --- merge picker --------------------------------------------------------
   Opened from the title band, so it sits at the top of the body at full
   width.

   The buttons that open it used to be filled red, to stop the one control
   that retires a record reading as a peer of Download PDF. That is no longer
   the case: the band's buttons are all the same outline style now, so the
   distinction is carried by the two-step — the button opens a picker and the
   picker is what commits — rather than by the colour. */
.sp-merge-form {
    margin: 0 0 0.6em;
}

/* The picker needs room for a full bidder name; the field it borrows from is
   sized for a short spelling. */
.sp-merge-input {
    min-width: 14em;
}

/* The merged record's name, typed by the person merging (required). Sized
   like the picker beside it, for the same full-name reason. */
.sp-merge-name {
    min-width: 16em;
}

/* An armed in-table merge: the Confirm button with the required name input
   stacked under it, inside the row's control cell. */
.bm-merge-arm {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.bm-merge-arm .bm-merge-name {
    width: 12em;
}

/* Red, because confirming this one retires a record. Same brand red the
   page-level rails use, so it reads as consequential rather than decorative. */
.sp-profile-body .sp-merge-confirm {
    border-color: var(--monconred);
    background-color: var(--monconred);
    color: #ffffff;
}

/* Inline pencil beside the bidder name. Borrows .sp-alias-remove's
   borderless sizing and only changes the hover colour, since renaming is an
   edit rather than a deletion. */
.sp-name-edit:hover {
    color: var(--pt-accent-dark);
}

/* Sub-category toggles on a trade bullet. Geometry, hairline and light face
   are make_inline_pill's 'sm' chip, so these read as the same pill family as
   the rest of the app — and at 9px on the light face they are neither larger
   nor heavier than the bullet text they sit beside.

   Every sub-category the trade defines is shown, so the pill has to say which
   state it is in: filled means assigned, outlined means one click away. */
.sp-subcat-pill,
.sp-removed-toggle,
.bm-subcat-pill {
    display: inline-block;
    box-sizing: border-box;
    padding: 0 5px;
    border: 1px solid var(--gray-800);
    border-radius: 8px;
    background-color: var(--gray-150);
    color: var(--textcolor);
    font-family: var(--textfont);
    font-size: 9px;
    /* No vertical margin, and a line-height that keeps the chip's outer box
       (9px text + 2px border ≈ 13px) well inside the table's fixed 1.75em row
       height. A taller chip grew the rows that had one, which is what put the
       divisional tables out of rhythm. */
    line-height: 1.2;
    margin: 0;
    white-space: nowrap;
    /* Baseline, not middle: an inline-block aligns on the baseline of its own
       last line, so the chip's text lands on the same baseline as the bidder
       name beside it instead of floating against the box centre. */
    vertical-align: baseline;
}

/* An enabled toggle fills with the same dark neutral every other filled
   chip in the identity cards wears — the R switch, the spelling tags — so
   'filled' reads as one formatting across the top two cards rather than a
   palette of dark grays. 'On' still reads at a glance against the outlined
   'off' state. The table's chips keep the light neutral fill: they are
   read-only, so they have no state to signal.

   The transition is the app's shared pill-morph, for the hover below. */
.sp-subcat-pill {
    cursor: pointer;
    border-color: var(--pillgray-dark);
    background-color: var(--pillgray-dark);
    color: #ffffff;
    transition: var(--pill-morph-transition);
}

/* The chips have their own column, so the gap goes after each one rather than
   before: a leading margin would indent the column off the header.

   Colour and font-size are inherited rather than declared, which is what
   matches the bidder name beside it: .bm-sub-name sets neither, so both take
   the row's. Inheriting the size overrides the 9px the shared rule above sets
   for the profile modal's toggles — in the table the chip text reads at the
   row's own size. The chip's outer box (1.2 line-height + 2px of border) still
   sits inside the table's fixed 1.75em row height, so rows with chips keep the
   same rhythm as rows without. A removed row greys its chips with its name.

   Transparent rather than the pill family's gray-150 fill, so the chip takes
   whatever the row is showing — the white/gray zebra, the yellow hover, the
   removed row's tone — and only the hairline says 'chip'. */
.bm-subcat-pill {
    margin-right: 4px;
    color: inherit;
    font-size: inherit;
    background-color: transparent;
}

/* Sized to its chips and no wider. Without nowrap a bidder carrying three of
   them wraps and grows that one row, which is what put the divisional tables
   out of rhythm before. */
.bm-subcat-cell {
    white-space: nowrap;
}

/* In the modal the chips drop to their own line under the trade they qualify.
   A block inside the li starts at the li's content edge, so they line up with
   the text above rather than with the bullet. */
.sp-subcat-row {
    margin-top: 0.15em;
}

.sp-subcat-row .sp-subcat-pill {
    margin-right: 4px;
}

.sp-subcat-pill.off,
.sp-removed-toggle.off {
    border-color: var(--gray-500);
    background-color: transparent;
    color: var(--gray-600);
}

/* The 'R' switch takes the dark chip the table's own R marker uses, not the
   red of an enabled sub-category: removal is a status to respect, while a
   sub-category is a qualifier, and the two should not read alike. */
.sp-removed-toggle {
    cursor: pointer;
    margin-left: 0.4em;
    border-color: var(--pillgray-dark);
    background-color: var(--pillgray-dark);
    color: #ffffff;
    transition: var(--pill-morph-transition);
}

/* Hover like the app's other buttons: the corners round out to a pill on
   the shared slow ease, and the chip fills the regular dark gray with
   light text — the same invert the title-band buttons do. One rule for
   on and off alike, so the two states meet in the same place under the
   pointer. */
.sp-subcat-pill:hover,
.sp-removed-toggle:hover {
    border-radius: var(--pill-radius-max);
    border-color: var(--pt-border);
    background-color: var(--pt-border);
    color: #ffffff;
}

/* The '+' beside a section heading. Square and sized from one em so the glyph
   centres on both axes, and small enough not to grow the heading line. */
.button1.sp-alias-add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 1.4em;
    height: 1.4em;
    padding: 0;
    margin: 0;
    line-height: 1;
    font-size: inherit;
    text-align: center;
    vertical-align: middle;
}

/* Inside the bidder modal the '+' hovers the way the title band's buttons do
   (REFRESH, MERGE BIDDERS, DOWNLOAD PDF — see
   .pt-red-title-band__action button:hover): the square fills with the same
   dark gray and the glyph goes white, on the same transition token. Scoped
   to .sp-profile-body so the green-tint .button1 hover elsewhere is
   untouched. The corner morph is the app-wide rule near the top of this file
   and applies to the band's buttons too, so it is left alone here. */
.sp-profile-body .button1.sp-alias-add {
    transition: var(--button-link-transition);
}

.sp-profile-body .button1.sp-alias-add:hover {
    background-color: var(--pt-border);
    border-color: var(--pt-border);
    color: #ffffff;
}

/* Opens beside the '+' on that same bullet, so the field belongs to the line
   the user clicked. inline-flex, not flex: a block would push itself onto the
   next line and leave the bullet marker stranded above it. Wraps because
   these columns are a quarter of the modal wide, and a field plus a Save
   button does not always fit on one line there. */
.sp-alias-form {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5em;
    margin-left: 0.5em;
    vertical-align: middle;
}

/* Committed trades inside a project card, each able to move to another
   bidder. Tighter than .sp-fact elsewhere because these sit inside a card
   that is one of five across the modal. */
.sp-award-block {
    margin-top: 0.35em;
}

.sp-profile-body .sp-award-list {
    margin: 0.15em 0 0 0;
    padding-left: 0.9em;
}

.sp-profile-body .sp-award-list li {
    line-height: 1.3;
}

.sp-award-trade {
    padding-right: 0.15em;
}

/* The app's standard .button1, shrunk to sit on a line of text inside a
   project card. Only the footprint changes — the border, the hover
   pill-morph and the type all come from .button1 — so it reads as the same
   control as every other button in the app. */
.sp-award-move {
    display: inline-block;
    margin: 0 0 0 0.4em;
    padding: 0 5px;
    font-size: var(--font_em_5A);
    vertical-align: baseline;
}

.sp-award-form {
    margin: 0.3em 0 0.5em 0;
}

/* Same form on the Bidder List's Project Commitments card, which has a whole
   page width rather than a fifth of a modal, so the picker is capped instead
   of filling it. */
.bm-award-picker {
    display: inline-block;
    min-width: 18em;
    max-width: 28em;
    vertical-align: middle;
}

.sp-profile-body .sp-award-picker {
    width: 100%;
    min-width: 0;
}

.sp-award-save {
    margin-top: 0.3em;
}

/* The picker for attaching a PDF. A dashed box rather than a button, since
   it takes a drop as well as a click, and wide enough to read as a target.
   Sits in the same form row the other add fields use. */
.sp-alias-form .sp-doc-upload {
    flex: 1 1 24em;
    max-width: 100%;
    border: 1px dashed var(--gray-500);
    border-radius: 6px;
    background: var(--gray-060);
    cursor: pointer;
}

.sp-alias-form .sp-doc-upload:hover {
    border-color: var(--monconred);
}

.sp-doc-drop {
    padding: 0.6em 1em;
    font-family: var(--textfont);
    font-size: var(--font_em_4A);
    color: var(--gray-500);
    text-align: center;
}

/* An attached file's name is a link that opens it; it reads as one. */
.sp-profile-body .sp-doc-link {
    color: var(--text_dark);
    text-decoration: underline;
    text-decoration-color: var(--gray-500);
}

.sp-profile-body .sp-doc-link:hover {
    color: var(--monconred);
    text-decoration-color: var(--monconred);
}

/* Room for 'Skye's SDVBD Tracker (8/11/22)' without wrapping. */
.sp-alias-form .sp-source-input {
    width: 22em;
}

/* Borderless, and sized off the line it sits on: this is inline in a bullet
   list, not one of a row of controls, and a bordered button would outweigh
   the spelling it belongs to. */
.sp-alias-remove {
    margin-left: 0.4em;
    padding: 0;
    border: 0;
    background: none;
    color: var(--sp-control-color);
    font-family: var(--buttonfont);
    font-size: inherit;
    line-height: 1;
    cursor: pointer;
}

.sp-alias-remove:hover {
    color: var(--sp-control-hover-color);
}

/* .input2 and .dropdown1 are blocks sized for a nav card. Inside an
   inline-flex row there is no parent width to grow into, so each field states
   its own; max-width keeps it inside its column. Both are the same width so
   the two lists' fields read as the same control. */
.sp-alias-form .sp-alias-input,
.sp-alias-form .sp-trade-input {
    flex: 0 1 auto;
    margin: 0;
    width: 11em;
    max-width: 100%;
}

.sp-alias-form .button1 {
    flex: 0 0 auto;
    margin: 0;
}

/* Muted aside: where a section's numbers came from, the empty states, and the
   confirmation after an edit. font-family is set explicitly rather than
   inherited — a bare font-style: italic here rendered in the UA serif inside
   the Bootstrap modal, which is where the stray Times italic came from. */
.sp-note {
    font-family: var(--textfont);
    color: var(--sp-note-color);
    font-size: var(--sp-text-size);
    line-height: 1.5;
}

/* Same, but sitting directly under a heading as its byline rather than
   closing out a section, so it needs the gap below instead of above. */
.sp-note-tight {
    margin: -0.25em 0 0.75em;
}

/* A value standing in for one that is legitimately unset — an unset short
   name falls back to the full name, which already fits. Muted so the fallback
   does not read as recorded data, but inline so it keeps its place on the
   fact row. */
.sp-note-inline {
    color: var(--sp-quiet-color);
}

/* Why a listing is marked 'R', typed on its own line under the trade name.
   Sized down to the modal's fact text rather than the app's standard input,
   because it sits inside a bulleted list of trades and a full-height field
   would make one line of that list twice the height of its neighbours. Full
   width of the list so a sentence has somewhere to go. */
.sp-removed-reason {
    display: block;
    width: 100%;
    margin-top: 0.25em;
    padding: 0.15em 0.4em;
    font-family: var(--textfont);
    font-size: var(--sp-text-size);
    line-height: 1.4;
}

/* The same reason where there is nothing to type into — a reader without
   edit rights, and the PDF. Muted, because it explains a row rather than
   being one of its facts. */
.sp-removed-note {
    font-family: var(--textfont);
    font-size: var(--sp-text-size);
    color: var(--sp-note-color);
    line-height: 1.4;
    margin-top: 0.15em;
}

/* The small action buttons in the nav-column cards (saved bid lists, new
   bidder) and the line each reports into. Compact rather than the app's
   standard button size, which beside a nav card's text reads as a page
   action. */
.bm-state-btn {
    font-size: var(--font_em_4A);
    padding: 0.25em 0.7em;
    margin: 0.5em 0 0;
    white-space: nowrap;
}

/* Empty until a run reports, so it must not reserve space when it has
   nothing to say. */
.bm-state-note:empty,
.budsim-config-note:empty {
    display: none;
}

.bm-state-note,
.budsim-config-note {
    margin-top: 0.5em;
}

/* The associated-list add form takes two fields — the name or address, and
   an optional role — where the spellings form takes one, so they stack
   instead of sitting on one line and cramping both. */
.sp-assoc-fields {
    display: flex;
    flex-direction: column;
    gap: 0.25em;
    flex: 1 1 auto;
    min-width: 0;
}

.sp-assoc-role {
    font-size: var(--font_em_4A);
}
