import { B as applyStyles, C as getAnchorPositionStyle, D as createButton, E as createPopover, F as selectTime, H as tryShowPopover, I as selectVolume, M as selectPlayback, N as selectPlaybackRate, O as selectBuffer, P as selectTextTrack, S as getAnchorNameStyle, T as resolveOffsets, U as supportsAnchorPositioning, V as tryHidePopover, W as createState, _ as getSliderPreviewStyle, a as MediaElement, b as clamp, c as ContextConsumer, d as applyElementProps, f as createTransition, g as getSliderCSSVars, h as ThumbnailCore, i as MediaContainerElement, l as applyStateDataAttrs, m as createThumbnail, n as PlayerController, p as createTooltip, r as SnapshotController, s as ContextProvider, u as logMissingFeature, v as getTimeSliderCSSVars, w as getPopupPositionRect, x as roundToStep, y as createSlider } from "./create-player-Dv7K1Ezk.js";
import { i as isNumber, o as isUndefined, t as isFunction } from "./predicate-BG-dj_kF.js";
import { i as createContext, r as playerContext } from "./context-DTY0nOpS.js";
import { t as safeDefine } from "./safe-define-B8lHgj_K.js";

//#region ../utils/dist/object/defaults.js
/**
* Creates a new object with default values filled in for undefined properties.
*
* @example
* ```ts
* const props = { label: undefined, disabled: true };
* const defaultProps = { label: '', disabled: false };
* defaults(props, defaultProps); // { label: '', disabled: true }
* ```
*/
function defaults(object, defaultValues) {
	const result = { ...defaultValues };
	for (const key in object) if (!isUndefined(object[key])) result[key] = object[key];
	return result;
}

//#endregion
//#region ../utils/dist/dom/direction.js
/** Check whether an element's text direction is right-to-left. */
function isRTL(element) {
	const dir = element.closest("[dir]")?.getAttribute("dir");
	if (dir) return dir.toLowerCase() === "rtl";
	return getComputedStyle(element).direction === "rtl";
}

//#endregion
//#region inline-css:src/define/base.js
var base_default = "video-player {\n  display: contents;\n}\n\n/*\nRequired to override any default video and image styles (such as\nTailwind's CSS reset) and ensure they fill the container as expected.\n*/\nvideo-player video,\nvideo-player [slot=\"poster\"] {\n  display: block;\n  width: 100%;\n  height: 100%;\n}\n\nvideo-player video::-webkit-media-text-track-container {\n  transition: translate var(--media-caption-track-duration, 0) ease-out;\n  transition-delay: var(--media-caption-track-delay, 0);\n  translate: 0 var(--media-caption-track-y, 0);\n  scale: 0.98;\n  z-index: 1;\n  font-family: inherit;\n}\n";

//#endregion
//#region inline-css:src/define/shared.js
var shared_default = "media-tooltip-group {\n  display: contents;\n}\n\n/* Fixes a weird issue with Safari when setting aspect-ratio */\n:host {\n  display: grid;\n}\n\n/* Hide volume popover when volume control is unsupported (e.g., iOS Safari). */\n.media-popover--volume:has(media-volume-slider[data-availability=\"unsupported\"]) {\n  display: none;\n}\n";

//#endregion
//#region src/define/skin-mixin.ts
const STYLES_ID = "__media-styles";
function ensureRootStyles() {
	if (document.getElementById(STYLES_ID)) return;
	const style = document.createElement("style");
	style.id = STYLES_ID;
	style.textContent = base_default;
	document.head.appendChild(style);
}
const sharedSheet = new CSSStyleSheet();
sharedSheet.replaceSync(shared_default);
/**
* Mixin for skin elements that renders the template from a static
* `getTemplateHTML` method into a shadow root. Native `<slot>` elements
* handle light DOM projection automatically.
*
* When `static styles` is set, the stylesheet is adopted into the
* shadow root via `adoptedStyleSheets`.
*/
function SkinMixin(BaseClass) {
	class SkinElement extends BaseClass {
		static {
			this.shadowRootOptions = { mode: "open" };
		}
		constructor(...args) {
			super(...args);
			ensureRootStyles();
			if (!this.shadowRoot) {
				const ctor = this.constructor;
				this.attachShadow(ctor.shadowRootOptions);
				const sheets = [sharedSheet];
				if (ctor.styles) sheets.push(ctor.styles);
				this.shadowRoot.adoptedStyleSheets = sheets;
				if (ctor.getTemplateHTML) this.shadowRoot.innerHTML = ctor.getTemplateHTML();
			}
		}
	}
	return SkinElement;
}
/** Create a shared `CSSStyleSheet` from a CSS string. */
function createStyles(css) {
	const sheet = new CSSStyleSheet();
	sheet.replaceSync(css);
	return sheet;
}

//#endregion
//#region src/define/media/container.ts
safeDefine(MediaContainerElement);

//#endregion
//#region ../core/dist/dev/core/ui/transition.js
function getTransitionFlags(status) {
	return {
		transitionStarting: status === "starting",
		transitionEnding: status === "ending"
	};
}

//#endregion
//#region ../core/dist/dev/core/ui/buffering-indicator/buffering-indicator-core.js
var BufferingIndicatorCore = class BufferingIndicatorCore {
	static defaultProps = { delay: 500 };
	state = createState({ visible: false });
	#props = { ...BufferingIndicatorCore.defaultProps };
	#timer = null;
	setProps(props) {
		this.#props = defaults(props, BufferingIndicatorCore.defaultProps);
	}
	update(media) {
		const buffering = media.waiting && !media.paused;
		if (buffering && !this.state.current.visible && !this.#timer) this.#timer = setTimeout(() => {
			this.#timer = null;
			this.state.patch({ visible: true });
		}, this.#props.delay);
		else if (!buffering) {
			if (this.#timer !== null) {
				clearTimeout(this.#timer);
				this.#timer = null;
			}
			this.state.patch({ visible: false });
		}
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/buffering-indicator/buffering-indicator-data-attrs.js
const BufferingIndicatorDataAttrs = { visible: "data-visible" };

//#endregion
//#region ../core/dist/dev/core/ui/captions-button/captions-button-core.js
var CaptionsButtonCore = class CaptionsButtonCore {
	static defaultProps = {
		label: "",
		disabled: false
	};
	#props = { ...CaptionsButtonCore.defaultProps };
	#media = null;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, CaptionsButtonCore.defaultProps);
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		return state.subtitlesShowing ? "Disable captions" : "Enable captions";
	}
	getAttrs(state) {
		return {
			"aria-label": this.getLabel(state),
			"aria-disabled": this.#props.disabled ? "true" : void 0
		};
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		const media = this.#media;
		return {
			subtitlesShowing: media.subtitlesShowing,
			availability: media.textTrackList.some((t) => t.kind === "captions" || t.kind === "subtitles") ? "available" : "unavailable"
		};
	}
	toggle(media) {
		if (this.#props.disabled) return;
		media.toggleSubtitles();
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/captions-button/captions-button-data-attrs.js
const CaptionsButtonDataAttrs = {
	subtitlesShowing: "data-active",
	availability: "data-availability"
};

//#endregion
//#region ../core/dist/dev/core/ui/controls/controls-core.js
var ControlsCore = class {
	#media = null;
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		const media = this.#media;
		return {
			visible: media.controlsVisible,
			userActive: media.userActive
		};
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/controls/controls-data-attrs.js
const ControlsDataAttrs = {
	visible: "data-visible",
	userActive: "data-user-active"
};

//#endregion
//#region ../core/dist/dev/core/ui/fullscreen-button/fullscreen-button-core.js
var FullscreenButtonCore = class FullscreenButtonCore {
	static defaultProps = {
		label: "",
		disabled: false
	};
	#props = { ...FullscreenButtonCore.defaultProps };
	#media = null;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, FullscreenButtonCore.defaultProps);
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		return state.fullscreen ? "Exit fullscreen" : "Enter fullscreen";
	}
	getAttrs(state) {
		return {
			"aria-label": this.getLabel(state),
			"aria-disabled": this.#props.disabled ? "true" : void 0
		};
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		const media = this.#media;
		return {
			fullscreen: media.fullscreen,
			availability: media.fullscreenAvailability
		};
	}
	async toggle(media) {
		if (this.#props.disabled) return;
		if (media.fullscreenAvailability !== "available") return;
		try {
			if (media.fullscreen) await media.exitFullscreen();
			else await media.requestFullscreen();
		} catch {}
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/fullscreen-button/fullscreen-button-data-attrs.js
const FullscreenButtonDataAttrs = {
	fullscreen: "data-fullscreen",
	availability: "data-availability"
};

//#endregion
//#region ../core/dist/dev/core/ui/mute-button/mute-button-core.js
var MuteButtonCore = class MuteButtonCore {
	static defaultProps = {
		label: "",
		disabled: false
	};
	#props = { ...MuteButtonCore.defaultProps };
	#media = null;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, MuteButtonCore.defaultProps);
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		return state.muted ? "Unmute" : "Mute";
	}
	getAttrs(state) {
		return {
			"aria-label": this.getLabel(state),
			"aria-disabled": this.#props.disabled ? "true" : void 0
		};
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		const media = this.#media;
		return {
			muted: media.muted || media.volume === 0,
			volumeLevel: getVolumeLevel(media)
		};
	}
	toggle(media) {
		if (this.#props.disabled) return;
		media.toggleMuted();
	}
};
function getVolumeLevel(media) {
	if (media.muted || media.volume === 0) return "off";
	if (media.volume < .5) return "low";
	if (media.volume < .75) return "medium";
	return "high";
}

//#endregion
//#region ../core/dist/dev/core/ui/mute-button/mute-button-data-attrs.js
const MuteButtonDataAttrs = {
	muted: "data-muted",
	volumeLevel: "data-volume-level"
};

//#endregion
//#region ../core/dist/dev/core/ui/pip-button/pip-button-core.js
var PiPButtonCore = class PiPButtonCore {
	static defaultProps = {
		label: "",
		disabled: false
	};
	#props = { ...PiPButtonCore.defaultProps };
	#media = null;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, PiPButtonCore.defaultProps);
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		return state.pip ? "Exit picture-in-picture" : "Enter picture-in-picture";
	}
	getAttrs(state) {
		return {
			"aria-label": this.getLabel(state),
			"aria-disabled": this.#props.disabled ? "true" : void 0
		};
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		const media = this.#media;
		return {
			pip: media.pip,
			availability: media.pipAvailability
		};
	}
	async toggle(media) {
		if (this.#props.disabled) return;
		if (media.pipAvailability !== "available") return;
		try {
			if (media.pip) await media.exitPictureInPicture();
			else await media.requestPictureInPicture();
		} catch {}
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/pip-button/pip-button-data-attrs.js
const PiPButtonDataAttrs = {
	pip: "data-pip",
	availability: "data-availability"
};

//#endregion
//#region ../core/dist/dev/core/ui/play-button/play-button-core.js
var PlayButtonCore = class PlayButtonCore {
	static defaultProps = {
		label: "",
		disabled: false
	};
	#props = { ...PlayButtonCore.defaultProps };
	#media = null;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, PlayButtonCore.defaultProps);
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		if (state.ended) return "Replay";
		return state.paused ? "Play" : "Pause";
	}
	getAttrs(state) {
		return {
			"aria-label": this.getLabel(state),
			"aria-disabled": this.#props.disabled ? "true" : void 0
		};
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		const media = this.#media;
		return {
			paused: media.paused,
			ended: media.ended,
			started: media.started
		};
	}
	async toggle(media) {
		if (this.#props.disabled) return;
		if (media.paused || media.ended) return media.play();
		media.pause();
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/play-button/play-button-data-attrs.js
const PlayButtonDataAttrs = {
	paused: "data-paused",
	ended: "data-ended",
	started: "data-started"
};

//#endregion
//#region ../core/dist/dev/core/ui/playback-rate-button/playback-rate-button-core.js
var PlaybackRateButtonCore = class PlaybackRateButtonCore {
	static defaultProps = {
		label: "",
		disabled: false
	};
	#props = { ...PlaybackRateButtonCore.defaultProps };
	#media = null;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, PlaybackRateButtonCore.defaultProps);
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		return `Playback rate ${state.rate}`;
	}
	getAttrs(state) {
		return {
			"aria-label": this.getLabel(state),
			"aria-disabled": this.#props.disabled ? "true" : void 0
		};
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		return { rate: this.#media.playbackRate };
	}
	cycle(media) {
		if (this.#props.disabled) return;
		const { playbackRates, playbackRate } = media;
		if (playbackRates.length === 0) return;
		const idx = playbackRates.indexOf(playbackRate);
		const next = idx === -1 ? playbackRates.find((r) => r > playbackRate) ?? playbackRates[0] : playbackRates[(idx + 1) % playbackRates.length];
		media.setPlaybackRate(next);
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/playback-rate-button/playback-rate-button-data-attrs.js
const PlaybackRateButtonDataAttrs = { rate: "data-rate" };

//#endregion
//#region ../core/dist/dev/core/ui/popover/popover-core.js
var PopoverCore = class PopoverCore {
	static defaultProps = {
		side: "top",
		align: "center",
		modal: false,
		closeOnEscape: true,
		closeOnOutsideClick: true,
		open: false,
		defaultOpen: false,
		openOnHover: false,
		delay: 300,
		closeDelay: 0
	};
	#props = { ...PopoverCore.defaultProps };
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, PopoverCore.defaultProps);
	}
	#input = null;
	setInput(input) {
		this.#input = input;
	}
	getState() {
		const input = this.#input;
		return {
			open: input.active,
			status: input.status,
			side: this.#props.side,
			align: this.#props.align,
			modal: this.#props.modal,
			...getTransitionFlags(input.status)
		};
	}
	getTriggerAttrs(state, popupId) {
		return {
			"aria-expanded": state.open ? "true" : "false",
			"aria-haspopup": "dialog",
			"aria-controls": popupId
		};
	}
	getPopupAttrs(state) {
		return {
			popover: "manual",
			role: "dialog",
			"aria-modal": state.modal === true ? "true" : void 0
		};
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/popover/popover-data-attrs.js
const PopoverDataAttrs = {
	open: "data-open",
	side: "data-side",
	align: "data-align",
	transitionStarting: "data-starting-style",
	transitionEnding: "data-ending-style"
};

//#endregion
//#region ../core/dist/dev/core/ui/poster/poster-core.js
var PosterCore = class {
	#media = null;
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		return { visible: !this.#media.started };
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/poster/poster-data-attrs.js
const PosterDataAttrs = { visible: "data-visible" };

//#endregion
//#region ../core/dist/dev/core/ui/seek-button/seek-button-core.js
var SeekButtonCore = class SeekButtonCore {
	static defaultProps = {
		seconds: 30,
		label: "",
		disabled: false
	};
	#props = { ...SeekButtonCore.defaultProps };
	#media = null;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, SeekButtonCore.defaultProps);
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		const abs = Math.abs(this.#props.seconds);
		return state.direction === "backward" ? `Seek backward ${abs} seconds` : `Seek forward ${abs} seconds`;
	}
	getAttrs(state) {
		return {
			"aria-label": this.getLabel(state),
			"aria-disabled": this.#props.disabled ? "true" : void 0
		};
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		return {
			seeking: this.#media.seeking,
			direction: this.#props.seconds < 0 ? "backward" : "forward"
		};
	}
	async seek(media) {
		if (this.#props.disabled) return;
		await media.seek(media.currentTime + this.#props.seconds);
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/seek-button/seek-button-data-attrs.js
const SeekButtonDataAttrs = {
	seeking: "data-seeking",
	direction: "data-direction"
};

//#endregion
//#region ../core/dist/dev/core/ui/slider/slider-core.js
/** Base slider logic: value mapping, ARIA attrs, and step calculations. */
var SliderCore = class SliderCore {
	static defaultProps = {
		label: "",
		step: 1,
		largeStep: 10,
		orientation: "horizontal",
		disabled: false,
		thumbAlignment: "center",
		value: 0,
		min: 0,
		max: 100
	};
	static defaultInput = {
		pointerPercent: 0,
		dragPercent: 0,
		dragging: false,
		pointing: false,
		focused: false
	};
	#props = { ...SliderCore.defaultProps };
	#input = { ...SliderCore.defaultInput };
	get props() {
		return this.#props;
	}
	get input() {
		return this.#input;
	}
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, SliderCore.defaultProps);
	}
	setInput(input) {
		this.#input = input;
	}
	getSliderState(value) {
		const { orientation, disabled, thumbAlignment } = this.#props;
		const { pointerPercent, dragging, pointing, focused } = this.#input;
		return {
			value,
			fillPercent: this.percentFromValue(value),
			pointerPercent,
			dragging,
			pointing,
			interactive: dragging || pointing || focused,
			orientation,
			disabled,
			thumbAlignment
		};
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		return "";
	}
	getAttrs(state) {
		return {
			role: "slider",
			tabIndex: state.disabled ? -1 : 0,
			autoComplete: "off",
			"aria-label": this.getLabel(state),
			"aria-valuemin": this.#props.min,
			"aria-valuemax": this.#props.max,
			"aria-valuenow": state.value,
			"aria-orientation": state.orientation,
			"aria-disabled": state.disabled ? "true" : void 0
		};
	}
	valueFromPercent(percent) {
		const { min, max, step } = this.#props;
		return roundToStep(clamp(min + percent / 100 * (max - min), min, max), step, min);
	}
	/** Convert percent to a clamped value without applying step rounding. */
	rawValueFromPercent(percent) {
		const { min, max } = this.#props;
		return clamp(min + percent / 100 * (max - min), min, max);
	}
	percentFromValue(value) {
		const { min, max } = this.#props;
		if (max === min) return 0;
		return (value - min) / (max - min) * 100;
	}
	/** Step as a percentage of the slider range. */
	getStepPercent() {
		const { step, min, max } = this.#props;
		const range = max - min;
		return range > 0 ? step / range * 100 : 0;
	}
	/** Large step as a percentage of the slider range. */
	getLargeStepPercent() {
		const { largeStep, min, max } = this.#props;
		const range = max - min;
		return range > 0 ? largeStep / range * 100 : 0;
	}
	adjustPercentForAlignment(rawPercent, thumbSize, trackSize) {
		if (this.#props.thumbAlignment === "center" || trackSize === 0) return rawPercent;
		const thumbHalf = thumbSize / trackSize * 100 / 2;
		const minPercent = thumbHalf;
		const maxPercent = 100 - thumbHalf;
		return minPercent + rawPercent / 100 * (maxPercent - minPercent);
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/slider/slider-data-attrs.js
const SliderDataAttrs = {
	dragging: "data-dragging",
	pointing: "data-pointing",
	interactive: "data-interactive",
	orientation: "data-orientation",
	disabled: "data-disabled"
};

//#endregion
//#region ../core/dist/dev/core/ui/thumbnail/thumbnail-data-attrs.js
const ThumbnailDataAttrs = {
	loading: "data-loading",
	error: "data-error",
	hidden: "data-hidden"
};

//#endregion
//#region ../core/dist/dev/core/ui/thumbnail/thumbnail-media-fragment.js
/** Parse `url#xywh=x,y,w,h` into a URL and optional sprite coordinates. */
function parseMediaFragment(text, baseURL) {
	const parts = text.trim().split("#");
	const rawURL = parts[0] ?? "";
	const hash = parts[1];
	const url = baseURL ? new URL(rawURL, baseURL).href : rawURL;
	if (!hash) return { url };
	const eqIndex = hash.indexOf("=");
	if (eqIndex === -1) return { url };
	const keys = hash.slice(0, eqIndex);
	const values = hash.slice(eqIndex + 1).split(",").map(Number);
	const data = {};
	for (let i = 0; i < keys.length; i++) {
		const key = keys[i];
		const value = values[i];
		if (key && isNumber(value) && !Number.isNaN(value)) data[key] = value;
	}
	const result = { url };
	if (isNumber(data.w)) result.width = data.w;
	if (isNumber(data.h)) result.height = data.h;
	if (isNumber(data.x) && isNumber(data.y)) result.coords = {
		x: data.x,
		y: data.y
	};
	return result;
}
/**
* Convert an array of text cues (e.g. `VTTCue` from a `<track>` element)
* into {@link ThumbnailImage} entries by parsing the media-fragment in
* each cue's text.
*/
function mapCuesToThumbnails(cues, baseURL) {
	const images = [];
	for (const cue of cues) {
		const fragment = parseMediaFragment(cue.text, baseURL);
		const image = {
			url: fragment.url,
			startTime: cue.startTime,
			endTime: cue.endTime
		};
		if (fragment.width) image.width = fragment.width;
		if (fragment.height) image.height = fragment.height;
		if (fragment.coords) image.coords = fragment.coords;
		images.push(image);
	}
	return images;
}

//#endregion
//#region ../utils/dist/time/format.js
const UNIT_LABELS = [
	{
		singular: "hour",
		plural: "hours"
	},
	{
		singular: "minute",
		plural: "minutes"
	},
	{
		singular: "second",
		plural: "seconds"
	}
];
function isValidTime(value) {
	return isNumber(value) && Number.isFinite(value);
}
function toTimeUnitPhrase(value, unitIndex) {
	return `${value} ${value === 1 ? UNIT_LABELS[unitIndex]?.singular : UNIT_LABELS[unitIndex]?.plural}`;
}
/**
* Format seconds to digital display string.
*
* @param seconds - Time in seconds (can be negative)
* @param guide - Guide time (typically duration) to determine display format
* @returns Formatted string like "1:30" or "1:05:30"
*
* @example
* formatTime(90) // "1:30"
* formatTime(3661) // "1:01:01"
* formatTime(35, 3600) // "0:00:35" (guided by 1-hour duration)
* formatTime(35, 600) // "00:35" (guided by 10-minute duration)
*/
function formatTime(seconds, guide) {
	if (!isValidTime(seconds)) return "0:00";
	const negative = seconds < 0;
	const positiveSeconds = Math.abs(seconds);
	const h = Math.floor(positiveSeconds / 3600);
	const m = Math.floor(positiveSeconds / 60 % 60);
	const s = Math.floor(positiveSeconds % 60);
	const guideAbs = guide ? Math.abs(guide) : 0;
	const gh = Math.floor(guideAbs / 3600);
	const gm = Math.floor(guideAbs / 60 % 60);
	const showHours = h > 0 || gh > 0;
	const padMinutes = showHours || gm >= 10;
	const hoursStr = showHours ? `${h}:` : "";
	const minutesStr = `${padMinutes && m < 10 ? "0" : ""}${m}:`;
	const secondsStr = s < 10 ? `0${s}` : `${s}`;
	return `${negative ? "-" : ""}${hoursStr}${minutesStr}${secondsStr}`;
}
/**
* Format seconds to human-readable phrase for screen readers.
*
* @param seconds - Time in seconds (negative indicates remaining)
* @returns Human-readable phrase like "1 minute, 30 seconds"
*
* @example
* formatTimeAsPhrase(90) // "1 minute, 30 seconds"
* formatTimeAsPhrase(3661) // "1 hour, 1 minute, 1 second"
* formatTimeAsPhrase(-270) // "4 minutes, 30 seconds remaining"
*/
function formatTimeAsPhrase(seconds) {
	if (!isValidTime(seconds)) return "";
	const negative = seconds < 0;
	const positiveSeconds = Math.abs(seconds);
	const h = Math.floor(positiveSeconds / 3600);
	const m = Math.floor(positiveSeconds / 60 % 60);
	const s = Math.floor(positiveSeconds % 60);
	if (positiveSeconds === 0) return `${toTimeUnitPhrase(0, 2)}${negative ? " remaining" : ""}`;
	return `${[
		h,
		m,
		s
	].map((value, index) => value > 0 ? toTimeUnitPhrase(value, index) : null).filter(Boolean).join(", ")}${negative ? " remaining" : ""}`;
}
/**
* Convert seconds to ISO 8601 duration for datetime attribute.
*
* @param seconds - Time in seconds
* @returns ISO 8601 duration string like "PT1M30S"
*
* @example
* secondsToIsoDuration(90) // "PT1M30S"
* secondsToIsoDuration(3661) // "PT1H1M1S"
*/
function secondsToIsoDuration(seconds) {
	if (!isValidTime(seconds)) return "PT0S";
	const positiveSeconds = Math.abs(seconds);
	const h = Math.floor(positiveSeconds / 3600);
	const m = Math.floor(positiveSeconds / 60 % 60);
	const s = Math.floor(positiveSeconds % 60);
	let duration = "PT";
	if (h > 0) duration += `${h}H`;
	if (m > 0) duration += `${m}M`;
	if (s > 0 || duration === "PT") duration += `${s}S`;
	return duration;
}

//#endregion
//#region ../core/dist/dev/core/ui/time/time-core.js
const DEFAULT_LABELS = {
	current: "Current time",
	duration: "Duration",
	remaining: "Remaining"
};
var TimeCore = class TimeCore {
	static defaultProps = {
		type: "current",
		negativeSign: "-",
		label: ""
	};
	#props = { ...TimeCore.defaultProps };
	#media = null;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, TimeCore.defaultProps);
	}
	setMedia(media) {
		this.#media = media;
	}
	#getSeconds() {
		const media = this.#media;
		const { type } = this.#props;
		switch (type) {
			case "current": return media.currentTime;
			case "duration": return media.duration;
			case "remaining": return media.currentTime - media.duration;
			default: return 0;
		}
	}
	#getText() {
		const media = this.#media;
		const seconds = this.#getSeconds();
		return formatTime(Math.abs(seconds), media.duration);
	}
	#getPhrase() {
		const { type } = this.#props;
		const seconds = this.#getSeconds();
		if (type === "remaining") return formatTimeAsPhrase(seconds < 0 ? seconds : -Math.abs(seconds));
		return formatTimeAsPhrase(seconds);
	}
	#getDatetime() {
		const seconds = this.#getSeconds();
		return secondsToIsoDuration(Math.abs(seconds));
	}
	getLabel(state) {
		const { label } = this.#props;
		if (isFunction(label)) {
			const customLabel = label(state);
			if (customLabel) return customLabel;
		} else if (label) return label;
		return DEFAULT_LABELS[this.#props.type];
	}
	getAttrs(state) {
		return {
			"aria-label": this.getLabel(state),
			"aria-valuetext": state.phrase
		};
	}
	getState() {
		const seconds = this.#getSeconds();
		return {
			type: this.#props.type,
			seconds,
			negative: this.#props.type === "remaining" && seconds < 0,
			text: this.#getText(),
			phrase: this.#getPhrase(),
			datetime: this.#getDatetime()
		};
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/time/time-data-attrs.js
const TimeDataAttrs = { type: "data-type" };

//#endregion
//#region ../core/dist/dev/core/ui/time-slider/time-slider-core.js
/** Time-domain slider: maps media time/buffer state to slider state. */
var TimeSliderCore = class TimeSliderCore extends SliderCore {
	static defaultProps = {
		...SliderCore.defaultProps,
		label: "Seek",
		commitThrottle: 100
	};
	#props = { ...TimeSliderCore.defaultProps };
	#media = null;
	constructor(props) {
		super();
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, TimeSliderCore.defaultProps);
		super.setProps({
			...props,
			min: 0
		});
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		const { duration, currentTime, seeking, buffered } = this.#media;
		const { dragging, dragPercent } = this.input;
		super.setProps({
			...this.#props,
			min: 0,
			max: duration
		});
		const value = dragging ? clamp(dragPercent / 100 * duration, 0, duration) : currentTime;
		const base = super.getSliderState(value);
		const bufferedEnd = buffered.length > 0 ? buffered[buffered.length - 1][1] : 0;
		const bufferPercent = duration > 0 ? bufferedEnd / duration * 100 : 0;
		return {
			...base,
			currentTime,
			duration,
			seeking,
			bufferPercent
		};
	}
	getLabel(state) {
		return super.getLabel(state) || "Seek";
	}
	getAttrs(state) {
		const base = super.getAttrs(state);
		const currentPhrase = formatTimeAsPhrase(state.value);
		const durationPhrase = formatTimeAsPhrase(state.duration);
		const valuetext = durationPhrase ? `${currentPhrase} of ${durationPhrase}` : currentPhrase;
		return {
			...base,
			"aria-valuetext": valuetext
		};
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/time-slider/time-slider-data-attrs.js
const TimeSliderDataAttrs = {
	...SliderDataAttrs,
	seeking: "data-seeking"
};

//#endregion
//#region ../core/dist/dev/core/ui/tooltip/tooltip-core.js
var TooltipCore = class TooltipCore {
	static defaultProps = {
		side: "top",
		align: "center",
		open: false,
		defaultOpen: false,
		delay: 600,
		closeDelay: 0,
		disableHoverablePopup: true,
		disabled: false
	};
	#props = { ...TooltipCore.defaultProps };
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, TooltipCore.defaultProps);
	}
	#input = null;
	setInput(input) {
		this.#input = input;
	}
	getState() {
		const input = this.#input;
		return {
			open: input.active,
			status: input.status,
			side: this.#props.side,
			align: this.#props.align,
			...getTransitionFlags(input.status)
		};
	}
	getTriggerAttrs(state, popupId) {
		return { "aria-describedby": state.open ? popupId : void 0 };
	}
	getPopupAttrs(_state) {
		return {
			popover: "manual",
			role: "tooltip"
		};
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/tooltip/tooltip-css-vars.js
const TooltipCSSVars = {
	sideOffset: "--media-tooltip-side-offset",
	alignOffset: "--media-tooltip-align-offset",
	anchorWidth: "--media-tooltip-anchor-width",
	anchorHeight: "--media-tooltip-anchor-height",
	availableWidth: "--media-tooltip-available-width",
	availableHeight: "--media-tooltip-available-height"
};

//#endregion
//#region ../core/dist/dev/core/ui/tooltip/tooltip-data-attrs.js
const TooltipDataAttrs = {
	open: "data-open",
	side: "data-side",
	align: "data-align",
	transitionStarting: "data-starting-style",
	transitionEnding: "data-ending-style"
};

//#endregion
//#region ../core/dist/dev/core/ui/tooltip/tooltip-group-core.js
var TooltipGroupCore = class TooltipGroupCore {
	static defaultProps = {
		delay: 600,
		closeDelay: 0,
		timeout: 400
	};
	#props = { ...TooltipGroupCore.defaultProps };
	#lastCloseTime = 0;
	#isOpen = false;
	constructor(props) {
		if (props) this.setProps(props);
	}
	setProps(props) {
		this.#props = defaults(props, TooltipGroupCore.defaultProps);
	}
	get delay() {
		return this.#props.delay;
	}
	get closeDelay() {
		return this.#props.closeDelay;
	}
	shouldSkipDelay() {
		if (this.#isOpen) return true;
		return Date.now() - this.#lastCloseTime < this.#props.timeout;
	}
	notifyOpen() {
		this.#isOpen = true;
	}
	notifyClose() {
		this.#isOpen = false;
		this.#lastCloseTime = Date.now();
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/volume-slider/volume-slider-core.js
/** Volume-domain slider: maps media volume/mute state to slider state. */
var VolumeSliderCore = class VolumeSliderCore extends SliderCore {
	static defaultProps = {
		...SliderCore.defaultProps,
		label: "Volume"
	};
	#media = null;
	constructor(props) {
		super();
		if (props) this.setProps(props);
	}
	setProps(props) {
		super.setProps(defaults(props, VolumeSliderCore.defaultProps));
	}
	setMedia(media) {
		this.#media = media;
	}
	getState() {
		const media = this.#media;
		const { volume, muted } = media;
		const effectivelyMuted = muted || volume === 0;
		const { dragging, dragPercent } = this.input;
		const volumePercent = volume * 100;
		const value = dragging ? this.valueFromPercent(dragPercent) : volumePercent;
		const base = super.getSliderState(value);
		return {
			...base,
			fillPercent: effectivelyMuted ? 0 : base.fillPercent,
			volume,
			muted: effectivelyMuted,
			availability: media.volumeAvailability
		};
	}
	getLabel(state) {
		return super.getLabel(state) || "Volume";
	}
	getAttrs(state) {
		const base = super.getAttrs(state);
		const valuetext = `${Math.round(state.value)} percent${state.muted ? ", muted" : ""}`;
		return {
			...base,
			"aria-valuetext": valuetext
		};
	}
};

//#endregion
//#region ../core/dist/dev/core/ui/volume-slider/volume-slider-data-attrs.js
const VolumeSliderDataAttrs = {
	...SliderDataAttrs,
	availability: "data-availability"
};

//#endregion
//#region src/ui/media-button-element.ts
/** Abstract base for HTML custom elements that render a media-control button. */
var MediaButtonElement = class extends MediaElement {
	constructor(..._args) {
		super(..._args);
		this.disabled = false;
		this.label = "";
	}
	static {
		this.properties = {
			label: { type: String },
			disabled: { type: Boolean }
		};
	}
	#disconnect = null;
	connectedCallback() {
		super.connectedCallback();
		this.#disconnect = new AbortController();
		const buttonProps = createButton({
			onActivate: () => this.activate(this.mediaState.value),
			isDisabled: () => this.disabled || !this.mediaState.value
		});
		applyElementProps(this, buttonProps, { signal: this.#disconnect.signal });
		if (!this.mediaState.value && this.mediaState.displayName) logMissingFeature(this.localName, this.mediaState.displayName);
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#disconnect?.abort();
		this.#disconnect = null;
	}
	willUpdate(changed) {
		super.willUpdate(changed);
		this.core.setProps?.(this);
	}
	update(changed) {
		super.update(changed);
		const media = this.mediaState.value;
		if (!media) return;
		this.core.setMedia(media);
		const state = this.core.getState();
		applyElementProps(this, this.core.getAttrs?.(state) ?? {});
		applyStateDataAttrs(this, state, this.stateAttrMap);
	}
};

//#endregion
//#region src/ui/context-part-element.ts
/**
* Abstract base for compound-component part elements that consume a parent
* context and apply data attributes from `ctx.state` + `ctx.stateAttrMap`.
*
* Subclasses only need to declare the `consumer` property:
*
* ```ts
* export class SliderTrackElement extends ContextPartElement<SliderState> {
*   static readonly tagName = 'media-slider-track';
*   protected readonly consumer = new ContextConsumer(this, { context: sliderContext, subscribe: true });
* }
* ```
*/
var ContextPartElement = class extends MediaElement {
	update(_changed) {
		super.update(_changed);
		const ctx = this.consumer.value;
		if (ctx) applyStateDataAttrs(this, ctx.state, ctx.stateAttrMap);
	}
};

//#endregion
//#region src/ui/mute-button/mute-button-element.ts
var MuteButtonElement = class extends MediaButtonElement {
	constructor(..._args) {
		super(..._args);
		this.core = new MuteButtonCore();
		this.stateAttrMap = MuteButtonDataAttrs;
		this.mediaState = new PlayerController(this, playerContext, selectVolume);
	}
	static {
		this.tagName = "media-mute-button";
	}
	activate(state) {
		this.core.toggle(state);
	}
};

//#endregion
//#region src/define/ui/mute-button.ts
safeDefine(MuteButtonElement);

//#endregion
//#region src/ui/play-button/play-button-element.ts
var PlayButtonElement = class extends MediaButtonElement {
	constructor(..._args) {
		super(..._args);
		this.core = new PlayButtonCore();
		this.stateAttrMap = PlayButtonDataAttrs;
		this.mediaState = new PlayerController(this, playerContext, selectPlayback);
	}
	static {
		this.tagName = "media-play-button";
	}
	activate(state) {
		this.core.toggle(state);
	}
};

//#endregion
//#region src/define/ui/play-button.ts
safeDefine(PlayButtonElement);

//#endregion
//#region src/ui/playback-rate-button/playback-rate-button-element.ts
var PlaybackRateButtonElement = class extends MediaButtonElement {
	constructor(..._args) {
		super(..._args);
		this.core = new PlaybackRateButtonCore();
		this.stateAttrMap = PlaybackRateButtonDataAttrs;
		this.mediaState = new PlayerController(this, playerContext, selectPlaybackRate);
	}
	static {
		this.tagName = "media-playback-rate-button";
	}
	activate(state) {
		this.core.cycle(state);
	}
};

//#endregion
//#region src/define/ui/playback-rate-button.ts
safeDefine(PlaybackRateButtonElement);

//#endregion
//#region src/ui/popover/popover-element.ts
var PopoverElement = class extends MediaElement {
	constructor(..._args) {
		super(..._args);
		this.open = PopoverCore.defaultProps.open;
		this.defaultOpen = PopoverCore.defaultProps.defaultOpen;
		this.side = PopoverCore.defaultProps.side;
		this.align = PopoverCore.defaultProps.align;
		this.modal = PopoverCore.defaultProps.modal;
		this.closeOnEscape = PopoverCore.defaultProps.closeOnEscape;
		this.closeOnOutsideClick = PopoverCore.defaultProps.closeOnOutsideClick;
		this.openOnHover = PopoverCore.defaultProps.openOnHover;
		this.delay = PopoverCore.defaultProps.delay;
		this.closeDelay = PopoverCore.defaultProps.closeDelay;
	}
	static {
		this.tagName = "media-popover";
	}
	static {
		this.properties = {
			open: { type: Boolean },
			defaultOpen: {
				type: Boolean,
				attribute: "default-open"
			},
			side: { type: String },
			align: { type: String },
			modal: { type: Boolean },
			closeOnEscape: {
				type: Boolean,
				attribute: "close-on-escape"
			},
			closeOnOutsideClick: {
				type: Boolean,
				attribute: "close-on-outside-click"
			},
			openOnHover: {
				type: Boolean,
				attribute: "open-on-hover"
			},
			delay: { type: Number },
			closeDelay: {
				type: Number,
				attribute: "close-delay"
			}
		};
	}
	#core = new PopoverCore();
	#popover = null;
	#snapshot = null;
	#disconnect = null;
	#triggerAbort = null;
	#currentTrigger = null;
	#positionAbort = null;
	#positionFrame = 0;
	#resizeObserver = null;
	#positionTrigger = null;
	connectedCallback() {
		super.connectedCallback();
		if (this.destroyed) return;
		this.#disconnect = new AbortController();
		this.#popover = createPopover({
			transition: createTransition(),
			onOpenChange: (nextOpen, details) => {
				this.open = nextOpen;
				this.dispatchEvent(new CustomEvent("open-change", { detail: {
					open: nextOpen,
					...details
				} }));
			},
			closeOnEscape: () => this.closeOnEscape,
			closeOnOutsideClick: () => this.closeOnOutsideClick,
			openOnHover: () => this.openOnHover,
			delay: () => this.delay,
			closeDelay: () => this.closeDelay
		});
		this.#popover.setPopupElement(this);
		applyElementProps(this, this.#popover.popupProps, { signal: this.#disconnect.signal });
		if (this.#snapshot) this.#snapshot.track(this.#popover.input);
		else this.#snapshot = new SnapshotController(this, this.#popover.input);
	}
	firstUpdated(changed) {
		super.firstUpdated(changed);
		if (this.defaultOpen && !this.open) this.#popover?.open();
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#cleanupPositioning();
		this.#disconnect?.abort();
		this.#disconnect = null;
	}
	destroyCallback() {
		this.#cleanupPositioning();
		this.#cleanupTrigger();
		this.#popover?.destroy();
		super.destroyCallback();
	}
	willUpdate(changed) {
		super.willUpdate(changed);
		this.#core.setProps(this);
		if (this.#popover && changed.has("open")) {
			const { active: interactionOpen } = this.#popover.input.current;
			if (this.open !== interactionOpen) if (this.open) this.#popover.open();
			else this.#popover.close();
		}
	}
	update(_changed) {
		super.update(_changed);
		if (!this.#popover) return;
		const triggerEl = this.#findTrigger();
		this.#syncTrigger(triggerEl);
		const input = this.#popover.input.current;
		this.#core.setInput(input);
		const state = this.#core.getState();
		applyElementProps(this, this.#core.getPopupAttrs(state));
		applyStateDataAttrs(this, state, PopoverDataAttrs);
		if (state.open) tryShowPopover(this);
		else tryHidePopover(this);
		if (this.#currentTrigger) {
			applyElementProps(this.#currentTrigger, this.#core.getTriggerAttrs(state, this.id));
			applyStyles(this.#currentTrigger, getAnchorNameStyle(this.id));
		}
		if (!state.open) {
			this.#cleanupPositioning();
			return;
		}
		const posOpts = {
			side: state.side,
			align: state.align
		};
		if (supportsAnchorPositioning()) applyStyles(this, getAnchorPositionStyle(this.id, posOpts));
		else {
			const triggerRect = this.#currentTrigger?.getBoundingClientRect();
			const selfRect = getPopupPositionRect(this);
			const boundaryRect = document.documentElement.getBoundingClientRect();
			const offsets = resolveOffsets(this);
			applyStyles(this, getAnchorPositionStyle(this.id, posOpts, triggerRect, selfRect, boundaryRect, offsets));
		}
		this.#syncPositioning();
	}
	#findTrigger() {
		if (!this.id) return null;
		return this.getRootNode().querySelector(`[commandfor="${this.id}"]`);
	}
	#syncTrigger(triggerEl) {
		if (triggerEl === this.#currentTrigger) return;
		this.#cleanupPositioning();
		this.#cleanupTrigger();
		this.#currentTrigger = triggerEl;
		this.#popover?.setTriggerElement(triggerEl);
		if (triggerEl && this.#popover) {
			this.#triggerAbort = new AbortController();
			applyElementProps(triggerEl, this.#popover.triggerProps, { signal: this.#triggerAbort.signal });
		}
	}
	#cleanupTrigger() {
		if (this.#currentTrigger) {
			applyElementProps(this.#currentTrigger, {
				"aria-expanded": void 0,
				"aria-haspopup": void 0,
				"aria-controls": void 0
			});
			this.#currentTrigger.style.removeProperty("anchor-name");
		}
		this.#triggerAbort?.abort();
		this.#triggerAbort = null;
		this.#currentTrigger = null;
	}
	#syncPositioning() {
		if (supportsAnchorPositioning()) return;
		const triggerEl = this.#currentTrigger;
		if (!triggerEl) return;
		if (this.#positionAbort && this.#positionTrigger === triggerEl) return;
		this.#cleanupPositioning();
		this.#positionAbort = new AbortController();
		this.#positionTrigger = triggerEl;
		const { signal } = this.#positionAbort;
		const reposition = () => {
			cancelAnimationFrame(this.#positionFrame);
			this.#positionFrame = requestAnimationFrame(() => {
				if (signal.aborted) return;
				this.requestUpdate();
			});
		};
		window.addEventListener("scroll", reposition, {
			capture: true,
			passive: true,
			signal
		});
		window.addEventListener("resize", reposition, { signal });
		if (typeof ResizeObserver === "function") {
			this.#resizeObserver = new ResizeObserver(() => {
				reposition();
			});
			this.#resizeObserver.observe(triggerEl);
			this.#resizeObserver.observe(this);
		}
		reposition();
	}
	#cleanupPositioning() {
		this.#positionAbort?.abort();
		this.#positionAbort = null;
		this.#positionTrigger = null;
		cancelAnimationFrame(this.#positionFrame);
		this.#positionFrame = 0;
		this.#resizeObserver?.disconnect();
		this.#resizeObserver = null;
	}
};

//#endregion
//#region src/define/ui/popover.ts
safeDefine(PopoverElement);

//#endregion
//#region src/ui/seek-button/seek-button-element.ts
var SeekButtonElement = class extends MediaButtonElement {
	constructor(..._args) {
		super(..._args);
		this.seconds = SeekButtonCore.defaultProps.seconds;
		this.core = new SeekButtonCore();
		this.stateAttrMap = SeekButtonDataAttrs;
		this.mediaState = new PlayerController(this, playerContext, selectTime);
	}
	static {
		this.tagName = "media-seek-button";
	}
	static {
		this.properties = {
			...MediaButtonElement.properties,
			seconds: { type: Number }
		};
	}
	activate(state) {
		this.core.seek(state);
	}
};

//#endregion
//#region src/define/ui/seek-button.ts
safeDefine(SeekButtonElement);

//#endregion
//#region src/ui/time/time-element.ts
var TimeElement = class extends MediaElement {
	static {
		this.tagName = "media-time";
	}
	static {
		this.properties = {
			type: { type: String },
			negativeSign: {
				type: String,
				attribute: "negative-sign"
			},
			label: { type: String }
		};
	}
	#core = new TimeCore();
	#state = new PlayerController(this, playerContext, selectTime);
	#signSpan = document.createElement("span");
	#textNode = document.createTextNode("");
	constructor() {
		super();
		this.type = TimeCore.defaultProps.type;
		this.negativeSign = TimeCore.defaultProps.negativeSign;
		this.label = TimeCore.defaultProps.label;
		this.#signSpan.setAttribute("aria-hidden", "true");
		this.#signSpan.hidden = true;
		this.appendChild(this.#signSpan);
		this.appendChild(this.#textNode);
	}
	connectedCallback() {
		super.connectedCallback();
		if (!this.#state.value) logMissingFeature(this.localName, this.#state.displayName);
	}
	willUpdate(changed) {
		super.willUpdate(changed);
		this.#core.setProps(this);
	}
	update(changed) {
		super.update(changed);
		const media = this.#state.value;
		if (!media) return;
		this.#core.setMedia(media);
		const state = this.#core.getState();
		this.#signSpan.hidden = !state.negative;
		this.#signSpan.textContent = state.negative ? this.negativeSign : "";
		this.#textNode.textContent = state.text;
		applyElementProps(this, this.#core.getAttrs(state));
		applyStateDataAttrs(this, state, TimeDataAttrs);
	}
};

//#endregion
//#region src/ui/time/time-group-element.ts
var TimeGroupElement = class extends MediaElement {
	static {
		this.tagName = "media-time-group";
	}
};

//#endregion
//#region src/ui/time/time-separator-element.ts
var TimeSeparatorElement = class extends MediaElement {
	static {
		this.tagName = "media-time-separator";
	}
	connectedCallback() {
		super.connectedCallback();
		this.setAttribute("aria-hidden", "true");
		if (!this.textContent?.trim()) this.textContent = "/";
	}
};

//#endregion
//#region src/define/ui/time.ts
safeDefine(TimeElement);
safeDefine(TimeGroupElement);
safeDefine(TimeSeparatorElement);

//#endregion
//#region src/ui/slider/context.ts
const SLIDER_CONTEXT_KEY = Symbol("@videojs/slider");
const sliderContext = createContext(SLIDER_CONTEXT_KEY);

//#endregion
//#region src/ui/slider/slider-buffer-element.ts
var SliderBufferElement = class extends ContextPartElement {
	constructor(..._args) {
		super(..._args);
		this.consumer = new ContextConsumer(this, {
			context: sliderContext,
			subscribe: true
		});
	}
	static {
		this.tagName = "media-slider-buffer";
	}
};

//#endregion
//#region src/ui/slider/slider-fill-element.ts
var SliderFillElement = class extends ContextPartElement {
	constructor(..._args) {
		super(..._args);
		this.consumer = new ContextConsumer(this, {
			context: sliderContext,
			subscribe: true
		});
	}
	static {
		this.tagName = "media-slider-fill";
	}
};

//#endregion
//#region src/ui/slider/slider-preview-element.ts
var SliderPreviewElement = class extends MediaElement {
	constructor(..._args) {
		super(..._args);
		this.overflow = "clamp";
	}
	static {
		this.tagName = "media-slider-preview";
	}
	static {
		this.properties = { overflow: { type: String } };
	}
	#ctx = new ContextConsumer(this, {
		context: sliderContext,
		subscribe: true
	});
	#resizeObserver = null;
	#width = 0;
	connectedCallback() {
		super.connectedCallback();
		this.#resizeObserver = new ResizeObserver(([entry]) => {
			this.#width = entry.contentRect.width;
			this.#applyPosition();
		});
		this.#resizeObserver.observe(this);
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#resizeObserver?.disconnect();
		this.#resizeObserver = null;
	}
	#applyPosition() {
		applyStyles(this, getSliderPreviewStyle(this.#width, this.overflow));
	}
	update(_changed) {
		super.update(_changed);
		const ctx = this.#ctx.value;
		if (ctx) applyStateDataAttrs(this, ctx.state, ctx.stateAttrMap);
		this.#applyPosition();
	}
};

//#endregion
//#region src/ui/slider/slider-thumb-element.ts
var SliderThumbElement = class extends MediaElement {
	static {
		this.tagName = "media-slider-thumb";
	}
	#ctx = new ContextConsumer(this, {
		context: sliderContext,
		subscribe: true
	});
	#disconnect = null;
	#thumbPropsApplied = false;
	connectedCallback() {
		super.connectedCallback();
		this.#disconnect = new AbortController();
		this.#thumbPropsApplied = false;
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#disconnect?.abort();
		this.#disconnect = null;
		this.#thumbPropsApplied = false;
	}
	update(_changed) {
		super.update(_changed);
		const ctx = this.#ctx.value;
		if (!ctx) return;
		if (!this.#thumbPropsApplied && this.#disconnect) {
			applyElementProps(this, ctx.thumbProps, { signal: this.#disconnect.signal });
			this.#thumbPropsApplied = true;
		}
		applyElementProps(this, ctx.thumbAttrs);
		applyStateDataAttrs(this, ctx.state, ctx.stateAttrMap);
	}
};

//#endregion
//#region src/ui/thumbnail/thumbnail-element.ts
const SHADOW_CSS = `\
:host {
  display: inline-block;
  overflow: hidden;
}
img {
  display: block;
}`;
var ThumbnailElement = class extends MediaElement {
	static {
		this.tagName = "media-thumbnail";
	}
	static {
		this.properties = {
			time: { type: Number },
			crossOrigin: {
				type: String,
				attribute: "crossorigin"
			},
			loading: { type: String },
			fetchPriority: {
				type: String,
				attribute: "fetchpriority"
			}
		};
	}
	#core = new ThumbnailCore();
	#img = document.createElement("img");
	#textTracks = new PlayerController(this, playerContext, selectTextTrack);
	#thumbnails = [];
	#externalThumbnails;
	#lastTextTrack;
	#api = null;
	constructor() {
		super();
		this.time = 0;
		const shadow = this.attachShadow({ mode: "open" });
		const style = document.createElement("style");
		style.textContent = SHADOW_CSS;
		shadow.appendChild(style);
		this.#img.alt = "";
		this.#img.setAttribute("part", "img");
		this.#img.setAttribute("aria-hidden", "true");
		this.#img.setAttribute("decoding", "async");
		shadow.appendChild(this.#img);
	}
	/**
	* Set thumbnail images directly, bypassing the automatic `<track>` detection.
	* When set, this takes priority over the text track path.
	*/
	get thumbnails() {
		return this.#externalThumbnails;
	}
	set thumbnails(value) {
		this.#externalThumbnails = value;
		this.requestUpdate();
	}
	connectedCallback() {
		super.connectedCallback();
		if (this.destroyed) return;
		this.#api = createThumbnail({
			getContainer: () => this,
			getImg: () => this.#img,
			onStateChange: () => this.requestUpdate()
		});
	}
	disconnectedCallback() {
		super.disconnectedCallback();
	}
	destroyCallback() {
		this.#api?.destroy();
		super.destroyCallback();
	}
	update(changed) {
		super.update(changed);
		if (this.#externalThumbnails) this.#thumbnails = this.#externalThumbnails;
		else {
			const textTrack = this.#textTracks.value;
			if (textTrack !== this.#lastTextTrack) {
				this.#lastTextTrack = textTrack;
				this.#thumbnails = textTrack && textTrack.thumbnailCues.length > 0 ? mapCuesToThumbnails(textTrack.thumbnailCues, textTrack.thumbnailTrackSrc ?? void 0) : [];
			}
		}
		const thumbnail = this.#core.findActiveThumbnail(this.#thumbnails, this.time);
		applyElementProps(this.#img, {
			crossorigin: this.crossOrigin || void 0,
			loading: this.loading,
			fetchpriority: this.fetchPriority
		});
		this.#api?.updateSrc(thumbnail?.url);
		if (!thumbnail) {
			this.#img.removeAttribute("src");
			this.#resetStyles();
			const state = this.#core.getState(false, false, void 0);
			applyElementProps(this, this.#core.getAttrs(state));
			applyStateDataAttrs(this, state, ThumbnailDataAttrs);
			return;
		}
		if (this.#img.getAttribute("src") !== thumbnail.url) this.#img.src = thumbnail.url;
		const api = this.#api;
		const state = this.#core.getState(api?.loading ?? false, api?.error ?? false, thumbnail);
		applyElementProps(this, this.#core.getAttrs(state));
		applyStateDataAttrs(this, state, ThumbnailDataAttrs);
		if (api?.naturalWidth && api.naturalHeight) {
			const constraints = api.readConstraints();
			const result = this.#core.resize(thumbnail, api.naturalWidth, api.naturalHeight, constraints);
			if (result) this.#applyResize(result);
		}
	}
	#applyResize(result) {
		this.style.width = `${result.containerWidth}px`;
		this.style.height = `${result.containerHeight}px`;
		const imgStyle = this.#img.style;
		imgStyle.width = `${result.imageWidth}px`;
		imgStyle.height = `${result.imageHeight}px`;
		imgStyle.maxWidth = "none";
		imgStyle.transform = result.offsetX || result.offsetY ? `translate(-${result.offsetX}px, -${result.offsetY}px)` : "";
	}
	#resetStyles() {
		this.style.width = "";
		this.style.height = "";
		const imgStyle = this.#img.style;
		imgStyle.width = "";
		imgStyle.height = "";
		imgStyle.maxWidth = "";
		imgStyle.transform = "";
	}
};

//#endregion
//#region src/ui/slider/slider-thumbnail-element.ts
var SliderThumbnailElement = class extends ThumbnailElement {
	static {
		this.tagName = "media-slider-thumbnail";
	}
	#ctx = new ContextConsumer(this, {
		context: sliderContext,
		subscribe: true
	});
	update(changed) {
		const ctx = this.#ctx.value;
		if (ctx) this.time = ctx.pointerValue;
		super.update(changed);
	}
};

//#endregion
//#region src/ui/slider/slider-track-element.ts
var SliderTrackElement = class extends ContextPartElement {
	constructor(..._args) {
		super(..._args);
		this.consumer = new ContextConsumer(this, {
			context: sliderContext,
			subscribe: true
		});
	}
	static {
		this.tagName = "media-slider-track";
	}
};

//#endregion
//#region src/ui/slider/slider-value-element.ts
var SliderValueElement = class extends MediaElement {
	constructor(..._args) {
		super(..._args);
		this.type = "current";
	}
	static {
		this.tagName = "media-slider-value";
	}
	static {
		this.properties = { type: { type: String } };
	}
	#ctx = new ContextConsumer(this, {
		context: sliderContext,
		subscribe: true
	});
	connectedCallback() {
		super.connectedCallback();
		this.setAttribute("aria-live", "off");
	}
	update(_changed) {
		super.update(_changed);
		const ctx = this.#ctx.value;
		if (!ctx) return;
		const value = this.type === "pointer" ? ctx.pointerValue : ctx.state.value;
		this.textContent = ctx.formatValue ? ctx.formatValue(value, this.type) : String(Math.round(value));
		applyStateDataAttrs(this, ctx.state, ctx.stateAttrMap);
	}
};

//#endregion
//#region src/ui/time-slider/time-slider-element.ts
var TimeSliderElement = class extends MediaElement {
	constructor(..._args) {
		super(..._args);
		this.label = TimeSliderCore.defaultProps.label;
		this.commitThrottle = TimeSliderCore.defaultProps.commitThrottle;
		this.step = TimeSliderCore.defaultProps.step;
		this.largeStep = TimeSliderCore.defaultProps.largeStep;
		this.orientation = TimeSliderCore.defaultProps.orientation;
		this.disabled = TimeSliderCore.defaultProps.disabled;
		this.thumbAlignment = TimeSliderCore.defaultProps.thumbAlignment;
	}
	static {
		this.tagName = "media-time-slider";
	}
	static {
		this.properties = {
			label: { type: String },
			commitThrottle: {
				type: Number,
				attribute: "commit-throttle"
			},
			step: { type: Number },
			largeStep: {
				type: Number,
				attribute: "large-step"
			},
			orientation: { type: String },
			disabled: { type: Boolean },
			thumbAlignment: {
				type: String,
				attribute: "thumb-alignment"
			}
		};
	}
	#core = new TimeSliderCore();
	#provider = new ContextProvider(this, { context: sliderContext });
	#timeState = new PlayerController(this, playerContext, selectTime);
	#bufferState = new PlayerController(this, playerContext, selectBuffer);
	#slider = null;
	#disconnect = null;
	connectedCallback() {
		super.connectedCallback();
		if (this.destroyed) return;
		this.#disconnect = new AbortController();
		const signal = this.#disconnect.signal;
		this.#slider = createSlider({
			getElement: () => this,
			getThumbElement: () => this.querySelector("media-slider-thumb"),
			getOrientation: () => this.orientation,
			isRTL: () => isRTL(this),
			isDisabled: () => this.disabled || !this.#timeState.value,
			getPercent: () => {
				const media = this.#timeState.value;
				if (!media) return 0;
				return this.#core.percentFromValue(media.currentTime);
			},
			getStepPercent: () => this.#core.getStepPercent(),
			getLargeStepPercent: () => this.#core.getLargeStepPercent(),
			onValueCommit: (percent) => {
				const media = this.#timeState.value;
				if (media) media.seek(this.#core.rawValueFromPercent(percent));
			},
			commitThrottle: this.commitThrottle,
			onDragStart: () => {
				this.dispatchEvent(new CustomEvent("drag-start", { bubbles: true }));
			},
			onDragEnd: () => {
				this.dispatchEvent(new CustomEvent("drag-end", { bubbles: true }));
			},
			adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),
			onResize: () => this.requestUpdate()
		});
		applyElementProps(this, this.#slider.rootProps, { signal });
		applyStyles(this, this.#slider.rootStyle);
		this.#slider.input.subscribe(() => this.requestUpdate(), { signal });
		if (!this.#timeState.value) logMissingFeature(this.localName, this.#timeState.displayName);
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#disconnect?.abort();
		this.#disconnect = null;
	}
	destroyCallback() {
		this.#slider?.destroy();
		super.destroyCallback();
	}
	willUpdate(_changed) {
		super.willUpdate(_changed);
		this.#core.setProps(this);
	}
	update(_changed) {
		super.update(_changed);
		if (!this.#slider) return;
		const time = this.#timeState.value;
		const buffer = this.#bufferState.value;
		if (!time) return;
		this.#core.setInput(this.#slider.input.current);
		const media = {
			...time,
			...buffer ?? {
				buffered: [],
				seekable: []
			}
		};
		this.#core.setMedia(media);
		const state = this.#core.getState();
		const cssVars = getTimeSliderCSSVars(this.#slider.adjustForAlignment(state));
		applyStyles(this, cssVars);
		applyStateDataAttrs(this, state, TimeSliderDataAttrs);
		this.#provider.setValue({
			state,
			stateAttrMap: TimeSliderDataAttrs,
			pointerValue: this.#core.valueFromPercent(state.pointerPercent),
			thumbAttrs: this.#core.getAttrs(state),
			thumbProps: this.#slider.thumbProps,
			formatValue: (value) => formatTime(value, state.duration)
		});
	}
};

//#endregion
//#region src/define/ui/time-slider.ts
safeDefine(TimeSliderElement);
safeDefine(SliderBufferElement);
safeDefine(SliderFillElement);
safeDefine(SliderPreviewElement);
safeDefine(SliderThumbElement);
safeDefine(SliderThumbnailElement);
safeDefine(SliderTrackElement);
safeDefine(SliderValueElement);

//#endregion
//#region src/ui/tooltip/context.ts
const TOOLTIP_GROUP_CONTEXT_KEY = Symbol("@videojs/tooltip-group");
const tooltipGroupContext = createContext(TOOLTIP_GROUP_CONTEXT_KEY);

//#endregion
//#region src/ui/tooltip/tooltip-element.ts
var TooltipElement = class extends MediaElement {
	constructor(..._args) {
		super(..._args);
		this.open = TooltipCore.defaultProps.open;
		this.defaultOpen = TooltipCore.defaultProps.defaultOpen;
		this.side = TooltipCore.defaultProps.side;
		this.align = TooltipCore.defaultProps.align;
		this.delay = TooltipCore.defaultProps.delay;
		this.closeDelay = TooltipCore.defaultProps.closeDelay;
		this.disableHoverablePopup = TooltipCore.defaultProps.disableHoverablePopup;
		this.disabled = TooltipCore.defaultProps.disabled;
	}
	static {
		this.tagName = "media-tooltip";
	}
	static {
		this.properties = {
			open: { type: Boolean },
			defaultOpen: {
				type: Boolean,
				attribute: "default-open"
			},
			side: { type: String },
			align: { type: String },
			delay: { type: Number },
			closeDelay: {
				type: Number,
				attribute: "close-delay"
			},
			disableHoverablePopup: {
				type: Boolean,
				attribute: "disable-hoverable-popup"
			},
			disabled: { type: Boolean }
		};
	}
	#core = new TooltipCore();
	#groupConsumer = new ContextConsumer(this, { context: tooltipGroupContext });
	#tooltip = null;
	#snapshot = null;
	#disconnect = null;
	#triggerAbort = null;
	#currentTrigger = null;
	#positionAbort = null;
	#positionFrame = 0;
	#resizeObserver = null;
	#positionTrigger = null;
	connectedCallback() {
		super.connectedCallback();
		this.#disconnect = new AbortController();
		this.#tooltip = createTooltip({
			transition: createTransition(),
			onOpenChange: (nextOpen, details) => {
				this.open = nextOpen;
				this.dispatchEvent(new CustomEvent("open-change", { detail: {
					open: nextOpen,
					...details
				} }));
			},
			delay: () => this.delay,
			closeDelay: () => this.closeDelay,
			disableHoverablePopup: () => this.disableHoverablePopup,
			disabled: () => this.disabled,
			group: () => this.#groupConsumer.value
		});
		this.#tooltip.setPopupElement(this);
		applyElementProps(this, this.#tooltip.popupProps, { signal: this.#disconnect.signal });
		if (this.#snapshot) this.#snapshot.track(this.#tooltip.input);
		else this.#snapshot = new SnapshotController(this, this.#tooltip.input);
	}
	firstUpdated(changed) {
		super.firstUpdated(changed);
		if (this.defaultOpen && !this.open) this.#tooltip?.open();
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#cleanupPositioning();
		this.#cleanupTrigger();
		this.#tooltip?.destroy();
		this.#tooltip = null;
		this.#disconnect?.abort();
		this.#disconnect = null;
	}
	willUpdate(changed) {
		super.willUpdate(changed);
		this.#core.setProps(this);
		if (this.#tooltip && changed.has("open")) {
			const { active: interactionOpen } = this.#tooltip.input.current;
			if (this.open !== interactionOpen) if (this.open) this.#tooltip.open();
			else this.#tooltip.close();
		}
	}
	update(_changed) {
		super.update(_changed);
		if (!this.#tooltip) return;
		const triggerEl = this.#findTrigger();
		this.#syncTrigger(triggerEl);
		const input = this.#tooltip.input.current;
		this.#core.setInput(input);
		const state = this.#core.getState();
		applyElementProps(this, this.#core.getPopupAttrs(state));
		applyStateDataAttrs(this, state, TooltipDataAttrs);
		if (state.open) tryShowPopover(this);
		else tryHidePopover(this);
		if (this.#currentTrigger) {
			applyElementProps(this.#currentTrigger, this.#core.getTriggerAttrs(state, this.id));
			applyStyles(this.#currentTrigger, getAnchorNameStyle(this.id));
		}
		if (!state.open) {
			this.#cleanupPositioning();
			return;
		}
		const posOpts = {
			side: state.side,
			align: state.align
		};
		if (supportsAnchorPositioning()) applyStyles(this, getAnchorPositionStyle(this.id, posOpts, void 0, void 0, void 0, void 0, TooltipCSSVars));
		else {
			const triggerRect = this.#currentTrigger?.getBoundingClientRect();
			const selfRect = getPopupPositionRect(this);
			const boundaryRect = document.documentElement.getBoundingClientRect();
			const offsets = resolveOffsets(this, TooltipCSSVars);
			applyStyles(this, getAnchorPositionStyle(this.id, posOpts, triggerRect, selfRect, boundaryRect, offsets, TooltipCSSVars));
		}
		this.#syncPositioning();
	}
	#findTrigger() {
		if (!this.id) return null;
		return this.getRootNode().querySelector(`[commandfor="${this.id}"]`);
	}
	#syncTrigger(triggerEl) {
		if (triggerEl === this.#currentTrigger) return;
		this.#cleanupPositioning();
		this.#cleanupTrigger();
		this.#currentTrigger = triggerEl;
		this.#tooltip?.setTriggerElement(triggerEl);
		if (triggerEl && this.#tooltip) {
			this.#triggerAbort = new AbortController();
			applyElementProps(triggerEl, this.#tooltip.triggerProps, { signal: this.#triggerAbort.signal });
		}
	}
	#cleanupTrigger() {
		if (this.#currentTrigger) {
			applyElementProps(this.#currentTrigger, { "aria-describedby": void 0 });
			this.#currentTrigger.style.removeProperty("anchor-name");
		}
		this.#triggerAbort?.abort();
		this.#triggerAbort = null;
		this.#currentTrigger = null;
	}
	#syncPositioning() {
		if (supportsAnchorPositioning()) return;
		const triggerEl = this.#currentTrigger;
		if (!triggerEl) return;
		if (this.#positionAbort && this.#positionTrigger === triggerEl) return;
		this.#cleanupPositioning();
		this.#positionAbort = new AbortController();
		this.#positionTrigger = triggerEl;
		const { signal } = this.#positionAbort;
		const reposition = () => {
			cancelAnimationFrame(this.#positionFrame);
			this.#positionFrame = requestAnimationFrame(() => {
				if (signal.aborted) return;
				this.requestUpdate();
			});
		};
		window.addEventListener("scroll", reposition, {
			capture: true,
			passive: true,
			signal
		});
		window.addEventListener("resize", reposition, { signal });
		if (typeof ResizeObserver === "function") {
			this.#resizeObserver = new ResizeObserver(() => {
				reposition();
			});
			this.#resizeObserver.observe(triggerEl);
			this.#resizeObserver.observe(this);
		}
		reposition();
	}
	#cleanupPositioning() {
		this.#positionAbort?.abort();
		this.#positionAbort = null;
		this.#positionTrigger = null;
		cancelAnimationFrame(this.#positionFrame);
		this.#positionFrame = 0;
		this.#resizeObserver?.disconnect();
		this.#resizeObserver = null;
	}
};

//#endregion
//#region src/define/ui/tooltip.ts
safeDefine(TooltipElement);

//#endregion
//#region src/ui/tooltip/tooltip-group-element.ts
var TooltipGroupElement = class extends MediaElement {
	constructor(..._args) {
		super(..._args);
		this.delay = TooltipGroupCore.defaultProps.delay;
		this.closeDelay = TooltipGroupCore.defaultProps.closeDelay;
		this.timeout = TooltipGroupCore.defaultProps.timeout;
	}
	static {
		this.tagName = "media-tooltip-group";
	}
	static {
		this.properties = {
			delay: { type: Number },
			closeDelay: {
				type: Number,
				attribute: "close-delay"
			},
			timeout: { type: Number }
		};
	}
	#core = new TooltipGroupCore();
	#provider = new ContextProvider(this, {
		context: tooltipGroupContext,
		initialValue: this.#core
	});
	update(_changed) {
		super.update(_changed);
		this.#core.setProps(this);
		this.#provider.setValue(this.#core);
	}
};

//#endregion
//#region src/define/ui/tooltip-group.ts
safeDefine(TooltipGroupElement);

//#endregion
//#region src/ui/volume-slider/volume-slider-element.ts
var VolumeSliderElement = class extends MediaElement {
	constructor(..._args) {
		super(..._args);
		this.label = VolumeSliderCore.defaultProps.label;
		this.step = VolumeSliderCore.defaultProps.step;
		this.largeStep = VolumeSliderCore.defaultProps.largeStep;
		this.orientation = VolumeSliderCore.defaultProps.orientation;
		this.disabled = VolumeSliderCore.defaultProps.disabled;
		this.thumbAlignment = VolumeSliderCore.defaultProps.thumbAlignment;
	}
	static {
		this.tagName = "media-volume-slider";
	}
	static {
		this.properties = {
			label: { type: String },
			step: { type: Number },
			largeStep: {
				type: Number,
				attribute: "large-step"
			},
			orientation: { type: String },
			disabled: { type: Boolean },
			thumbAlignment: {
				type: String,
				attribute: "thumb-alignment"
			}
		};
	}
	#core = new VolumeSliderCore();
	#provider = new ContextProvider(this, { context: sliderContext });
	#volumeState = new PlayerController(this, playerContext, selectVolume);
	#slider = null;
	#disconnect = null;
	connectedCallback() {
		super.connectedCallback();
		if (this.destroyed) return;
		this.#disconnect = new AbortController();
		const signal = this.#disconnect.signal;
		this.#slider = createSlider({
			getElement: () => this,
			getThumbElement: () => this.querySelector("media-slider-thumb"),
			getOrientation: () => this.orientation,
			isRTL: () => isRTL(this),
			isDisabled: () => this.disabled || !this.#volumeState.value,
			getPercent: () => {
				const media = this.#volumeState.value;
				if (!media) return 0;
				return media.volume * 100;
			},
			getStepPercent: () => this.#core.getStepPercent(),
			getLargeStepPercent: () => this.#core.getLargeStepPercent(),
			onValueChange: (percent) => {
				this.#setVolume(percent);
			},
			onValueCommit: (percent) => {
				this.#setVolume(percent);
			},
			onDragStart: () => {
				this.dispatchEvent(new CustomEvent("drag-start", { bubbles: true }));
			},
			onDragEnd: () => {
				this.dispatchEvent(new CustomEvent("drag-end", { bubbles: true }));
			},
			adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),
			onResize: () => this.requestUpdate()
		});
		applyElementProps(this, this.#slider.rootProps, { signal });
		applyStyles(this, this.#slider.rootStyle);
		this.#slider.input.subscribe(() => this.requestUpdate(), { signal });
		if (!this.#volumeState.value) logMissingFeature(this.localName, this.#volumeState.displayName);
	}
	disconnectedCallback() {
		super.disconnectedCallback();
		this.#disconnect?.abort();
		this.#disconnect = null;
	}
	destroyCallback() {
		this.#slider?.destroy();
		super.destroyCallback();
	}
	willUpdate(_changed) {
		super.willUpdate(_changed);
		this.#core.setProps(this);
	}
	update(_changed) {
		super.update(_changed);
		if (!this.#slider) return;
		const media = this.#volumeState.value;
		if (!media) return;
		this.#core.setInput(this.#slider.input.current);
		this.#core.setMedia(media);
		const state = this.#core.getState();
		const cssVars = getSliderCSSVars(this.#slider.adjustForAlignment(state));
		applyStyles(this, cssVars);
		applyStateDataAttrs(this, state, VolumeSliderDataAttrs);
		this.#provider.setValue({
			state,
			stateAttrMap: VolumeSliderDataAttrs,
			pointerValue: this.#core.valueFromPercent(state.pointerPercent),
			thumbAttrs: this.#core.getAttrs(state),
			thumbProps: this.#slider.thumbProps,
			formatValue: (value) => `${Math.round(value)}%`
		});
	}
	#setVolume(percent) {
		this.#volumeState.value?.setVolume(this.#core.valueFromPercent(percent) / 100);
	}
};

//#endregion
//#region src/define/ui/volume-slider.ts
safeDefine(VolumeSliderElement);
safeDefine(SliderFillElement);
safeDefine(SliderPreviewElement);
safeDefine(SliderThumbElement);
safeDefine(SliderTrackElement);
safeDefine(SliderValueElement);

//#endregion
export { PiPButtonDataAttrs as a, FullscreenButtonCore as c, CaptionsButtonDataAttrs as d, CaptionsButtonCore as f, createStyles as g, SkinMixin as h, PosterCore as i, ControlsDataAttrs as l, BufferingIndicatorCore as m, MediaButtonElement as n, PiPButtonCore as o, BufferingIndicatorDataAttrs as p, PosterDataAttrs as r, FullscreenButtonDataAttrs as s, ContextPartElement as t, ControlsCore as u };
//# sourceMappingURL=volume-slider-CfhOO9RM.js.map