
html, body {
    scroll-behavior: smooth;
}

body {
    --body-font: "Segoe UI Variable", "Segoe UI", sans-serif;
    font-family: var(--body-font);
    font-size: var(--type-ramp-base-font-size);
    line-height: var(--type-ramp-base-line-height);
    margin: 0;
}

.rz-body {
    padding: 0rem !important;
}

.main {
    min-height: calc(100dvh - 50px);
    color: var(--neutral-foreground-rest);
}

.body-content {
    align-self: stretch;
    display: flex;
}

.content {
    padding: 0.5rem 0.8rem 0.5rem 0.5rem;
    align-self: stretch !important;
    width: 100%;
}

.manage {
    width: 100dvw;
}

footer {
    background: var(--neutral-layer-4);
    color: var(--neutral-foreground-rest);
    align-items: center;
    padding: 10px 10px;
}

    footer a {
        color: var(--neutral-foreground-rest);
        text-decoration: none;
    }

        footer a:focus {
            outline: 1px dashed;
            outline-offset: 3px;
        }

        footer a:hover {
            text-decoration: underline;
        }



#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
    margin: 0 0;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.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::before {
        content: "An error has occurred. "
    }

.loading-progress {
    position: relative;
    display: block;
    width: 8rem;
    height: 8rem;
    margin: 20vh auto 1rem auto;
}

    .loading-progress circle {
        fill: none;
        stroke: #e0e0e0;
        stroke-width: 0.6rem;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

        .loading-progress circle:last-child {
            stroke: #1b6ec2;
            stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
            transition: stroke-dasharray 0.05s ease-in-out;
        }

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "Loading");
    }

code {
    color: #c02d76;
}

/* One-time API token display (Account/Manage/ApiTokens). Uses Radzen success theme
   variables (loaded app-wide via RadzenTheme) so the callout stays on-brand and
   readable in both light and dark themes — the previous Fluent message bar inherited
   the dark-theme foreground, which was unreadable on the light-green background. */
.api-token-callout {
    background-color: var(--rz-success-lighter);
    border: 1px solid var(--rz-success-light);
    border-radius: var(--rz-border-radius, 4px);
    padding: 0.75rem 1rem;
    color: var(--rz-success-darker);
}

.api-token-callout-title {
    display: block;
    font-weight: 600;
    margin-bottom: 0.25rem;
}

.api-token-callout p {
    margin: 0 0 0.5rem 0;
    color: var(--rz-success-darker);
}

.api-token-field {
    display: flex;
    gap: 0.5rem;
    align-items: stretch;
}

.api-token-field input {
    flex: 1 1 auto;
    font-family: monospace;
    padding: 0.4rem 0.5rem;
    border: 1px solid var(--rz-success-light);
    border-radius: var(--rz-border-radius, 4px);
    background-color: var(--rz-base-background-color);
    color: var(--rz-text-color);
    cursor: text;
}

.api-token-copy {
    flex: 0 0 auto;
    padding: 0.4rem 0.9rem;
    border: 1px solid var(--rz-success);
    border-radius: var(--rz-border-radius, 4px);
    background-color: var(--rz-success);
    color: var(--rz-on-success);
    cursor: pointer;
    font: inherit;
}

.api-token-copy:hover {
    background-color: var(--rz-success-dark);
    border-color: var(--rz-success-dark);
}

.api-token-copy:focus-visible {
    outline: 2px solid var(--rz-success-dark);
    outline-offset: 2px;
}

.entity-edit-header {
    margin-bottom: 1rem;
}

:root {
    --oc-sidebar-rail-width: 88px;
    --oc-sidebar-open-width: 260px;
    --oc-login-card-background-color: var(--rz-primary-lighter);
}

/* ============================================================================
   Navigation sidebar: SharePoint/Zoho-style rail (RSS-2291)
   ----------------------------------------------------------------------------
   Desktop: a permanent icon-over-label rail. Leaf items navigate on click; items with subitems show a
   corner indicator and fly their subitems out to the right on hover — the rail plus flyouts reach every
   destination, so there is no expand/hide chrome.
   Narrow viewports: the rail is replaced by an off-canvas drawer revealed by the header hamburger.
   The sidebar is fixed-positioned below the header; the content reserves the rail width via a body margin.
   Scoped to .oc-shell so the server-rendered admin/auth pages (a different layout without this wrapper)
   keep Radzen's stock full-width sidebar; the WASM shell and the server shell both opt in via .oc-shell.
   ============================================================================ */

.oc-shell .rz-sidebar {
    position: fixed !important;
    top: var(--rz-header-min-height, 3.125rem);
    bottom: 0;
    left: 0;
    width: var(--oc-sidebar-rail-width) !important;
    overflow-x: hidden;
    overflow-y: auto;
    scrollbar-width: none;
    z-index: 3;
}
.oc-shell .rz-sidebar::-webkit-scrollbar {
    display: none;
}

/* Reserve the rail width for the content. width:auto overrides Radzen's width:100vw (which it applies when
   the sidebar is fixed/out of the grid); with the left margin that 100vw overflowed the viewport on the right. */
.oc-shell .rz-body {
    margin-left: var(--oc-sidebar-rail-width) !important;
    width: auto !important;
}

/* ---------- Icon-over-label tiles + right-side flyout (desktop) ---------- */
/* Desktop-only so the mobile drawer stays a normal full-width list.
   NB: expandable items are detected by :has(> .rz-expander) — this Radzen build does NOT add a
   .rz-navigation-item-expandable class, and ShowArrow="false" means there's no built-in arrow element,
   so the corner indicator is drawn with a ::after triangle.
   Applies at all widths: the static server shell never gets the off-canvas drawer, so it keeps the tile rail
   on narrow screens; the interactive shell hides that same rail behind the hamburger on narrow (see below). */
    /* Open up EVERY clip box between the rail and the tile so the flyout can escape — including the list
       item itself, which the Radzen theme gives overflow:hidden (that was clipping the popup to the tile). */
    .oc-shell .rz-sidebar,
    .oc-shell .rz-sidebar .rz-panel-menu,
    .oc-shell .rz-sidebar .rz-card,
    .oc-shell .rz-sidebar .rz-stack,
    .oc-shell .rz-panel-menu > .rz-navigation-item,
    .oc-shell .rz-panel-menu > .rz-navigation-item > .rz-navigation-item-wrapper {
        overflow: visible !important;
    }
    /* Anchor the flyout to its own tile. */
    .oc-shell .rz-panel-menu > .rz-navigation-item {
        position: relative;
    }

    /* Top-level items become centered icon-over-label tiles. */
    .oc-shell .rz-panel-menu > .rz-navigation-item > .rz-navigation-item-wrapper .rz-navigation-item-link {
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 8px 4px;
        text-align: center;
    }
    .oc-shell .rz-panel-menu > .rz-navigation-item > .rz-navigation-item-wrapper .rz-navigation-item-icon {
        margin: 0;
    }
    .oc-shell .rz-panel-menu > .rz-navigation-item > .rz-navigation-item-wrapper .rz-navigation-item-text {
        opacity: 1;
        font-size: 0.7rem;
        line-height: 1.15;
        white-space: normal;      /* allow two-line labels like "Live Monitor" */
        overflow: hidden;
    }

    /* Corner triangle (bottom-right) marking a tile that has subitems. */
    .oc-shell .rz-panel-menu > .rz-navigation-item:has(> .rz-expander) > .rz-navigation-item-wrapper::after {
        content: "";
        position: absolute;
        bottom: 3px;
        inset-inline-end: 3px;
        border-style: solid;
        border-width: 0 0 8px 8px;
        border-color: transparent transparent currentColor transparent;
        opacity: 0.4;
    }

    /* Keep subitems collapsed inline in the rail (a click on a parent tile must not expand it in place)…
       transition:none avoids the grid-rows animation making the popup feel laggy/sticky when switching tiles. */
    .oc-shell .rz-panel-menu > .rz-navigation-item > .rz-expander {
        grid-template-rows: 0fr;
        transition: none;
    }
    /* …and reveal them as a popup to the right of the hovered tile instead. */
    .oc-shell .rz-panel-menu > .rz-navigation-item:hover > .rz-expander {
        position: absolute;
        inset-inline-start: 100%;
        top: 0;
        min-width: 210px;
        grid-template-rows: 1fr;
        background-color: var(--rz-menu-background-color, #fff);
        box-shadow: var(--rz-context-menu-box-shadow, 0 4px 16px rgba(0, 0, 0, 0.2));
        border-radius: var(--rz-menu-border-radius, 4px);
        z-index: 30;
    }
    .oc-shell .rz-panel-menu > .rz-navigation-item:hover > .rz-expander > .rz-expander-content {
        visibility: visible;
        overflow: visible;
    }
    /* Force the flyout hidden after a subitem click (GlobalFunctions.js adds the class), instead of it
       lingering while the pointer is still over the popup. NOT gated on :hover — that would flip-flop
       (hiding it drops :hover, which would re-show it). Cleared on pointer-leave by the same script. */
    .oc-shell .rz-panel-menu > .rz-navigation-item.oc-flyout-suppressed > .rz-expander {
        display: none !important;
    }
    /* Flyout subitems: reset Radzen's indented 2nd-level accordion styling (negative icon margins, the
       <ul>'s overflow:hidden, wrapper indent offsets) to plain popup-menu items — otherwise the icons get
       pushed to the popup's left edge and clipped. */
    .oc-shell .rz-panel-menu > .rz-navigation-item:hover > .rz-expander .rz-navigation-menu {
        overflow: visible;
        padding: 4px 0;
    }
    .oc-shell .rz-panel-menu > .rz-navigation-item:hover > .rz-expander .rz-navigation-item-wrapper {
        margin: 0;
        overflow: visible;
    }
    .oc-shell .rz-panel-menu > .rz-navigation-item:hover > .rz-expander .rz-navigation-item-link {
        flex-direction: row;
        justify-content: flex-start;
        padding: 8px 16px;
        white-space: nowrap;
    }
    .oc-shell .rz-panel-menu > .rz-navigation-item:hover > .rz-expander .rz-navigation-item-icon {
        width: auto;
        min-width: 1.25rem;
        margin: 0 10px 0 0;
    }

/* The header hamburger is a phone-only reveal: hidden by default (desktop keeps the always-visible rail),
   shown only on narrow viewports while the drawer is closed (see the media query below). */
.oc-mobile-menu-toggle {
    display: none;
}

/* Scrim behind the narrow-viewport drawer — hidden except when the drawer is open. */
.oc-sidebar-scrim {
    display: none;
}

/* Narrow viewports (interactive WASM shell only): hide the rail off-canvas and reveal it with the hamburger.
   The static server shell has no hamburger, so it keeps the rail visible at narrow widths instead. */
@media (max-width: 768px) {
    .oc-shell-interactive .rz-sidebar {
        top: 0;
        transform: translateX(-100%);
        z-index: 25;
        box-shadow: none;
        transition: transform 0.2s ease-in-out;
    }
    .oc-shell-interactive .rz-body {
        margin-left: 0 !important;
    }

    .oc-shell-interactive.oc-sidebar-mobile-open .rz-sidebar {
        transform: translateX(0);
        box-shadow: var(--rz-shadow-4, 2px 0 16px rgba(0, 0, 0, 0.35));
    }
    .oc-shell-interactive.oc-sidebar-mobile-open .oc-sidebar-scrim {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.4);
        z-index: 20;
    }

    /* Hamburger: shown while the drawer is closed (menu hidden), hidden once it's open (close via scrim). */
    .oc-mobile-menu-toggle {
        display: inline-flex;
    }
    .oc-shell-interactive.oc-sidebar-mobile-open .oc-mobile-menu-toggle {
        display: none;
    }
}

.rz-chart-clickable g[role='menuitem'], 
.rz-chart-clickable rect,
.rz-chart-clickable path {
    cursor: pointer !important;
}

.rz-scheduler-clickable .rz-month-view .rz-slot,
.rz-scheduler-clickable .rz-event-content {
    cursor: pointer !important;
}

.settings-menu .rz-navigation-menu {
    left: auto !important;
    right: 0 !important;
}

/* Force light mode for printing regardless of the active Radzen theme.
   Scoped component CSS cannot override :root variables, so these live here. */
@media print {
    :root {
        color-scheme: light !important;
        --rz-base-background-color: #ffffff !important;
        --rz-base-100: #f8f9fa !important;
        --rz-base-200: #e9ecef !important;
        --rz-base-300: #dee2e6 !important;
        --rz-text-color: #212529 !important;
        --rz-text-secondary-color: #6c757d !important;
        --rz-card-background-color: #ffffff !important;
        --rz-body-background-color: #ffffff !important;
    }

    html, body {
        background: white !important;
        color: black !important;
        min-height: 0 !important;
        height: auto !important;
        color-adjust: exact;
        -webkit-print-color-adjust: exact;
    }

    .checklist-item-wrap {
        display: inline-block;
        width: 100%;
        break-inside: avoid;
        page-break-inside: avoid;
    }

    /* Radzen wraps the WASM setup island in a fixed-height, scrolling layout/body. Without this reset the
       printout is clamped to a single viewport (content cut off, no page 2). These are Radzen's own
       (child-component) elements, which a page's scoped CSS can't target — so the reset lives here globally. */
    .rz-layout,
    .rz-body,
    .rz-body-content {
        height: auto !important;
        min-height: 0 !important;
        max-height: none !important;
        overflow: visible !important;
    }

    /* RadzenLayout is a CSS grid with (empty) header/sidebar/footer tracks. In print Firefox fragments those
       empty tracks into a blank first page (Chrome collapses them). Drop to normal block flow so only the
       body content paginates. */
    .rz-layout {
        display: block !important;
        grid-template: none !important;
    }

    /* Hide screen-only chrome in print. `no-print` is applied to Radzen components too (e.g. the setup
       toolbar's My/Role toggle and Print button), which scoped CSS cannot reach — so the canonical hide
       rule is global. */
    .no-print {
        display: none !important;
    }
}

/* ============================================================================
   Board mode — a board page filling the viewport
   ============================================================================
   The pit board and the race boards are broadcast surfaces: read at a distance, by someone holding a physical
   board over a wall. In board mode the board must be the only thing on screen, with no app chrome framing it.

   This used to lean entirely on the Fullscreen API, which put the board in the browser's top layer — outside
   normal flow, so neither the RadzenHeader nor .content's padding applied to it, and ::backdrop painted the
   gaps black. iOS WebKit disables that API in a standalone (home-screen) PWA, where there is no browser chrome
   left for it to hide, so on an iPhone the request no-ops and the board renders as an ordinary in-flow element:
   app header above it, .content's padding showing as a light border on all four sides. So do the framing in
   CSS, which works everywhere, and let the Fullscreen API be a bonus where it is allowed.

   The :has() rule below is load-bearing, not defensive. Radzen sets `transform: translateZ(0)` on
   `.rz-layout .rz-body`, which makes .rz-body BOTH the containing block for fixed-position descendants and a
   stacking context. Left in place, the `position: fixed; inset: 0` below resolves against .rz-body's own box —
   the grid's body area, already below the header and right of the sidebar rail — and the z-index is trapped
   beneath .rz-header's. The overlay would then cover the content area and nothing else, i.e. reproduce exactly
   the bug it exists to fix. Scoped to board mode so every other page keeps Radzen's compositing hint. */
.rz-layout .rz-body:has(.oc-board-fill) {
    transform: none !important;
}

.oc-board-fill {
    position: fixed;
    inset: 0;
    /* Above the app shell's chrome (.rz-header 2, the sidebar rail 3, the narrow-viewport drawer 25 and its
       scrim 20) and deliberately BELOW everything that must still reach the user over the top of a board:
       #blazor-error-ui (1000), Radzen dialogs (1001) and notifications (1002), and Radzen's dropdown popups,
       which it appends to <body> with an inline z-index of 2000 — a board's own selectors are those popups, so
       a higher value here would open them behind the board. */
    z-index: 40;
    overflow-y: auto;
    /* Don't chain the board's scroll to the document behind it — that rubber-bands the page on iOS. */
    overscroll-behavior: contain;
    /* Landscape notch: board mode is edge-to-edge under viewport-fit=cover, and a board's own safe-area
       padding only covers top/bottom. Harmless (resolves to 0) everywhere without insets. */
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
}
