/* ==========================================================================
   Custom player
   ========================================================================== */

.fs-player {
	border-radius: var(--radius-lg);
	/* overflow: hidden removed — it clips the menu panels (CC/Quality/Sources)
	   which are position:absolute and need to render above the controls bar.
	   The frame's own overflow:hidden keeps the video clipped correctly. */
	overflow: visible;
	background: #000;
	box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}

.fs-player__frame {
	position: relative;
	aspect-ratio: 16/9;
	width: 100%;
	background: #000;
	/* Without this, a real double-tap gets interpreted by the browser as a
	   double-tap-to-zoom gesture — it either eats the second tap entirely or
	   delays its synthesized click well past our 350ms double-tap window,
	   which is why double-tap seek silently does nothing on mobile. */
	touch-action: manipulation;
}

.fs-player__video {
	width: 100%; height: 100%;
	display: block;
	background: #000;
}

/* ---- Click-to-play splash ---- */
.fs-player__splash {
	position: absolute; inset: 0;
	z-index: 10;
	display: flex; align-items: center; justify-content: center;
	cursor: pointer;
	transition: opacity 0.35s ease;
}
.fs-player__splash[hidden] { display: none; }
.fs-player__splash.is-hiding { opacity: 0; pointer-events: none; }

.fs-player__splash-bg {
	position: absolute; inset: 0;
	background-size: cover;
	background-position: center 20%;
	background-color: #000;
}
/* Poster images are portrait — use contain + black bars rather than cropping */
.fs-player__splash-bg.is-poster {
	background-size: contain;
	background-repeat: no-repeat;
	background-position: center center;
}
/* Dark gradient so the play button pops regardless of image brightness */
.fs-player__splash-bg::after {
	content: '';
	position: absolute; inset: 0;
	background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.35) 100%);
}

.fs-player__splash-btn {
	position: relative; z-index: 1;
	display: flex; align-items: center; justify-content: center;
	width: 80px; height: 80px;
	border-radius: 50%;
	background: rgba(255,255,255,0.15);
	backdrop-filter: blur(8px);
	border: 2px solid rgba(255,255,255,0.35);
	color: #fff;
	transition: transform 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
	box-shadow: 0 0 40px rgba(0,0,0,0.5);
}
.fs-player__splash-btn:hover {
	transform: scale(1.1);
	background: rgba(255,255,255,0.25);
	box-shadow: 0 0 60px rgba(0,0,0,0.6), 0 0 0 6px rgba(255,255,255,0.08);
}
.fs-player__splash-btn:active { transform: scale(0.97); }

/* ── Mid-playback pause cover ─────────────────────────────────────────────
   Shows over the video when paused mid-playback.
   When a backdrop/poster image is available the bg div fills with it
   (just like the initial splash). Without an image, a semi-transparent
   dark veil sits over the paused video frame instead. */
.fs-player__pause-cover {
	position: absolute; inset: 0;
	z-index: 9;
	display: flex; align-items: center; justify-content: center;
	cursor: pointer;
	opacity: 0;
	transition: opacity 0.22s ease;
}
.fs-player__pause-cover[hidden] { display: none; }
.fs-player__pause-cover.is-visible { opacity: 1; }
.fs-player__pause-cover.is-hiding  { opacity: 0; pointer-events: none; }

/* Background layer — same layout as .fs-player__splash-bg */
.fs-player__pause-cover-bg {
	position: absolute; inset: 0;
	background-size: cover;
	background-position: center 20%;
	background-color: #000;
}
/* No image set: just a semi-transparent dark overlay + subtle blur */
.fs-player__pause-cover-bg:not(.has-image) {
	background-color: rgba(0,0,0,0.48);
	backdrop-filter: blur(3px);
	-webkit-backdrop-filter: blur(3px);
}
/* Poster images are portrait — contain + black bars, same as splash */
.fs-player__pause-cover-bg.is-poster {
	background-size: contain;
	background-repeat: no-repeat;
	background-position: center center;
}
/* Dark gradient so the play button pops — mirrors the splash gradient */
.fs-player__pause-cover-bg.has-image::after {
	content: '';
	position: absolute; inset: 0;
	background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.25) 50%, rgba(0,0,0,0.4) 100%);
}

/* The inner play button is visual only — whole cover area is the click target */
.fs-player__pause-cover-btn { pointer-events: none; }

/* Loading overlay */
.fs-player__overlay {
	position: absolute; inset: 0;
	display: flex; flex-direction: column; align-items: center; justify-content: center;
	gap: 20px;
	background: rgba(0,0,0,0.82);
	color: #fff;
	font-size: 13.5px;
	transition: opacity 0.2s ease;
	z-index: 20;
}
.fs-player__overlay[hidden] { display: none; }

/* Initial spinner + text — shown before mirrors are known */
.fs-player__loader {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
}

.fs-player__spinner {
	width: 36px; height: 36px;
	border-radius: 50%;
	border: 3px solid rgba(255,255,255,0.12);
	border-top-color: var(--accent-2, #a78bfa);
	animation: fs-spin 0.8s linear infinite;
	flex-shrink: 0;
}
@keyframes fs-spin { to { transform: rotate(360deg); } }

.fs-player__status {
	color: rgba(255,255,255,0.5);
	font-size: 12.5px;
	margin: 0;
	letter-spacing: 0.02em;
}

/* ── Server probe list ───────────────────────────────────────────────── */
/* Shown once we know how many mirrors exist — replaces the plain spinner */
.fs-probe {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
	width: 100%;
	max-width: 280px;
}
.fs-probe[hidden] { display: none; }

.fs-probe__label {
	font-size: 12px;
	color: rgba(255,255,255,0.35);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	margin: 0;
}

.fs-probe__list {
	display: flex;
	flex-direction: column;
	gap: 7px;
	width: 100%;
}

/* Each server row */
.fs-probe__row {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 14px;
	border-radius: 8px;
	background: rgba(255,255,255,0.05);
	border: 1px solid rgba(255,255,255,0.07);
	transition: background 0.2s ease, border-color 0.2s ease;
}

/* Active/loading row */
.fs-probe__row.is-loading {
	background: rgba(167,139,250,0.1);
	border-color: rgba(167,139,250,0.25);
}

/* Success row */
.fs-probe__row.is-ok {
	background: rgba(52,211,153,0.08);
	border-color: rgba(52,211,153,0.2);
}

/* Failed row */
.fs-probe__row.is-fail {
	background: rgba(255,255,255,0.03);
	border-color: rgba(255,255,255,0.05);
	opacity: 0.55;
}

/* Server name */
.fs-probe__name {
	flex: 1;
	font-size: 13px;
	font-weight: 500;
	color: rgba(255,255,255,0.75);
	letter-spacing: 0.01em;
}

.fs-probe__row.is-ok   .fs-probe__name { color: #6ee7b7; }
.fs-probe__row.is-fail .fs-probe__name { color: rgba(255,255,255,0.3); }

/* Status badge on the right */
.fs-probe__badge {
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.04em;
	min-width: 52px;
	text-align: right;
	transition: color 0.2s ease;
}

/* Idle — not yet tried */
.fs-probe__row .fs-probe__badge { color: rgba(255,255,255,0.2); }

/* Spinning dot for the active row */
.fs-probe__row.is-loading .fs-probe__badge {
	color: #a78bfa;
}
.fs-probe__row.is-loading .fs-probe__badge::before {
	content: '';
	display: inline-block;
	width: 7px; height: 7px;
	border-radius: 50%;
	background: #a78bfa;
	margin-right: 5px;
	vertical-align: middle;
	animation: fs-probe-pulse 0.9s ease-in-out infinite;
}
@keyframes fs-probe-pulse {
	0%, 100% { opacity: 1;   transform: scale(1); }
	50%       { opacity: 0.3; transform: scale(0.7); }
}

/* Tick for success */
.fs-probe__row.is-ok .fs-probe__badge { color: #6ee7b7; }

/* Cross for failure */
.fs-probe__row.is-fail .fs-probe__badge { color: rgba(255,255,255,0.2); }

/* Mobile: slightly more compact */
@media (max-width: 480px) {
	.fs-probe { max-width: 220px; }
	.fs-probe__row { padding: 7px 11px; gap: 8px; }
	.fs-probe__name { font-size: 12px; }
	.fs-probe__badge { font-size: 10px; min-width: 44px; }
}

.fs-player__error {
	/* Error overlay disabled: mirror-switching keeps running silently in
	   the background (see player.js), but we no longer interrupt an
	   otherwise-playing stream with a false "failed to load" message. */
	display: none !important;
}

/* ── "Video Not Yet Available" / all-mirrors-failed state ────────────── */
.fs-player__unavailable {
	position: absolute;
	inset: 0;
	z-index: 40;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 12px;
	text-align: center;
	padding: 32px 28px;
	background: rgba(5, 5, 16, 0.96);
}

.fs-player__unavailable[hidden] { display: none; }

.fs-player__unavailable-icon {
	color: rgba(255,255,255,0.2);
	margin-bottom: 4px;
	line-height: 1;
}

.fs-player__unavailable h3 {
	font-size: 18px;
	font-weight: 700;
	color: #fff;
	letter-spacing: -0.2px;
	margin: 0;
}

.fs-player__unavailable p {
	color: rgba(255,255,255,0.55);
	font-size: 13.5px;
	line-height: 1.6;
	max-width: 340px;
	margin: 0;
}

.fs-player__unavailable-actions {
	display: flex;
	gap: 10px;
	flex-wrap: wrap;
	justify-content: center;
	margin-top: 8px;
}

/* Smaller, tighter buttons inside the player */
.fs-player__unavailable .fs-btn {
	padding: 9px 18px;
	font-size: 13px;
}

/* Mobile: stack to single column if tight */
@media (max-width: 480px) {
	.fs-player__unavailable {
		padding: 24px 16px;
		gap: 10px;
	}
	.fs-player__unavailable h3 { font-size: 15px; }
	.fs-player__unavailable p  { font-size: 12.5px; }
	.fs-player__unavailable-actions { flex-direction: column; align-items: center; }
}

/* Sandbox-restricted embed notice — sits above splash/controls/everything.
   See FSTREAM_PLAYER_SETTINGS.isEmbed / player.js for when this shows. */
.fs-player__sandbox-warn {
	position: absolute; inset: 0;
	z-index: 50;
	display: flex; flex-direction: column; align-items: center; justify-content: center;
	gap: 14px;
	text-align: center;
	padding: 40px 24px;
	background: rgba(5,5,5,0.97);
}
.fs-player__sandbox-warn[hidden] { display: none; }
.fs-player__sandbox-icon { font-size: 40px; line-height: 1; }
.fs-player__sandbox-warn h2 {
	font-size: 17px; font-weight: 700;
	color: #ff6b6b;
	letter-spacing: -0.2px;
}
.fs-player__sandbox-warn p {
	color: var(--text-muted);
	font-size: 13.5px; line-height: 1.6;
	max-width: 320px;
}
.fs-player__sandbox-warn .fs-btn { margin-top: 4px; }

/* Controls bar — glassmorphism */
.fs-player__controls {
	position: absolute;
	left: 0; right: 0; bottom: 0;
	z-index: 6;
	padding: 10px 16px 14px;
	background: linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.4) 60%, transparent 100%);
	opacity: 1;
	transition: opacity 0.25s ease;
	/* Must be visible so .fs-player__menu-panel (position:absolute) can
	   render above the controls bar without being clipped. */
	overflow: visible;
}
.fs-player.is-idle .fs-player__controls { opacity: 0; pointer-events: none; }
.fs-player.is-idle .fs-player__video { cursor: none; }

.fs-player__progress {
	position: relative;
	height: 5px;
	border-radius: 3px;
	background: rgba(255,255,255,0.2);
	margin-bottom: 10px;
	cursor: pointer;
}
.fs-player__progress-buffered {
	position: absolute; left: 0; top: 0; bottom: 0;
	background: rgba(255,255,255,0.35);
	border-radius: 3px;
	width: 0%;
}
.fs-player__progress-played {
	position: absolute; left: 0; top: 0; bottom: 0;
	background: linear-gradient(90deg, var(--accent), var(--accent-2));
	border-radius: 3px;
	width: 0%;
}
.fs-player__progress-handle {
	position: absolute; top: 50%; left: 0%;
	width: 13px; height: 13px;
	background: #fff;
	border-radius: 50%;
	transform: translate(-50%, -50%);
	box-shadow: 0 0 8px rgba(0,0,0,0.5);
	opacity: 0;
	transition: opacity 0.15s ease;
}
.fs-player__progress:hover .fs-player__progress-handle { opacity: 1; }

.fs-player__row {
	display: flex;
	align-items: center;
	gap: 4px;
}

.fs-player__row .fs-icon-btn {
	width: 36px; height: 36px;
	color: #fff;
}
.fs-player__row .fs-icon-btn:hover { background: rgba(255,255,255,0.12); }
/* .fs-icon-btn (main.css) sets display:inline-flex, which — because author CSS
   always wins over the UA stylesheet's [hidden]{display:none}, regardless of
   specificity — silently defeats the hidden attribute entirely. Same trap the
   .fs-player__menu-item[hidden] rule below already exists to beat; #fs-cast
   needs the identical fix or the button never actually hides. */
#fs-cast[hidden] { display: none; }
/* Brief pulse while a cast prompt() call is in flight, so tapping doesn't feel dead
   even during the moment before the browser resolves/rejects the picker. */
#fs-cast.is-connecting { animation: fs-cast-pulse 0.9s ease-in-out infinite; }
@keyframes fs-cast-pulse {
	0%, 100% { opacity: 1; }
	50%      { opacity: 0.4; }
}

/* Feedback toast for cast failures/no-devices — mobile Chrome in particular gives no
   native UI at all when prompt() finds nothing, so this is the only way the user can
   tell "no device nearby" apart from "button is broken". */
.fs-cast-tip {
	position: absolute;
	left: 50%;
	bottom: 62px;
	transform: translateX(-50%) translateY(6px);
	max-width: min(86%, 320px);
	text-align: center;
	background: rgba(15,15,28,0.97);
	border: 1px solid var(--border);
	border-radius: 8px;
	padding: 8px 14px;
	font-size: 12.5px;
	color: #fff;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.2s ease, transform 0.2s ease;
	z-index: 100;
}
.fs-cast-tip.is-visible {
	opacity: 1;
	transform: translateX(-50%) translateY(0);
}

.fs-player__volume { display: flex; align-items: center; gap: 4px; }
.fs-player__volume input[type="range"] {
	width: 70px;
	accent-color: var(--accent-2);
}
/* Muted state: dim the button so the user can tell at a glance */
#fs-mute.is-muted { opacity: 0.45; }

.fs-player__time {
	font-family: var(--font-mono);
	font-size: 12.5px;
	color: rgba(255,255,255,0.85);
	margin-left: 6px;
	white-space: nowrap;
}

.fs-player__spacer { flex: 1; }

.fs-player__menu { position: relative; overflow: visible; }
.fs-player__menu-panel {
	position: absolute;
	bottom: 46px; right: 0;
	min-width: 180px;
	max-height: 240px;
	overflow-y: auto;
	background: rgba(15,15,28,0.97);
	backdrop-filter: blur(10px);
	border: 1px solid var(--border);
	border-radius: 8px;
	padding: 6px;
	/* Must be above tap zones (z-index:5), controls (z-index:6), overlay (z-index:20) */
	z-index: 100;
}
.fs-player__menu-item {
	display: block;
	width: 100%;
	text-align: left;
	padding: 8px 10px;
	border-radius: 6px;
	font-size: 13px;
	color: var(--text-muted);
}
.fs-player__menu-item:hover { background: rgba(255,255,255,0.06); color: #fff; }
.fs-player__menu-item.is-active { color: var(--accent-2); font-weight: 600; }
/* The [hidden] attribute is how the search filter hides non-matching items.
   This needs to beat the plain .fs-player__menu-item{display:block} rule
   above on specificity, or the browser's default [hidden]{display:none}
   loses and "filtered" buttons stay visible. */
.fs-player__menu-item[hidden] { display: none; }
.fs-player__menu-empty { font-size: 12px; color: var(--text-faint); padding: 8px 10px; margin: 0; }

/* Section dividers inside the settings/quality panel (Quality / Audio Boost) */
.fs-menu-section-label {
	font-size: 11px;
	color: var(--text-muted);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	font-weight: 600;
	margin: 0;
	padding: 8px 10px 4px;
}
.fs-menu-section-label--boost {
	margin-top: 4px;
	border-top: 1px solid rgba(255,255,255,0.05);
}

.fs-player__menu-search {
	display: block;
	width: 100%;
	box-sizing: border-box;
	margin-bottom: 6px;
	padding: 7px 10px;
	border: 1px solid rgba(255,255,255,0.12);
	border-radius: 6px;
	background: rgba(255,255,255,0.05);
	color: #fff;
	font-size: 13px;
}
.fs-player__menu-search::placeholder { color: var(--text-faint); }
.fs-player__menu-search:focus {
	outline: none;
	border-color: var(--accent-2);
	background: rgba(255,255,255,0.08);
}

/* Subtitle rendering (native <track> cues styled via ::cue where supported) */
.fs-player__video::cue {
	background: rgba(0,0,0,0.7);
	color: #fff;
	font-size: 1.1em;
	padding: 2px 6px;
}

/* ---- Double-tap-to-seek zones (mobile) ---- */
/* Left/right halves of the frame, sitting above the video but below the
   controls bar (which needs to stay clickable on top). Zones stop short of
   the bottom controls area so they never intercept those taps. */
.fs-player__tap-zone {
	position: absolute;
	top: 0; bottom: 64px;
	width: 40%;
	z-index: 5;
	display: flex;
	align-items: center;
	cursor: pointer;
}
.fs-player__tap-zone--left { left: 0; justify-content: flex-start; }
.fs-player__tap-zone--right { right: 0; justify-content: flex-end; }

.fs-player__tap-flash {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 2px;
	margin: 0 18px;
	padding: 14px;
	border-radius: 50%;
	background: rgba(0,0,0,0.45);
	color: #fff;
	font-size: 11px;
	font-weight: 700;
	opacity: 0;
	transform: scale(0.7);
	pointer-events: none;
}
.fs-player__tap-flash.is-flashing {
	animation: fs-tap-flash 0.55s ease-out;
}
@keyframes fs-tap-flash {
	0%   { opacity: 0; transform: scale(0.7); }
	25%  { opacity: 1; transform: scale(1); }
	70%  { opacity: 1; transform: scale(1); }
	100% { opacity: 0; transform: scale(1); }
}

/* Desktop: double-tap gesture isn't the primary interaction (buttons are) —
   keep the zones present for touch laptops/tablets but let mouse users
   click straight through to the video for play/pause without a delay. */
@media (hover: hover) and (pointer: fine) {
	.fs-player__tap-zone { pointer-events: none; }
}

/* Play/pause button icons — toggled via .is-playing class on the button.
   Class-based specificity (1,2,0) always beats the base (1,1,0), no !important
   or [hidden] attribute battles needed. */
#fs-play-pause .fs-icon-pause            { display: none;  }
#fs-play-pause .fs-icon-play             { display: block; }
#fs-play-pause.is-playing .fs-icon-play  { display: none;  }
#fs-play-pause.is-playing .fs-icon-pause { display: block; }
/* Shown briefly when the user taps/clicks the video to toggle playback. */
.fs-player__center-flash {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	pointer-events: none;
	z-index: 8;
}
.fs-player__center-flash svg {
	display: none;
	opacity: 0;
	filter: drop-shadow( 0 2px 8px rgba(0,0,0,0.7) );
	color: #fff;
}
/* Show the correct icon based on the state JS sets */
.fs-player__center-flash[data-state="play"]  .fs-center-flash__play  { display: block; }
.fs-player__center-flash[data-state="pause"] .fs-center-flash__pause { display: block; }

.fs-player__center-flash.is-flashing svg {
	animation: fs-center-flash 0.6s ease-out forwards;
}
@keyframes fs-center-flash {
	0%   { opacity: 0;   transform: scale(0.6); }
	20%  { opacity: 1;   transform: scale(1.1); }
	50%  { opacity: 1;   transform: scale(1);   }
	100% { opacity: 0;   transform: scale(1.05); }
}

/* ---- Mid-playback buffering spinner ---- */
/* Shown via .is-buffering class on .fs-player (set by player.js on video
   'waiting'/'stalled' events). Hidden when initial overlay is active. */
.fs-player__buffer-spin {
	position: absolute;
	inset: 0;
	display: none;        /* shown only when .is-buffering is on the root */
	align-items: center;
	justify-content: center;
	pointer-events: none;
	z-index: 7;
	background: rgba(0,0,0,0.25);
}
.fs-player.is-buffering .fs-player__buffer-spin {
	display: flex;
}
/* Don't show buffering spinner while the source-loading overlay is visible */
.fs-player:has( #fs-player-overlay:not([hidden]) ) .fs-player__buffer-spin {
	display: none;
}
.fs-player__buffer-spinner {
	width: 48px;
	height: 48px;
	border: 4px solid rgba(255,255,255,0.2);
	border-top-color: var(--accent-2, #38cfb0);
	border-radius: 50%;
	animation: fs-spin 0.75s linear infinite;
}
@keyframes fs-spin {
	to { transform: rotate(360deg); }
}

/* ---- Fullscreen mode ---- */
/* When the .fs-player itself is the fullscreen element, drop the fixed
   16/9 aspect-ratio so it fills whatever the device gives us (landscape
   after orientation lock) instead of leaving letterboxed bars. */
.fs-player:fullscreen,
.fs-player:-webkit-full-screen {
	width: 100vw;
	height: 100vh;
	border-radius: 0;
}
.fs-player:fullscreen .fs-player__frame,
.fs-player:-webkit-full-screen .fs-player__frame {
	aspect-ratio: unset;
	width: 100%;
	height: 100%;
}

@media (max-width: 640px) {
	/* Show the mute button on mobile — only hide the volume slider */
	.fs-player__volume input[type="range"] { display: none; }
	.fs-player__row .fs-icon-btn { width: 32px; height: 32px; }
	/* Seek ±10 is handled by double-tap on mobile (see tap zones below) —
	   drop the redundant buttons so the control bar isn't overcrowded. */
	#fs-seek-back, #fs-seek-forward { display: none; }
	/* Larger touch target for progress bar on mobile */
	.fs-player__progress { height: 6px; margin-bottom: 8px; }
	.fs-player__progress-handle { width: 16px; height: 16px; opacity: 1; }
	/* Tighten control padding so buttons aren't clipped */
	.fs-player__controls { padding: 8px 10px 12px; }
	.fs-player__row { gap: 2px; }

	/* ── Fullscreen: always visible and reachable on every screen size ── */
	/* Never let the fullscreen button shrink away or get pushed off screen */
	#fs-fullscreen {
		flex-shrink: 0;
		width: 36px !important;
		height: 36px !important;
		min-width: 36px;
		/* Slightly larger than other buttons so it's easy to tap */
		background: rgba(255,255,255,0.08);
		border-radius: 6px;
	}
	/* PiP is less critical on mobile — hide it to free space for fullscreen */
	#fs-pip { display: none; }

	/* Quality and mirror menus are still accessible but can shrink slightly */
	#fs-quality-toggle, #fs-mirror-toggle { width: 30px; height: 30px; }

	/* CC button: keep it, it's important for accessibility */
	#fs-subtitle-toggle { width: 32px; height: 32px; }

	/* Right side of the control bar: keep fullscreen pinned to the far end */
	.fs-player__row:last-child {
		flex-wrap: nowrap;
		/* overflow: hidden removed — it clips the CC/Quality/Sources popup panels.
		   Panels are position:absolute so they don't affect flex layout anyway. */
	}
	/* Spacer compress so right-side buttons never get pushed off */
	.fs-player__spacer { min-width: 0; flex-shrink: 10; }

	/* ---- Menu panels: position:fixed so ancestor overflow:hidden never clips them ---- */
	/* position:fixed is relative to the viewport — escapes all ancestor clipping.        */
	/* JS (positionPanel) sets --panel-bottom/--panel-right for upward mode, or sets      */
	/* inline top + bottom:auto for downward mode. max-height also set by JS dynamically. */
	.fs-player__menu-panel {
		position: fixed !important;
		/* Upward mode (default): bottom/right from JS-written CSS vars */
		bottom: var(--panel-bottom, 70px);
		right: var(--panel-right, 8px) !important;
		left: auto !important;
		/* top is intentionally NOT !important — JS sets inline top for downward mode */
		top: auto;
		max-height: 50vh; /* overridden by JS inline style */
		min-width: 160px;
		max-width: calc(100vw - 16px);
		z-index: 9999;
	}
}

/* Extra narrow (< 360px — old Android, small iPhones) */
@media (max-width: 360px) {
	/* Hide subtitle and quality to give fullscreen breathing room */
	#fs-subtitle-toggle, #fs-quality-toggle { display: none; }
	/* Cast is a nice-to-have on this little room — same treatment as PiP above */
	#fs-cast { display: none; }
	#fs-fullscreen {
		width: 40px !important;
		height: 40px !important;
	}
}

/* ── CC (Closed Captions) button ─────────────────────────────────────── */

/* The CC icon uses an SVG <text> node — ensure crisp rendering */
#fs-subtitle-toggle svg {
	overflow: visible;
	shape-rendering: crispEdges;
}
#fs-subtitle-toggle svg text {
	user-select: none;
	-webkit-font-smoothing: antialiased;
}

/* When subtitles are ON: fill the badge background with accent colour
   so the user can see at a glance that captions are active */
#fs-subtitle-toggle.is-cc-on svg rect:first-child {
	fill: var(--accent-2, #a78bfa);
	opacity: 1;
}
#fs-subtitle-toggle.is-cc-on svg rect:last-of-type {
	stroke: var(--accent-2, #a78bfa);
}
#fs-subtitle-toggle.is-cc-on svg text {
	fill: #fff;
}
/* Subtle glow on the button itself when on */
#fs-subtitle-toggle.is-cc-on {
	color: var(--accent-2, #a78bfa);
	background: rgba(167, 139, 250, 0.12);
	border-radius: 6px;
}

/* ── Subtitle Sync Row ──────────────────────────────────────────────────────── */
.fs-sync-row {
	display: none; /* hidden by default — JS shows it when a subtitle is active */
	align-items: center;
	gap: 4px;
	padding: 6px 8px;
	margin-bottom: 4px;
	background: rgba(255,255,255,0.04);
	border: 1px solid rgba(255,255,255,0.08);
	border-radius: 6px;
}
.fs-sync-row.is-visible {
	display: flex;
}
.fs-sync-label {
	font-size: 11px;
	color: var(--text-faint);
	text-transform: uppercase;
	letter-spacing: 0.04em;
	margin-right: 2px;
	flex-shrink: 0;
}
.fs-sync-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 26px;
	height: 26px;
	padding: 0 6px;
	border-radius: 5px;
	border: 1px solid rgba(255,255,255,0.12);
	background: rgba(255,255,255,0.06);
	color: #fff;
	font-size: 14px;
	line-height: 1;
	cursor: pointer;
	flex-shrink: 0;
	transition: background 0.15s;
}
.fs-sync-btn:hover { background: rgba(255,255,255,0.14); }
.fs-sync-btn:active { background: rgba(255,255,255,0.2); }
.fs-sync-reset {
	font-size: 11px;
	margin-left: auto;
	color: var(--text-faint);
}
.fs-sync-value {
	font-size: 12px;
	font-weight: 600;
	color: var(--text-muted);
	min-width: 36px;
	text-align: center;
	flex-shrink: 0;
	transition: color 0.15s;
}
.fs-sync-value.is-offset {
	color: var(--accent-2); /* teal highlight when not at 0 */
}

/* ================================================================
   Backup-mode floating toolbar  (v2.3.2, fixed v2.5.1)
   Floats above the external iframe at z-index 9 so the user can
   always switch servers or return to primary sources.
   ================================================================ */

.fs-backup-iframe {
	z-index: 3;
}

/* ── Backup mode: the floating top-left toolbar (.fs-backup-bar) already
   has its own server switcher + "Primary" exit button, and the external
   iframe brings its own fullscreen control — so the native controls bar
   isn't needed at all here. Hiding it completely (rather than leaving the
   mirror-menu/fullscreen buttons behind) is what actually stops our own
   controls from sitting on top of / blocking the iframe's controls. */
.fs-player--backup #fs-player-controls {
	display: none !important;
	pointer-events: none !important;
}

/* ── Backup bar: compact floating badge, top-right corner ── */
/* (not a bottom-spanning strip — that would fight the iframe's own controls) */
.fs-backup-bar {
	position: absolute;
	top: 12px; left: 12px;
	bottom: auto; right: auto;
	width: auto;
	z-index: 9;
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 7px 10px;
	background: rgba(8,8,20,.88);
	backdrop-filter: blur(10px);
	border: 1px solid rgba(255,255,255,.13);
	border-radius: 10px;
	box-shadow: 0 4px 20px rgba(0,0,0,.5);
	pointer-events: auto;
}
.fs-backup-bar[hidden] { display: none; }
/* Always visible — never idle-hides */
.fs-player.is-idle .fs-backup-bar { opacity: 1 !important; pointer-events: auto !important; }
/* Hide the server name label and the Primary exit button — Servers dropdown only */
.fs-backup-bar__label,
.fs-backup-bar__btn--exit { display: none !important; }

/* ── Left: server name badge ── */
.fs-backup-bar__label {
	display: flex;
	align-items: center;
	gap: 6px;
	min-width: 0;
	overflow: hidden;
}
.fs-backup-bar__dot {
	flex-shrink: 0;
	width: 6px; height: 6px;
	border-radius: 50%;
	background: var(--accent, #7c3aed);
	animation: fs-backup-pulse 2s infinite;
}
@keyframes fs-backup-pulse {
	0%   { box-shadow: 0 0 0 0   rgba(124,58,237,.65); }
	60%  { box-shadow: 0 0 0 5px rgba(124,58,237,0); }
	100% { box-shadow: 0 0 0 0   rgba(124,58,237,0); }
}
.fs-backup-bar__name {
	font-size: 11px;
	font-weight: 600;
	color: rgba(255,255,255,.85);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	max-width: 120px;
}

/* ── Right: action buttons ── */
.fs-backup-bar__actions {
	display: flex;
	align-items: center;
	gap: 5px;
	flex-shrink: 0;
}
.fs-backup-bar__btn {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding: 7px 13px;
	border-radius: 7px;
	font-size: 12px;
	font-weight: 600;
	line-height: 1;
	color: rgba(255,255,255,.85);
	background: rgba(255,255,255,.1);
	border: 1px solid rgba(255,255,255,.16);
	cursor: pointer;
	min-height: 38px;
	touch-action: manipulation;
	white-space: nowrap;
	transition: background .15s, color .15s, border-color .15s;
}
.fs-backup-bar__btn:hover,
.fs-backup-bar__btn:focus-visible {
	background: rgba(255,255,255,.18);
	color: #fff;
	outline: none;
}
.fs-backup-bar__btn--exit {
	background: rgba(124,58,237,.18);
	border-color: rgba(124,58,237,.4);
	color: #c4b5fd;
}
.fs-backup-bar__btn--exit:hover {
	background: rgba(124,58,237,.35);
	color: #fff;
}

/* ── Servers dropdown ── */
.fs-backup-bar__switcher { position: relative; }
.fs-backup-bar__dropdown {
	position: absolute;
	top: calc(100% + 6px);  /* opens downward — bar is at top of frame */
	bottom: auto;
	left: 0;   /* anchored to left edge of button since bar is on left */
	right: auto;
	min-width: 210px;
	max-height: 280px;
	overflow-y: auto;
	background: rgba(10,10,22,.97);
	backdrop-filter: blur(14px);
	border: 1px solid rgba(255,255,255,.1);
	border-radius: 10px;
	padding: 6px;
	z-index: 200;
	box-shadow: 0 8px 32px rgba(0,0,0,.6);
}
.fs-backup-bar__dropdown[hidden] { display: none; }

.fs-backup-bar__drop-item {
	display: flex;
	align-items: center;
	gap: 8px;
	width: 100%;
	text-align: left;
	padding: 9px 12px;
	border-radius: 7px;
	font-size: 13px;
	color: rgba(255,255,255,.72);
	cursor: pointer;
	touch-action: manipulation;
	transition: background .12s, color .12s;
}
.fs-backup-bar__drop-item:hover  { background: rgba(255,255,255,.07); color: #fff; }
.fs-backup-bar__drop-item.is-active {
	color: var(--accent-2, #818cf8);
	font-weight: 700;
}
.fs-backup-bar__drop-divider {
	border: none;
	border-top: 1px solid rgba(255,255,255,.1);
	margin: 5px 0;
}
.fs-backup-bar__drop-badge {
	font-size: 10px;
	padding: 2px 6px;
	border-radius: 4px;
	background: rgba(124,58,237,.25);
	color: #c4b5fd;
	font-weight: 700;
	flex-shrink: 0;
	margin-left: auto;
}

/* ── Mobile ── */
@media (max-width: 640px) {
	.fs-backup-bar { top: 8px; left: 8px; gap: 4px; padding: 6px 8px; }
	.fs-backup-bar__btn { padding: 5px 8px; font-size: 10px; min-height: 34px; }
	.fs-backup-bar__chevron { display: none; }
}

/* ── Backup mode: inline server label — hidden per user preference ── */
.fs-backup-label,
.fs-player--backup .fs-backup-label {
	display: none !important;
}

/* ================================================================
   Player intro branding  (v2.7.1)
   A brief, lightweight text-only reveal shown once when playback
   first starts. Only transform/opacity are animated — both are
   GPU-composited, so this never triggers layout or paint work on
   the rest of the page, even on low-end devices.
   ================================================================ */

.fs-brand-intro {
	position: absolute;
	inset: 0;
	z-index: 50; /* above controls/mirror menu — brief and non-interactive */
	display: flex;
	align-items: center;
	justify-content: center;
	background: #05050a;
	opacity: 0;
	pointer-events: none; /* never blocks a click, even mid-transition */
	will-change: opacity;
	transition: opacity 450ms ease;
}

.fs-brand-intro.is-active {
	opacity: 1;
}

.fs-brand-intro.is-leaving {
	opacity: 0;
}

.fs-brand-intro__text {
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	font-size: clamp(22px, 5vw, 44px);
	font-weight: 700;
	color: #fff;
	letter-spacing: 0.35em;
	text-indent: 0.35em; /* balances the trailing tracking so the text still looks centered */
	opacity: 0;
	transform: scale(0.92);
	will-change: transform, opacity;
	transition: transform 700ms cubic-bezier(.16,1,.3,1), opacity 600ms ease;
	position: relative;
	padding-bottom: 14px;
}

.fs-brand-intro__text::after {
	content: "";
	position: absolute;
	left: 50%;
	bottom: 0;
	width: 0;
	height: 2px;
	background: linear-gradient(90deg, var(--accent, #7c3aed), var(--accent-2, #a78bfa));
	transform: translateX(-50%);
	transition: width 550ms cubic-bezier(.16,1,.3,1) 150ms;
}

.fs-brand-intro.is-active .fs-brand-intro__text {
	opacity: 1;
	transform: scale(1);
}

.fs-brand-intro.is-active .fs-brand-intro__text::after {
	width: 60%;
}

.fs-brand-intro.is-leaving .fs-brand-intro__text {
	opacity: 0;
	transform: scale(1.04);
	transition: transform 400ms ease, opacity 350ms ease;
}

@media (max-width: 640px) {
	.fs-brand-intro__text {
		letter-spacing: 0.22em;
		text-indent: 0.22em;
	}
}

/* Respect reduced-motion preferences: skip the scale/tracking flourish,
   just a plain fade so the intro still communicates the brand quickly
   without motion some users have asked their OS to minimize. */
@media (prefers-reduced-motion: reduce) {
	.fs-brand-intro,
	.fs-brand-intro__text,
	.fs-brand-intro__text::after {
		transition-duration: 200ms;
	}
	.fs-brand-intro__text {
		transform: none !important;
	}
}
