/* StravixVMS.Player — player + timeline styles.
   Ported from Stravix-Interview's wwwroot/css/multiview.css (the .camera-player* and
   .recording-timeline* rules), de-MudBlazor'd: every color that used to read a
   --mud-palette-* custom property now reads its own --stravix-player-* or --stravix-timeline-*
   property with the SAME fallback hex, so the package looks identical out of the box and a
   host can re-theme it by setting these on an ancestor — no MudBlazor (or any CSS
   framework) required. Load this stylesheet from the host page:
     <link rel="stylesheet" href="_content/StravixVMS.Player/css/player.css" /> */

/* ── Player ──────────────────────────────────────────────────────────────── */

/* Fills whatever box the host gives it and acts as the query container the fit box sizes
   against. Transparent so the letterbox area shows the host's own background. */
.stravix-player {
    --stravix-player-bar-h: 36px;
    position: relative;
    width: 100%;
    height: 100%;
    container-type: size;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    overflow: hidden;
    font-family: inherit;
}

/* With ShowControls off, no bar is rendered — stop reserving its height so the video fills
   the box (otherwise that strip becomes dead space below the video). */
.stravix-player--no-bar { --stravix-player-bar-h: 0px; }

/* No-bar mode skips the fit-box math entirely: under a percentage-height host chain that
   resolves to auto, 100cqh degrades and the min() collapses to its width branch — the video
   fills the width pinned to the top of the cell. Filling the host box directly lets
   object-fit: contain letterbox symmetrically, with no JS-computed aspect ratio needed. */
.stravix-player--no-bar .stravix-player__fit {
    width: 100%;
    height: 100%;
}

.stravix-player--no-bar .stravix-player__video-wrap {
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
}

/* Bar-less but still fit-sized: the fit box keeps hugging the video's aspect ratio (bar
   height zeroed), so overlays positioned on the video wrap ride on the picture instead of
   floating in the letterbox bars. Needs a host box with a definite height for 100cqh. */
.stravix-player--fit-only { --stravix-player-bar-h: 0px; }

/* The fit box — the largest box of the video's aspect ratio (plus the bar's height) that
   fits the host's box, sized purely in CSS via container-query units. --stravix-player-ar
   (the video's intrinsic width/height) is set by videoPlayer.js on loadedmetadata; it
   defaults to 16:9 until metadata loads. The info bar sits directly below the video with no
   letterbox gap, and the area around the box is transparent. */
.stravix-player__fit {
    display: flex;
    flex-direction: column;
    width: min(100cqw, (100cqh - var(--stravix-player-bar-h)) * var(--stravix-player-ar, 1.7778));
    max-width: 100%;
    max-height: 100%;
}

/* Video area — sized to the video's aspect ratio so object-fit never letterboxes; the
   positioned parent for the overlay so the bar is never obscured. Carries the black ground
   so a tile with nothing loaded yet still reads as a video tile. */
.stravix-player__video-wrap {
    position: relative;
    width: 100%;
    aspect-ratio: var(--stravix-player-ar, 1.7778);
    min-height: 0;
    overflow: hidden;
    background: #000;
}

/* No background of its own, deliberately. The black ground belongs to the wrapper
   above; painting it here as well made the element itself opaque black the instant it lost
   its decoded frame, which is precisely the flash-to-black a stall must not produce. */
.stravix-player__video {
    width: 100%;
    height: 100%;
    object-fit: contain; /* box matches the video aspect, so this never letterboxes */
    display: block;
}

/* Native captions: the browser's default cue size scales with the video element's height and
   gets enormous on a large tile. Only the properties ::cue supports are set here. */
.stravix-player__video::cue {
    font-size: var(--stravix-player-cue-size, 1rem);
    font-family: inherit;
    color: #fff;
    background: rgba(0, 0, 0, 0.6);
}

/* Fullscreen targets the video wrapper (so caption/name/mute overlays ride along). Drop
   the aspect-ratio box and fill the screen; the video letterboxes inside via
   object-fit:contain and the caption stays bottom-centred over it. */
.stravix-player__video-wrap:fullscreen {
    width: 100vw;
    height: 100vh;
    aspect-ratio: auto;
    background: #000;
}

.stravix-player__overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: rgba(0, 0, 0, 0.72);
    color: #ccc;
    text-align: center;
    font-size: 0.8rem;
}

/* Stalled is the one overlay state with something worth seeing underneath it: videoPlayer.js
   recovers a live stream in place rather than tearing the element down, so the last decoded
   frame is still painted. Scrim it only as much as the spinner and label need to stay
   readable — the full 0.72 wash would hide the very frame the recovery exists to keep.
   Error and Offline keep the heavy scrim: there is nothing behind them worth showing, and a
   stale frame must never be mistaken for live video. */
.stravix-player__overlay--stalled {
    background: rgba(0, 0, 0, 0.3);
    color: #eee;
}

.stravix-player__overlay--stalled .stravix-player__overlay-text {
    color: #fff;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}

.stravix-player__overlay-text { color: #ccc; }
.stravix-player__overlay-text--error { color: #f88; max-width: 80%; }
.stravix-player__overlay-text--dim { color: #888; max-width: 80%; }
.stravix-player__overlay-link { color: var(--stravix-player-accent, #7c4dff); font-size: 0.8rem; }
.stravix-player__overlay-link:hover { text-decoration: underline; }

.stravix-player__spinner {
    width: 30px;
    height: 30px;
    border: 3px solid rgba(255, 255, 255, 0.25);
    border-top-color: #fff;
    border-radius: 50%;
    animation: stravix-player-spin 0.8s linear infinite;
}

@keyframes stravix-player-spin {
    to { transform: rotate(360deg); }
}

.stravix-player__hint {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
}

/* Name / mute overlays float on the video itself, independent of the info bar. */
.stravix-player__name-overlay {
    position: absolute;
    top: 6px;
    left: 8px;
    z-index: 4;
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
    pointer-events: none;
    max-width: calc(100% - 16px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ── Tile affordance cluster ──────────────────────────────────────────────── */
/* Controls that float on the video itself rather than living in the info bar, so a host
   running ShowControls=false still gets them. A flex ROW, not a fixed slot: it lays out
   however many affordances the component gives it, so the next one to arrive costs no layout
   work here. Top-right, opposite the name overlay's top-left, and above both the state
   overlay and the caption so a control is never buried by a scrim.

   pointer-events is off on the cluster and back on for each child: the cluster spans a strip
   of the tile, and a host that puts a click-to-focus handler on the tile must keep getting
   those clicks everywhere except on an actual button. */
.stravix-player__affordances {
    position: absolute;
    top: 6px;
    right: 6px;
    z-index: 6;
    display: flex;
    align-items: center;
    gap: 4px;
    pointer-events: none;
}

/* One affordance. Sized for a finger as well as a mouse, and carrying its own scrim, since
   unlike the info-bar icon buttons it sits directly on video that could be any colour. */
.stravix-player__tile-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: rgba(255, 255, 255, 0.92);
    cursor: pointer;
    pointer-events: auto;
    flex: 0 0 auto;
    transition: background-color 0.12s ease;
}

.stravix-player__tile-btn:hover { background: rgba(0, 0, 0, 0.78); }
.stravix-player__tile-btn:disabled { opacity: 0.45; cursor: default; }
.stravix-player__tile-btn svg { width: 17px; height: 17px; display: block; }

/* The "this affordance is currently active" treatment — an unmuted tile on a wall of muted
   ones has to be findable at a glance, because it is the one making noise. */
.stravix-player__tile-btn--on {
    background: var(--stravix-player-accent, #7c4dff);
    color: #fff;
}

.stravix-player__tile-btn--on:hover { background: var(--stravix-player-accent, #7c4dff); filter: brightness(1.15); }

/* Caption overlay — bottom-centred line(s) of text. Decorative: never intercepts clicks, so
   tile controls keep working underneath. Clamps to two lines so a long line can't grow the
   tile. */
.stravix-player__caption {
    position: absolute;
    bottom: 8px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    max-width: calc(100% - 24px);
    padding: 2px 8px;
    background: rgba(0, 0, 0, 0.65);
    color: #fff;
    font-size: 0.8rem;
    line-height: 1.3;
    text-align: center;
    border-radius: 4px;
    pointer-events: none;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* PTZ pad — bottom-right of the video, revealed while the video area is hovered or holds
   focus so it doesn't sit over the picture at rest. Lives inside the video wrapper, so
   fullscreen carries it. 3x3 grid:
   [zoom-][tilt up][zoom+] / [pan left][home][pan right] / [ ][tilt down][ ]. */
.stravix-player__ptz {
    position: absolute;
    right: 8px;
    bottom: 8px;
    z-index: 6;
    display: grid;
    grid-template-columns: repeat(3, 34px);
    gap: 4px;
    opacity: 0;
    pointer-events: none; /* invisible at rest, so a blind tap must not drive the camera */
    transition: opacity 0.15s ease;
}

.stravix-player__video-wrap:hover .stravix-player__ptz,
.stravix-player__ptz:focus-within {
    opacity: 1;
    pointer-events: auto;
}

.stravix-player__ptz-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: rgba(255, 255, 255, 0.85);
    cursor: pointer;
    touch-action: none; /* hold-to-move on touch must not scroll/pan the page */
    user-select: none;
}

.stravix-player__ptz-btn:hover { background: rgba(0, 0, 0, 0.8); }
.stravix-player__ptz-btn:active { background: var(--stravix-player-accent, #7c4dff); }
.stravix-player__ptz-btn svg { width: 20px; height: 20px; display: block; pointer-events: none; }

/* ── Info bar — always-visible strip below the video ──────────────────────── */
/* Accent normally; switches to the recording color while IsRecording is set. */

.stravix-player__info-bar {
    flex: 0 0 var(--stravix-player-bar-h);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 2px 0 8px;
    background: var(--stravix-player-accent, #7c4dff);
    gap: 4px;
    overflow: hidden;
}

.stravix-player__info-bar--recording {
    background: var(--stravix-player-recording, #f44336);
}

/* Border variant (PlayerOptions.RecordingBorder): an inset ring around the whole tile. An
   overlay rather than a box-shadow on the root, because the opaque video wrapper would paint
   over a shadow on its parent. */
.stravix-player--rec-border::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 7;
    box-shadow: inset 0 0 0 3px var(--stravix-player-recording, #f44336);
    pointer-events: none;
}

.stravix-player__bar-left {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
}

.stravix-player__bar-name {
    color: #fff;
    font-size: 0.72rem;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.stravix-player__bar-right {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
}

/* Compact volume slider in the bar next to the mute button. White accent so it's visible
   on the coloured bar. */
.stravix-player__volume {
    width: 72px;
    height: 4px;
    margin: 0 4px;
    accent-color: #fff;
    cursor: pointer;
    flex: 0 0 auto;
}

/* Status dot — white on the coloured bar: dim when not live, bright + glowing when live. */
.stravix-player__status {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.35);
    transition: background 0.3s ease;
}

.stravix-player__status--live {
    background: #fff;
    box-shadow: 0 0 5px rgba(255, 255, 255, 0.8);
}

/* Icon buttons (mute, snapshot, PiP, quality toggle) — plain, framework-free. */
.stravix-player__icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: rgba(255, 255, 255, 0.85);
    cursor: pointer;
    flex: 0 0 auto;
}

.stravix-player__icon-btn:hover { background: rgba(255, 255, 255, 0.15); }
.stravix-player__icon-btn:disabled { opacity: 0.5; cursor: default; }
.stravix-player__icon-btn svg { width: 18px; height: 18px; display: block; }

/* HD/SD quality toggle — text instead of an icon, so the round icon-button shape widens
   to fit two letters. */
.stravix-player__icon-btn--text {
    width: auto;
    min-width: 28px;
    border-radius: 10px;
    padding: 0 6px;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

/* Text buttons (Retry, quality-switch hint, and the overlay's own action). */
.stravix-player__text-btn {
    border: 1px solid rgba(255, 255, 255, 0.4);
    background: transparent;
    color: #fff;
    border-radius: 4px;
    padding: 4px 12px;
    font-size: 0.75rem;
    cursor: pointer;
}

.stravix-player__text-btn:hover { background: rgba(255, 255, 255, 0.12); }

.stravix-player__text-btn--filled {
    background: var(--stravix-player-accent, #7c4dff);
    border-color: transparent;
}

.stravix-player__text-btn--filled:hover { filter: brightness(1.1); }

/* ── Timeline ────────────────────────────────────────────────────────────── */

.stravix-timeline {
    position: relative;
    height: 64px;
    background: rgba(0, 0, 0, 0.85);
    flex-shrink: 0;
    overflow: visible;
    color: #ddd;
    font-size: 11px;
    font-family: inherit;
}

.stravix-timeline__host {
    /* vis-timeline sets `style="position: relative"` inline on the container element it
       owns. Use explicit width/height so the host fills the parent regardless. */
    width: 100%;
    height: 100%;
}

.stravix-timeline__skeleton {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.stravix-timeline__skeleton-events,
.stravix-timeline__skeleton-axis {
    background: rgba(255, 255, 255, 0.08);
    border-radius: 3px;
    animation: stravix-timeline-pulse 1.4s ease-in-out infinite;
}

.stravix-timeline__skeleton-events { flex: 0 0 20px; }
.stravix-timeline__skeleton-axis { flex: 1 1 auto; min-height: 0; }

@keyframes stravix-timeline-pulse {
    0%, 100% { opacity: 0.35; }
    50%      { opacity: 0.7; }
}

/* Off-screen cursor indicator — pinned to the active edge with an arrow and the time. */
.stravix-timeline__cursor-bubble {
    position: absolute;
    top: 4px;
    background: rgba(20, 20, 20, 0.92);
    color: #fff;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 11px;
    line-height: 16px;
    z-index: 5;
    pointer-events: none;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: center;
    gap: 4px;
}

.stravix-timeline__cursor-bubble--left  { left: 4px; }
.stravix-timeline__cursor-bubble--right { right: 4px; }
.stravix-timeline__cursor-arrow         { font-weight: bold; }

/* Floating cursor pill — JS-rendered sibling of the host. */
.stravix-timeline .st-cursor-pill {
    position: absolute;
    top: -10px;
    transform: translateX(-50%);
    background: rgba(20, 20, 20, 0.92);
    color: #fff;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 11px;
    line-height: 16px;
    white-space: nowrap;
    z-index: 6;
    pointer-events: none;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

/* vis-timeline elements are JS-rendered; selectors target classes the lib emits, scoped
   under .stravix-timeline so they don't leak into the host page. */

.stravix-timeline .vis-timeline {
    border: none;
    background: transparent;
    font-family: inherit;
    color: #ddd;
}

.stravix-timeline .vis-panel.vis-top,
.stravix-timeline .vis-panel.vis-bottom,
.stravix-timeline .vis-panel.vis-left,
.stravix-timeline .vis-panel.vis-right,
.stravix-timeline .vis-panel.vis-center {
    border-color: rgba(255, 255, 255, 0.08);
}

.stravix-timeline .vis-time-axis .vis-text {
    color: #bbb;
}

.stravix-timeline .vis-time-axis .vis-grid.vis-minor {
    border-color: rgba(255, 255, 255, 0.06);
}

.stravix-timeline .vis-time-axis .vis-grid.vis-major {
    border-color: rgba(255, 255, 255, 0.12);
}

/* The default full-span (or per-source coverage) item. */
.stravix-timeline .vis-item.vis-range.recording-span {
    background-color: var(--stravix-timeline-coverage, #4caf50);
    border-color: var(--stravix-timeline-coverage-darken, #388e3c);
    border-radius: 2px;
    color: transparent;
    cursor: pointer;
    min-width: 2px;
}

.stravix-timeline .vis-item.vis-range.recording-span:hover {
    background-color: var(--stravix-timeline-coverage-hover, #66bb6a);
}

/* Note point items. vis-timeline renders a point item as a small dot with a label; we hide
   the label and color the dot so a note reads as a pin on the bar. */
.stravix-timeline .vis-item.vis-point.note-mark {
    color: transparent;
    cursor: pointer;
}

.stravix-timeline .vis-item.vis-point.note-mark .vis-dot {
    border-color: var(--stravix-timeline-note, #2196f3);
    border-width: 7px;
    background-color: var(--stravix-timeline-note, #2196f3);
    cursor: pointer;
}

.stravix-timeline .vis-item.vis-point.note-mark:hover .vis-dot {
    border-color: var(--stravix-timeline-note-hover, #64b5f6);
    background-color: var(--stravix-timeline-note-hover, #64b5f6);
}

/* The playback cursor custom-time line. */
.stravix-timeline .vis-custom-time.playback-cursor {
    background-color: var(--stravix-timeline-cursor, #ff9800);
    width: 2px;
    z-index: 4;
}

/* Editable segment ranges. Drawn translucent over the default span so the underlying
   footage block still reads. */
.stravix-timeline .vis-item.vis-range.clip-segment {
    background-color: color-mix(in srgb, var(--stravix-timeline-segment, #9c27b0) 55%, transparent);
    border-color: var(--stravix-timeline-segment, #9c27b0);
    border-radius: 2px;
    color: transparent;
    cursor: grab;
    min-width: 2px;
}

.stravix-timeline .vis-item.vis-range.clip-segment:hover {
    background-color: color-mix(in srgb, var(--stravix-timeline-segment, #9c27b0) 75%, transparent);
}

/* vis-timeline draws drag handles on an editable item's ends. */
.stravix-timeline .vis-item.clip-segment .vis-drag-left,
.stravix-timeline .vis-item.clip-segment .vis-drag-right {
    cursor: ew-resize;
}

/* Image marks — a point in the timeline, click-to-seek like a note. */
.stravix-timeline .vis-item.vis-point.clip-image {
    color: transparent;
    cursor: pointer;
}

.stravix-timeline .vis-item.vis-point.clip-image .vis-dot {
    border-color: var(--stravix-timeline-segment, #9c27b0);
    border-width: 7px;
    background-color: var(--stravix-timeline-segment, #9c27b0);
    cursor: pointer;
}

.stravix-timeline .vis-item.vis-point.clip-image:hover .vis-dot {
    border-color: var(--stravix-timeline-segment-hover, #ba68c8);
    background-color: var(--stravix-timeline-segment-hover, #ba68c8);
}

/* Ghost rectangle drawn while Shift+dragging a new segment onto the timeline. */
.stravix-timeline .st-segment-ghost {
    position: absolute;
    top: 0;
    bottom: 0;
    background: color-mix(in srgb, var(--stravix-timeline-segment, #9c27b0) 30%, transparent);
    border: 1px dashed var(--stravix-timeline-segment, #9c27b0);
    pointer-events: none;
    z-index: 5;
}

/* ── SyncedPlayback ──────────────────────────────────────────────────────── */
/* A grid of .stravix-player fit boxes (bar-less, aspect-fitted) driven off one master clock by
   syncPlayback.js. --stravix-sync-cols is set inline by the component. */

.stravix-sync {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;
    min-height: 0;
}

.stravix-sync__grid {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    gap: 8px;
    grid-template-columns: repeat(var(--stravix-sync-cols, 2), minmax(0, 1fr));
    grid-auto-rows: 1fr;
}

/* The tile is itself the .stravix-player box, so the fit-box centering applies unchanged.
   This layers the card chrome on top: a black backdrop, a hairline outline and the
   drop-shadow video frame. */
.stravix-sync__tile {
    box-sizing: border-box;
    background: #000;
    border-radius: 8px;
    border: 1px solid var(--stravix-sync-line, rgba(148, 163, 184, 0.12));
    box-shadow: 0 10px 36px rgba(0, 0, 0, 0.45);
    min-height: 0;
    transition: opacity 150ms ease, box-shadow 150ms ease, border-color 150ms ease;
    cursor: pointer;
}

/* Selection ring. The component only adds this with more than one tile. */
.stravix-sync__tile--selected {
    border-color: var(--stravix-player-accent, #7c4dff);
    box-shadow: 0 0 0 2px var(--stravix-player-accent, #7c4dff), 0 10px 36px rgba(0, 0, 0, 0.45);
}

/* A tile whose footage doesn't cover the master instant: dimmed, with a label. The class is
   toggled by syncPlayback.js alone, so the drift loop never touches the Blazor circuit. */
.stravix-sync__tile--uncovered {
    opacity: 0.3;
}

.stravix-sync__tile--uncovered::after {
    content: "No footage at this time";
    position: absolute;
    inset: 0;
    z-index: 7;
    pointer-events: none; /* the tile's audio controls stay clickable underneath */
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 0.8rem;
    background: rgba(0, 0, 0, 0.45);
}

/* Audio cluster, top-right over the video: the mute button with the volume slider beside it. */
.stravix-sync__audio {
    position: absolute;
    top: 6px;
    right: 6px;
    z-index: 6;
    display: flex;
    align-items: center;
}

/* Collapsed to nothing and expanded in while the tile is hovered or the control has
   keyboard focus; the mute button beside it stays visible regardless. */
.stravix-sync__volume {
    width: 0;
    height: 4px;
    margin: 0;
    opacity: 0;
    accent-color: #fff;
    cursor: pointer;
    flex: 0 0 auto;
    transition: width 0.18s ease, opacity 0.18s ease, margin 0.18s ease;
}

.stravix-sync__tile:hover .stravix-sync__volume,
.stravix-sync__audio:focus-within .stravix-sync__volume {
    width: 64px;
    opacity: 1;
    margin: 0 6px 0 2px;
}
