/* One number for the app's interface text - the side menu and every form label.

   Before this there were three scales and none of them agreed: menu links at 0.9rem (14.4px),
   form labels at Bootstrap's untouched 1rem (16px), and Syncfusion's inputs and grid cells at
   about 14px. So a label was LARGER than the value it described, which reads backwards.

   Set here as a variable rather than typed into each rule because tuning it is a judgement call
   somebody will want to make twice - change this line, not two files. */
:root {
    --cm-ui-font: 0.8rem;    /* 12.8px - forms. Came down one notch from 0.85rem on 2026-09-19. */

    /* THE SIDE MENU HAS ITS OWN SCALE, one step below the forms.
       These were one variable until 2026-09-19, on the reasoning that the menu and the forms
       should be "one size rather than two that merely happen to be close". That reasoning was
       wrong in one direction: a form label sits next to the value it describes and has to be
       legible at reading distance, whereas a menu row is a target you glance at and click. Tying
       them together meant the only way to get the menu down was to drag the forms down with it.
       They move together through the density scale, just not at the same size. */
    --cm-nav-font: 0.7rem;   /* 11.2px - side menu */

    /* Secondary text: the explanatory line under a field, the copyright line and the build-info
       strip. All three are the same kind of text - quiet, read once rather than scanned - and all
       three were different sizes: 14px, 12.8px and 11.5px monospace.

       ONE NOTCH BELOW --cm-ui-font, deliberately. The hints were the outlier: Bootstrap sizes
       .form-text at .875em of the PARENT, the parent here is an unstyled div, so they sat at a
       fixed 14px - LARGER than the 12.8px label they explain, and immune to the density. Measured
       on the running page, not read off the stylesheet. A hint that shouts louder than its own
       label is the same inversion this file already fixes at the top, pointing the other way. */
    --cm-hint-font: 0.75rem; /* 12px */

    /* Minimum height of a side-menu row. Was a hardcoded 1.5rem (24px) in two files, chosen when
       the menu text was 0.9rem. At 0.85rem with line-height 1.2 the text occupies about 16px, so
       24px forced roughly 8px of empty space into every row - and the smaller the font got, the
       more obvious that gap became. Exactly the mistake the label margins made.
       A variable because it is a judgement call, and because it is set in two places. */
    --cm-nav-row: 1.05rem;   /* 16.8px */

    /* Vertical padding inside a side-menu row, and the size of its icon.

       These exist because of a Blazor rule that is easy to miss: SCOPED CSS NEVER ATTACHES TO A
       COMPONENT TAG. The side menu's rows are <NavLink> components, so the <a> each one renders
       carries no b-xxxxxxxxxx attribute, and every `.nav-link` rule in NavMenu.razor.css misses
       it entirely. What actually won was Bootstrap's untouched `.nav-link { padding: .5rem 1rem }`
       - 16px of vertical padding on every row, which no amount of shrinking the font would ever
       have touched. That is why the rows sat ~38px apart while the CSS above said ~21px.

       The icon is the same mistake in reverse: hardcoded at 1.05rem with a 1.25rem line-height it
       put a 20px floor under every row, so the row could not follow the font down even where the
       font did shrink. Both now move with the density. */
    --cm-nav-pad: 0.1rem;    /* 1.6px top and bottom */
    --cm-nav-icon: 0.85rem;  /* 13.6px */
}

/* ---------------------------------------------------------------------------------------------
   DISPLAY DENSITY - a per-user setting, the way the legacy Code On Time app had it.

   Density is about eyesight and screen size, not about the tenant, so two people on the same
   site want different answers and a site-wide setting would let whoever has the best eyesight
   decide for everybody. Stored on Users (migration 055) and rendered as data-density on <html>.

   This costs almost nothing only because everything density-related already flows through the
   two variables above. A density is a pair of values for them, nothing more.

   The scale brackets where hand-tuning landed on 2026-09-19: "compact" IS that setting, and
   "comfortable" is what it was before. The numbers are chosen, not inherited - Code On Time
   applies its own density from JavaScript at runtime and its values are not in its stylesheets.

   :root above stays as the fallback, so a user with no preference, a signed-out page, or a
   value the CSS does not recognise all render as compact rather than as nothing.
   --------------------------------------------------------------------------------------------- */
[data-density="tiny"] {
    --cm-ui-font: 0.7rem;   /* 11.2px - forms */
    --cm-nav-font: 0.6rem;  /* 9.6px - side menu */
    --cm-hint-font: 0.65rem;  /* 10.4px - hints, copyright and build-info */
    --cm-nav-row: 0.85rem;
    --cm-nav-pad: 0.04rem;
    --cm-nav-icon: 0.75rem;
}

[data-density="condensed"] {
    --cm-ui-font: 0.75rem;  /* 12px - forms */
    --cm-nav-font: 0.65rem; /* 10.4px - side menu */
    --cm-hint-font: 0.7rem;   /* 11.2px - hints, copyright and build-info */
    --cm-nav-row: 0.95rem;
    --cm-nav-pad: 0.06rem;
    --cm-nav-icon: 0.8rem;
}

[data-density="compact"] {
    --cm-ui-font: 0.8rem;   /* 12.8px - forms  <- the default */
    --cm-nav-font: 0.7rem;  /* 11.2px - side menu */
    --cm-hint-font: 0.75rem;  /* 12px - hints, copyright and build-info */
    --cm-nav-row: 1.05rem;
    --cm-nav-pad: 0.1rem;
    --cm-nav-icon: 0.85rem;
}

[data-density="comfortable"] {
    --cm-ui-font: 0.9rem;   /* 14.4px - forms */
    --cm-nav-font: 0.8rem;  /* 12.8px - side menu */
    --cm-hint-font: 0.85rem;  /* 13.6px - hints, copyright and build-info */
    --cm-nav-row: 1.3rem;
    --cm-nav-pad: 0.25rem;
    --cm-nav-icon: 0.95rem;
}

html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

/* 1,162 labels carry class="form-label" and not one bare <label> exists, so this reaches every
   form in the app. form-check-label covers the 42 checkbox captions.

   The INPUTS are here too, deliberately. Shrinking only the labels left a 13.6px caption above
   16px text - a bigger contrast than intended, and not what "the same size" means. Both move
   together off the one variable. */
.form-label,
.form-check-label,
.form-control,
.form-select,
.input-group-text {
    font-size: var(--cm-ui-font);
}

/* The 76 explanatory lines under fields. Bootstrap sizes these at .875em of the PARENT, and the
   parent is an unstyled div, so they sat at a fixed 14px and were the one piece of form text that
   ignored the density entirely. Same variable as the footer now - see --cm-hint-font. */
.form-text {
    font-size: var(--cm-hint-font);
}

/* The gap under a label was sized for 16px text and did not come down with the font.
   Bootstrap gives .form-label margin-bottom: 0.5rem (8px) AND line-height 1.5 - which at 13.6px
   leaves about 3.4px of leading below the glyphs before the margin even starts, so the visible
   gap was nearer 11px than 8. Measured on the running page rather than guessed.

   Margin and line-height only - the checkbox label is left alone, since it sits beside its box
   rather than above a field and a tighter line-height there just crowds it. */
.form-label {
    margin-bottom: 0.15rem;
    line-height: 1.3;
}

.login-page {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background-color: #f5f5f5;
}

.login-card {
    width: 100%;
    max-width: 360px;
    padding: 2rem;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.1);
}

.login-card h1 {
    font-size: 1.5rem;
    margin-bottom: 1.5rem;
    text-align: center;
}

.legal-page {
    width: 100%;
    max-width: 760px;
    padding: 2rem;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.1);
    line-height: 1.6;
}

.legal-page h2 {
    font-size: 1.15rem;
    margin-top: 1.75rem;
}

.login-logo {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 0 auto 1.5rem;
}

/* Reusable "show/hide password" toggle - wrap a password <input> (or SfTextBox root)
   in .password-field, add a .password-toggle button inside it. Works for both plain
   HTML inputs and Syncfusion's rendered markup since it just targets input padding/position. */
.password-field {
    position: relative;
}

    .password-field input,
    .password-field .e-input-group {
        padding-right: 2.5rem;
    }

.password-toggle {
    position: absolute;
    top: 50%;
    right: 0.5rem;
    transform: translateY(-50%);
    background: none;
    border: none;
    padding: 0.25rem;
    color: #6c757d;
    cursor: pointer;
    line-height: 1;
    z-index: 2;
}

    .password-toggle:hover {
        color: #343a40;
    }

.detail-panel {
    border: 1px solid #dee2e6;
    border-radius: 4px;
    margin-bottom: 1rem;
    background: #fff;
}

.detail-panel-header {
    background: #f1f3f5;
    padding: 0.5rem 0.75rem;
    font-weight: 600;
    font-size: 0.85rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: #495057;
    display: flex;
    align-items: center;
    user-select: none;
}

.detail-panel-header-text {
    cursor: pointer;
}

.detail-panel-chevron {
    margin-left: auto;
    cursor: pointer;
    transition: transform 0.15s ease;
}

.detail-panel-mobile-hint {
    font-size: 0.75rem;
    color: #adb5bd;
    margin-left: 0.15rem;
}

.detail-panel-chevron.expanded {
    transform: rotate(180deg);
}

.detail-panel-body {
    padding: 0.75rem;
}

/* Panels with no required fields (CollapsiblePanel NoRequiredFields="true") default to
   collapsed on a narrow/phone viewport - so the detail screen doesn't feel overwhelming there -
   and expanded on a wider one, matching how every other panel already behaves on desktop. Pure
   CSS, no JS/interop: it reacts live to browser resize, and ".toggled" (added by the header's
   click handler) always flips whichever default the current viewport would otherwise apply. */
.detail-panel-body.optional.toggled {
    display: none;
}

@media (max-width: 768px) {
    .detail-panel-body.optional {
        display: none;
    }

    .detail-panel-body.optional.toggled {
        display: block;
    }
}

/* MobileTabSelector.razor - the phone-sized single-line "List: [dropdown]" replacement for the
   entity detail pages' real SfTab header (which wraps to several rows on a narrow viewport,
   pushing the actual form fields below the fold). Same pure-CSS, no-JS-interop pattern and same
   768px breakpoint as CollapsiblePanel above - hidden by default, shown only on phone, with the
   real .e-tab-header doing the opposite so exactly one of the two is ever visible. */
.mobile-tab-selector {
    display: none;
}

@media (max-width: 768px) {
    .mobile-tab-selector {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        padding: 0.5rem 0.75rem;
    }

    .mobile-tab-selector-label {
        margin: 0;
        font-weight: 600;
        white-space: nowrap;
    }

    .mobile-tab-selector select {
        flex: 1;
    }

    .e-tab .e-tab-header {
        display: none !important;
    }
}

/* Syncfusion's Tab component sometimes fails to detect header overflow (its own
   scroll-nav arrows never get injected), leaving .e-tab-header at its default
   overflow-x: hidden and silently clipping tabs past the visible width with no
   way to reach them. Force native browser scrolling as a reliable fallback. */
.e-tab .e-tab-header {
    overflow-x: auto !important;
}

/* Tab content (button rows, grids, etc.) rendered flush against the tab strip's
   bottom border with zero breathing room - Syncfusion's theme ships no top padding
   on .e-content .e-item by default. One global rule covers every SfTab-based
   detail page instead of a per-sub-tab-component fix. */
.e-tab .e-content .e-item {
    padding-top: 1rem;
}

.detail-map {
    width: 100%;
    height: 220px;
    border: 0;
    border-radius: 4px;
    margin-top: 0.5rem;
}

a, .btn-link {
    color: #006bb7;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.page-title {
    font-size: 1.5rem;
    font-weight: 700;
    margin-bottom: 1rem;
}

/* Toolbar icon-button color treatment ("Option C" - tinted icon chip, white button), trial on
   the Leads page first. Semantic per action, not decorative: purple = print, green = Excel/
   export, pink = map/location. */
/* The button itself becomes the flex container - aligning the chip against the text via
   vertical-align is fragile (depends on exact font metrics); flex + align-items:center is not. */
.e-btn:has(.icon-chip) {
    display: inline-flex !important;
    align-items: center;
}
.icon-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    margin-right: 0.45rem;
    flex-shrink: 0;
}
.icon-chip i {
    font-size: 0.78rem;
    line-height: 1;
}

.chip-purple { background-color: #f1e9fb; }
.chip-purple i { color: #6f42c1; }

/* Trial: same light-green tint on every toolbar button, not just the icon ones, to see the
   uniform effect. */
.btn-tint-green-all.e-btn { background-color: #e3f6e9 !important; border-color: #c8ecd4 !important; color: #14532d !important; }
.btn-tint-green-all.e-btn:hover { background-color: #d2f0dc !important; }

.chip-green { background-color: #e3f6e9; }
.chip-green i { color: #1e7e34; }

/* Icon-only "+" create/add buttons - a real circle, matching the nav-profile-avatar badge shape
   (NavMenu.razor.css) rather than Syncfusion's default rounded-rect. */
.btn-circle-add.e-btn {
    width: 2rem;
    height: 2rem;
    min-width: 2rem;
    padding: 0 !important;
    border-radius: 50% !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

/* The "+" is the first thing in its row, on every screen.

   This began scoped to sub-item grid toolbars only (d-flex gap-2 flex-wrap mb-2), where the
   reason was wrapping: the "+" was the last flex item, so on a narrow viewport it dropped to a
   line of its own. That covered 59 toolbars and left about 47 alone - 30 page-title rows where
   the "+" sat after the <h1>, plus some justify-content-end rows where it sat at the far right.

   Widened 2026-09-19 on the user's instruction: one position, everywhere. The earlier note here
   argued against exactly this, because on a page-title row it puts the "+" in front of the
   heading - "(+) Companies" rather than "Companies (+)". That is what it does, and it is the
   point: the button is in the same place whatever page you are on, instead of sitting after a
   heading whose width changes from page to page.

   `order` only means anything inside a flex container, so this is inert everywhere else. */
.btn-circle-add.e-btn {
    order: -1;
}
.btn-circle-add.e-btn i { margin: 0; }

.chip-pink { background-color: #fbe6f0; }
.chip-pink i { color: #d63384; }

/* Global (unscoped) override for the "you are here" active state on a direct-link NavGroup
   header (My Tasks, Reference Admin) - NavGroup.razor.css's own scoped text-decoration:none
   and NavMenu.razor.css's a.active background/color don't reliably reach the <a> a <NavLink>
   component renders (its scope attribute doesn't propagate the same way a literal element's
   does), so the browser's default active-link underline was showing through. Global CSS has
   no scope-attribute matching requirement, so this wins regardless of that mechanism. */
.nav-group-header-main.active {
    text-decoration: none !important;
    background-color: rgba(13, 110, 253, 0.12);
    color: #0d6efd !important;
}

/* Small teal "directions" diamond badge next to a Project's Address field
   (ProjectEditForm.razor) - a rotated square gives the diamond shape, the
   icon inside is rotated back to stay upright. */
.directions-icon-link {
    display: inline-flex;
    vertical-align: middle;
    text-decoration: none;
}
.directions-icon-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    background-color: #00838f;
    border-radius: 3px;
    transform: rotate(45deg);
}
.directions-icon-badge i {
    display: inline-block;
    transform: rotate(-45deg);
    color: #fff;
    font-size: 9px;
}

/* Click-to-reveal distance/travel-time popover anchored under the directions
   icon (DirectionsButton.razor). */
.directions-button-wrap {
    position: relative;
    display: inline-flex;
}
.directions-popover {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1000;
    margin-top: 4px;
    padding: 8px 10px;
    background-color: #fff;
    border: 1px solid #dee2e6;
    border-radius: 6px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    white-space: nowrap;
}

/* Small green "call" badge next to a phone number (CallButton.razor) - deliberately the same
   16px badge geometry as the directions diamond above, but left square and tinted green so the
   two actions read as siblings without being mistaken for each other at a glance. */
.call-icon-link {
    display: inline-flex;
    vertical-align: middle;
    text-decoration: none;
}
.call-icon-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    background-color: #198754;
    border-radius: 3px;
}
.call-icon-badge i {
    color: #fff;
    font-size: 9px;
}

/* Click-to-reveal call-status popover anchored under the call icon (CallButton.razor) - same
   anchoring and shape as .directions-popover, but allowed to wrap: a failure message here is a
   full sentence ("Add your own mobile number..."), not a short distance string. */
.call-button-wrap {
    position: relative;
    display: inline-flex;
}
.call-popover {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1000;
    margin-top: 4px;
    padding: 8px 10px;
    background-color: #fff;
    border: 1px solid #dee2e6;
    border-radius: 6px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    max-width: 260px;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Global (non-scoped) override - the component-scoped .nav-group-header rule in
   NavGroup.razor.css wasn't taking effect on this specific NavLink for reasons
   that resisted diagnosis without live DOM access, so this bypasses component
   CSS isolation entirely by targeting the link directly. */
a[href="reference-admin"] {
    color: #343a40 !important;
    text-decoration: none !important;
    font-weight: 500 !important;
}

/* Quick Print: a purpose-built read-only "Label | Value" view (not the live
   interactive form), so a Print button just needs CssClass="no-print" calling
   JS.InvokeVoidAsync("print"). The container-freeing rules below still matter
   because the print view renders inside the same Syncfusion Dialog/Tab, whose
   own fixed-height/overflow would otherwise clip it to one screenful. */
.quick-print-title {
    text-align: center;
}

.quick-print-table {
    width: 100%;
    border-collapse: collapse;
}

.quick-print-table td {
    padding: 0.35rem 0.5rem;
    border-bottom: 1px solid #dee2e6;
    vertical-align: top;
}

.quick-print-label {
    font-weight: bold;
    width: 30%;
    white-space: nowrap;
}

.quick-print-footer {
    margin-top: 1rem;
    font-size: 0.85rem;
    color: #6c757d;
}

/* Maximize/restore toggle for SfDialog headers (matches the desktop app's dialog
   chrome). SfDialog has no built-in maximize, so HeaderTemplate replaces the title
   area and this sits to the left of Syncfusion's own close icon (.e-close-icon,
   ~2.5rem wide) rather than overlapping it. */
.dialog-header-with-maximize {
    width: 100%;
    padding-right: 2.5rem;
}

/* Entity edit dialogs (Project/Company/Person/Lead/Opportunity/Employee/Cost Database/Expense)
   put Cancel/Save in the header bar next to the title. On "Edit X" the title also carries the
   record's own name/description ("Edit Project - <name>"), which on a phone-width dialog leaves
   Cancel/Save squeezed to a sliver next to a long title. Same 768px breakpoint as
   MobileTabSelector/CollapsiblePanel above - stacks the title above a left-aligned Cancel/Save
   row instead of forcing them to share one line. "New X" titles are short and never hit this,
   so they just render the same two-row layout with plenty of room to spare. */
@media (max-width: 768px) {
    /* !important because Bootstrap 5's own .align-items-center utility class (also present on
       this element, for the desktop row layout) is itself !important by design - a normal
       declaration here, no matter how specific the selector, can never beat that. */
    .entity-dialog-header-titlebar {
        flex-direction: column;
        align-items: flex-start !important;
        gap: 0.5rem;
    }
}

.dialog-maximize-toggle {
    cursor: pointer;
    font-size: 1rem;
    opacity: 0.85;
    padding: 0 0.5rem;
}

.dialog-maximize-toggle:hover {
    opacity: 1;
}

.dialog-maximized.e-dialog {
    top: 0 !important;
    left: 0 !important;
    max-width: 100vw !important;
    max-height: 100vh !important;
    margin: 0 !important;
}

.dialog-maximized .e-dlg-content {
    max-height: calc(100vh - 100px);
    overflow-y: auto;
}

@media print {
    .sidebar, .top-row, .no-print, .e-dlg-header-content, .e-close-icon, .e-tab-header {
        display: none !important;
    }

    .e-dialog {
        position: static !important;
        box-shadow: none !important;
        width: 100% !important;
        height: auto !important;
        max-width: none !important;
    }

    .e-dlg-content,
    .e-tab .e-content,
    .e-tab .e-content .e-item,
    .e-tab .e-content .e-item.e-active {
        overflow: visible !important;
        height: auto !important;
        max-height: none !important;
    }
}
.copyright-footer {
    text-align: center;
    font-size: var(--cm-hint-font);
    color: #6c757d;
    padding: 1rem 0 0.5rem;
}

/* ---------------------------------------------------------------------------------------------
   Grid toolbars on a phone: icons only.

   Every grid carries the same row of actions - Show/Hide Filters, Advanced Filter, Print List,
   Excel Export, Choose Columns, Reset Columns, and on some grids Map or Kanban View. With their
   labels that row is far wider than a phone screen, so it wraps into four or five stacked lines
   and pushes the actual grid off the bottom. The icons alone fit on one line.

   Done here rather than in eighty-four razor files: they all share .btn-tint-green-all, and the
   labels are bare text nodes next to the <i>, which cannot be targeted individually by CSS. So
   the button's font-size goes to zero - which collapses any text inside it, wrapped or not - and
   the icon gets its size back explicitly. One rule, every grid, nothing to keep in sync.

   Buttons carry a title attribute, so a long-press still says what each one does.
   --------------------------------------------------------------------------------------------- */
@media (max-width: 576px) {
    .btn-tint-green-all.e-btn {
        font-size: 0;
        padding-left: 0.6rem;
        padding-right: 0.6rem;
    }

    .btn-tint-green-all.e-btn i {
        font-size: 1rem;
        margin-right: 0 !important;
    }

    /* The toolbar itself can breathe a little tighter once the labels are gone. */
    .btn-tint-green-all.e-btn + .btn-tint-green-all.e-btn {
        margin-left: 0.25rem;
    }
}

/* ---------------------------------------------------------------------------------------------
   Banded grid rows, when a site asks for them (Site Settings -> "Use alternating grid row colour").

   The grids already mark every second row with .e-altrow - Syncfusion does that by default. What
   was missing is any colour: the bootstrap5 theme styles .e-altrow in exactly one place, inside a
   multicolumn dropdown popup, and leaves grid rows alone. Bootstrap 5's own tables are unstriped
   by default and the theme follows it, so every row came out white.

   So this is the paint, switched on by a class on the page shell rather than a property set on
   eighty-four grids.

   A very light green, picked to sit with the green-tinted toolbar buttons (btn-tint-green-all,
   #e3f6e9) rather than introduce a second accent. Deliberately far lighter than those buttons:
   this is behind every second row of a dense grid all day, so it has to be noticeable on a wide
   row and invisible the rest of the time. It must also never fight the hover highlight, which is
   what actually tells you where the pointer is.
   --------------------------------------------------------------------------------------------- */
.alt-rows .e-grid .e-row.e-altrow > .e-rowcell,
.alt-rows .e-grid .e-altrow > .e-rowcell {
    background-color: #f4fbf6;
}

/* Hover has to win, or the banding swallows it. */
.alt-rows .e-grid .e-row.e-altrow:hover > .e-rowcell {
    background-color: #e8f4ec;
}

/* Selection is Syncfusion's own colour and must come through untouched. */
.alt-rows .e-grid .e-row.e-altrow > .e-rowcell.e-selectionbackground,
.alt-rows .e-grid .e-altrow.e-active > .e-rowcell {
    background-color: inherit;
}

@media print {
    /* On paper there is no hover at all, which is where banding earns its keep - it becomes the
       only thing helping the eye stay on one row across a wide printed list. A shade stronger,
       because print washes very light tints out, and print-color-adjust because browsers drop
       background colours when printing unless told not to. */
    .alt-rows .e-grid .e-row.e-altrow > .e-rowcell,
    .alt-rows .e-grid .e-altrow > .e-rowcell {
        background-color: #e9f5ed !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
}

/* Build info strip - Site 1 only. Deliberately quiet: it is for whoever is debugging
   which environment they are actually looking at, not something to read every day. */
.build-info-footer {
    text-align: center;
    /* Was 0.72rem (11.5px) monospace - smaller than anything else on the page and a different
       typeface, which made a line that is occasionally important genuinely hard to read. Matches
       the field hints now, in size and in family. The monospace went with it: it bought nothing,
       since nothing here is column-aligned. */
    font-size: var(--cm-hint-font);
    color: #8a8279;
    padding: 2px 12px 10px;
    word-break: break-word;
}
.build-info-footer .bi-sep { opacity: 0.45; margin: 0 5px; }
.build-info-footer .bi-env { font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.build-info-footer .bi-db { color: #6b655d; }
.build-info-footer a.bi-commit { color: #8a8279; text-decoration: underline dotted; }
.build-info-footer a.bi-commit:hover { color: #c8102e; }

/* Display density picker in the side menu. Deliberately quiet - it sits beside Expand/Collapse
   All, which is the same kind of control, and it should not compete with the menu itself. */
.density-picker {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: var(--cm-hint-font);
    color: #6c757d;
    /* Shares its row with the notification bell, so it takes the leftover width and shrinks
       rather than pushing the bell off the edge. The row owns the spacing below, not this. */
    flex: 1 1 auto;
    min-width: 0;
}

/* Density on the left, bell on the right, the gap between them rather than around them. */
.nav-density-bell-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

    /* Sized to sit level with the select beside it - Bootstrap's own .btn-sm is built for a
       16px page and stands a good 6px taller than this row needs. */
    .nav-density-bell-row .btn {
        flex-shrink: 0;
        font-size: var(--cm-hint-font);
        padding: 0.1rem 0.4rem;
        line-height: 1.4;
    }

/* Collapsed to the icon rail the picker is hidden (below), leaving the bell alone - centre it
   over the icon column instead of letting space-between strand it on the left. */
.nav-collapsed .nav-density-bell-row {
    justify-content: center;
}
.density-picker .density-label { flex-shrink: 0; }
.density-picker .density-select {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--cm-hint-font);
    color: #6c757d;
    background-color: transparent;
    border: 1px solid #dee2e6;
    border-radius: 4px;
    padding: 0.1rem 0.2rem;
    cursor: pointer;
}
.density-picker .density-select:hover { color: #212529; border-color: #adb5bd; }
.density-picker .density-select:disabled { opacity: 0.5; cursor: default; }

/* Hidden when the sidebar is collapsed to an icon rail - there is no room for it, and the rail
   is not where somebody goes to change a preference. */
.nav-collapsed .density-picker { display: none; }
