/* ═══════════════════════════════════════════════════════════════════
    URUS — Main application stylesheet
    Loaded by base_page.html (authenticated pages) and
    _auth_base.html (login, password reset, logged out).
    ═══════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════
    DUNE RISE — Display font for URUS branding wordmark only.
    Free for personal + commercial use. Source: dafont.com/dune-rise
    ═══════════════════════════════════════════════════════════════════ */

@font-face {
    font-family: 'Dune Rise';
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url("../vendor/dune-rise/dune-rise.efa61f3c96af.woff2") format('woff2');
}

/* ═══════════════════════════════════════════════════════════════════
    NOTO NASKH ARABIC — Jawi branding script only.
    OFL license. Source: fontsource (Google Fonts).
    Arabic subset only — Latin glyphs fall through to JetBrains Mono.
    ═══════════════════════════════════════════════════════════════════ */

@font-face {
    font-family: 'Noto Naskh Arabic';
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url("../vendor/noto-naskh-arabic@5.2.11/noto-naskh-arabic-arabic-400-normal.9ebecc332fb3.woff2")
        format('woff2');
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0897-08E1,
        U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74,
        U+FE76-FEFC;
}

/* ═══════════════════════════════════════════════════════════════════
    JETBRAINS MONO — Primary body font.
    Variable weight (100-800), Latin subset.
    Vendored from @fontsource-variable/jetbrains-mono via npm.
    ═══════════════════════════════════════════════════════════════════ */

/* latin */
@font-face {
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-display: swap;
    font-weight: 100 800;
    src: url("../vendor/jetbrains-mono@2.304/jetbrains-mono-latin-wght-normal.b058178d7f30.woff2") format('woff2');
}

/* ═══════════════════════════════════════════════════════════════════
    OPENTYPE FEATURES
    Font family + size now set in SCSS (static/scss/urus-bootstrap.scss).
    These OpenType features are CSS-only, not SASS-configurable.
    ═══════════════════════════════════════════════════════════════════ */
:root {
    /* tabular-nums for fixed-width digits (column alignment in tables). */
    font-variant-numeric: tabular-nums;
}

/* ═══════════════════════════════════════════════════════════════════
    LAYOUT — Column-based flexbox layout
    Body is a horizontal flex container: [sidebar][content-wrapper]
    ═══════════════════════════════════════════════════════════════════ */
:root {
    --sidebar-width: 200px; /* server#291 — the one token; theme.md */

    /* Component tokens */
    --urus-legend-dot-size: 10px;
    --urus-legend-dot-size-lg: 12px;
    --urus-legend-line-width: 12px;
    --urus-legend-panel-width: 200px;

    --urus-thumbnail-xs: 60px;
    --urus-thumbnail-sm: 100px;
    --urus-thumbnail-md: 180px;

    --urus-chart-height: 300px;

    /* The categorical palette — spec ui-grid-convention.md § 11, fourth bullet (D2).
       A CATEGORY (work scope, location, asset type) takes these, dealt by the
       server as an index 1..6 (or none); a STATUS keeps the theme's semantic
       colours. Theme-invariant: no [data-bs-theme=dark] copy, by declaration. */
    --urus-chart-1: #36A2EB;
    --urus-chart-2: #FF6384;
    --urus-chart-3: #4BC0C0;
    --urus-chart-4: #FF9F40;
    --urus-chart-5: #9966FF;
    --urus-chart-6: #FFCD56;
    --urus-chart-none: #C9CBCF;
    --urus-sticky-offset: 1rem;
    --urus-sel-col-width: 2.75rem;
    --urus-map-z-index: 1000;
    --urus-map-inset: 0.5rem;
    --urus-font-size-s: 0.8125rem;
    --urus-font-size-xs: 0.6875rem;

    /* Map layer colors — single source of truth for templates + JS */
    --urus-map-completed: var(--bs-success);
    --urus-map-in-progress: var(--bs-warning);
    --urus-map-overdue: var(--bs-danger);
    --urus-map-approved: var(--bs-primary);
    --urus-map-reported: var(--bs-secondary);
    --urus-map-level-1: var(--bs-info);
    --urus-map-level-2: var(--bs-primary);
    --urus-map-level-2-fill: rgba(var(--bs-primary-rgb), 0.1);
    /* Level 3 and deeper — the picked Location's chain (MP-009, server#358) */
    --urus-map-level-3: var(--bs-warning);
    --urus-map-roads: var(--bs-warning);
}

.urus-sidebar {
    width: var(--sidebar-width);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    background: var(--bs-secondary-bg);
    border-right: 1px solid var(--bs-border-color);
    transition: margin-left 0.3s ease;
}

.urus-content-wrapper {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Mobile: sidebar becomes fixed overlay */
@media (max-width: 991.98px) {
    .urus-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        /* 100dvh accounts for mobile browser URL bar; 100vh fallback for
           engines without dvh support (< Chrome 108 / Firefox 101 / Safari
           15.4). Without this, #sidebar-utilities (bell + profile) clips
           below the address bar on Android Chrome + Firefox. */
        height: 100vh;
        height: 100dvh;
        z-index: 1040;
        transform: translateX(-100%);
    }
    .urus-sidebar.show {
        transform: translateX(0);
    }
    #sidebar-backdrop {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.5);
        z-index: 1035;
        display: none;
    }
    #sidebar-backdrop.show {
        display: block;
    }
}

/* Desktop: collapse via negative margin */
@media (min-width: 992px) {
    .urus-sidebar.collapsed {
        margin-left: calc(-1 * var(--sidebar-width));
    }
}

/* Content area */
.urus-content-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Scrollable region — contains #main + offcanvas */
.urus-content-scroll {
    flex: 1;
    display: flex;
    flex-direction: column;
    position: relative;
    overflow: hidden;
}

/* Offcanvas within scrollable region (native <aside>, Bootstrap-free) */
.urus-offcanvas {
    --bs-offcanvas-padding-x: 1rem;
    --bs-offcanvas-padding-y: 1rem;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 1045;
    width: min(400px, 100vw);
    background-color: var(--bs-secondary-bg);
    color: var(--bs-body-color);
    border-left: 1px solid var(--bs-border-color-translucent);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 0.3s ease-in-out, visibility 0s linear 0.3s;
}

.urus-offcanvas.show {
    transform: translateX(0);
    visibility: visible;
    transition: transform 0.3s ease-in-out, visibility 0s linear 0s;
}

/* A non-painting wrapper: its children lay out as if it were absent (the picker dialogs' lazy loaders, modal.md MD-001) */
.d-contents {
    display: contents;
}

/* Modal uses Secondary surface */
.modal-content {
    --bs-modal-bg: var(--bs-secondary-bg);
}

/* --- Tree Picker --- */

.tree-children {
    margin-left: 0;
}

/* Picker trees (<c-tree-group-row>) indent children by nesting — those rows
   carry no per-row level padding, unlike the catalog tree's <c-sor-heading-row>.
   Scoped to this modifier so the catalog tree stays flat (margin 0) and keeps
   its full-width row borders — the reason .tree-children itself is 0 (fce0df15).
   Picker rows have no border-bottom, so the margin is safe here. */
.tree-children-indent {
    margin-left: 1rem;
}

/* Tree-picker scroll regions. The 70vh cap was written for a FLOATING modal,
   where it stops a long tree from growing past the viewport. Below md the
   modal is fullscreen (see the fullscreen-modal block), so the same cap leaves
   dead space instead — measured 172–340px unused on a 390×844 screen, ~23% of
   the phone. There, the region fills the modal body and that body's own
   height governs. Was two inline styles in cotton/tree_picker.html. */
.tree-picker-scroll {
    max-height: 70vh;
    overflow-y: auto;
}
.tree-picker-split {
    min-height: 400px;
}
@media (max-width: 767.98px) {
    .tree-picker-scroll {
        max-height: none;
        height: 100%;
    }
    .tree-picker-split {
        min-height: 0;
        height: 100%;
    }
}

.tree-item-active {
    background-color: var(--bs-primary-bg-subtle) !important;
}

.tree-item:hover {
    background-color: var(--bs-tertiary-bg);
}

/* SoR tree item rows: Bil.-style code column — right-aligned minimum width so
   1 / 10 / 154 share a right edge and names start at a uniform x (mirrors the
   JKR PDF's Bil. column); color pairs with the heading-row code links. */
.sor-item-code {
    min-width: 2.5rem;
    text-align: right;
}

.tree-detail-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--bs-secondary-color);
}

/* Sidebar utilities bottom bar */
#sidebar-utilities {
    min-height: 57px;
    align-items: center;
}

/* Scrollable areas */
.sidebar-nav-scroll {
    flex: 1;
    overflow-y: auto;
}
#main { overflow-y: auto; }
#subnav { scrollbar-width: none; }
#subnav::-webkit-scrollbar { display: none; }

/* Horizontal layout contract for pages rendered through base_page.html's
   non-full_bleed wrapper: EVERYTHING GETS THE GUTTER — surfaces included.
   Cards and alerts keep the gutter, their radius and their borders at every
   width (the stock Bootstrap look).

   The mobile SURFACE BREAKOUT that used to live here (cards/alerts pulled to
   the screen edge below md via negative --urus-gutter margins, plus the
   nested-surface cancellations, the dialog guards and the #alert-container
   square-edge rules that existed only to serve it) was retired 2026-09-01 —
   server#203, owner-decided. Do not reintroduce any of it; the record is in
   .claude/rules/templates.md § Horizontal layout contract. */
.urus-content-gutter {
    --urus-gutter: 1rem;
    padding-left: var(--urus-gutter);
    padding-right: var(--urus-gutter);
}

@media (max-width: 767.98px) {
    /* Subnav right-edge fade: hints at horizontal scroll when tabs overflow
       the viewport. Template sets d-flex flex-nowrap flex-md-wrap
       overflow-auto — so this block, and the swipe it advertises, is the
       BELOW-md half only: from md up the strip wraps onto a second line and
       nothing scrolls sideways (server#255's ride-along, 21 Sep). This adds
       the visual affordance so the swipe is discoverable. mask-image on
       the subnav itself fades actual tab content regardless of parent
       padding; invisible when no overflow (no content to fade). */
    #subnav {
        mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent 100%);
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent 100%);
    }

    /* Map cards on mobile: 60vh + 400px min-height dominates the iPhone 14
       viewport (664px) with asset/WO metadata pushed below the fold. Shrink
       the large variant so both the map AND the Information card are visible
       without scrolling. */
    .map-container-lg {
        min-height: 240px;
        max-height: 40vh;
    }
}

/* ═══════════════════════════════════════════════════════════════════
   THE FOUR-COLUMN GRID (docs/specs/ui-grid-convention.md, server#262)
   ═══════════════════════════════════════════════════════════════════
   Every page is laid out on ONE grid of four equal columns across the content
   area. A card states its width as `span` (1-4) on <c-card>; an element states
   its own on <c-field> — and a span is measured against the SCREEN, not against
   the card it sits in. The arithmetic happens HERE, never in a template.

   Two inherited custom properties do it, exactly the shape of Bootstrap's own
   `.col-*`:
     --urus-cols   how many columns the CONTAINER has: 4 for a <c-card-row>,
                   the card's own span for a <c-field-grid>.
     --urus-span   this item's width in those columns.
   <c-card>'s wrapper sets --urus-span; <c-field-grid> inherits it and re-states
   it as --urus-cols, so a span-1 field inside a span-3 card is one THIRD of that
   card with nothing passed twice and no page doing arithmetic.

   ⛔ The rows are Bootstrap's own `.row` with Bootstrap gutters — do not zero
   `.row` margins or `.row > *` padding (§ Horizontal layout contract above). */

.urus-col {
    flex: 0 0 auto;
    width: calc(100% * var(--urus-span, 4) / var(--urus-cols, 4));
}

/* Cards sharing a row share a bottom edge — the wrapper is stretched by the
   row, and the card fills it (keeping its own mb-4). */
.urus-card-col {
    display: flex;
    flex-direction: column;
}

.urus-card-col > .card {
    flex: 1 0 auto;
}

/* A card whose content IS one picture — the Operator's logo (owner-ruled
   2026-09-19, server#262): the header stays, and the picture fills the whole
   card body edge to edge. `cover`, centred: it is zoomed, proportions
   untouched, until no side shows empty space, and whatever falls outside the
   body is clipped. Same family as the map-in-a-card treatment
   (.claude/rules/templates.md § Maps in cards) — a single element owns the body,
   so the body's padding goes.

   ⚠ `cover` CROPS, which is only acceptable because the whole mark is one
   click away: the filling element is the lightbox ANCHOR, and clicking it opens
   the picture uncropped (docs/specs/ui-grid-span-tables.md § 12). The two halves
   are ONE ruling — do not keep `cover` here and drop the anchor there.
   ⚠ And the anchor, not the image, must be the body's DIRECT child: the
   `:has(> .urus-card-fill)` selectors below select on exactly that. */
.card-body:has(> .urus-card-fill) {
    position: relative;
    padding: 0;
    min-height: 8rem;
}

/* ⚠ ABSOLUTE, so the picture contributes NO height of its own. In flow it sized
   the body to the image's natural height at the card's width, which made the
   logo the TALLEST card in its row and left a hole under its sibling's fields.
   Out of flow, the row height still comes from the sibling and the picture fills
   whatever box that gives it. `min-height` is the floor for a card standing
   alone (tablet and phone, where the row collapses). */
.urus-card-fill {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* When the filling element is an ANCHOR, the picture inside it fills the
   anchor and takes the crop. `display: block` kills the inline baseline gap
   that would otherwise leave a sliver of card showing along the bottom edge. */
a.urus-card-fill {
    cursor: zoom-in;
    overflow: hidden;
}

.urus-card-fill > img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* The picture reaches the card's bottom corners, so the card must clip them —
   templates.md § Card `overflow-hidden`, applied by rule rather than by a class
   the page would have to remember. */
.card:has(> .card-body > .urus-card-fill) {
    overflow: hidden;
}

/* The FIT sibling — the asset's QR Label card (span-tables § 10.1a, owner-ruled
   2026-09-26, server#262): one picture owns the body edge to edge like the Logo
   card, but it is scaled to FIT, never to cover. A cropped QR does not scan, so
   a body taller or wider than square leaves blank space on two sides instead.
   The inline QR SVG carries a viewBox and no width/height (apps/asset/qr.py),
   so a 100 % × 100 % box scales it on its own (preserveAspectRatio's default is
   `meet`, centred); its white quiet zone is inside the SVG, so the body's
   padding can go. ABSOLUTE for the same reason as the fill: in a row the
   height comes from the card beside it, never from the picture. */
.card-body:has(> .urus-card-fit) {
    position: relative;
    padding: 0;
    min-height: 8rem;
}

.urus-card-fit {
    position: absolute;
    inset: 0;
}

.urus-card-fit > svg,
.urus-card-fit > img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.card:has(> .card-body > .urus-card-fit) {
    overflow: hidden;
}

/* Standing alone (the row collapsed below lg — tablet and phone) the card has
   no neighbour to take a height from, so the floor is a SQUARE as wide as the
   card, not the fill's 8 rem strip: the QR is as big as the screen allows. */
@media (max-width: 991.98px) {
    .card-body:has(> .urus-card-fit) {
        min-height: 0;
        aspect-ratio: 1;
    }
}

/* One <c-field-grid> is ONE ROW, and a card may hold several. Two adjacent
   Bootstrap `.row.g-3` butt together with NO gap, because the row's
   `margin-top: calc(-1 * gutter-y)` cancels its own children's
   `margin-top: gutter-y`. Dropping it on every row after the first leaves the
   children's margin standing as the gap — once, here, so no page writes a
   spacer div. */
.urus-field-grid + .urus-field-grid {
    margin-top: 0;
}

/* <c-strip> — one row of N equal stages inside a card (convention § 6, span
   tables § 13.31): the three dashboard pipelines. N is data and need not divide
   4, so the strip is not on the grid's columns: the stages share the line
   equally and wrap onto more lines when a stage would fall under 8 rem.
   Stations flat, no box (8 Oct 2026, server#262 owner "B"): label above, number
   below on the card itself, so the gap is 1rem to keep two stations from
   reading as one run of text. */
.urus-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.urus-strip > * {
    flex: 1 1 8rem;
    min-width: 0;
}

/* Tablet (md, 768-991px) — the grid keeps its rule and loses columns: 2.
   A span-1 item is half, anything wider is the whole row; inside a card the
   same mapping applies to the card's own column count. Rows stay FULL — an item
   that would end its wrapped row short GROWS to fill it, which is what
   flex-grow does with no per-page class. */
@media (max-width: 991.98px) {
    .urus-col {
        --urus-cols-md: min(var(--urus-cols, 4), 2);
        flex: 1 1 auto;
        width: calc(100% * min(var(--urus-span, 4), var(--urus-cols-md)) / var(--urus-cols-md));
    }
}

/* Phone (below md) — one column; everything is full width and stacks. */
@media (max-width: 767.98px) {
    .urus-col {
        flex: 0 0 auto;
        width: 100%;
    }
}

/* Small utilities */
.urus-avatar { width: 48px; height: 48px; }
.urus-avatar-lg { width: 64px; height: 64px; font-size: 1.25rem; }
.fs-xxs { font-size: 0.7rem; }

/* Detail page key-value tables: label column + row number column */
.detail-label-cell { width: 40%; }
.row-number-cell { width: 60px; }

/* Timeline/history component (user_detail_history) */
.timeline-rail { width: 2rem; }
.timeline-badge { width: 1.75rem; height: 1.75rem; }
.timeline-connector { margin-top: 0.25rem; }

/* Photo comparison preview */
.photo-preview-constrained { max-height: 200px; max-width: 100%; }

/* Map popup content (executive-map, nearby-assets) */
.map-popup { min-width: 150px; }
.map-popup-lg { min-width: 180px; }
.map-popup-title { font-weight: 600; margin-bottom: 0.25rem; }
.map-popup-meta { font-size: var(--urus-font-size-s); color: var(--bs-secondary-color); margin-bottom: 0.25rem; }
.map-popup-meta:last-child { margin-bottom: 0; }
.map-popup-link { display: block; font-size: var(--urus-font-size-s); margin-top: 0.375rem; }

/* Notification badge pulse (SSE updates) */
@keyframes badge-pulse {
    0% { box-shadow: 0 0 0 0 rgba(var(--bs-danger-rgb), 0.7); }
    70% { box-shadow: 0 0 0 6px rgba(var(--bs-danger-rgb), 0); }
    100% { box-shadow: 0 0 0 0 rgba(var(--bs-danger-rgb), 0); }
}
.badge-pulse { animation: badge-pulse 0.6s ease-out; }

/* Legend indicators (executive map) */
.legend-dot {
    display: inline-block;
    width: var(--urus-legend-dot-size);
    height: var(--urus-legend-dot-size);
    padding: 0;
    border-radius: 50%;
}
.legend-dot-lg {
    width: var(--urus-legend-dot-size-lg);
    height: var(--urus-legend-dot-size-lg);
}
.legend-square {
    display: inline-block;
    width: var(--urus-legend-dot-size);
    height: var(--urus-legend-dot-size);
    padding: 0;
    border-radius: 2px;
}
.legend-square-lg {
    width: var(--urus-legend-dot-size-lg);
    height: var(--urus-legend-dot-size-lg);
}
.legend-line {
    display: inline-block;
    width: var(--urus-legend-line-width);
    height: 3px;
    padding: 0;
}

/* Image thumbnails */
.thumbnail-xs {
    width: var(--urus-thumbnail-xs);
    height: var(--urus-thumbnail-xs);
    object-fit: cover;
}
.thumbnail-sm { height: var(--urus-thumbnail-sm); object-fit: cover; }
.thumbnail-md { height: var(--urus-thumbnail-md); object-fit: cover; }

/* Chart.js containers */
.chart-container { height: var(--urus-chart-height); }



/* ═══════════════════════════════════════════════════════════════════
    SIDEBAR NAVIGATION
    ═══════════════════════════════════════════════════════════════════ */
.sidebar-heading {
    font-size: var(--urus-font-size-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--bs-secondary-color);
    padding: 0.75rem 0.75rem 0.25rem;
    margin-top: 1rem;
    margin-bottom: 0;
}
.sidebar-heading:first-child { margin-top: 0; }

/* Match branding height to topbar first row */
#sidebar-brand {
    min-height: 61px;
    display: flex;
    align-items: center;
    background-color: var(--bs-primary);
    border-bottom: 1px solid var(--bs-border-color);
}

/* Sidebar primary nav — left-border active indicator (mirrors subnav underline) */
#sidebar-nav .nav-link {
    color: var(--bs-body-color);
    border-left: 3px solid transparent;
    border-radius: 0;
    padding-left: 0.75rem;
    padding-right: 0.75rem;
}
#sidebar-nav .nav-link.active {
    color: var(--bs-link-color);
    font-weight: 600;
    border-left-color: currentcolor;
}
#sidebar-nav .nav-link:hover:not(.active) {
    background: var(--bs-tertiary-bg);
}

/* Sidebar utilities — pills (notification, profile) */
#sidebar-utilities .nav-link {
    color: var(--bs-body-color);
}
#sidebar-utilities .nav-link.active {
    color: var(--bs-white);
}
#sidebar-utilities .nav-link:hover:not(.active) {
    background: var(--bs-tertiary-bg);
}

/* ═══════════════════════════════════════════════════════════════════
    TOPBAR — Two-row elevated command bar
    Row 1: hamburger + page title + action buttons
    Row 2: subnav tabs (conditional)
    ═══════════════════════════════════════════════════════════════════ */
#topbar {
    background: var(--bs-secondary-bg);
    flex-shrink: 0;
}
#topbar-row1 {
    display: flex;
    align-items: center;
    min-height: 61px;
    border-bottom: 1px solid var(--bs-border-color);
    padding: 0 1rem;
    gap: 0.5rem;
}
#topbar-row1 > h1 {
    min-width: 0; /* Allow flex truncation — text-truncate needs this */
}
#topbar-row2 {
    padding: 0 1rem;
}

/* nav-underline global: primary = selected (matches sidebar convention) */
.nav-underline {
    --bs-nav-underline-link-active-color: var(--bs-link-color);
}
.nav-underline .nav-link {
    color: var(--bs-body-color);
}
.nav-underline .nav-link:hover:not(.active) {
    background: var(--bs-tertiary-bg);
    border-bottom-color: var(--bs-border-color);
}

/* Subnav layout overrides */
#subnav {
    --bs-nav-underline-border-width: 3px;
}
.nav-underline .nav-link {
    padding: 0.75rem 1rem;
}
#subnav .nav-link.active {
    font-weight: 600;
}


/* Table visual hierarchy (inside cards on secondary-bg):
   thead (tertiary-bg) > group header (subtle tint) > body rows (card bg)
   Column headers don't wrap — long headers scroll via .table-responsive. */
.table > thead {
    --bs-table-bg: var(--bs-tertiary-bg);
}
.table > thead th {
    white-space: nowrap;
}
/* List posture (docs/specs/ui-grid-convention.md § 12): every body cell of
   the list table stays on one line — the card scrolls sideways instead. */
#table > tbody > tr > td {
    white-space: nowrap;
}
/* A free-text column (attrs=TEXT_TD) is cut at 10rem; its title holds the whole text (§ 12). */
#table td.urus-cell-text {
    max-width: 10rem;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Table edges (docs/specs/ui-grid-convention.md § 12.1, B10): every list
   table pins its first and last column — inert until the card scrolls. Where
   the first column is the bulk-selection checkbox (.urus-cell-sel, fixed
   width), the identifier beside it pins too. Each pinned cell paints
   --bs-table-bg and a 2px separator on its scroll side; header cells sit one
   z-index above the body. will-change gives each pinned cell its own layer:
   without it a fractional cell edge left a 1px sliver at the card's edge
   where scrolled-under text showed through (measured on dev, 14 Oct). A one-column table (td:first-child is also
   td:last-child) would take the right-edge box-shadow by source order —
   harmless, and no list table has one column. */
#table > thead > tr > th:first-child,
#table > tbody > tr > td:first-child {
    position: sticky;
    left: 0;
    z-index: 3;
    background-color: var(--bs-table-bg);
    box-shadow: 2px 0 0 var(--bs-border-color);
    will-change: transform;
}
#table > thead > tr > th:last-child,
#table > tbody > tr > td:last-child {
    position: sticky;
    right: 0;
    z-index: 3;
    background-color: var(--bs-table-bg);
    box-shadow: -2px 0 0 var(--bs-border-color);
    will-change: transform;
}
/* The checkbox cell hands its separator to the identifier beside it; the
   fully-qualified selectors out-rank the first-child pin above. */
/* The eye column takes no more width than its buttons (§ 12.1). */
#table .urus-cell-action {
    width: 1%;
}
#table .urus-cell-sel,
#table > thead > tr > th.urus-cell-sel,
#table > tbody > tr > td.urus-cell-sel {
    width: var(--urus-sel-col-width);
    min-width: var(--urus-sel-col-width);
    max-width: var(--urus-sel-col-width);
    box-shadow: none;
}
#table > thead > tr > th.urus-cell-sel + th,
#table > tbody > tr > td.urus-cell-sel + td {
    position: sticky;
    left: var(--urus-sel-col-width);
    z-index: 3;
    background-color: var(--bs-table-bg);
    box-shadow: 2px 0 0 var(--bs-border-color);
    will-change: transform;
}
#table > thead > tr > th:first-child,
#table > thead > tr > th:last-child,
#table > thead > tr > th.urus-cell-sel + th {
    z-index: 4;
}
/* Hover: Bootstrap paints a cell as --bs-table-bg plus an inset box-shadow
   state layer; a pinned cell's separator replaces that layer, so re-list both
   — never a translucent background, or scrolled-under text ghosts through. */
#table.table-hover > tbody > tr:hover > td:first-child,
#table.table-hover > tbody > tr:hover > td.urus-cell-sel + td {
    background-color: var(--bs-table-bg);
    box-shadow: inset 0 0 0 9999px var(--bs-table-hover-bg), 2px 0 0 var(--bs-border-color);
}
#table.table-hover > tbody > tr:hover > td:last-child {
    background-color: var(--bs-table-bg);
    box-shadow: inset 0 0 0 9999px var(--bs-table-hover-bg), -2px 0 0 var(--bs-border-color);
}
#table.table-hover > tbody > tr:hover > td.urus-cell-sel {
    box-shadow: inset 0 0 0 9999px var(--bs-table-hover-bg);
}
/* A pinned cell is its own stacking layer, so an open ⋯ menu would draw under
   the next row's pinned cell — lift the cell whose menu is open above them. */
#table > tbody > tr > td:has(.dropdown-menu.show) {
    z-index: 5;
}
/* LT-003 — the filter row (docs/specs/shared/list-toolbar.md § 6.2 item 9):
   the second <thead> row's cells sit on the tertiary tint (werkwyse's thead
   colour) by re-pointing --bs-table-bg, so the pinned first / last cells
   below pick it up too; light and dark both, the token flips. Its first and
   last cells pin with the columns above them. */
#table > thead > tr.urus-filter-row > td {
    --bs-table-bg: var(--bs-tertiary-bg);
    vertical-align: middle;
}
#table > thead > tr.urus-filter-row > td:first-child,
#table > thead > tr.urus-filter-row > td:last-child {
    position: sticky;
    z-index: 4;
    background-color: var(--bs-table-bg);
    will-change: transform;
}
#table > thead > tr.urus-filter-row > td:first-child {
    left: 0;
    box-shadow: 2px 0 0 var(--bs-border-color);
}
#table > thead > tr.urus-filter-row > td:last-child {
    right: 0;
    box-shadow: -2px 0 0 var(--bs-border-color);
}
.urus-filter-row .form-select {
    min-width: 6.5rem;
}
/* LT-003 § 6.5 — a compact <c-tree-select> in a filter-row cell: the control
   takes a standard .form-control's height (the row's boxes), its chosen code
   on one line; a minimum width so "Select..." and the two buttons fit. */
.urus-tree-select-compact {
    min-width: 12rem;
}
.urus-tree-select-compact .form-control {
    min-height: calc(1.5em + 0.75rem + calc(var(--bs-border-width) * 2));
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Group header rows — subtle tint, less prominent than thead.
   Uses emphasis-color-rgb (black in light, white in dark) for auto-adaptation.
   Bootstrap's compile-time .table-secondary doesn't adapt to dark mode
   (Bootstrap issue #39272), so we override for both modes. */
.table-secondary,
.table-light {
    --bs-table-color: var(--bs-body-color);
    --bs-table-bg: rgba(var(--bs-emphasis-color-rgb), 0.06);
    --bs-table-border-color: var(--bs-border-color);
    --bs-table-hover-color: var(--bs-body-color);
    --bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), 0.08);
}

/* Tables in cards: one padding on every cell — 8px top/bottom, 12px
   left/right, no extra on the first or last column (spec
   ui-grid-convention.md § 12.1 spacing; owner's verdict on dev 14 Oct,
   after werkwyse's uniform-padding ruling). The 1rem first/last rule
   that stood here is retired. */
.card .table th,
.card .table td {
    padding: 0.5rem 0.75rem;
}

/* Tables in cards: prevent double bottom border when no card-footer */
.card.overflow-hidden .table-responsive:last-child .table > :last-child > tr:last-child > * {
    border-bottom-width: 0;
}

/* Card header as last visible child: remove bottom border to avoid double-border */
.card.overflow-hidden > .card-header:has(+ .d-none) {
    border-bottom-width: 0;
}

/*
 * Stat-card footers align across a row (docs/specs/dashboard.md §6.4).
 *
 * `h-100` equalises card BOTTOMS, not footers: a one-line definition and a
 * two-line one produce footers of different heights, so the divider rules land
 * at different heights across a row — the reported "box footer not same
 * height". Reserving two lines makes the divider level however each definition
 * wraps. Below `sm` the cards stack, so there is no row to align within and the
 * reservation would only add dead space.
 */
@media (min-width: 576px) {
    .stat-card-footer {
        min-height: calc(2 * 1.5em + 0.5rem);
    }
}

/* Table header — sortable columns use body color, not primary */
#table thead a {
    color: var(--bs-body-color);
}
#table thead a:hover {
    color: var(--bs-body-color);
}

/* ═══════════════════════════════════════════════════════════════════
    HTMX INDICATORS
    ═══════════════════════════════════════════════════════════════════ */
#table-wrapper { position: relative; }
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { display: inline-block; }
.htmx-indicator-overlay {
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(var(--bs-body-bg-rgb), 0.85);
    z-index: 10;
}
.htmx-request .htmx-indicator-overlay {
    display: block;
}
.htmx-indicator-overlay > .htmx-indicator-content {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 0.5rem 1.25rem;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    color: var(--bs-body-color);
    font-weight: 600;
    animation: htmx-indicator-pulse 1.4s ease-in-out infinite;
}
@keyframes htmx-indicator-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.55; }
}

/* ═══════════════════════════════════════════════════════════════════
    GLOBAL HTMX PROGRESS BAR (#htmx-progress)
    A thin top-of-page bar (YouTube/NProgress style) shown during HTMX
    page requests — the consistent "something is happening" feedback that
    makes navigation feel responsive instead of dead-timed. Created and
    driven by initProgressBar() in urus-ui.js (htmx:beforeRequest → trickle,
    htmx:afterRequest → complete + fade), with a ~120ms delay-to-show so
    fast swaps stay flicker-free.

    Replaces the old `.htmx-request #wrapper::before` bar, which only matched
    when the *requesting element* was #wrapper or an ancestor — so sidebar /
    subnav / cross-app (#body) navigation never lit it (the "inconsistent
    loading" complaint). The JS version fires for every navigation regardless
    of which element triggered it.
    ═══════════════════════════════════════════════════════════════════ */
#htmx-progress {
    position: fixed;
    top: 0;
    left: 0;
    width: 0;
    height: 3px;
    /* Orange (not brand teal): the bar overlays the teal sidebar at the top-left,
       so a teal bar would be invisible there. Orange contrasts with both the dark
       teal sidebar and the light content area. One-line knob — swap for
       var(--bs-danger) for a literal YouTube-red, or any --bs-* color. */
    background: var(--bs-orange, #fd7e14);
    box-shadow: 0 0 8px var(--bs-orange, #fd7e14);
    z-index: 9999;
    opacity: 0;
    pointer-events: none;
    transition: width 0.2s ease;
}
#htmx-progress.htmx-progress-active {
    opacity: 1;
}
#htmx-progress.htmx-progress-done {
    opacity: 0;
    transition: width 0.2s ease, opacity 0.3s ease 0.1s;
}

/* Row fade-out for HTMX inline delete (swap:500ms delay) */
tr.htmx-swapping td {
    opacity: 0;
    transition: opacity 500ms ease-out;
}

/* ═══════════════════════════════════════════════════════════════════
    MAPLIBRE THEME SUPPORT
    Uses Bootstrap CSS variables to respect data-bs-theme (dark/light).
    MapLibre's vendor CSS hard-codes white backgrounds; override here.
    ═══════════════════════════════════════════════════════════════════ */

/* Control wrappers (zoom, layers, attribution, custom IControls).
 * overflow: hidden so child buttons clip to the container's border-radius —
 * MapLibre's vendor CSS hard-codes the per-button radius at 4px while
 * Bootstrap's --bs-border-radius is 6px, so without clipping the corners
 * would show a 2px artifact line at top/bottom.
 */
.maplibregl-ctrl-group {
    background-color: var(--bs-body-bg) !important;
    border: 1px solid var(--bs-border-color) !important;
    border-radius: var(--bs-border-radius) !important;
    box-shadow: var(--bs-box-shadow-sm) !important;
    overflow: hidden !important;
}
.maplibregl-ctrl-group button {
    background-color: var(--bs-body-bg) !important;
    color: var(--bs-body-color) !important;
}
.maplibregl-ctrl-group button:hover {
    background-color: var(--bs-secondary-bg) !important;
}
.maplibregl-ctrl-group button + button {
    border-top: 1px solid var(--bs-border-color) !important;
}

/*
 * Control icon contrast in URUS dark mode.
 * MapLibre's vendor CSS swaps the inline-SVG fill via @media (prefers-
 * color-scheme), which follows the OS, not URUS's data-bs-theme. When
 * the OS is light but the app is dark, default-fill #333 icons render
 * invisible on the dark button background. Re-deliver the white-fill
 * SVGs whenever data-bs-theme="dark" so the URUS theme drives the icon.
 */
[data-bs-theme="dark"] .maplibregl-ctrl button.maplibregl-ctrl-zoom-in .maplibregl-ctrl-icon {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='29' height='29' fill='%23fff' viewBox='0 0 29 29'%3E%3Cpath d='M14.5 8.5c-.75 0-1.5.75-1.5 1.5v3h-3c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h3v3c0 .75.75 1.5 1.5 1.5S16 19.75 16 19v-3h3c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13h-3v-3c0-.75-.75-1.5-1.5-1.5'/%3E%3C/svg%3E") !important;
}
[data-bs-theme="dark"] .maplibregl-ctrl button.maplibregl-ctrl-zoom-out .maplibregl-ctrl-icon {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='29' height='29' fill='%23fff' viewBox='0 0 29 29'%3E%3Cpath d='M10 13c-.75 0-1.5.75-1.5 1.5S9.25 16 10 16h9c.75 0 1.5-.75 1.5-1.5S19.75 13 19 13z'/%3E%3C/svg%3E") !important;
}
[data-bs-theme="dark"] .maplibregl-ctrl button.maplibregl-ctrl-fullscreen .maplibregl-ctrl-icon {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='29' height='29' fill='%23fff' viewBox='0 0 29 29'%3E%3Cpath d='M24 16v5.5c0 1.75-.75 2.5-2.5 2.5H16v-1l3-1.5-4-5.5 1-1 5.5 4 1.5-3zM6 16l1.5 3 5.5-4 1 1-4 5.5 3 1.5v1H7.5C5.75 24 5 23.25 5 21.5V16zm7-11v1l-3 1.5 4 5.5-1 1-5.5-4L6 13H5V7.5C5 5.75 5.75 5 7.5 5zm11 2.5c0-1.75-.75-2.5-2.5-2.5H16v1l3 1.5-4 5.5 1 1 5.5-4 1.5 3h1z'/%3E%3C/svg%3E") !important;
}

/* Compact attribution chip — keep visible (zero-CDN attribution requirement) */
.maplibregl-ctrl-attrib {
    background-color: var(--bs-body-bg) !important;
    color: var(--bs-body-color) !important;
    font-size: var(--urus-font-size-s);
}
.maplibregl-ctrl-attrib a {
    color: var(--bs-link-color) !important;
}
.maplibregl-ctrl-attrib-button {
    background-color: var(--bs-body-bg) !important;
}

/* Popups */
.maplibregl-popup-content {
    background-color: var(--bs-body-bg) !important;
    color: var(--bs-body-color) !important;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    box-shadow: var(--bs-box-shadow);
}
.maplibregl-popup-tip {
    border-top-color: var(--bs-body-bg) !important;
    border-bottom-color: var(--bs-body-bg) !important;
}
.maplibregl-popup-close-button {
    color: var(--bs-body-color) !important;
}

/* Map loading overlay */
.map-loading-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--bs-body-bg);
    opacity: 0.9;
    z-index: var(--urus-map-z-index);
    display: flex;
    align-items: center;
    justify-content: center;
}
.map-loading-overlay.d-none {
    display: none !important;
}

/* ═══════════════════════════════════════════════════════════════════
    MAP CONTAINER UTILITIES
    ═══════════════════════════════════════════════════════════════════ */
.map-container {
    height: 50vh;
    min-height: 350px;
    width: 100%;
}
.map-container-lg {
    height: 60vh;
    min-height: 400px;
    width: 100%;
}
.map-container-sm {
    height: 300px;
    width: 100%;
}

/* Map inside card — match card's bottom border-radius to prevent corner clipping */
.card > .map-container:last-child,
.card > .map-container-lg:last-child,
.card > .map-container-sm:last-child {
    border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius);
}

/* ═══════════════════════════════════════════════════════════════════
    EXECUTIVE MAP
    ═══════════════════════════════════════════════════════════════════ */
.executive-map-container {
    position: relative;
}
#executive-map {
    height: 100%;
    width: 100%;
    flex: 1;
}
.legend-panel {
    z-index: var(--urus-map-z-index);
    width: var(--urus-legend-panel-width);
}

.asset-type-options {
    margin-left: 1.5rem;
    padding-left: 0.5rem;
    border-left: 2px solid var(--bs-border-color);
}

/* ═══════════════════════════════════════════════════════════════════
    PHOTO CAPTURE
    ═══════════════════════════════════════════════════════════════════ */
.photo-capture-container {
    border: 2px dashed var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    padding: 1rem;
    text-align: center;
    transition: border-color 0.15s, background-color 0.15s;
}
.photo-capture-container:hover {
    border-color: var(--bs-primary);
    background-color: rgba(var(--bs-primary-rgb), 0.05);
}
.photo-capture-container.drag-over {
    border-color: var(--bs-primary);
    background-color: rgba(var(--bs-primary-rgb), 0.1);
}
.photo-capture-container.has-photos {
    border-style: solid;
}
.photo-capture-buttons {
    display: flex;
    gap: 0.5rem;
    justify-content: center;
    margin-bottom: 0.75rem;
}
.photo-capture-preview {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.75rem;
}
.photo-capture-item {
    position: relative;
    width: 80px;
    height: 80px;
    border-radius: var(--bs-border-radius);
    overflow: hidden;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
}
.photo-capture-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.photo-capture-item .remove-btn {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 20px;
    height: 20px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(var(--bs-danger-rgb), 0.9);
    color: var(--bs-white);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--bs-body-font-size);
    line-height: 1;
}
.photo-capture-item .remove-btn:hover {
    background: var(--bs-danger);
}
.photo-capture-counter {
    font-size: var(--bs-body-font-size);
    color: var(--bs-secondary-color);
    margin-top: 0.5rem;
}
.camera-modal-video {
    width: 100%;
    max-height: 60vh;
    background: var(--bs-black);
    border-radius: var(--bs-border-radius);
}

/* ═══════════════════════════════════════════════════════════════════
    MAP PICKER
    ═══════════════════════════════════════════════════════════════════ */
.map-picker-controls {
    position: absolute;
    top: var(--urus-map-inset);
    right: var(--urus-map-inset);
    z-index: var(--urus-map-z-index);
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.map-picker-btn {
    width: 36px;
    height: 36px;
    background: var(--bs-body-bg);
    border: 2px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-sm);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--bs-box-shadow-sm);
}
.map-picker-btn:hover { background: var(--bs-secondary-bg); }
.map-picker-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.map-picker-btn svg { width: 20px; height: 20px; }
.map-picker-manual-input {
    position: absolute;
    bottom: var(--urus-map-inset);
    left: var(--urus-map-inset);
    right: var(--urus-map-inset);
    z-index: var(--urus-map-z-index);
    background: var(--bs-body-bg);
    border-radius: var(--bs-border-radius-sm);
    padding: 0.75rem;
    box-shadow: var(--bs-box-shadow);
    display: none;
}
.map-picker-manual-input.show { display: block; }
.map-picker-manual-input .row { display: flex; gap: 0.5rem; margin-bottom: 0.5rem; }
.map-picker-manual-input .col { flex: 1; }
.map-picker-manual-input input {
    width: 100%;
    padding: 0.5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-sm);
    font-size: var(--bs-body-font-size);
}
.map-picker-manual-input label {
    display: block;
    font-size: var(--urus-font-size-s);
    color: var(--bs-secondary-color);
    margin-bottom: 0.25rem;
}
.map-picker-manual-input .btn-row {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}
.map-picker-coords {
    position: absolute;
    bottom: var(--urus-map-inset);
    left: var(--urus-map-inset);
    z-index: var(--urus-map-z-index);
    background: var(--bs-body-bg);
    padding: 0.5rem;
    border-radius: var(--bs-border-radius-sm);
    font-size: var(--urus-font-size-s);
    box-shadow: var(--bs-box-shadow-sm);
}

/* ═══════════════════════════════════════════════════════════════════
    WORK ORDER CREATE MAP
    ═══════════════════════════════════════════════════════════════════ */
#wo-map-container { position: relative; height: 600px; }
#wo-map { position: absolute; top: 0; left: 0; right: 0; bottom: 0; }
.map-toolbar { z-index: var(--urus-map-z-index); }
/* The create page's floating coordinates panel is a <c-card> (server#262):
   its width moved here from an inline style, which the card family does not
   pass through; the tighter body padding keeps it a compact overlay; and the
   family's own mb-4 is cancelled because a panel floating on the map has
   nothing below it to space from (the margin only grew the toolbar box over
   the map). */
.manual-input-panel { display: none; width: 280px; margin-bottom: 0 !important; }
.manual-input-panel.show { display: block; }
.manual-input-panel > .card-body { padding: 0.5rem; }
.coords-display { z-index: var(--urus-map-z-index); }
.asset-finder-loading { z-index: var(--urus-map-z-index); }
.asset-finder-map-count { z-index: var(--urus-map-z-index); }

/* server#195 slice 2 — <c-asset-finder layout="split">, the modal host
   (docs/specs/shared/asset-finder.md § 3.1). Both columns share one height,
   sized like the tree picker's split so the two pickers read as one family;
   the list scrolls inside its column, the map fills its column.

   ⚠ Every box in the chain needs a DEFINITE height or the list never scrolls:
   a flex row's cross-axis stretch never shrinks a column below its content,
   and `min-height: 0` only bites under a definite parent. Measured
   2026-08-28: without `height: 100%` on the column, 1,829 rows made the
   column 108,025 px tall, the dialog overflowed the page and MapLibre clamped
   the canvas to 25 × 4096. */
.asset-finder-split { height: 70vh; min-height: 400px; flex-wrap: nowrap; }
.asset-finder-split .asset-finder-results-col { height: 100%; min-height: 0; }
.asset-finder-split .asset-finder-map-wrap { height: 100%; }
.asset-finder-split .asset-finder-results-flush { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.asset-finder-split .asset-finder-scroll { overflow-y: auto; min-height: 0; }
.asset-finder-split .asset-finder-map { position: absolute; inset: 0; }
/* Below md the dialog is fullscreen (modal.md § 4): the two columns stack as a
   real column — results first at up to 40vh, the map takes the rest. */
@media (max-width: 767.98px) {
    .asset-finder[data-layout="split"] { height: 100%; }
    .asset-finder-split { height: 100%; min-height: 0; flex-direction: column; }
    .asset-finder-split .asset-finder-results-col { height: auto; max-height: 40vh; flex: 0 0 auto; }
    .asset-finder-split .asset-finder-map-wrap { height: auto; flex: 1 1 auto; min-height: 240px; }
}
}

/* Date inputs use native <input type="date"> — no JS datepicker library. */

/* ═══════════════════════════════════════════════════════════════════
    GLOBAL SEARCH — topbar search input + results dropdown
    ═══════════════════════════════════════════════════════════════════ */

/* --- Wrapper: positions the icon, spinner, and close button over the input --- */
.global-search-wrapper {
    width: 260px;
}

/* --- Input: padded left for icon, right for spinner --- */
.global-search-input {
    padding-left: 2.25rem !important;
    padding-right: 2rem !important;
    background-color: var(--bs-body-bg) !important;
}
/* Remove the browser-native clear (×) button on type="search" */
.global-search-input::-webkit-search-cancel-button {
    -webkit-appearance: none;
}

/* --- Magnifying glass icon (left) --- */
.global-search-icon {
    position: absolute;
    left: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    pointer-events: none;
    z-index: 4;
}

/* --- HTMX spinner (right) — uses HTMX's native opacity toggle --- */
.global-search-spinner {
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    z-index: 4;
}
.global-search-spinner .spinner-border {
    width: 0.75rem;
    height: 0.75rem;
}

/* --- Mobile close button (right, after spinner position) --- */
.global-search-close {
    position: absolute;
    right: 0.25rem;
    top: 50%;
    transform: translateY(-50%);
    z-index: 4;
    background: none;
    border: none;
    padding: 0.25rem;
    color: var(--bs-secondary-color);
    line-height: 1;
    cursor: pointer;
}
.global-search-close:hover {
    color: var(--bs-body-color);
}

/* --- Results dropdown --- */
.global-search-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin-top: 0.25rem;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    box-shadow: var(--bs-box-shadow-sm);
    max-height: 400px;
    overflow-y: auto;
    z-index: 1050;
    scrollbar-width: thin;
}

/* --- Hybrid select (<c-hybrid-select>, docs/specs/shared/hybrid-select.md) ---
   Closed, the box is Bootstrap's own form-select (HS-001). Open, the panel is
   position:fixed — left, width and top set by hybrid-select.js from the box —
   above pinned table cells (3-4), the kebab (5) and global search (1050). The
   list scrolls inside the panel; its max-height is set by the script (HS-008). */
.hybrid-select {
    position: relative;
}
.hybrid-select-control {
    cursor: pointer;
}
.hybrid-select-panel {
    position: fixed;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    box-shadow: var(--bs-box-shadow-sm);
    z-index: 1060;
    padding: 0.5rem;
}
.hybrid-select-panel input[type="search"] {
    margin-bottom: 0.5rem;
}
.hybrid-select-panel [role="listbox"] {
    overflow-y: auto;
    scrollbar-width: thin;
}
.hybrid-select-panel [role="option"] {
    padding: 0.375rem 0.5rem;
    border-radius: var(--bs-border-radius-sm);
    cursor: pointer;
}
.hybrid-select-panel [role="option"]:hover {
    background: var(--bs-tertiary-bg);
}
.hybrid-select-panel [role="option"].active {
    background: var(--bs-primary-bg-subtle);
}
.hybrid-select-panel [role="listbox"] .disabled {
    padding: 0.375rem 0.5rem;
    color: var(--bs-secondary-color);
    cursor: default;
}
.hybrid-select-count:not(:empty) {
    margin-top: 0.5rem;
}

.global-search-group-header {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 0.5rem 0.75rem 0.25rem;
    color: var(--bs-secondary-color);
    border-bottom: 1px solid var(--bs-border-color-translucent);
}

.global-search-item {
    display: flex;
    flex-direction: column;
    padding: 0.5rem 0.75rem;
    text-decoration: none;
    color: var(--bs-body-color);
    border-bottom: 1px solid var(--bs-border-color-translucent);
}
.global-search-item:last-child {
    border-bottom: none;
}
.global-search-item:hover {
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}

/* Overdue row indicator — subtle left border on work order list rows.
   Uses ::before pseudo-element to avoid shifting cell content (border-left
   adds 3px to the box model, misaligning with the header). */
.table tr.overdue-row > td:first-child {
    position: relative;
}
.table tr.overdue-row > td:first-child::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--bs-danger);
}

/* ── Hierarchy map two-way binding ── */
.hierarchy-row-active {
    background: var(--bs-tertiary-bg);
}
.hierarchy-marker-self {
    background: transparent;
}

/* ═══════════════════════════════════════════════════════════════════
    COLLAPSIBLE CARDS — <details> + <summary>
    Native replacement for Bootstrap Collapse. Used in:
    - workorder/workorder/create.html (#browse-by-location-details)
    - billing/claim/work_records.html (#batch-add-details)
    ═══════════════════════════════════════════════════════════════════ */
details > summary {
    list-style: none;
    cursor: pointer;
}
details > summary::-webkit-details-marker {
    display: none;
}
/* Card-styled <details>: suppress card-header border-bottom when closed */
details.card:not([open]) > summary.card-header {
    border-bottom: 0;
}

/* ═══════════════════════════════════════════════════════════════════
    MODAL DIALOGS — <dialog class="urus-modal">
    Native <dialog> replaces Bootstrap Modal JS (backlog #107 phase 2).
    Outer <dialog> is transparent; Bootstrap's .modal-dialog /
    .modal-content / .modal-header / etc. classes still style the inner
    content. Browser handles focus trap, Escape, and top-layer stacking.

    Bootstrap's .modal-header/.modal-body/.modal-footer read --bs-modal-*
    custom properties that are ONLY defined inside `.modal`. Since we use
    <dialog>, we redeclare the same vars here so the inner padding /
    border / radius render correctly.
    ═══════════════════════════════════════════════════════════════════ */
dialog.urus-modal {
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    max-width: 100vw;
    max-height: 100vh;
    margin: auto;
    overflow: visible;

    --bs-modal-zindex: 1055;
    --bs-modal-width: 500px;
    --bs-modal-padding: 1rem;
    --bs-modal-margin: 0.5rem;
    --bs-modal-color: var(--bs-body-color);
    --bs-modal-bg: var(--bs-body-bg);
    --bs-modal-border-color: var(--bs-border-color-translucent);
    --bs-modal-border-width: var(--bs-border-width);
    --bs-modal-border-radius: var(--bs-border-radius-lg);
    --bs-modal-box-shadow: var(--bs-box-shadow-sm);
    --bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));
    --bs-modal-header-padding-x: 1rem;
    --bs-modal-header-padding-y: 1rem;
    --bs-modal-header-padding: 1rem 1rem;
    --bs-modal-header-border-color: var(--bs-border-color);
    --bs-modal-header-border-width: var(--bs-border-width);
    --bs-modal-title-line-height: 1.5;
    --bs-modal-footer-gap: 0.5rem;
    --bs-modal-footer-bg: ;
    --bs-modal-footer-border-color: var(--bs-border-color);
    --bs-modal-footer-border-width: var(--bs-border-width);
}
/* MD-002 (docs/specs/shared/modal.md § 3, server#194): a native <dialog> is
   width: fit-content, so Bootstrap's max-width-only sizing let every modal
   shrink to its content and grow as rows loaded. Size by class, cap to the
   viewport; .modal-sm/-lg/-xl keep setting --bs-modal-width per breakpoint. */
@media (min-width: 576px) {
    dialog.urus-modal .modal-dialog {
        width: var(--bs-modal-width);
        max-width: calc(100vw - 2 * var(--bs-modal-margin));
    }
}
dialog.urus-modal::backdrop {
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(2px);
}

/* server#70 (docs/specs/shared/modal.md §§ 4.1–4.2). Two rules that were
   mobile-only until 2026-08-30 and now hold at EVERY width, plus a desktop cap.

   5 of the 13 dialogs wrap header/body/footer in a <form> (display:block), so
   Bootstrap's `.modal-body { flex: 1 1 auto }` never fires: the body does not
   grow and the footer floats (fullscreen) or, once the box is capped, the
   block-level wrapper overflows it and the footer is unreachable (desktop).
   `:has(> .modal-body)` rather than `> form`, deliberately — it names the
   INTENT ("whatever wraps the body joins the column"), so a <div>/<fieldset>
   wrapper cannot silently regress the footer, and it does not match a form
   that lives inside the footer or the picker's own .modal-dialog. */
dialog.urus-modal .modal-content > :has(> .modal-body) {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
dialog.urus-modal .modal-body {
    overflow-y: auto;
    min-height: 0;
}
/* Desktop: a modal is never taller than the viewport — the body scrolls,
   header and footer stay pinned. Before this, dialog.urus-modal capped itself
   at 100vh with overflow visible, so bulkCancelModal at 1280×400 put its
   buttons at 394..465 with nothing to scroll (measured 2026-07-31). On the
   shared class, never Bootstrap's per-dialog .modal-dialog-scrollable opt-in. */
@media (min-width: 768px) {
    dialog.urus-modal .modal-content {
        max-height: calc(100vh - 2 * var(--bs-modal-margin));
    }
}

/* Mobile: modals go FULLSCREEN below md. A dialog there is not a card
   floating on the page — it IS the page. (Untouched by server#203's surface
   retirement: the owner's ruling names the surfaces, not the modal.)

   Done here rather than with Bootstrap's per-dialog `.modal-fullscreen-md-down`
   opt-in class: that would need adding to all 12 dialogs and any 13th would
   silently miss it, which is exactly how the nine `px-3 px-md-0` band-aids
   happened. A rule on the shared class cannot drift. */
@media (max-width: 767.98px) {
    dialog.urus-modal {
        width: 100vw;
        max-width: none;
        /* 100vh fallback for engines without dvh, matching .urus-sidebar */
        height: 100vh;
        height: 100dvh;
        max-height: none;
        margin: 0;
    }
    dialog.urus-modal .modal-dialog {
        width: 100%;
        max-width: none;
        height: 100%;
        margin: 0;
    }
    dialog.urus-modal .modal-content {
        height: 100%;
        border: 0;
        border-radius: 0;
    }
    /* The body-wrapper flex rule and the scrolling body used to live here,
       mobile-only; since server#70 they hold at every width (see above).
       The modal-body surface breakout (.modal-body > .card/.alert cancelling
       --bs-modal-padding) also lived here — retired with the page-side
       breakout at server#203, 2026-09-01: a surface inside the body keeps the
       body's padding, exactly as a surface on the page keeps the gutter. */
}

/* ═══════════════════════════════════════════════════════════════════
    INFO TIP — <c-info-tip> metric-definition hover icon (ⓘ).
    Surfaces scorecard / dashboard / report metric definitions inline.
    Slightly smaller than the header text so it reads as an adornment.
    ═══════════════════════════════════════════════════════════════════ */
.urus-info-tip {
    cursor: help;
    font-size: 0.8em;
}

/* ═══════════════════════════════════════════════════════════════════
   Work-order timeline strip — the dashboard legend above Operator queues
   (server#221, docs/specs/dashboard.md §6.5 "The timeline strip").
   An 18-column grid whose columns are the HALF-spans between nine dots:
   stop i occupies columns 2i+1..2i+2, so its dot centres on grid line
   2i+2; a bracket from dot i to dot j spans lines 2i+2 → 2j+2 through the
   .wo-tl-from-N / .wo-tl-to-N classes. Row 1 labels, row 2 the line and
   the dots (overlapping the same cells), rows 3–5 the brackets. Theme
   colours come from Bootstrap's variables; below its minimum width the
   strip scrolls sideways rather than wrapping (nine labels do not fit a
   phone, and a wrapped timeline is not a timeline).
   ═══════════════════════════════════════════════════════════════════ */
.wo-timeline {
    display: grid;
    grid-template-columns: repeat(18, minmax(0, 1fr));
    grid-template-rows: auto 1rem auto auto auto;
    row-gap: 0.4rem;
    min-width: 44rem;
}
.card-body:has(> .wo-timeline) {
    overflow-x: auto;
}
.wo-timeline-label {
    grid-row: 1;
    text-align: center;
    font-size: 0.8125rem;
    color: var(--bs-body-color);
    white-space: nowrap;
}
.wo-timeline-line {
    grid-column: 2 / 18;
    grid-row: 2;
    align-self: center;
    height: 3px;
    background: var(--bs-body-color);
    opacity: 0.6;
}
.wo-timeline-dot {
    grid-row: 2;
    justify-self: center;
    align-self: center;
    position: relative;
    z-index: 1;
    width: 0.9rem;
    height: 0.9rem;
    border-radius: 50%;
    border: 3px solid var(--bs-primary);
    background: var(--bs-body-bg);
}
.wo-timeline-label:nth-child(1), .wo-timeline-dot:nth-child(11) { grid-column: 1 / 3; }
.wo-timeline-label:nth-child(2), .wo-timeline-dot:nth-child(12) { grid-column: 3 / 5; }
.wo-timeline-label:nth-child(3), .wo-timeline-dot:nth-child(13) { grid-column: 5 / 7; }
.wo-timeline-label:nth-child(4), .wo-timeline-dot:nth-child(14) { grid-column: 7 / 9; }
.wo-timeline-label:nth-child(5), .wo-timeline-dot:nth-child(15) { grid-column: 9 / 11; }
.wo-timeline-label:nth-child(6), .wo-timeline-dot:nth-child(16) { grid-column: 11 / 13; }
.wo-timeline-label:nth-child(7), .wo-timeline-dot:nth-child(17) { grid-column: 13 / 15; }
.wo-timeline-label:nth-child(8), .wo-timeline-dot:nth-child(18) { grid-column: 15 / 17; }
.wo-timeline-label:nth-child(9), .wo-timeline-dot:nth-child(19) { grid-column: 17 / 19; }
.wo-timeline-bracket {
    position: relative;
    margin: 0 1px;
    padding-top: 0.3rem;
    border-top: 2px solid var(--bs-secondary-color);
    text-align: center;
    font-size: 0.75rem;
    color: var(--bs-body-color);
    white-space: nowrap;
}
.wo-timeline-bracket::before,
.wo-timeline-bracket::after {
    content: "";
    position: absolute;
    top: -5px;
    width: 2px;
    height: 8px;
    background: var(--bs-secondary-color);
}
.wo-timeline-bracket::before { left: 0; }
.wo-timeline-bracket::after { right: 0; }
.wo-tl-row-1 { grid-row: 3; }
.wo-tl-row-2 { grid-row: 4; }
.wo-tl-row-3 { grid-row: 5; }
.wo-tl-from-0 { grid-column-start: 2; }
.wo-tl-from-1 { grid-column-start: 4; }
.wo-tl-from-2 { grid-column-start: 6; }
.wo-tl-from-3 { grid-column-start: 8; }
.wo-tl-from-4 { grid-column-start: 10; }
.wo-tl-from-5 { grid-column-start: 12; }
.wo-tl-from-6 { grid-column-start: 14; }
.wo-tl-from-7 { grid-column-start: 16; }
.wo-tl-to-1 { grid-column-end: 4; }
.wo-tl-to-2 { grid-column-end: 6; }
.wo-tl-to-3 { grid-column-end: 8; }
.wo-tl-to-4 { grid-column-end: 10; }
.wo-tl-to-5 { grid-column-end: 12; }
.wo-tl-to-6 { grid-column-end: 14; }
.wo-tl-to-7 { grid-column-end: 16; }
.wo-tl-to-8 { grid-column-end: 18; }

/* server#226 — a reveal-under-a-switch with no JavaScript. The first
   `.form-check` inside `.urus-reveal` holds the switch; while it is unticked
   the `.urus-reveal-body` sibling is hidden. Used by the Water card on the
   work-scope form (docs/specs/nrw.md § The work-scope form). */
.urus-reveal:has(> .form-check > input:not(:checked)) > .urus-reveal-body {
    display: none;
}

/* ==========================================================================
   QR label — the label card on the printable sheet
   (docs/specs/entities/asset.md § QR label → § The label card and the
   downloads, server#227 item 3 / server#265). The card is Bootstrap's own
   `.card` with a `.card-header` (type), the QR full width, and a `.card-body`
   (code, name); these rules only size the QR. The QR SVG carries a viewBox
   only, so the container sets its size. The detail page's QR Label card does
   not use these — it fills its card through `.urus-card-fit` above
   (span-tables § 10.1a) — and the A4 PDF carries a stylesheet of its own
   (asset/asset/label_pdf.html).
   ========================================================================== */
.asset-label-qr {
    padding: 1rem;
    background: #fff;
}
.asset-label-qr .urus-qr {
    display: block;
    width: 100%;
    height: auto;
}

.asset-label-sheet {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
    gap: 0.75rem;
}
.asset-label {
    break-inside: avoid;
    page-break-inside: avoid;
}
.asset-label .card-title {
    overflow-wrap: anywhere;
}

/* What prints is the sheet alone: the chrome goes, the grid becomes a fixed
   four-across on A4 with the labels' borders drawn for cutting. */
@media print {
    @page {
        size: A4;
        margin: 10mm;
    }
    #sidebar,
    #sidebar-backdrop,
    #topbar,
    #alert-container,
    .urus-offcanvas,
    main > footer {
        display: none !important;
    }
    /* The app shell is a viewport-high, overflow-hidden flex column (body
       `vh-100 overflow-hidden` → .urus-content-wrapper → -area → -scroll →
       #main), so a printer would get exactly ONE page — the first viewport
       — and nothing else. Measured 2026-09-09: 182 labels printed as 20.
       Every level of the shell becomes a plain block for print. */
    html,
    body,
    .urus-content-wrapper,
    .urus-content-area,
    .urus-content-scroll,
    #main {
        display: block !important;
        overflow: visible !important;
        height: auto !important;
        min-height: 0 !important;
        background: #fff !important;
    }
    .urus-content-gutter {
        padding: 0 !important;
    }
    .asset-label-sheet {
        grid-template-columns: repeat(4, 1fr);
        gap: 4mm;
    }
    .asset-label {
        border: 0.3mm solid #000 !important;
        border-radius: 0 !important;
        color: #000 !important;
        background: #fff !important;
    }
    .asset-label .card-header,
    .asset-label .card-body {
        color: #000 !important;
        background: #fff !important;
    }
    .asset-label .card-header {
        border-bottom: 0.3mm solid #000 !important;
        padding: 1.5mm 3mm;
    }
    .asset-label .card-body {
        padding: 1.5mm 3mm 3mm;
    }
    .asset-label .card-subtitle {
        color: #000 !important;
    }
    /* A4 four-across leaves ~43 mm per label: the QR takes the width inside
       3 mm of padding (~37 mm — its ~37 modules print at ~1 mm each). */
    .asset-label-qr {
        padding: 3mm;
    }
}

/* ═══════════════════════════════════════════════════════════════════
    CATEGORICAL PALETTE — badges and chips (spec ui-grid-convention.md § 11)
    A category's badge (<c-scope-badges>) and its filter chip wear the chart
    colour palette_color names; a status badge never does. Dark text #212529
    on all seven — white fails AA on every one (contrast on server#299).
    ═══════════════════════════════════════════════════════════════════ */
.text-bg-chart-blue { background-color: var(--urus-chart-1); color: #212529; }
.text-bg-chart-red { background-color: var(--urus-chart-2); color: #212529; }
.text-bg-chart-teal { background-color: var(--urus-chart-3); color: #212529; }
.text-bg-chart-orange { background-color: var(--urus-chart-4); color: #212529; }
.text-bg-chart-purple { background-color: var(--urus-chart-5); color: #212529; }
.text-bg-chart-yellow { background-color: var(--urus-chart-6); color: #212529; }
.text-bg-chart-grey { background-color: var(--urus-chart-none); color: #212529; }

.btn-chart-blue,
.btn-outline-chart-blue { --urus-cat: var(--urus-chart-1); }
.btn-chart-red,
.btn-outline-chart-red { --urus-cat: var(--urus-chart-2); }
.btn-chart-teal,
.btn-outline-chart-teal { --urus-cat: var(--urus-chart-3); }
.btn-chart-orange,
.btn-outline-chart-orange { --urus-cat: var(--urus-chart-4); }
.btn-chart-purple,
.btn-outline-chart-purple { --urus-cat: var(--urus-chart-5); }
.btn-chart-yellow,
.btn-outline-chart-yellow { --urus-cat: var(--urus-chart-6); }
.btn-chart-grey,
.btn-outline-chart-grey { --urus-cat: var(--urus-chart-none); }

/* Filled chip: the chosen scope. */
.btn-chart-blue,
.btn-chart-red,
.btn-chart-teal,
.btn-chart-orange,
.btn-chart-purple,
.btn-chart-yellow,
.btn-chart-grey {
    --bs-btn-color: #212529;
    --bs-btn-bg: var(--urus-cat);
    --bs-btn-border-color: var(--urus-cat);
    --bs-btn-hover-color: #212529;
    --bs-btn-hover-bg: var(--urus-cat);
    --bs-btn-hover-border-color: var(--urus-cat);
    --bs-btn-active-color: #212529;
    --bs-btn-active-bg: var(--urus-cat);
    --bs-btn-active-border-color: var(--urus-cat);
    --bs-btn-focus-shadow-rgb: 33, 37, 41;
}

/* Outline chip = the house look for an UNSELECTED category chip (spec ui-grid-convention.md § 11, server#300):
   border in the colour, a dot in the colour before the name (.urus-cat-dot, put in the template),
   the name in the page's body text colour. Hover, .active and :focus-visible fill it. */
.btn-outline-chart-blue,
.btn-outline-chart-red,
.btn-outline-chart-teal,
.btn-outline-chart-orange,
.btn-outline-chart-purple,
.btn-outline-chart-yellow,
.btn-outline-chart-grey {
    --bs-btn-color: var(--bs-body-color);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: var(--urus-cat);
    --bs-btn-hover-color: #212529;
    --bs-btn-hover-bg: var(--urus-cat);
    --bs-btn-hover-border-color: var(--urus-cat);
    --bs-btn-active-color: #212529;
    --bs-btn-active-bg: var(--urus-cat);
    --bs-btn-active-border-color: var(--urus-cat);
    --bs-btn-focus-shadow-rgb: 33, 37, 41;
}

/* The dot of an unselected category chip (server#300). */
.urus-cat-dot {
    display: inline-block;
    width: .6em;
    height: .6em;
    margin-right: .4em;
    border-radius: 50%;
    background: var(--urus-cat);
    vertical-align: middle;
}

/* Nested rows — a location's Assets tab (docs/specs/shared/nested-rows.md,
   server#361). NR-004: the indent is on the Code cell, inside the pinned cell,
   so the pin holds: depth × 1.5rem on top of the card cell's own 0.75rem
   (`.card .table td` above; there is no --urus-cell-pad variable, so the
   literal is repeated here). */
#table > tbody > tr.urus-nr-depth-1 > td:first-child {
    padding-left: calc(1 * 1.5rem + 0.75rem);
}
#table > tbody > tr.urus-nr-depth-2 > td:first-child {
    padding-left: calc(2 * 1.5rem + 0.75rem);
}
#table > tbody > tr.urus-nr-depth-3 > td:first-child {
    padding-left: calc(3 * 1.5rem + 0.75rem);
}
/* The "… N more below" line sits one step deeper than the row it follows. */
#table > tbody > tr.urus-nr-more > td:first-child {
    padding-left: calc(4 * 1.5rem + 0.75rem);
}
/* A nested row is drawn on a lighter ground. Redefining the table's own
   background variable on the cell keeps the pinned cells opaque (they paint
   var(--bs-table-bg)) and leaves the hover tint (an inset box-shadow) intact. */
#table > tbody > tr.urus-nr-child > td,
#table > tbody > tr.urus-nr-more > td {
    --bs-table-bg: var(--bs-tertiary-bg);
}
/* The chevron with its children count, and the grey dot for no children. */
.urus-nr-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 2.25rem;
    margin-right: 0.5rem;
    text-decoration: none;
    color: var(--bs-body-color);
}
.urus-nr-toggle .urus-nr-count {
    font-size: 0.875em;
    color: var(--bs-secondary-color);
}
.urus-nr-dot {
    display: inline-block;
    min-width: 2.25rem;
    margin-right: 0.5rem;
    text-align: center;
    color: var(--bs-secondary-color);
}
