/* Frontend player — scoped, CSS-variable driven. No Tailwind (keeps the
   frontend bundle lean). */

.trueplayer-mount {
	--tp-accent: #4f46e5;
	--tp-bg: #000;
	--tp-fg: #fff;
	/* The player's own type stack. Declared as a variable and re-applied to the
	   text-bearing children below: a theme rule on a generic selector beats
	   plain inheritance from the stage, which is why the same video rendered
	   with the theme's font on a page and the player's font in the editor. */
	--tp-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
	width: 100%;
	max-width: 100%;
}

/* Click-to-load poster facade — static HTML shown until the visitor plays, so
   the real player (and its network cost) never loads on page render. */
.tp-facade {
	position: relative;
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	margin: 0;
	padding: 0;
	border: 0;
	cursor: pointer;
	overflow: hidden;
	background: #000;
	border-radius: var( --tp-radius, 10px );
	-moz-appearance: none;
	     appearance: none;
	-webkit-appearance: none;
}
.tp-facade.is-audio {
	aspect-ratio: auto;
	height: 120px;
	background: #111827;
}
/* A poster is a cover image for the frame, so it fills it — the convention
   every video platform uses. `contain` was letterboxing author-uploaded
   posters inside the stage, and it also left YouTube's smaller sizes showing
   the black bars baked into their pixels. Off-ratio art is cropped, centred. */
.tp-facade-poster {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	-o-object-fit: cover;
	   object-fit: cover;
	-o-object-position: center;
	   object-position: center;
	background: #000;
}
.tp-hover-preview {
	-o-object-fit: cover;
	   object-fit: cover;
	animation: tp-preview-in 0.25s ease;
}
@keyframes tp-preview-in {
	from { opacity: 0; }
	to { opacity: 1; }
}
.tp-facade-btn {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate( -50%, -50% );
	width: 68px;
	height: 68px;
	border-radius: 50%;
	background: var( --tp-accent, #4f46e5 );
	color: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	box-shadow: 0 2px 14px rgba( 0, 0, 0, 0.35 );
	transition: transform 0.15s ease, filter 0.15s ease;
}
.tp-facade:hover .tp-facade-btn {
	transform: translate( -50%, -50% ) scale( 1.06 );
	filter: brightness( 1.08 );
}
.tp-facade-btn svg {
	width: 30px;
	height: 30px;
	fill: currentColor;
	margin-left: 3px;
}

.tp-stage {
	position: relative;
	aspect-ratio: 16 / 9;
	background: var(--tp-bg);
	color: var(--tp-fg);
	overflow: hidden;
	border-radius: var(--tp-radius, 10px);
	font-family: var( --tp-font );
	outline: none;
	/* Size container so the control bar can adapt to the player's own width
	   (narrow admin preview panel, small/mobile embeds) instead of the viewport. */
	container-type: inline-size;
}

/* Re-assert the stack on everything that draws text, so a theme's own rules
   can't win over inheritance (see --tp-font). */
.tp-stage .tp-controls,
.tp-stage .tp-time,
.tp-stage .tp-info,
.tp-stage .tp-menu,
.tp-stage .tp-chapter-now,
.tp-stage button,
.tp-stage input,
.tp-stage select {
	font-family: var( --tp-font );
}

/* control-bar style variants */
.tp-bar-solid .tp-controls {
	background: rgba( 0, 0, 0, 0.85 );
}
.tp-bar-minimal .tp-controls {
	background: transparent;
}
.tp-bar-minimal .tp-controls-row {
	background: rgba( 0, 0, 0, 0.45 );
	border-radius: 8px;
	padding: 2px 6px;
}

/* play-button style variants */
.tp-play-square .tp-bigplay {
	border-radius: 8px;
}
.tp-play-soft .tp-bigplay {
	border-radius: 22px;
}

/* sticky (float on scroll) */
/* Reserves the stage's normal footprint once it goes `position: fixed`
   (sticky), and hosts the sentinel the sticky-on-scroll observer watches —
   see the comment in Player.jsx for why this can't be the stage itself. */
.tp-stage-slot {
	position: relative;
	width: 100%;
}
.tp-stage-sentinel {
	position: absolute;
	inset: 0;
	opacity: 0;
	pointer-events: none;
}

/* Shown in the stage's normal spot while it's actually floating in a
   Picture-in-Picture window elsewhere. */
.tp-pip-placeholder {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 10px;
	background: #0b0d12;
	color: rgba( 255, 255, 255, 0.75 );
	font-size: 13px;
	border-radius: var( --tp-radius, 10px );
}
.tp-pip-return {
	background: var( --tp-accent );
	color: #fff;
	border: 0;
	border-radius: 8px;
	padding: 8px 16px;
	font-size: 13px;
	font-weight: 600;
	cursor: pointer;
}

.tp-sticky {
	position: fixed !important;
	z-index: 99999;
	width: 380px;
	max-width: 46vw;
	aspect-ratio: 16 / 9;
	box-shadow: 0 10px 40px rgba( 0, 0, 0, 0.35 );
}
.tp-sticky-bottom-right { right: 20px; bottom: 20px; }
.tp-sticky-bottom-left { left: 20px; bottom: 20px; }
.tp-sticky-top-right { right: 20px; top: 20px; }
.tp-sticky-top-left { left: 20px; top: 20px; }
.tp-sticky-close {
	position: absolute;
	top: 6px;
	left: 6px;
	z-index: 10;
	width: 24px;
	height: 24px;
	border: 0;
	border-radius: 50%;
	background: rgba( 0, 0, 0, 0.6 );
	color: #fff;
	font-size: 16px;
	line-height: 1;
	cursor: pointer;
}
/* Audio: a proper compact player bar, not a short video box. Art tile on the
   left, controls (progress + buttons) fill the rest — no empty picture area. */
.tp-stage.is-audio {
	aspect-ratio: auto;
	height: auto;
	min-height: 72px;
	background: linear-gradient( 180deg, #232838, #171a22 );
	display: flex;
	align-items: center;
	gap: 12px;
	padding-left: 12px;
	overflow: visible; /* let the settings menu pop out of the short bar */
}
.tp-audio-art {
	width: 48px;
	height: 48px;
	flex-shrink: 0;
	border-radius: 8px;
	overflow: hidden;
	background: rgba( 255, 255, 255, 0.08 );
	color: var( --tp-accent );
	display: flex;
	align-items: center;
	justify-content: center;
	z-index: 2;
}
.tp-audio-art img {
	width: 100%;
	height: 100%;
	-o-object-fit: cover;
	   object-fit: cover;
}
.tp-audio-art svg {
	width: 24px;
	height: 24px;
	fill: currentColor;
}
.tp-stage.is-audio .tp-controls {
	position: static;
	background: none;
	flex: 1;
	min-width: 0;
	padding: 8px 14px 8px 0;
}
.tp-audio-title {
	font-size: 12.5px;
	font-weight: 600;
	color: rgba( 255, 255, 255, 0.92 );
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	margin-bottom: 2px;
}
/* Pseudo-waveform progress bar (audio) */
.tp-stage.is-audio .tp-scrubber {
	padding: 4px 0;
}
.tp-wave {
	position: relative;
	display: flex;
	align-items: center;
	gap: 2px;
	height: 26px;
	width: 100%;
}
.tp-wave-bar {
	flex: 1 1 0;
	min-width: 2px;
	min-height: 3px;
	background: rgba( 255, 255, 255, 0.25 );
	border-radius: 1px;
}
.tp-wave-bar.is-played {
	background: var( --tp-accent );
}

.tp-media-container,
.tp-media {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}
.tp-media {
	-o-object-fit: contain;
	   object-fit: contain;
	background: #000;
}
.tp-media-container iframe {
	width: 100%;
	height: 100%;
	border: 0;
}

/* Audio mode has no picture. The <audio> element the provider builds is
   invisible on its own, but a player still mounted from before the source was
   switched to audio-only — or a provider that only hands back an iframe —
   would otherwise paint video across the bar, behind the waveform.
   `visibility`, not `display`, so nothing about how the media loads or plays
   changes; the cover art is a sibling and is unaffected. */
.tp-stage.is-audio .tp-media,
.tp-stage.is-audio .tp-media-container iframe {
	visibility: hidden;
}

/* Transparent click-shield over embedded players (YouTube/Vimeo): swallows
   pointer events so their in-frame links can't be clicked, while our own
   controls (z-index 5) and big-play button sit above it and stay usable. */
.tp-shield {
	position: absolute;
	inset: 0;
	z-index: 2;
	cursor: pointer;
	background: transparent;
}

.tp-poster {
	position: absolute;
	inset: 0;
	background-size: cover; /* see .tp-facade-poster — the poster fills the frame */
	background-position: center;
	background-repeat: no-repeat;
	background-color: #000;
	z-index: 3;
}

.tp-logo {
	position: absolute;
	max-height: 34px;
	max-width: 120px;
	opacity: 0.9;
	z-index: 4;
	pointer-events: none;
}
.tp-logo img {
	max-height: 34px;
	max-width: 120px;
	display: block;
}
.tp-logo.is-link {
	pointer-events: auto;
	cursor: pointer;
}
.tp-logo,
.tp-logo-top-right { top: 12px; right: 12px; }
.tp-logo-top-left { top: 12px; left: 12px; right: auto; }
.tp-logo-bottom-right { top: auto; bottom: 52px; right: 12px; }
.tp-logo-bottom-left { top: auto; bottom: 52px; left: 12px; right: auto; }

/* ---- caption cue styling (html5-backed providers) ---- */
.tp-stage video::cue {
	color: var( --tp-cap-color, #fff );
	background-color: var( --tp-cap-bg, rgba( 0, 0, 0, 0.75 ) );
	font-size: calc( 1em * var( --tp-cap-scale, 1 ) );
}

/* ---- skins ----
   Audio layout rules live at the END of this file and are written with a
   three-class prefix (.tp-stage.is-audio.tp-audio-*) so they outrank anything
   here on specificity rather than on source order. A skin rule that needs to
   beat them is a bug — fix it there, don't move this block. */
/* modern: floating-feel solid bar, brighter accents, roomier padding */
.tp-skin-modern .tp-controls {
	background: linear-gradient( transparent, rgba( 10, 12, 20, 0.9 ) );
	padding: 8px 14px 12px;
}
.tp-skin-modern .tp-scrubber-track,
.tp-skin-modern .tp-scrubber-segs {
	height: 6px;
}
.tp-skin-modern .tp-btn {
	border-radius: 8px;
}
.tp-skin-modern .tp-bigplay {
	width: var( --tp-bigplay-size, 84px );
	height: var( --tp-bigplay-size, 84px );
}

/* simple: flat thin bar, no gradient wash */
.tp-skin-simple .tp-controls {
	background: rgba( 0, 0, 0, 0.6 );
	padding: 4px 10px 6px;
}
.tp-skin-simple .tp-scrubber {
	padding: 5px 0;
}
.tp-skin-simple .tp-scrubber-thumb {
	width: 10px;
	height: 10px;
}
.tp-skin-simple .tp-bigplay {
	width: var( --tp-bigplay-size, 64px );
	height: var( --tp-bigplay-size, 64px );
}

/* minimal: scrubber + essentials only; secondary controls hidden */
.tp-skin-minimal .tp-controls {
	background: transparent;
	padding: 4px 10px 8px;
}
.tp-skin-minimal .tp-controls-row {
	background: rgba( 0, 0, 0, 0.5 );
	border-radius: 10px;
	padding: 2px 8px;
}
.tp-skin-minimal .tp-time,
.tp-skin-minimal .tp-volume,
.tp-skin-minimal .tp-chapter-now {
	display: none;
}

/* standard: classic opaque deck, square corners on the bar */
.tp-skin-standard .tp-controls {
	background: rgba( 12, 14, 18, 0.96 );
	padding: 6px 12px 8px;
}
.tp-skin-standard .tp-scrubber-track,
.tp-skin-standard .tp-scrubber-segs,
.tp-skin-standard .tp-scrubber-buffered,
.tp-skin-standard .tp-scrubber-played,
.tp-skin-standard .tp-seg {
	border-radius: 0;
}

/* --- floating + ambient: premium looks, and why their CSS is here --- */
/* Free ships everything needed to RENDER the premium looks; Pro ships only the
   code that makes them reachable. So these rules stay in the free stylesheet
   and are simply never matched without Pro: Helper::enforce_pro_limits() resets
   `skin` to `default` before the config reaches the page, so the class that
   would select them is never written. Dead CSS on a free install, and that is
   the intended state — a stylesheet is UI, not the thing being sold.
   Names in TruePlayer\Pro::PREMIUM_SKINS; the picker offers them locked. */

/* floating (pro): detached rounded bar hovering above the bottom edge */
.tp-skin-floating .tp-controls {
	left: 12px;
	right: 12px;
	bottom: 12px;
	border-radius: 14px;
	background: rgba( 15, 17, 26, 0.82 );
	backdrop-filter: blur( 10px );
	padding: 6px 14px 8px;
	box-shadow: 0 8px 28px rgba( 0, 0, 0, 0.35 );
}
.tp-skin-floating .tp-info {
	bottom: 4.6rem;
}

/* ambient (pro): blurred poster glow behind the stage */
.tp-ambient-wrap {
	position: relative;
	width: 100%;
}
.tp-ambient-glow {
	position: absolute;
	inset: -28px;
	background-position: center;
	background-size: cover;
	filter: blur( 36px ) saturate( 1.5 );
	opacity: 0.5;
	border-radius: 24px;
	pointer-events: none;
	z-index: 0;
}
.tp-ambient-wrap .tp-stage {
	position: relative;
	z-index: 1;
}

/* ---- "In this video" drawer: chapters + transcript ---- */
.tp-info {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 3.4rem;
	width: min( 340px, 42% );
	z-index: 6;
	display: flex;
	flex-direction: column;
	background: rgba( 18, 18, 18, 0.94 );
	backdrop-filter: blur( 6px );
	color: #fff;
	border-top-left-radius: var( --tp-radius, 8px );
	overflow: hidden;
	animation: tp-info-in 0.2s ease;
}
@keyframes tp-info-in {
	from {
		transform: translateX( 16px );
		opacity: 0;
	}
	to {
		transform: none;
		opacity: 1;
	}
}
.tp-info-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 8px 6px 8px 12px;
	border-bottom: 1px solid rgba( 255, 255, 255, 0.1 );
	flex-shrink: 0;
}
.tp-info-tabs {
	display: flex;
	gap: 4px;
}
.tp-info-tab {
	background: transparent;
	border: 0;
	color: rgba( 255, 255, 255, 0.6 );
	font-size: 13px;
	font-weight: 600;
	padding: 6px 10px;
	border-radius: 6px;
	cursor: pointer;
}
.tp-info-tab:hover {
	color: #fff;
}
.tp-info-tab.is-active {
	color: #fff;
	background: rgba( 255, 255, 255, 0.14 );
}
.tp-info-close {
	background: transparent;
	border: 0;
	color: rgba( 255, 255, 255, 0.7 );
	font-size: 22px;
	line-height: 1;
	cursor: pointer;
	width: 30px;
	height: 30px;
	border-radius: 6px;
}
.tp-info-close:hover {
	background: rgba( 255, 255, 255, 0.12 );
	color: #fff;
}
.tp-info-body {
	flex: 1;
	overflow-y: auto;
	padding: 6px;
	scrollbar-width: thin;
}
.tp-info-row {
	display: flex;
	gap: 10px;
	width: 100%;
	text-align: left;
	background: transparent;
	border: 0;
	color: #eaeaea;
	padding: 8px 10px;
	border-radius: 8px;
	cursor: pointer;
	font-size: 13px;
	line-height: 1.4;
	align-items: flex-start;
}
.tp-info-row:hover {
	background: rgba( 255, 255, 255, 0.08 );
}
.tp-info-row.is-active {
	background: rgba( 255, 255, 255, 0.14 );
}
.tp-info-row.is-locked {
	opacity: 0.4;
	cursor: not-allowed;
}
.tp-info-time {
	color: var( --tp-accent );
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	flex-shrink: 0;
	min-width: 44px;
}
.tp-info-cue .tp-info-time {
	color: rgba( 255, 255, 255, 0.45 );
	font-weight: 500;
}
.tp-info-cue.is-active .tp-info-time {
	color: var( --tp-accent );
}
.tp-info-label {
	flex: 1;
}
.tp-info-empty {
	color: rgba( 255, 255, 255, 0.6 );
	font-size: 13px;
	padding: 20px 16px;
	text-align: center;
}
.tp-controls .tp-btn.is-active {
	color: var( --tp-accent );
}
@media ( max-width: 520px ) {
	.tp-info {
		width: 100%;
	}
}

/* ---- controls ---- */
.tp-controls {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	padding: 6px 12px 10px;
	background: linear-gradient( transparent, rgba( 0, 0, 0, 0.72 ) );
	transition: opacity 0.25s ease;
	z-index: 5;
}
.tp-stage.is-idle .tp-controls {
	opacity: 0;
	pointer-events: none;
}
.tp-controls-row {
	display: flex;
	align-items: center;
	gap: 8px;
}
.tp-spacer {
	flex: 1;
}
.tp-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	color: #fff;
	background: transparent;
	border: 0;
	border-radius: 6px;
	cursor: pointer;
	padding: 0;
}
.tp-btn:hover {
	background: var(--tp-hover, rgba( 255, 255, 255, 0.15 ));
}
/* The speed button shows text ("1.5\00d7") where the others show a 20px icon,
   so it needs its own type sizing and room to grow past a fixed 34px square. */
.tp-btn.tp-speed {
	width: auto;
	min-width: 34px;
	padding: 0 7px;
	font-size: 12px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	line-height: 1;
}
.tp-btn.tp-speed.is-active {
	color: var( --tp-accent );
}
.tp-time {
	font-size: 12px;
	color: #e5e7eb;
	font-variant-numeric: tabular-nums;
}
/* !important: the player is embedded in arbitrary theme/page markup, and a
   generic host-page reset like `input { width: 100% }` (common in form-
   styling frameworks) otherwise wins the cascade on this specific property
   over a single-class selector — accent-color/cursor aren't touched by that
   kind of rule so they apply fine, but width silently loses, and since this
   sits in a flex row (.tp-controls-row) an unconstrained width stretches it
   across the whole bar. flex is pinned too so it can't grow/shrink either. */
.tp-volume,
.tp-volume:hover,
.tp-volume:focus,
.tp-volume:active {
	width: 74px !important;
	flex: 0 0 74px !important;
	height: 16px; /* comfortable click target; the visible track is drawn thin below */
	cursor: pointer;
	/* Taking manual control of the track/thumb below via the WebKit/Moz
	   pseudo-elements — accent-color only recolors the browser's default
	   chrome (full-size thumb, solid track block), which read as a second,
	   heavier control bar rather than a slim volume slider. */
	-moz-appearance: none;
	     appearance: none;
	-webkit-appearance: none;
    background: transparent;
    background-image: none !important;
    border: 0 !important;
    box-shadow: none !important;
    outline: 0 !important;
}
.tp-volume::-webkit-slider-runnable-track {
	height: 3px;
	border-radius: 2px;
	background: rgba( 255, 255, 255, 0.4 ) !important;
    box-shadow: none !important;
}
.tp-volume::-webkit-slider-thumb {
	-webkit-appearance: none;
	appearance: none;
	width: 0.4rem;
	height: 0.4rem;
	margin-top: -3.5px; /* center the 10px thumb on the 3px track */
	border-radius: 50%;
	background: var( --tp-accent );
	cursor: pointer;
}
.tp-volume::-moz-range-track {
	height: 3px;
	border-radius: 2px;
	background: rgba( 255, 255, 255, 0.3 );
	box-shadow: none !important;
}
.tp-volume::-moz-range-progress {
	height: 8px;
	border-radius: 8px;
	background: var( --tp-accent );
}
.tp-volume::-moz-range-thumb {
	width: 0.3rem !important;
	height: 0.3rem !important;
	border: 0;
	border-radius: 50%;
	background: var( --tp-accent );
	cursor: pointer;
}

/* Narrow players: shed the widest, least-critical controls so the single-row
   control bar never overflows the (overflow:hidden) stage and gets clipped.
   Keyed to the player's own width via the .tp-stage size container. */
@container (max-width: 480px) {
	.tp-controls-row {
		gap: 4px;
	}
	.tp-volume {
		display: none; /* mute button stays */
	}
	.tp-btn {
		width: 30px;
		height: 30px;
	}
	.tp-time {
		font-size: 11px;
	}
}
@container (max-width: 340px) {
	.tp-btn {
		width: 28px;
		height: 28px;
	}
	.tp-btn svg {
		width: 17px;
		height: 17px;
	}
}

/* ---- scrubber ---- */
.tp-scrubber {
	padding: 8px 0;
	cursor: pointer;
	touch-action: none; /* let a pointer drag scrub instead of scrolling the page */
	-webkit-user-select: none;
	   -moz-user-select: none;
	        user-select: none;
}
.tp-scrubber.is-disabled {
	cursor: not-allowed;
}
.tp-scrubber-track {
	position: relative;
	height: 5px;
	background: rgba( 255, 255, 255, 0.28 );
	border-radius: 4px;
}
.tp-scrubber-buffered {
	position: absolute;
	top: 0;
	left: 0;
	height: 100%;
	background: rgba( 255, 255, 255, 0.4 );
	border-radius: 4px;
}
.tp-scrubber-played {
	position: absolute;
	top: 0;
	left: 0;
	height: 100%;
	background: var(--tp-accent);
	border-radius: 4px;
}
.tp-scrubber-thumb {
	position: absolute;
	top: 50%;
	width: 13px;
	height: 13px;
	background: #fff;
	border-radius: 50%;
	transform: translate( -50%, -50% );
	box-shadow: 0 0 4px rgba( 0, 0, 0, 0.5 );
}
.tp-scrubber-lockline {
	position: absolute;
	top: -3px;
	bottom: -3px;
	width: 2px;
	background: #f59e0b;
	transform: translateX( -1px );
}
.tp-chapter-marker {
	position: absolute;
	top: 50%;
	width: 3px;
	height: 11px;
	background: #fff;
	transform: translate( -50%, -50% );
	border-radius: 1px;
	opacity: 0.85;
}

/* ---- YouTube-style segmented chapters ---- */
.tp-scrubber-segs {
	position: relative;
	height: 5px;
	transition: height 0.1s ease;
}
.tp-scrubber:hover .tp-scrubber-segs {
	height: 7px;
}
.tp-seg {
	position: absolute;
	top: 0;
	height: 100%;
	background: rgba( 255, 255, 255, 0.28 );
	border-radius: 3px;
	overflow: hidden;
}
.tp-seg-buffered {
	position: absolute;
	left: 0;
	top: 0;
	height: 100%;
	background: rgba( 255, 255, 255, 0.4 );
}
.tp-seg-played {
	position: absolute;
	left: 0;
	top: 0;
	height: 100%;
	background: var(--tp-accent);
}
.tp-chapter-tip {
	position: absolute;
	bottom: 22px;
	transform: translateX( -50% );
	background: rgba( 17, 24, 39, 0.95 );
	color: #fff;
	font-size: 12px;
	padding: 4px 9px;
	border-radius: 6px;
	white-space: nowrap;
	pointer-events: none;
	max-width: 240px;
	overflow: hidden;
	text-overflow: ellipsis;
}
.tp-chapter-now {
	font-size: 12px;
	color: #d1d5db;
	max-width: 180px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* ---- settings menu ---- */
.tp-menu-wrap {
	position: relative;
}
.tp-menu {
	position: absolute;
	bottom: 42px;
	right: 0;
	min-width: 150px;
	max-height: 260px;
	overflow-y: auto;
	background: rgba( 17, 24, 39, 0.97 );
	border-radius: 8px;
	padding: 6px;
	box-shadow: 0 6px 24px rgba( 0, 0, 0, 0.4 );
}
.tp-menu-section {
	font-size: 10px;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: #9ca3af;
	padding: 6px 8px 2px;
}
.tp-menu-item {
	display: flex;
	align-items: center;
	gap: 6px;
	width: 100%;
	text-align: left;
	background: transparent;
	border: 0;
	color: #e5e7eb;
	padding: 7px 8px;
	border-radius: 6px;
	font-size: 13px;
	cursor: pointer;
}
.tp-menu-item:hover {
	background: rgba( 255, 255, 255, 0.1 );
}
.tp-menu-item.is-active {
	color: #fff;
	font-weight: 600;
}
.tp-menu-item.is-active::after {
	/* Masked SVG tick rather than a text glyph, so it renders identically
	   everywhere and still takes the player's accent colour. */
	content: '';
	width: 13px;
	height: 13px;
	margin-left: auto;
	flex: none;
	background-color: var(--tp-accent);
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%23fff%27 stroke-width=%273%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M5 12.5l4.5 4.5L19 7.5%27/%3E%3C/svg%3E") no-repeat center / contain;
	mask: url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%23fff%27 stroke-width=%273%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpath d=%27M5 12.5l4.5 4.5L19 7.5%27/%3E%3C/svg%3E") no-repeat center / contain;
}

/* ---- timed text overlays ---- */
.tp-text-overlay {
	position: absolute;
	z-index: 4;
	max-width: 60%;
	padding: 8px 14px;
	border-radius: 8px;
	color: #fff;
	font-size: 14px;
	line-height: 1.45;
	pointer-events: none;
	display: flex;
	flex-direction: column;
	gap: 2px;
	animation: tp-cta-in 0.25s ease;
}
.tp-text-overlay-title {
	font-size: 15px;
	font-weight: 700;
}
.tp-pos-top-left { top: 14px; left: 14px; }
.tp-pos-top-center { top: 14px; left: 50%; transform: translateX( -50% ); text-align: center; }
.tp-pos-top-right { top: 14px; right: 14px; text-align: right; }
.tp-pos-middle-left { top: 50%; left: 14px; transform: translateY( -50% ); }
.tp-pos-middle-center { top: 50%; left: 50%; transform: translate( -50%, -50% ); text-align: center; }
.tp-pos-middle-right { top: 50%; right: 14px; transform: translateY( -50% ); text-align: right; }
.tp-pos-bottom-left { bottom: 64px; left: 14px; }
.tp-pos-bottom-center { bottom: 64px; left: 50%; transform: translateX( -50% ); text-align: center; }
.tp-pos-bottom-right { bottom: 64px; right: 14px; text-align: right; }

/* ---- action bar ---- */
.tp-actionbar {
	position: absolute;
	left: 0;
	right: 0;
	z-index: 5;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 12px;
	padding: 8px 14px;
	background: var( --tp-accent );
	color: #fff;
	font-size: 14px;
	font-weight: 500;
}
.tp-actionbar-top { top: 0; }
.tp-actionbar-bottom { bottom: 0; }
/* When the control bar is visible, lift a bottom action bar above it. */
.tp-stage:not( .is-idle ) .tp-actionbar-bottom {
	bottom: 3.6rem;
}
.tp-stage.is-audio .tp-actionbar {
	display: none; /* the compact audio bar has no room for it */
}
.tp-actionbar-text {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.tp-actionbar-btn {
	flex-shrink: 0;
	background: rgba( 255, 255, 255, 0.18 );
	border: 1px solid rgba( 255, 255, 255, 0.5 );
	color: #fff;
	border-radius: 6px;
	padding: 4px 14px;
	font-size: 13px;
	font-weight: 600;
	text-decoration: none;
	transition: background 0.15s ease;
}
.tp-actionbar-btn:hover {
	background: rgba( 255, 255, 255, 0.3 );
	color: #fff;
}

/* ---- description under the player ---- */
.tp-description {
	margin-top: 12px;
	font-size: 14.5px;
	line-height: 1.6;
	color: inherit;
}

/* ---- interactive layers (pro) ---- */
.tp-layers {
	position: absolute;
	inset: 0;
	z-index: 4;
	pointer-events: none;
}
/* Raised over the big play button (z-index 5) while an email form is showing,
   so the form reads as the thing being asked of the viewer rather than sitting
   behind the button. The container still passes pointer events through
   everywhere except the layer itself, so the control bar stays usable. */
.tp-layers.is-blocking {
	z-index: 6;
}
.tp-layer {
	pointer-events: auto;
}
.tp-hotspot {
	position: absolute;
	display: block;
	cursor: pointer;
	border-radius: 8px;
}
.tp-hotspot-pulse {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 16px;
	height: 16px;
	margin: -8px 0 0 -8px;
	border-radius: 50%;
	background: var( --tp-accent );
	box-shadow: 0 0 0 0 var( --tp-accent );
	animation: tp-hotspot-pulse 1.8s infinite;
}
@keyframes tp-hotspot-pulse {
	0% { box-shadow: 0 0 0 0 rgba( 255, 255, 255, 0.5 ); }
	70% { box-shadow: 0 0 0 14px rgba( 255, 255, 255, 0 ); }
	100% { box-shadow: 0 0 0 0 rgba( 255, 255, 255, 0 ); }
}
.tp-hotspot-tip {
	position: absolute;
	bottom: calc( 50% + 18px );
	left: 50%;
	transform: translateX( -50% );
	background: rgba( 17, 24, 39, 0.95 );
	color: #fff;
	font-size: 12px;
	padding: 4px 9px;
	border-radius: 6px;
	white-space: nowrap;
	opacity: 0;
	transition: opacity 0.15s ease;
	pointer-events: none;
}
.tp-hotspot:hover .tp-hotspot-tip {
	opacity: 1;
}
.tp-banner {
	position: absolute;
	max-width: 70%;
}
.tp-banner img {
	max-width: 100%;
	max-height: 110px;
	display: block;
	border-radius: 8px;
}
.tp-shortcode-layer {
	position: absolute;
	max-width: 80%;
	background: rgba( 255, 255, 255, 0.96 );
	color: #111827;
	border-radius: 10px;
	padding: 14px 16px;
}
/* Editor preview only: PHP renders shortcodes, and the preview builds its
   config in the browser, so there is no html to show. Naming the shortcode
   beats an empty stage that reads as a broken feature. */
.tp-shortcode-layer.is-placeholder {
	background: rgba( 17, 24, 39, 0.88 );
	color: #e5e7eb;
	border: 1px dashed rgba( 229, 231, 235, 0.45 );
	text-align: center;
}
.tp-shortcode-layer.is-placeholder code {
	display: block;
	font-size: 12px;
	word-break: break-all;
	color: #fff;
}
.tp-shortcode-layer.is-placeholder span {
	display: block;
	margin-top: 6px;
	font-size: 11px;
	opacity: 0.7;
}
/* ---- email form ----
   One form, one appearance. The mode decides only where it sits and whether it
   blocks: the gate is centred on the dimmed video, the inline panel is placed
   over the picture and lets playback continue. Nothing below is per-mode, so
   switching Mode cannot change how the form looks — and a colour set on the
   Style tab means the same thing either way. */
.tp-emailform {
	display: flex;
	flex-direction: column;
	gap: 10px;
	box-sizing: border-box;
	margin: 0;
	width: 100%;
	max-width: 420px;
	padding: 22px;
	border-radius: 12px;
	background: var( --tp-of-bg, #fff );
	color: #111827;
	text-align: center;
	box-shadow: 0 12px 40px rgba( 0, 0, 0, 0.3 );
}

/* Gate: centred by .tp-overlay. It covers the whole stage, so it has to fit
   inside it — a short player (21:9, or the scaled editor preview) would
   otherwise spill the form past the picture with its button out of reach. */
.tp-emailform-card {
	max-height: 90%;
	overflow-y: auto;
}

/* Inline: placed over the picture by tp-pos-*. */
.tp-emailform-panel {
	position: absolute;
	max-width: min( 420px, 88% );
}

.tp-emailform-title {
	margin: 0;
	font-weight: 700;
	color: var( --tp-of-title, inherit );
}
/* Scoped to the stage on purpose: the admin styles headings inside `.tp-admin`
   and a theme will style them on the front end, either of which outranks a bare
   class — which is why the headline colour looked dead in the preview. */
.tp-stage .tp-emailform-title {
	font-size: 19px;
	margin-bottom: 6px;
}

.tp-emailform-desc {
	margin: 0 0 4px;
	font-size: 14px;
	color: var( --tp-of-muted, #6b7280 );
}

.tp-emailform-input {
	width: 100%;
	min-width: 0;
	box-sizing: border-box;
	font-size: 14px;
	border-radius: 8px;
	padding: 11px 12px;
	background: #f3f4f6;
	border: 1px solid #d1d5db;
	color: #111827;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/* Hover previews the focus state rather than a grey step towards it — the same
   rule the admin's own fields follow. Both track the button colour, so a
   restyled form gets matching field states. */
.tp-emailform-input:hover,
.tp-emailform-input:focus {
	outline: none;
	border-color: var( --tp-of-btn-bg, var( --tp-accent ) );
}
.tp-emailform-input:focus {
	box-shadow: 0 0 0 3px rgba( 0, 107, 255, 0.15 );
}
.tp-emailform-input::-moz-placeholder {
	color: var( --tp-of-muted, #9ca3af );
	opacity: 0.75;
}
.tp-emailform-input::placeholder {
	color: var( --tp-of-muted, #9ca3af );
	opacity: 0.75;
}

/* Email + submit share a line; a name field, when asked for, stays above it. */
.tp-emailform-row {
	display: flex;
	align-items: stretch;
	gap: 8px;
}
.tp-emailform-submit {
	flex: 0 0 auto;
	background: var( --tp-of-btn-bg, var( --tp-accent, #4f46e5 ) );
	color: var( --tp-of-btn-text, #fff );
	border: 0;
	border-radius: var( --tp-of-btn-radius, 8px );
	padding: 11px 18px;
	font-size: 14px;
	font-weight: 600;
	white-space: nowrap;
	cursor: pointer;
}
.tp-emailform-submit:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}
/* Narrow players can't hold both on one line without squeezing the field to
   nothing, so they stack instead. */
@container (max-width: 420px) {
	.tp-emailform-row {
		flex-direction: column;
	}
	.tp-emailform-submit {
		width: 100%;
	}
}

.tp-emailform-error {
	margin: 0;
	font-size: 13px;
	color: #dc2626;
}

.tp-emailform-thanks {
	margin: 0;
	font-weight: 600;
}

.tp-emailform-skip {
	align-self: center;
	background: none;
	border: 0;
	padding: 0;
	font-size: 13px;
	text-decoration: underline;
	cursor: pointer;
	color: var( --tp-of-muted, #6b7280 );
}

/* ---- dynamic watermark (pro) ---- */
.tp-watermark {
	position: absolute;
	top: 12%;
	left: 8%;
	z-index: 4;
	color: #fff;
	font-size: 12px;
	letter-spacing: 0.03em;
	text-shadow: 0 1px 3px rgba( 0, 0, 0, 0.8 );
	pointer-events: none;
	-webkit-user-select: none;
	   -moz-user-select: none;
	        user-select: none;
	white-space: nowrap;
}
.tp-watermark.is-drifting {
	animation: tp-wm-drift 46s linear infinite;
}
@keyframes tp-wm-drift {
	0% { top: 12%; left: 8%; }
	25% { top: 70%; left: 62%; }
	50% { top: 24%; left: 70%; }
	75% { top: 76%; left: 12%; }
	100% { top: 12%; left: 8%; }
}

/* ---- overlays ---- */
.tp-overlay {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba( 0, 0, 0, 0.6 );
	z-index: 6;
	padding: 16px;
}

/* ---- popup (lightbox) ---- */
.trueplayer-popup {
	display: inline-block;
}
.trueplayer-popup-trigger {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	background: var( --tp-accent, #008dff );
	color: #fff;
	border: 0;
	border-radius: 8px;
	padding: 10px 18px;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
	font-family: inherit;
	transition: filter 0.15s ease;
}
.trueplayer-popup-trigger:hover {
	filter: brightness( 1.08 );
}
.tp-popup-backdrop {
	position: fixed;
	inset: 0;
	z-index: 100000;
	background: rgba( 0, 0, 0, 0.82 );
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
	animation: tp-cta-in 0.18s ease;
}
.tp-popup-dialog {
	position: relative;
	width: min( 900px, 92vw );
}
.tp-popup-close {
	position: absolute;
	top: -38px;
	right: 0;
	background: none;
	border: 0;
	color: #fff;
	font-size: 30px;
	line-height: 1;
	cursor: pointer;
	opacity: 0.85;
}
.tp-popup-close:hover {
	opacity: 1;
}
.tp-popup-player {
	width: 100%;
}

/* ---- CTA / end-screen overlay ---- */
.tp-cta-card {
	position: relative;
	background: #fff;
	color: #111827;
	border-radius: 14px;
	padding: 28px 28px 24px;
	max-width: 460px;
	width: 100%;
	text-align: center;
	box-shadow: 0 12px 40px rgba( 0, 0, 0, 0.35 );
	animation: tp-cta-in 0.2s ease;
}
@keyframes tp-cta-in {
	from { transform: translateY( 8px ) scale( 0.98 ); opacity: 0; }
	to { transform: none; opacity: 1; }
}
.tp-cta-close {
	position: absolute;
	top: 8px;
	right: 10px;
	background: none;
	border: 0;
	font-size: 24px;
	line-height: 1;
	color: #9ca3af;
	cursor: pointer;
}
.tp-cta-close:hover { color: #374151; }
.tp-cta-img {
	max-height: 96px;
	max-width: 100%;
	margin: 0 auto 14px;
	border-radius: 10px;
	-o-object-fit: cover;
	   object-fit: cover;
}
.tp-cta-title {
	font-size: 20px;
	font-weight: 700;
	margin: 0 0 6px;
}
.tp-cta-text {
	font-size: 14px;
	line-height: 1.5;
	color: #4b5563;
	margin: 0 0 18px;
}
.tp-cta-actions {
	display: flex;
	gap: 10px;
	justify-content: center;
	flex-wrap: wrap;
}
.tp-cta-btn {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	background: var( --tp-accent );
	color: #fff;
	font-size: 14px;
	font-weight: 600;
	padding: 10px 20px;
	border-radius: 8px;
	border: 0;
	cursor: pointer;
	text-decoration: none;
	transition: filter 0.15s ease;
}
.tp-cta-btn:hover { filter: brightness( 1.08 ); }
.tp-cta-secondary {
	background: #f3f4f6;
	color: #374151;
}
.tp-bigplay {
	position: absolute;
	inset: 0;
	margin: auto;
	/* Size is author-controllable via --tp-bigplay-size; each skin keeps its own
	   fallback when the control is left on "Auto". */
	width: var( --tp-bigplay-size, 78px );
	height: var( --tp-bigplay-size, 78px );
	border-radius: 50%;
	border: 0;
	/* Accent-driven on every skin (matches the poster facade button). Skins may
	   still override size/shape, but the accent color stays. */
	background: var( --tp-accent, #4f46e5 );
	color: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	z-index: 5;
}
/* Icon scales with the button so larger sizes stay proportional. */
.tp-bigplay svg {
	width: 48%;
	height: 48%;
}
.tp-bigplay:hover {
	filter: brightness( 1.08 );
}

.tp-lock-card,
.tp-quiz-card {
	background: #fff;
	color: #111827;
	border-radius: 12px;
	padding: 24px;
	max-width: 480px;
	width: 100%;
	max-height: 90%;
	overflow-y: auto;
	text-align: center;
	box-shadow: 0 12px 40px rgba( 0, 0, 0, 0.3 );
}
.tp-lock-icon {
	display: flex;
	justify-content: center;
	margin-bottom: 4px;
	opacity: 0.9;
}
.tp-quiz-card {
	text-align: left;
}
.tp-quiz-title {
	margin: 0 0 14px;
	font-size: 18px;
	font-weight: 700;
}
.tp-quiz-q {
	margin-bottom: 16px;
}
.tp-quiz-prompt {
	font-weight: 600;
	margin: 0 0 8px;
}
.tp-quiz-num {
	color: var(--tp-accent);
}
.tp-quiz-opts {
	display: flex;
	flex-direction: column;
	gap: 6px;
}
.tp-quiz-opt {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 9px 12px;
	border: 1px solid #e5e7eb;
	border-radius: 8px;
	cursor: pointer;
}
.tp-quiz-opt.is-picked {
	border-color: var(--tp-accent);
	background: rgba( 79, 70, 229, 0.06 );
}
.tp-quiz-feedback {
	display: flex;
	align-items: center;
	gap: 6px;
	font-weight: 600;
	margin: 8px 0;
}
.tp-quiz-feedback.tp-pass {
	color: #16a34a;
}
.tp-quiz-feedback.tp-fail {
	color: #dc2626;
}
/* The final pass/fail/pending outcome of a QuizPress-sourced quiz — given
   its own banner, not just another feedback line, so it reads as the one
   unambiguous result rather than blending in with in-progress messages. */
.tp-quiz-verdict {
	font-size: 15px;
	padding: 12px 14px;
	border-radius: 8px;
	background: rgba( 0, 0, 0, 0.04 );
}
.tp-quiz-verdict.tp-pass {
	background: rgba( 22, 163, 74, 0.1 );
}
.tp-quiz-verdict.tp-fail {
	background: rgba( 220, 38, 38, 0.08 );
}
.tp-quiz-submit {
	margin-top: 8px;
	background: var(--tp-accent);
	color: #fff;
	border: 0;
	border-radius: 8px;
	padding: 11px 20px;
	font-weight: 600;
	cursor: pointer;
}
.tp-quiz-submit:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}

/* A QuizPress-sourced quiz's own answer widgets (images, matching pairs,
   graphs, …) need real room — wider than the compact native quiz card. */
.tp-quiz--quizpress .tp-quiz-card {
	max-width: 680px;
}
.tp-quiz-qp-progress {
	font-size: 12px;
	font-weight: 600;
	color: var(--tp-accent);
	margin: 0 0 8px;
}
.tp-quiz-qp-widget {
	margin: 12px 0;
}
.tp-quiz-qp-nav {
	display: flex;
	justify-content: space-between;
	gap: 8px;
	margin-top: 8px;
}
.tp-quiz-qp-prev {
	background: transparent;
	color: #374151;
	border: 1px solid #e5e7eb;
	border-radius: 8px;
	padding: 11px 20px;
	font-weight: 600;
	cursor: pointer;
}
.tp-quiz-qp-prev:disabled {
	opacity: 0.5;
	cursor: not-allowed;
}
.tp-quiz-qp-start p {
	margin: 0 0 8px;
	font-size: 14px;
	color: #374151;
}

/* ---- opt-in / subscribe ---- */
.tp-optin-card {
	background: #fff;
	color: #111827;
	border-radius: 12px;
	padding: 26px;
	max-width: 420px;
	width: 100%;
	text-align: center;
	box-shadow: 0 12px 40px rgba( 0, 0, 0, 0.3 );
}
.tp-optin-title {
	margin: 0 0 8px;
	font-size: 19px;
	font-weight: 700;
}
.tp-optin-desc {
	margin: 0 0 16px;
	color: #6b7280;
	font-size: 14px;
}
.tp-optin-input {
	width: 100%;
	box-sizing: border-box;
	padding: 11px 12px;
	margin-bottom: 10px;
	border: 1px solid #d1d5db;
	border-radius: 8px;
	font-size: 14px;
}
.tp-optin-input:focus {
	outline: none;
	border-color: var(--tp-accent);
}
.tp-optin-error {
	color: #dc2626;
	font-size: 13px;
	margin: 0 0 10px;
}
.tp-optin-skip {
	display: block;
	margin: 12px auto 0;
	background: none;
	border: 0;
	color: #6b7280;
	font-size: 13px;
	text-decoration: underline;
	cursor: pointer;
}

/* ---- spinner ---- */
.tp-spinner {
	position: absolute;
	inset: 0;
	margin: auto;
	width: 44px;
	height: 44px;
	border: 4px solid rgba( 255, 255, 255, 0.25 );
	border-top-color: #fff;
	border-radius: 50%;
	animation: tp-spin 0.8s linear infinite;
	z-index: 5;
}
@keyframes tp-spin {
	to {
		transform: rotate( 360deg );
	}
}

/* ---- playlists ---- */
.trueplayer-playlist {
	--tp-accent: #4f46e5;
	--tp-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
	width: 100%;
	font-family: var( --tp-font );
}
/* Query the playlist's own width, not the viewport — the video must stack the
   list below it whenever the container (not the screen) is narrow, e.g. inside
   a narrow content column, sidebar, or page-builder cell. */
.tp-pl {
	container-type: inline-size;
	width: 100%;
}
.tp-pl-title {
	font-size: 18px;
	font-weight: 600;
	margin-bottom: 12px;
	color: #111827;
}
/* Cap the stage the way the standalone embed does — but as a *max*, not a
   hard width. A fixed width overflows any content column narrower than the cap
   (a theme's column is commonly ~650px), which is what pushed the sidebar list
   out of the row entirely. */
.tp-pl-main {
	width: 100%;
	max-width: min(960px, calc((100vh - 100px) * 16 / 9));
}
.tp-pl-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
}
.tp-pl-sidebar .tp-pl-body {
	display: flex;
	gap: 16px;
	align-items: flex-start;
	justify-content: center;
	width: 100%;
	margin: 0 auto;
}
/* 450px stage. Kept as a shrinkable basis rather than a hard `width` so a
   content column narrower than 450 + gap + list can't be overflowed — that
   fixed width is what broke this layout in the first place. `min-width: 0` is
   required or the video refuses to shrink below its intrinsic size. */
.tp-pl-sidebar .tp-pl-main {
	flex: 0 1 450px;
	max-width: 450px;
	min-width: 0;
}
.tp-pl-sidebar .tp-pl-list {
	/* Basis 0 so the list claims only the room the 450px stage leaves, rather
	   than competing with it for width and shrinking it below 450. The floor
	   makes the stage yield instead of starving the list in a mid-width column;
	   the cap stops a wide container handing the list half the row. */
	flex: 1 1 0;
	min-width: 150px;
	max-width: 300px;
	gap: 6px;
	max-height: 70vh;
	overflow-y: auto;
	padding-right: 4px;
}
.tp-pl-grid .tp-pl-body {
	display: flex;
	flex-direction: column;
	gap: 16px;
}
.tp-pl-grid .tp-pl-list {
	display: grid;
	grid-template-columns: repeat( auto-fill, minmax( 160px, 1fr ) );
	gap: 12px;
}
.tp-pl-item {
	display: flex;
	gap: 10px;
	align-items: center;
	text-align: left;
	background: transparent;
	border: 1px solid transparent;
	border-radius: 8px;
	padding: 6px;
	cursor: pointer;
	color: #1f2937;
	width: 100%;
}
.tp-pl-item:hover {
	background: rgba( 0, 0, 0, 0.04 );
}
/* Clicking an item leaves it focused, and a theme's default button ring on a
   picked row reads as a rendering glitch — drop it. `:focus-visible` then puts
   the ring back for keyboard navigation only, so arrowing/tabbing through the
   list still shows where you are. */
.tp-pl-item:focus {
	outline: none;
}
.tp-pl-item:focus-visible {
	outline: 2px solid var( --tp-accent );
	outline-offset: 2px;
}
.tp-pl-item.is-active {
	background: rgba( 0, 0, 0, 0.06 );
	border-color: var(--tp-accent);
}
/* Compact icon used in the sidebar list (keeps rows slim vs. a poster thumb). */
.tp-pl-icon {
	width: 30px;
	height: 30px;
	flex-shrink: 0;
	border-radius: 6px;
	background: rgba( 0, 0, 0, 0.06 );
	color: #4b5563;
	display: flex;
	align-items: center;
	justify-content: center;
}
.tp-pl-icon svg {
	width: 15px;
	height: 15px;
	fill: currentColor;
}
.tp-pl-item.is-active .tp-pl-icon {
	background: var( --tp-accent );
	color: #fff;
}
.tp-pl-thumb {
	width: 72px;
	height: 44px;
	flex-shrink: 0;
	border-radius: 6px;
	background: #111827 center/cover no-repeat;
	color: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 12px;
}
.tp-pl-item-title {
	font-size: 13px;
	line-height: 1.3;
}
.tp-pl-grid .tp-pl-item {
	flex-direction: column;
	align-items: stretch;
	gap: 6px;
}
.tp-pl-grid .tp-pl-thumb {
	width: 100%;
	height: 96px;
}
/* ---- sidebar rows ---- */
.tp-pl-sidebar .tp-pl-item {
	gap: 12px;
	padding: 8px 10px;
	border-radius: 10px;
}
.tp-pl-sidebar .tp-pl-item.is-active {
	background: rgba( 0, 0, 0, 0.06 );
	border-color: var( --tp-accent );
}
.tp-pl-sidebar .tp-pl-icon {
	width: 28px;
	height: 28px;
	border-radius: 8px;
	background: rgba( 0, 0, 0, 0.06 );
	color: #111827;
}
.tp-pl-sidebar .tp-pl-icon svg {
	width: 13px;
	height: 13px;
}
.tp-pl-sidebar .tp-pl-item-title {
	font-size: 14px;
	font-weight: 500;
	line-height: 1.35;
	color: #111827;
	/* A long title wraps to two lines instead of stretching the row. */
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}
@container ( max-width: 520px ) {
	.tp-pl-sidebar .tp-pl-body {
		flex-direction: column;
		align-items: stretch; /* full-width video when stacked */
	}
	/* Stacked, the body is a COLUMN flex container — flex-basis maps to
	   HEIGHT, so the row-mode `flex: 1 1 0` collapsed this list to 0px tall
	   (items clipped, area looked empty) and `flex: 0 1 450px` gave the
	   stage a 450px height basis. Reset both to content sizing. */
	.tp-pl-sidebar .tp-pl-main {
		flex: 0 0 auto;
		width: 100%;
		max-width: none;
	}
	.tp-pl-sidebar .tp-pl-list {
		flex: 0 0 auto;
		width: 100%;
		max-width: none;
		min-width: 0;
		flex-direction: row;
		overflow-x: auto;
		max-height: none;
	}
	/* Stacked, the rows scroll sideways — size each to its content instead
	   of letting them share the width and truncate to a few characters. */
	.tp-pl-sidebar .tp-pl-item {
		flex: 0 0 auto;
		width: auto;
		max-width: 220px;
	}
	.tp-pl-sidebar .tp-pl-item-title {
		-webkit-line-clamp: 1;
		white-space: nowrap;
	}
}
/* Fallback for browsers without container queries: stack on a narrow viewport. */
@supports not ( container-type: inline-size ) {
	@media ( max-width: 520px ) {
		.tp-pl-sidebar .tp-pl-body {
			flex-direction: column;
			align-items: stretch;
		}
		/* Stacked, the body is a COLUMN flex container — flex-basis maps to
		   HEIGHT, so the row-mode `flex: 1 1 0` collapsed this list to 0px tall
		   (items clipped, area looked empty) and `flex: 0 1 450px` gave the
		   stage a 450px height basis. Reset both to content sizing. */
		.tp-pl-sidebar .tp-pl-main {
			flex: 0 0 auto;
			width: 100%;
			max-width: none;
		}
		.tp-pl-sidebar .tp-pl-list {
			flex: 0 0 auto;
			width: 100%;
			max-width: none;
			min-width: 0;
			flex-direction: row;
			overflow-x: auto;
			max-height: none;
		}
		/* Stacked, the rows scroll sideways — size each to its content instead
		   of letting them share the width and truncate to a few characters. */
		.tp-pl-sidebar .tp-pl-item {
			flex: 0 0 auto;
			width: auto;
			max-width: 220px;
		}
		.tp-pl-sidebar .tp-pl-item-title {
			-webkit-line-clamp: 1;
			white-space: nowrap;
		}
	}
}

.tp-stage:fullscreen {
	border-radius: 0;
}
.tp-stage:fullscreen .tp-media,
.tp-stage:fullscreen .tp-media-container {
	-o-object-fit: contain;
	   object-fit: contain;
}

/* Timed content region (pro): swaps below the player with the timeline. */
.tp-timed-content {
	margin-top: 12px;
	padding: 14px 16px;
	border: 1px solid var(--tp-line, #e5e7eb);
	border-radius: var(--tp-radius, 8px);
	background: var(--tp-timed-bg, rgba(0, 0, 0, 0.02));
	animation: tp-timed-in 0.25s ease;
}
@keyframes tp-timed-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ==========================================================================
   Audio layouts — MUST STAY LAST IN THIS FILE.

   Every rule below carries a three-class prefix (.tp-stage.is-audio.tp-audio-*
   = specificity 0-4-0) so it beats the skin rules (.tp-skin-x .tp-y = 0-2-0)
   on specificity, not on source order. The base audio block further up this
   file wins by order alone, which is fragile — anything added between it and
   the skins would silently lose. These do not have that problem.

   Skins were written for a 16:9 picture; the ones whose rules are actively
   wrong inside a short bar are neutralised here by name rather than left to
   cancel out as a side effect of some other rule.
   ========================================================================== */

/* --- skin neutralisers (audio, any layout) --- */

/* `floating` detaches the bar and pins it inset from the stage edges. Those
   offsets only do nothing today because .tp-stage.is-audio .tp-controls sets
   position:static; say so explicitly so a future position change can't
   resurrect a bar floating outside a 72px box. */
.tp-stage.is-audio .tp-controls {
	left: auto;
	right: auto;
	bottom: auto;
}

/* `minimal` paints a translucent pill around the control row — sensible over
   a picture, but inside an audio bar it reads as a stray button group. */
.tp-stage.is-audio .tp-controls-row {
	background: none;
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border-radius: 0;
	padding: 0;
}

/* --- compact: the default bar (art tile left, controls right) --- */
.tp-stage.is-audio.tp-audio-compact {
	flex-direction: row;
}
.tp-stage.is-audio.tp-audio-compact .tp-controls {
	min-width: 0;
}

/* --- card: large cover art above a stacked title / scrubber / buttons --- */
.tp-stage.is-audio.tp-audio-card {
	flex-direction: column;
	align-items: stretch;
	gap: 14px;
	min-height: 0;
	padding: 16px;
}
/* A square that is min(stage content width, 260px), centred.
   Capping the WIDTH is what keeps it square: capping max-height instead lets
   the 100% width win and letterboxes the cover art into a wide, short strip. */
.tp-stage.is-audio.tp-audio-card .tp-audio-art {
	width: 100%;
	max-width: 260px;
	height: auto;
	aspect-ratio: 1 / 1;
	align-self: center;
	border-radius: 12px;
}
.tp-stage.is-audio.tp-audio-card .tp-audio-art img {
	-o-object-fit: cover;
	   object-fit: cover;
}
.tp-stage.is-audio.tp-audio-card .tp-audio-art svg {
	width: 38px;
	height: 38px;
}
.tp-stage.is-audio.tp-audio-card .tp-controls {
	padding: 0;
	flex: none;
}
/* Room to breathe once the bar is no longer a single 72px strip. */
.tp-stage.is-audio.tp-audio-card .tp-audio-title {
	font-size: 15px;
	white-space: normal;
	margin-bottom: 6px;
}

/* --- minimal: play button + waveform, nothing else --- */
/* Keeps the base audio background. It must NOT go transparent: every control
   in the bar is white (.tp-btn colour, the waveform's rgba(255,255,255,…)), so
   on any light surface — the editor's preview panel, a light theme — a
   transparent bar renders as an empty white box. "Minimal" here means fewer
   parts (no art, title, time or volume) and a shorter bar, not no surface. */
.tp-stage.is-audio.tp-audio-minimal {
	min-height: 56px;
	padding-left: 0;
	gap: 0;
}
.tp-stage.is-audio.tp-audio-minimal .tp-audio-art,
.tp-stage.is-audio.tp-audio-minimal .tp-audio-title,
.tp-stage.is-audio.tp-audio-minimal .tp-time,
.tp-stage.is-audio.tp-audio-minimal .tp-volume {
	display: none;
}
/* One row: the buttons sit left of the scrubber rather than under it. The
   children are reordered rather than re-rendered, so Controls.jsx stays a
   single tree for every layout. */
.tp-stage.is-audio.tp-audio-minimal .tp-controls {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 12px;
}
.tp-stage.is-audio.tp-audio-minimal .tp-controls-row {
	order: 1;
	width: auto;
	flex: none;
}
.tp-stage.is-audio.tp-audio-minimal .tp-scrubber {
	order: 2;
	flex: 1;
	min-width: 0;
}
/* The spacer exists to push the right-hand button group away from the left
   one; with the row shrunk to its content it would just add dead space. */
.tp-stage.is-audio.tp-audio-minimal .tp-spacer {
	display: none;
}

/* --- podcast (pro): a show, not a strip --- */
/* Here for the same reason floating and ambient are: free renders the premium
   UI, Pro unlocks it. Without Pro, enforce_pro_limits() has already rewritten
   `audioLayout` to `compact`, so `tp-audio-podcast` is never on the stage.

   Compact is a 72px bar with a 48px art tile — right for "a file is playing",
   too cramped for an episode with a name. This gives the art and the title the
   room a show needs, and is the reason podcast is a layout at all rather than
   compact with some buttons switched on. */
.tp-stage.is-audio.tp-audio-podcast {
	flex-direction: row;
	min-height: 96px;
	gap: 14px;
	padding: 14px 16px;
}
.tp-stage.is-audio.tp-audio-podcast .tp-audio-art {
	width: 68px;
	height: 68px;
	flex: none;
	border-radius: 10px;
}
.tp-stage.is-audio.tp-audio-podcast .tp-audio-art svg {
	width: 26px;
	height: 26px;
}
.tp-stage.is-audio.tp-audio-podcast .tp-audio-title {
	font-size: 15px;
	margin-bottom: 8px;
}
.tp-stage.is-audio.tp-audio-podcast .tp-controls {
	min-width: 0;
	padding: 0;
}
.tp-stage.is-audio.tp-audio-podcast .tp-controls-row {
	gap: 10px;
}

/* --- audiobook (pro): the transport, centred and enlarged --- */
/* A listener crosses hours with these buttons and reaches for the same two
   over and over, so the skips and play sit in the middle of the bar at a size
   worth aiming at, instead of tucked into the left corner beside everything
   else. The spacer goes with them: it exists to push the right-hand group
   away, and there is no left and right group here. */
.tp-stage.is-audio.tp-audio-audiobook {
	flex-direction: row;
	min-height: 88px;
	gap: 14px;
	padding: 12px 16px;
}
.tp-stage.is-audio.tp-audio-audiobook .tp-audio-art {
	width: 56px;
	height: 56px;
	flex: none;
	border-radius: 8px;
}
.tp-stage.is-audio.tp-audio-audiobook .tp-controls {
	min-width: 0;
	padding: 0;
}
.tp-stage.is-audio.tp-audio-audiobook .tp-controls-row {
	justify-content: center;
	gap: 14px;
}
.tp-stage.is-audio.tp-audio-audiobook .tp-spacer {
	display: none;
}
.tp-stage.is-audio.tp-audio-audiobook .tp-btn {
	width: 40px;
	height: 40px;
}

