/* ========== MEDIA BROWSER STYLES ========== */
/* Separated from base.css for cleaner organization */

/* ========== MEDIA BROWSER TOGGLE BUTTON ========== */
/* 2nd row, above visual mode toggle on bottom-left */
.media-browser-toggle-btn {
    position: fixed;
    bottom: 76px; /* 24px + 40px + 12px gap = second row above visual mode */
    left: 24px;
    z-index: 140;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s ease;
    backdrop-filter: blur(5px);
}

.media-browser-toggle-btn:hover {
    background: rgba(255, 255, 255, 0.2);
    color: white;
    transform: scale(1.05);
}

/* ========== VIDEO STREAM TOGGLE BUTTON ========== */
/* Row 2 — same bottom as media-browser, right of it */
.video-stream-toggle-btn {
    position: fixed;
    bottom: 76px; /* same row as media-browser */
    left: 76px;   /* media-browser width(40) + gap(12) + left(24) */
    z-index: 140;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s ease;
    backdrop-filter: blur(5px);
}

.video-stream-toggle-btn:hover {
    background: rgba(255, 255, 255, 0.2);
    color: white;
    transform: scale(1.05);
}

.video-stream-toggle-btn i {
    font-size: 1.2rem;
}

.video-stream-toggle-btn.active {
    color: white;
    background: rgba(59, 130, 246, 0.15);
    border-color: rgba(59, 130, 246, 0.3);
}

/* Hide in minimal mode */
body[data-minimal="true"] .video-stream-toggle-btn {
    display: none !important;
}

/* Push up when bottom nav is visible */
body:not(.hide-nav) .video-stream-toggle-btn {
    bottom: 108px; /* same as media-browser nav-visible offset */
}

/* ========== HOME ASSISTANT TOGGLE BUTTON ========== */
/* Row 2 — rightmost of the three, same bottom as media-browser and video-stream */
.ha-toggle-btn {
    position: fixed;
    bottom: 76px; /* same row */
    left: 128px;  /* left(24) + btn(40) + gap(12) + btn(40) + gap(12) */
    z-index: 140;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s ease;
    backdrop-filter: blur(5px);
}

.ha-toggle-btn:hover {
    background: rgba(255, 255, 255, 0.2);
    color: white;
    transform: scale(1.05);
}

.ha-toggle-btn i {
    font-size: 1.2rem;
}

/* Active state when modal is open */
.ha-toggle-btn.active {
    color: #18BCEF; /* HA blue */
    background: rgba(24, 188, 239, 0.15);
    border-color: rgba(24, 188, 239, 0.3);
}

/* Hide in minimal mode */
body[data-minimal="true"] .ha-toggle-btn {
    display: none !important;
}

/* Push up when bottom nav is visible */
body:not(.hide-nav) .ha-toggle-btn {
    bottom: 108px;
}

/* Home Assistant icon — MDI home-assistant SVG as mask (same technique as icon-ma) */
.ha-toggle-btn .icon-ha {
    display: inline-block;
    width: 1.2rem;
    height: 1.2rem;
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M21.8 13H20V21H13V17.67L15.79 14.88L16.5 15C17.66 15 18.6 14.06 18.6 12.9C18.6 11.74 17.66 10.8 16.5 10.8A2.1 2.1 0 0 0 14.4 12.9L14.5 13.61L13 15.13V9.65C13.66 9.29 14.1 8.6 14.1 7.8A2.1 2.1 0 0 0 12 5.7A2.1 2.1 0 0 0 9.9 7.8C9.9 8.6 10.34 9.29 11 9.65V15.13L9.5 13.61L9.6 12.9A2.1 2.1 0 0 0 7.5 10.8A2.1 2.1 0 0 0 5.4 12.9A2.1 2.1 0 0 0 7.5 15L8.21 14.88L11 17.67V21H4V13H2.25C1.83 13 1.42 13 1.42 12.79C1.43 12.57 1.85 12.15 2.28 11.72L11 3C11.33 2.67 11.67 2.33 12 2.33C12.33 2.33 12.67 2.67 13 3L17 7V6H19V9L21.78 11.78C22.18 12.18 22.59 12.59 22.6 12.8C22.6 13 22.2 13 21.8 13M7.5 12A0.9 0.9 0 0 1 8.4 12.9A0.9 0.9 0 0 1 7.5 13.8A0.9 0.9 0 0 1 6.6 12.9A0.9 0.9 0 0 1 7.5 12M16.5 12C17 12 17.4 12.4 17.4 12.9C17.4 13.4 17 13.8 16.5 13.8A0.9 0.9 0 0 1 15.6 12.9A0.9 0.9 0 0 1 16.5 12M12 6.9C12.5 6.9 12.9 7.3 12.9 7.8C12.9 8.3 12.5 8.7 12 8.7C11.5 8.7 11.1 8.3 11.1 7.8C11.1 7.3 11.5 6.9 12 6.9Z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M21.8 13H20V21H13V17.67L15.79 14.88L16.5 15C17.66 15 18.6 14.06 18.6 12.9C18.6 11.74 17.66 10.8 16.5 10.8A2.1 2.1 0 0 0 14.4 12.9L14.5 13.61L13 15.13V9.65C13.66 9.29 14.1 8.6 14.1 7.8A2.1 2.1 0 0 0 12 5.7A2.1 2.1 0 0 0 9.9 7.8C9.9 8.6 10.34 9.29 11 9.65V15.13L9.5 13.61L9.6 12.9A2.1 2.1 0 0 0 7.5 10.8A2.1 2.1 0 0 0 5.4 12.9A2.1 2.1 0 0 0 7.5 15L8.21 14.88L11 17.67V21H4V13H2.25C1.83 13 1.42 13 1.42 12.79C1.43 12.57 1.85 12.15 2.28 11.72L11 3C11.33 2.67 11.67 2.33 12 2.33C12.33 2.33 12.67 2.67 13 3L17 7V6H19V9L21.78 11.78C22.18 12.18 22.59 12.59 22.6 12.8C22.6 13 22.2 13 21.8 13M7.5 12A0.9 0.9 0 0 1 8.4 12.9A0.9 0.9 0 0 1 7.5 13.8A0.9 0.9 0 0 1 6.6 12.9A0.9 0.9 0 0 1 7.5 12M16.5 12C17 12 17.4 12.4 17.4 12.9C17.4 13.4 17 13.8 16.5 13.8A0.9 0.9 0 0 1 15.6 12.9A0.9 0.9 0 0 1 16.5 12M12 6.9C12.5 6.9 12.9 7.3 12.9 7.8C12.9 8.3 12.5 8.7 12 8.7C11.5 8.7 11.1 8.3 11.1 7.8C11.1 7.3 11.5 6.9 12 6.9Z'/%3E%3C/svg%3E");
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

/* ========== REAPER DAW TOGGLE BUTTON ========== */
/* Row 2 — rightmost of the four */
.reaper-toggle-btn {
    position: fixed;
    bottom: 76px; /* same row */
    left: 180px;  /* 128 + 40 + 12 */
    z-index: 140;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.7);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s ease;
    backdrop-filter: blur(5px);
}

.reaper-toggle-btn:hover {
    background: rgba(255, 255, 255, 0.2);
    color: white;
    transform: scale(1.05);
}

.reaper-toggle-btn i {
    font-size: 1.2rem;
}

.reaper-toggle-btn.active {
    color: #1db954; /* Spotify Green */
    background: rgba(29, 185, 84, 0.15);
    border-color: rgba(29, 185, 84, 0.3);
}

body[data-minimal="true"] .reaper-toggle-btn {
    display: none !important;
}

body:not(.hide-nav) .reaper-toggle-btn {
    bottom: 108px;
}

/* ========== VIDEO STREAM OVERLAY ========== */
/*
 * A floating full-width panel — NOT a modal.
 * The overlay itself has pointer-events: none so touch/tap events
 * pass through to SyncLyrics lyrics underneath.
 * Only the .vs-controls strip captures pointer events.
 */
.video-stream-overlay {
    position: fixed;
    left: 0;
    width: 100%;
    z-index: 950; /* above player-ui-container (900), below settings (1000) */
    /* top is set dynamically by JS (centerOverlay) after image dimensions are known */
    /* NO transform: — transform creates a GPU compositing layer which breaks */
    /* mix-blend-mode: multiply on children (they blend against the layer, not the page) */
    top: 0;
    background: transparent;
    /* Let touch events fall through to lyrics by default; JS sets pointer-events
     * to 'auto' when unlocked (drag mode) and 'none' when locked (passthrough mode) */
    pointer-events: none;
    /* Prevent browser scroll/pan from claiming touches during drag.
     * Orthogonal to pointer-events — only has effect when overlay actually receives events. */
    touch-action: none;
    transition: opacity 0.5s ease;
}

/* Fullscreen handoff iframe — dark background prevents white flash during initial load.
 * Chromium shows the iframe element's own background before the document's CSS takes over;
 * #000 here matches the streamer's `body { background: #000 }` for a seamless transition. */
#vs-native-iframe {
    background: #000;
}

/* Embedded ReaTabs uses the overlay's box as its viewport. The same iframe is
 * promoted to the native fullscreen handoff for the existing video path. */
#vs-native-iframe.vs-tabs-iframe {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    border: none;
    background: transparent;
}

#vs-native-iframe.vs-tabs-iframe:fullscreen {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    z-index: 9999;
}

/* The shared iframe also serves the video fullscreen handoff after its Tabs
 * class is removed. Keep fullscreen geometry independent of that class. */
#vs-native-iframe:fullscreen {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    z-index: 9999;
}

/* Move/Size ownership layer. An iframe cannot pass a touch back to its
 * parent, so this sibling owns the whole box only in that pointer state. */
.vs-tabs-glass {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: none;
    background: transparent;
    pointer-events: none;
    touch-action: none;
}

.video-stream-overlay.vs-pointer-move .vs-tabs-glass {
    display: block;
    pointer-events: auto;
}

.video-stream-overlay.vs-pointer-interact .vs-tabs-glass,
.video-stream-overlay.vs-pointer-passive .vs-tabs-glass {
    display: none;
    pointer-events: none;
}

.vs-tabs-status {
    position: absolute;
    z-index: 3;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    color: rgba(255, 255, 255, 0.78);
    text-align: center;
    font-size: 0.95rem;
    pointer-events: none;
}

.vs-tabs-status.hidden {
    display: none;
}

.video-stream-overlay.hidden,
#vs-native-iframe.hidden {
    display: none !important;
    pointer-events: none !important;
}

/* Standby mode: mathematically identical hidden state but using opacity for smooth fading */
.video-stream-overlay.vs-standby,
.vs-controls.vs-standby,
.vs-edit-bar.vs-standby,
#vs-native-iframe.vs-standby {
    opacity: 0 !important;
    pointer-events: none !important;
}

/* In Tabs Interact mode ReaTabs owns its own chrome. Keep only the pointer
 * cycle button reachable so the user can return to our controls. */
.vs-controls.vs-interact-hidden {
    visibility: hidden;
    pointer-events: none !important;
}

.vs-edit-bar.vs-interact-hidden > *:not(#vs-lock-btn) {
    visibility: hidden;
    pointer-events: none !important;
}

.vs-edit-bar.vs-interact-hidden {
    opacity: 1 !important;
}

.vs-edit-bar.vs-interact-hidden #vs-lock-btn {
    visibility: visible;
    pointer-events: auto;
}

/* Partial standby for the edit bar: most controls fade to invisible, but the mode toggle
 * stays faintly visible and interactable so the user can always switch modes.
 *
 * Why this approach: CSS opacity is multiplicative — setting opacity: 0 on a parent makes
 * all children invisible regardless of their own opacity. So we skip the full .vs-standby
 * class on editBar and use this partial class instead, targeting children individually.
 *
 * pointer-events: auto on a child of pointer-events: none parent IS valid per CSS spec. */
.vs-edit-bar.vs-standby-partial {
    pointer-events: none; /* bar background doesn't intercept touches */
    /* Note: do NOT reposition the bar here — invisible flex siblings would push
     * #vs-mode-toggle to an unpredictable offset. Instead we fix #vs-mode-toggle
     * directly (see rule below) to break it out of the flex layout entirely. */
}
.vs-edit-bar.vs-standby-partial > *:not(#vs-mode-toggle):not(#vs-lock-btn) {
    opacity: 0 !important;
    pointer-events: none !important;
}
.vs-edit-bar.vs-standby-partial #vs-mode-toggle {
    /* Break out of edit bar's flex flow so invisible siblings don't push us off */
    position: fixed !important;
    bottom: 124px !important; /* above video-stream-toggle-btn (76px + 40px height + 8px gap) */
    left: 24px !important;    /* aligned with video-stream-toggle-btn */
    top: auto !important;     /* override the JS-set style.top on the parent */
    z-index: 145 !important;  /* above media browser (z-index: 140) */
    opacity: 0.08;            /* barely visible, hinted at rather than shown */
    pointer-events: auto;     /* stays interactable — escape hatch to switch modes */
}
.vs-edit-bar.vs-standby-partial #vs-mode-toggle .vs-control-btn {
    pointer-events: auto;                          /* buttons inside also receive clicks/taps */
    /* Match the aesthetic of .media-browser-toggle-btn / .video-stream-toggle-btn */
    width: 40px;
    height: 40px;
    background: rgba(255, 255, 255, 0.1);         /* white-tinted, not black */
    border: 1px solid rgba(255, 255, 255, 0.1);   /* subtle, matches sibling buttons */
    backdrop-filter: blur(5px);
    -webkit-backdrop-filter: blur(5px);
    box-shadow: none;                              /* remove the glow from .active state */
}

.vs-edit-bar.vs-standby-partial #vs-lock-btn {
    position: fixed !important;
    bottom: 124px !important;
    left: 150px !important;
    top: auto !important;
    z-index: 145 !important;
    opacity: 0.08;
    pointer-events: auto;
    width: 40px;
    height: 40px;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(5px);
    -webkit-backdrop-filter: blur(5px);
    box-shadow: none;
}

/* The MJPEG image — full width, auto height (= exact video frame dimensions) */
.vs-img {
    display: block;
    width: 100%;
    height: auto;
    pointer-events: none;
}

/* The HTML5 video element — full width, auto height (same as img) */
.vs-video {
    display: block;
    width: 100%;
    height: auto;
    /* aspect-ratio: 16 / 9; */
    /* NOTE (2026-04-13): Commented out — this was intended as a placeholder to prevent
     * the overlay collapsing to 0px before a video src is set in Direct mode.
     * However it forces the element box to exactly 16:9 regardless of the video's actual
     * encoded dimensions. When the video is not 16:9 the element box is taller than the
     * visual content, creating invisible extra space that throws off crop handles and
     * prevents dragging to the bottom of the screen. Testing without it. */
    transition: opacity 0.3s ease; /* smooth fade on file-change (opacity controlled by JS) */
    pointer-events: none;
}

/*
 * CSS blend modes for Guitar Pro transparency.
 * All CSS-only — streams /stream JPEG, zero server overhead.
 *
 * IMPORTANT: blend mode is applied to the overlay div itself, NOT to .vs-img.
 * Reason: position:fixed creates a new stacking context. A child element's
 * mix-blend-mode blends within that isolated context (transparent background)
 * rather than with the page below — producing no visible effect.
 * By applying mix-blend-mode to the fixed overlay itself, it blends against
 * the viewport stacking context (album art, lyrics, etc.) as intended.
 * Source: CSS Compositing spec + SO #33223603 (score 37).
 *
 * Multiply:      white paper → transparent, black notation stays.
 *                Works best on light album art backgrounds.
 * Screen+Invert: filter:invert(1) on the img flips colours, then overlay's
 *                screen blend removes the black (ex-white paper). Notation
 *                becomes white, visible on any background colour.
 *
 * Invert is applied to .vs-img (not the overlay) so all pixel manipulation
 * lives on the img and controls render normally without counter-invert hacks.
 * This also lets boost filters chain naturally: invert(1) contrast() brightness().
 */
.video-stream-overlay.vs-multiply {
    mix-blend-mode: multiply;
}

.video-stream-overlay.vs-screen {
    mix-blend-mode: screen;
}

/* ── Image pixel filters (pre-process before blend) ── */

/* All filters (invert for screen mode, contrast, brightness, saturation)
 * are applied via inline img.style.filter by JS computeFilter().
 * This allows continuous slider values and mode-specific filter chains:
 *   Screen:   saturate(s) invert(1) contrast(c) brightness(b)
 *   Multiply: saturate(s) contrast(c) brightness(b)
 * Per-mode values persisted as JSON in localStorage. */

/* Trim thin window-chrome borders that become visible after blend removes paper.
 * Bottom edge is thicker (scrollbar/status bar area). Order: top right bottom left. */
.video-stream-overlay.vs-multiply .vs-img,
.video-stream-overlay.vs-multiply .vs-video,
.video-stream-overlay.vs-screen .vs-img,
.video-stream-overlay.vs-screen .vs-video {
    clip-path: inset(3px 3px 6px 3px);
}

/* Control strip — sibling div positioned at overlay's top-right.
 * Extracted from inside the overlay so blend modes don't affect buttons.
 * JS syncs position to match overlay's top-right corner. */
.vs-controls {
    position: fixed;
    right: 10px;
    z-index: 960; /* above overlay (950) */
    display: flex;
    gap: 10px;
    pointer-events: auto;
    opacity: 1;
    transition: opacity 0.5s ease;
}

/* Auto-fade: after idle timeout JS adds this class */
.vs-controls.faded {
    opacity: 0.04;
}

.vs-controls.hidden {
    display: none;
}

.vs-control-btn {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.65);
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.85rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s ease;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    pointer-events: auto;
}

.vs-control-btn:hover {
    background: rgba(0, 0, 0, 0.75);
    color: white;
    border-color: rgba(255, 255, 255, 0.3);
}

/* Explicit :active prevents the brief invisible-icon flash on touch
   that occurs when no :active rule exists and the browser applies its own highlight. */
.vs-control-btn:active {
    background: rgba(0, 0, 0, 0.95);
    color: white;
    border-color: rgba(255, 255, 255, 0.45);
    transition: none; /* instant — no fade on press */
}

.vs-control-btn.vs-close:hover {
    background: rgba(239, 68, 68, 0.35);
    border-color: rgba(239, 68, 68, 0.5);
    color: #f87171;
}

/* Unified active state — high opacity black for maximum visibility on all backgrounds */
.vs-control-btn.active,
.vs-control-btn.vs-locked {
    color: white;
    background: rgba(0, 0, 0, 0.85);
    border-color: rgba(255, 255, 255, 0.5);
    box-shadow: 0 0 8px rgba(255, 255, 255, 0.15);
}

/* Edit bar — top-left sibling, mirrors vs-controls positioning */
.vs-edit-bar {
    position: fixed;
    left: 10px;
    z-index: 960;
    display: flex;
    gap: 10px;
    pointer-events: auto;
    opacity: 1;
    transition: opacity 0.5s ease;
}

.vs-edit-bar.faded {
    opacity: 0.04;
}

.vs-edit-bar.hidden {
    display: none;
}

/* Crop Presets Pill Bar */
.vs-crop-presets {
    display: flex;
    gap: 8px;
    align-items: center;
    border-left: 0px solid rgba(255, 255, 255, 0.0);
    padding-left: 0px;
    margin-left: 0px;
}

.vs-crop-preset-btn {
    font-size: 14px;
    font-weight: 600;
    font-family: inherit;
    padding: 0 12px;
}

/* Mode Toggle (Stream vs Direct video) — plain flex wrapper, no separator */
.vs-mode-toggle {
    display: flex;
    gap: 10px; /* match .vs-edit-bar gap */
    align-items: center;
}

/* Latency compensation buttons */
.vs-latency-btn {
    width: 32px;
    height: 28px;
    background: rgba(255, 255, 255, 0.08);
    color: rgba(255, 255, 255, 0.7);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 4px;
    font-size: 14px;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    touch-action: manipulation;
    transition: background 0.15s, color 0.15s;
}

.vs-latency-btn:hover {
    background: rgba(255, 255, 255, 0.15);
    color: white;
}

.vs-latency-btn:active {
    background: rgba(255, 255, 255, 0.25);
}

/* Overlay dragging cursor — applied to body during drag so cursor stays correct */
body.vs-dragging {
    cursor: grabbing !important;
    user-select: none;
}

/* ── Crop handles ─────────────────────────────────────────────────────────── */
/* Positioning wrapper only — pointer-events off so it doesn't block buttons.
 * Only the center pill indicator captures touch/drag. */
.vs-crop-handle {
    position: fixed;
    left: 0;
    width: 100%;
    height: 44px;                          /* tall wrapper for centering */
    z-index: 961;                          /* above controls bar */
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;                  /* wrapper is NOT interactive */
    touch-action: none;
}

.vs-crop-handle.hidden {
    display: none;
}

/* The pill is the ONLY draggable target */
.vs-crop-handle-indicator {
    position: relative;
    width: 80px;
    height: 8px;                          /* tall enough for comfortable touch */
    background: rgba(251, 146, 60, 0.85);  /* orange */
    border-radius: 16px;
    box-shadow: 0 0 10px rgba(251, 146, 60, 0.5);
    pointer-events: auto;                  /* ← only the pill is interactive */
    cursor: ns-resize;
    touch-action: none;
    transition: background 0.15s, box-shadow 0.15s;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Invisible fat touch target for easier grabbing */
.vs-crop-handle-indicator::after {
    content: '';
    position: absolute;
    top: -28px;
    bottom: -28px;
    left: -24px;
    right: -24px;
}

/* Hairline track across full width — purely visual, not interactive */
.vs-crop-handle::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    height: 2px;
    background: rgba(251, 146, 60, 0.3);
    pointer-events: none;
}

.vs-crop-handle.dragging .vs-crop-handle-indicator {
    background: rgba(251, 146, 60, 1);
    box-shadow: 0 0 16px rgba(251, 146, 60, 0.8);
}

/* Modifiers for horizontal side handles */
.vs-crop-handle.horizontal {
    top: 0;
    left: auto;
    width: 44px;
    height: 100%;
    flex-direction: column;
}

.vs-crop-handle.horizontal .vs-crop-handle-indicator {
    width: 8px;
    height: 80px;
    cursor: ew-resize;
}

.vs-crop-handle.horizontal::before {
    top: 0;
    bottom: 0;
    left: 21px; /* perfectly center hairline within 44px wrapper */
    right: auto;
    width: 2px;
    height: 100%;
}

/* ── Lyrics Focus Mode (REAPER video overlay only) ──────────────────────────── */
/* Classes toggled on #lyrics by videostream.js. Resets to 'full' on overlay close. */

/* Smooth transition anchors for Video UI Restoration */
#lyrics {
    transition: margin-top 0.3s ease !important;
}

body .background-layer,
body .background-overlay {
    transition: background-image 0.5s ease-in-out, backdrop-filter 0.3s ease, -webkit-backdrop-filter 0.3s ease, background 0.3s ease, filter 0.3s ease !important;
}

/* Supply explicit metrics so the GPU can smoothly interpolate the vertical collapse instead of snapping */
#lyrics .lyric-line {
    max-height: 500px; 
}

/* Focused & Solo Modes: Smooth collapse instead of display:none snapping */
#lyrics.vs-lyric-focused .far-previous,
#lyrics.vs-lyric-focused .far-next,
#lyrics.vs-lyric-solo .far-previous,
#lyrics.vs-lyric-solo .previous,
#lyrics.vs-lyric-solo .next,
#lyrics.vs-lyric-solo .far-next {
    opacity: 0;
    max-height: 0;
    margin-top: 0;
    margin-bottom: 0;
    padding-top: 0;
    padding-bottom: 0;
    overflow: hidden;
    pointer-events: none;
}

/* ── Lyrics Lines mode toggle buttons (All / 3 / 1) ────────────────────────── */
/* Separate class from vs-zindex-btn — these need to fill available row space. */
.vs-lyrics-mode-btns {
    display: flex;
    flex: 1;
    gap: 4px;
    min-width: 0;
}

/* Scoped to slider popup only — prevents conflict with .vs-mode-btn on edit-bar buttons */
.vs-slider-popup .vs-mode-btn {
    flex: 1;
    height: 26px;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.7);
    font-size: 0.78rem;
    font-weight: 500;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.vs-slider-popup .vs-mode-btn:hover {
    background: rgba(255, 255, 255, 0.16);
    color: white;
}

.vs-slider-popup .vs-mode-btn.active {
    background: rgba(59, 130, 246, 0.25);
    border-color: rgba(59, 130, 246, 0.5);
    color: #93c5fd;
}

/* ── Background blur override (REAPER video overlay only) ───────────────────── */
/* When video overlay is open, body.vs-overlay-active is added by videostream.js.
 * The --vs-blur-override CSS var is set to the user's chosen blur level.
 * This selector is more specific than body.sharp-mode / body.soft-mode rules
 * so it wins without disrupting any existing mode state. On overlay close,
 * the class is removed and the background-overlay reverts to the current mode. */
/* 1. Default (Blur) Mode: Natively 180% saturation */
body.vs-overlay-active #background-overlay {
    backdrop-filter: blur(var(--vs-blur-override, 15px)) saturate(180%) !important;
    -webkit-backdrop-filter: blur(var(--vs-blur-override, 15px)) saturate(180%) !important;
}

/* 2. Soft Mode: Natively 140% saturation */
body.vs-overlay-active.soft-mode #background-overlay {
    backdrop-filter: blur(var(--vs-blur-override, 15px)) saturate(140%) !important;
    -webkit-backdrop-filter: blur(var(--vs-blur-override, 15px)) saturate(140%) !important;
}

/* 3. Sharp Mode: Natively 130% saturation */
body.vs-overlay-active.sharp-mode #background-overlay {
    backdrop-filter: blur(var(--vs-blur-override, 15px)) saturate(130%) !important;
    -webkit-backdrop-filter: blur(var(--vs-blur-override, 15px)) saturate(130%) !important;
    
    /* Preserve Sharp Mode's ultra-transparent mask (3% black) to let sharp art shine */
    background: rgba(0, 0, 0, 0.03) !important;
}

/* ── OVERRIDE MODE (Ultimate Sandbox Control) ────────────────────────── */
/* Zero out the underlying album art layer completely */
body.vs-overlay-active.vs-override-mode #background-layer {
    filter: blur(0px) !important;
    transform: none !important;
}

/* Master override using the math injected from the slider (calculated in videostream.js) */
body.vs-overlay-active.vs-override-mode #background-overlay {
    backdrop-filter: blur(var(--vs-blur-override, 15px)) saturate(var(--vs-computed-saturate, 160%)) !important;
    -webkit-backdrop-filter: blur(var(--vs-blur-override, 15px)) saturate(var(--vs-computed-saturate, 160%)) !important;
    background: rgba(0, 0, 0, var(--vs-computed-opacity, 0.4)) !important;
}

/* ========== VIDEO STREAM SLIDER POPUP ========== */
/* Floating panel for fine-tuning boost + opacity. Positioned as a sibling
 * to the overlay (not inside it) so blend modes don't affect it. */
.vs-slider-popup {
    position: fixed;
    top: 40px;
    right: 12px;
    min-width: 240px;
    background: rgba(26, 27, 38, 0.95);
    backdrop-filter: blur(15px);
    -webkit-backdrop-filter: blur(15px);
    padding: 12px 16px;
    border-radius: 14px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
    z-index: 550; /* above overlay (500), below player-ui (900) */
    transition: opacity 0.2s ease, visibility 0.2s ease;
    pointer-events: auto;
}

.vs-slider-popup.hidden {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

.vs-slider-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 0;
}

.vs-slider-label {
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.7);
    min-width: 70px;
    display: flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.vs-slider {
    flex: 1;
    height: 6px;
    -webkit-appearance: none;
    appearance: none;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 3px;
    outline: none;
    cursor: pointer;
}

.vs-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    background: white;
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
}

.vs-slider::-moz-range-thumb {
    width: 16px;
    height: 16px;
    background: white;
    border-radius: 50%;
    border: none;
    cursor: pointer;
    box-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
}

.vs-slider-value {
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.55);
    min-width: 32px;
    text-align: right;
}

/* (Boost-active removed — all active buttons now use unified .active class) */

/* Z-Index stepper row in slider popup */
.vs-zindex-row {
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    margin-top: 4px;
    padding-top: 8px;
}

.vs-zindex-btn {
    width: 24px;
    height: 24px;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: white;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: background 0.15s ease;
}

.vs-zindex-btn:hover {
    background: rgba(255, 255, 255, 0.2);
}

.vs-zindex-val {
    min-width: 36px;
    text-align: center;
}

/* ── Fullscreen ── */
/* When the overlay is fullscreened, show it as a centered black stage */
.video-stream-overlay:fullscreen,
.video-stream-overlay:-webkit-full-screen {
    background: #000;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    top: 0 !important; /* override JS-set top */
    transform: none;
    pointer-events: auto;
    /* Reset blend mode + filters — blending against a fullscreen black bg
     * makes everything black (multiply) or broken (screen). */
    mix-blend-mode: normal !important;
    filter: none !important;
}

.video-stream-overlay:fullscreen .vs-img,
.video-stream-overlay:-webkit-full-screen .vs-img {
    width: auto;
    height: 100vh;
    max-width: 100vw;
    object-fit: contain;
    pointer-events: none;
    /* Reset img-level filters and clip: blending is already disabled on the
     * overlay, so invert+clip applied in blend mode must not persist here. */
    filter: none !important;
    clip-path: none !important;
}

/* Controls bar is already position:fixed as a sibling — in fullscreen,
 * JS keeps it visible and positioned at the top-right of the fullscreen overlay. */

/* Icon sizing */
.media-browser-toggle-btn i {
    font-size: 1.2rem;
}

/* Custom Music Assistant icon (using SVG mask for color inheritance) */
.media-browser-toggle-btn .icon-ma {
    display: inline-block;
    width: 1.2rem;
    height: 1.2rem;
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='100 160 312 200'%3E%3Cpath d='m224.9 336.6 60.7-161.2h17.8l-60.7 161.2zm150.7 0-60.7-161.2h17.8l60.7 161.2zm-257.1 0V175.4h17v161.2zm38.6 0V175.4h17v161.2zm38.5 0V175.4h17v161.2z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='100 160 312 200'%3E%3Cpath d='m224.9 336.6 60.7-161.2h17.8l-60.7 161.2zm150.7 0-60.7-161.2h17.8l60.7 161.2zm-257.1 0V175.4h17v161.2zm38.6 0V175.4h17v161.2zm38.5 0V175.4h17v161.2z'/%3E%3C/svg%3E");
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

/* Active state when media browser is open - Spotify */
.media-browser-toggle-btn.active {
    color: #1DB954; /* Spotify green */
    background: rgba(29, 185, 84, 0.15);
    border-color: rgba(29, 185, 84, 0.3);
}

/* Active state - Music Assistant */
.media-browser-toggle-btn.active-ma {
    color: #4A90D9; /* MA blue */
    background: rgba(74, 144, 217, 0.15);
    border-color: rgba(74, 144, 217, 0.3);
}

/* Hide in minimal mode */
body[data-minimal="true"] .media-browser-toggle-btn {
    display: none !important;
}

/* Push up when bottom nav is visible */
body:not(.hide-nav) .media-browser-toggle-btn {
    bottom: 108px; /* 56px nav + 52px (to stay above visual mode which is at 56px) */
}

/* ========== MEDIA BROWSER MODAL ========== */
/* Backdrop - click to close */
.media-browser-modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

.media-browser-modal:not(.hidden) {
    opacity: 1;
    pointer-events: auto;
}

.media-browser-modal.hidden {
    display: flex; /* Keep flex during transition */
}

/* Modal content - the popup itself */
.media-browser-content {
    position: relative;
    background: rgba(18, 18, 18, 0.98);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 16px;
    width: 100%;
    height: 100%;
    max-width: 95vw;
    max-height: 95vh;
    overflow: hidden;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
    transform: scale(0.95) translateY(20px);
    transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
    display: flex;
    flex-direction: column;
}

.media-browser-modal:not(.hidden) .media-browser-content {
    transform: scale(1) translateY(0);
}

/* Minimalist control bar - top right corner */
.media-browser-controls {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 10;
    display: flex;
    gap: 12px;
}

/* Add extra spacing after toggle button to separate from refresh/close */
#media-browser-toggle-source {
    margin-right: 2px;
}

/* Add spacing after devices button to separate from toggle */
#media-browser-devices {
    margin-right: 4px;
}

.media-browser-control-btn {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    border: 1px solid rgba(255, 255, 255, 0.15);
    color: rgba(255, 255, 255, 0.7);
    font-size: 1rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s ease;
    backdrop-filter: blur(4px);
}

.media-browser-control-btn:hover {
    background: rgba(255, 255, 255, 0.15);
    color: white;
    border-color: rgba(255, 255, 255, 0.3);
}

.media-browser-control-btn.close-btn:hover {
    background: rgba(239, 68, 68, 0.3);
    border-color: rgba(239, 68, 68, 0.5);
    color: #f87171;
}

/* Toggle source button icon sizing (same as other buttons) */
.media-browser-control-btn .icon-ma {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    background-color: currentColor;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='100 160 312 200'%3E%3Cpath d='m224.9 336.6 60.7-161.2h17.8l-60.7 161.2zm150.7 0-60.7-161.2h17.8l60.7 161.2zm-257.1 0V175.4h17v161.2zm38.6 0V175.4h17v161.2zm38.5 0V175.4h17v161.2z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='100 160 312 200'%3E%3Cpath d='m224.9 336.6 60.7-161.2h17.8l-60.7 161.2zm150.7 0-60.7-161.2h17.8l60.7 161.2zm-257.1 0V175.4h17v161.2zm38.6 0V175.4h17v161.2zm38.5 0V175.4h17v161.2z'/%3E%3C/svg%3E");
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

/* iframe takes remaining space */
.media-browser-frame {
    flex: 1;
    width: 100%;
    border: none;
    background: #121212;
    border-radius: 0 0 16px 16px;
}

/* ========== HA MODAL ========== */
/* Shares the same modal pattern as media-browser-modal */
.ha-modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2000;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

.ha-modal:not(.hidden) {
    opacity: 1;
    pointer-events: auto;
}

.ha-modal.hidden {
    display: flex; /* Keep flex during transition */
}

.ha-modal-content {
    position: relative;
    background: rgba(18, 18, 18, 0.98);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 16px;
    width: 100%;
    height: 100%;
    max-width: 97vw;
    max-height: 97vh;
    overflow: hidden;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
    transform: scale(0.95) translateY(20px);
    transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
    display: flex;
    flex-direction: column;
}

.ha-modal:not(.hidden) .ha-modal-content {
    transform: scale(1) translateY(0);
}

.ha-modal-controls {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 10;
    display: flex;
    gap: 12px;
}

.ha-frame {
    flex: 1;
    width: 100%;
    border: none;
    background: #121212;
    border-radius: 0 0 16px 16px;
    color-scheme: light; /* Force HA to resolve prefers-color-scheme as light */
}

/* Debug HUD — positioned inside overlay, top-left, moves with overlay */
.vs-dbg {
    display: none;
    position: absolute;
    top: 4px; /* Tuck perfectly against the top, between edit & control bars */
    left: 50%;
    transform: translateX(-50%);
    background: rgba(0, 0, 0, 0.72);
    backdrop-filter: blur(6px);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 8px;
    padding: 4px 6px;
    pointer-events: none;
    z-index: 9998;
    font-family: 'SF Mono', 'Menlo', 'Consolas', monospace;
    white-space: nowrap;
    user-select: none;
}
.vs-dbg.vs-dbg-on { display: block; }

/* Transparent HUD styling when overlay has transparency blend mode */
.video-stream-overlay.vs-multiply .vs-dbg,
.video-stream-overlay.vs-screen .vs-dbg {
    background: transparent;
    backdrop-filter: none;
    border: 1px solid transparent; /* invisible border keeps spacing */
}

.vs-dbg-row { display: flex; gap: 8px; align-items: center; }
.vs-dbg-cell { display: flex; flex-direction: column; align-items: center; gap: 1px; }

/* Fixed widths to prevent jitter */
.vs-dbg-val {
    color: rgba(255,255,255,0.9);
    font-size: 10px;
    font-variant-numeric: tabular-nums;
    text-align: center;
    min-width: 36px;
}
.vs-dbg-cell.vs-dbg-wide .vs-dbg-val { min-width: 52px; }

.vs-dbg-lbl { color: rgba(255,255,255,0.4); font-size: 8px; text-transform: uppercase; }
.vs-dbg-val.dim    { color: rgba(255,255,255,0.3); }
.vs-dbg-val.locked { color: #4ade80; }  /* green */
.vs-dbg-val.pll    { color: #fbbf24; }  /* yellow */
.vs-dbg-val.seek   { color: #f87171; }  /* red */

/* ========== MOBILE LAYOUT ========== */
@media (max-width: 825px) {
    .media-browser-toggle-btn {
        right: auto;
        left: 16px;
        bottom: calc(var(--buttons-base, 80px) + 150px);
    }

    /* Video stream: stacked above media-browser (original vertical layout) */
    .video-stream-toggle-btn {
        right: auto;
        left: 16px;
        bottom: calc(var(--buttons-base, 80px) + 202px); /* 150px + 40px + 12px gap */
    }

    /* HA: stacked above video-stream — mobile layout to be refined later */
    .ha-toggle-btn {
        right: auto;
        left: 16px;
        bottom: calc(var(--buttons-base, 80px) + 254px); /* 202px + 40px + 12px gap */
    }

    /* On mobile, overlay top is still managed by JS */
    .video-stream-overlay {
        top: 0;
    }
}
