h1:focus {
    outline: none;
}

.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;
}

/* Main-content top offset below the fixed app bar (the bar sits inside an
   AuthorizeView, so MudLayout can't apply it). Live view shrinks all padding
   to 2px to give the video as much screen as possible. */
.main-default {
    padding-top: calc(var(--mud-appbar-height) + 16px);
}

.main-live {
    padding: calc(var(--mud-appbar-height) + 2px) 2px 2px 2px;
}

/* ── Live page ─────────────────────────────────────────────────────────────
   Portrait: compact title row on the page (.live-header), app-bar copy hidden.
   Landscape: title + LIVE move into the app bar (.appbar-live) and the page
   header disappears, giving the video the full height. */
.appbar-live {
    display: none;
}

/* the live main-content padding is only 2px - indent the title a touch */
.live-header {
    padding-left: 6px;
}

@media (orientation: landscape) {
    .appbar-live {
        display: flex;
        align-items: center;
        gap: 8px;
        min-width: 0;
    }

    .appbar-live-title {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .live-header {
        display: none;
    }
}

/* Sized by the stream's aspect ratio (default 16:9, corrected from the real
   video dimensions once frames arrive) so there are no letterbox bars baked
   into the box; max-height stops it overflowing the viewport. */
.live-player {
    position: relative;
    cursor: pointer;
    width: 100%;
    aspect-ratio: 16 / 9;
    max-height: calc(100vh - var(--mud-appbar-height) - 4px);
    background: #000;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    overflow: hidden;
}

@media (orientation: portrait) {
    .live-player {
        max-height: calc(100vh - var(--mud-appbar-height) - 44px);
    }
}

/* Manual record control (RecordMode.Manual): pill with a pulsing red dot,
   the elapsed time and the stop button, sitting next to the fullscreen button. */
.rec-badge {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 4px 2px 12px;
    border-radius: 20px;
    background: rgba(0, 0, 0, .45);
    color: #fff;
}

.rec-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #e53935;
    flex-shrink: 0;
    animation: rec-pulse 1.2s ease-in-out infinite;
}

.rec-elapsed {
    font-size: .8rem;
    font-variant-numeric: tabular-nums;
}

@keyframes rec-pulse {
    0%, 100% {
        opacity: 1;
        transform: scale(1);
    }

    50% {
        opacity: .35;
        transform: scale(.75);
    }
}
/* Per-device capability badges (Devices page "Setup" column + mobile list).
   Tighter than a default small chip so a row of 5 stays compact. */
.vantage-badge.mud-chip {
    height: 19px;
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .02em;
}

/* ── Control room (/control) ──────────────────────────────────────────────
   Three-pane operator workspace: queue | player | incidents. Fills the
   viewport under the app bar (main-default pads 16px top/bottom); each pane
   scrolls its own body. Below Md (960px) the grid stacks vertically. */
.control-grid {
    display: grid;
    grid-template-columns: 340px minmax(0, 1fr) 380px;
    gap: 12px;
    height: calc(100vh - var(--mud-appbar-height) - 32px);
    min-height: 480px;
}

.control-pane {
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 8px;
    background: var(--mud-palette-surface);
    overflow: hidden;
}

.control-pane-header {
    flex-shrink: 0;
    border-bottom: 1px solid var(--mud-palette-lines-default);
}

.control-pane-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

@media (max-width: 959.98px) {
    .control-grid {
        grid-template-columns: 1fr;
        height: auto;
    }

    .control-pane {
        min-height: 280px;
        max-height: 70vh;
    }
}

/* Dark reconnection overlay. Blazor toggles these state classes on #components-reconnect-modal
   when the circuit drops; hidden otherwise. Replaces the framework's default white box. */
#components-reconnect-modal {
    display: none;
}
#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 12000;
    align-items: center;
    justify-content: center;
    background: rgba(10, 11, 14, 0.72);
}
#components-reconnect-modal .reconnect-box {
    background: #1e2128;
    color: #e6e6e6;
    border: 1px solid #2c303a;
    border-radius: 12px;
    padding: 28px 40px;
    text-align: center;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
    font-family: system-ui, "Segoe UI", Roboto, sans-serif;
}
#components-reconnect-modal .reconnect-spinner {
    width: 40px;
    height: 40px;
    margin: 0 auto 14px;
    border: 3px solid #3a3f4b;
    border-top-color: #3b82f6;
    border-radius: 50%;
    animation: vantage-reconnect-spin 0.9s linear infinite;
}
#components-reconnect-modal .reconnect-text {
    margin: 0;
    font-size: 14px;
    color: #c4c8d0;
}
#components-reconnect-modal.components-reconnect-failed .reconnect-text::after {
    content: " connection lost — retrying.";
}
#components-reconnect-modal.components-reconnect-rejected .reconnect-text::after {
    content: " session expired — refreshing.";
}
@keyframes vantage-reconnect-spin {
    to { transform: rotate(360deg); }
}
