KICK Enhancer

Enhances KICK with viewer counts, stream uptime, content controls, and direct clip downloads.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         KICK Enhancer
// @namespace    kick-enhancer/userscript
// @version      0.1.1
// @author       emy
// @description  Enhances KICK with viewer counts, stream uptime, content controls, and direct clip downloads.
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAW9yTlQBz6J3mgAABtRJREFUWMPFl2uoZWUdxn/P+66199nnnLk2kl0QisBE88J8EaIQ1LwcGZsMRs/UaFcTIa1BQdIvKUp5KYsCZ5Co1BQl1LyATh8SGz+YGTkSUhZEXhh1dDpzbnut9T59eNfZe5+tZknQ+2FtNmu97/P/P//nf3nh/7wEcE7/GCbLEiESDgEFkxyImDT4NGFVpBQgCXHU4ie4snvz8CwRDRYCPALhlV8ZksiHptRkA97NSovLqFuOOCLRHpz/6b9goDqayaIjkBM+NqIjTbMsimCSwYjgROpWpD8F2FfQ0c/8pG0HkhNB6yRO8YCMVQwIqIANhqcEzwBKqXYB0IvTQD+C60j8qmkuhlCBi+xHAKhBpdANQpctMBeNkySnSBngdmCmpTcMqTeZGQXwc9gnm5ahZAqAWg2RRPZUC5Bs9LqgGCGyNt6USIuBghP8SUmw2Ee9kjuBGWA5g7sZYbkG9YB9hpOR9gNSCAayAQONMHBXQhEI+ZUlhFAw9hwH2KDDBEq90ncAnwH6oHIoPgSqgR74r8YzwP723MYp0dR15haNxotV1rg90NAkjFxMHvCrXPzKtRXJtwLnZXCK1eDUQAl+0eZM0N9pwSFzXHQ6rQHtzxDMA/iQ1d2Ap0XYP8HaOz+ny6k31T9CfHEIvkrYTWaD12xmgOfacA7AY4wMQhAG2bPKc6sFN54wYb7Huq0n6aynzvUl34uEi0B98FuBF8Ah4y2IPwgKpBqDnQbgAwO8Km0GAWjB6SaHpQnWnHMa2/aezRe+E4mXgsfBV9QegWXjrYK9QIGH4KGIqzaEvCtliQ0UCaAG3DFqeqzZdhbbH9vCBd8u6VwOrsZobzcKwMbnCu0BZc9DxhgHHxhQuBiJ/EoYXJqgDtOzZ7J9zww7ruzQvaoFj2O1zFnJjuDPC+4FSkSdLfIq2kdXMcyCgLIObIQJReHu9rN1/oNnMHtZh87VbwYf5LAyOBci3ZHVTwXgZEIMb1uKw4r4EsYkTFIuvJ0vzWjHfad79usdJr7bplXgTe0jW2/YibQLKFLdVAvNAva/Bx8YYGoCQgQCYS3mrhM56e6Pp9OO6dK9bqSyjZ/WtIzskXQTUDqlRoKeJgghvGMzCgCR7or3JNJBydue4NHZJ8Ij+5ZZumyE9jRSbPLWbNwp2FdgKilERD4rNe9oQAGwxALdAUYg0WCaXfd5d1Wq/PHpPq/XYeKGNq7xLTpqAl0Lnkf6gQiFFlTvmDpO56cTaBQokAW8UC/ySPnsOANl9j0rISj3z6Wk5qcP+CdbH+aOG/ssf6utbg3jFQO71cjNJH8FVDPpcL3v9xG810emeU/7Fab9Cuvja2+RBSPCUp4JJIVGqFrUoZ/fz63bGqprz/IFvQ4TVw6zwSP93rnziV0mLf5Tb9z2Q76x9kW/3CGsnzdTiwGxHwMvjxeipk1BoO18oGhcg1yx+IuHue3Ue7X7qor+9ZkJ1awuXFpJCePr1lUb9TeevyURX+i7ukaO2BQfpNb56Sgu8NF82ptXekFYNfvlpzGKgr5Qd5mFux/lrq3LWrp81t/sROIlw0YkwAH0hszzoBcowWhjkjvJXpfyN17PBxy1BjATo71g6Ik99MvOVKtPNuKe3/CrmTm9fumFvnoqEr8MXgZ3culmhsDe7f0tEwvNnzXdmxxMRUuaopsOTB7i+aWa+UoUTLFpvBdoTA+t2XnKmTdsnGfunHu4hcLFhcDtoG676WXg6XP52D2dzkvPru1N/j4SjgcdKqQzJph7WqF8ptHUDYU2UmhdeFVFZqAYA/VYoQVb7XTUkBZ7THNdOC/WS3M7iu70NHA2uL+MypLORyF8GEiGBaASYb3R4TlM8SMMtBZXQjB8rgoG2LaVZ2wrdwxt4DAKRxUTa5JTs00Ke4ATuib9RX/c+R4ffsQmvb8wzdeMj0nweElxW8IbQPsCZZ5LqFbSMAxzIE+1yTnVvDLfGzXGjXFqqPmtHko7/f2AWDY+U+hx5N17U//GhurAian75JHxuDMC4di+m2cFuwXxVdwcny7C4PetiLCmGp2FeoJgaxPK7zMrro1jsqeE6LEGoQQhkJizOFXiMSs9CXrxd8EfmuX4tc73pHWNE1Gx3KSCl+KuBuDQSgjK5bXQPZja0PzS6B+gBUxYocAmWWnS8HirhVRRUVIkAlFmP+ZTQWEWc0BSf5bNNwO/Nn5CEonUP8hcekDPvamWvrvrWb+PimJ4lgcFBMXwn1/NPuvNdAYlPgacBjcbtXXRhiRTuU6RkAAOqstD9d5RMAExOREeiPX2LZujjCrqVFIkAa9rngf/VwyML990xUjXHnZX7bzmbff8Cx1fShSwufUVAAAAAElFTkSuQmCC
// @homepage     https://github.com/sixem/kick-enhancer#readme
// @homepageURL  https://github.com/sixem/kick-enhancer
// @source       https://github.com/sixem/kick-enhancer
// @supportURL   https://github.com/sixem/kick-enhancer/issues
// @match        https://kick.com/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/preact.umd.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/hooks/dist/hooks.umd.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/compat/dist/compat.umd.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/jsx-runtime/dist/jsxRuntime.umd.js
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        unsafeWindow
// @run-at       document-start
// @noframes
// ==/UserScript==

/*!
 * Preact 10.29.7
 * Source: https://github.com/preactjs/preact
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-present Jason Miller
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * ---
 *
 * mux.js 6.3.0
 * Source: https://github.com/videojs/mux.js
 *
 * Apache License
 *                            Version 2.0, January 2004
 *                         http://www.apache.org/licenses/
 *
 *    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 *
 *    1. Definitions.
 *
 *       "License" shall mean the terms and conditions for use, reproduction,
 *       and distribution as defined by Sections 1 through 9 of this document.
 *
 *       "Licensor" shall mean the copyright owner or entity authorized by
 *       the copyright owner that is granting the License.
 *
 *       "Legal Entity" shall mean the union of the acting entity and all
 *       other entities that control, are controlled by, or are under common
 *       control with that entity. For the purposes of this definition,
 *       "control" means (i) the power, direct or indirect, to cause the
 *       direction or management of such entity, whether by contract or
 *       otherwise, or (ii) ownership of fifty percent (50%) or more of the
 *       outstanding shares, or (iii) beneficial ownership of such entity.
 *
 *       "You" (or "Your") shall mean an individual or Legal Entity
 *       exercising permissions granted by this License.
 *
 *       "Source" form shall mean the preferred form for making modifications,
 *       including but not limited to software source code, documentation
 *       source, and configuration files.
 *
 *       "Object" form shall mean any form resulting from mechanical
 *       transformation or translation of a Source form, including but
 *       not limited to compiled object code, generated documentation,
 *       and conversions to other media types.
 *
 *       "Work" shall mean the work of authorship, whether in Source or
 *       Object form, made available under the License, as indicated by a
 *       copyright notice that is included in or attached to the work
 *       (an example is provided in the Appendix below).
 *
 *       "Derivative Works" shall mean any work, whether in Source or Object
 *       form, that is based on (or derived from) the Work and for which the
 *       editorial revisions, annotations, elaborations, or other modifications
 *       represent, as a whole, an original work of authorship. For the purposes
 *       of this License, Derivative Works shall not include works that remain
 *       separable from, or merely link (or bind by name) to the interfaces of,
 *       the Work and Derivative Works thereof.
 *
 *       "Contribution" shall mean any work of authorship, including
 *       the original version of the Work and any modifications or additions
 *       to that Work or Derivative Works thereof, that is intentionally
 *       submitted to Licensor for inclusion in the Work by the copyright owner
 *       or by an individual or Legal Entity authorized to submit on behalf of
 *       the copyright owner. For the purposes of this definition, "submitted"
 *       means any form of electronic, verbal, or written communication sent
 *       to the Licensor or its representatives, including but not limited to
 *       communication on electronic mailing lists, source code control systems,
 *       and issue tracking systems that are managed by, or on behalf of, the
 *       Licensor for the purpose of discussing and improving the Work, but
 *       excluding communication that is conspicuously marked or otherwise
 *       designated in writing by the copyright owner as "Not a Contribution."
 *
 *       "Contributor" shall mean Licensor and any individual or Legal Entity
 *       on behalf of whom a Contribution has been received by Licensor and
 *       subsequently incorporated within the Work.
 *
 *    2. Grant of Copyright License. Subject to the terms and conditions of
 *       this License, each Contributor hereby grants to You a perpetual,
 *       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 *       copyright license to reproduce, prepare Derivative Works of,
 *       publicly display, publicly perform, sublicense, and distribute the
 *       Work and such Derivative Works in Source or Object form.
 *
 *    3. Grant of Patent License. Subject to the terms and conditions of
 *       this License, each Contributor hereby grants to You a perpetual,
 *       worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 *       (except as stated in this section) patent license to make, have made,
 *       use, offer to sell, sell, import, and otherwise transfer the Work,
 *       where such license applies only to those patent claims licensable
 *       by such Contributor that are necessarily infringed by their
 *       Contribution(s) alone or by combination of their Contribution(s)
 *       with the Work to which such Contribution(s) was submitted. If You
 *       institute patent litigation against any entity (including a
 *       cross-claim or counterclaim in a lawsuit) alleging that the Work
 *       or a Contribution incorporated within the Work constitutes direct
 *       or contributory patent infringement, then any patent licenses
 *       granted to You under this License for that Work shall terminate
 *       as of the date such litigation is filed.
 *
 *    4. Redistribution. You may reproduce and distribute copies of the
 *       Work or Derivative Works thereof in any medium, with or without
 *       modifications, and in Source or Object form, provided that You
 *       meet the following conditions:
 *
 *       (a) You must give any other recipients of the Work or
 *           Derivative Works a copy of this License; and
 *
 *       (b) You must cause any modified files to carry prominent notices
 *           stating that You changed the files; and
 *
 *       (c) You must retain, in the Source form of any Derivative Works
 *           that You distribute, all copyright, patent, trademark, and
 *           attribution notices from the Source form of the Work,
 *           excluding those notices that do not pertain to any part of
 *           the Derivative Works; and
 *
 *       (d) If the Work includes a "NOTICE" text file as part of its
 *           distribution, then any Derivative Works that You distribute must
 *           include a readable copy of the attribution notices contained
 *           within such NOTICE file, excluding those notices that do not
 *           pertain to any part of the Derivative Works, in at least one
 *           of the following places: within a NOTICE text file distributed
 *           as part of the Derivative Works; within the Source form or
 *           documentation, if provided along with the Derivative Works; or,
 *           within a display generated by the Derivative Works, if and
 *           wherever such third-party notices normally appear. The contents
 *           of the NOTICE file are for informational purposes only and
 *           do not modify the License. You may add Your own attribution
 *           notices within Derivative Works that You distribute, alongside
 *           or as an addendum to the NOTICE text from the Work, provided
 *           that such additional attribution notices cannot be construed
 *           as modifying the License.
 *
 *       You may add Your own copyright statement to Your modifications and
 *       may provide additional or different license terms and conditions
 *       for use, reproduction, or distribution of Your modifications, or
 *       for any such Derivative Works as a whole, provided Your use,
 *       reproduction, and distribution of the Work otherwise complies with
 *       the conditions stated in this License.
 *
 *    5. Submission of Contributions. Unless You explicitly state otherwise,
 *       any Contribution intentionally submitted for inclusion in the Work
 *       by You to the Licensor shall be under the terms and conditions of
 *       this License, without any additional terms or conditions.
 *       Notwithstanding the above, nothing herein shall supersede or modify
 *       the terms of any separate license agreement you may have executed
 *       with Licensor regarding such Contributions.
 *
 *    6. Trademarks. This License does not grant permission to use the trade
 *       names, trademarks, service marks, or product names of the Licensor,
 *       except as required for reasonable and customary use in describing the
 *       origin of the Work and reproducing the content of the NOTICE file.
 *
 *    7. Disclaimer of Warranty. Unless required by applicable law or
 *       agreed to in writing, Licensor provides the Work (and each
 *       Contributor provides its Contributions) on an "AS IS" BASIS,
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 *       implied, including, without limitation, any warranties or conditions
 *       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 *       PARTICULAR PURPOSE. You are solely responsible for determining the
 *       appropriateness of using or redistributing the Work and assume any
 *       risks associated with Your exercise of permissions under this License.
 *
 *    8. Limitation of Liability. In no event and under no legal theory,
 *       whether in tort (including negligence), contract, or otherwise,
 *       unless required by applicable law (such as deliberate and grossly
 *       negligent acts) or agreed to in writing, shall any Contributor be
 *       liable to You for damages, including any direct, indirect, special,
 *       incidental, or consequential damages of any character arising as a
 *       result of this License or out of the use or inability to use the
 *       Work (including but not limited to damages for loss of goodwill,
 *       work stoppage, computer failure or malfunction, or any and all
 *       other commercial damages or losses), even if such Contributor
 *       has been advised of the possibility of such damages.
 *
 *    9. Accepting Warranty or Additional Liability. While redistributing
 *       the Work or Derivative Works thereof, You may choose to offer,
 *       and charge a fee for, acceptance of support, warranty, indemnity,
 *       or other liability obligations and/or rights consistent with this
 *       License. However, in accepting such obligations, You may act only
 *       on Your own behalf and on Your sole responsibility, not on behalf
 *       of any other Contributor, and only if You agree to indemnify,
 *       defend, and hold each Contributor harmless for any liability
 *       incurred by, or claims asserted against, such Contributor by reason
 *       of your accepting any such warranty or additional liability.
 *
 *    END OF TERMS AND CONDITIONS
 *
 *    APPENDIX: How to apply the Apache License to your work.
 *
 *       To apply the Apache License to your work, attach the following
 *       boilerplate notice, with the fields enclosed by brackets "[]"
 *       replaced with your own identifying information. (Don't include
 *       the brackets!)  The text should be enclosed in the appropriate
 *       comment syntax for the file format. We also recommend that a
 *       file or class name and description of purpose be included on the
 *       same "printed page" as the copyright notice for easier
 *       identification within third-party archives.
 *
 *    Copyright Brightcove, Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

(function(preact, preact_jsx_runtime, preact_hooks, preact_compat) {
	"use strict";
	var _GM = (() => typeof GM != "undefined" ? GM : void 0)();
	var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
	var LEVEL_VALUES = {
		debug: 0,
		info: 1,
		warn: 2,
		error: 3,
		silent: 4
	};
	var LEVEL_STYLES = {
		debug: "color: #8c8c8c",
		info: "color: #53fc18",
		warn: "color: #f5c451",
		error: "color: #ff6b6b"
	};
	var BRAND_STYLE = [
		"background: #53fc18",
		"border-radius: 3px",
		"color: #071402",
		"font-weight: 700",
		"padding: 1px 4px"
	].join("; ");
	var SCOPE_STYLE = "color: #b0b0b0; font-weight: 600";
	var RESET_STYLE = "color: inherit; font-weight: normal";
	var HISTORY_NOTIFY_INTERVAL_MS = 200;
	var config = {
		colors: true,
		filters: ["*"],
		historyLimit: 250,
		level: "info"
	};
	var history = [];
	var historyListeners = new Set();
	var historyNotifyTimer;
	var nextLogEntryId = 1;
	function notifyHistoryListeners() {
		const snapshot = getLogHistory();
		for (const listener of historyListeners) try {
			listener(snapshot);
		} catch (error) {
			console.error("[KICK Enhancer] Log history listener failed.", error);
		}
	}
	function cancelHistoryNotification() {
		if (historyNotifyTimer === void 0) return;
		globalThis.clearTimeout(historyNotifyTimer);
		historyNotifyTimer = void 0;
	}
	function flushHistoryListeners() {
		cancelHistoryNotification();
		notifyHistoryListeners();
	}
	function scheduleHistoryNotification() {
		if (historyListeners.size === 0 || historyNotifyTimer !== void 0) return;
		historyNotifyTimer = globalThis.setTimeout(() => {
			historyNotifyTimer = void 0;
			notifyHistoryListeners();
		}, HISTORY_NOTIFY_INTERVAL_MS);
	}
	function matchesPattern(scope, pattern) {
		if (pattern === "*") return true;
		if (pattern.endsWith("*")) return scope.startsWith(pattern.slice(0, -1));
		return scope === pattern;
	}
	function isScopeEnabled(scope) {
		const includedPatterns = config.filters.filter((pattern) => !pattern.startsWith("-"));
		const excludedPatterns = config.filters.filter((pattern) => pattern.startsWith("-")).map((pattern) => pattern.slice(1));
		return (includedPatterns.length === 0 || includedPatterns.some((pattern) => matchesPattern(scope, pattern))) && !excludedPatterns.some((pattern) => matchesPattern(scope, pattern));
	}
	function remember(entry) {
		if (config.historyLimit <= 0) return;
		history.push(entry);
		if (history.length > config.historyLimit) history = config.historyLimit === 0 ? [] : history.slice(-config.historyLimit);
		scheduleHistoryNotification();
	}
	function write(level, scope, values) {
		remember({
			arguments: values,
			id: nextLogEntryId,
			level,
			scope,
			timestamp: Date.now()
		});
		nextLogEntryId += 1;
		if (LEVEL_VALUES[level] < LEVEL_VALUES[config.level] || !isScopeEnabled(scope)) return;
		const method = console[level].bind(console);
		if (!config.colors) {
			method(`[KICK Enhancer] [${scope}]`, ...values);
			return;
		}
		method("%cKICK Enhancer%c %s%c", BRAND_STYLE, `${SCOPE_STYLE}; ${LEVEL_STYLES[level]}`, scope, RESET_STYLE, ...values);
	}
	function createLogger(scope) {
		return {
			child: (childScope) => createLogger(`${scope}:${childScope}`),
			debug: (...values) => write("debug", scope, values),
			error: (...values) => write("error", scope, values),
			info: (...values) => write("info", scope, values),
			warn: (...values) => write("warn", scope, values)
		};
	}
	function getLogHistory() {
		return [...history];
	}
	function clearLogHistory() {
		if (history.length === 0) return;
		history = [];
		flushHistoryListeners();
	}
	function subscribeLogHistory(listener) {
		historyListeners.add(listener);
		return () => {
			historyListeners.delete(listener);
			if (historyListeners.size === 0) cancelHistoryNotification();
		};
	}
	var CHAT_FONT_FAMILIES = [
		"arial",
		"verdana",
		"tahoma",
		"trebuchet",
		"georgia",
		"monospace"
	];
	var CHAT_FONT_WEIGHTS = [
		100,
		200,
		300,
		400,
		500,
		600,
		700,
		800,
		900
	];
	var DEFAULT_SETTINGS = {
		chat: {
			fontFamily: null,
			fontSize: null,
			fontWeight: null,
			messageDividers: false,
			messageSpacing: null
		},
		ui: {
			hideFollowingRecommendations: false,
			hideGamblingStreams: false,
			hideHomepageCarousel: false,
			hideRecommendedChannels: false,
			rememberSidebarState: false,
			showClipDownloadButtons: true,
			showHiddenViewerCounts: true,
			showStreamUptime: false,
			sidebarCollapsed: false
		},
		version: 5
	};
	function parseSettings(value) {
		if (!isRecord$2(value)) return DEFAULT_SETTINGS;
		const chat = isRecord$2(value.chat) ? value.chat : {};
		const ui = isRecord$2(value.ui) ? value.ui : {};
		return {
			chat: {
				fontFamily: normalizeChatFontFamily(chat.fontFamily),
				fontSize: normalizeChatValue(chat.fontSize, 10, 24),
				fontWeight: normalizeChatFontWeight(chat.fontWeight),
				messageDividers: chat.messageDividers === true,
				messageSpacing: normalizeChatValue(chat.messageSpacing, 0, 12)
			},
			ui: {
				hideFollowingRecommendations: ui.hideFollowingRecommendations === true,
				hideGamblingStreams: ui.hideGamblingStreams === true,
				hideHomepageCarousel: ui.hideHomepageCarousel === true,
				hideRecommendedChannels: ui.hideRecommendedChannels === true,
				rememberSidebarState: ui.rememberSidebarState === true,
				showClipDownloadButtons: ui.showClipDownloadButtons !== false,
				showHiddenViewerCounts: ui.showHiddenViewerCounts !== false,
				showStreamUptime: ui.showStreamUptime === true,
				sidebarCollapsed: ui.sidebarCollapsed === true
			},
			version: 5
		};
	}
	function parseSettingsFile(text) {
		let value;
		try {
			value = JSON.parse(text);
		} catch {
			return { ok: false };
		}
		if (!isRecord$2(value) || !hasRecognizedSetting(value)) return { ok: false };
		const settings = parseSettings(value);
		return {
			compatibilityWarning: !matchesCanonicalValue(value, settings),
			ok: true,
			settings
		};
	}
	function serializeSettings(settings) {
		return `${JSON.stringify(settings, null, 2)}\n`;
	}
	function normalizeChatFontFamily(value) {
		return typeof value === "string" && CHAT_FONT_FAMILIES.includes(value) ? value : null;
	}
	function normalizeChatFontWeight(value) {
		return typeof value === "number" && CHAT_FONT_WEIGHTS.includes(value) ? value : null;
	}
	function normalizeChatValue(value, min, max) {
		if (typeof value !== "number" || !Number.isFinite(value)) return null;
		return Math.min(max, Math.max(min, Math.round(value)));
	}
	function hasRecognizedSetting(value) {
		return hasRecognizedSectionValue(value.chat, DEFAULT_SETTINGS.chat) || hasRecognizedSectionValue(value.ui, DEFAULT_SETTINGS.ui);
	}
	function hasRecognizedSectionValue(value, expected) {
		return isRecord$2(value) && Object.keys(expected).some((key) => Object.prototype.hasOwnProperty.call(value, key));
	}
	function matchesCanonicalValue(value, expected) {
		if (!isRecord$2(expected)) return Object.is(value, expected);
		if (!isRecord$2(value)) return false;
		const expectedKeys = Object.keys(expected);
		const valueKeys = Object.keys(value);
		return expectedKeys.length === valueKeys.length && expectedKeys.every((key) => Object.prototype.hasOwnProperty.call(value, key) && matchesCanonicalValue(value[key], expected[key]));
	}
	function isRecord$2(value) {
		return value !== null && typeof value === "object" && !Array.isArray(value);
	}
	var SETTINGS_KEY = "settings";
	var log$8 = createLogger("settings");
	var listeners$1 = new Set();
	var currentSettings = DEFAULT_SETTINGS;
	var pendingWrite = Promise.resolve();
	function notifyListeners() {
		for (const listener of listeners$1) listener(currentSettings);
	}
	async function initializeSettings() {
		try {
			const storedSettings = await _GM.getValue(SETTINGS_KEY, "");
			currentSettings = storedSettings ? parseSettings(JSON.parse(storedSettings)) : DEFAULT_SETTINGS;
		} catch (error) {
			log$8.warn("Load failed; using defaults", error);
			currentSettings = DEFAULT_SETTINGS;
		}
	}
	function getSettings() {
		return currentSettings;
	}
	function resetSettings() {
		return updateSettings(() => DEFAULT_SETTINGS);
	}
	function replaceSettings(settings) {
		return updateSettings(() => settings);
	}
	function subscribeSettings(listener) {
		listeners$1.add(listener);
		return () => {
			listeners$1.delete(listener);
		};
	}
	function observeSetting(selector, listener) {
		let currentValue = selector(currentSettings);
		listener(currentValue);
		return subscribeSettings((settings) => {
			const nextValue = selector(settings);
			if (Object.is(currentValue, nextValue)) return;
			currentValue = nextValue;
			listener(nextValue);
		});
	}
	function updateSettings(update) {
		const nextSettings = update(currentSettings);
		if (nextSettings === currentSettings) return pendingWrite;
		currentSettings = nextSettings;
		notifyListeners();
		const serializedSettings = JSON.stringify(currentSettings);
		pendingWrite = pendingWrite.catch(() => void 0).then(() => _GM.setValue(SETTINGS_KEY, serializedSettings)).catch((error) => {
			log$8.error("Save failed", error);
		});
		return pendingWrite;
	}
	function createChatAppearanceStyles({ fontFamily, fontSize, fontWeight, messageDividers, messageSpacing }) {
		const declarations = [
			fontFamily === null ? void 0 : `font-family: ${FONT_FAMILY_STACKS[fontFamily]};`,
			fontSize === null ? void 0 : `--chatroom-font-size: ${fontSize}px;`,
			messageSpacing === null ? void 0 : `--chatroom-message-spacing: ${messageSpacing}px;`
		].filter((declaration) => declaration !== void 0);
		const rules = [];
		if (declarations.length > 0) rules.push(`#channel-chatroom {\n  ${declarations.join("\n  ")}\n}`);
		if (messageDividers) rules.push([
			"#chatroom-messages > div > [data-index]::after {",
			"  position: absolute;",
			"  right: 0;",
			"  bottom: 0;",
			"  left: 0;",
			"  height: 1px;",
			"  pointer-events: none;",
			"  content: \"\";",
			"  background: #161616;",
			"}"
		].join("\n"));
		if (fontWeight !== null) rules.push([
			"#chatroom-messages > div > [data-index] .font-normal[class~=\"leading-[1.55]\"] {",
			`  font-weight: ${fontWeight};`,
			"}"
		].join("\n"));
		if (rules.length === 0) return "";
		return rules.join("\n\n");
	}
	var FONT_FAMILY_STACKS = {
		arial: "Arial, Helvetica, sans-serif",
		georgia: "Georgia, \"Times New Roman\", serif",
		monospace: "ui-monospace, Consolas, \"Courier New\", monospace",
		tahoma: "Tahoma, Verdana, sans-serif",
		trebuchet: "\"Trebuchet MS\", Arial, sans-serif",
		verdana: "Verdana, Geneva, sans-serif"
	};
	var STYLE_ID$8 = "kick-enhancer-chat-appearance";
	var stopActiveFeature$4;
	function startChatAppearance() {
		stopActiveFeature$4?.();
		let stopped = false;
		const stopObserving = observeSetting((settings) => settings.chat, applyChatAppearance);
		const stop = () => {
			if (stopped) return;
			stopped = true;
			stopObserving();
			document.getElementById(STYLE_ID$8)?.remove();
			if (stopActiveFeature$4 === stop) stopActiveFeature$4 = void 0;
		};
		stopActiveFeature$4 = stop;
		return stop;
	}
	function applyChatAppearance(settings) {
		const styles = createChatAppearanceStyles(settings);
		const existingStyle = document.getElementById(STYLE_ID$8);
		if (!styles) {
			existingStyle?.remove();
			return;
		}
		if (existingStyle) {
			if (existingStyle.textContent !== styles) existingStyle.textContent = styles;
			return;
		}
		const style = document.createElement("style");
		style.id = STYLE_ID$8;
		style.textContent = styles;
		document.documentElement.append(style);
	}
	function onDocumentElementReady(callback, ownerDocument = document, createObserver = (observerCallback) => new MutationObserver(observerCallback)) {
		if (ownerDocument.documentElement) {
			callback();
			return () => void 0;
		}
		let active = true;
		const observer = createObserver(() => {
			if (!active || !ownerDocument.documentElement) return;
			active = false;
			observer.disconnect();
			callback();
		});
		observer.observe(ownerDocument, { childList: true });
		return () => {
			active = false;
			observer.disconnect();
		};
	}
	var shared_ui_default = ".ke-confirmation-host {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  min-width: 0;\n  min-height: 0;\n  overflow: hidden;\n}\n\n.ke-confirmation-layer {\n  position: absolute;\n  z-index: 10;\n  inset: 0;\n  display: grid;\n  padding: 1rem;\n  place-items: center;\n  background: rgba(0, 0, 0, 0.32);\n  backdrop-filter: blur(3px);\n}\n\n.ke-confirmation-dialog {\n  width: min(24rem, 100%);\n  padding: 1.1rem;\n  border: 1px solid #303030;\n  border-radius: 0.45rem;\n  background: #080808;\n  box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.55);\n}\n\n.ke-confirmation-dialog__copy {\n  display: grid;\n  gap: 0.45rem;\n}\n\n.ke-confirmation-dialog__title {\n  margin: 0;\n  color: #f2f2f2;\n  font-size: 1rem;\n  font-weight: 700;\n  line-height: 1.3;\n}\n\n.ke-confirmation-dialog__description {\n  margin: 0;\n  color: #747474;\n  font-size: 0.825rem;\n  font-weight: 500;\n  line-height: 1.5;\n}\n\n.ke-confirmation-dialog__actions {\n  display: flex;\n  justify-content: flex-end;\n  gap: 0.65rem;\n  margin-top: 1rem;\n}\n\n.ke-button,\n.ke-text-field,\n.ke-select-box__input,\n.ke-track-bar {\n  box-sizing: border-box;\n  font: inherit;\n}\n\n.ke-button {\n  min-height: 2.35rem;\n  padding: 0 0.85rem;\n  border: 1px solid #1b1b1b;\n  border-radius: 0.45rem;\n  background: #0a0a0a;\n  color: #f2f2f2;\n  font-size: 0.875rem;\n  font-weight: 650;\n  line-height: 1;\n  cursor: pointer;\n  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;\n}\n.ke-button:hover:not(:disabled) {\n  border-color: #303030;\n  background: #101010;\n}\n.ke-button:focus-visible {\n  outline: 2px solid #53fc18;\n  outline-offset: 2px;\n}\n.ke-button:disabled {\n  cursor: not-allowed;\n  opacity: 0.45;\n}\n.ke-button--compact {\n  min-height: 2rem;\n  padding-inline: 0.65rem;\n}\n.ke-button--primary {\n  border-color: #53fc18;\n  background: #53fc18;\n  color: #071402;\n}\n.ke-button--primary:hover:not(:disabled) {\n  border-color: #7dff50;\n  background: #7dff50;\n}\n.ke-button--danger {\n  color: #ff6b6b;\n}\n\n.ke-form-field {\n  display: grid;\n  min-width: 0;\n  gap: 0.4rem;\n  color: #f2f2f2;\n}\n\n.ke-form-field__label {\n  display: block;\n  font-size: 0.875rem;\n  font-weight: 650;\n  line-height: 1.25;\n}\n\n.ke-form-field__description {\n  display: block;\n  color: #747474;\n  font-size: 0.78rem;\n  line-height: 1.4;\n  font-weight: 500;\n}\n\n.ke-text-field,\n.ke-select-box__input {\n  width: 100%;\n  min-height: 2.35rem;\n  border: 1px solid #1b1b1b;\n  border-radius: 0.45rem;\n  outline: none;\n  background: #0a0a0a;\n  color: #f2f2f2;\n  font-size: 0.875rem;\n  transition: background 140ms ease, border-color 140ms ease;\n}\n.ke-text-field:hover:not(:disabled),\n.ke-select-box__input:hover:not(:disabled) {\n  border-color: #303030;\n  background: #101010;\n}\n.ke-text-field:focus-visible,\n.ke-select-box__input:focus-visible {\n  border-color: #53fc18;\n  box-shadow: 0 0 0 1px #53fc18;\n}\n.ke-text-field:disabled,\n.ke-select-box__input:disabled {\n  cursor: not-allowed;\n  opacity: 0.45;\n}\n\n.ke-text-field {\n  padding: 0 0.72rem;\n  user-select: text;\n}\n.ke-text-field::placeholder {\n  color: #8c8c8c;\n}\n\n.ke-text-field-shell {\n  display: flex;\n  align-items: stretch;\n}\n\n.ke-text-field-shell .ke-text-field {\n  flex: 1 1 auto;\n  min-width: 0;\n  border-radius: 0.45rem 0 0 0.45rem;\n}\n\n.ke-text-field__suffix {\n  display: flex;\n  flex: 0 0 auto;\n  align-items: center;\n  padding-inline: 0.7rem;\n  border: 1px solid #1b1b1b;\n  border-left: 0;\n  border-radius: 0 0.45rem 0.45rem 0;\n  background: #080808;\n  color: #8c8c8c;\n  font-size: 0.875rem;\n}\n\n.ke-text-field-shell:focus-within .ke-text-field__suffix {\n  border-color: #53fc18;\n}\n\n.ke-select-box {\n  position: relative;\n  display: block;\n}\n\n.ke-select-box__input {\n  appearance: none;\n  padding: 0 2.2rem 0 0.72rem;\n  color-scheme: dark;\n  cursor: pointer;\n}\n\n.ke-select-box__chevron {\n  position: absolute;\n  top: 50%;\n  right: 0.85rem;\n  width: 0.45rem;\n  height: 0.45rem;\n  border-right: 1.5px solid #8c8c8c;\n  border-bottom: 1.5px solid #8c8c8c;\n  pointer-events: none;\n  transform: translateY(-70%) rotate(45deg);\n}\n\n.ke-toggle {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 1rem;\n  color: #f2f2f2;\n  cursor: pointer;\n}\n\n.ke-toggle__copy {\n  display: grid;\n  min-width: 0;\n  gap: 0.4rem;\n}\n\n.ke-toggle__control {\n  position: relative;\n  flex: 0 0 auto;\n}\n\n.ke-toggle__input {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  overflow: hidden;\n  opacity: 0;\n  pointer-events: none;\n}\n\n.ke-toggle__track {\n  position: relative;\n  display: block;\n  width: 2.4rem;\n  height: 1.35rem;\n  border: 1px solid #303030;\n  border-radius: 999px;\n  background: #0a0a0a;\n  transition: background 140ms ease, border-color 140ms ease;\n}\n\n.ke-toggle__thumb {\n  position: absolute;\n  top: 0.18rem;\n  left: 0.18rem;\n  width: 0.85rem;\n  height: 0.85rem;\n  border-radius: 50%;\n  background: #8c8c8c;\n  transition: background 140ms ease, transform 140ms ease;\n}\n\n.ke-toggle__input:checked + .ke-toggle__track {\n  border-color: #53fc18;\n  background: #53fc18;\n}\n\n.ke-toggle__input:checked + .ke-toggle__track .ke-toggle__thumb {\n  background: #071402;\n  transform: translateX(1.02rem);\n}\n\n.ke-toggle__input:focus-visible + .ke-toggle__track {\n  outline: 2px solid #53fc18;\n  outline-offset: 2px;\n}\n\n.ke-toggle__input:disabled + .ke-toggle__track {\n  opacity: 0.45;\n}\n\n.ke-track-bar__heading {\n  display: flex;\n  align-items: baseline;\n  justify-content: space-between;\n  gap: 1rem;\n}\n\n.ke-track-bar__value {\n  color: #8c8c8c;\n  font-size: 0.78rem;\n  font-variant-numeric: tabular-nums;\n}\n\n.ke-track-bar {\n  width: 100%;\n  height: 1.25rem;\n  margin: 0;\n  appearance: none;\n  outline: none;\n  background: transparent;\n  cursor: pointer;\n}\n.ke-track-bar::-webkit-slider-runnable-track {\n  height: 0.28rem;\n  border-radius: 999px;\n  background: linear-gradient(to right, #53fc18 0 var(--ke-track-progress), #1b1b1b var(--ke-track-progress) 100%);\n}\n.ke-track-bar::-moz-range-track {\n  height: 0.28rem;\n  border-radius: 999px;\n  background: #1b1b1b;\n}\n.ke-track-bar::-moz-range-progress {\n  height: 0.28rem;\n  border-radius: 999px;\n  background: #53fc18;\n}\n.ke-track-bar::-webkit-slider-thumb {\n  width: 1rem;\n  height: 1rem;\n  margin-top: -0.36rem;\n  appearance: none;\n  border: 2px solid #53fc18;\n  border-radius: 50%;\n  background: #050505;\n}\n.ke-track-bar::-moz-range-thumb {\n  width: 0.8rem;\n  height: 0.8rem;\n  border: 2px solid #53fc18;\n  border-radius: 50%;\n  background: #050505;\n}\n.ke-track-bar:focus-visible::-webkit-slider-thumb {\n  outline: 2px solid #53fc18;\n  outline-offset: 2px;\n}\n.ke-track-bar:focus-visible::-moz-range-thumb {\n  outline: 2px solid #53fc18;\n  outline-offset: 2px;\n}\n\n.ke-list-view {\n  --ke-list-view-scrollbar-gutter: 0.5rem;\n  min-width: 0;\n  min-height: 0;\n  display: grid;\n  grid-template-rows: 2rem minmax(0, 1fr);\n  overflow: hidden;\n  border: 1px solid #1b1b1b;\n  border-radius: 0.45rem;\n  background: #080808;\n  user-select: none;\n}\n\n.ke-list-view__header-group,\n.ke-list-view__scroll {\n  min-width: 0;\n  min-height: 0;\n  box-sizing: border-box;\n  padding-right: var(--ke-list-view-scrollbar-gutter);\n}\n\n.ke-list-view__scroll {\n  --ke-scroll-indicator-right: var(\n    --ke-list-view-scrollbar-gutter\n  );\n}\n\n.ke-list-view__header-group {\n  border-bottom: 1px solid #1b1b1b;\n  background: #0a0a0a;\n}\n\n.ke-list-view__header,\n.ke-list-view__row {\n  min-width: 0;\n  width: 100%;\n  display: grid;\n}\n\n.ke-list-view__header {\n  height: 100%;\n  color: #8c8c8c;\n  font-size: 0.72rem;\n  font-weight: 700;\n  letter-spacing: 0.04em;\n  text-transform: uppercase;\n}\n\n.ke-list-view__header-cell,\n.ke-list-view__cell {\n  min-width: 0;\n  display: flex;\n  align-items: center;\n  padding: 0.42rem 0.6rem;\n  overflow: hidden;\n}\n.ke-list-view__header-cell:not(:last-child),\n.ke-list-view__cell:not(:last-child) {\n  border-right: 1px solid #1b1b1b;\n}\n.ke-list-view__header-cell[data-align=center],\n.ke-list-view__cell[data-align=center] {\n  justify-content: center;\n  text-align: center;\n}\n.ke-list-view__header-cell[data-align=end],\n.ke-list-view__cell[data-align=end] {\n  justify-content: flex-end;\n  text-align: right;\n}\n\n.ke-list-view__header-label,\n.ke-list-view__cell-content {\n  min-width: 0;\n  max-width: 100%;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.ke-list-view__body {\n  position: relative;\n  min-width: 0;\n  min-height: 100%;\n}\n.ke-list-view__body[data-virtualized=true] {\n  contain: layout paint style;\n}\n\n.ke-list-view__row {\n  min-height: 2.125rem;\n  box-sizing: border-box;\n  border-bottom: 1px solid #1b1b1b;\n  color: #f2f2f2;\n  font-size: 0.76rem;\n}\n.ke-list-view__row[data-last-row=true] {\n  border-bottom: 0;\n}\n.ke-list-view__row[data-virtualized=true] {\n  position: absolute;\n  top: 0;\n  left: 0;\n  contain: layout paint style;\n}\n.ke-list-view__row:hover {\n  background: #101010;\n}\n.ke-list-view__row.is-interactive {\n  cursor: pointer;\n}\n.ke-list-view__row.is-interactive:focus-visible {\n  outline: 1px solid #53fc18;\n  outline-offset: -1px;\n}\n\n.ke-list-view__empty {\n  min-height: 4rem;\n  display: grid;\n  place-items: center;\n  padding: 1rem;\n  color: #8c8c8c;\n  font-size: 0.78rem;\n  text-align: center;\n}\n\n.ke-list-view__live-status {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0 0 0 0);\n  clip-path: inset(50%);\n  border: 0;\n  white-space: nowrap;\n}\n\n.ke-modal {\n  width: min(36rem, 100vw - 2rem);\n  max-width: none;\n  max-height: calc(100vh - 2rem);\n  margin: auto;\n  padding: 0;\n  overflow: visible;\n  border: 1px solid #1b1b1b;\n  border-radius: 0.65rem;\n  outline: none;\n  background: transparent;\n  color: #f2f2f2;\n  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n  font-size: 16px;\n  line-height: 1.5;\n  box-shadow: 0 1.5rem 5rem rgba(0, 0, 0, 0.65);\n  user-select: none;\n}\n.ke-modal::backdrop {\n  background: rgba(0, 0, 0, 0.62);\n  backdrop-filter: blur(2px);\n}\n\n.ke-modal,\n.ke-modal * {\n  box-sizing: border-box;\n}\n\n.ke-modal ::selection {\n  background: #fff;\n  color: #000;\n}\n\n.ke-modal__surface {\n  display: grid;\n  max-height: calc(100vh - 2rem);\n  overflow: hidden;\n  border-radius: inherit;\n  background: #050505;\n  animation: ke-modal-enter 150ms ease-out;\n}\n\n.ke-modal__header {\n  display: flex;\n  align-items: flex-start;\n  justify-content: space-between;\n  gap: 1rem;\n  padding: 1.25rem 1.25rem 1rem;\n  border-bottom: 1px solid #1b1b1b;\n}\n\n.ke-modal__heading {\n  min-width: 0;\n}\n\n.ke-modal__identity {\n  min-width: 0;\n  display: flex;\n  align-items: center;\n  gap: 0.85rem;\n}\n\n.ke-modal__icon {\n  width: 2.75rem;\n  height: 2.75rem;\n  flex: 0 0 auto;\n  object-fit: contain;\n}\n\n.ke-modal__title {\n  margin: 0;\n  color: #f2f2f2;\n  font-size: 1.1rem;\n  font-weight: 750;\n  line-height: 1.25;\n}\n\n.ke-modal__description {\n  margin: 0.35rem 0 0;\n  color: #8c8c8c;\n  font-size: 0.8rem;\n  font-weight: 500;\n  line-height: 1.45;\n}\n\n.ke-modal__close {\n  display: grid;\n  width: 2rem;\n  min-width: 2rem;\n  min-height: 2rem;\n  padding: 0;\n  place-items: center;\n  font-size: 1.3rem;\n  font-weight: 400;\n}\n\n.ke-modal__body {\n  min-height: 0;\n  padding: 1.25rem;\n  overflow-y: auto;\n  scrollbar-color: #303030 transparent;\n}\n\n.ke-modal__footer {\n  display: flex;\n  justify-content: flex-end;\n  gap: 0.65rem;\n  padding: 1rem 1.25rem;\n  border-top: 1px solid #1b1b1b;\n  background: #080808;\n}\n\n.ke-settings {\n  display: grid;\n  gap: 1.35rem;\n}\n\n.ke-settings__actions {\n  display: flex;\n  justify-content: flex-end;\n}\n\n.ke-workspace-modal {\n  --ke-workspace-modal-gutter: clamp(1rem, 4vw, 2rem);\n  --ke-workspace-modal-height: 52rem;\n  --ke-workspace-modal-width: 52rem;\n  width: min(var(--ke-workspace-modal-width), 100vw - var(--ke-workspace-modal-gutter));\n  max-height: calc(100dvh - var(--ke-workspace-modal-gutter));\n}\n\n.ke-workspace-modal .ke-modal__surface {\n  height: min(var(--ke-workspace-modal-height), 100dvh - var(--ke-workspace-modal-gutter));\n  grid-template-rows: auto minmax(0, 1fr) auto;\n}\n\n.ke-workspace-modal .ke-modal__body {\n  padding: 0;\n  overflow: hidden;\n}\n\n.ke-settings-modal {\n  --ke-workspace-modal-height: 46rem;\n}\n\n.ke-settings-modal__tabs {\n  width: 100%;\n  height: 100%;\n}\n\n.ke-settings-modal__github {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.45rem;\n  margin-right: auto;\n}\n.ke-settings-modal__github:hover:not(:disabled) {\n  background: #0a0a0a;\n  color: #53fc18;\n}\n\n.ke-settings-modal__github-icon {\n  width: 1.05rem;\n  height: 1.05rem;\n  flex: 0 0 auto;\n}\n\n@keyframes ke-modal-enter {\n  from {\n    opacity: 0;\n    transform: translateY(0.35rem) scale(0.985);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0) scale(1);\n  }\n}\n@media (prefers-reduced-motion: reduce) {\n  .ke-modal__surface {\n    animation: none;\n  }\n}\n.ke-scroll-area {\n  position: relative;\n  min-width: 0;\n  min-height: 0;\n  height: 100%;\n  overflow: hidden;\n}\n.ke-scroll-area[data-height=content] {\n  height: auto;\n}\n.ke-scroll-area[data-height=content] .ke-scroll-area__viewport {\n  height: auto;\n  max-height: inherit;\n}\n.ke-scroll-area[data-height=content] .ke-scroll-area__content {\n  min-height: 0;\n}\n\n.ke-scroll-area__viewport {\n  min-width: 0;\n  min-height: 0;\n  width: 100%;\n  height: 100%;\n  overflow: auto;\n  overscroll-behavior: contain;\n  scrollbar-width: none;\n}\n.ke-scroll-area__viewport::-webkit-scrollbar {\n  width: 0;\n  height: 0;\n}\n.ke-scroll-area__viewport:focus {\n  outline: none;\n}\n.ke-scroll-area__viewport:focus-visible {\n  outline: 1px solid #1b1b1b;\n  outline-offset: -1px;\n}\n\n.ke-scroll-area__content {\n  min-width: 100%;\n  min-height: 100%;\n}\n\n.ke-scroll-area[data-scroll-indicators=true]::before, .ke-scroll-area[data-scroll-indicators=true]::after {\n  position: absolute;\n  z-index: 1;\n  right: var(--ke-scroll-indicator-right, 0);\n  left: 0;\n  height: 0.75rem;\n  content: \"\";\n  pointer-events: none;\n}\n.ke-scroll-area[data-scroll-indicators=true][data-overflow-top]::before {\n  top: 0;\n  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), transparent);\n}\n.ke-scroll-area[data-scroll-indicators=true][data-overflow-bottom]::after {\n  bottom: 0;\n  background: linear-gradient(to top, rgba(0, 0, 0, 0.5), transparent);\n}\n\n.ke-scroll-area__thumb {\n  position: absolute;\n  z-index: 2;\n  top: 0;\n  right: 0.25rem;\n  width: 0.25rem;\n  border-radius: 0.125rem;\n  background: #fff;\n  cursor: default;\n  opacity: 0;\n  pointer-events: none;\n  touch-action: none;\n  transition: background 140ms ease, opacity 140ms ease;\n}\n.ke-scroll-area__thumb:not([data-visible=true]) {\n  display: none;\n}\n\n.ke-scroll-area:hover > .ke-scroll-area__thumb[data-visible=true],\n.ke-scroll-area:focus-within > .ke-scroll-area__thumb[data-visible=true],\n.ke-scroll-area.is-dragging > .ke-scroll-area__thumb[data-visible=true] {\n  background: #fff;\n  opacity: 1;\n  pointer-events: auto;\n}\n\n.ke-scroll-area[data-scrollbar=compact] > .ke-scroll-area__thumb {\n  right: 0.15rem;\n  width: 0.1875rem;\n}\n\n.ke-scroll-area[data-scrollbar=overlay] > .ke-scroll-area__thumb {\n  right: 0.3rem;\n  width: 0.25rem;\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .ke-scroll-area__thumb {\n    transition: none;\n  }\n}\n.ke-tabs {\n  width: 100%;\n  height: 100%;\n  min-width: 0;\n  min-height: 0;\n  display: grid;\n  grid-template-rows: auto minmax(0, 1fr);\n  overflow: hidden;\n}\n\n.ke-tabs__list {\n  display: flex;\n  min-width: 0;\n  min-height: 2.5rem;\n  align-items: stretch;\n  overflow: hidden;\n  border-bottom: 1px solid #1b1b1b;\n  background: #050505;\n}\n\n.ke-tabs__tab {\n  min-width: 0;\n  flex: 0 1 auto;\n  padding: 0.5rem 0.75rem;\n  overflow: hidden;\n  border: 0;\n  border-bottom: 0.125rem solid transparent;\n  outline: none;\n  background: transparent;\n  color: #8c8c8c;\n  font: inherit;\n  font-size: 0.875rem;\n  font-weight: 550;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  cursor: pointer;\n  user-select: none;\n  transition: background 140ms ease, color 140ms ease;\n}\n.ke-tabs__tab:hover:not(:disabled) {\n  background: #101010;\n  color: #f2f2f2;\n}\n.ke-tabs__tab:focus-visible {\n  outline: 1px solid #53fc18;\n  outline-offset: -1px;\n}\n.ke-tabs__tab[aria-selected=true] {\n  border-bottom-color: #f2f2f2;\n  color: #f2f2f2;\n}\n.ke-tabs__tab:disabled {\n  color: #747474;\n  cursor: default;\n  opacity: 0.45;\n}\n\n.ke-tabs__panel {\n  min-width: 0;\n  min-height: 0;\n  overflow: hidden;\n}\n.ke-tabs__panel[hidden] {\n  display: none;\n}\n\n.ke-tabs__scroll {\n  height: 100%;\n}\n\n.ke-tabs__panel-content {\n  padding: 1rem 1.25rem 1.25rem;\n}\n\n.ke-tabs__panel-content--centered {\n  display: grid;\n  align-items: safe center;\n  justify-items: center;\n}";
	var STYLE_ID$7 = "kick-enhancer-shared-ui-styles";
	function installSharedUiStyles() {
		if (document.getElementById(STYLE_ID$7)) return;
		const style = document.createElement("style");
		style.id = STYLE_ID$7;
		style.textContent = shared_ui_default;
		document.documentElement.append(style);
	}
	function DownloadIcon({ class: className }) {
		return (0, preact_jsx_runtime.jsxs)("svg", {
			"aria-hidden": "true",
			class: className,
			fill: "none",
			viewBox: "0 0 24 24",
			children: [(0, preact_jsx_runtime.jsx)("path", {
				d: "M14 8a1 1 0 0 1 1 1v2a1 1 0 0 0 1 1h3.293a.707.707 0 0 1 .5 1.207l-6.939 6.939a1.207 1.207 0 0 1-1.708 0l-6.94-6.94a.707.707 0 0 1 .5-1.206H8a1 1 0 0 0 1-1V9a1 1 0 0 1 1-1z",
				stroke: "currentColor",
				"stroke-linecap": "round",
				"stroke-linejoin": "round",
				"stroke-width": "2"
			}), (0, preact_jsx_runtime.jsx)("path", {
				d: "M9 4h6",
				stroke: "currentColor",
				"stroke-linecap": "round",
				"stroke-linejoin": "round",
				"stroke-width": "2"
			})]
		});
	}
	function GitHubIcon({ class: className }) {
		return (0, preact_jsx_runtime.jsx)("svg", {
			"aria-hidden": "true",
			class: className,
			fill: "currentColor",
			viewBox: "0 0 24 24",
			children: (0, preact_jsx_runtime.jsx)("path", { d: "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" })
		});
	}
	function LoadingSpinnerIcon({ class: className }) {
		return (0, preact_jsx_runtime.jsxs)("svg", {
			"aria-hidden": "true",
			class: className,
			fill: "none",
			viewBox: "0 0 24 24",
			children: [(0, preact_jsx_runtime.jsx)("circle", {
				cx: "12",
				cy: "12",
				opacity: "0.25",
				r: "9",
				stroke: "currentColor",
				"stroke-width": "2.5"
			}), (0, preact_jsx_runtime.jsx)("path", {
				d: "M12 3a9 9 0 0 1 9 9",
				stroke: "currentColor",
				"stroke-linecap": "round",
				"stroke-width": "2.5"
			})]
		});
	}
	var CLIP_CARD_SELECTOR = "[data-testid=\"livestream-results-card\"]";
	var CLIP_MODAL_BUTTON_SELECTOR = "button[aria-label=\"Open clip modal\"]";
	var CLIP_PERMALINK_SELECTOR = "a[href*=\"/clips/clip_\"]";
	var CLIP_ID_PATTERN = /^clip_[A-Za-z0-9_-]+$/;
	var MAX_CLIP_ID_LENGTH = 128;
	function isValidClipId(value) {
		return value.length <= MAX_CLIP_ID_LENGTH && CLIP_ID_PATTERN.test(value);
	}
	function getClipIdFromHref(href, kickOrigin) {
		if (!href) return;
		let baseUrl;
		let clipUrl;
		try {
			baseUrl = new URL(kickOrigin);
			clipUrl = new URL(href, `${baseUrl.origin}/`);
		} catch {
			return;
		}
		if (clipUrl.origin !== baseUrl.origin) return;
		const pathSegments = clipUrl.pathname.split("/").filter(Boolean);
		if (pathSegments.length !== 3 || pathSegments[1] !== "clips") return;
		const clipId = pathSegments[2];
		if (!isValidClipId(clipId)) return;
		return clipId;
	}
	function getUniqueClipId(hrefs, kickOrigin) {
		const clipIds = new Set();
		for (const href of hrefs) {
			const clipId = getClipIdFromHref(href, kickOrigin);
			if (clipId) clipIds.add(clipId);
		}
		return clipIds.size === 1 ? clipIds.values().next().value : void 0;
	}
	function getClipIdFromCard(card, kickOrigin) {
		if (!card.querySelector("button[aria-label=\"Open clip modal\"]")) return;
		return getUniqueClipId(Array.from(card.querySelectorAll(CLIP_PERMALINK_SELECTOR), (link) => link.getAttribute("href")), kickOrigin);
	}
	function activateClipDownload(event, clipId, onSelectClip) {
		event.preventDefault();
		event.stopPropagation();
		onSelectClip(clipId);
	}
	function createBatchedCardScheduler(processCards, schedule = queueMicrotask) {
		const pendingCards = new Set();
		let active = true;
		let scheduled = false;
		function flush() {
			scheduled = false;
			if (!active || pendingCards.size === 0) return;
			const cards = [...pendingCards];
			pendingCards.clear();
			processCards(cards);
		}
		return {
			cancel() {
				active = false;
				pendingCards.clear();
			},
			enqueue(card) {
				if (!active) return;
				pendingCards.add(card);
				if (scheduled) return;
				scheduled = true;
				schedule(flush);
			}
		};
	}
	function ClipDownloadAction({ clipId, onSelectClip }) {
		function stopPointerPropagation(event) {
			event.stopPropagation();
		}
		return (0, preact_jsx_runtime.jsx)("button", {
			"aria-label": "Download source clip",
			class: "ke-clip-download-action",
			"data-ke-clip-download": true,
			onClick: (event) => activateClipDownload(event, clipId, onSelectClip),
			onMouseDown: stopPointerPropagation,
			onPointerDown: stopPointerPropagation,
			type: "button",
			children: (0, preact_jsx_runtime.jsx)(DownloadIcon, { class: "ke-icon ke-clip-download-action__icon" })
		});
	}
	var icon_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABACAYAAABC6cT1AAASRklEQVRo3r2be7AkdXXHP+d0z9y5j2VhEUUqWXwbjQTxSYhloCS+YsRoWaISrSSUUVcERVxXwBJBBUFBnqWQGCuAIsEnagIGKUtUBB8QICslhfISFFzcvXvvnTv9O9/80T09M3cee9Fdu/bO9kz3zK/P73ce3/M952evjqc+p0H+vBbTHgSJ5QgiMhruZBYIyj+BmUgyMkRgGIYjZEFSIgj8oXkWvwy0/8t/zmqPhYe30VozA6G9yfwwYBpJ5VUDwxAq/+9+Xl/rvVH1KsBkYOV5+WIytkj6Sj7DmkONeB8gAzJyZYDhGGYOEmbU387LwQb+VJ25B37LFK2rQe3VCt35+d1ka2YhYk/MPwwcUUtkfWLV4lUfCUZc7fvcqCerPJ83+KBC83mDKUsseVgRQkJmhoNBENV8WN/00p2j6ggJgQzHraAg1VqyuiPbdx+UtNYyPxV4czWPg4IwQkgbIfDo9wYsgk6T4nx3L/JUqqi6OtKdJPV9c0CZenpUrXV5WZT/gpCTZKsUOlKAtMbcPoTx5noAq9R2NROwUmgbODdgGfiE4CzIOp45uVBtBta15r4pt6Hf7F3rTU9pdNXzWvRMY7LQRYKIGdw/gPFWRLbCVkvXslLS1WpA+b5AnBvoowZLWeYAeN8DSvW5RhjUyl/sn5yuToggLDCLHQidOolIauH+foyjEPnoVRwzPPUqjZtjAwJxkdBJBgtZltUXyxUv3ZepEt4GPIo0OJKtsPH+Z3EzImA5JgsdAFOe2XEY7waatQ8dZavGuLkffa27BsbFQsdjbMs8G7jspYjW9fm1yOr6MFkpe18EGTYnWRVh5LgJN415olgusJRyc96JsxFolQ9pw2psI2xt8ir3PZaukOK9Ztqidhq6wa0cUd1lHOEou2KXyrFixN50OUIUVNFh5EoXSMppZG8DTkDMIGlgtlcKK8ZrgQ344O59hrhSxrFY9hubv4l8ujksePchDbPKQZURsBRS/b+q/jUeHE99GiZjcArVyCkkOgvulmX/iPEhjDXlY/avtAZXXDsIV91Bel7ZMa5FOtrgHi0W2G7PHqkSLqKUsu+HbIJpjXgEqQ6Appyp3C13p2dTsW0Bm1+w5ixvBH0YsXZgLTXCmLVC3Xd8OOg6SW83tzuXl4N8tjHpZrOuHhumKnwaVv0/FBJ7rn7ABZbPb0a2Deh0r6Slgm3fuhtrtV6Dczpue9W324pVsx0CkXHAxTF+IniHmW1WUdBqNSbPUp+w9IFa9S+DVX/9yt67v2ui5gXpzg7ptCfE7NYg6Cx28KmMNS973N/hdibiMUCsnMWJK7pjD+/ArYTeZvKfSh282dyxelgVkG1H45Tim9WGUb3KQO4ZU/dA47iX6aXfvtN/y9eKW8laOZH0YsM+ifEnVVxlAAFpFMYe6cgGr6kW+g6hd5D59ahDlk2t1i7MpJ7HkjSQ/PRjCKN2eOp5e3ki3RvwntPu+8HVP7Dv8sWFm/CGQ9IhZpwLPB6IUenGMEQYgpzjApYDdyPe6e7XRtHBG01We+Qr9WoAkw2AdPU8uepndcgeKEjvvdyu/2baZz8uKW4jmzaUdBDOecCTUd9K70i1bFUAxYEHEO/+7R1bv7H749eQPwKhu+GsTjHGPUMvKatjuapY8OvANhb2mysP135cvPQTvOFE4rkY5wNPQ7VNr+7Q2NDV72IeQmxU6lyxxxPmyBsZj/TwGmTXQ42CjeoHTAJ3I/ttguMftBu/lGuaS5ZvxFvTKOmZ5lwA7F8LPWmFJ6EwG0pKDNiGODEi/oMsV5bn/D6Hj9O3IT/SzTtLoPNwQh/Yyvx/rtEzuGz7bXizgUU83YzzMJ5d27SNQWNahUcfdHgGLCCdInSRuUV/0vGIBS8BDJhhVXDuBul+OFa9moHPB37KPFsunaEZV2z/PszkRIqn4HYBxkGl0Bqvuiu9tDH53tLptBFnSDrbROcPEbq34hrEEQzCsu4CGbAQ6KOLpH9vsXtcHD+C1iwKHm/u5yJeWMdpbLR670i1R3v+AnFeSB/DrO35HyY0QN5j7jQ88gCU9HYizlhk24U5jeILy7dgJThab865wKED3nsyxh7NmGik8Am4EPQhNxY8+8OFrgBMboZJ/WCityqK8nQ5wVltOL/BXOdzC7diDZDYB+Ms4GUT/bHRnw/sOMcezIYuUXCCZFt3ltBdYG+qiQWrE6TKe5uTFQkuWGD5LCPapz90DY3pQNLe5pyFcVgvRxlK6FfwlKsUvuYwdQVoozlbtrXvYWceeRCBVcRhjdiscmQqAruwIDt9mmzpM/M/oLW7E8Gj3Pk48Jo62g1mLGOyLRuGncYoAsKBKxHvAh7Agt1n1+9Uwd1wTF7TEKrpPZfILl5g8SPG8vbPb3oR03MZEOvcOQ14Xa2WI4WeEKc1KWbLgWuAY3C7t6027jk7+8gzcu+wXFFUXlVJRId0SdA8aYY185/z66HzY1Sk3SzzUzDeNMQzj1JfTYCeGmN64jrQBszvKOa3ML3bOnbF4UGhMseyLng1yL8U+Acz4uHP+fVEkZCYs8xPwjgSVTzTJPihCRowmmBwjB/JbIOZbV5sFzR3kdAAniiqionJME/w1UU6mwx76PN2I1EEEjOW+YkYb68TG1uRWe2IANTYc1UrfQvSBne7aWl7m9npBrvycMfIcAuCguJK8E3Tlv9644UHl0G56Eyb20aMdwKNgWrDJGxtE4CJrUgvxc8EG8z9+ugUTK+ZZlcf7jiG4/iiiM83Ke67XQ9wwPpDSzfXyJ8IHIHUGqANtEJAYzJROMqL9yjaq6MT30tFkDUb/DEOz2limIJiBuLYJYr992MvXviSt0AUSMu3gU4Ce6hWb43ImTUCktqKz0aFrhIDHJ41/B9EWCrSH0fwZdqWKDBcTRrPmqZ1zjyd/dazF4f4k7Dl5WDrA5eATgR+N5C3jsVqmgxVB7M1YTwK49TM/XCssJR2vfCeSN2ykUEWQewPcfp25p+8J9P85fQBsNujk4hPI05EbKto+AkUkfUJp9VQSYF4NNjHjfzvr/HL2dXCu2Fy87oSkkjJsQOnmTpzijVP3FdzHKMjMVlSpE+BPoyxMIKg0WgCoZ/G0qSiTwCPBTvzRfHal7s7KRW7TvCMHKvIVhECkZGlBs0XOPGJguX19/oPeSMHY2YdIp2FdCqwtMK/7zCmq7/W2NWEQb8QGOvBzpHiUPeMVHR22Yp7XRirK6VuQUTQ+WuHMwqKfZb8QfazA8CzZdAZwCcw2kOF1R0RierThNH3BcYTkJ0dioPccorY+cJ7lCtd0ete5Qeq6DKLBo0XzzF3+lza/bHP8BZf/NipYCxB+gjoHKAzdtFtAvlgE9FeAE8zcZ6I52TkRHth5wreG7LXIdNPfeQ0lJO9Qln7ox1t3fOyjZeUSUPYAimdDFyIqraXAX5Nq2NZRkJYlSuPPROzC6T0F+QtOrGwMwWvqqVmfRUSYbgZbqXD60Sic1iTxilGc93rtD9vefgo8Gwb0gmgz1SUk01IQAahrSZnK7XDE88Bu0Cmp+e0aBfLO8vGM+slWl3jM+vnWgPhZDRovL4Bp7S1uHbLumux/zkZ0MMQ78e4rN+NDcA3m0Q02ogU1vq/HpgdZNh5ivSkRtZA6uetf7/D3hQHbkosbcIUXUjabfcaLICXuVsiqSAuSmQnG2y79FUP0/jKXdBe3JtG6+yanJgEYUeVjXaE+YWBriIV/0Kj+csj0n4Urj2n8AMyskagTkDm5LZE2vw4m/3FTx9Y4Kq9fzKOXk41f2t9ddGV3seqrpCMzFs0j5whPyFYnnnjl9ewsPA7aLTuRzoG+FqtKuMSFa2CehouJgqzQ8nzvwZInpHTeqXwS8E+6+QXG/5Zxy9p0HjXeenHxl5LExkYs4FCwoiRreJk8O4bF+mfp2i8t8nM9JHTh8C2bZDZfaCjgau6yf1Irz2uimI7qKeVKDmTgnlrI2wuYCqhPFDT8GYiGh3as4/Ldjcm9F65eus9mgy0weUyM2TI8bxJc4NRHLvA1qnX7nYgsa0As18ibajoI5sIcWwsKaGhyallsMzMmdU0QYpu81LXTqMyxxaOT3CcPizteJesehqsop6jIdJRM8wc7cw23zB3ICwXAHcgbcD4XkUyDFPIk/m43lRICanASBXHrrLM2yBnqixzm6oenvIHc3K3oTaloYKCVW5YI9TchkoaNeQyA0kZ+VSOH5tIsYWtn3x1c//OF7bfQGNu9meKeDvYRRjP7V+zIcc3zNEF8H2MrwL39bqbJNANEoQVlfkFvc4t1dxGG1FMED1Xf5FopF5qjMexMvZLCopWkN49y9RCMPPpN8y+oPjC9htgNr+Z0AbgX4H9BkrGK/P03jAOfEmKowz/VUpBY2qQnNiUXokQXlrqQPtRGf9CGRnJDHEIkDC+M2TjdfqkscY4quJX9k6UUd8ipzEzw8zxLfinm7nL/nZmf+h0MLcbEBuA2ytMPNrTW1/tG51lnv1q+3WnDwld1qweQ5Doa0rUYHdJEbuxrLUSxrcHhL5a4moJOyKevylov89NApNWlg8r6Glmwwx4n9JWb7I2xY+3Uxxm2O++7reRltt4o4lCL8H4FLDvgNoPzq1j3CrFoVf7V+8/R8evncHf1MQf5ZTdt4lOZGQuVBiN54n4K6vqU90+vYLO5ib5txxXkMJpuEgEnZTRXOqQXZ7XyaJMA2zSCjl7mwVMffyT6PYCltKoTHXxrv5kzSlSUeBZ9t+KOAaz84B9hoTvaUJh5sVNfIcp8n0h3gO2DkxmZq5GNWRU1QeP6tG73VdqqPFnhj+j7KLPqt0NLqcpYcugu0rnZjYiqRi2+W7uIevVW2oLqX5DhII0EMeyPCeKDizMf5m5tXPAmYg9RzITZYsnjtGilQcdIIpea5wNtC6MBH3mqrJG64VhFGW1KIw8z6n028bQo/3+UgN5t61w0upWid1oDCXbnjeIVCDiUpPNgJ0GAx2OEOrDUDX7a1YWNtWD/r3gX9v5qKBc1UeEul2LGLmLLPOq69WsF6s1qOID1KGGMoq6/bf7SF4nPsN0Tw6dItRe/DfQRxALw4Rl2X7mQFBEUHQbDVSWuLyvIa2sAPWMlNLhlkVPkFVnvSbGRIogFXkZ+A1Z9Gphg01eK/qh1OcC+nxp1YTsZJTqOTqGZlMtIhUF0tkYs5htBKYQgfcm0JVhuJzMrQxxRsULVjDbhAIiSr7Q1Ofl3cmyLpGKeobneAhT3o0wdTYom5Aqj0d1PfWLsHqVxhF9OZGKNoqPYdkaxFFY3fWbIbL9/QX8r75/V1CcKmKtl32yXnppd8MiUTw/URys2q+WBl6Q/m+W1jdLIaX+rEvYYof4Xl7F4xXuzAhpbCl7aEeUdRsKRJC0mv1HnuVEkRZIOglnFrMjK8y2txlPPjhecf9BN121pbNu3fkxNc3ax26qv/ty/Tl7aJqADTkc0t+OZrgvU9xyrW4++am2t77tt49FblazPzJ6/evlFp0VGaYZVpl0V4WszuBUpvRu5KZVbMbxPCNS2oriBCybQ7weYx3GcUrpF81nnnN3M5bwvKyl6SsXwp13czSbuYfbyGkChbKuJQBBUlCwh2dmKjQBsqKeX4bBbXq1imgY1HSvVrNdrXNGbpBstfvOlr1Ns5h6kKTjcJvFeBXwcvPsMhFfw5sPpqIokyI3IV13Jtnm1/Os7qbAqraf1WyRMBJTFCvb+PoF7/oNyYa6G9UjgU19ttzd7Ti8qcARRRLLsdoezpbNEFvvgrk//RWKd4HNIv4GONCwA8tBraT8McnsrSZtziqhujoXfQlKRoYjGhME9yCqQgJ1PjvSnVnPl/eHtz58ryBUUChG/M5Eld9tPduXFzDZLwi9A/juUHnS67ZDYUZZ10/d2n5Fi1cbSkisrQxh7JhFuYm2t3tVRh85YaLkMaQyvlZBstqmV4VCsCCszJjyDHKHR9aataY1SyoSZHY7aANwI+BUcKtSM7MyxNNihhbTntGwPjXt+hafZpqc8b0zeZPWYqL962oTjZn1tkt2nVkv0NX9UagfNpQx1kSY6Dwolgtbdbty38O0GhTRwclvrlicT2Ksr91ORMhtu0kUtoyRP2DY/UZGVFprWCZ07zX8PF7KUybYeGSXu2ffidKZmWqCvH/bRR0qahZmENh0q60iiO3B4rzx+zXj5d4gLRV4ih9qKjscsz26Q6nMB+4W0LGCoPP1FlObwV1lTLJEok3c+2Y9m2/YrWPH+X9edoYQgIbGYAAAAABJRU5ErkJggg==";
	function DirectClipDownloadAction({ clipId, onSelectClip }) {
		const tooltipId = (0, preact_hooks.useId)();
		const label = "Download source clip (KICK Enhancer)";
		return (0, preact_jsx_runtime.jsxs)(preact_jsx_runtime.Fragment, { children: [(0, preact_jsx_runtime.jsxs)("button", {
			"aria-describedby": tooltipId,
			"aria-label": label,
			className: "ke-direct-clip-download-action",
			"data-ke-direct-clip-download": true,
			onClick: (event) => activateClipDownload(event, clipId, onSelectClip),
			type: "button",
			children: [(0, preact_jsx_runtime.jsx)("img", {
				alt: "",
				className: "ke-direct-clip-download-action__brand",
				draggable: false,
				src: icon_default
			}), (0, preact_jsx_runtime.jsx)(DownloadIcon, { class: "ke-icon ke-direct-clip-download-action__icon" })]
		}), (0, preact_jsx_runtime.jsx)("span", {
			className: "ke-direct-clip-download-tooltip",
			id: tooltipId,
			role: "tooltip",
			children: label
		})] });
	}
	function calculateListViewRange(itemCount, rowHeight, overscan, scrollTop, viewportHeight) {
		if (itemCount <= 0) return {
			end: 0,
			start: 0
		};
		const safeRowHeight = Math.max(1, rowHeight);
		const safeOverscan = Number.isFinite(overscan) ? Math.max(0, Math.floor(overscan)) : 0;
		const firstVisible = Math.floor(Math.max(0, scrollTop) / safeRowHeight);
		const afterLastVisible = Math.ceil((Math.max(0, scrollTop) + Math.max(0, viewportHeight)) / safeRowHeight);
		return {
			end: Math.min(itemCount, Math.max(firstVisible + 1, afterLastVisible) + safeOverscan),
			start: Math.min(itemCount, Math.max(0, firstVisible - safeOverscan))
		};
	}
	var EDGE_TOLERANCE = 2;
	function calculateScrollOverflow(scrollTop, viewportHeight, contentHeight) {
		const maximumScrollTop = Math.max(0, contentHeight - viewportHeight);
		const resolvedScrollTop = Math.min(maximumScrollTop, Math.max(0, scrollTop));
		return {
			bottom: maximumScrollTop - resolvedScrollTop > EDGE_TOLERANCE,
			top: resolvedScrollTop > EDGE_TOLERANCE
		};
	}
	function joinClassNames(...values) {
		return values.filter(Boolean).join(" ");
	}
	function ScrollArea({ children, className, contentClassName, heightMode = "fill", minimumThumbSize = 24, onViewportChange, onViewportMetricsChange, onViewportScroll, scrollIndicators = false, scrollbarVariant = "default", viewportAriaLabel, viewportClassName, viewportTabIndex = 0 }) {
		const viewportRef = (0, preact_hooks.useRef)(null);
		const contentRef = (0, preact_hooks.useRef)(null);
		const rootRef = (0, preact_hooks.useRef)(null);
		const thumbRef = (0, preact_hooks.useRef)(null);
		const animationFrameRef = (0, preact_hooks.useRef)(null);
		const thumbSizeRef = (0, preact_hooks.useRef)(minimumThumbSize);
		const thumbVisibleRef = (0, preact_hooks.useRef)(false);
		const dragRef = (0, preact_hooks.useRef)(null);
		const updateThumb = (0, preact_hooks.useCallback)(() => {
			const viewport = viewportRef.current;
			const root = rootRef.current;
			const thumb = thumbRef.current;
			if (!viewport || !root || !thumb) return;
			const viewportHeight = viewport.clientHeight;
			const contentHeight = viewport.scrollHeight;
			const maximumScrollTop = Math.max(0, contentHeight - viewportHeight);
			const overflow = calculateScrollOverflow(viewport.scrollTop, viewportHeight, contentHeight);
			root.toggleAttribute("data-overflow-top", scrollIndicators && overflow.top);
			root.toggleAttribute("data-overflow-bottom", scrollIndicators && overflow.bottom);
			if (viewportHeight <= 0 || maximumScrollTop <= 0) {
				thumbVisibleRef.current = false;
				thumb.removeAttribute("data-visible");
				thumb.style.height = "";
				thumb.style.transform = "";
				return;
			}
			const nextSize = Math.min(viewportHeight, Math.max(Math.max(1, minimumThumbSize), Math.round(viewportHeight / contentHeight * viewportHeight)));
			const maximumOffset = Math.max(0, viewportHeight - nextSize);
			const nextOffset = Math.round(viewport.scrollTop / maximumScrollTop * maximumOffset);
			thumbSizeRef.current = nextSize;
			thumbVisibleRef.current = true;
			thumb.dataset.visible = "true";
			thumb.style.height = `${nextSize}px`;
			thumb.style.transform = `translateY(${nextOffset}px)`;
		}, [minimumThumbSize, scrollIndicators]);
		const scheduleThumbUpdate = (0, preact_hooks.useCallback)(() => {
			if (animationFrameRef.current !== null) return;
			animationFrameRef.current = window.requestAnimationFrame(() => {
				animationFrameRef.current = null;
				updateThumb();
			});
		}, [updateThumb]);
		const setViewport = (0, preact_hooks.useCallback)((viewport) => {
			viewportRef.current = viewport;
			onViewportChange?.(viewport);
		}, [onViewportChange]);
		const handleScroll = (0, preact_hooks.useCallback)((event) => {
			onViewportScroll?.(event.currentTarget);
			scheduleThumbUpdate();
		}, [onViewportScroll, scheduleThumbUpdate]);
		(0, preact_hooks.useEffect)(() => {
			const viewport = viewportRef.current;
			const content = contentRef.current;
			const handleMetricsChange = () => {
				scheduleThumbUpdate();
				if (viewportRef.current) onViewportMetricsChange?.(viewportRef.current);
			};
			const resizeObserver = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(handleMetricsChange);
			handleMetricsChange();
			if (viewport) resizeObserver?.observe(viewport);
			if (content) resizeObserver?.observe(content);
			return () => {
				resizeObserver?.disconnect();
				if (animationFrameRef.current !== null) {
					window.cancelAnimationFrame(animationFrameRef.current);
					animationFrameRef.current = null;
				}
			};
		}, [onViewportMetricsChange, scheduleThumbUpdate]);
		const finishDrag = (0, preact_hooks.useCallback)((event) => {
			if (!dragRef.current || event.pointerId !== dragRef.current.pointerId) return;
			if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
			dragRef.current = null;
			rootRef.current?.classList.remove("is-dragging");
		}, []);
		const handleThumbPointerDown = (0, preact_hooks.useCallback)((event) => {
			const viewport = viewportRef.current;
			if (event.button !== 0 || !viewport || !thumbVisibleRef.current) return;
			event.preventDefault();
			event.stopPropagation();
			event.currentTarget.setPointerCapture(event.pointerId);
			dragRef.current = {
				pointerId: event.pointerId,
				startClientY: event.clientY,
				startScrollTop: viewport.scrollTop
			};
			rootRef.current?.classList.add("is-dragging");
		}, []);
		const handleThumbPointerMove = (0, preact_hooks.useCallback)((event) => {
			const drag = dragRef.current;
			const viewport = viewportRef.current;
			if (!drag || drag.pointerId !== event.pointerId || !viewport) return;
			const maximumScrollTop = Math.max(0, viewport.scrollHeight - viewport.clientHeight);
			const maximumThumbOffset = Math.max(1, viewport.clientHeight - thumbSizeRef.current);
			const scrollDelta = (event.clientY - drag.startClientY) * maximumScrollTop / maximumThumbOffset;
			viewport.scrollTop = Math.min(maximumScrollTop, Math.max(0, drag.startScrollTop + scrollDelta));
		}, []);
		return (0, preact_jsx_runtime.jsxs)("div", {
			className: joinClassNames("ke-scroll-area", className),
			"data-height": heightMode,
			"data-scroll-indicators": scrollIndicators ? "true" : void 0,
			"data-scrollbar": scrollbarVariant,
			ref: rootRef,
			children: [(0, preact_jsx_runtime.jsx)("div", {
				"aria-label": viewportAriaLabel,
				className: joinClassNames("ke-scroll-area__viewport", viewportClassName),
				onScroll: handleScroll,
				ref: setViewport,
				tabIndex: viewportTabIndex,
				children: (0, preact_jsx_runtime.jsx)("div", {
					className: joinClassNames("ke-scroll-area__content", contentClassName),
					ref: contentRef,
					children
				})
			}), (0, preact_jsx_runtime.jsx)("div", {
				"aria-hidden": "true",
				className: "ke-scroll-area__thumb",
				onLostPointerCapture: finishDrag,
				onPointerCancel: finishDrag,
				onPointerDown: handleThumbPointerDown,
				onPointerMove: handleThumbPointerMove,
				onPointerUp: finishDrag,
				ref: thumbRef
			})]
		});
	}
	function useListViewRange(itemCount, overscan, rowHeight) {
		const virtualized = rowHeight !== void 0;
		const viewportRef = (0, preact_hooks.useRef)(null);
		const animationFrameRef = (0, preact_hooks.useRef)(null);
		const updateRangeRef = (0, preact_hooks.useRef)(() => void 0);
		const [range, setRange] = (0, preact_hooks.useState)(() => virtualized ? calculateListViewRange(itemCount, rowHeight, overscan, 0, 0) : {
			end: itemCount,
			start: 0
		});
		const updateRange = (0, preact_hooks.useCallback)(() => {
			const viewport = viewportRef.current;
			const nextRange = virtualized && viewport ? calculateListViewRange(itemCount, rowHeight, overscan, viewport.scrollTop, viewport.clientHeight) : {
				end: itemCount,
				start: 0
			};
			setRange((current) => current.start === nextRange.start && current.end === nextRange.end ? current : nextRange);
		}, [
			itemCount,
			overscan,
			rowHeight,
			virtualized
		]);
		updateRangeRef.current = updateRange;
		const scheduleRangeUpdate = (0, preact_hooks.useCallback)(() => {
			if (animationFrameRef.current !== null) return;
			animationFrameRef.current = window.requestAnimationFrame(() => {
				animationFrameRef.current = null;
				updateRangeRef.current();
			});
		}, []);
		const setViewport = (0, preact_hooks.useCallback)((viewport) => {
			viewportRef.current = viewport;
			if (viewport && virtualized) scheduleRangeUpdate();
		}, [scheduleRangeUpdate, virtualized]);
		(0, preact_hooks.useEffect)(() => {
			if (virtualized) scheduleRangeUpdate();
		}, [
			scheduleRangeUpdate,
			updateRange,
			virtualized
		]);
		(0, preact_hooks.useEffect)(() => {
			const viewport = viewportRef.current;
			if (!virtualized || !viewport || typeof ResizeObserver === "undefined") return;
			const resizeObserver = new ResizeObserver(scheduleRangeUpdate);
			resizeObserver.observe(viewport);
			return () => resizeObserver.disconnect();
		}, [scheduleRangeUpdate, virtualized]);
		(0, preact_hooks.useEffect)(() => () => {
			if (animationFrameRef.current !== null) window.cancelAnimationFrame(animationFrameRef.current);
		}, []);
		return {
			range,
			scheduleRangeUpdate,
			setViewport,
			virtualized
		};
	}
	function ListViewRowComponent({ ariaLabel, className, columns, gridTemplateColumns, index, item, itemCount, onItemActivate, rowHeight }) {
		const virtualized = rowHeight !== void 0;
		const rowStyle = {
			gridTemplateColumns,
			...virtualized ? {
				height: `${rowHeight}px`,
				transform: `translateY(${index * rowHeight}px)`
			} : {}
		};
		return (0, preact_jsx_runtime.jsx)("div", {
			"aria-label": ariaLabel,
			"aria-rowindex": index + 2,
			className: joinClassNames("ke-list-view__row", onItemActivate && "is-interactive", className),
			"data-last-row": index === itemCount - 1 ? "true" : void 0,
			"data-virtualized": virtualized ? "true" : void 0,
			onClick: onItemActivate ? () => onItemActivate(item) : void 0,
			onKeyDown: onItemActivate ? (event) => {
				if (event.key !== "Enter" && event.key !== " ") return;
				event.preventDefault();
				onItemActivate(item);
			} : void 0,
			role: "row",
			style: rowStyle,
			tabIndex: onItemActivate ? 0 : void 0,
			children: columns.map((column) => (0, preact_jsx_runtime.jsx)("div", {
				className: joinClassNames("ke-list-view__cell", column.cellClassName),
				"data-align": column.align,
				"data-column-id": column.id,
				role: "cell",
				children: (0, preact_jsx_runtime.jsx)("div", {
					className: "ke-list-view__cell-content",
					children: column.renderCell(item)
				})
			}, column.id))
		});
	}
	var ListViewRow = (0, preact_compat.memo)(ListViewRowComponent);
	function ListView({ ariaLabel, ariaLive = "off", className, columns, emptyContent = "No items", getItemKey, getRowAriaLabel, getRowClassName, heightMode = "fill", items, onItemActivate, overscan = 8, rowHeight }) {
		if (rowHeight !== void 0 && (!Number.isFinite(rowHeight) || rowHeight <= 0)) throw new Error("ListView rowHeight must be a positive finite number.");
		const gridTemplateColumns = (0, preact_hooks.useMemo)(() => columns.map((column) => column.width).join(" "), [columns]);
		const rowStyle = { gridTemplateColumns };
		const { range, scheduleRangeUpdate, setViewport, virtualized } = useListViewRange(items.length, overscan, rowHeight);
		const rangeStart = Math.min(items.length, range.start);
		const rangeEnd = Math.min(items.length, Math.max(rangeStart, range.end));
		const visibleItems = virtualized ? items.slice(rangeStart, rangeEnd) : items;
		const bodyStyle = virtualized && rowHeight !== void 0 ? { height: `${items.length * rowHeight}px` } : void 0;
		return (0, preact_jsx_runtime.jsxs)("div", {
			"aria-colcount": columns.length,
			"aria-label": ariaLabel,
			"aria-rowcount": items.length + 1,
			className: joinClassNames("ke-list-view", className),
			"data-empty": items.length === 0 ? "true" : "false",
			role: "table",
			children: [(0, preact_jsx_runtime.jsx)("div", {
				className: "ke-list-view__header-group",
				role: "rowgroup",
				children: (0, preact_jsx_runtime.jsx)("div", {
					"aria-rowindex": 1,
					className: "ke-list-view__header",
					role: "row",
					style: rowStyle,
					children: columns.map((column) => (0, preact_jsx_runtime.jsx)("div", {
						className: "ke-list-view__header-cell",
						"data-align": column.align,
						"data-column-id": column.id,
						role: "columnheader",
						children: (0, preact_jsx_runtime.jsx)("span", {
							className: "ke-list-view__header-label",
							children: column.header
						})
					}, column.id))
				})
			}), (0, preact_jsx_runtime.jsxs)(ScrollArea, {
				className: "ke-list-view__scroll",
				contentClassName: "ke-list-view__scroll-content",
				heightMode,
				onViewportChange: setViewport,
				onViewportScroll: virtualized ? scheduleRangeUpdate : void 0,
				scrollIndicators: true,
				scrollbarVariant: "compact",
				viewportAriaLabel: `${ariaLabel} rows`,
				viewportClassName: "ke-list-view__viewport",
				viewportTabIndex: onItemActivate ? -1 : 0,
				children: [(0, preact_jsx_runtime.jsx)("div", {
					"aria-live": virtualized ? "off" : ariaLive,
					className: "ke-list-view__body",
					"data-virtualized": virtualized ? "true" : void 0,
					role: "rowgroup",
					style: bodyStyle,
					children: items.length === 0 ? (0, preact_jsx_runtime.jsx)("div", {
						className: "ke-list-view__empty",
						role: "status",
						children: emptyContent
					}) : visibleItems.map((item, visibleIndex) => {
						const index = virtualized ? rangeStart + visibleIndex : visibleIndex;
						return (0, preact_jsx_runtime.jsx)(ListViewRow, {
							ariaLabel: getRowAriaLabel?.(item),
							className: getRowClassName?.(item),
							columns,
							gridTemplateColumns,
							index,
							item,
							itemCount: items.length,
							onItemActivate,
							rowHeight
						}, getItemKey(item, index));
					})
				}), virtualized && ariaLive !== "off" ? (0, preact_jsx_runtime.jsxs)("span", {
					"aria-atomic": "true",
					"aria-live": ariaLive,
					className: "ke-list-view__live-status",
					children: [
						items.length,
						" ",
						items.length === 1 ? "row" : "rows"
					]
				}) : null]
			})]
		});
	}
	function Button({ children, className, density = "default", tone = "default", type = "button", ...props }) {
		return (0, preact_jsx_runtime.jsx)("button", {
			...props,
			className: joinClassNames("ke-button", `ke-button--${density}`, `ke-button--${tone}`, className),
			type,
			children
		});
	}
	function SelectBox({ className, description, id, label, onValueChange, options, ...props }) {
		const generatedId = (0, preact_hooks.useId)();
		const selectId = id ?? generatedId;
		const descriptionId = description ? `${selectId}-description` : void 0;
		return (0, preact_jsx_runtime.jsxs)("label", {
			className: "ke-form-field",
			htmlFor: selectId,
			children: [
				(0, preact_jsx_runtime.jsx)("span", {
					className: "ke-form-field__label",
					children: label
				}),
				description ? (0, preact_jsx_runtime.jsx)("span", {
					className: "ke-form-field__description",
					id: descriptionId,
					children: description
				}) : null,
				(0, preact_jsx_runtime.jsxs)("span", {
					className: "ke-select-box",
					children: [(0, preact_jsx_runtime.jsx)("select", {
						...props,
						"aria-describedby": descriptionId,
						className: joinClassNames("ke-select-box__input", className),
						id: selectId,
						onChange: (event) => onValueChange?.(event.currentTarget.value),
						children: options.map((option) => (0, preact_jsx_runtime.jsx)("option", {
							disabled: option.disabled,
							value: option.value,
							children: option.label
						}, option.value))
					}), (0, preact_jsx_runtime.jsx)("span", {
						"aria-hidden": "true",
						className: "ke-select-box__chevron"
					})]
				})
			]
		});
	}
	function TextField({ className, description, id, label, onValueChange, suffix, ...props }) {
		const generatedId = (0, preact_hooks.useId)();
		const inputId = id ?? generatedId;
		const descriptionId = description ? `${inputId}-description` : void 0;
		const suffixId = suffix ? `${inputId}-suffix` : void 0;
		const describedBy = [descriptionId, suffixId].filter(Boolean).join(" ") || void 0;
		return (0, preact_jsx_runtime.jsxs)("label", {
			className: "ke-form-field",
			htmlFor: inputId,
			children: [
				(0, preact_jsx_runtime.jsx)("span", {
					className: "ke-form-field__label",
					children: label
				}),
				description ? (0, preact_jsx_runtime.jsx)("span", {
					className: "ke-form-field__description",
					id: descriptionId,
					children: description
				}) : null,
				(0, preact_jsx_runtime.jsxs)("span", {
					className: suffix ? "ke-text-field-shell" : void 0,
					children: [(0, preact_jsx_runtime.jsx)("input", {
						...props,
						"aria-describedby": describedBy,
						className: joinClassNames("ke-text-field", className),
						id: inputId,
						onInput: (event) => onValueChange?.(event.currentTarget.value)
					}), suffix ? (0, preact_jsx_runtime.jsx)("span", {
						className: "ke-text-field__suffix",
						id: suffixId,
						children: suffix
					}) : null]
				})
			]
		});
	}
	function Toggle({ className, description, id, label, onCheckedChange, ...props }) {
		const generatedId = (0, preact_hooks.useId)();
		const inputId = id ?? generatedId;
		const descriptionId = description ? `${inputId}-description` : void 0;
		return (0, preact_jsx_runtime.jsxs)("label", {
			className: joinClassNames("ke-toggle", className),
			htmlFor: inputId,
			children: [(0, preact_jsx_runtime.jsxs)("span", {
				className: "ke-toggle__copy",
				children: [(0, preact_jsx_runtime.jsx)("span", {
					className: "ke-form-field__label",
					children: label
				}), description ? (0, preact_jsx_runtime.jsx)("span", {
					className: "ke-form-field__description",
					id: descriptionId,
					children: description
				}) : null]
			}), (0, preact_jsx_runtime.jsxs)("span", {
				className: "ke-toggle__control",
				children: [(0, preact_jsx_runtime.jsx)("input", {
					...props,
					"aria-describedby": descriptionId,
					className: "ke-toggle__input",
					id: inputId,
					onChange: (event) => onCheckedChange?.(event.currentTarget.checked),
					role: "switch",
					type: "checkbox"
				}), (0, preact_jsx_runtime.jsx)("span", {
					"aria-hidden": "true",
					className: "ke-toggle__track",
					children: (0, preact_jsx_runtime.jsx)("span", { className: "ke-toggle__thumb" })
				})]
			})]
		});
	}
	function TrackBar({ defaultValue, description, formatValue = String, id, label, max, min, onValueChange, value, ...props }) {
		const generatedId = (0, preact_hooks.useId)();
		const inputId = id ?? generatedId;
		const descriptionId = description ? `${inputId}-description` : void 0;
		const [internalValue, setInternalValue] = (0, preact_hooks.useState)(defaultValue ?? min);
		const currentValue = value ?? internalValue;
		const range = max - min;
		const progress = range > 0 ? (currentValue - min) / range * 100 : 0;
		const handleInput = (event) => {
			const nextValue = event.currentTarget.valueAsNumber;
			if (value === void 0) setInternalValue(nextValue);
			onValueChange?.(nextValue);
		};
		return (0, preact_jsx_runtime.jsxs)("label", {
			className: "ke-form-field",
			htmlFor: inputId,
			children: [
				(0, preact_jsx_runtime.jsxs)("span", {
					className: "ke-track-bar__heading",
					children: [(0, preact_jsx_runtime.jsx)("span", {
						className: "ke-form-field__label",
						children: label
					}), (0, preact_jsx_runtime.jsx)("output", {
						className: "ke-track-bar__value",
						htmlFor: inputId,
						children: formatValue(currentValue)
					})]
				}),
				description ? (0, preact_jsx_runtime.jsx)("span", {
					className: "ke-form-field__description",
					id: descriptionId,
					children: description
				}) : null,
				(0, preact_jsx_runtime.jsx)("input", {
					...props,
					"aria-describedby": descriptionId,
					className: "ke-track-bar",
					id: inputId,
					max,
					min,
					onInput: handleInput,
					style: { "--ke-track-progress": `${progress}%` },
					type: "range",
					value: currentValue
				})
			]
		});
	}
	function Modal({ children, className, closeLabel = "Close settings", description, dismissDisabled = false, footer, icon, initialFocusRef, onRequestClose, open, title }) {
		const dialogRef = (0, preact_hooks.useRef)(null);
		const previousFocusRef = (0, preact_hooks.useRef)(null);
		const titleId = (0, preact_hooks.useId)();
		const descriptionId = (0, preact_hooks.useId)();
		(0, preact_hooks.useEffect)(() => {
			const dialog = dialogRef.current;
			if (!dialog) return;
			if (open && !dialog.open) {
				previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
				dialog.showModal();
				initialFocusRef?.current?.focus();
			} else if (!open && dialog.open) dialog.close();
		}, [initialFocusRef, open]);
		(0, preact_hooks.useEffect)(() => {
			return () => {
				previousFocusRef.current?.focus();
			};
		}, []);
		const requestClose = () => {
			if (!dismissDisabled) {
				onRequestClose();
				previousFocusRef.current?.focus();
			}
		};
		const handleCancel = (event) => {
			event.preventDefault();
			requestClose();
		};
		const handleBackdropPointerDown = (event) => {
			if (event.target === event.currentTarget) requestClose();
		};
		if (!open) return null;
		return (0, preact_compat.createPortal)((0, preact_jsx_runtime.jsx)("dialog", {
			"aria-describedby": description ? descriptionId : void 0,
			"aria-labelledby": titleId,
			className: joinClassNames("ke-modal", className),
			onCancel: handleCancel,
			onPointerDown: handleBackdropPointerDown,
			ref: dialogRef,
			children: (0, preact_jsx_runtime.jsxs)("div", {
				className: "ke-modal__surface",
				children: [
					(0, preact_jsx_runtime.jsxs)("header", {
						className: "ke-modal__header",
						children: [(0, preact_jsx_runtime.jsxs)("div", {
							className: "ke-modal__identity",
							children: [icon ? (0, preact_jsx_runtime.jsx)("img", {
								alt: "",
								className: "ke-modal__icon",
								draggable: false,
								src: icon
							}) : null, (0, preact_jsx_runtime.jsxs)("div", {
								className: "ke-modal__heading",
								children: [(0, preact_jsx_runtime.jsx)("h2", {
									className: "ke-modal__title",
									id: titleId,
									children: title
								}), description ? (0, preact_jsx_runtime.jsx)("p", {
									className: "ke-modal__description",
									id: descriptionId,
									children: description
								}) : null]
							})]
						}), (0, preact_jsx_runtime.jsx)(Button, {
							"aria-label": closeLabel,
							className: "ke-modal__close",
							disabled: dismissDisabled,
							onClick: requestClose,
							children: (0, preact_jsx_runtime.jsx)("span", {
								"aria-hidden": "true",
								children: "×"
							})
						})]
					}),
					(0, preact_jsx_runtime.jsx)("div", {
						className: "ke-modal__body",
						children
					}),
					footer ? (0, preact_jsx_runtime.jsx)("footer", {
						className: "ke-modal__footer",
						children: footer
					}) : null
				]
			})
		}), document.body);
	}
	function findEnabledTabIndex(tabs, startIndex, direction) {
		for (let offset = 1; offset <= tabs.length; offset += 1) {
			const index = (startIndex + direction * offset + tabs.length) % tabs.length;
			if (!tabs[index].disabled) return index;
		}
		return -1;
	}
	function findEdgeTabIndex(tabs, fromEnd) {
		const start = fromEnd ? tabs.length - 1 : 0;
		const end = fromEnd ? -1 : tabs.length;
		const step = fromEnd ? -1 : 1;
		for (let index = start; index !== end; index += step) if (!tabs[index].disabled) return index;
		return -1;
	}
	function Tabs({ ariaLabel, className, defaultValue, onChange, panelClassName, tabs, value }) {
		const instanceId = (0, preact_hooks.useId)();
		const tabButtonsRef = (0, preact_hooks.useRef)([]);
		const [uncontrolledValue, setUncontrolledValue] = (0, preact_hooks.useState)(defaultValue);
		const controlled = value !== void 0;
		const requestedValue = controlled ? value : uncontrolledValue;
		let selectedIndex = tabs.findIndex((tab) => !tab.disabled && tab.id === requestedValue);
		if (selectedIndex === -1) selectedIndex = tabs.findIndex((tab) => !tab.disabled);
		const selectTab = (index) => {
			const tab = tabs[index];
			if (!tab || tab.disabled) return;
			if (!controlled) setUncontrolledValue(tab.id);
			if (tab.id !== requestedValue) onChange?.(tab.id);
		};
		const handleKeyDown = (event, currentIndex) => {
			let nextIndex = -1;
			if (event.key === "ArrowLeft") nextIndex = findEnabledTabIndex(tabs, currentIndex, -1);
			else if (event.key === "ArrowRight") nextIndex = findEnabledTabIndex(tabs, currentIndex, 1);
			else if (event.key === "Home") nextIndex = findEdgeTabIndex(tabs, false);
			else if (event.key === "End") nextIndex = findEdgeTabIndex(tabs, true);
			if (nextIndex === -1) return;
			event.preventDefault();
			selectTab(nextIndex);
			tabButtonsRef.current[nextIndex]?.focus();
		};
		return (0, preact_jsx_runtime.jsxs)("div", {
			className: joinClassNames("ke-tabs", className),
			children: [(0, preact_jsx_runtime.jsx)("div", {
				"aria-label": ariaLabel,
				"aria-orientation": "horizontal",
				className: "ke-tabs__list",
				role: "tablist",
				children: tabs.map((tab, index) => {
					const selected = index === selectedIndex;
					return (0, preact_jsx_runtime.jsx)("button", {
						"aria-controls": `${instanceId}-panel-${index}`,
						"aria-selected": selected,
						className: "ke-tabs__tab",
						disabled: tab.disabled,
						id: `${instanceId}-tab-${index}`,
						onClick: () => selectTab(index),
						onKeyDown: (event) => handleKeyDown(event, index),
						ref: (button) => {
							tabButtonsRef.current[index] = button;
						},
						role: "tab",
						tabIndex: selected ? 0 : -1,
						type: "button",
						children: tab.label
					}, tab.id);
				})
			}), tabs.map((tab, index) => {
				const selected = index === selectedIndex;
				return (0, preact_jsx_runtime.jsx)("div", {
					"aria-labelledby": `${instanceId}-tab-${index}`,
					className: joinClassNames("ke-tabs__panel", panelClassName),
					hidden: !selected,
					id: `${instanceId}-panel-${index}`,
					role: "tabpanel",
					children: (0, preact_jsx_runtime.jsx)(ScrollArea, {
						className: "ke-tabs__scroll",
						contentClassName: joinClassNames("ke-tabs__panel-content", tab.contentClassName),
						scrollIndicators: true,
						scrollbarVariant: "overlay",
						viewportAriaLabel: tab.panelAriaLabel ?? (typeof tab.label === "string" ? `${tab.label} settings` : void 0),
						viewportTabIndex: selected ? 0 : -1,
						children: tab.content
					})
				}, tab.id);
			})]
		});
	}
	var ClipDownloadError = class extends Error {
		code;
		constructor(code, message) {
			super(message);
			this.name = "ClipDownloadError";
			this.code = code;
		}
	};
	function toDisplayError(error) {
		if (error instanceof ClipDownloadError) return {
			code: error.code,
			message: error.message
		};
		if (error instanceof DOMException && error.name === "AbortError") return {
			code: "cancelled",
			message: "The operation was cancelled."
		};
		return {
			code: "media-request",
			message: "The clip download could not be completed."
		};
	}
	var MP4_SIGNATURE_SEARCH_BYTES = 64;
	function inspectMp4Probe(prefix, suffix) {
		if (!hasFtypSignature(prefix)) unsupported$2("The direct clip resource is not an MP4 file.");
		const probes = suffix ? [prefix, suffix] : [prefix];
		const hasMoov = probes.some((bytes) => containsBoxType(bytes, "moov"));
		const hasH264 = probes.some((bytes) => containsBoxType(bytes, "avc1") || containsBoxType(bytes, "avc3"));
		const hasAac = probes.some((bytes) => containsBoxType(bytes, "mp4a"));
		const unsupportedVideo = probes.some((bytes) => containsBoxType(bytes, "hev1") || containsBoxType(bytes, "hvc1") || containsBoxType(bytes, "av01") || containsBoxType(bytes, "vp09"));
		if (!hasMoov) unsupported$2("The MP4 metadata could not be verified within the probe limit.");
		if (!hasH264 || !hasAac || unsupportedVideo) unsupported$2("The direct MP4 uses unsupported codecs.");
		return {
			audioCodec: "aac",
			videoCodec: "h264"
		};
	}
	function hasFtypSignature(bytes) {
		const searchLength = Math.min(bytes.byteLength - 4, MP4_SIGNATURE_SEARCH_BYTES);
		for (let offset = 4; offset <= searchLength; offset += 1) if (readType(bytes, offset) === "ftyp") {
			const size = readUint32(bytes, offset - 4);
			return size >= 8 && offset - 4 + size <= bytes.byteLength;
		}
		return false;
	}
	function containsBoxType(bytes, type) {
		for (let offset = 4; offset + 4 <= bytes.byteLength; offset += 1) {
			if (readType(bytes, offset) !== type) continue;
			const size = readUint32(bytes, offset - 4);
			if (size === 0 || size >= 8) return true;
		}
		return false;
	}
	function readType(bytes, offset) {
		return String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]);
	}
	function readUint32(bytes, offset) {
		return bytes[offset] * 16777216 + (bytes[offset + 1] << 16) + (bytes[offset + 2] << 8) + bytes[offset + 3];
	}
	function unsupported$2(message) {
		throw new ClipDownloadError("unsupported-media", message);
	}
	var ALLOWED_MEDIA_HOSTS = new Set(["clips.kick.com"]);
	function isAllowedMediaUrl(url) {
		return url.protocol === "https:" && ALLOWED_MEDIA_HOSTS.has(url.hostname.toLowerCase());
	}
	async function readResponseBytes(response, maximumBytes, expectedBytes) {
		const reader = response.body?.getReader();
		if (!reader) throw new ClipDownloadError("media-request", "The media response did not contain a readable body.");
		const chunks = [];
		let receivedBytes = 0;
		try {
			while (true) {
				const { done, value } = await reader.read();
				if (done) break;
				receivedBytes += value.byteLength;
				if (receivedBytes > maximumBytes) {
					await reader.cancel();
					throw new ClipDownloadError("unsupported-media", "The media response exceeded the inspection limit.");
				}
				chunks.push(value);
			}
		} finally {
			reader.releaseLock();
		}
		if (expectedBytes !== void 0 && receivedBytes !== expectedBytes) throw new ClipDownloadError("media-request", "The media response was truncated.");
		const bytes = new Uint8Array(receivedBytes);
		let offset = 0;
		for (const chunk of chunks) {
			bytes.set(chunk, offset);
			offset += chunk.byteLength;
		}
		return bytes;
	}
	async function fetchExactRange(url, start, length, signal, fetchImplementation = fetch) {
		const end = start + length - 1;
		const response = await fetchImplementation(url, {
			headers: { Range: `bytes=${start}-${end}` },
			signal
		});
		validateFinalMediaUrl(response);
		if (response.status !== 206) {
			await response.body?.cancel();
			throw new ClipDownloadError("media-request", "The media server did not honor a required byte range.");
		}
		const contentRange = parseContentRange(response.headers.get("content-range"));
		if (contentRange.start !== start || contentRange.end !== end || contentRange.total <= end) {
			await response.body?.cancel();
			throw new ClipDownloadError("media-request", "The media server returned an unexpected byte range.");
		}
		return {
			bytes: await readResponseBytes(response, length, length),
			contentRange
		};
	}
	async function fetchInitialMediaProbe(url, maximumBytes, signal, fetchImplementation = fetch) {
		const response = await fetchImplementation(url, {
			headers: { Range: `bytes=0-${maximumBytes - 1}` },
			signal
		});
		validateFinalMediaUrl(response);
		if (response.status === 206) {
			const contentRange = parseContentRange(response.headers.get("content-range"));
			if (contentRange.start !== 0 || contentRange.end >= maximumBytes || contentRange.end < maximumBytes - 1 && contentRange.end !== contentRange.total - 1) {
				await response.body?.cancel();
				throw new ClipDownloadError("media-request", "The media server returned an unexpected probe range.");
			}
			const length = contentRange.end + 1;
			return {
				bytes: await readResponseBytes(response, length, length),
				totalBytes: contentRange.total
			};
		}
		if (!response.ok) throw new ClipDownloadError("media-request", "The clip media could not be inspected.");
		const declaredLength = parseContentLength(response.headers.get("content-length"));
		if (declaredLength === void 0 || declaredLength > maximumBytes) {
			await response.body?.cancel();
			throw new ClipDownloadError("unsupported-media", "The media server ignored the bounded inspection request.");
		}
		return {
			bytes: await readResponseBytes(response, maximumBytes, declaredLength),
			totalBytes: declaredLength
		};
	}
	function parseContentRange(value) {
		const match = /^bytes (\d+)-(\d+)\/(\d+)$/.exec(value ?? "");
		if (!match) throw new ClipDownloadError("media-request", "The media response did not contain a valid byte range.");
		const start = Number(match[1]);
		const end = Number(match[2]);
		const total = Number(match[3]);
		if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || !Number.isSafeInteger(total) || start < 0 || end < start || total <= end) throw new ClipDownloadError("media-request", "The media response contained an invalid byte range.");
		return {
			end,
			start,
			total
		};
	}
	function validateFinalMediaUrl(response) {
		let finalUrl;
		try {
			finalUrl = new URL(response.url);
		} catch {
			throw new ClipDownloadError("media-request", "The media server returned an invalid final URL.");
		}
		if (!isAllowedMediaUrl(finalUrl)) {
			response.body?.cancel().catch(() => void 0);
			throw new ClipDownloadError("media-request", "The media request redirected to an untrusted host.");
		}
	}
	function parseContentLength(value) {
		if (!value || !/^\d+$/.test(value)) return;
		const length = Number(value);
		return Number.isSafeInteger(length) && length >= 0 ? length : void 0;
	}
	var MAX_INPUT_BYTES = 8 * 1024 * 1024;
	var MAX_PROBE_BYTES = 256 * 1024;
	function summarizeMediaPlan(plan) {
		if (plan.kind === "direct-mp4") return {
			kind: plan.kind,
			logicalSegmentCount: 1,
			sourceBytes: plan.sourceBytes,
			uniqueSourceObjectCount: 1
		};
		return {
			duration: plan.duration,
			kind: plan.kind,
			logicalSegmentCount: plan.segments.length,
			sourceBytes: plan.sourceBytes,
			uniqueSourceObjectCount: plan.uniqueSourceObjectCount
		};
	}
	var UNSUPPORTED_TAGS = [
		"#EXT-X-BYTERANGE-START",
		"#EXT-X-DISCONTINUITY",
		"#EXT-X-GAP",
		"#EXT-X-I-FRAMES-ONLY",
		"#EXT-X-I-FRAME-STREAM-INF",
		"#EXT-X-KEY",
		"#EXT-X-MAP",
		"#EXT-X-MEDIA:",
		"#EXT-X-PART",
		"#EXT-X-PRELOAD-HINT",
		"#EXT-X-RENDITION-REPORT",
		"#EXT-X-SKIP",
		"#EXT-X-STREAM-INF"
	];
	var ALLOWED_TAG_PREFIXES = [
		"#EXTM3U",
		"#EXT-X-ENDLIST",
		"#EXT-X-INDEPENDENT-SEGMENTS",
		"#EXT-X-MEDIA-SEQUENCE:",
		"#EXT-X-PLAYLIST-TYPE:",
		"#EXT-X-PROGRAM-DATE-TIME:",
		"#EXT-X-TARGETDURATION:",
		"#EXT-X-VERSION:"
	];
	function parseKickMediaPlaylist(text, { isAllowedMediaUrl, playlistUrl: playlistUrlValue }) {
		const playlistUrl = toUrl(playlistUrlValue);
		const lines = text.split(/\r?\n/);
		const segments = [];
		let ended = false;
		let pendingDuration;
		let pendingRange;
		if (lines[0]?.trim() !== "#EXTM3U") unsupported$1("The clip response is not an HLS playlist.");
		for (const rawLine of lines) {
			const line = rawLine.trim();
			if (!line) continue;
			if (line === "#EXT-X-ENDLIST") {
				ended = true;
				continue;
			}
			if (line.startsWith("#EXTINF:")) {
				if (pendingDuration !== void 0) unsupported$1("The playlist contains an incomplete segment.");
				const durationText = line.slice(8).split(",")[0];
				const duration = Number(durationText);
				if (!Number.isFinite(duration) || duration <= 0) unsupported$1("The playlist contains an invalid segment duration.");
				pendingDuration = duration;
				continue;
			}
			if (line.startsWith("#EXT-X-BYTERANGE:")) {
				const match = /^#EXT-X-BYTERANGE:(\d+)@(\d+)$/.exec(line);
				if (!match) unsupported$1("The playlist uses an unsupported implicit byte range.");
				const length = Number(match[1]);
				const offset = Number(match[2]);
				validateRange(offset, length);
				if (length > 8388608) unsupported$1("A clip segment exceeds the safe processing limit.");
				pendingRange = {
					length,
					offset
				};
				continue;
			}
			if (line.startsWith("#")) {
				if (UNSUPPORTED_TAGS.some((tag) => line.startsWith(tag))) unsupported$1("The clip uses an unsupported HLS layout.");
				if (!ALLOWED_TAG_PREFIXES.some((tag) => line.startsWith(tag))) unsupported$1(`The clip uses an unsupported HLS tag: ${line}`);
				continue;
			}
			if (pendingDuration === void 0) unsupported$1("The playlist segment is missing its duration.");
			if (segments.length >= 256) unsupported$1("The clip contains too many media segments.");
			const mediaUrl = new URL(line, playlistUrl);
			if (!isAllowedMediaUrl(mediaUrl)) unsupported$1("The playlist contains an untrusted media URL.");
			segments.push({
				duration: pendingDuration,
				index: segments.length,
				...pendingRange ?? {},
				url: mediaUrl.href
			});
			pendingDuration = void 0;
			pendingRange = void 0;
		}
		if (!ended) unsupported$1("Only completed clip playlists are supported.");
		if (segments.length === 0 || pendingDuration !== void 0 || pendingRange !== void 0) unsupported$1("The playlist does not contain complete media segments.");
		validateNonOverlappingRanges(segments);
		const sourceBytes = segments.every((segment) => segment.length !== void 0) ? segments.reduce((total, segment) => {
			const next = total + (segment.length ?? 0);
			if (!Number.isSafeInteger(next)) unsupported$1("The playlist media size is invalid.");
			return next;
		}, 0) : void 0;
		return {
			duration: segments.reduce((total, segment) => total + segment.duration, 0),
			kind: "hls-ts",
			playlistUrl: playlistUrl.href,
			segments,
			sourceBytes,
			uniqueSourceObjectCount: new Set(segments.map((segment) => segment.url)).size
		};
	}
	function validateRange(offset, length) {
		const inclusiveEnd = offset + length - 1;
		if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(length) || offset < 0 || length <= 0 || !Number.isSafeInteger(inclusiveEnd)) unsupported$1("The playlist contains an invalid byte range.");
	}
	function validateNonOverlappingRanges(segments) {
		const rangesByUrl = new Map();
		for (const segment of segments) {
			if (segment.length === void 0 || segment.offset === void 0) continue;
			const ranges = rangesByUrl.get(segment.url) ?? [];
			ranges.push({
				end: segment.offset + segment.length - 1,
				start: segment.offset
			});
			rangesByUrl.set(segment.url, ranges);
		}
		for (const ranges of rangesByUrl.values()) {
			ranges.sort((left, right) => left.start - right.start);
			for (let index = 1; index < ranges.length; index += 1) if (ranges[index].start <= ranges[index - 1].end) unsupported$1("The playlist contains overlapping byte ranges.");
		}
	}
	function toUrl(value) {
		try {
			return new URL(value);
		} catch {
			unsupported$1("The clip playlist URL is invalid.");
		}
	}
	function unsupported$1(message) {
		throw new ClipDownloadError("unsupported-media", message);
	}
	var TS_PACKET_BYTES = 188;
	var H264_STREAM_TYPE = 27;
	var AAC_STREAM_TYPES = new Set([15, 17]);
	var ID3_STREAM_TYPE = 21;
	function inspectTransportStream(bytes) {
		if (bytes.byteLength < TS_PACKET_BYTES * 3) unsupported("The media probe is too short to identify its streams.");
		const packetBytes = Math.floor(bytes.byteLength / TS_PACKET_BYTES) * TS_PACKET_BYTES;
		for (let offset = 0; offset < packetBytes; offset += TS_PACKET_BYTES) if (bytes[offset] !== 71) unsupported("The clip media is not a valid MPEG transport stream.");
		const streamTypes = parseStreamTypes(findPsiSection(bytes, parseProgramMapPid(findPsiSection(bytes, 0, 0)), 2));
		const hasH264 = streamTypes.includes(H264_STREAM_TYPE);
		const hasAac = streamTypes.some((type) => AAC_STREAM_TYPES.has(type));
		const unsupportedTypes = streamTypes.filter((type) => type !== H264_STREAM_TYPE && !AAC_STREAM_TYPES.has(type) && type !== ID3_STREAM_TYPE);
		if (!hasH264 || !hasAac || unsupportedTypes.length > 0) unsupported("The clip uses unsupported transport-stream codecs.");
		return {
			audioCodec: "aac",
			metadata: streamTypes.includes(ID3_STREAM_TYPE),
			videoCodec: "h264"
		};
	}
	function findPsiSection(bytes, targetPid, tableId) {
		let sectionBytes = [];
		let expectedLength;
		for (let packetOffset = 0; packetOffset + TS_PACKET_BYTES <= bytes.byteLength; packetOffset += TS_PACKET_BYTES) {
			const byte1 = bytes[packetOffset + 1];
			const byte2 = bytes[packetOffset + 2];
			const byte3 = bytes[packetOffset + 3];
			if (((byte1 & 31) << 8 | byte2) !== targetPid || (byte1 & 128) !== 0) continue;
			const adaptationControl = byte3 >> 4 & 3;
			if (adaptationControl === 0 || adaptationControl === 2) continue;
			let payloadOffset = packetOffset + 4;
			if (adaptationControl === 3) payloadOffset += bytes[payloadOffset] + 1;
			if (payloadOffset >= packetOffset + TS_PACKET_BYTES) continue;
			if ((byte1 & 64) !== 0) {
				const pointer = bytes[payloadOffset];
				payloadOffset += pointer + 1;
				sectionBytes = [];
				expectedLength = void 0;
			}
			for (let index = payloadOffset; index < packetOffset + TS_PACKET_BYTES; index += 1) {
				if (sectionBytes.length === 0 && bytes[index] === 255) break;
				sectionBytes.push(bytes[index]);
				if (sectionBytes.length === 3) {
					if (sectionBytes[0] !== tableId) {
						sectionBytes = [];
						break;
					}
					expectedLength = 3 + ((sectionBytes[1] & 15) << 8 | sectionBytes[2]);
				}
				if (expectedLength !== void 0 && sectionBytes.length === expectedLength) return Uint8Array.from(sectionBytes);
			}
		}
		unsupported("The transport-stream track metadata is incomplete.");
	}
	function parseProgramMapPid(section) {
		for (let offset = 8; offset + 4 <= section.byteLength - 4; offset += 4) if ((section[offset] << 8 | section[offset + 1]) !== 0) return (section[offset + 2] & 31) << 8 | section[offset + 3];
		unsupported("The transport stream does not declare a media program.");
	}
	function parseStreamTypes(section) {
		if (section.byteLength < 16) unsupported("The transport-stream program metadata is invalid.");
		const programInfoLength = (section[10] & 15) << 8 | section[11];
		const streamTypes = [];
		let offset = 12 + programInfoLength;
		const end = section.byteLength - 4;
		while (offset + 5 <= end) {
			const streamType = section[offset];
			const infoLength = (section[offset + 3] & 15) << 8 | section[offset + 4];
			streamTypes.push(streamType);
			offset += 5 + infoLength;
		}
		if (offset !== end || streamTypes.length === 0) unsupported("The transport-stream tracks are invalid.");
		return streamTypes;
	}
	function unsupported(message) {
		throw new ClipDownloadError("unsupported-media", message);
	}
	var MAX_API_RESPONSE_BYTES = 256 * 1024;
	var INITIAL_PROBE_BYTES = MAX_PROBE_BYTES / 2;
	var MAX_METADATA_TEXT_LENGTH = 300;
	async function inspectClip(clipId, signal, { fetchImplementation = fetch, pageUrl = window.location.href } = {}) {
		if (!isValidClipId(clipId)) throw new ClipDownloadError("clip-unavailable", "The clip link contains an invalid clip ID.");
		const response = await fetchImplementation(new URL(`/api/v2/clips/${encodeURIComponent(clipId)}/play`, pageUrl).href, {
			credentials: "same-origin",
			headers: { Accept: "application/json" },
			signal
		});
		if (response.status === 404) throw new ClipDownloadError("clip-unavailable", "This clip is unavailable or has been deleted.");
		if (!response.ok) throw new ClipDownloadError("inspection-blocked", "KICK blocked the clip inspection request. Try again shortly.");
		const clip = getRecord(parseJson(await readResponseBytes(response, MAX_API_RESPONSE_BYTES)).clip);
		const clipUrlValue = clip?.clip_url;
		if (!clip || typeof clipUrlValue !== "string") throw new ClipDownloadError("clip-unavailable", "KICK returned incomplete clip information.");
		validateResponseClipId(clip, clipId);
		const clipUrl = toAllowedMediaUrl(clipUrlValue);
		const initialProbe = await fetchInitialMediaProbe(clipUrl.href, INITIAL_PROBE_BYTES, signal, fetchImplementation);
		const probeText = new TextDecoder().decode(initialProbe.bytes);
		let plan;
		if (probeText.startsWith("#EXTM3U")) {
			if (initialProbe.totalBytes > 131072 || initialProbe.totalBytes !== initialProbe.bytes.byteLength) throw new ClipDownloadError("unsupported-media", "The clip playlist exceeds the safe inspection limit.");
			plan = parseKickMediaPlaylist(probeText, {
				isAllowedMediaUrl,
				playlistUrl: clipUrl.href
			});
			await validateTransportStreamPlan(plan, signal, fetchImplementation);
		} else {
			try {
				inspectMp4Probe(initialProbe.bytes);
			} catch (initialError) {
				const remainingProbeBytes = MAX_PROBE_BYTES - initialProbe.bytes.byteLength;
				if (remainingProbeBytes <= 0 || initialProbe.totalBytes <= initialProbe.bytes.byteLength) throw initialError;
				const suffixStart = Math.max(initialProbe.bytes.byteLength, initialProbe.totalBytes - remainingProbeBytes);
				const suffixLength = initialProbe.totalBytes - suffixStart;
				const suffix = (await fetchExactRange(clipUrl.href, suffixStart, suffixLength, signal, fetchImplementation)).bytes;
				inspectMp4Probe(initialProbe.bytes, suffix);
			}
			plan = {
				kind: "direct-mp4",
				sourceBytes: initialProbe.totalBytes,
				url: clipUrl.href
			};
		}
		return {
			clipId,
			metadata: normalizeMetadata(clip, pageUrl),
			plan
		};
	}
	async function validateTransportStreamPlan(plan, signal, fetchImplementation) {
		const firstSegment = plan.segments[0];
		if (!firstSegment) throw new ClipDownloadError("unsupported-media", "The clip playlist does not contain media.");
		const probeLength = Math.min(MAX_PROBE_BYTES, firstSegment.length ?? 262144);
		inspectTransportStream(firstSegment.length === void 0 ? (await fetchInitialMediaProbe(firstSegment.url, probeLength, signal, fetchImplementation)).bytes : (await fetchExactRange(firstSegment.url, firstSegment.offset ?? 0, probeLength, signal, fetchImplementation)).bytes);
	}
	function normalizeMetadata(clip, pageUrl) {
		const category = getRecord(clip.category);
		const channel = getRecord(clip.channel);
		const creator = getRecord(clip.creator) ?? getRecord(clip.user);
		return {
			category: firstSafeString(category?.name, clip.category),
			channel: firstSafeString(channel?.username, channel?.slug, channel?.name),
			creator: firstSafeString(creator?.username, creator?.name),
			duration: safeDuration(clip.duration),
			likeCount: safeCount(clip.likes),
			pageUrl,
			publishedAt: safeTimestamp(clip.created_at),
			thumbnailUrl: safeThumbnailUrl(clip.thumbnail_url ?? clip.thumbnail),
			title: firstSafeString(clip.title),
			viewCount: safeCount(clip.views)
		};
	}
	function validateResponseClipId(clip, expectedClipId) {
		const declaredIds = [clip.id, clip.clip_id].filter((value) => typeof value === "string" && value.startsWith("clip_"));
		if (declaredIds.length > 0 && declaredIds.some((value) => value !== expectedClipId)) throw new ClipDownloadError("clip-unavailable", "KICK returned information for a different clip.");
	}
	function parseJson(bytes) {
		try {
			const record = getRecord(JSON.parse(new TextDecoder().decode(bytes)));
			if (record) return record;
		} catch {}
		throw new ClipDownloadError("clip-unavailable", "KICK returned malformed clip information.");
	}
	function getRecord(value) {
		return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
	}
	function firstSafeString(...values) {
		for (const value of values) {
			if (typeof value !== "string") continue;
			const normalized = value.replace(/\s+/g, " ").trim();
			if (normalized) return normalized.slice(0, MAX_METADATA_TEXT_LENGTH);
		}
	}
	function safeDuration(value) {
		return typeof value === "number" && Number.isFinite(value) && value > 0 && value <= 180 ? value : void 0;
	}
	function safeCount(value) {
		return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
	}
	function safeTimestamp(value) {
		if (typeof value !== "string") return;
		const timestamp = Date.parse(value);
		return Number.isFinite(timestamp) ? timestamp : void 0;
	}
	function safeThumbnailUrl(value) {
		if (typeof value !== "string") return;
		try {
			const url = new URL(value);
			return url.protocol === "https:" && (url.hostname === "kick.com" || url.hostname.endsWith(".kick.com")) ? url.href : void 0;
		} catch {
			return;
		}
	}
	function toAllowedMediaUrl(value) {
		let url;
		try {
			url = new URL(value);
		} catch {
			throw new ClipDownloadError("unsupported-media", "KICK returned an invalid clip media URL.");
		}
		if (!isAllowedMediaUrl(url)) throw new ClipDownloadError("unsupported-media", "KICK returned an untrusted clip media URL.");
		return url;
	}
	var jsContent = `(function() {
	//#region \\0rolldown/runtime.js
	var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/utils/stream.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* A lightweight readable stream implemention that handles event dispatching.
	* Objects that inherit from streams should call init in their constructors.
	*/
	var require_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = function Stream() {
			this.init = function() {
				var listeners = {};
				/**
				* Add a listener for a specified event type.
				* @param type {string} the event name
				* @param listener {function} the callback to be invoked when an event of
				* the specified type occurs
				*/
				this.on = function(type, listener) {
					if (!listeners[type]) listeners[type] = [];
					listeners[type] = listeners[type].concat(listener);
				};
				/**
				* Remove a listener for a specified event type.
				* @param type {string} the event name
				* @param listener {function} a function previously registered for this
				* type of event through \`on\`
				*/
				this.off = function(type, listener) {
					var index;
					if (!listeners[type]) return false;
					index = listeners[type].indexOf(listener);
					listeners[type] = listeners[type].slice();
					listeners[type].splice(index, 1);
					return index > -1;
				};
				/**
				* Trigger an event of the specified type on this stream. Any additional
				* arguments to this function are passed as parameters to event listeners.
				* @param type {string} the event name
				*/
				this.trigger = function(type) {
					var callbacks = listeners[type], i, length, args;
					if (!callbacks) return;
					if (arguments.length === 2) {
						length = callbacks.length;
						for (i = 0; i < length; ++i) callbacks[i].call(this, arguments[1]);
					} else {
						args = [];
						i = arguments.length;
						for (i = 1; i < arguments.length; ++i) args.push(arguments[i]);
						length = callbacks.length;
						for (i = 0; i < length; ++i) callbacks[i].apply(this, args);
					}
				};
				/**
				* Destroys the stream and cleans up.
				*/
				this.dispose = function() {
					listeners = {};
				};
			};
		};
		/**
		* Forwards all \`data\` events on this stream to the destination stream. The
		* destination stream should provide a method \`push\` to receive the data
		* events as they arrive.
		* @param destination {stream} the stream that will receive all \`data\` events
		* @param autoFlush {boolean} if false, we will not call \`flush\` on the destination
		*                            when the current stream emits a 'done' event
		* @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
		*/
		Stream.prototype.pipe = function(destination) {
			this.on("data", function(data) {
				destination.push(data);
			});
			this.on("done", function(flushSource) {
				destination.flush(flushSource);
			});
			this.on("partialdone", function(flushSource) {
				destination.partialFlush(flushSource);
			});
			this.on("endedtimeline", function(flushSource) {
				destination.endTimeline(flushSource);
			});
			this.on("reset", function(flushSource) {
				destination.reset(flushSource);
			});
			return destination;
		};
		Stream.prototype.push = function(data) {
			this.trigger("data", data);
		};
		Stream.prototype.flush = function(flushSource) {
			this.trigger("done", flushSource);
		};
		Stream.prototype.partialFlush = function(flushSource) {
			this.trigger("partialdone", flushSource);
		};
		Stream.prototype.endTimeline = function(flushSource) {
			this.trigger("endedtimeline", flushSource);
		};
		Stream.prototype.reset = function(flushSource) {
			this.trigger("reset", flushSource);
		};
		module.exports = Stream;
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/utils/numbers.js
	var require_numbers = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var MAX_UINT32 = Math.pow(2, 32);
		module.exports = {
			getUint64: function getUint64(uint8) {
				var dv = new DataView(uint8.buffer, uint8.byteOffset, uint8.byteLength);
				var value;
				if (dv.getBigUint64) {
					value = dv.getBigUint64(0);
					if (value < Number.MAX_SAFE_INTEGER) return Number(value);
					return value;
				}
				return dv.getUint32(0) * MAX_UINT32 + dv.getUint32(4);
			},
			MAX_UINT32
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/mp4/mp4-generator.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* Functions that generate fragmented MP4s suitable for use with Media
	* Source Extensions.
	*/
	var require_mp4_generator = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var MAX_UINT32 = require_numbers().MAX_UINT32;
		var box;
		var dinf;
		var esds;
		var ftyp;
		var mdat;
		var mfhd;
		var minf;
		var moof;
		var moov;
		var mvex;
		var mvhd;
		var trak;
		var tkhd;
		var mdia;
		var mdhd;
		var hdlr;
		var sdtp;
		var stbl;
		var stsd;
		var traf;
		var trex;
		var trun;
		var types;
		var MAJOR_BRAND;
		var MINOR_VERSION;
		var AVC1_BRAND;
		var VIDEO_HDLR;
		var AUDIO_HDLR;
		var HDLR_TYPES;
		var VMHD;
		var SMHD;
		var DREF;
		var STCO;
		var STSC;
		var STSZ;
		var STTS;
		(function() {
			var i;
			types = {
				avc1: [],
				avcC: [],
				btrt: [],
				dinf: [],
				dref: [],
				esds: [],
				ftyp: [],
				hdlr: [],
				mdat: [],
				mdhd: [],
				mdia: [],
				mfhd: [],
				minf: [],
				moof: [],
				moov: [],
				mp4a: [],
				mvex: [],
				mvhd: [],
				pasp: [],
				sdtp: [],
				smhd: [],
				stbl: [],
				stco: [],
				stsc: [],
				stsd: [],
				stsz: [],
				stts: [],
				styp: [],
				tfdt: [],
				tfhd: [],
				traf: [],
				trak: [],
				trun: [],
				trex: [],
				tkhd: [],
				vmhd: []
			};
			if (typeof Uint8Array === "undefined") return;
			for (i in types) if (types.hasOwnProperty(i)) types[i] = [
				i.charCodeAt(0),
				i.charCodeAt(1),
				i.charCodeAt(2),
				i.charCodeAt(3)
			];
			MAJOR_BRAND = new Uint8Array([
				"i".charCodeAt(0),
				"s".charCodeAt(0),
				"o".charCodeAt(0),
				"m".charCodeAt(0)
			]);
			AVC1_BRAND = new Uint8Array([
				"a".charCodeAt(0),
				"v".charCodeAt(0),
				"c".charCodeAt(0),
				"1".charCodeAt(0)
			]);
			MINOR_VERSION = new Uint8Array([
				0,
				0,
				0,
				1
			]);
			VIDEO_HDLR = new Uint8Array([
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				118,
				105,
				100,
				101,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				86,
				105,
				100,
				101,
				111,
				72,
				97,
				110,
				100,
				108,
				101,
				114,
				0
			]);
			AUDIO_HDLR = new Uint8Array([
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				115,
				111,
				117,
				110,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				83,
				111,
				117,
				110,
				100,
				72,
				97,
				110,
				100,
				108,
				101,
				114,
				0
			]);
			HDLR_TYPES = {
				video: VIDEO_HDLR,
				audio: AUDIO_HDLR
			};
			DREF = new Uint8Array([
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				12,
				117,
				114,
				108,
				32,
				0,
				0,
				0,
				1
			]);
			SMHD = new Uint8Array([
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0
			]);
			STCO = new Uint8Array([
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0
			]);
			STSC = STCO;
			STSZ = new Uint8Array([
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0
			]);
			STTS = STCO;
			VMHD = new Uint8Array([
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0
			]);
		})();
		box = function box(type) {
			var payload = [], size = 0, i, result, view;
			for (i = 1; i < arguments.length; i++) payload.push(arguments[i]);
			i = payload.length;
			while (i--) size += payload[i].byteLength;
			result = new Uint8Array(size + 8);
			view = new DataView(result.buffer, result.byteOffset, result.byteLength);
			view.setUint32(0, result.byteLength);
			result.set(type, 4);
			for (i = 0, size = 8; i < payload.length; i++) {
				result.set(payload[i], size);
				size += payload[i].byteLength;
			}
			return result;
		};
		dinf = function dinf() {
			return box(types.dinf, box(types.dref, DREF));
		};
		esds = function esds(track) {
			return box(types.esds, new Uint8Array([
				0,
				0,
				0,
				0,
				3,
				25,
				0,
				0,
				0,
				4,
				17,
				64,
				21,
				0,
				6,
				0,
				0,
				0,
				218,
				192,
				0,
				0,
				218,
				192,
				5,
				2,
				track.audioobjecttype << 3 | track.samplingfrequencyindex >>> 1,
				track.samplingfrequencyindex << 7 | track.channelcount << 3,
				6,
				1,
				2
			]));
		};
		ftyp = function ftyp() {
			return box(types.ftyp, MAJOR_BRAND, MINOR_VERSION, MAJOR_BRAND, AVC1_BRAND);
		};
		hdlr = function hdlr(type) {
			return box(types.hdlr, HDLR_TYPES[type]);
		};
		mdat = function mdat(data) {
			return box(types.mdat, data);
		};
		mdhd = function mdhd(track) {
			var result = new Uint8Array([
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				2,
				0,
				0,
				0,
				3,
				0,
				1,
				95,
				144,
				track.duration >>> 24 & 255,
				track.duration >>> 16 & 255,
				track.duration >>> 8 & 255,
				track.duration & 255,
				85,
				196,
				0,
				0
			]);
			if (track.samplerate) {
				result[12] = track.samplerate >>> 24 & 255;
				result[13] = track.samplerate >>> 16 & 255;
				result[14] = track.samplerate >>> 8 & 255;
				result[15] = track.samplerate & 255;
			}
			return box(types.mdhd, result);
		};
		mdia = function mdia(track) {
			return box(types.mdia, mdhd(track), hdlr(track.type), minf(track));
		};
		mfhd = function mfhd(sequenceNumber) {
			return box(types.mfhd, new Uint8Array([
				0,
				0,
				0,
				0,
				(sequenceNumber & 4278190080) >> 24,
				(sequenceNumber & 16711680) >> 16,
				(sequenceNumber & 65280) >> 8,
				sequenceNumber & 255
			]));
		};
		minf = function minf(track) {
			return box(types.minf, track.type === "video" ? box(types.vmhd, VMHD) : box(types.smhd, SMHD), dinf(), stbl(track));
		};
		moof = function moof(sequenceNumber, tracks) {
			var trackFragments = [], i = tracks.length;
			while (i--) trackFragments[i] = traf(tracks[i]);
			return box.apply(null, [types.moof, mfhd(sequenceNumber)].concat(trackFragments));
		};
		/**
		* Returns a movie box.
		* @param tracks {array} the tracks associated with this movie
		* @see ISO/IEC 14496-12:2012(E), section 8.2.1
		*/
		moov = function moov(tracks) {
			var i = tracks.length, boxes = [];
			while (i--) boxes[i] = trak(tracks[i]);
			return box.apply(null, [types.moov, mvhd(4294967295)].concat(boxes).concat(mvex(tracks)));
		};
		mvex = function mvex(tracks) {
			var i = tracks.length, boxes = [];
			while (i--) boxes[i] = trex(tracks[i]);
			return box.apply(null, [types.mvex].concat(boxes));
		};
		mvhd = function mvhd(duration) {
			var bytes = new Uint8Array([
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				2,
				0,
				1,
				95,
				144,
				(duration & 4278190080) >> 24,
				(duration & 16711680) >> 16,
				(duration & 65280) >> 8,
				duration & 255,
				0,
				1,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				64,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				255,
				255,
				255,
				255
			]);
			return box(types.mvhd, bytes);
		};
		sdtp = function sdtp(track) {
			var samples = track.samples || [], bytes = new Uint8Array(4 + samples.length), flags, i;
			for (i = 0; i < samples.length; i++) {
				flags = samples[i].flags;
				bytes[i + 4] = flags.dependsOn << 4 | flags.isDependedOn << 2 | flags.hasRedundancy;
			}
			return box(types.sdtp, bytes);
		};
		stbl = function stbl(track) {
			return box(types.stbl, stsd(track), box(types.stts, STTS), box(types.stsc, STSC), box(types.stsz, STSZ), box(types.stco, STCO));
		};
		(function() {
			var videoSample, audioSample;
			stsd = function stsd(track) {
				return box(types.stsd, new Uint8Array([
					0,
					0,
					0,
					0,
					0,
					0,
					0,
					1
				]), track.type === "video" ? videoSample(track) : audioSample(track));
			};
			videoSample = function videoSample(track) {
				var sps = track.sps || [], pps = track.pps || [], sequenceParameterSets = [], pictureParameterSets = [], i, avc1Box;
				for (i = 0; i < sps.length; i++) {
					sequenceParameterSets.push((sps[i].byteLength & 65280) >>> 8);
					sequenceParameterSets.push(sps[i].byteLength & 255);
					sequenceParameterSets = sequenceParameterSets.concat(Array.prototype.slice.call(sps[i]));
				}
				for (i = 0; i < pps.length; i++) {
					pictureParameterSets.push((pps[i].byteLength & 65280) >>> 8);
					pictureParameterSets.push(pps[i].byteLength & 255);
					pictureParameterSets = pictureParameterSets.concat(Array.prototype.slice.call(pps[i]));
				}
				avc1Box = [
					types.avc1,
					new Uint8Array([
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						1,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						(track.width & 65280) >> 8,
						track.width & 255,
						(track.height & 65280) >> 8,
						track.height & 255,
						0,
						72,
						0,
						0,
						0,
						72,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						1,
						19,
						118,
						105,
						100,
						101,
						111,
						106,
						115,
						45,
						99,
						111,
						110,
						116,
						114,
						105,
						98,
						45,
						104,
						108,
						115,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						0,
						24,
						17,
						17
					]),
					box(types.avcC, new Uint8Array([
						1,
						track.profileIdc,
						track.profileCompatibility,
						track.levelIdc,
						255
					].concat([sps.length], sequenceParameterSets, [pps.length], pictureParameterSets))),
					box(types.btrt, new Uint8Array([
						0,
						28,
						156,
						128,
						0,
						45,
						198,
						192,
						0,
						45,
						198,
						192
					]))
				];
				if (track.sarRatio) {
					var hSpacing = track.sarRatio[0], vSpacing = track.sarRatio[1];
					avc1Box.push(box(types.pasp, new Uint8Array([
						(hSpacing & 4278190080) >> 24,
						(hSpacing & 16711680) >> 16,
						(hSpacing & 65280) >> 8,
						hSpacing & 255,
						(vSpacing & 4278190080) >> 24,
						(vSpacing & 16711680) >> 16,
						(vSpacing & 65280) >> 8,
						vSpacing & 255
					])));
				}
				return box.apply(null, avc1Box);
			};
			audioSample = function audioSample(track) {
				return box(types.mp4a, new Uint8Array([
					0,
					0,
					0,
					0,
					0,
					0,
					0,
					1,
					0,
					0,
					0,
					0,
					0,
					0,
					0,
					0,
					(track.channelcount & 65280) >> 8,
					track.channelcount & 255,
					(track.samplesize & 65280) >> 8,
					track.samplesize & 255,
					0,
					0,
					0,
					0,
					(track.samplerate & 65280) >> 8,
					track.samplerate & 255,
					0,
					0
				]), esds(track));
			};
		})();
		tkhd = function tkhd(track) {
			var result = new Uint8Array([
				0,
				0,
				0,
				7,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				(track.id & 4278190080) >> 24,
				(track.id & 16711680) >> 16,
				(track.id & 65280) >> 8,
				track.id & 255,
				0,
				0,
				0,
				0,
				(track.duration & 4278190080) >> 24,
				(track.duration & 16711680) >> 16,
				(track.duration & 65280) >> 8,
				track.duration & 255,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				64,
				0,
				0,
				0,
				(track.width & 65280) >> 8,
				track.width & 255,
				0,
				0,
				(track.height & 65280) >> 8,
				track.height & 255,
				0,
				0
			]);
			return box(types.tkhd, result);
		};
		/**
		* Generate a track fragment (traf) box. A traf box collects metadata
		* about tracks in a movie fragment (moof) box.
		*/
		traf = function traf(track) {
			var trackFragmentHeader = box(types.tfhd, new Uint8Array([
				0,
				0,
				0,
				58,
				(track.id & 4278190080) >> 24,
				(track.id & 16711680) >> 16,
				(track.id & 65280) >> 8,
				track.id & 255,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0
			])), trackFragmentDecodeTime, trackFragmentRun, sampleDependencyTable, dataOffset, upperWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime / MAX_UINT32), lowerWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime % MAX_UINT32);
			trackFragmentDecodeTime = box(types.tfdt, new Uint8Array([
				1,
				0,
				0,
				0,
				upperWordBaseMediaDecodeTime >>> 24 & 255,
				upperWordBaseMediaDecodeTime >>> 16 & 255,
				upperWordBaseMediaDecodeTime >>> 8 & 255,
				upperWordBaseMediaDecodeTime & 255,
				lowerWordBaseMediaDecodeTime >>> 24 & 255,
				lowerWordBaseMediaDecodeTime >>> 16 & 255,
				lowerWordBaseMediaDecodeTime >>> 8 & 255,
				lowerWordBaseMediaDecodeTime & 255
			]));
			dataOffset = 92;
			if (track.type === "audio") {
				trackFragmentRun = trun(track, dataOffset);
				return box(types.traf, trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun);
			}
			sampleDependencyTable = sdtp(track);
			trackFragmentRun = trun(track, sampleDependencyTable.length + dataOffset);
			return box(types.traf, trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun, sampleDependencyTable);
		};
		/**
		* Generate a track box.
		* @param track {object} a track definition
		* @return {Uint8Array} the track box
		*/
		trak = function trak(track) {
			track.duration = track.duration || 4294967295;
			return box(types.trak, tkhd(track), mdia(track));
		};
		trex = function trex(track) {
			var result = new Uint8Array([
				0,
				0,
				0,
				0,
				(track.id & 4278190080) >> 24,
				(track.id & 16711680) >> 16,
				(track.id & 65280) >> 8,
				track.id & 255,
				0,
				0,
				0,
				1,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				1,
				0,
				1
			]);
			if (track.type !== "video") result[result.length - 1] = 0;
			return box(types.trex, result);
		};
		(function() {
			var audioTrun, videoTrun, trunHeader = function trunHeader(samples, offset) {
				var durationPresent = 0, sizePresent = 0, flagsPresent = 0, compositionTimeOffset = 0;
				if (samples.length) {
					if (samples[0].duration !== void 0) durationPresent = 1;
					if (samples[0].size !== void 0) sizePresent = 2;
					if (samples[0].flags !== void 0) flagsPresent = 4;
					if (samples[0].compositionTimeOffset !== void 0) compositionTimeOffset = 8;
				}
				return [
					0,
					0,
					durationPresent | sizePresent | flagsPresent | compositionTimeOffset,
					1,
					(samples.length & 4278190080) >>> 24,
					(samples.length & 16711680) >>> 16,
					(samples.length & 65280) >>> 8,
					samples.length & 255,
					(offset & 4278190080) >>> 24,
					(offset & 16711680) >>> 16,
					(offset & 65280) >>> 8,
					offset & 255
				];
			};
			videoTrun = function videoTrun(track, offset) {
				var bytesOffest, bytes, header, samples = track.samples || [], sample, i;
				offset += 20 + 16 * samples.length;
				header = trunHeader(samples, offset);
				bytes = new Uint8Array(header.length + samples.length * 16);
				bytes.set(header);
				bytesOffest = header.length;
				for (i = 0; i < samples.length; i++) {
					sample = samples[i];
					bytes[bytesOffest++] = (sample.duration & 4278190080) >>> 24;
					bytes[bytesOffest++] = (sample.duration & 16711680) >>> 16;
					bytes[bytesOffest++] = (sample.duration & 65280) >>> 8;
					bytes[bytesOffest++] = sample.duration & 255;
					bytes[bytesOffest++] = (sample.size & 4278190080) >>> 24;
					bytes[bytesOffest++] = (sample.size & 16711680) >>> 16;
					bytes[bytesOffest++] = (sample.size & 65280) >>> 8;
					bytes[bytesOffest++] = sample.size & 255;
					bytes[bytesOffest++] = sample.flags.isLeading << 2 | sample.flags.dependsOn;
					bytes[bytesOffest++] = sample.flags.isDependedOn << 6 | sample.flags.hasRedundancy << 4 | sample.flags.paddingValue << 1 | sample.flags.isNonSyncSample;
					bytes[bytesOffest++] = sample.flags.degradationPriority & 61440;
					bytes[bytesOffest++] = sample.flags.degradationPriority & 15;
					bytes[bytesOffest++] = (sample.compositionTimeOffset & 4278190080) >>> 24;
					bytes[bytesOffest++] = (sample.compositionTimeOffset & 16711680) >>> 16;
					bytes[bytesOffest++] = (sample.compositionTimeOffset & 65280) >>> 8;
					bytes[bytesOffest++] = sample.compositionTimeOffset & 255;
				}
				return box(types.trun, bytes);
			};
			audioTrun = function audioTrun(track, offset) {
				var bytes, bytesOffest, header, samples = track.samples || [], sample, i;
				offset += 20 + 8 * samples.length;
				header = trunHeader(samples, offset);
				bytes = new Uint8Array(header.length + samples.length * 8);
				bytes.set(header);
				bytesOffest = header.length;
				for (i = 0; i < samples.length; i++) {
					sample = samples[i];
					bytes[bytesOffest++] = (sample.duration & 4278190080) >>> 24;
					bytes[bytesOffest++] = (sample.duration & 16711680) >>> 16;
					bytes[bytesOffest++] = (sample.duration & 65280) >>> 8;
					bytes[bytesOffest++] = sample.duration & 255;
					bytes[bytesOffest++] = (sample.size & 4278190080) >>> 24;
					bytes[bytesOffest++] = (sample.size & 16711680) >>> 16;
					bytes[bytesOffest++] = (sample.size & 65280) >>> 8;
					bytes[bytesOffest++] = sample.size & 255;
				}
				return box(types.trun, bytes);
			};
			trun = function trun(track, offset) {
				if (track.type === "audio") return audioTrun(track, offset);
				return videoTrun(track, offset);
			};
		})();
		module.exports = {
			ftyp,
			mdat,
			moof,
			moov,
			initSegment: function initSegment(tracks) {
				var fileType = ftyp(), movie = moov(tracks), result = new Uint8Array(fileType.byteLength + movie.byteLength);
				result.set(fileType);
				result.set(movie, fileType.byteLength);
				return result;
			}
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/mp4/frame-utils.js
	var require_frame_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		/**
		* mux.js
		*
		* Copyright (c) Brightcove
		* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
		*/
		var groupNalsIntoFrames = function groupNalsIntoFrames(nalUnits) {
			var i, currentNal, currentFrame = [], frames = [];
			frames.byteLength = 0;
			frames.nalCount = 0;
			frames.duration = 0;
			currentFrame.byteLength = 0;
			for (i = 0; i < nalUnits.length; i++) {
				currentNal = nalUnits[i];
				if (currentNal.nalUnitType === "access_unit_delimiter_rbsp") {
					if (currentFrame.length) {
						currentFrame.duration = currentNal.dts - currentFrame.dts;
						frames.byteLength += currentFrame.byteLength;
						frames.nalCount += currentFrame.length;
						frames.duration += currentFrame.duration;
						frames.push(currentFrame);
					}
					currentFrame = [currentNal];
					currentFrame.byteLength = currentNal.data.byteLength;
					currentFrame.pts = currentNal.pts;
					currentFrame.dts = currentNal.dts;
				} else {
					if (currentNal.nalUnitType === "slice_layer_without_partitioning_rbsp_idr") currentFrame.keyFrame = true;
					currentFrame.duration = currentNal.dts - currentFrame.dts;
					currentFrame.byteLength += currentNal.data.byteLength;
					currentFrame.push(currentNal);
				}
			}
			if (frames.length && (!currentFrame.duration || currentFrame.duration <= 0)) currentFrame.duration = frames[frames.length - 1].duration;
			frames.byteLength += currentFrame.byteLength;
			frames.nalCount += currentFrame.length;
			frames.duration += currentFrame.duration;
			frames.push(currentFrame);
			return frames;
		};
		var groupFramesIntoGops = function groupFramesIntoGops(frames) {
			var i, currentFrame, currentGop = [], gops = [];
			currentGop.byteLength = 0;
			currentGop.nalCount = 0;
			currentGop.duration = 0;
			currentGop.pts = frames[0].pts;
			currentGop.dts = frames[0].dts;
			gops.byteLength = 0;
			gops.nalCount = 0;
			gops.duration = 0;
			gops.pts = frames[0].pts;
			gops.dts = frames[0].dts;
			for (i = 0; i < frames.length; i++) {
				currentFrame = frames[i];
				if (currentFrame.keyFrame) {
					if (currentGop.length) {
						gops.push(currentGop);
						gops.byteLength += currentGop.byteLength;
						gops.nalCount += currentGop.nalCount;
						gops.duration += currentGop.duration;
					}
					currentGop = [currentFrame];
					currentGop.nalCount = currentFrame.length;
					currentGop.byteLength = currentFrame.byteLength;
					currentGop.pts = currentFrame.pts;
					currentGop.dts = currentFrame.dts;
					currentGop.duration = currentFrame.duration;
				} else {
					currentGop.duration += currentFrame.duration;
					currentGop.nalCount += currentFrame.length;
					currentGop.byteLength += currentFrame.byteLength;
					currentGop.push(currentFrame);
				}
			}
			if (gops.length && currentGop.duration <= 0) currentGop.duration = gops[gops.length - 1].duration;
			gops.byteLength += currentGop.byteLength;
			gops.nalCount += currentGop.nalCount;
			gops.duration += currentGop.duration;
			gops.push(currentGop);
			return gops;
		};
		var extendFirstKeyFrame = function extendFirstKeyFrame(gops) {
			var currentGop;
			if (!gops[0][0].keyFrame && gops.length > 1) {
				currentGop = gops.shift();
				gops.byteLength -= currentGop.byteLength;
				gops.nalCount -= currentGop.nalCount;
				gops[0][0].dts = currentGop.dts;
				gops[0][0].pts = currentGop.pts;
				gops[0][0].duration += currentGop.duration;
			}
			return gops;
		};
		/**
		* Default sample object
		* see ISO/IEC 14496-12:2012, section 8.6.4.3
		*/
		var createDefaultSample = function createDefaultSample() {
			return {
				size: 0,
				flags: {
					isLeading: 0,
					dependsOn: 1,
					isDependedOn: 0,
					hasRedundancy: 0,
					degradationPriority: 0,
					isNonSyncSample: 1
				}
			};
		};
		var sampleForFrame = function sampleForFrame(frame, dataOffset) {
			var sample = createDefaultSample();
			sample.dataOffset = dataOffset;
			sample.compositionTimeOffset = frame.pts - frame.dts;
			sample.duration = frame.duration;
			sample.size = 4 * frame.length;
			sample.size += frame.byteLength;
			if (frame.keyFrame) {
				sample.flags.dependsOn = 2;
				sample.flags.isNonSyncSample = 0;
			}
			return sample;
		};
		module.exports = {
			groupNalsIntoFrames,
			groupFramesIntoGops,
			extendFirstKeyFrame,
			generateSampleTable: function generateSampleTable(gops, baseDataOffset) {
				var h, i, sample, currentGop, currentFrame, dataOffset = baseDataOffset || 0, samples = [];
				for (h = 0; h < gops.length; h++) {
					currentGop = gops[h];
					for (i = 0; i < currentGop.length; i++) {
						currentFrame = currentGop[i];
						sample = sampleForFrame(currentFrame, dataOffset);
						dataOffset += sample.size;
						samples.push(sample);
					}
				}
				return samples;
			},
			concatenateNalData: function concatenateNalData(gops) {
				var h, i, j, currentGop, currentFrame, currentNal, dataOffset = 0, totalByteLength = gops.byteLength + 4 * gops.nalCount, data = new Uint8Array(totalByteLength), view = new DataView(data.buffer);
				for (h = 0; h < gops.length; h++) {
					currentGop = gops[h];
					for (i = 0; i < currentGop.length; i++) {
						currentFrame = currentGop[i];
						for (j = 0; j < currentFrame.length; j++) {
							currentNal = currentFrame[j];
							view.setUint32(dataOffset, currentNal.data.byteLength);
							dataOffset += 4;
							data.set(currentNal.data, dataOffset);
							dataOffset += currentNal.data.byteLength;
						}
					}
				}
				return data;
			},
			generateSampleTableForFrame: function generateSampleTableForFrame(frame, baseDataOffset) {
				var sample, dataOffset = baseDataOffset || 0, samples = [];
				sample = sampleForFrame(frame, dataOffset);
				samples.push(sample);
				return samples;
			},
			concatenateNalDataForFrame: function concatenateNalDataForFrame(frame) {
				var i, currentNal, dataOffset = 0, totalByteLength = frame.byteLength + 4 * frame.length, data = new Uint8Array(totalByteLength), view = new DataView(data.buffer);
				for (i = 0; i < frame.length; i++) {
					currentNal = frame[i];
					view.setUint32(dataOffset, currentNal.data.byteLength);
					dataOffset += 4;
					data.set(currentNal.data, dataOffset);
					dataOffset += currentNal.data.byteLength;
				}
				return data;
			}
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/data/silence.js
	var require_silence = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		/**
		* mux.js
		*
		* Copyright (c) Brightcove
		* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
		*/
		var highPrefix = [
			33,
			16,
			5,
			32,
			164,
			27
		];
		var lowPrefix = [
			33,
			65,
			108,
			84,
			1,
			2,
			4,
			8,
			168,
			2,
			4,
			8,
			17,
			191,
			252
		];
		var zeroFill = function zeroFill(count) {
			var a = [];
			while (count--) a.push(0);
			return a;
		};
		var makeTable = function makeTable(metaTable) {
			return Object.keys(metaTable).reduce(function(obj, key) {
				obj[key] = new Uint8Array(metaTable[key].reduce(function(arr, part) {
					return arr.concat(part);
				}, []));
				return obj;
			}, {});
		};
		var silence;
		module.exports = function() {
			if (!silence) silence = makeTable({
				96e3: [
					highPrefix,
					[227, 64],
					zeroFill(154),
					[56]
				],
				88200: [
					highPrefix,
					[231],
					zeroFill(170),
					[56]
				],
				64e3: [
					highPrefix,
					[248, 192],
					zeroFill(240),
					[56]
				],
				48e3: [
					highPrefix,
					[255, 192],
					zeroFill(268),
					[
						55,
						148,
						128
					],
					zeroFill(54),
					[112]
				],
				44100: [
					highPrefix,
					[255, 192],
					zeroFill(268),
					[
						55,
						163,
						128
					],
					zeroFill(84),
					[112]
				],
				32e3: [
					highPrefix,
					[255, 192],
					zeroFill(268),
					[55, 234],
					zeroFill(226),
					[112]
				],
				24e3: [
					highPrefix,
					[255, 192],
					zeroFill(268),
					[
						55,
						255,
						128
					],
					zeroFill(268),
					[111, 112],
					zeroFill(126),
					[224]
				],
				16e3: [
					highPrefix,
					[255, 192],
					zeroFill(268),
					[
						55,
						255,
						128
					],
					zeroFill(268),
					[111, 255],
					zeroFill(269),
					[223, 108],
					zeroFill(195),
					[1, 192]
				],
				12e3: [
					lowPrefix,
					zeroFill(268),
					[
						3,
						127,
						248
					],
					zeroFill(268),
					[
						6,
						255,
						240
					],
					zeroFill(268),
					[
						13,
						255,
						224
					],
					zeroFill(268),
					[
						27,
						253,
						128
					],
					zeroFill(259),
					[56]
				],
				11025: [
					lowPrefix,
					zeroFill(268),
					[
						3,
						127,
						248
					],
					zeroFill(268),
					[
						6,
						255,
						240
					],
					zeroFill(268),
					[
						13,
						255,
						224
					],
					zeroFill(268),
					[
						27,
						255,
						192
					],
					zeroFill(268),
					[
						55,
						175,
						128
					],
					zeroFill(108),
					[112]
				],
				8e3: [
					lowPrefix,
					zeroFill(268),
					[
						3,
						121,
						16
					],
					zeroFill(47),
					[7]
				]
			});
			return silence;
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/utils/clock.js
	var require_clock = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		/**
		* mux.js
		*
		* Copyright (c) Brightcove
		* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
		*/
		var ONE_SECOND_IN_TS = 9e4;
		var secondsToVideoTs = function secondsToVideoTs(seconds) {
			return seconds * ONE_SECOND_IN_TS;
		};
		var secondsToAudioTs = function secondsToAudioTs(seconds, sampleRate) {
			return seconds * sampleRate;
		};
		var videoTsToSeconds = function videoTsToSeconds(timestamp) {
			return timestamp / ONE_SECOND_IN_TS;
		};
		var audioTsToSeconds = function audioTsToSeconds(timestamp, sampleRate) {
			return timestamp / sampleRate;
		};
		module.exports = {
			ONE_SECOND_IN_TS,
			secondsToVideoTs,
			secondsToAudioTs,
			videoTsToSeconds,
			audioTsToSeconds,
			audioTsToVideoTs: function audioTsToVideoTs(timestamp, sampleRate) {
				return secondsToVideoTs(audioTsToSeconds(timestamp, sampleRate));
			},
			videoTsToAudioTs: function videoTsToAudioTs(timestamp, sampleRate) {
				return secondsToAudioTs(videoTsToSeconds(timestamp), sampleRate);
			},
			metadataTsToSeconds: function metadataTsToSeconds(timestamp, timelineStartPts, keepOriginalTimestamps) {
				return videoTsToSeconds(keepOriginalTimestamps ? timestamp : timestamp - timelineStartPts);
			}
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/mp4/audio-frame-utils.js
	var require_audio_frame_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		/**
		* mux.js
		*
		* Copyright (c) Brightcove
		* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
		*/
		var coneOfSilence = require_silence();
		var clock = require_clock();
		/**
		* Sum the \`byteLength\` properties of the data in each AAC frame
		*/
		var sumFrameByteLengths = function sumFrameByteLengths(array) {
			var i, currentObj, sum = 0;
			for (i = 0; i < array.length; i++) {
				currentObj = array[i];
				sum += currentObj.data.byteLength;
			}
			return sum;
		};
		module.exports = {
			prefixWithSilence: function prefixWithSilence(track, frames, audioAppendStartTs, videoBaseMediaDecodeTime) {
				var baseMediaDecodeTimeTs, frameDuration = 0, audioGapDuration = 0, audioFillFrameCount = 0, audioFillDuration = 0, silentFrame, i, firstFrame;
				if (!frames.length) return;
				baseMediaDecodeTimeTs = clock.audioTsToVideoTs(track.baseMediaDecodeTime, track.samplerate);
				frameDuration = Math.ceil(clock.ONE_SECOND_IN_TS / (track.samplerate / 1024));
				if (audioAppendStartTs && videoBaseMediaDecodeTime) {
					audioGapDuration = baseMediaDecodeTimeTs - Math.max(audioAppendStartTs, videoBaseMediaDecodeTime);
					audioFillFrameCount = Math.floor(audioGapDuration / frameDuration);
					audioFillDuration = audioFillFrameCount * frameDuration;
				}
				if (audioFillFrameCount < 1 || audioFillDuration > clock.ONE_SECOND_IN_TS / 2) return;
				silentFrame = coneOfSilence()[track.samplerate];
				if (!silentFrame) silentFrame = frames[0].data;
				for (i = 0; i < audioFillFrameCount; i++) {
					firstFrame = frames[0];
					frames.splice(0, 0, {
						data: silentFrame,
						dts: firstFrame.dts - frameDuration,
						pts: firstFrame.pts - frameDuration
					});
				}
				track.baseMediaDecodeTime -= Math.floor(clock.videoTsToAudioTs(audioFillDuration, track.samplerate));
				return audioFillDuration;
			},
			trimAdtsFramesByEarliestDts: function trimAdtsFramesByEarliestDts(adtsFrames, track, earliestAllowedDts) {
				if (track.minSegmentDts >= earliestAllowedDts) return adtsFrames;
				track.minSegmentDts = Infinity;
				return adtsFrames.filter(function(currentFrame) {
					if (currentFrame.dts >= earliestAllowedDts) {
						track.minSegmentDts = Math.min(track.minSegmentDts, currentFrame.dts);
						track.minSegmentPts = track.minSegmentDts;
						return true;
					}
					return false;
				});
			},
			generateSampleTable: function generateSampleTable(frames) {
				var i, currentFrame, samples = [];
				for (i = 0; i < frames.length; i++) {
					currentFrame = frames[i];
					samples.push({
						size: currentFrame.data.byteLength,
						duration: 1024
					});
				}
				return samples;
			},
			concatenateFrameData: function concatenateFrameData(frames) {
				var i, currentFrame, dataOffset = 0, data = new Uint8Array(sumFrameByteLengths(frames));
				for (i = 0; i < frames.length; i++) {
					currentFrame = frames[i];
					data.set(currentFrame.data, dataOffset);
					dataOffset += currentFrame.data.byteLength;
				}
				return data;
			}
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/mp4/track-decode-info.js
	var require_track_decode_info = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		/**
		* mux.js
		*
		* Copyright (c) Brightcove
		* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
		*/
		var ONE_SECOND_IN_TS = require_clock().ONE_SECOND_IN_TS;
		module.exports = {
			clearDtsInfo: function clearDtsInfo(track) {
				delete track.minSegmentDts;
				delete track.maxSegmentDts;
				delete track.minSegmentPts;
				delete track.maxSegmentPts;
			},
			calculateTrackBaseMediaDecodeTime: function calculateTrackBaseMediaDecodeTime(track, keepOriginalTimestamps) {
				var baseMediaDecodeTime, scale, minSegmentDts = track.minSegmentDts;
				if (!keepOriginalTimestamps) minSegmentDts -= track.timelineStartInfo.dts;
				baseMediaDecodeTime = track.timelineStartInfo.baseMediaDecodeTime;
				baseMediaDecodeTime += minSegmentDts;
				baseMediaDecodeTime = Math.max(0, baseMediaDecodeTime);
				if (track.type === "audio") {
					scale = track.samplerate / ONE_SECOND_IN_TS;
					baseMediaDecodeTime *= scale;
					baseMediaDecodeTime = Math.floor(baseMediaDecodeTime);
				}
				return baseMediaDecodeTime;
			},
			collectDtsInfo: function collectDtsInfo(track, data) {
				if (typeof data.pts === "number") {
					if (track.timelineStartInfo.pts === void 0) track.timelineStartInfo.pts = data.pts;
					if (track.minSegmentPts === void 0) track.minSegmentPts = data.pts;
					else track.minSegmentPts = Math.min(track.minSegmentPts, data.pts);
					if (track.maxSegmentPts === void 0) track.maxSegmentPts = data.pts;
					else track.maxSegmentPts = Math.max(track.maxSegmentPts, data.pts);
				}
				if (typeof data.dts === "number") {
					if (track.timelineStartInfo.dts === void 0) track.timelineStartInfo.dts = data.dts;
					if (track.minSegmentDts === void 0) track.minSegmentDts = data.dts;
					else track.minSegmentDts = Math.min(track.minSegmentDts, data.dts);
					if (track.maxSegmentDts === void 0) track.maxSegmentDts = data.dts;
					else track.maxSegmentDts = Math.max(track.maxSegmentDts, data.dts);
				}
			}
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/tools/caption-packet-parser.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* Reads in-band caption information from a video elementary
	* stream. Captions must follow the CEA-708 standard for injection
	* into an MPEG-2 transport streams.
	* @see https://en.wikipedia.org/wiki/CEA-708
	* @see https://www.gpo.gov/fdsys/pkg/CFR-2007-title47-vol1/pdf/CFR-2007-title47-vol1-sec15-119.pdf
	*/
	var require_caption_packet_parser = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var USER_DATA_REGISTERED_ITU_T_T35 = 4;
		var RBSP_TRAILING_BITS = 128;
		module.exports = {
			parseSei: function parseSei(bytes) {
				var i = 0, result = {
					payloadType: -1,
					payloadSize: 0
				}, payloadType = 0, payloadSize = 0;
				while (i < bytes.byteLength) {
					if (bytes[i] === RBSP_TRAILING_BITS) break;
					while (bytes[i] === 255) {
						payloadType += 255;
						i++;
					}
					payloadType += bytes[i++];
					while (bytes[i] === 255) {
						payloadSize += 255;
						i++;
					}
					payloadSize += bytes[i++];
					if (!result.payload && payloadType === USER_DATA_REGISTERED_ITU_T_T35) if (String.fromCharCode(bytes[i + 3], bytes[i + 4], bytes[i + 5], bytes[i + 6]) === "GA94") {
						result.payloadType = payloadType;
						result.payloadSize = payloadSize;
						result.payload = bytes.subarray(i, i + payloadSize);
						break;
					} else result.payload = void 0;
					i += payloadSize;
					payloadType = 0;
					payloadSize = 0;
				}
				return result;
			},
			parseUserData: function parseUserData(sei) {
				if (sei.payload[0] !== 181) return null;
				if ((sei.payload[1] << 8 | sei.payload[2]) !== 49) return null;
				if (String.fromCharCode(sei.payload[3], sei.payload[4], sei.payload[5], sei.payload[6]) !== "GA94") return null;
				if (sei.payload[7] !== 3) return null;
				return sei.payload.subarray(8, sei.payload.length - 1);
			},
			parseCaptionPackets: function parseCaptionPackets(pts, userData) {
				var results = [], i, count, offset, data;
				if (!(userData[0] & 64)) return results;
				count = userData[0] & 31;
				for (i = 0; i < count; i++) {
					offset = i * 3;
					data = {
						type: userData[offset + 2] & 3,
						pts
					};
					if (userData[offset + 2] & 4) {
						data.ccData = userData[offset + 3] << 8 | userData[offset + 4];
						results.push(data);
					}
				}
				return results;
			},
			discardEmulationPreventionBytes: function discardEmulationPreventionBytes(data) {
				var length = data.byteLength, emulationPreventionBytesPositions = [], i = 1, newLength, newData;
				while (i < length - 2) if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 3) {
					emulationPreventionBytesPositions.push(i + 2);
					i += 2;
				} else i++;
				if (emulationPreventionBytesPositions.length === 0) return data;
				newLength = length - emulationPreventionBytesPositions.length;
				newData = new Uint8Array(newLength);
				var sourceIndex = 0;
				for (i = 0; i < newLength; sourceIndex++, i++) {
					if (sourceIndex === emulationPreventionBytesPositions[0]) {
						sourceIndex++;
						emulationPreventionBytesPositions.shift();
					}
					newData[i] = data[sourceIndex];
				}
				return newData;
			},
			USER_DATA_REGISTERED_ITU_T_T35
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/m2ts/caption-stream.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* Reads in-band caption information from a video elementary
	* stream. Captions must follow the CEA-708 standard for injection
	* into an MPEG-2 transport streams.
	* @see https://en.wikipedia.org/wiki/CEA-708
	* @see https://www.gpo.gov/fdsys/pkg/CFR-2007-title47-vol1/pdf/CFR-2007-title47-vol1-sec15-119.pdf
	*/
	var require_caption_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = require_stream();
		var cea708Parser = require_caption_packet_parser();
		var CaptionStream = function CaptionStream(options) {
			options = options || {};
			CaptionStream.prototype.init.call(this);
			this.parse708captions_ = typeof options.parse708captions === "boolean" ? options.parse708captions : true;
			this.captionPackets_ = [];
			this.ccStreams_ = [
				new Cea608Stream(0, 0),
				new Cea608Stream(0, 1),
				new Cea608Stream(1, 0),
				new Cea608Stream(1, 1)
			];
			if (this.parse708captions_) this.cc708Stream_ = new Cea708Stream({ captionServices: options.captionServices });
			this.reset();
			this.ccStreams_.forEach(function(cc) {
				cc.on("data", this.trigger.bind(this, "data"));
				cc.on("partialdone", this.trigger.bind(this, "partialdone"));
				cc.on("done", this.trigger.bind(this, "done"));
			}, this);
			if (this.parse708captions_) {
				this.cc708Stream_.on("data", this.trigger.bind(this, "data"));
				this.cc708Stream_.on("partialdone", this.trigger.bind(this, "partialdone"));
				this.cc708Stream_.on("done", this.trigger.bind(this, "done"));
			}
		};
		CaptionStream.prototype = new Stream();
		CaptionStream.prototype.push = function(event) {
			var sei, userData, newCaptionPackets;
			if (event.nalUnitType !== "sei_rbsp") return;
			sei = cea708Parser.parseSei(event.escapedRBSP);
			if (!sei.payload) return;
			if (sei.payloadType !== cea708Parser.USER_DATA_REGISTERED_ITU_T_T35) return;
			userData = cea708Parser.parseUserData(sei);
			if (!userData) return;
			if (event.dts < this.latestDts_) {
				this.ignoreNextEqualDts_ = true;
				return;
			} else if (event.dts === this.latestDts_ && this.ignoreNextEqualDts_) {
				this.numSameDts_--;
				if (!this.numSameDts_) this.ignoreNextEqualDts_ = false;
				return;
			}
			newCaptionPackets = cea708Parser.parseCaptionPackets(event.pts, userData);
			this.captionPackets_ = this.captionPackets_.concat(newCaptionPackets);
			if (this.latestDts_ !== event.dts) this.numSameDts_ = 0;
			this.numSameDts_++;
			this.latestDts_ = event.dts;
		};
		CaptionStream.prototype.flushCCStreams = function(flushType) {
			this.ccStreams_.forEach(function(cc) {
				return flushType === "flush" ? cc.flush() : cc.partialFlush();
			}, this);
		};
		CaptionStream.prototype.flushStream = function(flushType) {
			if (!this.captionPackets_.length) {
				this.flushCCStreams(flushType);
				return;
			}
			this.captionPackets_.forEach(function(elem, idx) {
				elem.presortIndex = idx;
			});
			this.captionPackets_.sort(function(a, b) {
				if (a.pts === b.pts) return a.presortIndex - b.presortIndex;
				return a.pts - b.pts;
			});
			this.captionPackets_.forEach(function(packet) {
				if (packet.type < 2) this.dispatchCea608Packet(packet);
				else this.dispatchCea708Packet(packet);
			}, this);
			this.captionPackets_.length = 0;
			this.flushCCStreams(flushType);
		};
		CaptionStream.prototype.flush = function() {
			return this.flushStream("flush");
		};
		CaptionStream.prototype.partialFlush = function() {
			return this.flushStream("partialFlush");
		};
		CaptionStream.prototype.reset = function() {
			this.latestDts_ = null;
			this.ignoreNextEqualDts_ = false;
			this.numSameDts_ = 0;
			this.activeCea608Channel_ = [null, null];
			this.ccStreams_.forEach(function(ccStream) {
				ccStream.reset();
			});
		};
		CaptionStream.prototype.dispatchCea608Packet = function(packet) {
			if (this.setsTextOrXDSActive(packet)) this.activeCea608Channel_[packet.type] = null;
			else if (this.setsChannel1Active(packet)) this.activeCea608Channel_[packet.type] = 0;
			else if (this.setsChannel2Active(packet)) this.activeCea608Channel_[packet.type] = 1;
			if (this.activeCea608Channel_[packet.type] === null) return;
			this.ccStreams_[(packet.type << 1) + this.activeCea608Channel_[packet.type]].push(packet);
		};
		CaptionStream.prototype.setsChannel1Active = function(packet) {
			return (packet.ccData & 30720) === 4096;
		};
		CaptionStream.prototype.setsChannel2Active = function(packet) {
			return (packet.ccData & 30720) === 6144;
		};
		CaptionStream.prototype.setsTextOrXDSActive = function(packet) {
			return (packet.ccData & 28928) === 256 || (packet.ccData & 30974) === 4138 || (packet.ccData & 30974) === 6186;
		};
		CaptionStream.prototype.dispatchCea708Packet = function(packet) {
			if (this.parse708captions_) this.cc708Stream_.push(packet);
		};
		var CHARACTER_TRANSLATION_708 = {
			127: 9834,
			4128: 32,
			4129: 160,
			4133: 8230,
			4138: 352,
			4140: 338,
			4144: 9608,
			4145: 8216,
			4146: 8217,
			4147: 8220,
			4148: 8221,
			4149: 8226,
			4153: 8482,
			4154: 353,
			4156: 339,
			4157: 8480,
			4159: 376,
			4214: 8539,
			4215: 8540,
			4216: 8541,
			4217: 8542,
			4218: 9168,
			4219: 9124,
			4220: 9123,
			4221: 9135,
			4222: 9126,
			4223: 9121,
			4256: 12600
		};
		var get708CharFromCode = function get708CharFromCode(code) {
			var newCode = CHARACTER_TRANSLATION_708[code] || code;
			if (code & 4096 && code === newCode) return "";
			return String.fromCharCode(newCode);
		};
		var within708TextBlock = function within708TextBlock(b) {
			return 32 <= b && b <= 127 || 160 <= b && b <= 255;
		};
		var Cea708Window = function Cea708Window(windowNum) {
			this.windowNum = windowNum;
			this.reset();
		};
		Cea708Window.prototype.reset = function() {
			this.clearText();
			this.pendingNewLine = false;
			this.winAttr = {};
			this.penAttr = {};
			this.penLoc = {};
			this.penColor = {};
			this.visible = 0;
			this.rowLock = 0;
			this.columnLock = 0;
			this.priority = 0;
			this.relativePositioning = 0;
			this.anchorVertical = 0;
			this.anchorHorizontal = 0;
			this.anchorPoint = 0;
			this.rowCount = 1;
			this.virtualRowCount = this.rowCount + 1;
			this.columnCount = 41;
			this.windowStyle = 0;
			this.penStyle = 0;
		};
		Cea708Window.prototype.getText = function() {
			return this.rows.join("\\n");
		};
		Cea708Window.prototype.clearText = function() {
			this.rows = [""];
			this.rowIdx = 0;
		};
		Cea708Window.prototype.newLine = function(pts) {
			if (this.rows.length >= this.virtualRowCount && typeof this.beforeRowOverflow === "function") this.beforeRowOverflow(pts);
			if (this.rows.length > 0) {
				this.rows.push("");
				this.rowIdx++;
			}
			while (this.rows.length > this.virtualRowCount) {
				this.rows.shift();
				this.rowIdx--;
			}
		};
		Cea708Window.prototype.isEmpty = function() {
			if (this.rows.length === 0) return true;
			else if (this.rows.length === 1) return this.rows[0] === "";
			return false;
		};
		Cea708Window.prototype.addText = function(text) {
			this.rows[this.rowIdx] += text;
		};
		Cea708Window.prototype.backspace = function() {
			if (!this.isEmpty()) {
				var row = this.rows[this.rowIdx];
				this.rows[this.rowIdx] = row.substr(0, row.length - 1);
			}
		};
		var Cea708Service = function Cea708Service(serviceNum, encoding, stream) {
			this.serviceNum = serviceNum;
			this.text = "";
			this.currentWindow = new Cea708Window(-1);
			this.windows = [];
			this.stream = stream;
			if (typeof encoding === "string") this.createTextDecoder(encoding);
		};
		/**
		* Initialize service windows
		* Must be run before service use
		*
		* @param  {Integer}  pts               PTS value
		* @param  {Function} beforeRowOverflow Function to execute before row overflow of a window
		*/
		Cea708Service.prototype.init = function(pts, beforeRowOverflow) {
			this.startPts = pts;
			for (var win = 0; win < 8; win++) {
				this.windows[win] = new Cea708Window(win);
				if (typeof beforeRowOverflow === "function") this.windows[win].beforeRowOverflow = beforeRowOverflow;
			}
		};
		/**
		* Set current window of service to be affected by commands
		*
		* @param  {Integer} windowNum Window number
		*/
		Cea708Service.prototype.setCurrentWindow = function(windowNum) {
			this.currentWindow = this.windows[windowNum];
		};
		/**
		* Try to create a TextDecoder if it is natively supported
		*/
		Cea708Service.prototype.createTextDecoder = function(encoding) {
			if (typeof TextDecoder === "undefined") this.stream.trigger("log", {
				level: "warn",
				message: "The \`encoding\` option is unsupported without TextDecoder support"
			});
			else try {
				this.textDecoder_ = new TextDecoder(encoding);
			} catch (error) {
				this.stream.trigger("log", {
					level: "warn",
					message: "TextDecoder could not be created with " + encoding + " encoding. " + error
				});
			}
		};
		var Cea708Stream = function Cea708Stream(options) {
			options = options || {};
			Cea708Stream.prototype.init.call(this);
			var self = this;
			var captionServices = options.captionServices || {};
			var captionServiceEncodings = {};
			var serviceProps;
			Object.keys(captionServices).forEach(function(serviceName) {
				serviceProps = captionServices[serviceName];
				if (/^SERVICE/.test(serviceName)) captionServiceEncodings[serviceName] = serviceProps.encoding;
			});
			this.serviceEncodings = captionServiceEncodings;
			this.current708Packet = null;
			this.services = {};
			this.push = function(packet) {
				if (packet.type === 3) {
					self.new708Packet();
					self.add708Bytes(packet);
				} else {
					if (self.current708Packet === null) self.new708Packet();
					self.add708Bytes(packet);
				}
			};
		};
		Cea708Stream.prototype = new Stream();
		/**
		* Push current 708 packet, create new 708 packet.
		*/
		Cea708Stream.prototype.new708Packet = function() {
			if (this.current708Packet !== null) this.push708Packet();
			this.current708Packet = {
				data: [],
				ptsVals: []
			};
		};
		/**
		* Add pts and both bytes from packet into current 708 packet.
		*/
		Cea708Stream.prototype.add708Bytes = function(packet) {
			var data = packet.ccData;
			var byte0 = data >>> 8;
			var byte1 = data & 255;
			this.current708Packet.ptsVals.push(packet.pts);
			this.current708Packet.data.push(byte0);
			this.current708Packet.data.push(byte1);
		};
		/**
		* Parse completed 708 packet into service blocks and push each service block.
		*/
		Cea708Stream.prototype.push708Packet = function() {
			var packet708 = this.current708Packet;
			var packetData = packet708.data;
			var serviceNum = null;
			var blockSize = null;
			var i = 0;
			var b = packetData[i++];
			packet708.seq = b >> 6;
			packet708.sizeCode = b & 63;
			for (; i < packetData.length; i++) {
				b = packetData[i++];
				serviceNum = b >> 5;
				blockSize = b & 31;
				if (serviceNum === 7 && blockSize > 0) {
					b = packetData[i++];
					serviceNum = b;
				}
				this.pushServiceBlock(serviceNum, i, blockSize);
				if (blockSize > 0) i += blockSize - 1;
			}
		};
		/**
		* Parse service block, execute commands, read text.
		*
		* Note: While many of these commands serve important purposes,
		* many others just parse out the parameters or attributes, but
		* nothing is done with them because this is not a full and complete
		* implementation of the entire 708 spec.
		*
		* @param  {Integer} serviceNum Service number
		* @param  {Integer} start      Start index of the 708 packet data
		* @param  {Integer} size       Block size
		*/
		Cea708Stream.prototype.pushServiceBlock = function(serviceNum, start, size) {
			var b;
			var i = start;
			var packetData = this.current708Packet.data;
			var service = this.services[serviceNum];
			if (!service) service = this.initService(serviceNum, i);
			for (; i < start + size && i < packetData.length; i++) {
				b = packetData[i];
				if (within708TextBlock(b)) i = this.handleText(i, service);
				else if (b === 24) i = this.multiByteCharacter(i, service);
				else if (b === 16) i = this.extendedCommands(i, service);
				else if (128 <= b && b <= 135) i = this.setCurrentWindow(i, service);
				else if (152 <= b && b <= 159) i = this.defineWindow(i, service);
				else if (b === 136) i = this.clearWindows(i, service);
				else if (b === 140) i = this.deleteWindows(i, service);
				else if (b === 137) i = this.displayWindows(i, service);
				else if (b === 138) i = this.hideWindows(i, service);
				else if (b === 139) i = this.toggleWindows(i, service);
				else if (b === 151) i = this.setWindowAttributes(i, service);
				else if (b === 144) i = this.setPenAttributes(i, service);
				else if (b === 145) i = this.setPenColor(i, service);
				else if (b === 146) i = this.setPenLocation(i, service);
				else if (b === 143) service = this.reset(i, service);
				else if (b === 8) service.currentWindow.backspace();
				else if (b === 12) service.currentWindow.clearText();
				else if (b === 13) service.currentWindow.pendingNewLine = true;
				else if (b === 14) service.currentWindow.clearText();
				else if (b === 141) i++;
				else if (b === 142) {} else if (b === 3) {} else if (b === 0) {}
			}
		};
		/**
		* Execute an extended command
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.extendedCommands = function(i, service) {
			var b = this.current708Packet.data[++i];
			if (within708TextBlock(b)) i = this.handleText(i, service, { isExtended: true });
			return i;
		};
		/**
		* Get PTS value of a given byte index
		*
		* @param  {Integer} byteIndex  Index of the byte
		* @return {Integer}            PTS
		*/
		Cea708Stream.prototype.getPts = function(byteIndex) {
			return this.current708Packet.ptsVals[Math.floor(byteIndex / 2)];
		};
		/**
		* Initializes a service
		*
		* @param  {Integer} serviceNum Service number
		* @return {Service}            Initialized service object
		*/
		Cea708Stream.prototype.initService = function(serviceNum, i) {
			var serviceName = "SERVICE" + serviceNum;
			var self = this;
			var serviceName;
			var encoding;
			if (serviceName in this.serviceEncodings) encoding = this.serviceEncodings[serviceName];
			this.services[serviceNum] = new Cea708Service(serviceNum, encoding, self);
			this.services[serviceNum].init(this.getPts(i), function(pts) {
				self.flushDisplayed(pts, self.services[serviceNum]);
			});
			return this.services[serviceNum];
		};
		/**
		* Execute text writing to current window
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.handleText = function(i, service, options) {
			var isExtended = options && options.isExtended;
			var isMultiByte = options && options.isMultiByte;
			var packetData = this.current708Packet.data;
			var extended = isExtended ? 4096 : 0;
			var currentByte = packetData[i];
			var nextByte = packetData[i + 1];
			var win = service.currentWindow;
			var char;
			var charCodeArray;
			if (service.textDecoder_ && !isExtended) {
				if (isMultiByte) {
					charCodeArray = [currentByte, nextByte];
					i++;
				} else charCodeArray = [currentByte];
				char = service.textDecoder_.decode(new Uint8Array(charCodeArray));
			} else char = get708CharFromCode(extended | currentByte);
			if (win.pendingNewLine && !win.isEmpty()) win.newLine(this.getPts(i));
			win.pendingNewLine = false;
			win.addText(char);
			return i;
		};
		/**
		* Handle decoding of multibyte character
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.multiByteCharacter = function(i, service) {
			var packetData = this.current708Packet.data;
			var firstByte = packetData[i + 1];
			var secondByte = packetData[i + 2];
			if (within708TextBlock(firstByte) && within708TextBlock(secondByte)) i = this.handleText(++i, service, { isMultiByte: true });
			return i;
		};
		/**
		* Parse and execute the CW# command.
		*
		* Set the current window.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.setCurrentWindow = function(i, service) {
			var windowNum = this.current708Packet.data[i] & 7;
			service.setCurrentWindow(windowNum);
			return i;
		};
		/**
		* Parse and execute the DF# command.
		*
		* Define a window and set it as the current window.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.defineWindow = function(i, service) {
			var packetData = this.current708Packet.data;
			var b = packetData[i];
			var windowNum = b & 7;
			service.setCurrentWindow(windowNum);
			var win = service.currentWindow;
			b = packetData[++i];
			win.visible = (b & 32) >> 5;
			win.rowLock = (b & 16) >> 4;
			win.columnLock = (b & 8) >> 3;
			win.priority = b & 7;
			b = packetData[++i];
			win.relativePositioning = (b & 128) >> 7;
			win.anchorVertical = b & 127;
			b = packetData[++i];
			win.anchorHorizontal = b;
			b = packetData[++i];
			win.anchorPoint = (b & 240) >> 4;
			win.rowCount = b & 15;
			b = packetData[++i];
			win.columnCount = b & 63;
			b = packetData[++i];
			win.windowStyle = (b & 56) >> 3;
			win.penStyle = b & 7;
			win.virtualRowCount = win.rowCount + 1;
			return i;
		};
		/**
		* Parse and execute the SWA command.
		*
		* Set attributes of the current window.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.setWindowAttributes = function(i, service) {
			var packetData = this.current708Packet.data;
			var b = packetData[i];
			var winAttr = service.currentWindow.winAttr;
			b = packetData[++i];
			winAttr.fillOpacity = (b & 192) >> 6;
			winAttr.fillRed = (b & 48) >> 4;
			winAttr.fillGreen = (b & 12) >> 2;
			winAttr.fillBlue = b & 3;
			b = packetData[++i];
			winAttr.borderType = (b & 192) >> 6;
			winAttr.borderRed = (b & 48) >> 4;
			winAttr.borderGreen = (b & 12) >> 2;
			winAttr.borderBlue = b & 3;
			b = packetData[++i];
			winAttr.borderType += (b & 128) >> 5;
			winAttr.wordWrap = (b & 64) >> 6;
			winAttr.printDirection = (b & 48) >> 4;
			winAttr.scrollDirection = (b & 12) >> 2;
			winAttr.justify = b & 3;
			b = packetData[++i];
			winAttr.effectSpeed = (b & 240) >> 4;
			winAttr.effectDirection = (b & 12) >> 2;
			winAttr.displayEffect = b & 3;
			return i;
		};
		/**
		* Gather text from all displayed windows and push a caption to output.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		*/
		Cea708Stream.prototype.flushDisplayed = function(pts, service) {
			var displayedText = [];
			for (var winId = 0; winId < 8; winId++) if (service.windows[winId].visible && !service.windows[winId].isEmpty()) displayedText.push(service.windows[winId].getText());
			service.endPts = pts;
			service.text = displayedText.join("\\n\\n");
			this.pushCaption(service);
			service.startPts = pts;
		};
		/**
		* Push a caption to output if the caption contains text.
		*
		* @param  {Service} service  The service object to be affected
		*/
		Cea708Stream.prototype.pushCaption = function(service) {
			if (service.text !== "") {
				this.trigger("data", {
					startPts: service.startPts,
					endPts: service.endPts,
					text: service.text,
					stream: "cc708_" + service.serviceNum
				});
				service.text = "";
				service.startPts = service.endPts;
			}
		};
		/**
		* Parse and execute the DSW command.
		*
		* Set visible property of windows based on the parsed bitmask.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.displayWindows = function(i, service) {
			var b = this.current708Packet.data[++i];
			var pts = this.getPts(i);
			this.flushDisplayed(pts, service);
			for (var winId = 0; winId < 8; winId++) if (b & 1 << winId) service.windows[winId].visible = 1;
			return i;
		};
		/**
		* Parse and execute the HDW command.
		*
		* Set visible property of windows based on the parsed bitmask.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.hideWindows = function(i, service) {
			var b = this.current708Packet.data[++i];
			var pts = this.getPts(i);
			this.flushDisplayed(pts, service);
			for (var winId = 0; winId < 8; winId++) if (b & 1 << winId) service.windows[winId].visible = 0;
			return i;
		};
		/**
		* Parse and execute the TGW command.
		*
		* Set visible property of windows based on the parsed bitmask.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.toggleWindows = function(i, service) {
			var b = this.current708Packet.data[++i];
			var pts = this.getPts(i);
			this.flushDisplayed(pts, service);
			for (var winId = 0; winId < 8; winId++) if (b & 1 << winId) service.windows[winId].visible ^= 1;
			return i;
		};
		/**
		* Parse and execute the CLW command.
		*
		* Clear text of windows based on the parsed bitmask.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.clearWindows = function(i, service) {
			var b = this.current708Packet.data[++i];
			var pts = this.getPts(i);
			this.flushDisplayed(pts, service);
			for (var winId = 0; winId < 8; winId++) if (b & 1 << winId) service.windows[winId].clearText();
			return i;
		};
		/**
		* Parse and execute the DLW command.
		*
		* Re-initialize windows based on the parsed bitmask.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.deleteWindows = function(i, service) {
			var b = this.current708Packet.data[++i];
			var pts = this.getPts(i);
			this.flushDisplayed(pts, service);
			for (var winId = 0; winId < 8; winId++) if (b & 1 << winId) service.windows[winId].reset();
			return i;
		};
		/**
		* Parse and execute the SPA command.
		*
		* Set pen attributes of the current window.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.setPenAttributes = function(i, service) {
			var packetData = this.current708Packet.data;
			var b = packetData[i];
			var penAttr = service.currentWindow.penAttr;
			b = packetData[++i];
			penAttr.textTag = (b & 240) >> 4;
			penAttr.offset = (b & 12) >> 2;
			penAttr.penSize = b & 3;
			b = packetData[++i];
			penAttr.italics = (b & 128) >> 7;
			penAttr.underline = (b & 64) >> 6;
			penAttr.edgeType = (b & 56) >> 3;
			penAttr.fontStyle = b & 7;
			return i;
		};
		/**
		* Parse and execute the SPC command.
		*
		* Set pen color of the current window.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.setPenColor = function(i, service) {
			var packetData = this.current708Packet.data;
			var b = packetData[i];
			var penColor = service.currentWindow.penColor;
			b = packetData[++i];
			penColor.fgOpacity = (b & 192) >> 6;
			penColor.fgRed = (b & 48) >> 4;
			penColor.fgGreen = (b & 12) >> 2;
			penColor.fgBlue = b & 3;
			b = packetData[++i];
			penColor.bgOpacity = (b & 192) >> 6;
			penColor.bgRed = (b & 48) >> 4;
			penColor.bgGreen = (b & 12) >> 2;
			penColor.bgBlue = b & 3;
			b = packetData[++i];
			penColor.edgeRed = (b & 48) >> 4;
			penColor.edgeGreen = (b & 12) >> 2;
			penColor.edgeBlue = b & 3;
			return i;
		};
		/**
		* Parse and execute the SPL command.
		*
		* Set pen location of the current window.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Integer}          New index after parsing
		*/
		Cea708Stream.prototype.setPenLocation = function(i, service) {
			var packetData = this.current708Packet.data;
			var b = packetData[i];
			var penLoc = service.currentWindow.penLoc;
			service.currentWindow.pendingNewLine = true;
			b = packetData[++i];
			penLoc.row = b & 15;
			b = packetData[++i];
			penLoc.column = b & 63;
			return i;
		};
		/**
		* Execute the RST command.
		*
		* Reset service to a clean slate. Re-initialize.
		*
		* @param  {Integer} i        Current index in the 708 packet
		* @param  {Service} service  The service object to be affected
		* @return {Service}          Re-initialized service
		*/
		Cea708Stream.prototype.reset = function(i, service) {
			var pts = this.getPts(i);
			this.flushDisplayed(pts, service);
			return this.initService(service.serviceNum, i);
		};
		var CHARACTER_TRANSLATION = {
			42: 225,
			92: 233,
			94: 237,
			95: 243,
			96: 250,
			123: 231,
			124: 247,
			125: 209,
			126: 241,
			127: 9608,
			304: 174,
			305: 176,
			306: 189,
			307: 191,
			308: 8482,
			309: 162,
			310: 163,
			311: 9834,
			312: 224,
			313: 160,
			314: 232,
			315: 226,
			316: 234,
			317: 238,
			318: 244,
			319: 251,
			544: 193,
			545: 201,
			546: 211,
			547: 218,
			548: 220,
			549: 252,
			550: 8216,
			551: 161,
			552: 42,
			553: 39,
			554: 8212,
			555: 169,
			556: 8480,
			557: 8226,
			558: 8220,
			559: 8221,
			560: 192,
			561: 194,
			562: 199,
			563: 200,
			564: 202,
			565: 203,
			566: 235,
			567: 206,
			568: 207,
			569: 239,
			570: 212,
			571: 217,
			572: 249,
			573: 219,
			574: 171,
			575: 187,
			800: 195,
			801: 227,
			802: 205,
			803: 204,
			804: 236,
			805: 210,
			806: 242,
			807: 213,
			808: 245,
			809: 123,
			810: 125,
			811: 92,
			812: 94,
			813: 95,
			814: 124,
			815: 126,
			816: 196,
			817: 228,
			818: 214,
			819: 246,
			820: 223,
			821: 165,
			822: 164,
			823: 9474,
			824: 197,
			825: 229,
			826: 216,
			827: 248,
			828: 9484,
			829: 9488,
			830: 9492,
			831: 9496
		};
		var getCharFromCode = function getCharFromCode(code) {
			if (code === null) return "";
			code = CHARACTER_TRANSLATION[code] || code;
			return String.fromCharCode(code);
		};
		var BOTTOM_ROW = 14;
		var ROWS = [
			4352,
			4384,
			4608,
			4640,
			5376,
			5408,
			5632,
			5664,
			5888,
			5920,
			4096,
			4864,
			4896,
			5120,
			5152
		];
		var createDisplayBuffer = function createDisplayBuffer() {
			var result = [], i = BOTTOM_ROW + 1;
			while (i--) result.push("");
			return result;
		};
		var Cea608Stream = function Cea608Stream(field, dataChannel) {
			Cea608Stream.prototype.init.call(this);
			this.field_ = field || 0;
			this.dataChannel_ = dataChannel || 0;
			this.name_ = "CC" + ((this.field_ << 1 | this.dataChannel_) + 1);
			this.setConstants();
			this.reset();
			this.push = function(packet) {
				var data = packet.ccData & 32639, swap, char0, char1, text;
				if (data === this.lastControlCode_) {
					this.lastControlCode_ = null;
					return;
				}
				if ((data & 61440) === 4096) this.lastControlCode_ = data;
				else if (data !== this.PADDING_) this.lastControlCode_ = null;
				char0 = data >>> 8;
				char1 = data & 255;
				if (data === this.PADDING_) return;
				else if (data === this.RESUME_CAPTION_LOADING_) this.mode_ = "popOn";
				else if (data === this.END_OF_CAPTION_) {
					this.mode_ = "popOn";
					this.clearFormatting(packet.pts);
					this.flushDisplayed(packet.pts);
					swap = this.displayed_;
					this.displayed_ = this.nonDisplayed_;
					this.nonDisplayed_ = swap;
					this.startPts_ = packet.pts;
				} else if (data === this.ROLL_UP_2_ROWS_) {
					this.rollUpRows_ = 2;
					this.setRollUp(packet.pts);
				} else if (data === this.ROLL_UP_3_ROWS_) {
					this.rollUpRows_ = 3;
					this.setRollUp(packet.pts);
				} else if (data === this.ROLL_UP_4_ROWS_) {
					this.rollUpRows_ = 4;
					this.setRollUp(packet.pts);
				} else if (data === this.CARRIAGE_RETURN_) {
					this.clearFormatting(packet.pts);
					this.flushDisplayed(packet.pts);
					this.shiftRowsUp_();
					this.startPts_ = packet.pts;
				} else if (data === this.BACKSPACE_) if (this.mode_ === "popOn") this.nonDisplayed_[this.row_] = this.nonDisplayed_[this.row_].slice(0, -1);
				else this.displayed_[this.row_] = this.displayed_[this.row_].slice(0, -1);
				else if (data === this.ERASE_DISPLAYED_MEMORY_) {
					this.flushDisplayed(packet.pts);
					this.displayed_ = createDisplayBuffer();
				} else if (data === this.ERASE_NON_DISPLAYED_MEMORY_) this.nonDisplayed_ = createDisplayBuffer();
				else if (data === this.RESUME_DIRECT_CAPTIONING_) {
					if (this.mode_ !== "paintOn") {
						this.flushDisplayed(packet.pts);
						this.displayed_ = createDisplayBuffer();
					}
					this.mode_ = "paintOn";
					this.startPts_ = packet.pts;
				} else if (this.isSpecialCharacter(char0, char1)) {
					char0 = (char0 & 3) << 8;
					text = getCharFromCode(char0 | char1);
					this[this.mode_](packet.pts, text);
					this.column_++;
				} else if (this.isExtCharacter(char0, char1)) {
					if (this.mode_ === "popOn") this.nonDisplayed_[this.row_] = this.nonDisplayed_[this.row_].slice(0, -1);
					else this.displayed_[this.row_] = this.displayed_[this.row_].slice(0, -1);
					char0 = (char0 & 3) << 8;
					text = getCharFromCode(char0 | char1);
					this[this.mode_](packet.pts, text);
					this.column_++;
				} else if (this.isMidRowCode(char0, char1)) {
					this.clearFormatting(packet.pts);
					this[this.mode_](packet.pts, " ");
					this.column_++;
					if ((char1 & 14) === 14) this.addFormatting(packet.pts, ["i"]);
					if ((char1 & 1) === 1) this.addFormatting(packet.pts, ["u"]);
				} else if (this.isOffsetControlCode(char0, char1)) this.column_ += char1 & 3;
				else if (this.isPAC(char0, char1)) {
					var row = ROWS.indexOf(data & 7968);
					if (this.mode_ === "rollUp") {
						if (row - this.rollUpRows_ + 1 < 0) row = this.rollUpRows_ - 1;
						this.setRollUp(packet.pts, row);
					}
					if (row !== this.row_) {
						this.clearFormatting(packet.pts);
						this.row_ = row;
					}
					if (char1 & 1 && this.formatting_.indexOf("u") === -1) this.addFormatting(packet.pts, ["u"]);
					if ((data & 16) === 16) this.column_ = ((data & 14) >> 1) * 4;
					if (this.isColorPAC(char1)) {
						if ((char1 & 14) === 14) this.addFormatting(packet.pts, ["i"]);
					}
				} else if (this.isNormalChar(char0)) {
					if (char1 === 0) char1 = null;
					text = getCharFromCode(char0);
					text += getCharFromCode(char1);
					this[this.mode_](packet.pts, text);
					this.column_ += text.length;
				}
			};
		};
		Cea608Stream.prototype = new Stream();
		Cea608Stream.prototype.flushDisplayed = function(pts) {
			var content = this.displayed_.map(function(row, index) {
				try {
					return row.trim();
				} catch (e) {
					this.trigger("log", {
						level: "warn",
						message: "Skipping a malformed 608 caption at index " + index + "."
					});
					return "";
				}
			}, this).join("\\n").replace(/^\\n+|\\n+$/g, "");
			if (content.length) this.trigger("data", {
				startPts: this.startPts_,
				endPts: pts,
				text: content,
				stream: this.name_
			});
		};
		/**
		* Zero out the data, used for startup and on seek
		*/
		Cea608Stream.prototype.reset = function() {
			this.mode_ = "popOn";
			this.topRow_ = 0;
			this.startPts_ = 0;
			this.displayed_ = createDisplayBuffer();
			this.nonDisplayed_ = createDisplayBuffer();
			this.lastControlCode_ = null;
			this.column_ = 0;
			this.row_ = BOTTOM_ROW;
			this.rollUpRows_ = 2;
			this.formatting_ = [];
		};
		/**
		* Sets up control code and related constants for this instance
		*/
		Cea608Stream.prototype.setConstants = function() {
			if (this.dataChannel_ === 0) {
				this.BASE_ = 16;
				this.EXT_ = 17;
				this.CONTROL_ = (20 | this.field_) << 8;
				this.OFFSET_ = 23;
			} else if (this.dataChannel_ === 1) {
				this.BASE_ = 24;
				this.EXT_ = 25;
				this.CONTROL_ = (28 | this.field_) << 8;
				this.OFFSET_ = 31;
			}
			this.PADDING_ = 0;
			this.RESUME_CAPTION_LOADING_ = this.CONTROL_ | 32;
			this.END_OF_CAPTION_ = this.CONTROL_ | 47;
			this.ROLL_UP_2_ROWS_ = this.CONTROL_ | 37;
			this.ROLL_UP_3_ROWS_ = this.CONTROL_ | 38;
			this.ROLL_UP_4_ROWS_ = this.CONTROL_ | 39;
			this.CARRIAGE_RETURN_ = this.CONTROL_ | 45;
			this.RESUME_DIRECT_CAPTIONING_ = this.CONTROL_ | 41;
			this.BACKSPACE_ = this.CONTROL_ | 33;
			this.ERASE_DISPLAYED_MEMORY_ = this.CONTROL_ | 44;
			this.ERASE_NON_DISPLAYED_MEMORY_ = this.CONTROL_ | 46;
		};
		/**
		* Detects if the 2-byte packet data is a special character
		*
		* Special characters have a second byte in the range 0x30 to 0x3f,
		* with the first byte being 0x11 (for data channel 1) or 0x19 (for
		* data channel 2).
		*
		* @param  {Integer} char0 The first byte
		* @param  {Integer} char1 The second byte
		* @return {Boolean}       Whether the 2 bytes are an special character
		*/
		Cea608Stream.prototype.isSpecialCharacter = function(char0, char1) {
			return char0 === this.EXT_ && char1 >= 48 && char1 <= 63;
		};
		/**
		* Detects if the 2-byte packet data is an extended character
		*
		* Extended characters have a second byte in the range 0x20 to 0x3f,
		* with the first byte being 0x12 or 0x13 (for data channel 1) or
		* 0x1a or 0x1b (for data channel 2).
		*
		* @param  {Integer} char0 The first byte
		* @param  {Integer} char1 The second byte
		* @return {Boolean}       Whether the 2 bytes are an extended character
		*/
		Cea608Stream.prototype.isExtCharacter = function(char0, char1) {
			return (char0 === this.EXT_ + 1 || char0 === this.EXT_ + 2) && char1 >= 32 && char1 <= 63;
		};
		/**
		* Detects if the 2-byte packet is a mid-row code
		*
		* Mid-row codes have a second byte in the range 0x20 to 0x2f, with
		* the first byte being 0x11 (for data channel 1) or 0x19 (for data
		* channel 2).
		*
		* @param  {Integer} char0 The first byte
		* @param  {Integer} char1 The second byte
		* @return {Boolean}       Whether the 2 bytes are a mid-row code
		*/
		Cea608Stream.prototype.isMidRowCode = function(char0, char1) {
			return char0 === this.EXT_ && char1 >= 32 && char1 <= 47;
		};
		/**
		* Detects if the 2-byte packet is an offset control code
		*
		* Offset control codes have a second byte in the range 0x21 to 0x23,
		* with the first byte being 0x17 (for data channel 1) or 0x1f (for
		* data channel 2).
		*
		* @param  {Integer} char0 The first byte
		* @param  {Integer} char1 The second byte
		* @return {Boolean}       Whether the 2 bytes are an offset control code
		*/
		Cea608Stream.prototype.isOffsetControlCode = function(char0, char1) {
			return char0 === this.OFFSET_ && char1 >= 33 && char1 <= 35;
		};
		/**
		* Detects if the 2-byte packet is a Preamble Address Code
		*
		* PACs have a first byte in the range 0x10 to 0x17 (for data channel 1)
		* or 0x18 to 0x1f (for data channel 2), with the second byte in the
		* range 0x40 to 0x7f.
		*
		* @param  {Integer} char0 The first byte
		* @param  {Integer} char1 The second byte
		* @return {Boolean}       Whether the 2 bytes are a PAC
		*/
		Cea608Stream.prototype.isPAC = function(char0, char1) {
			return char0 >= this.BASE_ && char0 < this.BASE_ + 8 && char1 >= 64 && char1 <= 127;
		};
		/**
		* Detects if a packet's second byte is in the range of a PAC color code
		*
		* PAC color codes have the second byte be in the range 0x40 to 0x4f, or
		* 0x60 to 0x6f.
		*
		* @param  {Integer} char1 The second byte
		* @return {Boolean}       Whether the byte is a color PAC
		*/
		Cea608Stream.prototype.isColorPAC = function(char1) {
			return char1 >= 64 && char1 <= 79 || char1 >= 96 && char1 <= 127;
		};
		/**
		* Detects if a single byte is in the range of a normal character
		*
		* Normal text bytes are in the range 0x20 to 0x7f.
		*
		* @param  {Integer} char  The byte
		* @return {Boolean}       Whether the byte is a normal character
		*/
		Cea608Stream.prototype.isNormalChar = function(char) {
			return char >= 32 && char <= 127;
		};
		/**
		* Configures roll-up
		*
		* @param  {Integer} pts         Current PTS
		* @param  {Integer} newBaseRow  Used by PACs to slide the current window to
		*                               a new position
		*/
		Cea608Stream.prototype.setRollUp = function(pts, newBaseRow) {
			if (this.mode_ !== "rollUp") {
				this.row_ = BOTTOM_ROW;
				this.mode_ = "rollUp";
				this.flushDisplayed(pts);
				this.nonDisplayed_ = createDisplayBuffer();
				this.displayed_ = createDisplayBuffer();
			}
			if (newBaseRow !== void 0 && newBaseRow !== this.row_) for (var i = 0; i < this.rollUpRows_; i++) {
				this.displayed_[newBaseRow - i] = this.displayed_[this.row_ - i];
				this.displayed_[this.row_ - i] = "";
			}
			if (newBaseRow === void 0) newBaseRow = this.row_;
			this.topRow_ = newBaseRow - this.rollUpRows_ + 1;
		};
		Cea608Stream.prototype.addFormatting = function(pts, format) {
			this.formatting_ = this.formatting_.concat(format);
			var text = format.reduce(function(text, format) {
				return text + "<" + format + ">";
			}, "");
			this[this.mode_](pts, text);
		};
		Cea608Stream.prototype.clearFormatting = function(pts) {
			if (!this.formatting_.length) return;
			var text = this.formatting_.reverse().reduce(function(text, format) {
				return text + "</" + format + ">";
			}, "");
			this.formatting_ = [];
			this[this.mode_](pts, text);
		};
		Cea608Stream.prototype.popOn = function(pts, text) {
			var baseRow = this.nonDisplayed_[this.row_];
			baseRow += text;
			this.nonDisplayed_[this.row_] = baseRow;
		};
		Cea608Stream.prototype.rollUp = function(pts, text) {
			var baseRow = this.displayed_[this.row_];
			baseRow += text;
			this.displayed_[this.row_] = baseRow;
		};
		Cea608Stream.prototype.shiftRowsUp_ = function() {
			var i;
			for (i = 0; i < this.topRow_; i++) this.displayed_[i] = "";
			for (i = this.row_ + 1; i < BOTTOM_ROW + 1; i++) this.displayed_[i] = "";
			for (i = this.topRow_; i < this.row_; i++) this.displayed_[i] = this.displayed_[i + 1];
			this.displayed_[this.row_] = "";
		};
		Cea608Stream.prototype.paintOn = function(pts, text) {
			var baseRow = this.displayed_[this.row_];
			baseRow += text;
			this.displayed_[this.row_] = baseRow;
		};
		module.exports = {
			CaptionStream,
			Cea608Stream,
			Cea708Stream
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/m2ts/stream-types.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*/
	var require_stream_types = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		module.exports = {
			H264_STREAM_TYPE: 27,
			ADTS_STREAM_TYPE: 15,
			METADATA_STREAM_TYPE: 21
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/m2ts/timestamp-rollover-stream.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* Accepts program elementary stream (PES) data events and corrects
	* decode and presentation time stamps to account for a rollover
	* of the 33 bit value.
	*/
	var require_timestamp_rollover_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = require_stream();
		var MAX_TS = 8589934592;
		var RO_THRESH = 4294967296;
		var TYPE_SHARED = "shared";
		var handleRollover = function handleRollover(value, reference) {
			var direction = 1;
			if (value > reference) direction = -1;
			while (Math.abs(reference - value) > RO_THRESH) value += direction * MAX_TS;
			return value;
		};
		var TimestampRolloverStream = function TimestampRolloverStream(type) {
			var lastDTS, referenceDTS;
			TimestampRolloverStream.prototype.init.call(this);
			this.type_ = type || TYPE_SHARED;
			this.push = function(data) {
				if (this.type_ !== TYPE_SHARED && data.type !== this.type_) return;
				if (referenceDTS === void 0) referenceDTS = data.dts;
				data.dts = handleRollover(data.dts, referenceDTS);
				data.pts = handleRollover(data.pts, referenceDTS);
				lastDTS = data.dts;
				this.trigger("data", data);
			};
			this.flush = function() {
				referenceDTS = lastDTS;
				this.trigger("done");
			};
			this.endTimeline = function() {
				this.flush();
				this.trigger("endedtimeline");
			};
			this.discontinuity = function() {
				referenceDTS = void 0;
				lastDTS = void 0;
			};
			this.reset = function() {
				this.discontinuity();
				this.trigger("reset");
			};
		};
		TimestampRolloverStream.prototype = new Stream();
		module.exports = {
			TimestampRolloverStream,
			handleRollover
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/utils/typed-array.js
	var require_typed_array = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		module.exports = { typedArrayIndexOf: function typedArrayIndexOf(typedArray, element, fromIndex) {
			if (!typedArray) return -1;
			var currentIndex = fromIndex;
			for (; currentIndex < typedArray.length; currentIndex++) if (typedArray[currentIndex] === element) return currentIndex;
			return -1;
		} };
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/tools/parse-id3.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* Tools for parsing ID3 frame data
	* @see http://id3.org/id3v2.3.0
	*/
	var require_parse_id3 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var typedArrayIndexOf = require_typed_array().typedArrayIndexOf;
		var textEncodingDescriptionByte = {
			Iso88591: 0,
			Utf16: 1,
			Utf16be: 2,
			Utf8: 3
		};
		var percentEncode = function percentEncode(bytes, start, end) {
			var i, result = "";
			for (i = start; i < end; i++) result += "%" + ("00" + bytes[i].toString(16)).slice(-2);
			return result;
		};
		var parseUtf8 = function parseUtf8(bytes, start, end) {
			return decodeURIComponent(percentEncode(bytes, start, end));
		};
		var parseIso88591 = function parseIso88591(bytes, start, end) {
			return unescape(percentEncode(bytes, start, end));
		};
		var parseSyncSafeInteger = function parseSyncSafeInteger(data) {
			return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
		};
		var frameParsers = {
			"APIC": function APIC(frame) {
				var i = 1, mimeTypeEndIndex, descriptionEndIndex, LINK_MIME_TYPE = "-->";
				if (frame.data[0] !== textEncodingDescriptionByte.Utf8) return;
				mimeTypeEndIndex = typedArrayIndexOf(frame.data, 0, i);
				if (mimeTypeEndIndex < 0) return;
				frame.mimeType = parseIso88591(frame.data, i, mimeTypeEndIndex);
				i = mimeTypeEndIndex + 1;
				frame.pictureType = frame.data[i];
				i++;
				descriptionEndIndex = typedArrayIndexOf(frame.data, 0, i);
				if (descriptionEndIndex < 0) return;
				frame.description = parseUtf8(frame.data, i, descriptionEndIndex);
				i = descriptionEndIndex + 1;
				if (frame.mimeType === LINK_MIME_TYPE) frame.url = parseIso88591(frame.data, i, frame.data.length);
				else frame.pictureData = frame.data.subarray(i, frame.data.length);
			},
			"T*": function T(frame) {
				if (frame.data[0] !== textEncodingDescriptionByte.Utf8) return;
				frame.value = parseUtf8(frame.data, 1, frame.data.length).replace(/\\0*$/, "");
				frame.values = frame.value.split("\\0");
			},
			"TXXX": function TXXX(frame) {
				var descriptionEndIndex;
				if (frame.data[0] !== textEncodingDescriptionByte.Utf8) return;
				descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);
				if (descriptionEndIndex === -1) return;
				frame.description = parseUtf8(frame.data, 1, descriptionEndIndex);
				frame.value = parseUtf8(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\\0*$/, "");
				frame.data = frame.value;
			},
			"W*": function W(frame) {
				frame.url = parseIso88591(frame.data, 0, frame.data.length).replace(/\\0.*$/, "");
			},
			"WXXX": function WXXX(frame) {
				var descriptionEndIndex;
				if (frame.data[0] !== textEncodingDescriptionByte.Utf8) return;
				descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);
				if (descriptionEndIndex === -1) return;
				frame.description = parseUtf8(frame.data, 1, descriptionEndIndex);
				frame.url = parseIso88591(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\\0.*$/, "");
			},
			"PRIV": function PRIV(frame) {
				var i;
				for (i = 0; i < frame.data.length; i++) if (frame.data[i] === 0) {
					frame.owner = parseIso88591(frame.data, 0, i);
					break;
				}
				frame.privateData = frame.data.subarray(i + 1);
				frame.data = frame.privateData;
			}
		};
		module.exports = {
			parseId3Frames: function parseId3Frames(data) {
				var frameSize, frameHeader, frameStart = 10, tagSize = 0, frames = [];
				if (data.length < 10 || data[0] !== "I".charCodeAt(0) || data[1] !== "D".charCodeAt(0) || data[2] !== "3".charCodeAt(0)) return;
				tagSize = parseSyncSafeInteger(data.subarray(6, 10));
				tagSize += 10;
				if (data[5] & 64) {
					frameStart += 4;
					frameStart += parseSyncSafeInteger(data.subarray(10, 14));
					tagSize -= parseSyncSafeInteger(data.subarray(16, 20));
				}
				do {
					frameSize = parseSyncSafeInteger(data.subarray(frameStart + 4, frameStart + 8));
					if (frameSize < 1) break;
					frameHeader = String.fromCharCode(data[frameStart], data[frameStart + 1], data[frameStart + 2], data[frameStart + 3]);
					var frame = {
						id: frameHeader,
						data: data.subarray(frameStart + 10, frameStart + frameSize + 10)
					};
					frame.key = frame.id;
					if (frameParsers[frame.id]) frameParsers[frame.id](frame);
					else if (frame.id[0] === "T") frameParsers["T*"](frame);
					else if (frame.id[0] === "W") frameParsers["W*"](frame);
					frames.push(frame);
					frameStart += 10;
					frameStart += frameSize;
				} while (frameStart < tagSize);
				return frames;
			},
			parseSyncSafeInteger,
			frameParsers
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/m2ts/metadata-stream.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* Accepts program elementary stream (PES) data events and parses out
	* ID3 metadata from them, if present.
	* @see http://id3.org/id3v2.3.0
	*/
	var require_metadata_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = require_stream();
		var StreamTypes = require_stream_types();
		var id3 = require_parse_id3();
		var _MetadataStream = function MetadataStream(options) {
			var settings = { descriptor: options && options.descriptor }, tagSize = 0, buffer = [], bufferSize = 0, i;
			_MetadataStream.prototype.init.call(this);
			this.dispatchType = StreamTypes.METADATA_STREAM_TYPE.toString(16);
			if (settings.descriptor) for (i = 0; i < settings.descriptor.length; i++) this.dispatchType += ("00" + settings.descriptor[i].toString(16)).slice(-2);
			this.push = function(chunk) {
				var tag, frameStart, frameSize, frame, i, frameHeader;
				if (chunk.type !== "timed-metadata") return;
				if (chunk.dataAlignmentIndicator) {
					bufferSize = 0;
					buffer.length = 0;
				}
				if (buffer.length === 0 && (chunk.data.length < 10 || chunk.data[0] !== "I".charCodeAt(0) || chunk.data[1] !== "D".charCodeAt(0) || chunk.data[2] !== "3".charCodeAt(0))) {
					this.trigger("log", {
						level: "warn",
						message: "Skipping unrecognized metadata packet"
					});
					return;
				}
				buffer.push(chunk);
				bufferSize += chunk.data.byteLength;
				if (buffer.length === 1) {
					tagSize = id3.parseSyncSafeInteger(chunk.data.subarray(6, 10));
					tagSize += 10;
				}
				if (bufferSize < tagSize) return;
				tag = {
					data: new Uint8Array(tagSize),
					frames: [],
					pts: buffer[0].pts,
					dts: buffer[0].dts
				};
				for (i = 0; i < tagSize;) {
					tag.data.set(buffer[0].data.subarray(0, tagSize - i), i);
					i += buffer[0].data.byteLength;
					bufferSize -= buffer[0].data.byteLength;
					buffer.shift();
				}
				frameStart = 10;
				if (tag.data[5] & 64) {
					frameStart += 4;
					frameStart += id3.parseSyncSafeInteger(tag.data.subarray(10, 14));
					tagSize -= id3.parseSyncSafeInteger(tag.data.subarray(16, 20));
				}
				do {
					frameSize = id3.parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
					if (frameSize < 1) {
						this.trigger("log", {
							level: "warn",
							message: "Malformed ID3 frame encountered. Skipping remaining metadata parsing."
						});
						break;
					}
					frameHeader = String.fromCharCode(tag.data[frameStart], tag.data[frameStart + 1], tag.data[frameStart + 2], tag.data[frameStart + 3]);
					frame = {
						id: frameHeader,
						data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
					};
					frame.key = frame.id;
					if (id3.frameParsers[frame.id]) id3.frameParsers[frame.id](frame);
					else if (frame.id[0] === "T") id3.frameParsers["T*"](frame);
					else if (frame.id[0] === "W") id3.frameParsers["W*"](frame);
					if (frame.owner === "com.apple.streaming.transportStreamTimestamp") {
						var d = frame.data, size = (d[3] & 1) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
						size *= 4;
						size += d[7] & 3;
						frame.timeStamp = size;
						if (tag.pts === void 0 && tag.dts === void 0) {
							tag.pts = frame.timeStamp;
							tag.dts = frame.timeStamp;
						}
						this.trigger("timestamp", frame);
					}
					tag.frames.push(frame);
					frameStart += 10;
					frameStart += frameSize;
				} while (frameStart < tagSize);
				this.trigger("data", tag);
			};
		};
		_MetadataStream.prototype = new Stream();
		module.exports = _MetadataStream;
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/m2ts/m2ts.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* A stream-based mp2t to mp4 converter. This utility can be used to
	* deliver mp4s to a SourceBuffer on platforms that support native
	* Media Source Extensions.
	*/
	var require_m2ts = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = require_stream();
		var CaptionStream = require_caption_stream();
		var StreamTypes = require_stream_types();
		var TimestampRolloverStream = require_timestamp_rollover_stream().TimestampRolloverStream;
		var _TransportPacketStream;
		var _TransportParseStream;
		var _ElementaryStream;
		var MP2T_PACKET_LENGTH = 188;
		var SYNC_BYTE = 71;
		/**
		* Splits an incoming stream of binary data into MPEG-2 Transport
		* Stream packets.
		*/
		_TransportPacketStream = function TransportPacketStream() {
			var buffer = new Uint8Array(MP2T_PACKET_LENGTH), bytesInBuffer = 0;
			_TransportPacketStream.prototype.init.call(this);
			/**
			* Split a stream of data into M2TS packets
			**/
			this.push = function(bytes) {
				var startIndex = 0, endIndex = MP2T_PACKET_LENGTH, everything;
				if (bytesInBuffer) {
					everything = new Uint8Array(bytes.byteLength + bytesInBuffer);
					everything.set(buffer.subarray(0, bytesInBuffer));
					everything.set(bytes, bytesInBuffer);
					bytesInBuffer = 0;
				} else everything = bytes;
				while (endIndex < everything.byteLength) {
					if (everything[startIndex] === SYNC_BYTE && everything[endIndex] === SYNC_BYTE) {
						this.trigger("data", everything.subarray(startIndex, endIndex));
						startIndex += MP2T_PACKET_LENGTH;
						endIndex += MP2T_PACKET_LENGTH;
						continue;
					}
					startIndex++;
					endIndex++;
				}
				if (startIndex < everything.byteLength) {
					buffer.set(everything.subarray(startIndex), 0);
					bytesInBuffer = everything.byteLength - startIndex;
				}
			};
			/**
			* Passes identified M2TS packets to the TransportParseStream to be parsed
			**/
			this.flush = function() {
				if (bytesInBuffer === MP2T_PACKET_LENGTH && buffer[0] === SYNC_BYTE) {
					this.trigger("data", buffer);
					bytesInBuffer = 0;
				}
				this.trigger("done");
			};
			this.endTimeline = function() {
				this.flush();
				this.trigger("endedtimeline");
			};
			this.reset = function() {
				bytesInBuffer = 0;
				this.trigger("reset");
			};
		};
		_TransportPacketStream.prototype = new Stream();
		/**
		* Accepts an MP2T TransportPacketStream and emits data events with parsed
		* forms of the individual transport stream packets.
		*/
		_TransportParseStream = function TransportParseStream() {
			var parsePsi, parsePat, parsePmt, self;
			_TransportParseStream.prototype.init.call(this);
			self = this;
			this.packetsWaitingForPmt = [];
			this.programMapTable = void 0;
			parsePsi = function parsePsi(payload, psi) {
				var offset = 0;
				if (psi.payloadUnitStartIndicator) offset += payload[offset] + 1;
				if (psi.type === "pat") parsePat(payload.subarray(offset), psi);
				else parsePmt(payload.subarray(offset), psi);
			};
			parsePat = function parsePat(payload, pat) {
				pat.section_number = payload[7];
				pat.last_section_number = payload[8];
				self.pmtPid = (payload[10] & 31) << 8 | payload[11];
				pat.pmtPid = self.pmtPid;
			};
			/**
			* Parse out the relevant fields of a Program Map Table (PMT).
			* @param payload {Uint8Array} the PMT-specific portion of an MP2T
			* packet. The first byte in this array should be the table_id
			* field.
			* @param pmt {object} the object that should be decorated with
			* fields parsed from the PMT.
			*/
			parsePmt = function parsePmt(payload, pmt) {
				var sectionLength, tableEnd, programInfoLength, offset;
				if (!(payload[5] & 1)) return;
				self.programMapTable = {
					video: null,
					audio: null,
					"timed-metadata": {}
				};
				sectionLength = (payload[1] & 15) << 8 | payload[2];
				tableEnd = 3 + sectionLength - 4;
				programInfoLength = (payload[10] & 15) << 8 | payload[11];
				offset = 12 + programInfoLength;
				while (offset < tableEnd) {
					var streamType = payload[offset];
					var pid = (payload[offset + 1] & 31) << 8 | payload[offset + 2];
					if (streamType === StreamTypes.H264_STREAM_TYPE && self.programMapTable.video === null) self.programMapTable.video = pid;
					else if (streamType === StreamTypes.ADTS_STREAM_TYPE && self.programMapTable.audio === null) self.programMapTable.audio = pid;
					else if (streamType === StreamTypes.METADATA_STREAM_TYPE) self.programMapTable["timed-metadata"][pid] = streamType;
					offset += ((payload[offset + 3] & 15) << 8 | payload[offset + 4]) + 5;
				}
				pmt.programMapTable = self.programMapTable;
			};
			/**
			* Deliver a new MP2T packet to the next stream in the pipeline.
			*/
			this.push = function(packet) {
				var result = {}, offset = 4;
				result.payloadUnitStartIndicator = !!(packet[1] & 64);
				result.pid = packet[1] & 31;
				result.pid <<= 8;
				result.pid |= packet[2];
				if ((packet[3] & 48) >>> 4 > 1) offset += packet[offset] + 1;
				if (result.pid === 0) {
					result.type = "pat";
					parsePsi(packet.subarray(offset), result);
					this.trigger("data", result);
				} else if (result.pid === this.pmtPid) {
					result.type = "pmt";
					parsePsi(packet.subarray(offset), result);
					this.trigger("data", result);
					while (this.packetsWaitingForPmt.length) this.processPes_.apply(this, this.packetsWaitingForPmt.shift());
				} else if (this.programMapTable === void 0) this.packetsWaitingForPmt.push([
					packet,
					offset,
					result
				]);
				else this.processPes_(packet, offset, result);
			};
			this.processPes_ = function(packet, offset, result) {
				if (result.pid === this.programMapTable.video) result.streamType = StreamTypes.H264_STREAM_TYPE;
				else if (result.pid === this.programMapTable.audio) result.streamType = StreamTypes.ADTS_STREAM_TYPE;
				else result.streamType = this.programMapTable["timed-metadata"][result.pid];
				result.type = "pes";
				result.data = packet.subarray(offset);
				this.trigger("data", result);
			};
		};
		_TransportParseStream.prototype = new Stream();
		_TransportParseStream.STREAM_TYPES = {
			h264: 27,
			adts: 15
		};
		/**
		* Reconsistutes program elementary stream (PES) packets from parsed
		* transport stream packets. That is, if you pipe an
		* mp2t.TransportParseStream into a mp2t.ElementaryStream, the output
		* events will be events which capture the bytes for individual PES
		* packets plus relevant metadata that has been extracted from the
		* container.
		*/
		_ElementaryStream = function ElementaryStream() {
			var self = this, segmentHadPmt = false, video = {
				data: [],
				size: 0
			}, audio = {
				data: [],
				size: 0
			}, timedMetadata = {
				data: [],
				size: 0
			}, programMapTable, parsePes = function parsePes(payload, pes) {
				var ptsDtsFlags;
				var startPrefix = payload[0] << 16 | payload[1] << 8 | payload[2];
				pes.data = /* @__PURE__ */ new Uint8Array();
				if (startPrefix !== 1) return;
				pes.packetLength = 6 + (payload[4] << 8 | payload[5]);
				pes.dataAlignmentIndicator = (payload[6] & 4) !== 0;
				ptsDtsFlags = payload[7];
				if (ptsDtsFlags & 192) {
					pes.pts = (payload[9] & 14) << 27 | (payload[10] & 255) << 20 | (payload[11] & 254) << 12 | (payload[12] & 255) << 5 | (payload[13] & 254) >>> 3;
					pes.pts *= 4;
					pes.pts += (payload[13] & 6) >>> 1;
					pes.dts = pes.pts;
					if (ptsDtsFlags & 64) {
						pes.dts = (payload[14] & 14) << 27 | (payload[15] & 255) << 20 | (payload[16] & 254) << 12 | (payload[17] & 255) << 5 | (payload[18] & 254) >>> 3;
						pes.dts *= 4;
						pes.dts += (payload[18] & 6) >>> 1;
					}
				}
				pes.data = payload.subarray(9 + payload[8]);
			}, flushStream = function flushStream(stream, type, forceFlush) {
				var packetData = new Uint8Array(stream.size), event = { type }, i = 0, offset = 0, packetFlushable = false, fragment;
				if (!stream.data.length || stream.size < 9) return;
				event.trackId = stream.data[0].pid;
				for (i = 0; i < stream.data.length; i++) {
					fragment = stream.data[i];
					packetData.set(fragment.data, offset);
					offset += fragment.data.byteLength;
				}
				parsePes(packetData, event);
				packetFlushable = type === "video" || event.packetLength <= stream.size;
				if (forceFlush || packetFlushable) {
					stream.size = 0;
					stream.data.length = 0;
				}
				if (packetFlushable) self.trigger("data", event);
			};
			_ElementaryStream.prototype.init.call(this);
			/**
			* Identifies M2TS packet types and parses PES packets using metadata
			* parsed from the PMT
			**/
			this.push = function(data) {
				({
					pat: function pat() {},
					pes: function pes() {
						var stream, streamType;
						switch (data.streamType) {
							case StreamTypes.H264_STREAM_TYPE:
								stream = video;
								streamType = "video";
								break;
							case StreamTypes.ADTS_STREAM_TYPE:
								stream = audio;
								streamType = "audio";
								break;
							case StreamTypes.METADATA_STREAM_TYPE:
								stream = timedMetadata;
								streamType = "timed-metadata";
								break;
							default: return;
						}
						if (data.payloadUnitStartIndicator) flushStream(stream, streamType, true);
						stream.data.push(data);
						stream.size += data.data.byteLength;
					},
					pmt: function pmt() {
						var event = {
							type: "metadata",
							tracks: []
						};
						programMapTable = data.programMapTable;
						if (programMapTable.video !== null) event.tracks.push({
							timelineStartInfo: { baseMediaDecodeTime: 0 },
							id: +programMapTable.video,
							codec: "avc",
							type: "video"
						});
						if (programMapTable.audio !== null) event.tracks.push({
							timelineStartInfo: { baseMediaDecodeTime: 0 },
							id: +programMapTable.audio,
							codec: "adts",
							type: "audio"
						});
						segmentHadPmt = true;
						self.trigger("data", event);
					}
				})[data.type]();
			};
			this.reset = function() {
				video.size = 0;
				video.data.length = 0;
				audio.size = 0;
				audio.data.length = 0;
				this.trigger("reset");
			};
			/**
			* Flush any remaining input. Video PES packets may be of variable
			* length. Normally, the start of a new video packet can trigger the
			* finalization of the previous packet. That is not possible if no
			* more video is forthcoming, however. In that case, some other
			* mechanism (like the end of the file) has to be employed. When it is
			* clear that no additional data is forthcoming, calling this method
			* will flush the buffered packets.
			*/
			this.flushStreams_ = function() {
				flushStream(video, "video");
				flushStream(audio, "audio");
				flushStream(timedMetadata, "timed-metadata");
			};
			this.flush = function() {
				if (!segmentHadPmt && programMapTable) {
					var pmt = {
						type: "metadata",
						tracks: []
					};
					if (programMapTable.video !== null) pmt.tracks.push({
						timelineStartInfo: { baseMediaDecodeTime: 0 },
						id: +programMapTable.video,
						codec: "avc",
						type: "video"
					});
					if (programMapTable.audio !== null) pmt.tracks.push({
						timelineStartInfo: { baseMediaDecodeTime: 0 },
						id: +programMapTable.audio,
						codec: "adts",
						type: "audio"
					});
					self.trigger("data", pmt);
				}
				segmentHadPmt = false;
				this.flushStreams_();
				this.trigger("done");
			};
		};
		_ElementaryStream.prototype = new Stream();
		var m2ts = {
			PAT_PID: 0,
			MP2T_PACKET_LENGTH,
			TransportPacketStream: _TransportPacketStream,
			TransportParseStream: _TransportParseStream,
			ElementaryStream: _ElementaryStream,
			TimestampRolloverStream,
			CaptionStream: CaptionStream.CaptionStream,
			Cea608Stream: CaptionStream.Cea608Stream,
			Cea708Stream: CaptionStream.Cea708Stream,
			MetadataStream: require_metadata_stream()
		};
		for (var type in StreamTypes) if (StreamTypes.hasOwnProperty(type)) m2ts[type] = StreamTypes[type];
		module.exports = m2ts;
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/codecs/adts.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*/
	var require_adts = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = require_stream();
		var ONE_SECOND_IN_TS = require_clock().ONE_SECOND_IN_TS;
		var _AdtsStream;
		var ADTS_SAMPLING_FREQUENCIES = [
			96e3,
			88200,
			64e3,
			48e3,
			44100,
			32e3,
			24e3,
			22050,
			16e3,
			12e3,
			11025,
			8e3,
			7350
		];
		_AdtsStream = function AdtsStream(handlePartialSegments) {
			var buffer, frameNum = 0;
			_AdtsStream.prototype.init.call(this);
			this.skipWarn_ = function(start, end) {
				this.trigger("log", {
					level: "warn",
					message: "adts skiping bytes " + start + " to " + end + " in frame " + frameNum + " outside syncword"
				});
			};
			this.push = function(packet) {
				var i = 0, frameLength, protectionSkipBytes, oldBuffer, sampleCount, adtsFrameDuration;
				if (!handlePartialSegments) frameNum = 0;
				if (packet.type !== "audio") return;
				if (buffer && buffer.length) {
					oldBuffer = buffer;
					buffer = new Uint8Array(oldBuffer.byteLength + packet.data.byteLength);
					buffer.set(oldBuffer);
					buffer.set(packet.data, oldBuffer.byteLength);
				} else buffer = packet.data;
				var skip;
				while (i + 7 < buffer.length) {
					if (buffer[i] !== 255 || (buffer[i + 1] & 246) !== 240) {
						if (typeof skip !== "number") skip = i;
						i++;
						continue;
					}
					if (typeof skip === "number") {
						this.skipWarn_(skip, i);
						skip = null;
					}
					protectionSkipBytes = (~buffer[i + 1] & 1) * 2;
					frameLength = (buffer[i + 3] & 3) << 11 | buffer[i + 4] << 3 | (buffer[i + 5] & 224) >> 5;
					sampleCount = ((buffer[i + 6] & 3) + 1) * 1024;
					adtsFrameDuration = sampleCount * ONE_SECOND_IN_TS / ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 60) >>> 2];
					if (buffer.byteLength - i < frameLength) break;
					this.trigger("data", {
						pts: packet.pts + frameNum * adtsFrameDuration,
						dts: packet.dts + frameNum * adtsFrameDuration,
						sampleCount,
						audioobjecttype: (buffer[i + 2] >>> 6 & 3) + 1,
						channelcount: (buffer[i + 2] & 1) << 2 | (buffer[i + 3] & 192) >>> 6,
						samplerate: ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 60) >>> 2],
						samplingfrequencyindex: (buffer[i + 2] & 60) >>> 2,
						samplesize: 16,
						data: buffer.subarray(i + 7 + protectionSkipBytes, i + frameLength)
					});
					frameNum++;
					i += frameLength;
				}
				if (typeof skip === "number") {
					this.skipWarn_(skip, i);
					skip = null;
				}
				buffer = buffer.subarray(i);
			};
			this.flush = function() {
				frameNum = 0;
				this.trigger("done");
			};
			this.reset = function() {
				buffer = void 0;
				this.trigger("reset");
			};
			this.endTimeline = function() {
				buffer = void 0;
				this.trigger("endedtimeline");
			};
		};
		_AdtsStream.prototype = new Stream();
		module.exports = _AdtsStream;
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/utils/exp-golomb.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*/
	var require_exp_golomb = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		module.exports = function ExpGolomb(workingData) {
			var workingBytesAvailable = workingData.byteLength, workingWord = 0, workingBitsAvailable = 0;
			this.length = function() {
				return 8 * workingBytesAvailable;
			};
			this.bitsAvailable = function() {
				return 8 * workingBytesAvailable + workingBitsAvailable;
			};
			this.loadWord = function() {
				var position = workingData.byteLength - workingBytesAvailable, workingBytes = /* @__PURE__ */ new Uint8Array(4), availableBytes = Math.min(4, workingBytesAvailable);
				if (availableBytes === 0) throw new Error("no bytes available");
				workingBytes.set(workingData.subarray(position, position + availableBytes));
				workingWord = new DataView(workingBytes.buffer).getUint32(0);
				workingBitsAvailable = availableBytes * 8;
				workingBytesAvailable -= availableBytes;
			};
			this.skipBits = function(count) {
				var skipBytes;
				if (workingBitsAvailable > count) {
					workingWord <<= count;
					workingBitsAvailable -= count;
				} else {
					count -= workingBitsAvailable;
					skipBytes = Math.floor(count / 8);
					count -= skipBytes * 8;
					workingBytesAvailable -= skipBytes;
					this.loadWord();
					workingWord <<= count;
					workingBitsAvailable -= count;
				}
			};
			this.readBits = function(size) {
				var bits = Math.min(workingBitsAvailable, size), valu = workingWord >>> 32 - bits;
				workingBitsAvailable -= bits;
				if (workingBitsAvailable > 0) workingWord <<= bits;
				else if (workingBytesAvailable > 0) this.loadWord();
				bits = size - bits;
				if (bits > 0) return valu << bits | this.readBits(bits);
				return valu;
			};
			this.skipLeadingZeros = function() {
				var leadingZeroCount;
				for (leadingZeroCount = 0; leadingZeroCount < workingBitsAvailable; ++leadingZeroCount) if ((workingWord & 2147483648 >>> leadingZeroCount) !== 0) {
					workingWord <<= leadingZeroCount;
					workingBitsAvailable -= leadingZeroCount;
					return leadingZeroCount;
				}
				this.loadWord();
				return leadingZeroCount + this.skipLeadingZeros();
			};
			this.skipUnsignedExpGolomb = function() {
				this.skipBits(1 + this.skipLeadingZeros());
			};
			this.skipExpGolomb = function() {
				this.skipBits(1 + this.skipLeadingZeros());
			};
			this.readUnsignedExpGolomb = function() {
				var clz = this.skipLeadingZeros();
				return this.readBits(clz + 1) - 1;
			};
			this.readExpGolomb = function() {
				var valu = this.readUnsignedExpGolomb();
				if (1 & valu) return 1 + valu >>> 1;
				return -1 * (valu >>> 1);
			};
			this.readBoolean = function() {
				return this.readBits(1) === 1;
			};
			this.readUnsignedByte = function() {
				return this.readBits(8);
			};
			this.loadWord();
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/codecs/h264.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*/
	var require_h264 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = require_stream();
		var ExpGolomb = require_exp_golomb();
		var _H264Stream;
		var _NalByteStream;
		var PROFILES_WITH_OPTIONAL_SPS_DATA;
		/**
		* Accepts a NAL unit byte stream and unpacks the embedded NAL units.
		*/
		_NalByteStream = function NalByteStream() {
			var syncPoint = 0, i, buffer;
			_NalByteStream.prototype.init.call(this);
			this.push = function(data) {
				var swapBuffer;
				if (!buffer) buffer = data.data;
				else {
					swapBuffer = new Uint8Array(buffer.byteLength + data.data.byteLength);
					swapBuffer.set(buffer);
					swapBuffer.set(data.data, buffer.byteLength);
					buffer = swapBuffer;
				}
				var len = buffer.byteLength;
				for (; syncPoint < len - 3; syncPoint++) if (buffer[syncPoint + 2] === 1) {
					i = syncPoint + 5;
					break;
				}
				while (i < len) switch (buffer[i]) {
					case 0:
						if (buffer[i - 1] !== 0) {
							i += 2;
							break;
						} else if (buffer[i - 2] !== 0) {
							i++;
							break;
						}
						if (syncPoint + 3 !== i - 2) this.trigger("data", buffer.subarray(syncPoint + 3, i - 2));
						do
							i++;
						while (buffer[i] !== 1 && i < len);
						syncPoint = i - 2;
						i += 3;
						break;
					case 1:
						if (buffer[i - 1] !== 0 || buffer[i - 2] !== 0) {
							i += 3;
							break;
						}
						this.trigger("data", buffer.subarray(syncPoint + 3, i - 2));
						syncPoint = i - 2;
						i += 3;
						break;
					default:
						i += 3;
						break;
				}
				buffer = buffer.subarray(syncPoint);
				i -= syncPoint;
				syncPoint = 0;
			};
			this.reset = function() {
				buffer = null;
				syncPoint = 0;
				this.trigger("reset");
			};
			this.flush = function() {
				if (buffer && buffer.byteLength > 3) this.trigger("data", buffer.subarray(syncPoint + 3));
				buffer = null;
				syncPoint = 0;
				this.trigger("done");
			};
			this.endTimeline = function() {
				this.flush();
				this.trigger("endedtimeline");
			};
		};
		_NalByteStream.prototype = new Stream();
		PROFILES_WITH_OPTIONAL_SPS_DATA = {
			100: true,
			110: true,
			122: true,
			244: true,
			44: true,
			83: true,
			86: true,
			118: true,
			128: true,
			138: true,
			139: true,
			134: true
		};
		/**
		* Accepts input from a ElementaryStream and produces H.264 NAL unit data
		* events.
		*/
		_H264Stream = function H264Stream() {
			var nalByteStream = new _NalByteStream(), self, trackId, currentPts, currentDts, discardEmulationPreventionBytes, readSequenceParameterSet, skipScalingList;
			_H264Stream.prototype.init.call(this);
			self = this;
			this.push = function(packet) {
				if (packet.type !== "video") return;
				trackId = packet.trackId;
				currentPts = packet.pts;
				currentDts = packet.dts;
				nalByteStream.push(packet);
			};
			nalByteStream.on("data", function(data) {
				var event = {
					trackId,
					pts: currentPts,
					dts: currentDts,
					data,
					nalUnitTypeCode: data[0] & 31
				};
				switch (event.nalUnitTypeCode) {
					case 5:
						event.nalUnitType = "slice_layer_without_partitioning_rbsp_idr";
						break;
					case 6:
						event.nalUnitType = "sei_rbsp";
						event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1));
						break;
					case 7:
						event.nalUnitType = "seq_parameter_set_rbsp";
						event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1));
						event.config = readSequenceParameterSet(event.escapedRBSP);
						break;
					case 8:
						event.nalUnitType = "pic_parameter_set_rbsp";
						break;
					case 9:
						event.nalUnitType = "access_unit_delimiter_rbsp";
						break;
					default: break;
				}
				self.trigger("data", event);
			});
			nalByteStream.on("done", function() {
				self.trigger("done");
			});
			nalByteStream.on("partialdone", function() {
				self.trigger("partialdone");
			});
			nalByteStream.on("reset", function() {
				self.trigger("reset");
			});
			nalByteStream.on("endedtimeline", function() {
				self.trigger("endedtimeline");
			});
			this.flush = function() {
				nalByteStream.flush();
			};
			this.partialFlush = function() {
				nalByteStream.partialFlush();
			};
			this.reset = function() {
				nalByteStream.reset();
			};
			this.endTimeline = function() {
				nalByteStream.endTimeline();
			};
			/**
			* Advance the ExpGolomb decoder past a scaling list. The scaling
			* list is optionally transmitted as part of a sequence parameter
			* set and is not relevant to transmuxing.
			* @param count {number} the number of entries in this scaling list
			* @param expGolombDecoder {object} an ExpGolomb pointed to the
			* start of a scaling list
			* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
			*/
			skipScalingList = function skipScalingList(count, expGolombDecoder) {
				var lastScale = 8, nextScale = 8, j, deltaScale;
				for (j = 0; j < count; j++) {
					if (nextScale !== 0) {
						deltaScale = expGolombDecoder.readExpGolomb();
						nextScale = (lastScale + deltaScale + 256) % 256;
					}
					lastScale = nextScale === 0 ? lastScale : nextScale;
				}
			};
			/**
			* Expunge any "Emulation Prevention" bytes from a "Raw Byte
			* Sequence Payload"
			* @param data {Uint8Array} the bytes of a RBSP from a NAL
			* unit
			* @return {Uint8Array} the RBSP without any Emulation
			* Prevention Bytes
			*/
			discardEmulationPreventionBytes = function discardEmulationPreventionBytes(data) {
				var length = data.byteLength, emulationPreventionBytesPositions = [], i = 1, newLength, newData;
				while (i < length - 2) if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 3) {
					emulationPreventionBytesPositions.push(i + 2);
					i += 2;
				} else i++;
				if (emulationPreventionBytesPositions.length === 0) return data;
				newLength = length - emulationPreventionBytesPositions.length;
				newData = new Uint8Array(newLength);
				var sourceIndex = 0;
				for (i = 0; i < newLength; sourceIndex++, i++) {
					if (sourceIndex === emulationPreventionBytesPositions[0]) {
						sourceIndex++;
						emulationPreventionBytesPositions.shift();
					}
					newData[i] = data[sourceIndex];
				}
				return newData;
			};
			/**
			* Read a sequence parameter set and return some interesting video
			* properties. A sequence parameter set is the H264 metadata that
			* describes the properties of upcoming video frames.
			* @param data {Uint8Array} the bytes of a sequence parameter set
			* @return {object} an object with configuration parsed from the
			* sequence parameter set, including the dimensions of the
			* associated video frames.
			*/
			readSequenceParameterSet = function readSequenceParameterSet(data) {
				var frameCropLeftOffset = 0, frameCropRightOffset = 0, frameCropTopOffset = 0, frameCropBottomOffset = 0, expGolombDecoder, profileIdc, levelIdc, profileCompatibility, chromaFormatIdc, picOrderCntType, numRefFramesInPicOrderCntCycle, picWidthInMbsMinus1, picHeightInMapUnitsMinus1, frameMbsOnlyFlag, scalingListCount, sarRatio = [1, 1], aspectRatioIdc, i;
				expGolombDecoder = new ExpGolomb(data);
				profileIdc = expGolombDecoder.readUnsignedByte();
				profileCompatibility = expGolombDecoder.readUnsignedByte();
				levelIdc = expGolombDecoder.readUnsignedByte();
				expGolombDecoder.skipUnsignedExpGolomb();
				if (PROFILES_WITH_OPTIONAL_SPS_DATA[profileIdc]) {
					chromaFormatIdc = expGolombDecoder.readUnsignedExpGolomb();
					if (chromaFormatIdc === 3) expGolombDecoder.skipBits(1);
					expGolombDecoder.skipUnsignedExpGolomb();
					expGolombDecoder.skipUnsignedExpGolomb();
					expGolombDecoder.skipBits(1);
					if (expGolombDecoder.readBoolean()) {
						scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
						for (i = 0; i < scalingListCount; i++) if (expGolombDecoder.readBoolean()) if (i < 6) skipScalingList(16, expGolombDecoder);
						else skipScalingList(64, expGolombDecoder);
					}
				}
				expGolombDecoder.skipUnsignedExpGolomb();
				picOrderCntType = expGolombDecoder.readUnsignedExpGolomb();
				if (picOrderCntType === 0) expGolombDecoder.readUnsignedExpGolomb();
				else if (picOrderCntType === 1) {
					expGolombDecoder.skipBits(1);
					expGolombDecoder.skipExpGolomb();
					expGolombDecoder.skipExpGolomb();
					numRefFramesInPicOrderCntCycle = expGolombDecoder.readUnsignedExpGolomb();
					for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) expGolombDecoder.skipExpGolomb();
				}
				expGolombDecoder.skipUnsignedExpGolomb();
				expGolombDecoder.skipBits(1);
				picWidthInMbsMinus1 = expGolombDecoder.readUnsignedExpGolomb();
				picHeightInMapUnitsMinus1 = expGolombDecoder.readUnsignedExpGolomb();
				frameMbsOnlyFlag = expGolombDecoder.readBits(1);
				if (frameMbsOnlyFlag === 0) expGolombDecoder.skipBits(1);
				expGolombDecoder.skipBits(1);
				if (expGolombDecoder.readBoolean()) {
					frameCropLeftOffset = expGolombDecoder.readUnsignedExpGolomb();
					frameCropRightOffset = expGolombDecoder.readUnsignedExpGolomb();
					frameCropTopOffset = expGolombDecoder.readUnsignedExpGolomb();
					frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb();
				}
				if (expGolombDecoder.readBoolean()) {
					if (expGolombDecoder.readBoolean()) {
						aspectRatioIdc = expGolombDecoder.readUnsignedByte();
						switch (aspectRatioIdc) {
							case 1:
								sarRatio = [1, 1];
								break;
							case 2:
								sarRatio = [12, 11];
								break;
							case 3:
								sarRatio = [10, 11];
								break;
							case 4:
								sarRatio = [16, 11];
								break;
							case 5:
								sarRatio = [40, 33];
								break;
							case 6:
								sarRatio = [24, 11];
								break;
							case 7:
								sarRatio = [20, 11];
								break;
							case 8:
								sarRatio = [32, 11];
								break;
							case 9:
								sarRatio = [80, 33];
								break;
							case 10:
								sarRatio = [18, 11];
								break;
							case 11:
								sarRatio = [15, 11];
								break;
							case 12:
								sarRatio = [64, 33];
								break;
							case 13:
								sarRatio = [160, 99];
								break;
							case 14:
								sarRatio = [4, 3];
								break;
							case 15:
								sarRatio = [3, 2];
								break;
							case 16:
								sarRatio = [2, 1];
								break;
							case 255:
								sarRatio = [expGolombDecoder.readUnsignedByte() << 8 | expGolombDecoder.readUnsignedByte(), expGolombDecoder.readUnsignedByte() << 8 | expGolombDecoder.readUnsignedByte()];
								break;
						}
						if (sarRatio) sarRatio[0] / sarRatio[1];
					}
				}
				return {
					profileIdc,
					levelIdc,
					profileCompatibility,
					width: (picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2,
					height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - frameCropTopOffset * 2 - frameCropBottomOffset * 2,
					sarRatio
				};
			};
		};
		_H264Stream.prototype = new Stream();
		module.exports = {
			H264Stream: _H264Stream,
			NalByteStream: _NalByteStream
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/aac/utils.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* Utilities to detect basic properties and metadata about Aac data.
	*/
	var require_utils = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var ADTS_SAMPLING_FREQUENCIES = [
			96e3,
			88200,
			64e3,
			48e3,
			44100,
			32e3,
			24e3,
			22050,
			16e3,
			12e3,
			11025,
			8e3,
			7350
		];
		var parseId3TagSize = function parseId3TagSize(header, byteIndex) {
			var returnSize = header[byteIndex + 6] << 21 | header[byteIndex + 7] << 14 | header[byteIndex + 8] << 7 | header[byteIndex + 9], footerPresent = (header[byteIndex + 5] & 16) >> 4;
			returnSize = returnSize >= 0 ? returnSize : 0;
			if (footerPresent) return returnSize + 20;
			return returnSize + 10;
		};
		var getId3Offset = function getId3Offset(data, offset) {
			if (data.length - offset < 10 || data[offset] !== "I".charCodeAt(0) || data[offset + 1] !== "D".charCodeAt(0) || data[offset + 2] !== "3".charCodeAt(0)) return offset;
			offset += parseId3TagSize(data, offset);
			return getId3Offset(data, offset);
		};
		var isLikelyAacData = function isLikelyAacData(data) {
			var offset = getId3Offset(data, 0);
			return data.length >= offset + 2 && (data[offset] & 255) === 255 && (data[offset + 1] & 240) === 240 && (data[offset + 1] & 22) === 16;
		};
		var parseSyncSafeInteger = function parseSyncSafeInteger(data) {
			return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
		};
		var percentEncode = function percentEncode(bytes, start, end) {
			var i, result = "";
			for (i = start; i < end; i++) result += "%" + ("00" + bytes[i].toString(16)).slice(-2);
			return result;
		};
		var parseIso88591 = function parseIso88591(bytes, start, end) {
			return unescape(percentEncode(bytes, start, end));
		};
		module.exports = {
			isLikelyAacData,
			parseId3TagSize,
			parseAdtsSize: function parseAdtsSize(header, byteIndex) {
				var lowThree = (header[byteIndex + 5] & 224) >> 5, middle = header[byteIndex + 4] << 3;
				return header[byteIndex + 3] & 6144 | middle | lowThree;
			},
			parseType: function parseType(header, byteIndex) {
				if (header[byteIndex] === "I".charCodeAt(0) && header[byteIndex + 1] === "D".charCodeAt(0) && header[byteIndex + 2] === "3".charCodeAt(0)) return "timed-metadata";
				else if (header[byteIndex] & true && (header[byteIndex + 1] & 240) === 240) return "audio";
				return null;
			},
			parseSampleRate: function parseSampleRate(packet) {
				var i = 0;
				while (i + 5 < packet.length) {
					if (packet[i] !== 255 || (packet[i + 1] & 246) !== 240) {
						i++;
						continue;
					}
					return ADTS_SAMPLING_FREQUENCIES[(packet[i + 2] & 60) >>> 2];
				}
				return null;
			},
			parseAacTimestamp: function parseAacTimestamp(packet) {
				var frameStart = 10, frameSize, frame, frameHeader;
				if (packet[5] & 64) {
					frameStart += 4;
					frameStart += parseSyncSafeInteger(packet.subarray(10, 14));
				}
				do {
					frameSize = parseSyncSafeInteger(packet.subarray(frameStart + 4, frameStart + 8));
					if (frameSize < 1) return null;
					frameHeader = String.fromCharCode(packet[frameStart], packet[frameStart + 1], packet[frameStart + 2], packet[frameStart + 3]);
					if (frameHeader === "PRIV") {
						frame = packet.subarray(frameStart + 10, frameStart + frameSize + 10);
						for (var i = 0; i < frame.byteLength; i++) if (frame[i] === 0) {
							if (parseIso88591(frame, 0, i) === "com.apple.streaming.transportStreamTimestamp") {
								var d = frame.subarray(i + 1);
								var size = (d[3] & 1) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
								size *= 4;
								size += d[7] & 3;
								return size;
							}
							break;
						}
					}
					frameStart += 10;
					frameStart += frameSize;
				} while (frameStart < packet.byteLength);
				return null;
			}
		};
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/aac/index.js
	/**
	* mux.js
	*
	* Copyright (c) Brightcove
	* Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
	*
	* A stream-based aac to mp4 converter. This utility can be used to
	* deliver mp4s to a SourceBuffer on platforms that support native
	* Media Source Extensions.
	*/
	var require_aac = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = require_stream();
		var aacUtils = require_utils();
		var _AacStream = function AacStream() {
			var everything = /* @__PURE__ */ new Uint8Array(), timeStamp = 0;
			_AacStream.prototype.init.call(this);
			this.setTimestamp = function(timestamp) {
				timeStamp = timestamp;
			};
			this.push = function(bytes) {
				var frameSize = 0, byteIndex = 0, bytesLeft, chunk, packet, tempLength;
				if (everything.length) {
					tempLength = everything.length;
					everything = new Uint8Array(bytes.byteLength + tempLength);
					everything.set(everything.subarray(0, tempLength));
					everything.set(bytes, tempLength);
				} else everything = bytes;
				while (everything.length - byteIndex >= 3) {
					if (everything[byteIndex] === "I".charCodeAt(0) && everything[byteIndex + 1] === "D".charCodeAt(0) && everything[byteIndex + 2] === "3".charCodeAt(0)) {
						if (everything.length - byteIndex < 10) break;
						frameSize = aacUtils.parseId3TagSize(everything, byteIndex);
						if (byteIndex + frameSize > everything.length) break;
						chunk = {
							type: "timed-metadata",
							data: everything.subarray(byteIndex, byteIndex + frameSize)
						};
						this.trigger("data", chunk);
						byteIndex += frameSize;
						continue;
					} else if ((everything[byteIndex] & 255) === 255 && (everything[byteIndex + 1] & 240) === 240) {
						if (everything.length - byteIndex < 7) break;
						frameSize = aacUtils.parseAdtsSize(everything, byteIndex);
						if (byteIndex + frameSize > everything.length) break;
						packet = {
							type: "audio",
							data: everything.subarray(byteIndex, byteIndex + frameSize),
							pts: timeStamp,
							dts: timeStamp
						};
						this.trigger("data", packet);
						byteIndex += frameSize;
						continue;
					}
					byteIndex++;
				}
				bytesLeft = everything.length - byteIndex;
				if (bytesLeft > 0) everything = everything.subarray(byteIndex);
				else everything = /* @__PURE__ */ new Uint8Array();
			};
			this.reset = function() {
				everything = /* @__PURE__ */ new Uint8Array();
				this.trigger("reset");
			};
			this.endTimeline = function() {
				everything = /* @__PURE__ */ new Uint8Array();
				this.trigger("endedtimeline");
			};
		};
		_AacStream.prototype = new Stream();
		module.exports = _AacStream;
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/constants/audio-properties.js
	var require_audio_properties = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		module.exports = [
			"audioobjecttype",
			"channelcount",
			"samplerate",
			"samplingfrequencyindex",
			"samplesize"
		];
	}));
	//#endregion
	//#region node_modules/.pnpm/[email protected]/node_modules/mux.js/cjs/constants/video-properties.js
	var require_video_properties = /* @__PURE__ */ __commonJSMin(((exports, module) => {
		module.exports = [
			"width",
			"height",
			"profileIdc",
			"levelIdc",
			"profileCompatibility",
			"sarRatio"
		];
	}));
	//#endregion
	//#region src/features/clipDownloads/mediaTypes.ts
	var import_transmuxer = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
		var Stream = require_stream();
		var mp4 = require_mp4_generator();
		var frameUtils = require_frame_utils();
		var audioFrameUtils = require_audio_frame_utils();
		var trackDecodeInfo = require_track_decode_info();
		var m2ts = require_m2ts();
		var clock = require_clock();
		var AdtsStream = require_adts();
		var H264Stream = require_h264().H264Stream;
		var AacStream = require_aac();
		var isLikelyAacData = require_utils().isLikelyAacData;
		var ONE_SECOND_IN_TS = require_clock().ONE_SECOND_IN_TS;
		var AUDIO_PROPERTIES = require_audio_properties();
		var VIDEO_PROPERTIES = require_video_properties();
		var _VideoSegmentStream;
		var _AudioSegmentStream;
		var _Transmuxer;
		var _CoalesceStream;
		var retriggerForStream = function retriggerForStream(key, event) {
			event.stream = key;
			this.trigger("log", event);
		};
		var addPipelineLogRetriggers = function addPipelineLogRetriggers(transmuxer, pipeline) {
			var keys = Object.keys(pipeline);
			for (var i = 0; i < keys.length; i++) {
				var key = keys[i];
				if (key === "headOfPipeline" || !pipeline[key].on) continue;
				pipeline[key].on("log", retriggerForStream.bind(transmuxer, key));
			}
		};
		/**
		* Compare two arrays (even typed) for same-ness
		*/
		var arrayEquals = function arrayEquals(a, b) {
			var i;
			if (a.length !== b.length) return false;
			for (i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
			return true;
		};
		var generateSegmentTimingInfo = function generateSegmentTimingInfo(baseMediaDecodeTime, startDts, startPts, endDts, endPts, prependedContentDuration) {
			var ptsOffsetFromDts = startPts - startDts, decodeDuration = endDts - startDts, presentationDuration = endPts - startPts;
			return {
				start: {
					dts: baseMediaDecodeTime,
					pts: baseMediaDecodeTime + ptsOffsetFromDts
				},
				end: {
					dts: baseMediaDecodeTime + decodeDuration,
					pts: baseMediaDecodeTime + presentationDuration
				},
				prependedContentDuration,
				baseMediaDecodeTime
			};
		};
		/**
		* Constructs a single-track, ISO BMFF media segment from AAC data
		* events. The output of this stream can be fed to a SourceBuffer
		* configured with a suitable initialization segment.
		* @param track {object} track metadata configuration
		* @param options {object} transmuxer options object
		* @param options.keepOriginalTimestamps {boolean} If true, keep the timestamps
		*        in the source; false to adjust the first segment to start at 0.
		*/
		_AudioSegmentStream = function AudioSegmentStream(track, options) {
			var adtsFrames = [], sequenceNumber, earliestAllowedDts = 0, audioAppendStartTs = 0, videoBaseMediaDecodeTime = Infinity;
			options = options || {};
			sequenceNumber = options.firstSequenceNumber || 0;
			_AudioSegmentStream.prototype.init.call(this);
			this.push = function(data) {
				trackDecodeInfo.collectDtsInfo(track, data);
				if (track) AUDIO_PROPERTIES.forEach(function(prop) {
					track[prop] = data[prop];
				});
				adtsFrames.push(data);
			};
			this.setEarliestDts = function(earliestDts) {
				earliestAllowedDts = earliestDts;
			};
			this.setVideoBaseMediaDecodeTime = function(baseMediaDecodeTime) {
				videoBaseMediaDecodeTime = baseMediaDecodeTime;
			};
			this.setAudioAppendStart = function(timestamp) {
				audioAppendStartTs = timestamp;
			};
			this.flush = function() {
				var frames, moof, mdat, boxes, frameDuration, segmentDuration, videoClockCyclesOfSilencePrefixed;
				if (adtsFrames.length === 0) {
					this.trigger("done", "AudioSegmentStream");
					return;
				}
				frames = audioFrameUtils.trimAdtsFramesByEarliestDts(adtsFrames, track, earliestAllowedDts);
				track.baseMediaDecodeTime = trackDecodeInfo.calculateTrackBaseMediaDecodeTime(track, options.keepOriginalTimestamps);
				videoClockCyclesOfSilencePrefixed = audioFrameUtils.prefixWithSilence(track, frames, audioAppendStartTs, videoBaseMediaDecodeTime);
				track.samples = audioFrameUtils.generateSampleTable(frames);
				mdat = mp4.mdat(audioFrameUtils.concatenateFrameData(frames));
				adtsFrames = [];
				moof = mp4.moof(sequenceNumber, [track]);
				boxes = new Uint8Array(moof.byteLength + mdat.byteLength);
				sequenceNumber++;
				boxes.set(moof);
				boxes.set(mdat, moof.byteLength);
				trackDecodeInfo.clearDtsInfo(track);
				frameDuration = Math.ceil(ONE_SECOND_IN_TS * 1024 / track.samplerate);
				if (frames.length) {
					segmentDuration = frames.length * frameDuration;
					this.trigger("segmentTimingInfo", generateSegmentTimingInfo(clock.audioTsToVideoTs(track.baseMediaDecodeTime, track.samplerate), frames[0].dts, frames[0].pts, frames[0].dts + segmentDuration, frames[0].pts + segmentDuration, videoClockCyclesOfSilencePrefixed || 0));
					this.trigger("timingInfo", {
						start: frames[0].pts,
						end: frames[0].pts + segmentDuration
					});
				}
				this.trigger("data", {
					track,
					boxes
				});
				this.trigger("done", "AudioSegmentStream");
			};
			this.reset = function() {
				trackDecodeInfo.clearDtsInfo(track);
				adtsFrames = [];
				this.trigger("reset");
			};
		};
		_AudioSegmentStream.prototype = new Stream();
		/**
		* Constructs a single-track, ISO BMFF media segment from H264 data
		* events. The output of this stream can be fed to a SourceBuffer
		* configured with a suitable initialization segment.
		* @param track {object} track metadata configuration
		* @param options {object} transmuxer options object
		* @param options.alignGopsAtEnd {boolean} If true, start from the end of the
		*        gopsToAlignWith list when attempting to align gop pts
		* @param options.keepOriginalTimestamps {boolean} If true, keep the timestamps
		*        in the source; false to adjust the first segment to start at 0.
		*/
		_VideoSegmentStream = function VideoSegmentStream(track, options) {
			var sequenceNumber, nalUnits = [], gopsToAlignWith = [], config, pps;
			options = options || {};
			sequenceNumber = options.firstSequenceNumber || 0;
			_VideoSegmentStream.prototype.init.call(this);
			delete track.minPTS;
			this.gopCache_ = [];
			/**
			* Constructs a ISO BMFF segment given H264 nalUnits
			* @param {Object} nalUnit A data event representing a nalUnit
			* @param {String} nalUnit.nalUnitType
			* @param {Object} nalUnit.config Properties for a mp4 track
			* @param {Uint8Array} nalUnit.data The nalUnit bytes
			* @see lib/codecs/h264.js
			**/
			this.push = function(nalUnit) {
				trackDecodeInfo.collectDtsInfo(track, nalUnit);
				if (nalUnit.nalUnitType === "seq_parameter_set_rbsp" && !config) {
					config = nalUnit.config;
					track.sps = [nalUnit.data];
					VIDEO_PROPERTIES.forEach(function(prop) {
						track[prop] = config[prop];
					}, this);
				}
				if (nalUnit.nalUnitType === "pic_parameter_set_rbsp" && !pps) {
					pps = nalUnit.data;
					track.pps = [nalUnit.data];
				}
				nalUnits.push(nalUnit);
			};
			/**
			* Pass constructed ISO BMFF track and boxes on to the
			* next stream in the pipeline
			**/
			this.flush = function() {
				var frames, gopForFusion, gops, moof, mdat, boxes, prependedContentDuration = 0, firstGop, lastGop;
				while (nalUnits.length) {
					if (nalUnits[0].nalUnitType === "access_unit_delimiter_rbsp") break;
					nalUnits.shift();
				}
				if (nalUnits.length === 0) {
					this.resetStream_();
					this.trigger("done", "VideoSegmentStream");
					return;
				}
				frames = frameUtils.groupNalsIntoFrames(nalUnits);
				gops = frameUtils.groupFramesIntoGops(frames);
				if (!gops[0][0].keyFrame) {
					gopForFusion = this.getGopForFusion_(nalUnits[0], track);
					if (gopForFusion) {
						prependedContentDuration = gopForFusion.duration;
						gops.unshift(gopForFusion);
						gops.byteLength += gopForFusion.byteLength;
						gops.nalCount += gopForFusion.nalCount;
						gops.pts = gopForFusion.pts;
						gops.dts = gopForFusion.dts;
						gops.duration += gopForFusion.duration;
					} else gops = frameUtils.extendFirstKeyFrame(gops);
				}
				if (gopsToAlignWith.length) {
					var alignedGops;
					if (options.alignGopsAtEnd) alignedGops = this.alignGopsAtEnd_(gops);
					else alignedGops = this.alignGopsAtStart_(gops);
					if (!alignedGops) {
						this.gopCache_.unshift({
							gop: gops.pop(),
							pps: track.pps,
							sps: track.sps
						});
						this.gopCache_.length = Math.min(6, this.gopCache_.length);
						nalUnits = [];
						this.resetStream_();
						this.trigger("done", "VideoSegmentStream");
						return;
					}
					trackDecodeInfo.clearDtsInfo(track);
					gops = alignedGops;
				}
				trackDecodeInfo.collectDtsInfo(track, gops);
				track.samples = frameUtils.generateSampleTable(gops);
				mdat = mp4.mdat(frameUtils.concatenateNalData(gops));
				track.baseMediaDecodeTime = trackDecodeInfo.calculateTrackBaseMediaDecodeTime(track, options.keepOriginalTimestamps);
				this.trigger("processedGopsInfo", gops.map(function(gop) {
					return {
						pts: gop.pts,
						dts: gop.dts,
						byteLength: gop.byteLength
					};
				}));
				firstGop = gops[0];
				lastGop = gops[gops.length - 1];
				this.trigger("segmentTimingInfo", generateSegmentTimingInfo(track.baseMediaDecodeTime, firstGop.dts, firstGop.pts, lastGop.dts + lastGop.duration, lastGop.pts + lastGop.duration, prependedContentDuration));
				this.trigger("timingInfo", {
					start: gops[0].pts,
					end: gops[gops.length - 1].pts + gops[gops.length - 1].duration
				});
				this.gopCache_.unshift({
					gop: gops.pop(),
					pps: track.pps,
					sps: track.sps
				});
				this.gopCache_.length = Math.min(6, this.gopCache_.length);
				nalUnits = [];
				this.trigger("baseMediaDecodeTime", track.baseMediaDecodeTime);
				this.trigger("timelineStartInfo", track.timelineStartInfo);
				moof = mp4.moof(sequenceNumber, [track]);
				boxes = new Uint8Array(moof.byteLength + mdat.byteLength);
				sequenceNumber++;
				boxes.set(moof);
				boxes.set(mdat, moof.byteLength);
				this.trigger("data", {
					track,
					boxes
				});
				this.resetStream_();
				this.trigger("done", "VideoSegmentStream");
			};
			this.reset = function() {
				this.resetStream_();
				nalUnits = [];
				this.gopCache_.length = 0;
				gopsToAlignWith.length = 0;
				this.trigger("reset");
			};
			this.resetStream_ = function() {
				trackDecodeInfo.clearDtsInfo(track);
				config = void 0;
				pps = void 0;
			};
			this.getGopForFusion_ = function(nalUnit) {
				var halfSecond = 45e3, allowableOverlap = 1e4, nearestDistance = Infinity, dtsDistance, nearestGopObj, currentGop, currentGopObj, i;
				for (i = 0; i < this.gopCache_.length; i++) {
					currentGopObj = this.gopCache_[i];
					currentGop = currentGopObj.gop;
					if (!(track.pps && arrayEquals(track.pps[0], currentGopObj.pps[0])) || !(track.sps && arrayEquals(track.sps[0], currentGopObj.sps[0]))) continue;
					if (currentGop.dts < track.timelineStartInfo.dts) continue;
					dtsDistance = nalUnit.dts - currentGop.dts - currentGop.duration;
					if (dtsDistance >= -allowableOverlap && dtsDistance <= halfSecond) {
						if (!nearestGopObj || nearestDistance > dtsDistance) {
							nearestGopObj = currentGopObj;
							nearestDistance = dtsDistance;
						}
					}
				}
				if (nearestGopObj) return nearestGopObj.gop;
				return null;
			};
			this.alignGopsAtStart_ = function(gops) {
				var alignIndex, gopIndex, align, gop, byteLength = gops.byteLength, nalCount = gops.nalCount, duration = gops.duration, alignedGops;
				alignIndex = gopIndex = 0;
				while (alignIndex < gopsToAlignWith.length && gopIndex < gops.length) {
					align = gopsToAlignWith[alignIndex];
					gop = gops[gopIndex];
					if (align.pts === gop.pts) break;
					if (gop.pts > align.pts) {
						alignIndex++;
						continue;
					}
					gopIndex++;
					byteLength -= gop.byteLength;
					nalCount -= gop.nalCount;
					duration -= gop.duration;
				}
				if (gopIndex === 0) return gops;
				if (gopIndex === gops.length) return null;
				alignedGops = gops.slice(gopIndex);
				alignedGops.byteLength = byteLength;
				alignedGops.duration = duration;
				alignedGops.nalCount = nalCount;
				alignedGops.pts = alignedGops[0].pts;
				alignedGops.dts = alignedGops[0].dts;
				return alignedGops;
			};
			this.alignGopsAtEnd_ = function(gops) {
				var alignIndex = gopsToAlignWith.length - 1, gopIndex = gops.length - 1, align, gop, alignEndIndex = null, matchFound = false;
				while (alignIndex >= 0 && gopIndex >= 0) {
					align = gopsToAlignWith[alignIndex];
					gop = gops[gopIndex];
					if (align.pts === gop.pts) {
						matchFound = true;
						break;
					}
					if (align.pts > gop.pts) {
						alignIndex--;
						continue;
					}
					if (alignIndex === gopsToAlignWith.length - 1) alignEndIndex = gopIndex;
					gopIndex--;
				}
				if (!matchFound && alignEndIndex === null) return null;
				var trimIndex;
				if (matchFound) trimIndex = gopIndex;
				else trimIndex = alignEndIndex;
				if (trimIndex === 0) return gops;
				var alignedGops = gops.slice(trimIndex);
				var metadata = alignedGops.reduce(function(total, gop) {
					total.byteLength += gop.byteLength;
					total.duration += gop.duration;
					total.nalCount += gop.nalCount;
					return total;
				}, {
					byteLength: 0,
					duration: 0,
					nalCount: 0
				});
				alignedGops.byteLength = metadata.byteLength;
				alignedGops.duration = metadata.duration;
				alignedGops.nalCount = metadata.nalCount;
				alignedGops.pts = alignedGops[0].pts;
				alignedGops.dts = alignedGops[0].dts;
				return alignedGops;
			};
			this.alignGopsWith = function(newGopsToAlignWith) {
				gopsToAlignWith = newGopsToAlignWith;
			};
		};
		_VideoSegmentStream.prototype = new Stream();
		/**
		* A Stream that can combine multiple streams (ie. audio & video)
		* into a single output segment for MSE. Also supports audio-only
		* and video-only streams.
		* @param options {object} transmuxer options object
		* @param options.keepOriginalTimestamps {boolean} If true, keep the timestamps
		*        in the source; false to adjust the first segment to start at media timeline start.
		*/
		_CoalesceStream = function CoalesceStream(options, metadataStream) {
			this.numberOfTracks = 0;
			this.metadataStream = metadataStream;
			options = options || {};
			if (typeof options.remux !== "undefined") this.remuxTracks = !!options.remux;
			else this.remuxTracks = true;
			if (typeof options.keepOriginalTimestamps === "boolean") this.keepOriginalTimestamps = options.keepOriginalTimestamps;
			else this.keepOriginalTimestamps = false;
			this.pendingTracks = [];
			this.videoTrack = null;
			this.pendingBoxes = [];
			this.pendingCaptions = [];
			this.pendingMetadata = [];
			this.pendingBytes = 0;
			this.emittedTracks = 0;
			_CoalesceStream.prototype.init.call(this);
			this.push = function(output) {
				if (output.text) return this.pendingCaptions.push(output);
				if (output.frames) return this.pendingMetadata.push(output);
				this.pendingTracks.push(output.track);
				this.pendingBytes += output.boxes.byteLength;
				if (output.track.type === "video") {
					this.videoTrack = output.track;
					this.pendingBoxes.push(output.boxes);
				}
				if (output.track.type === "audio") {
					this.audioTrack = output.track;
					this.pendingBoxes.unshift(output.boxes);
				}
			};
		};
		_CoalesceStream.prototype = new Stream();
		_CoalesceStream.prototype.flush = function(flushSource) {
			var offset = 0, event = {
				captions: [],
				captionStreams: {},
				metadata: [],
				info: {}
			}, caption, id3, initSegment, timelineStartPts = 0, i;
			if (this.pendingTracks.length < this.numberOfTracks) {
				if (flushSource !== "VideoSegmentStream" && flushSource !== "AudioSegmentStream") return;
				else if (this.remuxTracks) return;
				else if (this.pendingTracks.length === 0) {
					this.emittedTracks++;
					if (this.emittedTracks >= this.numberOfTracks) {
						this.trigger("done");
						this.emittedTracks = 0;
					}
					return;
				}
			}
			if (this.videoTrack) {
				timelineStartPts = this.videoTrack.timelineStartInfo.pts;
				VIDEO_PROPERTIES.forEach(function(prop) {
					event.info[prop] = this.videoTrack[prop];
				}, this);
			} else if (this.audioTrack) {
				timelineStartPts = this.audioTrack.timelineStartInfo.pts;
				AUDIO_PROPERTIES.forEach(function(prop) {
					event.info[prop] = this.audioTrack[prop];
				}, this);
			}
			if (this.videoTrack || this.audioTrack) {
				if (this.pendingTracks.length === 1) event.type = this.pendingTracks[0].type;
				else event.type = "combined";
				this.emittedTracks += this.pendingTracks.length;
				initSegment = mp4.initSegment(this.pendingTracks);
				event.initSegment = new Uint8Array(initSegment.byteLength);
				event.initSegment.set(initSegment);
				event.data = new Uint8Array(this.pendingBytes);
				for (i = 0; i < this.pendingBoxes.length; i++) {
					event.data.set(this.pendingBoxes[i], offset);
					offset += this.pendingBoxes[i].byteLength;
				}
				for (i = 0; i < this.pendingCaptions.length; i++) {
					caption = this.pendingCaptions[i];
					caption.startTime = clock.metadataTsToSeconds(caption.startPts, timelineStartPts, this.keepOriginalTimestamps);
					caption.endTime = clock.metadataTsToSeconds(caption.endPts, timelineStartPts, this.keepOriginalTimestamps);
					event.captionStreams[caption.stream] = true;
					event.captions.push(caption);
				}
				for (i = 0; i < this.pendingMetadata.length; i++) {
					id3 = this.pendingMetadata[i];
					id3.cueTime = clock.metadataTsToSeconds(id3.pts, timelineStartPts, this.keepOriginalTimestamps);
					event.metadata.push(id3);
				}
				event.metadata.dispatchType = this.metadataStream.dispatchType;
				this.pendingTracks.length = 0;
				this.videoTrack = null;
				this.pendingBoxes.length = 0;
				this.pendingCaptions.length = 0;
				this.pendingBytes = 0;
				this.pendingMetadata.length = 0;
				this.trigger("data", event);
				for (i = 0; i < event.captions.length; i++) {
					caption = event.captions[i];
					this.trigger("caption", caption);
				}
				for (i = 0; i < event.metadata.length; i++) {
					id3 = event.metadata[i];
					this.trigger("id3Frame", id3);
				}
			}
			if (this.emittedTracks >= this.numberOfTracks) {
				this.trigger("done");
				this.emittedTracks = 0;
			}
		};
		_CoalesceStream.prototype.setRemux = function(val) {
			this.remuxTracks = val;
		};
		/**
		* A Stream that expects MP2T binary data as input and produces
		* corresponding media segments, suitable for use with Media Source
		* Extension (MSE) implementations that support the ISO BMFF byte
		* stream format, like Chrome.
		*/
		_Transmuxer = function Transmuxer(options) {
			var self = this, hasFlushed = true, videoTrack, audioTrack;
			_Transmuxer.prototype.init.call(this);
			options = options || {};
			this.baseMediaDecodeTime = options.baseMediaDecodeTime || 0;
			this.transmuxPipeline_ = {};
			this.setupAacPipeline = function() {
				var pipeline = {};
				this.transmuxPipeline_ = pipeline;
				pipeline.type = "aac";
				pipeline.metadataStream = new m2ts.MetadataStream();
				pipeline.aacStream = new AacStream();
				pipeline.audioTimestampRolloverStream = new m2ts.TimestampRolloverStream("audio");
				pipeline.timedMetadataTimestampRolloverStream = new m2ts.TimestampRolloverStream("timed-metadata");
				pipeline.adtsStream = new AdtsStream();
				pipeline.coalesceStream = new _CoalesceStream(options, pipeline.metadataStream);
				pipeline.headOfPipeline = pipeline.aacStream;
				pipeline.aacStream.pipe(pipeline.audioTimestampRolloverStream).pipe(pipeline.adtsStream);
				pipeline.aacStream.pipe(pipeline.timedMetadataTimestampRolloverStream).pipe(pipeline.metadataStream).pipe(pipeline.coalesceStream);
				pipeline.metadataStream.on("timestamp", function(frame) {
					pipeline.aacStream.setTimestamp(frame.timeStamp);
				});
				pipeline.aacStream.on("data", function(data) {
					if (data.type !== "timed-metadata" && data.type !== "audio" || pipeline.audioSegmentStream) return;
					audioTrack = audioTrack || {
						timelineStartInfo: { baseMediaDecodeTime: self.baseMediaDecodeTime },
						codec: "adts",
						type: "audio"
					};
					pipeline.coalesceStream.numberOfTracks++;
					pipeline.audioSegmentStream = new _AudioSegmentStream(audioTrack, options);
					pipeline.audioSegmentStream.on("log", self.getLogTrigger_("audioSegmentStream"));
					pipeline.audioSegmentStream.on("timingInfo", self.trigger.bind(self, "audioTimingInfo"));
					pipeline.adtsStream.pipe(pipeline.audioSegmentStream).pipe(pipeline.coalesceStream);
					self.trigger("trackinfo", {
						hasAudio: !!audioTrack,
						hasVideo: !!videoTrack
					});
				});
				pipeline.coalesceStream.on("data", this.trigger.bind(this, "data"));
				pipeline.coalesceStream.on("done", this.trigger.bind(this, "done"));
				addPipelineLogRetriggers(this, pipeline);
			};
			this.setupTsPipeline = function() {
				var pipeline = {};
				this.transmuxPipeline_ = pipeline;
				pipeline.type = "ts";
				pipeline.metadataStream = new m2ts.MetadataStream();
				pipeline.packetStream = new m2ts.TransportPacketStream();
				pipeline.parseStream = new m2ts.TransportParseStream();
				pipeline.elementaryStream = new m2ts.ElementaryStream();
				pipeline.timestampRolloverStream = new m2ts.TimestampRolloverStream();
				pipeline.adtsStream = new AdtsStream();
				pipeline.h264Stream = new H264Stream();
				pipeline.captionStream = new m2ts.CaptionStream(options);
				pipeline.coalesceStream = new _CoalesceStream(options, pipeline.metadataStream);
				pipeline.headOfPipeline = pipeline.packetStream;
				pipeline.packetStream.pipe(pipeline.parseStream).pipe(pipeline.elementaryStream).pipe(pipeline.timestampRolloverStream);
				pipeline.timestampRolloverStream.pipe(pipeline.h264Stream);
				pipeline.timestampRolloverStream.pipe(pipeline.adtsStream);
				pipeline.timestampRolloverStream.pipe(pipeline.metadataStream).pipe(pipeline.coalesceStream);
				pipeline.h264Stream.pipe(pipeline.captionStream).pipe(pipeline.coalesceStream);
				pipeline.elementaryStream.on("data", function(data) {
					var i;
					if (data.type === "metadata") {
						i = data.tracks.length;
						while (i--) if (!videoTrack && data.tracks[i].type === "video") {
							videoTrack = data.tracks[i];
							videoTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime;
						} else if (!audioTrack && data.tracks[i].type === "audio") {
							audioTrack = data.tracks[i];
							audioTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime;
						}
						if (videoTrack && !pipeline.videoSegmentStream) {
							pipeline.coalesceStream.numberOfTracks++;
							pipeline.videoSegmentStream = new _VideoSegmentStream(videoTrack, options);
							pipeline.videoSegmentStream.on("log", self.getLogTrigger_("videoSegmentStream"));
							pipeline.videoSegmentStream.on("timelineStartInfo", function(timelineStartInfo) {
								if (audioTrack && !options.keepOriginalTimestamps) {
									audioTrack.timelineStartInfo = timelineStartInfo;
									pipeline.audioSegmentStream.setEarliestDts(timelineStartInfo.dts - self.baseMediaDecodeTime);
								}
							});
							pipeline.videoSegmentStream.on("processedGopsInfo", self.trigger.bind(self, "gopInfo"));
							pipeline.videoSegmentStream.on("segmentTimingInfo", self.trigger.bind(self, "videoSegmentTimingInfo"));
							pipeline.videoSegmentStream.on("baseMediaDecodeTime", function(baseMediaDecodeTime) {
								if (audioTrack) pipeline.audioSegmentStream.setVideoBaseMediaDecodeTime(baseMediaDecodeTime);
							});
							pipeline.videoSegmentStream.on("timingInfo", self.trigger.bind(self, "videoTimingInfo"));
							pipeline.h264Stream.pipe(pipeline.videoSegmentStream).pipe(pipeline.coalesceStream);
						}
						if (audioTrack && !pipeline.audioSegmentStream) {
							pipeline.coalesceStream.numberOfTracks++;
							pipeline.audioSegmentStream = new _AudioSegmentStream(audioTrack, options);
							pipeline.audioSegmentStream.on("log", self.getLogTrigger_("audioSegmentStream"));
							pipeline.audioSegmentStream.on("timingInfo", self.trigger.bind(self, "audioTimingInfo"));
							pipeline.audioSegmentStream.on("segmentTimingInfo", self.trigger.bind(self, "audioSegmentTimingInfo"));
							pipeline.adtsStream.pipe(pipeline.audioSegmentStream).pipe(pipeline.coalesceStream);
						}
						self.trigger("trackinfo", {
							hasAudio: !!audioTrack,
							hasVideo: !!videoTrack
						});
					}
				});
				pipeline.coalesceStream.on("data", this.trigger.bind(this, "data"));
				pipeline.coalesceStream.on("id3Frame", function(id3Frame) {
					id3Frame.dispatchType = pipeline.metadataStream.dispatchType;
					self.trigger("id3Frame", id3Frame);
				});
				pipeline.coalesceStream.on("caption", this.trigger.bind(this, "caption"));
				pipeline.coalesceStream.on("done", this.trigger.bind(this, "done"));
				addPipelineLogRetriggers(this, pipeline);
			};
			this.setBaseMediaDecodeTime = function(baseMediaDecodeTime) {
				var pipeline = this.transmuxPipeline_;
				if (!options.keepOriginalTimestamps) this.baseMediaDecodeTime = baseMediaDecodeTime;
				if (audioTrack) {
					audioTrack.timelineStartInfo.dts = void 0;
					audioTrack.timelineStartInfo.pts = void 0;
					trackDecodeInfo.clearDtsInfo(audioTrack);
					if (pipeline.audioTimestampRolloverStream) pipeline.audioTimestampRolloverStream.discontinuity();
				}
				if (videoTrack) {
					if (pipeline.videoSegmentStream) pipeline.videoSegmentStream.gopCache_ = [];
					videoTrack.timelineStartInfo.dts = void 0;
					videoTrack.timelineStartInfo.pts = void 0;
					trackDecodeInfo.clearDtsInfo(videoTrack);
					pipeline.captionStream.reset();
				}
				if (pipeline.timestampRolloverStream) pipeline.timestampRolloverStream.discontinuity();
			};
			this.setAudioAppendStart = function(timestamp) {
				if (audioTrack) this.transmuxPipeline_.audioSegmentStream.setAudioAppendStart(timestamp);
			};
			this.setRemux = function(val) {
				var pipeline = this.transmuxPipeline_;
				options.remux = val;
				if (pipeline && pipeline.coalesceStream) pipeline.coalesceStream.setRemux(val);
			};
			this.alignGopsWith = function(gopsToAlignWith) {
				if (videoTrack && this.transmuxPipeline_.videoSegmentStream) this.transmuxPipeline_.videoSegmentStream.alignGopsWith(gopsToAlignWith);
			};
			this.getLogTrigger_ = function(key) {
				var self = this;
				return function(event) {
					event.stream = key;
					self.trigger("log", event);
				};
			};
			this.push = function(data) {
				if (hasFlushed) {
					var isAac = isLikelyAacData(data);
					if (isAac && this.transmuxPipeline_.type !== "aac") this.setupAacPipeline();
					else if (!isAac && this.transmuxPipeline_.type !== "ts") this.setupTsPipeline();
					hasFlushed = false;
				}
				this.transmuxPipeline_.headOfPipeline.push(data);
			};
			this.flush = function() {
				hasFlushed = true;
				this.transmuxPipeline_.headOfPipeline.flush();
			};
			this.endTimeline = function() {
				this.transmuxPipeline_.headOfPipeline.endTimeline();
			};
			this.reset = function() {
				if (this.transmuxPipeline_.headOfPipeline) this.transmuxPipeline_.headOfPipeline.reset();
			};
			this.resetCaptions = function() {
				if (this.transmuxPipeline_.captionStream) this.transmuxPipeline_.captionStream.reset();
			};
		};
		_Transmuxer.prototype = new Stream();
		module.exports = {
			Transmuxer: _Transmuxer,
			VideoSegmentStream: _VideoSegmentStream,
			AudioSegmentStream: _AudioSegmentStream,
			AUDIO_PROPERTIES,
			VIDEO_PROPERTIES,
			generateSegmentTimingInfo
		};
	})))();
	//#endregion
	//#region src/features/clipDownloads/transmuxerSession.ts
	const ISOLATED_TRACK_TYPES = /* @__PURE__ */ new Set(["audio", "video"]);
	function createTransmuxerSession(transmuxer) {
		let firstInitSegment;
		let pendingSegments = [];
		transmuxer.on("data", (segment) => {
			pendingSegments.push(segment);
		});
		function push(bytes) {
			transmuxer.push(bytes);
		}
		function flush() {
			pendingSegments = [];
			transmuxer.flush();
			const isolatedTrackRecovered = pendingSegments.length === 0 && firstInitSegment !== void 0;
			if (isolatedTrackRecovered) try {
				transmuxer.setRemux(false);
				transmuxer.flush();
			} finally {
				transmuxer.setRemux(true);
			}
			if (pendingSegments.length !== 1) throw new Error("The segment produced an unexpected output layout.");
			const [segment] = pendingSegments;
			pendingSegments = [];
			if (segment.type !== "combined" && !(isolatedTrackRecovered && ISOLATED_TRACK_TYPES.has(segment.type))) throw new Error("The clip did not produce supported audio and video tracks.");
			if (segment.data.byteLength > 8388608) throw new Error("The MP4 fragment exceeds the safe output limit.");
			let initSegment;
			if (segment.type === "combined") {
				if (!firstInitSegment) {
					firstInitSegment = segment.initSegment.slice();
					initSegment = firstInitSegment.slice();
				} else if (!equalBytes(firstInitSegment, segment.initSegment)) throw new Error("The clip track metadata changes during playback.");
			}
			return {
				data: segment.data,
				...initSegment ? { initSegment } : {}
			};
		}
		return {
			flush,
			push
		};
	}
	function equalBytes(left, right) {
		if (left.byteLength !== right.byteLength) return false;
		for (let index = 0; index < left.byteLength; index += 1) if (left[index] !== right[index]) return false;
		return true;
	}
	//#endregion
	//#region src/features/clipDownloads/download.worker.ts
	const worker = self;
	const session = createTransmuxerSession(new import_transmuxer.Transmuxer({ remux: true }));
	worker.onmessage = (event) => {
		const message = event.data;
		try {
			if (message.type === "cancel") {
				worker.close();
				return;
			}
			if (message.type === "push") {
				session.push(new Uint8Array(message.bytes));
				respond({
					requestId: message.requestId,
					type: "pushed"
				});
				return;
			}
			const fragment = session.flush();
			const data = toTransferBuffer(fragment.data);
			const initSegment = fragment.initSegment ? toTransferBuffer(fragment.initSegment) : void 0;
			respond({
				data,
				...initSegment ? { initSegment } : {},
				requestId: message.requestId,
				type: "fragment"
			}, initSegment ? [initSegment, data] : [data]);
		} catch {
			respond({
				message: "The clip could not be converted to MP4.",
				requestId: message.type === "cancel" ? void 0 : message.requestId,
				type: "error"
			});
		}
	};
	function respond(message, transfer = []) {
		worker.postMessage(message, transfer);
	}
	function toTransferBuffer(bytes) {
		if (bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength && bytes.buffer instanceof ArrayBuffer) return bytes.buffer;
		return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
	}
	//#endregion
})();
`;
	var blob = typeof self !== "undefined" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", jsContent], { type: "text/javascript;charset=utf-8" });
	function WorkerWrapper(options) {
		let objURL;
		try {
			objURL = blob && (self.URL || self.webkitURL).createObjectURL(blob);
			if (!objURL) throw "";
			const worker = new Worker(objURL, { name: options?.name });
			worker.addEventListener("error", () => {
				(self.URL || self.webkitURL).revokeObjectURL(objURL);
			});
			return worker;
		} catch (e) {
			return new Worker("data:text/javascript;charset=utf-8," + encodeURIComponent(jsContent), { name: options?.name });
		}
	}
	var TransmuxWorkerClient = class {
		worker = new WorkerWrapper();
		nextRequestId = 1;
		pending = new Map();
		constructor() {
			this.worker.onmessage = (event) => {
				const message = event.data;
				if (message.type === "error") {
					const error = new ClipDownloadError("transmuxing", message.message);
					if (message.requestId !== void 0) this.rejectRequest(message.requestId, error);
					else this.rejectAll(error);
					return;
				}
				const request = this.pending.get(message.requestId);
				if (!request) return;
				this.pending.delete(message.requestId);
				request.resolve(message);
			};
			this.worker.onerror = () => {
				this.rejectAll(new ClipDownloadError("transmuxing", "The MP4 conversion worker stopped unexpectedly."));
			};
		}
		async push(bytes) {
			const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
			if ((await this.request({
				bytes: buffer,
				requestId: this.nextRequestId,
				type: "push"
			}, [buffer])).type !== "pushed") throw unexpectedResponse();
		}
		async flush() {
			const response = await this.request({
				requestId: this.nextRequestId,
				type: "flush"
			});
			if (response.type !== "fragment") throw unexpectedResponse();
			return {
				data: new Uint8Array(response.data),
				...response.initSegment ? { initSegment: new Uint8Array(response.initSegment) } : {}
			};
		}
		terminate(reason = "The MP4 conversion was cancelled.") {
			this.worker.postMessage({ type: "cancel" });
			this.worker.terminate();
			this.rejectAll(new ClipDownloadError("cancelled", reason));
		}
		request(message, transfer = []) {
			const requestId = message.requestId;
			this.nextRequestId += 1;
			return new Promise((resolve, reject) => {
				this.pending.set(requestId, {
					reject,
					resolve
				});
				this.worker.postMessage(message, transfer);
			});
		}
		rejectRequest(requestId, error) {
			const request = this.pending.get(requestId);
			if (!request) return;
			this.pending.delete(requestId);
			request.reject(error);
		}
		rejectAll(error) {
			for (const request of this.pending.values()) request.reject(error);
			this.pending.clear();
		}
	};
	function unexpectedResponse() {
		return new ClipDownloadError("transmuxing", "The MP4 conversion worker returned an invalid response.");
	}
	var WORKER_INPUT_CHUNK_BYTES = 256 * 1024;
	async function downloadMediaPlan(plan, sink, signal, { createWorker = () => new TransmuxWorkerClient(), fetchImplementation = fetch, onProgress = () => void 0 } = {}) {
		if (plan.kind === "direct-mp4") {
			await downloadDirectMp4(plan.url, plan.sourceBytes, sink, signal, fetchImplementation, onProgress);
			return;
		}
		const worker = createWorker();
		let completedSegments = 0;
		let fetchedBytes = 0;
		let processedBytes = 0;
		let writtenBytes = 0;
		try {
			for (const segment of plan.segments) {
				assertNotAborted(signal);
				const segmentBytes = await pushSegment(segment, worker, signal, fetchImplementation, (chunkBytes) => {
					fetchedBytes += chunkBytes;
					onProgress({
						completedSegments,
						fetchedBytes,
						phase: "fetching",
						processedBytes,
						writtenBytes
					});
				});
				onProgress({
					completedSegments,
					fetchedBytes,
					phase: "transmuxing",
					processedBytes,
					writtenBytes
				});
				const fragment = await worker.flush();
				processedBytes += segmentBytes;
				onProgress({
					completedSegments,
					fetchedBytes,
					phase: "writing",
					processedBytes,
					writtenBytes
				});
				if (fragment.initSegment) await sink.write(fragment.initSegment);
				await sink.write(fragment.data);
				writtenBytes += segmentBytes;
				completedSegments += 1;
				onProgress({
					completedSegments,
					fetchedBytes,
					phase: "fetching",
					processedBytes,
					writtenBytes
				});
			}
		} finally {
			worker.terminate();
		}
	}
	async function pushSegment(segment, worker, signal, fetchImplementation, onFetched) {
		if (segment.length !== void 0 && segment.offset !== void 0) {
			const end = segment.offset + segment.length - 1;
			const response = await fetchImplementation(segment.url, {
				headers: { Range: `bytes=${segment.offset}-${end}` },
				signal
			});
			validateFinalMediaUrl(response);
			if (response.status !== 206) {
				await response.body?.cancel();
				throw new ClipDownloadError("media-request", "The media server did not honor a required byte range.");
			}
			const contentRange = parseContentRange(response.headers.get("content-range"));
			if (contentRange.start !== segment.offset || contentRange.end !== end || contentRange.total <= end) {
				await response.body?.cancel();
				throw new ClipDownloadError("media-request", "The media server returned an unexpected byte range.");
			}
			return streamSegmentResponse(response, segment.length, worker, signal, onFetched);
		}
		const response = await fetchImplementation(segment.url, { signal });
		validateFinalMediaUrl(response);
		if (!response.ok) throw new ClipDownloadError("media-request", "A clip media segment could not be downloaded.");
		return streamSegmentResponse(response, void 0, worker, signal, onFetched);
	}
	async function streamSegmentResponse(response, expectedBytes, worker, signal, onFetched) {
		const reader = response.body?.getReader();
		if (!reader) throw new ClipDownloadError("media-request", "A clip media segment did not contain a readable body.");
		let segmentBytes = 0;
		try {
			while (true) {
				const { done, value } = await reader.read();
				if (done) break;
				segmentBytes += value.byteLength;
				if (segmentBytes > 8388608) {
					await reader.cancel();
					throw new ClipDownloadError("unsupported-media", "A clip segment exceeds the safe processing limit.");
				}
				onFetched(value.byteLength);
				await pushBoundedChunks(value, worker, signal);
			}
		} finally {
			reader.releaseLock();
		}
		if (expectedBytes !== void 0 && segmentBytes !== expectedBytes) throw new ClipDownloadError("media-request", "A clip media segment was truncated.");
		return segmentBytes;
	}
	async function pushBoundedChunks(bytes, worker, signal) {
		for (let offset = 0; offset < bytes.byteLength; offset += WORKER_INPUT_CHUNK_BYTES) {
			assertNotAborted(signal);
			await worker.push(bytes.subarray(offset, offset + WORKER_INPUT_CHUNK_BYTES));
		}
	}
	async function downloadDirectMp4(url, expectedBytes, sink, signal, fetchImplementation, onProgress) {
		const response = await fetchImplementation(url, { signal });
		validateFinalMediaUrl(response);
		if (!response.ok) throw new ClipDownloadError("media-request", "The MP4 clip could not be downloaded.");
		const reader = response.body?.getReader();
		if (!reader) throw new ClipDownloadError("media-request", "The MP4 response did not contain a readable body.");
		let fetchedBytes = 0;
		let pendingChunks = [];
		const signaturePrefix = new Uint8Array(64);
		let signatureBytes = 0;
		let signatureChecked = false;
		let writtenBytes = 0;
		try {
			while (true) {
				const { done, value } = await reader.read();
				if (done) break;
				assertNotAborted(signal);
				fetchedBytes += value.byteLength;
				if (!signatureChecked) {
					pendingChunks.push(value);
					const copyBytes = Math.min(signaturePrefix.byteLength - signatureBytes, value.byteLength);
					signaturePrefix.set(value.subarray(0, copyBytes), signatureBytes);
					signatureBytes += copyBytes;
					if (signatureBytes < signaturePrefix.byteLength) continue;
					if (!isMp4Prefix(signaturePrefix)) {
						await reader.cancel();
						throw new ClipDownloadError("media-request", "The direct media response is no longer a valid MP4 file.");
					}
					signatureChecked = true;
					for (const pendingChunk of pendingChunks) writtenBytes = await writeDirectChunk(pendingChunk, sink, fetchedBytes, onProgress, writtenBytes);
					pendingChunks = [];
					continue;
				}
				writtenBytes = await writeDirectChunk(value, sink, fetchedBytes, onProgress, writtenBytes);
			}
		} finally {
			reader.releaseLock();
		}
		if (!signatureChecked) {
			if (!isMp4Prefix(signaturePrefix.subarray(0, signatureBytes))) throw new ClipDownloadError("media-request", "The direct media response is no longer a valid MP4 file.");
			for (const pendingChunk of pendingChunks) writtenBytes = await writeDirectChunk(pendingChunk, sink, fetchedBytes, onProgress, writtenBytes);
		}
		if (expectedBytes !== void 0 && fetchedBytes !== expectedBytes) throw new ClipDownloadError("media-request", "The MP4 response size changed after inspection.");
		onProgress({
			completedSegments: 1,
			fetchedBytes,
			phase: "writing",
			processedBytes: fetchedBytes,
			writtenBytes: fetchedBytes
		});
	}
	async function writeDirectChunk(bytes, sink, fetchedBytes, onProgress, startingWrittenBytes) {
		let chunkWritten = 0;
		for (let offset = 0; offset < bytes.byteLength; offset += MAX_INPUT_BYTES) {
			const chunk = bytes.subarray(offset, offset + MAX_INPUT_BYTES);
			onProgress({
				completedSegments: 0,
				fetchedBytes,
				phase: "writing",
				processedBytes: fetchedBytes,
				writtenBytes: startingWrittenBytes + chunkWritten
			});
			await sink.write(chunk);
			chunkWritten += chunk.byteLength;
		}
		onProgress({
			completedSegments: 0,
			fetchedBytes,
			phase: "fetching",
			processedBytes: fetchedBytes,
			writtenBytes: startingWrittenBytes + chunkWritten
		});
		return startingWrittenBytes + chunkWritten;
	}
	function isMp4Prefix(bytes) {
		const searchEnd = Math.min(64, bytes.byteLength - 4);
		for (let index = 4; index <= searchEnd; index += 1) if (bytes[index] === 102 && bytes[index + 1] === 116 && bytes[index + 2] === 121 && bytes[index + 3] === 112) return true;
		return false;
	}
	function assertNotAborted(signal) {
		if (signal.aborted) throw signal.reason instanceof Error ? signal.reason : new DOMException("The operation was aborted.", "AbortError");
	}
	function getSaveFilePicker() {
		const browserWindow = window;
		return browserWindow.showSaveFilePicker?.bind(browserWindow);
	}
	async function createFileSystemSink(handle) {
		let writable;
		try {
			try {
				writable = await handle.createWritable({
					keepExistingData: false,
					mode: "exclusive"
				});
			} catch (error) {
				if (!(error instanceof TypeError)) throw error;
				writable = await handle.createWritable({ keepExistingData: false });
			}
		} catch (error) {
			throw new ClipDownloadError("file-access", error instanceof DOMException && error.name === "NotAllowedError" ? "Permission to write the selected file was denied." : "The selected file could not be opened for writing.");
		}
		return {
			abort: async (reason) => {
				try {
					await writable.abort(reason);
				} catch {}
			},
			close: async () => {
				try {
					await writable.close();
				} catch {
					throw new ClipDownloadError("file-write", "The MP4 file could not be finalized.");
				}
			},
			filename: handle.name,
			write: async (bytes) => {
				try {
					await writable.write(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));
				} catch {
					throw new ClipDownloadError("file-write", "The MP4 file could not be written.");
				}
			}
		};
	}
	function createBlobSink(filename, triggerDownload = triggerBlobDownload) {
		let parts = [];
		let closed = false;
		return {
			abort: async () => {
				parts = [];
				closed = true;
			},
			close: async () => {
				if (closed) return;
				const blob = new Blob(parts, { type: "video/mp4" });
				parts = [];
				closed = true;
				triggerDownload(blob, filename);
			},
			filename,
			write: async (bytes) => {
				if (closed) throw new ClipDownloadError("file-write", "The memory-backed output is already closed.");
				parts.push(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));
			}
		};
	}
	function triggerBlobDownload(blob, filename) {
		const url = URL.createObjectURL(blob);
		const anchor = document.createElement("a");
		anchor.download = filename;
		anchor.href = url;
		anchor.style.display = "none";
		document.body.append(anchor);
		anchor.click();
		anchor.remove();
		window.setTimeout(() => URL.revokeObjectURL(url), 0);
	}
	var INVALID_FILENAME_CHARACTERS = /[\u0000-\u001f<>:"/\\|?*]/g;
	var RESERVED_WINDOWS_NAME = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/i;
	var MAX_BASENAME_LENGTH = 180;
	function createDefaultBasename({ channel, clipId, title }) {
		const candidates = [
			channel && title ? `${channel} - ${title}` : void 0,
			title,
			channel ? `${channel} - ${clipId}` : void 0,
			clipId
		];
		for (const candidate of candidates) {
			if (!candidate) continue;
			const sanitized = sanitizeBasename(candidate, clipId);
			if (sanitized) return sanitized;
		}
		return clipId;
	}
	function sanitizeBasename(value, fallback) {
		let basename = value.replace(INVALID_FILENAME_CHARACTERS, " ").replace(/\s+/g, " ").trim().replace(/[ .]+$/g, "");
		if (basename.length > MAX_BASENAME_LENGTH) basename = basename.slice(0, MAX_BASENAME_LENGTH).trimEnd();
		if (RESERVED_WINDOWS_NAME.test(basename)) basename = `${basename}_`;
		if (!basename) basename = fallback.replace(INVALID_FILENAME_CHARACTERS, " ").trim();
		return basename || "kick-clip";
	}
	function createMp4Filename(basename, fallback) {
		return `${sanitizeBasename(basename, fallback)}.mp4`;
	}
	var TERMINAL_STATUSES = new Set([
		"cancelled",
		"completed",
		"failed"
	]);
	var REMOVABLE_STATUSES = new Set([...TERMINAL_STATUSES, "ready"]);
	var ACTIVE_STATUSES = new Set([
		"active",
		"choosing-destination",
		"inspecting"
	]);
	var ATTENTION_STATUSES = new Set(["awaiting-destination", "ready"]);
	var MAX_INSPECTIONS = 2;
	var PROGRESS_INTERVAL_MS = 100;
	var nextJobNumber = 1;
	function createDownloadManager(dependencies) {
		const jobs = new Map();
		const runtimes = new Map();
		const listeners = new Set();
		const inspectionQueue = [];
		const mediaQueue = [];
		let activeInspections = 0;
		let reservedMediaJobId;
		function publish() {
			for (const listener of listeners) listener();
		}
		function getSnapshot() {
			return { jobs: [...jobs.values()].map((job) => ({
				...job,
				queuePosition: job.status === "queued" ? mediaQueue.indexOf(job.id) + 1 : void 0
			})) };
		}
		function inspectClip(clipId, pageUrl = window.location.href) {
			const existing = [...jobs.values()].find((job) => job.clipId === clipId && !TERMINAL_STATUSES.has(job.status));
			if (existing) return existing.id;
			const id = createJobId();
			const job = {
				acknowledged: false,
				basename: clipId,
				clipId,
				completedSegments: 0,
				createdAt: dependencies.now(),
				fetchedBytes: 0,
				filename: `${clipId}.mp4`,
				id,
				pageUrl,
				phase: "inspecting",
				processedBytes: 0,
				status: "inspecting",
				writtenBytes: 0
			};
			jobs.set(id, job);
			runtimes.set(id, { generation: 0 });
			inspectionQueue.push(id);
			publish();
			drainInspectionQueue();
			return id;
		}
		function drainInspectionQueue() {
			while (activeInspections < MAX_INSPECTIONS && inspectionQueue.length > 0) {
				const jobId = inspectionQueue.shift();
				const job = jobId ? jobs.get(jobId) : void 0;
				if (!job || job.status !== "inspecting") continue;
				activeInspections += 1;
				runInspection(job).finally(() => {
					activeInspections -= 1;
					drainInspectionQueue();
				});
			}
		}
		async function runInspection(job) {
			const runtime = getRuntime(job.id);
			const generation = runtime.generation + 1;
			const abortController = new AbortController();
			runtime.generation = generation;
			runtime.abortController = abortController;
			try {
				const inspection = await dependencies.inspectClip(job.clipId, abortController.signal, { pageUrl: job.pageUrl });
				if (!isCurrent(job.id, generation)) return;
				applyInspection(job, runtime, inspection);
				publish();
			} catch (error) {
				if (!isCurrent(job.id, generation)) return;
				const displayError = toDisplayError(error);
				job.phase = void 0;
				job.status = displayError.code === "cancelled" ? "cancelled" : "failed";
				job.error = displayError.code === "cancelled" ? void 0 : displayError;
				job.completedAt = dependencies.now();
				job.acknowledged = false;
				publish();
			} finally {
				if (isCurrent(job.id, generation)) runtime.abortController = void 0;
			}
		}
		function applyInspection(job, runtime, inspection) {
			const { metadata, plan } = inspection;
			const basename = createDefaultBasename({
				channel: metadata.channel,
				clipId: job.clipId,
				title: metadata.title
			});
			const media = summarizeMediaPlan(plan);
			runtime.plan = plan;
			job.basename = basename;
			job.category = metadata.category;
			job.channel = metadata.channel;
			job.creator = metadata.creator;
			job.error = void 0;
			job.filename = createMp4Filename(basename, job.clipId);
			job.likeCount = metadata.likeCount;
			job.media = {
				...media,
				duration: media.duration ?? metadata.duration
			};
			job.pageUrl = metadata.pageUrl;
			job.phase = void 0;
			job.publishedAt = metadata.publishedAt;
			job.status = "ready";
			job.thumbnailUrl = metadata.thumbnailUrl;
			job.title = metadata.title;
			job.viewCount = metadata.viewCount;
			job.acknowledged = false;
		}
		function updateBasename(jobId, value) {
			const job = jobs.get(jobId);
			if (!job || job.status !== "ready") return;
			job.basename = value;
			job.filename = createMp4Filename(value, job.clipId);
			publish();
		}
		function requestDownload(jobId, strategy) {
			const job = jobs.get(jobId);
			const runtime = runtimes.get(jobId);
			if (!job || !runtime || job.status !== "ready" || !runtime.plan) return;
			job.basename = sanitizeBasename(job.basename, job.clipId);
			job.filename = createMp4Filename(job.basename, job.clipId);
			job.error = void 0;
			job.saveStrategy = strategy;
			runtime.saveStrategy = strategy;
			if (reservedMediaJobId) {
				job.status = "queued";
				mediaQueue.push(jobId);
				publish();
				return;
			}
			reservedMediaJobId = jobId;
			if (strategy === "file-system") chooseDestination(jobId);
			else startReservedJob(jobId);
		}
		async function chooseDestination(jobId) {
			const job = jobs.get(jobId);
			const runtime = runtimes.get(jobId);
			if (!job || !runtime || reservedMediaJobId !== jobId || !runtime.plan || job.status !== "ready" && job.status !== "awaiting-destination") return;
			const picker = dependencies.getSaveFilePicker();
			if (!picker) {
				returnFileAccessToReady(job, "Direct file access is unavailable. Use the memory-backed download.");
				releaseMediaSlot(jobId);
				return;
			}
			job.status = "choosing-destination";
			publish();
			let handle;
			try {
				handle = await picker({
					excludeAcceptAllOption: true,
					suggestedName: job.filename,
					types: [{
						accept: { "video/mp4": [".mp4"] },
						description: "MP4 video"
					}]
				});
			} catch (error) {
				if (error instanceof DOMException && error.name === "AbortError") {
					job.status = "ready";
					job.error = void 0;
				} else returnFileAccessToReady(job, "The file destination could not be selected. You can try again or use the memory-backed download.");
				releaseMediaSlot(jobId);
				return;
			}
			if (reservedMediaJobId !== jobId || job.status !== "choosing-destination") return;
			try {
				runtime.sink = await dependencies.createFileSystemSink(handle);
				job.filename = runtime.sink.filename;
			} catch (error) {
				returnFileAccessToReady(job, toDisplayError(error).message);
				releaseMediaSlot(jobId);
				return;
			}
			await startReservedJob(jobId);
		}
		async function startReservedJob(jobId) {
			const job = jobs.get(jobId);
			const runtime = runtimes.get(jobId);
			if (!job || !runtime || !runtime.plan || reservedMediaJobId !== jobId) return;
			const sink = runtime.sink ?? dependencies.createBlobSink(job.filename);
			const abortController = new AbortController();
			const generation = runtime.generation + 1;
			runtime.abortController = abortController;
			runtime.generation = generation;
			runtime.sink = sink;
			job.acknowledged = false;
			job.completedAt = void 0;
			job.completedSegments = 0;
			job.error = void 0;
			job.fetchedBytes = 0;
			job.phase = "fetching";
			job.processedBytes = 0;
			job.startedAt = dependencies.now();
			job.status = "active";
			job.writtenBytes = 0;
			publish();
			try {
				await dependencies.downloadMediaPlan(runtime.plan, sink, abortController.signal, { onProgress: (progress) => {
					publishProgress(jobId, generation, progress);
				} });
				await sink.close();
				if (!isCurrent(jobId, generation)) return;
				flushProgressTimer(runtime);
				job.completedAt = dependencies.now();
				job.phase = void 0;
				job.status = "completed";
				job.acknowledged = false;
				cleanupAttempt(runtime);
				releaseMediaSlot(jobId);
			} catch (error) {
				if (!isCurrent(jobId, generation)) return;
				await sink.abort(error);
				const displayError = toDisplayError(error);
				flushProgressTimer(runtime);
				job.completedAt = dependencies.now();
				job.error = displayError.code === "cancelled" ? void 0 : displayError;
				job.phase = void 0;
				job.status = displayError.code === "cancelled" ? "cancelled" : "failed";
				job.acknowledged = false;
				cleanupAttempt(runtime);
				releaseMediaSlot(jobId);
			}
		}
		function publishProgress(jobId, generation, progress) {
			const job = jobs.get(jobId);
			const runtime = runtimes.get(jobId);
			if (!job || !runtime || !isCurrent(jobId, generation)) return;
			job.completedSegments = progress.completedSegments;
			job.fetchedBytes = progress.fetchedBytes;
			job.phase = progress.phase;
			job.processedBytes = progress.processedBytes;
			job.writtenBytes = progress.writtenBytes;
			if (runtime.progressTimer) return;
			runtime.progressTimer = setTimeout(() => {
				runtime.progressTimer = void 0;
				if (isCurrent(jobId, generation)) publish();
			}, PROGRESS_INTERVAL_MS);
		}
		function cancel(jobId) {
			const job = jobs.get(jobId);
			const runtime = runtimes.get(jobId);
			if (!job || !runtime || TERMINAL_STATUSES.has(job.status)) return;
			runtime.generation += 1;
			runtime.abortController?.abort(new DOMException("The operation was cancelled.", "AbortError"));
			runtime.sink?.abort("cancelled");
			flushProgressTimer(runtime);
			removeFromQueue(inspectionQueue, jobId);
			removeFromQueue(mediaQueue, jobId);
			job.completedAt = dependencies.now();
			job.error = void 0;
			job.phase = void 0;
			job.status = "cancelled";
			job.acknowledged = false;
			cleanupAttempt(runtime);
			if (reservedMediaJobId === jobId) releaseMediaSlot(jobId);
			else publish();
		}
		function retry(jobId) {
			const job = jobs.get(jobId);
			const runtime = runtimes.get(jobId);
			if (!job || !runtime || !TERMINAL_STATUSES.has(job.status)) return;
			runtime.generation += 1;
			job.acknowledged = false;
			job.completedAt = void 0;
			job.completedSegments = 0;
			job.error = void 0;
			job.fetchedBytes = 0;
			job.processedBytes = 0;
			job.saveStrategy = void 0;
			job.startedAt = void 0;
			job.writtenBytes = 0;
			if (runtime.plan) {
				job.phase = void 0;
				job.status = "ready";
				publish();
			} else {
				job.phase = "inspecting";
				job.status = "inspecting";
				inspectionQueue.push(jobId);
				publish();
				drainInspectionQueue();
			}
		}
		function remove(jobId) {
			const job = jobs.get(jobId);
			const runtime = runtimes.get(jobId);
			if (!job || !runtime || !REMOVABLE_STATUSES.has(job.status)) return;
			flushProgressTimer(runtime);
			jobs.delete(jobId);
			runtimes.delete(jobId);
			publish();
		}
		function clearInactive() {
			let changed = false;
			for (const [jobId, job] of jobs) {
				if (!REMOVABLE_STATUSES.has(job.status)) continue;
				const runtime = runtimes.get(jobId);
				if (runtime) flushProgressTimer(runtime);
				jobs.delete(jobId);
				runtimes.delete(jobId);
				changed = true;
			}
			if (changed) publish();
		}
		function acknowledgeAttention() {
			let changed = false;
			for (const job of jobs.values()) if (TERMINAL_STATUSES.has(job.status) && !job.acknowledged) {
				job.acknowledged = true;
				changed = true;
			}
			if (changed) publish();
		}
		function getActivitySummary() {
			const visibleJobs = [...jobs.values()];
			const activeCount = visibleJobs.filter((job) => ACTIVE_STATUSES.has(job.status)).length;
			const queuedCount = visibleJobs.filter((job) => job.status === "queued" || job.status === "awaiting-destination").length;
			const attention = visibleJobs.some((job) => TERMINAL_STATUSES.has(job.status) && !job.acknowledged) || visibleJobs.some((job) => ATTENTION_STATUSES.has(job.status));
			return {
				activeCount,
				attention,
				error: visibleJobs.some((job) => job.status === "failed" && !job.acknowledged),
				queuedCount,
				visible: activeCount > 0 || queuedCount > 0 || attention
			};
		}
		function releaseMediaSlot(jobId) {
			if (reservedMediaJobId === jobId) reservedMediaJobId = void 0;
			advanceMediaQueue();
			publish();
		}
		function advanceMediaQueue() {
			if (reservedMediaJobId) return;
			while (mediaQueue.length > 0) {
				const jobId = mediaQueue.shift();
				const job = jobId ? jobs.get(jobId) : void 0;
				const runtime = jobId ? runtimes.get(jobId) : void 0;
				if (!jobId || !job || !runtime || job.status !== "queued") continue;
				reservedMediaJobId = jobId;
				if (runtime.saveStrategy === "file-system") {
					job.status = "awaiting-destination";
					job.acknowledged = false;
				} else startReservedJob(jobId);
				return;
			}
		}
		function returnFileAccessToReady(job, message) {
			job.error = {
				code: "file-access",
				message
			};
			job.phase = void 0;
			job.status = "ready";
			job.acknowledged = false;
		}
		function cleanupAttempt(runtime) {
			runtime.abortController = void 0;
			runtime.sink = void 0;
			runtime.saveStrategy = void 0;
		}
		function flushProgressTimer(runtime) {
			if (runtime.progressTimer) {
				clearTimeout(runtime.progressTimer);
				runtime.progressTimer = void 0;
			}
		}
		function isCurrent(jobId, generation) {
			return runtimes.get(jobId)?.generation === generation;
		}
		function getRuntime(jobId) {
			const runtime = runtimes.get(jobId);
			if (!runtime) throw new Error(`Missing runtime for download job ${jobId}.`);
			return runtime;
		}
		return {
			acknowledgeAttention,
			cancel,
			chooseDestination,
			clearInactive,
			getActivitySummary,
			getSnapshot,
			inspectClip,
			remove,
			requestDownload,
			retry,
			subscribe(listener) {
				listeners.add(listener);
				return () => {
					listeners.delete(listener);
				};
			},
			updateBasename
		};
	}
	function createJobId() {
		const id = `clip-download-${nextJobNumber}`;
		nextJobNumber += 1;
		return id;
	}
	function removeFromQueue(queue, jobId) {
		const index = queue.indexOf(jobId);
		if (index !== -1) queue.splice(index, 1);
	}
	var downloadManager = createDownloadManager({
		createBlobSink,
		createFileSystemSink,
		downloadMediaPlan,
		getSaveFilePicker,
		inspectClip,
		now: Date.now
	});
	var listeners = new Set();
	var snapshot = { open: false };
	function publish(update) {
		snapshot = update;
		for (const listener of listeners) listener();
	}
	function openDownloadCenterForClip(clipId, pageUrl = window.location.href) {
		const jobId = downloadManager.inspectClip(clipId, pageUrl);
		openDownloadCenter(jobId);
		return jobId;
	}
	function openDownloadCenter(focusedJobId) {
		downloadManager.acknowledgeAttention();
		publish({
			focusedJobId: focusedJobId ?? snapshot.focusedJobId,
			open: true
		});
	}
	function focusDownloadJob(focusedJobId) {
		publish({
			focusedJobId,
			open: snapshot.open
		});
	}
	function minimizeDownloadCenter() {
		publish({
			...snapshot,
			open: false
		});
	}
	function getDownloadCenterSnapshot() {
		return snapshot;
	}
	function subscribeDownloadCenter(listener) {
		listeners.add(listener);
		return () => {
			listeners.delete(listener);
		};
	}
	var MINIMUM_ESTIMATE_AGE_MS = 1e3;
	function estimateDownloadTransfer(fetchedBytes, totalBytes, startedAt, now) {
		if (fetchedBytes <= 0 || startedAt === void 0 || now - startedAt < MINIMUM_ESTIMATE_AGE_MS) return;
		const bytesPerSecond = fetchedBytes / ((now - startedAt) / 1e3);
		if (!Number.isFinite(bytesPerSecond) || bytesPerSecond <= 0) return;
		const remainingBytes = totalBytes === void 0 ? void 0 : Math.max(0, totalBytes - fetchedBytes);
		return {
			bytesPerSecond,
			remainingSeconds: remainingBytes === void 0 || remainingBytes === 0 ? void 0 : remainingBytes / bytesPerSecond
		};
	}
	function useDownloads() {
		const [snapshot, setSnapshot] = (0, preact_hooks.useState)(downloadManager.getSnapshot);
		(0, preact_hooks.useEffect)(() => downloadManager.subscribe(() => {
			setSnapshot(downloadManager.getSnapshot());
		}), []);
		return snapshot;
	}
	function useDownloadActivity() {
		const [summary, setSummary] = (0, preact_hooks.useState)(downloadManager.getActivitySummary);
		(0, preact_hooks.useEffect)(() => downloadManager.subscribe(() => {
			const next = downloadManager.getActivitySummary();
			setSummary((current) => activityEquals(current, next) ? current : next);
		}), []);
		return summary;
	}
	function useDownloadCenter() {
		const [snapshot, setSnapshot] = (0, preact_hooks.useState)(getDownloadCenterSnapshot);
		(0, preact_hooks.useEffect)(() => subscribeDownloadCenter(() => {
			setSnapshot(getDownloadCenterSnapshot());
		}), []);
		return snapshot;
	}
	function activityEquals(left, right) {
		return left.activeCount === right.activeCount && left.attention === right.attention && left.error === right.error && left.queuedCount === right.queuedCount && left.visible === right.visible;
	}
	var MEMORY_WARNING_BYTES = 128 * 1024 * 1024;
	var CLIP_DATE_FORMATTER = new Intl.DateTimeFormat(void 0, {
		day: "numeric",
		month: "short",
		year: "numeric"
	});
	var COUNT_FORMATTER = new Intl.NumberFormat();
	var DOWNLOAD_COLUMNS = [
		{
			header: "Clip",
			id: "clip",
			renderCell: (job) => (0, preact_jsx_runtime.jsxs)("div", {
				className: "ke-download-queue__clip",
				children: [job.thumbnailUrl ? (0, preact_jsx_runtime.jsx)("img", {
					alt: "",
					className: "ke-download-queue__thumbnail",
					referrerPolicy: "no-referrer",
					src: job.thumbnailUrl
				}) : null, (0, preact_jsx_runtime.jsx)("span", {
					className: "ke-download-queue__title",
					children: job.title ?? job.clipId
				})]
			}),
			width: "minmax(12rem, 1fr)"
		},
		{
			align: "center",
			header: "Channel",
			id: "channel",
			renderCell: (job) => job.channel ?? "Unknown",
			width: "9rem"
		},
		{
			align: "center",
			header: "Status",
			id: "status",
			renderCell: (job) => (0, preact_jsx_runtime.jsx)("span", {
				className: "ke-download-queue__status",
				"data-status": job.status,
				children: formatStatus(job)
			}),
			width: "9rem"
		},
		{
			align: "center",
			header: "Duration",
			id: "duration",
			renderCell: (job) => formatDuration(job.media?.duration),
			width: "5.5rem"
		},
		{
			align: "center",
			header: "Size",
			id: "size",
			renderCell: (job) => job.media?.sourceBytes ? formatBytes(job.media.sourceBytes) : "Unknown",
			width: "6.5rem"
		}
	];
	function clearInactiveDownloads() {
		downloadManager.clearInactive();
		closeDownloadCenterIfEmpty();
	}
	function removeDownload(jobId) {
		downloadManager.remove(jobId);
		closeDownloadCenterIfEmpty();
	}
	function closeDownloadCenterIfEmpty() {
		if (downloadManager.getSnapshot().jobs.length === 0) minimizeDownloadCenter();
	}
	function DownloadCenter() {
		const center = useDownloadCenter();
		const { activeCount } = useDownloadActivity();
		const { jobs } = useDownloads();
		const [activeTab, setActiveTab] = (0, preact_hooks.useState)("selected");
		const listedJobs = jobs.filter((job) => job.media !== void 0);
		const focusedJob = jobs.find(({ id }) => id === center.focusedJobId) ?? jobs.at(-1);
		(0, preact_hooks.useEffect)(() => {
			if (center.open && !focusedJob) minimizeDownloadCenter();
		}, [center.open, focusedJob]);
		(0, preact_hooks.useEffect)(() => {
			if (center.open && focusedJob && focusedJob.id !== center.focusedJobId) focusDownloadJob(focusedJob.id);
		}, [
			center.focusedJobId,
			center.open,
			focusedJob
		]);
		(0, preact_hooks.useEffect)(() => {
			if (center.open && center.focusedJobId) setActiveTab("selected");
		}, [center.focusedJobId, center.open]);
		return (0, preact_jsx_runtime.jsx)(Modal, {
			className: "ke-workspace-modal ke-download-center",
			closeLabel: "Close Download Manager",
			description: "Manage clip downloads.",
			footer: (0, preact_jsx_runtime.jsxs)(preact_jsx_runtime.Fragment, { children: [(0, preact_jsx_runtime.jsx)(Button, {
				disabled: !jobs.some((job) => [
					"cancelled",
					"completed",
					"failed",
					"ready"
				].includes(job.status)),
				onClick: clearInactiveDownloads,
				children: "Clear inactive"
			}), (0, preact_jsx_runtime.jsx)(Button, {
				className: "ke-button--primary",
				onClick: minimizeDownloadCenter,
				children: "Hide"
			})] }),
			icon: icon_default,
			onRequestClose: minimizeDownloadCenter,
			open: center.open,
			title: "Download Manager",
			children: (0, preact_jsx_runtime.jsx)(Tabs, {
				ariaLabel: "Download Manager views",
				className: "ke-download-center__tabs",
				onChange: setActiveTab,
				tabs: [{
					content: focusedJob ? (0, preact_jsx_runtime.jsx)(DownloadJobDetail, { job: focusedJob }) : (0, preact_jsx_runtime.jsx)("div", {
						className: "ke-download-center__placeholder",
						children: "No clip selected."
					}),
					contentClassName: "ke-download-center__selected-panel",
					disabled: !focusedJob,
					id: "selected",
					label: "Selected",
					panelAriaLabel: "Selected clip download details"
				}, {
					content: (0, preact_jsx_runtime.jsx)(DownloadQueue, {
						focusedJobId: focusedJob?.id,
						jobs: listedJobs,
						onSelect: (jobId) => {
							focusDownloadJob(jobId);
							setActiveTab("selected");
						}
					}),
					contentClassName: "ke-download-center__downloads-panel",
					id: "downloads",
					label: (0, preact_jsx_runtime.jsxs)("span", {
						className: "ke-download-center__tab-label",
						children: ["Downloads", activeCount > 0 ? (0, preact_jsx_runtime.jsx)(LoadingSpinnerIcon, { class: "ke-icon ke-download-center__activity-indicator ke-icon--spinner" }) : null]
					}),
					panelAriaLabel: "Clip download queue and history"
				}],
				value: activeTab
			})
		});
	}
	function DownloadQueue({ focusedJobId, jobs, onSelect }) {
		return (0, preact_jsx_runtime.jsx)(ListView, {
			ariaLabel: "Clip downloads",
			ariaLive: "polite",
			className: "ke-download-queue",
			columns: DOWNLOAD_COLUMNS,
			emptyContent: null,
			getItemKey: (job) => job.id,
			getRowAriaLabel: (job) => `View ${job.title ?? job.clipId}, ${formatStatus(job)}`,
			getRowClassName: (job) => job.id === focusedJobId ? "ke-download-queue__row--selected" : void 0,
			items: jobs,
			onItemActivate: (job) => onSelect(job.id)
		});
	}
	function DownloadJobDetail({ job }) {
		if (job.status === "inspecting") return (0, preact_jsx_runtime.jsxs)("section", {
			"aria-live": "polite",
			className: "ke-download-detail-loading",
			role: "status",
			children: [(0, preact_jsx_runtime.jsx)(LoadingSpinnerIcon, { class: "ke-icon ke-download-detail-loading__icon ke-icon--spinner" }), (0, preact_jsx_runtime.jsx)("p", { children: "Loading clip…" })]
		});
		return (0, preact_jsx_runtime.jsxs)("article", {
			className: "ke-download-detail",
			children: [
				(0, preact_jsx_runtime.jsxs)("section", {
					className: `ke-download-detail__summary${job.thumbnailUrl ? "" : " has-no-thumbnail"}`,
					children: [job.thumbnailUrl ? (0, preact_jsx_runtime.jsx)("div", {
						className: "ke-download-detail__thumbnail-frame",
						children: (0, preact_jsx_runtime.jsx)("img", {
							alt: "",
							className: "ke-download-detail__thumbnail",
							referrerPolicy: "no-referrer",
							src: job.thumbnailUrl
						})
					}) : null, (0, preact_jsx_runtime.jsxs)("div", {
						className: "ke-download-detail__overview",
						children: [(0, preact_jsx_runtime.jsx)("header", {
							className: "ke-download-detail__header",
							children: (0, preact_jsx_runtime.jsxs)("div", {
								className: "ke-download-detail__identity",
								children: [
									job.category || job.publishedAt ? (0, preact_jsx_runtime.jsxs)("div", {
										className: "ke-download-detail__context",
										children: [job.category ? (0, preact_jsx_runtime.jsx)("span", {
											className: "ke-download-detail__category",
											children: job.category
										}) : null, job.publishedAt ? (0, preact_jsx_runtime.jsx)("time", {
											dateTime: new Date(job.publishedAt).toISOString(),
											children: CLIP_DATE_FORMATTER.format(job.publishedAt)
										}) : null]
									}) : null,
									(0, preact_jsx_runtime.jsx)("h3", {
										className: "ke-download-detail__title",
										children: job.channel ? (0, preact_jsx_runtime.jsx)("a", {
											className: "ke-download-detail__title-link",
											href: `https://kick.com/${encodeURIComponent(job.channel)}/clips/${encodeURIComponent(job.clipId)}`,
											rel: "noreferrer",
											target: "_blank",
											children: job.title ?? "KICK clip"
										}) : job.title ?? "KICK clip"
									}),
									(0, preact_jsx_runtime.jsxs)("p", {
										className: "ke-download-detail__metadata",
										children: [job.channel ? (0, preact_jsx_runtime.jsx)("a", {
											className: "ke-download-detail__channel",
											href: `https://kick.com/${encodeURIComponent(job.channel)}`,
											rel: "noreferrer",
											target: "_blank",
											children: job.channel
										}) : "Unknown channel", job.creator ? (0, preact_jsx_runtime.jsxs)(preact_jsx_runtime.Fragment, { children: [(0, preact_jsx_runtime.jsx)("span", {
											"aria-hidden": "true",
											className: "ke-download-detail__separator",
											children: "–"
										}), (0, preact_jsx_runtime.jsxs)("span", { children: [
											"Clipped by",
											" ",
											(0, preact_jsx_runtime.jsx)("a", {
												className: "ke-download-detail__creator",
												href: `https://kick.com/${encodeURIComponent(job.creator)}`,
												rel: "noreferrer",
												target: "_blank",
												children: job.creator
											})
										] })] }) : null]
									})
								]
							})
						}), job.media ? (0, preact_jsx_runtime.jsx)(MediaFacts, { job }) : null]
					})]
				}),
				job.status === "ready" ? (0, preact_jsx_runtime.jsx)(ReadyView, { job }) : null,
				job.status === "queued" ? (0, preact_jsx_runtime.jsx)(StatusPanel, {
					message: `Waiting in queue${job.queuePosition ? ` (position ${job.queuePosition})` : ""}.`,
					children: (0, preact_jsx_runtime.jsx)(Button, {
						onClick: () => downloadManager.cancel(job.id),
						children: "Cancel"
					})
				}) : null,
				job.status === "awaiting-destination" ? (0, preact_jsx_runtime.jsxs)(StatusPanel, {
					message: "This download is next. Choose its destination to start.",
					children: [(0, preact_jsx_runtime.jsx)(Button, {
						className: "ke-button--primary",
						onClick: () => {
							downloadManager.chooseDestination(job.id);
						},
						children: "Choose file and start"
					}), (0, preact_jsx_runtime.jsx)(Button, {
						onClick: () => downloadManager.cancel(job.id),
						children: "Cancel"
					})]
				}) : null,
				job.status === "choosing-destination" ? (0, preact_jsx_runtime.jsx)(StatusPanel, {
					icon: true,
					message: "Waiting for a file destination…"
				}) : null,
				job.status === "active" ? (0, preact_jsx_runtime.jsx)(ActiveView, { job }) : null,
				job.status === "completed" ? (0, preact_jsx_runtime.jsx)(TerminalView, {
					job,
					message: `Saved ${job.filename}`,
					primaryLabel: "Download again"
				}) : null,
				job.status === "failed" ? (0, preact_jsx_runtime.jsx)(TerminalView, {
					job,
					message: job.error?.message ?? "The clip download failed.",
					primaryLabel: "Retry"
				}) : null,
				job.status === "cancelled" ? (0, preact_jsx_runtime.jsx)(TerminalView, {
					job,
					message: "The download was cancelled.",
					primaryLabel: "Retry"
				}) : null
			]
		});
	}
	function ReadyView({ job }) {
		const hasFilePicker = Boolean(getSaveFilePicker());
		const isLargeFallback = job.media?.sourceBytes !== void 0 && job.media.sourceBytes >= MEMORY_WARNING_BYTES;
		return (0, preact_jsx_runtime.jsxs)("form", {
			className: "ke-download-ready",
			onSubmit: (event) => {
				event.preventDefault();
				downloadManager.requestDownload(job.id, hasFilePicker ? "file-system" : "memory");
			},
			children: [
				(0, preact_jsx_runtime.jsx)(TextField, {
					label: "Output filename",
					maxLength: 180,
					onValueChange: (value) => downloadManager.updateBasename(job.id, value),
					suffix: ".mp4",
					value: job.basename
				}),
				job.error ? (0, preact_jsx_runtime.jsx)("p", {
					className: "ke-download-message is-error",
					role: "alert",
					children: job.error.message
				}) : null,
				!hasFilePicker && isLargeFallback ? (0, preact_jsx_runtime.jsx)("p", {
					className: "ke-download-message is-warning",
					children: "This browser must keep the final MP4 in memory. The clip is unusually large, so close memory-heavy tabs before continuing."
				}) : null,
				hasFilePicker ? (0, preact_jsx_runtime.jsx)("p", {
					className: "ke-download-message",
					children: "If you select an existing file, the browser may clear it before processing finishes."
				}) : null,
				(0, preact_jsx_runtime.jsxs)("div", {
					className: "ke-download-actions",
					children: [
						(0, preact_jsx_runtime.jsx)(Button, {
							className: "ke-button--primary",
							type: "submit",
							children: "Download"
						}),
						hasFilePicker ? (0, preact_jsx_runtime.jsx)(Button, {
							onClick: () => downloadManager.requestDownload(job.id, "memory"),
							children: "Use memory download"
						}) : null,
						(0, preact_jsx_runtime.jsx)(Button, {
							onClick: () => removeDownload(job.id),
							children: "Remove"
						})
					]
				})
			]
		});
	}
	function ActiveView({ job }) {
		const total = job.media?.sourceBytes;
		const percentage = total && total > 0 ? Math.min(100, job.writtenBytes / total * 100) : void 0;
		return (0, preact_jsx_runtime.jsxs)("section", {
			className: "ke-download-active",
			children: [(0, preact_jsx_runtime.jsxs)("div", {
				className: "ke-download-progress",
				children: [(0, preact_jsx_runtime.jsxs)("div", {
					className: "ke-download-progress__heading",
					children: [(0, preact_jsx_runtime.jsx)("span", { children: job.phase === "fetching" ? formatFetchingStatus(job, Date.now()) : formatPhase(job.phase) }), (0, preact_jsx_runtime.jsxs)("span", { children: [formatBytes(job.writtenBytes), total ? ` of ${formatBytes(total)} - ${percentage?.toFixed(1)}%` : ` - ${job.completedSegments}/${job.media?.logicalSegmentCount ?? "?"} segments`] })]
				}), (0, preact_jsx_runtime.jsx)("progress", {
					"aria-label": "Download progress",
					className: "ke-download-progress__bar",
					max: total ?? void 0,
					value: total ? job.writtenBytes : void 0
				})]
			}), (0, preact_jsx_runtime.jsx)("div", {
				className: "ke-download-actions",
				children: (0, preact_jsx_runtime.jsx)(Button, {
					tone: "danger",
					onClick: () => downloadManager.cancel(job.id),
					children: "Cancel"
				})
			})]
		});
	}
	function TerminalView({ job, message, primaryLabel }) {
		return (0, preact_jsx_runtime.jsxs)(StatusPanel, {
			error: job.status === "failed",
			message,
			children: [(0, preact_jsx_runtime.jsx)(Button, {
				className: "ke-button--primary",
				onClick: () => downloadManager.retry(job.id),
				children: primaryLabel
			}), (0, preact_jsx_runtime.jsx)(Button, {
				onClick: () => removeDownload(job.id),
				children: "Remove"
			})]
		});
	}
	function MediaFacts({ job }) {
		const media = job.media;
		if (!media) return null;
		return (0, preact_jsx_runtime.jsxs)("dl", {
			className: "ke-download-facts",
			children: [
				(0, preact_jsx_runtime.jsxs)("div", { children: [(0, preact_jsx_runtime.jsx)("dt", { children: "Duration" }), (0, preact_jsx_runtime.jsx)("dd", { children: formatDuration(media.duration) })] }),
				(0, preact_jsx_runtime.jsxs)("div", { children: [(0, preact_jsx_runtime.jsx)("dt", { children: "Download size" }), (0, preact_jsx_runtime.jsxs)("dd", { children: [media.sourceBytes ? formatBytes(media.sourceBytes) : "Unknown", (0, preact_jsx_runtime.jsxs)("span", {
					className: "ke-download-facts__secondary",
					children: [
						" ",
						"(",
						media.logicalSegmentCount,
						" ",
						media.logicalSegmentCount === 1 ? "segment" : "segments",
						")"
					]
				})] })] }),
				job.viewCount !== void 0 ? (0, preact_jsx_runtime.jsxs)("div", { children: [(0, preact_jsx_runtime.jsx)("dt", { children: "Views" }), (0, preact_jsx_runtime.jsx)("dd", { children: COUNT_FORMATTER.format(job.viewCount) })] }) : null,
				job.likeCount !== void 0 ? (0, preact_jsx_runtime.jsxs)("div", { children: [(0, preact_jsx_runtime.jsx)("dt", { children: "Likes" }), (0, preact_jsx_runtime.jsx)("dd", { children: COUNT_FORMATTER.format(job.likeCount) })] }) : null
			]
		});
	}
	function StatusPanel({ children, error = false, icon = false, message }) {
		return (0, preact_jsx_runtime.jsxs)("section", {
			className: "ke-download-status",
			children: [(0, preact_jsx_runtime.jsxs)("p", {
				className: `ke-download-message${error ? " is-error" : ""}`,
				role: error ? "alert" : "status",
				children: [icon ? (0, preact_jsx_runtime.jsx)(LoadingSpinnerIcon, { class: "ke-icon ke-icon--spinner" }) : null, (0, preact_jsx_runtime.jsx)("span", { children: message })]
			}), children ? (0, preact_jsx_runtime.jsx)("div", {
				className: "ke-download-actions",
				children
			}) : null]
		});
	}
	function formatStatus(job) {
		return {
			active: formatPhase(job.phase),
			"awaiting-destination": "Choose file",
			cancelled: "Cancelled",
			"choosing-destination": "Choosing file",
			completed: "Completed",
			failed: "Failed",
			inspecting: "Inspecting",
			queued: job.queuePosition ? `Queued ${job.queuePosition}` : "Queued",
			ready: "Ready"
		}[job.status];
	}
	function formatPhase(phase) {
		return phase ? {
			fetching: "Downloading",
			inspecting: "Inspecting",
			transmuxing: "Converting to MP4",
			writing: "Writing MP4"
		}[phase] : "Working";
	}
	function formatFetchingStatus(job, now) {
		const segmentCount = job.media?.logicalSegmentCount;
		const label = segmentCount && segmentCount > 1 ? `Segment ${Math.min(segmentCount, job.completedSegments + 1)}/${segmentCount}` : "Downloading";
		const estimate = estimateDownloadTransfer(job.fetchedBytes, job.media?.sourceBytes, job.startedAt, now);
		if (!estimate) return label;
		const remaining = estimate.remainingSeconds === void 0 ? "" : ` - ${formatRemainingTime(estimate.remainingSeconds)} remaining`;
		return `${label}: ${formatBytes(estimate.bytesPerSecond)}/s${remaining}`;
	}
	function formatRemainingTime(duration) {
		const seconds = Math.max(1, Math.ceil(duration));
		const hours = Math.floor(seconds / 3600);
		const minutes = Math.floor(seconds % 3600 / 60);
		const remainingSeconds = seconds % 60;
		if (hours > 0) return `${hours}h ${minutes}m`;
		if (minutes > 0) return `${minutes}m ${remainingSeconds}s`;
		return `${remainingSeconds}s`;
	}
	function formatBytes(bytes) {
		if (bytes < 1024) return `${bytes} B`;
		const units = [
			"KiB",
			"MiB",
			"GiB"
		];
		let value = bytes / 1024;
		let unit = units[0];
		for (let index = 1; index < units.length && value >= 1024; index += 1) {
			value /= 1024;
			unit = units[index];
		}
		return `${value.toFixed(value >= 100 ? 0 : 1)} ${unit}`;
	}
	function formatDuration(duration) {
		if (!duration) return "Unknown";
		const seconds = Math.round(duration);
		return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}`;
	}
	function createClipCardReconciler({ isCardConnected, isMountConnected, mount, resolve, unmount, update }) {
		const mountedByCard = new WeakMap();
		const mountedCards = new Set();
		function removeMountedCard(mounted) {
			unmount(mounted.mount);
			mountedByCard.delete(mounted.card);
			mountedCards.delete(mounted);
		}
		function reconcile(card) {
			const mounted = mountedByCard.get(card);
			const resolution = resolve(card);
			if (!resolution) {
				if (mounted) removeMountedCard(mounted);
				return;
			}
			if (mounted && mounted.container === resolution.container && isMountConnected(mounted.mount)) {
				if (mounted.clipId !== resolution.clipId) {
					mounted.clipId = resolution.clipId;
					update(mounted.mount, resolution);
				}
				return;
			}
			if (mounted) removeMountedCard(mounted);
			const mountedCard = {
				card,
				clipId: resolution.clipId,
				container: resolution.container,
				mount: mount(resolution)
			};
			mountedByCard.set(card, mountedCard);
			mountedCards.add(mountedCard);
		}
		return {
			reconcile,
			removeDisconnected() {
				for (const mounted of mountedCards) if (!isCardConnected(mounted.card) || !isMountConnected(mounted.mount)) removeMountedCard(mounted);
			},
			teardown() {
				for (const mounted of [...mountedCards]) removeMountedCard(mounted);
			}
		};
	}
	var clipDownloads_default = ".ke-clip-download-host {\n  display: contents;\n}\n\n.ke-download-center-host {\n  display: contents;\n}\n\n.ke-direct-clip-download-host {\n  position: relative;\n  display: flex;\n  flex: 0 0 auto;\n}\n\n.ke-direct-clip-download-action {\n  display: flex;\n  box-sizing: border-box;\n  width: auto;\n  height: 2.5rem;\n  flex: 0 0 auto;\n  align-items: center;\n  justify-content: center;\n  padding: 0 0.5rem;\n  gap: 0.15rem;\n  border: 0;\n  border-radius: 0.25rem;\n  outline: 0;\n  background: #212931;\n  color: var(--neon-secondary-onSecondary, #fff);\n  cursor: pointer;\n  transition: none;\n}\n.ke-direct-clip-download-action:hover {\n  background: #2d3442;\n}\n.ke-direct-clip-download-action:focus-visible {\n  outline: 2px solid #fff;\n  outline-offset: 2px;\n}\n.ke-direct-clip-download-action:active {\n  transform: scale(0.95);\n}\n.ke-direct-clip-download-action__brand {\n  display: block;\n  width: 1.05rem;\n  height: 1.05rem;\n  flex: 0 0 auto;\n  object-fit: contain;\n  pointer-events: none;\n}\n.ke-direct-clip-download-action__icon {\n  display: block;\n  width: 1rem;\n  height: 1rem;\n  flex: 0 0 auto;\n  pointer-events: none;\n}\n\n.ke-direct-clip-download-tooltip {\n  position: absolute;\n  z-index: 1000;\n  bottom: calc(100% + 0.5rem);\n  left: 50%;\n  width: max-content;\n  max-width: 16rem;\n  padding: 0.35rem 0.5rem;\n  visibility: hidden;\n  border-radius: 0.25rem;\n  background: #232629;\n  color: #fff;\n  font-size: 0.75rem;\n  font-weight: 600;\n  line-height: 1.25;\n  opacity: 0;\n  pointer-events: none;\n  transform: translateX(-50%);\n}\n.ke-direct-clip-download-tooltip::after {\n  position: absolute;\n  top: 100%;\n  left: 50%;\n  border: 0.3rem solid transparent;\n  border-top-color: #232629;\n  content: \"\";\n  transform: translateX(-50%);\n}\n\n.ke-direct-clip-download-host:hover .ke-direct-clip-download-tooltip,\n.ke-direct-clip-download-host:focus-within .ke-direct-clip-download-tooltip {\n  visibility: visible;\n  opacity: 1;\n}\n\n.ke-clip-download-action {\n  position: absolute;\n  top: 4px;\n  right: 4px;\n  z-index: 203;\n  display: flex;\n  box-sizing: border-box;\n  align-items: center;\n  justify-content: center;\n  width: 1.75rem;\n  height: 1.75rem;\n  padding: 0;\n  border: 0;\n  border-radius: 4px;\n  outline: 0;\n  background: rgba(0, 0, 0, 0.82);\n  color: #fff;\n  backdrop-filter: blur(2px);\n  cursor: pointer;\n  transition: none;\n}\n.ke-clip-download-action:hover {\n  border: 0;\n  background: rgba(0, 0, 0, 0.82);\n  box-shadow: none;\n  color: #53fc18;\n  transform: none;\n}\n.ke-clip-download-action:hover > .ke-clip-download-action__icon {\n  transform: none;\n}\n.ke-clip-download-action:focus-visible {\n  outline: 2px solid #fff;\n  outline-offset: 2px;\n}\n.ke-clip-download-action:active {\n  transform: scale(0.94);\n}\n.ke-clip-download-action__icon {\n  display: block;\n  width: 1.125rem;\n  height: 1.125rem;\n  pointer-events: none;\n  transition: none;\n}";
	var downloadCenter_default = ".ke-modal.ke-download-center {\n  --ke-workspace-modal-height: 36rem;\n  --ke-workspace-modal-width: 68rem;\n}\n\n.ke-download-center__tabs {\n  min-width: 0;\n  min-height: 0;\n}\n\n.ke-download-center__tab-label {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.5rem;\n}\n\n.ke-download-center__activity-indicator {\n  color: #53fc18;\n}\n\n.ke-tabs__panel-content.ke-download-center__selected-panel {\n  width: 100%;\n  height: 100%;\n  min-height: 100%;\n  padding: 0;\n}\n\n.ke-tabs__panel-content.ke-download-center__downloads-panel {\n  position: relative;\n  min-height: 100%;\n  padding: 0;\n}\n\n.ke-download-center__placeholder {\n  margin: 0;\n  padding: 1rem;\n  color: #8c8c8c;\n  font-size: 0.8rem;\n  text-align: center;\n}\n\n.ke-list-view.ke-download-queue {\n  position: absolute;\n  inset: 0;\n  border: 0;\n  border-radius: 0;\n  background-color: #080808;\n}\n\n.ke-download-queue__clip {\n  display: flex;\n  min-width: 0;\n  align-items: center;\n  gap: 0.65rem;\n}\n\n.ke-download-queue__thumbnail {\n  width: 3.5rem;\n  aspect-ratio: 16/9;\n  flex: 0 0 auto;\n  border-radius: 0.25rem;\n  object-fit: cover;\n  background: #0a0a0a;\n}\n\n.ke-download-queue__title {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  color: #f2f2f2;\n  font-weight: 700;\n}\n\n.ke-download-queue .ke-list-view__row {\n  min-height: 0;\n}\n\n.ke-download-queue__row--selected {\n  box-shadow: inset 0.2rem 0 #53fc18;\n}\n\n.ke-download-queue__status {\n  display: inline-flex;\n  max-width: 100%;\n  align-items: center;\n  padding: 0.15rem 0.45rem;\n  overflow: hidden;\n  border: 1px solid #303030;\n  border-radius: 0.3rem;\n  color: #8c8c8c;\n  font-size: 0.68rem;\n  font-weight: 700;\n  line-height: 1.35;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.ke-download-queue__status[data-status=active], .ke-download-queue__status[data-status=ready] {\n  border-color: rgba(83, 252, 24, 0.4);\n  color: #53fc18;\n}\n.ke-download-queue__status[data-status=awaiting-destination], .ke-download-queue__status[data-status=choosing-destination], .ke-download-queue__status[data-status=inspecting], .ke-download-queue__status[data-status=queued] {\n  border-color: rgba(242, 184, 75, 0.4);\n  color: #f2b84b;\n}\n.ke-download-queue__status[data-status=completed] {\n  border-color: rgba(101, 169, 255, 0.4);\n  color: #65a9ff;\n}\n.ke-download-queue__status[data-status=failed] {\n  border-color: rgba(255, 107, 107, 0.45);\n  color: #ff6b6b;\n}\n\n.ke-download-detail {\n  display: flex;\n  min-height: 100%;\n  flex-direction: column;\n  padding: 1.5rem;\n  gap: 1.5rem;\n}\n\n.ke-download-detail-loading {\n  display: flex;\n  width: 100%;\n  height: 100%;\n  align-items: center;\n  justify-content: center;\n  flex-direction: column;\n  gap: 0.65rem;\n  color: #8c8c8c;\n}\n.ke-download-detail-loading p {\n  margin: 0;\n  font-size: 0.8rem;\n}\n\n.ke-download-detail-loading__icon {\n  width: 1.35rem;\n  height: 1.35rem;\n  color: #f2f2f2;\n}\n\n.ke-download-detail__summary {\n  display: grid;\n  min-width: 0;\n  grid-template-columns: minmax(18rem, 24rem) minmax(0, 1fr);\n  align-items: start;\n  gap: 1.5rem;\n}\n.ke-download-detail__summary.has-no-thumbnail {\n  grid-template-columns: minmax(0, 1fr);\n}\n\n.ke-download-detail__overview {\n  min-width: 0;\n  padding-top: 0;\n}\n\n.ke-download-detail__header {\n  display: flex;\n  min-width: 0;\n  align-items: center;\n  gap: 0.9rem;\n}\n\n.ke-download-detail__thumbnail-frame {\n  position: relative;\n  min-width: 0;\n  min-height: 0;\n  aspect-ratio: 16/9;\n  overflow: hidden;\n  border-radius: 0.25rem;\n  background: #0a0a0a;\n}\n\n.ke-download-detail__thumbnail {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 100%;\n  object-fit: cover;\n}\n\n.ke-download-detail__identity {\n  min-width: 0;\n  overflow: hidden;\n}\n\n.ke-download-detail__context {\n  display: flex;\n  min-width: 0;\n  align-items: center;\n  flex-wrap: wrap;\n  margin-bottom: 0.65rem;\n  gap: 0.55rem;\n  color: #747474;\n  font-size: 0.72rem;\n  font-weight: 500;\n}\n\n.ke-download-detail__category {\n  max-width: 100%;\n  padding: 0.12rem 0.45rem;\n  overflow: hidden;\n  border: 1px solid rgba(83, 252, 24, 0.4);\n  border-radius: 0.3rem;\n  color: #53fc18;\n  font-size: 0.68rem;\n  font-weight: 750;\n  line-height: 1.35;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.ke-download-detail__title {\n  width: 100%;\n  margin: 0;\n  overflow: hidden;\n  color: #f2f2f2;\n  font-size: 1.1rem;\n  font-weight: 700;\n  line-height: 1.25;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.ke-download-detail__title-link {\n  display: block;\n  overflow: hidden;\n  color: inherit;\n  text-decoration: none;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.ke-download-detail__title-link:hover {\n  text-decoration: underline;\n}\n\n.ke-download-detail__metadata {\n  display: flex;\n  align-items: baseline;\n  flex-wrap: wrap;\n  margin: 0.45rem 0 0;\n  gap: 0.4rem;\n  color: #8c8c8c;\n  font-size: 0.8rem;\n  font-weight: 500;\n}\n\n.ke-download-detail__channel,\n.ke-download-detail__creator {\n  text-decoration: none;\n}\n.ke-download-detail__channel:hover,\n.ke-download-detail__creator:hover {\n  text-decoration: underline;\n}\n\n.ke-download-detail__channel {\n  color: #53fc18;\n}\n\n.ke-download-detail__separator {\n  color: #747474;\n}\n\n.ke-download-detail__creator {\n  color: #f2f2f2;\n  font-weight: 650;\n}\n\n.ke-download-facts {\n  display: grid;\n  margin: 1rem 0 0;\n  grid-template-columns: repeat(2, minmax(0, 1fr));\n  border-top: 1px solid #1b1b1b;\n  border-bottom: 1px solid #1b1b1b;\n}\n.ke-download-facts div {\n  display: grid;\n  min-width: 0;\n  align-content: start;\n  padding: 0.65rem 0;\n  gap: 0.2rem;\n}\n.ke-download-facts div:nth-child(even) {\n  padding-left: 1rem;\n  border-left: 1px solid #1b1b1b;\n}\n.ke-download-facts div:nth-child(n+3) {\n  border-top: 1px solid #1b1b1b;\n}\n.ke-download-facts dt {\n  color: #747474;\n  font-size: 0.68rem;\n  font-weight: 700;\n  letter-spacing: 0.035em;\n  text-transform: uppercase;\n}\n.ke-download-facts dd {\n  margin: 0;\n  color: #f2f2f2;\n  font-size: 0.86rem;\n  font-weight: 700;\n  font-variant-numeric: tabular-nums;\n}\n\n.ke-download-facts__secondary {\n  color: #8c8c8c;\n  font-size: inherit;\n  font-weight: 600;\n  white-space: nowrap;\n}\n\n.ke-download-ready,\n.ke-download-active,\n.ke-download-status {\n  display: grid;\n  width: 100%;\n  min-height: 3.85rem;\n  grid-template-columns: minmax(0, 1fr) auto;\n  align-items: center;\n  margin-top: auto;\n  padding-top: 1.5rem;\n  border-top: 1px solid #1b1b1b;\n  gap: 1rem;\n}\n\n.ke-download-ready {\n  align-items: end;\n}\n.ke-download-ready > .ke-form-field .ke-form-field__label {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border: 0;\n}\n.ke-download-ready > .ke-download-message {\n  grid-column: 1/-1;\n}\n.ke-download-ready > .ke-download-actions {\n  grid-column: 2;\n  grid-row: 1;\n}\n\n.ke-download-active > .ke-download-actions {\n  align-self: stretch;\n  align-items: center;\n  padding-left: 1rem;\n  border-left: 1px solid #1b1b1b;\n}\n\n.ke-download-actions {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 0.65rem;\n}\n\n.ke-download-message {\n  display: flex;\n  align-items: center;\n  margin: 0;\n  gap: 0.55rem;\n  color: #8c8c8c;\n  font-size: 0.8rem;\n  line-height: 1.5;\n}\n.ke-download-message.is-error {\n  color: #ff6b6b;\n}\n.ke-download-message.is-warning {\n  padding: 0.65rem 0.75rem;\n  border: 1px solid #6c5528;\n  border-radius: 0.45rem;\n  background: #19150d;\n  color: #f5c451;\n}\n\n.ke-icon--spinner {\n  width: 1rem;\n  height: 1rem;\n  flex: 0 0 auto;\n  animation: ke-icon-spin 800ms linear infinite;\n}\n\n.ke-download-progress__heading {\n  display: flex;\n  justify-content: space-between;\n  gap: 1rem;\n  color: #f2f2f2;\n  font-size: 0.78rem;\n  font-variant-numeric: tabular-nums;\n}\n\n.ke-download-progress {\n  display: grid;\n  min-width: 0;\n  gap: 0.55rem;\n}\n\n.ke-download-progress__bar {\n  width: 100%;\n  height: 0.55rem;\n  overflow: hidden;\n  appearance: none;\n  border: 0;\n  border-radius: 999px;\n  background: #1b1b1b;\n}\n.ke-download-progress__bar::-webkit-progress-bar {\n  background: #1b1b1b;\n}\n.ke-download-progress__bar::-webkit-progress-value {\n  background: #53fc18;\n}\n.ke-download-progress__bar::-moz-progress-bar {\n  background: #53fc18;\n}\n\n@keyframes ke-icon-spin {\n  to {\n    transform: rotate(1turn);\n  }\n}\n@media (max-width: 44rem) {\n  .ke-download-detail__summary {\n    grid-template-columns: minmax(0, 1fr);\n  }\n  .ke-download-detail__overview {\n    padding-top: 0;\n  }\n  .ke-download-detail__thumbnail-frame {\n    display: none;\n  }\n}\n@media (max-width: 34rem) {\n  .ke-download-queue .ke-list-view__header,\n  .ke-download-queue .ke-list-view__row {\n    grid-template-columns: minmax(12rem, 1fr) 9rem !important;\n  }\n  .ke-download-queue :is(.ke-list-view__header-cell,\n  .ke-list-view__cell)[data-column-id=channel],\n  .ke-download-queue :is(.ke-list-view__header-cell,\n  .ke-list-view__cell)[data-column-id=duration],\n  .ke-download-queue :is(.ke-list-view__header-cell,\n  .ke-list-view__cell)[data-column-id=size] {\n    display: none;\n  }\n  .ke-download-detail {\n    padding: 1rem;\n    gap: 1rem;\n  }\n  .ke-download-detail__thumbnail-frame {\n    width: 100%;\n  }\n  .ke-download-ready,\n  .ke-download-active,\n  .ke-download-status {\n    min-height: 0;\n    grid-template-columns: 1fr;\n  }\n  .ke-download-ready > .ke-download-actions,\n  .ke-download-active > .ke-download-actions,\n  .ke-download-status > .ke-download-actions {\n    grid-column: 1;\n    grid-row: auto;\n  }\n  .ke-download-active > .ke-download-actions {\n    padding-top: 1rem;\n    padding-left: 0;\n    border-top: 1px solid #1b1b1b;\n    border-left: 0;\n  }\n}\n@media (prefers-reduced-motion: reduce) {\n  .ke-icon--spinner {\n    animation: none;\n  }\n}";
	var STYLE_ID$6 = "kick-enhancer-clip-download-styles";
	var CENTER_HOST_ID = "kick-enhancer-download-center";
	var ACTION_SELECTOR = "[data-ke-clip-download]";
	var HOST_SELECTOR = "[data-ke-clip-download-host]";
	var DIRECT_ACTION_ANCHOR_SELECTOR = "[data-testid=\"follow-button\"]";
	var DIRECT_HOST_SELECTOR = "[data-ke-direct-clip-download-host]";
	var log$7 = createLogger("clip-downloads");
	var stopActiveIntegration;
	function defaultSelectClip(clipId) {
		log$7.info("Manager opened", { clipId });
		openDownloadCenterForClip(clipId);
	}
	function installStyles$1() {
		installSharedUiStyles();
		if (document.getElementById(STYLE_ID$6)) return;
		const style = document.createElement("style");
		style.id = STYLE_ID$6;
		style.textContent = `${clipDownloads_default}\n${downloadCenter_default}`;
		document.documentElement.append(style);
	}
	function mountDownloadCenter() {
		if (document.getElementById(CENTER_HOST_ID) || !document.body) return;
		const host = document.createElement("span");
		host.id = CENTER_HOST_ID;
		host.className = "ke-download-center-host";
		document.body.append(host);
		(0, preact.render)((0, preact_jsx_runtime.jsx)(DownloadCenter, {}), host);
	}
	function startClipDownloadActions(onSelectClip = defaultSelectClip) {
		stopActiveIntegration?.();
		let observer;
		let actionsVisible = getSettings().ui.showClipDownloadButtons;
		let directActionClipId;
		let directActionHost;
		let stopWatchingSettings;
		let stopped = false;
		const reconciler = createClipCardReconciler({
			isCardConnected: (card) => card.isConnected,
			isMountConnected: (host) => host.isConnected,
			mount: ({ card, clipId, container }) => {
				for (const staleAction of card.querySelectorAll(ACTION_SELECTOR)) staleAction.remove();
				for (const staleHost of card.querySelectorAll(HOST_SELECTOR)) staleHost.remove();
				const host = document.createElement("span");
				host.className = "ke-clip-download-host";
				host.setAttribute("data-ke-clip-download-host", "");
				container.append(host);
				(0, preact.render)((0, preact_jsx_runtime.jsx)(ClipDownloadAction, {
					clipId,
					onSelectClip
				}), host);
				return host;
			},
			resolve: (card) => {
				const clipId = getClipIdFromCard(card, window.location.origin);
				const container = card.querySelector(CLIP_MODAL_BUTTON_SELECTOR)?.parentElement;
				return clipId && container ? {
					card,
					clipId,
					container
				} : void 0;
			},
			unmount: (host) => {
				(0, preact.render)(null, host);
				host.remove();
			},
			update: (host, { clipId }) => {
				(0, preact.render)((0, preact_jsx_runtime.jsx)(ClipDownloadAction, {
					clipId,
					onSelectClip
				}), host);
			}
		});
		const scheduler = createBatchedCardScheduler((cards) => {
			if (stopped || !actionsVisible) return;
			reconciler.removeDisconnected();
			for (const card of cards) if (card?.isConnected) reconciler.reconcile(card);
		});
		function removeDirectClipAction() {
			if (!directActionHost) return;
			(0, preact.render)(null, directActionHost);
			directActionHost.remove();
			directActionClipId = void 0;
			directActionHost = void 0;
		}
		function reconcileDirectClipAction() {
			if (directActionHost && !directActionHost.isConnected) {
				(0, preact.render)(null, directActionHost);
				directActionClipId = void 0;
				directActionHost = void 0;
			}
			const clipId = actionsVisible ? getClipIdFromHref(window.location.href, window.location.origin) : void 0;
			const anchor = clipId ? document.querySelector(DIRECT_ACTION_ANCHOR_SELECTOR) : void 0;
			const container = anchor?.parentElement;
			if (!clipId || !anchor || !container) {
				removeDirectClipAction();
				return;
			}
			if (directActionHost && directActionHost.parentElement === container) {
				if (directActionClipId !== clipId) {
					(0, preact.render)((0, preact_jsx_runtime.jsx)(DirectClipDownloadAction, {
						clipId,
						onSelectClip
					}), directActionHost);
					directActionClipId = clipId;
				}
				return;
			}
			removeDirectClipAction();
			for (const staleHost of document.querySelectorAll(DIRECT_HOST_SELECTOR)) staleHost.remove();
			const host = document.createElement("span");
			host.className = "ke-direct-clip-download-host";
			host.setAttribute("data-ke-direct-clip-download-host", "");
			anchor.after(host);
			(0, preact.render)((0, preact_jsx_runtime.jsx)(DirectClipDownloadAction, {
				clipId,
				onSelectClip
			}), host);
			directActionClipId = clipId;
			directActionHost = host;
		}
		function enqueueClosestCard(element) {
			const card = element.closest(CLIP_CARD_SELECTOR);
			if (card) scheduler.enqueue(card);
		}
		function enqueueCardsFromSubtree(node) {
			if (!(node instanceof Element)) return;
			enqueueClosestCard(node);
			for (const card of node.querySelectorAll(CLIP_CARD_SELECTOR)) scheduler.enqueue(card);
		}
		function handleMutations(records) {
			mountDownloadCenter();
			reconcileDirectClipAction();
			let shouldCleanDisconnectedActions = false;
			for (const record of records) {
				if (record.type === "attributes") {
					enqueueClosestCard(record.target);
					continue;
				}
				if (record.removedNodes.length > 0) shouldCleanDisconnectedActions = true;
				enqueueClosestCard(record.target);
				for (const node of record.addedNodes) enqueueCardsFromSubtree(node);
			}
			if (shouldCleanDisconnectedActions) scheduler.enqueue(void 0);
		}
		function beginObserving() {
			if (stopped) return;
			installStyles$1();
			mountDownloadCenter();
			reconcileDirectClipAction();
			if (actionsVisible) for (const card of document.querySelectorAll(CLIP_CARD_SELECTOR)) scheduler.enqueue(card);
			observer = new MutationObserver(handleMutations);
			observer.observe(document.documentElement, {
				attributeFilter: ["href"],
				attributes: true,
				childList: true,
				subtree: true
			});
		}
		const stopWaitingForDocument = onDocumentElementReady(beginObserving);
		stopWatchingSettings = observeSetting((settings) => settings.ui.showClipDownloadButtons, (visible) => {
			if (actionsVisible === visible) return;
			actionsVisible = visible;
			if (!visible) {
				reconciler.teardown();
				removeDirectClipAction();
				return;
			}
			reconcileDirectClipAction();
			for (const card of document.querySelectorAll(CLIP_CARD_SELECTOR)) scheduler.enqueue(card);
		});
		const stop = () => {
			if (stopped) return;
			stopped = true;
			stopWaitingForDocument();
			observer?.disconnect();
			stopWatchingSettings?.();
			scheduler.cancel();
			reconciler.teardown();
			removeDirectClipAction();
			const centerHost = document.getElementById(CENTER_HOST_ID);
			if (centerHost) {
				(0, preact.render)(null, centerHost);
				centerHost.remove();
			}
			document.getElementById(STYLE_ID$6)?.remove();
			if (stopActiveIntegration === stop) stopActiveIntegration = void 0;
		};
		stopActiveIntegration = stop;
		return stop;
	}
	var followingRecommendations_default = "[data-testid=following] [data-testid=followed-livestreams] + section {\n  display: none !important;\n}";
	function applyStyleToggle(id, styles, enabled) {
		const existingStyle = document.getElementById(id);
		if (!enabled) {
			existingStyle?.remove();
			return;
		}
		if (existingStyle) return;
		const style = document.createElement("style");
		style.id = id;
		style.textContent = styles;
		document.documentElement.append(style);
	}
	function createStyleSettingFeature({ id, selectEnabled, styles }) {
		let stopActiveFeature;
		return function startStyleSettingFeature() {
			stopActiveFeature?.();
			let stopped = false;
			const stopObserving = observeSetting(selectEnabled, (enabled) => applyStyleToggle(id, styles, enabled));
			const stop = () => {
				if (stopped) return;
				stopped = true;
				stopObserving();
				applyStyleToggle(id, styles, false);
				if (stopActiveFeature === stop) stopActiveFeature = void 0;
			};
			stopActiveFeature = stop;
			return stop;
		};
	}
	var startFollowingRecommendationsVisibility = createStyleSettingFeature({
		id: "kick-enhancer-hide-following-recommendations",
		selectEnabled: (settings) => settings.ui.hideFollowingRecommendations,
		styles: followingRecommendations_default
	});
	var gamblingStreams_default = "[data-testid=followed-livestreams] [data-testid=livestream-results-card]:has(a[href=\"/category/slots\"]),\n#sidebar-wrapper [data-kick-enhancer-gambling-stream] {\n  display: none !important;\n}";
	var STYLE_ID$4 = "kick-enhancer-hide-gambling-streams";
	var SIDEBAR_GAMBLING_ATTRIBUTE = "data-kick-enhancer-gambling-stream";
	var SIDEBAR_FOLLOWING_SELECTOR = "a[data-testid^=\"sidebar-following-channel-\"]";
	var GAMBLING_SURFACE_SELECTOR = ["[data-testid=\"followed-livestreams\"]", "#sidebar-wrapper"].join(", ");
	var gamblingStreamsHidden = false;
	var featureActive$1 = false;
	var sidebarScanFrame;
	var stopActiveFeature$3;
	function applyGamblingStreamsVisibility(hidden) {
		applyStyleToggle(STYLE_ID$4, gamblingStreams_default, hidden);
	}
	function getFollowedGamblingChannelPaths() {
		const paths = new Set();
		for (const card of document.querySelectorAll("[data-testid=\"followed-livestreams\"] [data-testid=\"livestream-results-card\"]:has(a[href=\"/category/slots\"])")) {
			const path = card.querySelector("a[data-testid=\"media-card-thumbnail\"]")?.getAttribute("href");
			if (path) paths.add(path);
		}
		return paths;
	}
	function isSlotsAndCasinoRow(link, gamblingChannelPaths) {
		const path = link.getAttribute("href");
		if (path && gamblingChannelPaths.has(path)) return true;
		return [...link.querySelectorAll("span")].some((span) => span.textContent?.trim() === "Slots & Casino");
	}
	function updateSidebarRows() {
		sidebarScanFrame = void 0;
		if (!gamblingStreamsHidden) {
			for (const row of document.querySelectorAll(`[${SIDEBAR_GAMBLING_ATTRIBUTE}]`)) row.removeAttribute(SIDEBAR_GAMBLING_ATTRIBUTE);
			return;
		}
		const gamblingChannelPaths = getFollowedGamblingChannelPaths();
		for (const link of document.querySelectorAll(SIDEBAR_FOLLOWING_SELECTOR)) (link.closest("button") ?? link).toggleAttribute(SIDEBAR_GAMBLING_ATTRIBUTE, isSlotsAndCasinoRow(link, gamblingChannelPaths));
	}
	function scheduleSidebarScan() {
		if (!featureActive$1 || sidebarScanFrame !== void 0) return;
		sidebarScanFrame = window.requestAnimationFrame(updateSidebarRows);
	}
	function mutationsTouchGamblingSurfaces(records) {
		return records.some((record) => {
			if ((record.target instanceof Element ? record.target : record.target.parentElement)?.closest(GAMBLING_SURFACE_SELECTOR)) return true;
			return [...record.addedNodes, ...record.removedNodes].some((node) => node instanceof Element && (node.matches(GAMBLING_SURFACE_SELECTOR) || Boolean(node.querySelector(GAMBLING_SURFACE_SELECTOR))));
		});
	}
	function startGamblingStreamsVisibility() {
		stopActiveFeature$3?.();
		featureActive$1 = true;
		const observer = new MutationObserver((records) => {
			if (gamblingStreamsHidden && mutationsTouchGamblingSurfaces(records)) scheduleSidebarScan();
		});
		observer.observe(document.documentElement, {
			characterData: true,
			childList: true,
			subtree: true
		});
		const stopObserving = observeSetting((settings) => settings.ui.hideGamblingStreams, (hidden) => {
			gamblingStreamsHidden = hidden;
			applyGamblingStreamsVisibility(gamblingStreamsHidden);
			scheduleSidebarScan();
		});
		let stopped = false;
		const stop = () => {
			if (stopped) return;
			stopped = true;
			featureActive$1 = false;
			observer.disconnect();
			stopObserving();
			if (sidebarScanFrame !== void 0) {
				window.cancelAnimationFrame(sidebarScanFrame);
				sidebarScanFrame = void 0;
			}
			gamblingStreamsHidden = false;
			applyGamblingStreamsVisibility(false);
			updateSidebarRows();
			if (stopActiveFeature$3 === stop) stopActiveFeature$3 = void 0;
		};
		stopActiveFeature$3 = stop;
		return stop;
	}
	var startHomepageCarouselVisibility = createStyleSettingFeature({
		id: "kick-enhancer-hide-homepage-carousel",
		selectEnabled: (settings) => settings.ui.hideHomepageCarousel,
		styles: "#main-container main div:has(> [data-testid=carousel]),\n#main-container main div:has(> div > [aria-hidden=true].invisible.aspect-video) {\n  display: none !important;\n}"
	});
	var startRecommendedChannelsVisibility = createStyleSettingFeature({
		id: "kick-enhancer-hide-recommended-channels",
		selectEnabled: (settings) => settings.ui.hideRecommendedChannels,
		styles: "#sidebar-wrapper section:has([data-testid^=sidebar-recommended-channel-]),\n#sidebar-wrapper section:has([data-testid^=sidebar-recommended-channel-]) + div:has([data-testid*=recommended]) {\n  display: none !important;\n}"
	});
	var SIDEBAR_BUTTON_SELECTOR = [
		"button[aria-controls=\"sidebar-wrapper\"]",
		"button[aria-label=\"Collapse sidebar\"]",
		"button[aria-label=\"Expand sidebar\"]",
		"button[data-testid=\"sidebar-collapse\"]",
		"button[data-testid=\"sidebar-expand\"]"
	].join(", ");
	var log$6 = createLogger("sidebar");
	var activeLayout = null;
	var featureActive = false;
	var rememberSidebarState = false;
	var restoreRequested = false;
	var restoreTarget;
	var stopActiveFeature$2;
	function getSidebarButton() {
		return document.querySelector(SIDEBAR_BUTTON_SELECTOR);
	}
	function getSidebarLayout() {
		return document.querySelector("[data-sidebar][data-chat][data-theatre]") ?? document.querySelector("[data-sidebar]");
	}
	function getCollapsedState() {
		const sidebarVisible = getSidebarLayout()?.getAttribute("data-sidebar");
		if (sidebarVisible === "true") return false;
		if (sidebarVisible === "false") return true;
		const expanded = getSidebarButton()?.getAttribute("aria-expanded");
		if (expanded === "true") return false;
		if (expanded === "false") return true;
	}
	function attemptRestore() {
		if (!featureActive || !restoreRequested || !rememberSidebarState) return;
		const collapsed = getCollapsedState();
		if (collapsed === void 0) return;
		const rememberedCollapsed = getSettings().ui.sidebarCollapsed;
		if (collapsed === rememberedCollapsed) {
			restoreRequested = false;
			return;
		}
		const button = getSidebarButton();
		if (!button) return;
		restoreRequested = false;
		restoreTarget = rememberedCollapsed;
		log$6.info("Restoring state", { collapsed: rememberedCollapsed });
		button.click();
	}
	function requestRestore() {
		if (!featureActive) return;
		restoreRequested = true;
		restoreTarget = void 0;
		queueMicrotask(attemptRestore);
	}
	function rememberCollapsedState(collapsed) {
		if (getSettings().ui.sidebarCollapsed === collapsed) return;
		log$6.info("State saved", { collapsed });
		updateSettings((settings) => ({
			...settings,
			ui: {
				...settings.ui,
				sidebarCollapsed: collapsed
			}
		}));
	}
	function setRememberSidebarState(enabled) {
		const collapsed = enabled ? getCollapsedState() : void 0;
		log$6.info(enabled ? "Memory enabled" : "Memory disabled");
		return updateSettings((settings) => ({
			...settings,
			ui: {
				...settings.ui,
				rememberSidebarState: enabled,
				sidebarCollapsed: collapsed ?? settings.ui.sidebarCollapsed
			}
		}));
	}
	function startSidebarStateMemory() {
		stopActiveFeature$2?.();
		featureActive = true;
		rememberSidebarState = getSettings().ui.rememberSidebarState;
		activeLayout = getSidebarLayout();
		const observer = new MutationObserver((records) => {
			const layout = getSidebarLayout();
			if (layout !== activeLayout) {
				activeLayout = layout;
				if (rememberSidebarState) requestRestore();
			}
			if (records.some((record) => record.type === "attributes" && record.attributeName === "data-sidebar" && record.target === layout)) {
				const collapsed = getCollapsedState();
				if (collapsed === void 0) return;
				if (restoreTarget !== void 0) {
					if (collapsed === restoreTarget) restoreTarget = void 0;
					return;
				}
				if (restoreRequested) {
					attemptRestore();
					return;
				}
				if (rememberSidebarState) rememberCollapsedState(collapsed);
			}
			if (restoreRequested && records.some((record) => record.type === "childList")) attemptRestore();
		});
		observer.observe(document.documentElement, {
			attributeFilter: ["data-sidebar"],
			attributes: true,
			childList: true,
			subtree: true
		});
		const stopObserving = subscribeSettings((settings) => {
			if (settings.ui.rememberSidebarState === rememberSidebarState) return;
			rememberSidebarState = settings.ui.rememberSidebarState;
			if (rememberSidebarState) requestRestore();
			else {
				restoreRequested = false;
				restoreTarget = void 0;
			}
		});
		if (rememberSidebarState) requestRestore();
		let stopped = false;
		const stop = () => {
			if (stopped) return;
			stopped = true;
			featureActive = false;
			observer.disconnect();
			stopObserving();
			activeLayout = null;
			rememberSidebarState = false;
			restoreRequested = false;
			restoreTarget = void 0;
			if (stopActiveFeature$2 === stop) stopActiveFeature$2 = void 0;
		};
		stopActiveFeature$2 = stop;
		return stop;
	}
	var RESERVED_ROUTES = new Set([
		"about",
		"browse",
		"category",
		"dashboard",
		"following",
		"privacy",
		"search",
		"settings",
		"subscriptions",
		"terms"
	]);
	var SLUG_PATTERN = /^[a-z0-9][a-z0-9_-]*$/i;
	function normalizeChannelSlug(value) {
		if (typeof value !== "string") return;
		const normalized = safeDecode(value).trim().toLowerCase();
		if (!normalized || RESERVED_ROUTES.has(normalized) || !SLUG_PATTERN.test(normalized)) return;
		return normalized;
	}
	function getChannelSlugFromHref(href) {
		if (!href) return;
		try {
			const url = new URL(href, window.location.href);
			if (url.hostname !== "kick.com" && url.hostname !== "www.kick.com") return;
			return getChannelSlugFromPath(url.pathname);
		} catch {
			return;
		}
	}
	function getChannelSlugFromPath(pathname) {
		const segments = pathname.split("/").filter(Boolean);
		if (segments.length !== 1) return;
		return normalizeChannelSlug(segments[0]);
	}
	function safeDecode(value) {
		try {
			return decodeURIComponent(value);
		} catch {
			return value;
		}
	}
	var MAX_CLOCK_SKEW_MS = 300 * 1e3;
	var KICK_UTC_TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)?$/;
	function parseStreamStartedAt(value) {
		if (typeof value !== "string") return;
		const trimmed = value.trim();
		if (!trimmed) return;
		const normalized = KICK_UTC_TIMESTAMP_PATTERN.test(trimmed) ? `${trimmed.replace(" ", "T")}Z` : trimmed;
		const timestamp = Date.parse(normalized);
		return Number.isFinite(timestamp) && timestamp >= 0 ? timestamp : void 0;
	}
	function formatStreamUptime(startedAt, now = Date.now()) {
		if (!Number.isFinite(startedAt) || !Number.isFinite(now) || startedAt > now + MAX_CLOCK_SKEW_MS) return;
		const totalMinutes = Math.floor(Math.max(0, now - startedAt) / (60 * 1e3));
		if (totalMinutes < 1) return "<1m";
		if (totalMinutes < 60) return `${totalMinutes}m`;
		const totalHours = Math.floor(totalMinutes / 60);
		const minutes = totalMinutes % 60;
		if (totalHours < 24) return minutes > 0 ? `${totalHours}h ${minutes}m` : `${totalHours}h`;
		const days = Math.floor(totalHours / 24);
		const hours = totalHours % 24;
		return hours > 0 ? `${days}d ${hours}h` : `${days}d`;
	}
	var SOURCE_BY_ENDPOINT = {
		CHANNEL_DETAILS: "channel-details",
		FEATURED_LIVESTREAMS: "featured",
		FOLLOWED_CHANNELS: "followed-channels",
		PAGINATED_RECOMMENDED_LIVESTREAMS: "recommendations",
		RECOMMENDED_LIVESTREAMS: "recommendations",
		SIDEBAR_LIVESTREAMS: "sidebar-recommendations",
		USER_LIVESTREAMS: "user-livestreams"
	};
	function normalizeViewerCountPayload(endpoint, payload, capturedAt) {
		if (endpoint === "CURRENT_VIEWERS") return {
			currentViewers: normalizeCurrentViewers(payload, capturedAt),
			kind: "current-viewers"
		};
		const source = SOURCE_BY_ENDPOINT[endpoint];
		let values = [];
		if (endpoint === "SIDEBAR_LIVESTREAMS" || endpoint === "FEATURED_LIVESTREAMS" || endpoint === "PAGINATED_RECOMMENDED_LIVESTREAMS") values = readNestedArray(payload, "data", "livestreams");
		else if (endpoint === "RECOMMENDED_LIVESTREAMS") values = readNestedArray(payload, "data");
		else if (endpoint === "FOLLOWED_CHANNELS") values = readNestedArray(payload, "channels");
		else if (endpoint === "USER_LIVESTREAMS") values = Array.isArray(payload) ? payload : [];
		else values = [payload];
		return {
			kind: "streams",
			streams: values.map((value) => normalizeStream(endpoint, source, value, capturedAt)).filter((stream) => stream !== void 0)
		};
	}
	function normalizeStream(endpoint, source, value, capturedAt) {
		if (!isRecord$1(value)) return;
		if (endpoint === "CHANNEL_DETAILS") return normalizeChannelDetails(value, source, capturedAt);
		if (endpoint === "FOLLOWED_CHANNELS") return normalizeFollowedChannel(value, source, capturedAt);
		if (endpoint === "USER_LIVESTREAMS") return normalizeUserLivestream(value, source, capturedAt);
		return normalizeRecommendation(value, source, capturedAt);
	}
	function normalizeChannelDetails(channel, source, capturedAt) {
		if (!isRecord$1(channel.livestream)) return;
		const livestream = channel.livestream;
		const livestreamChannel = isRecord$1(livestream.channel) ? livestream.channel : void 0;
		const channelSlug = normalizeChannelSlug(channel.slug) ?? normalizeChannelSlug(livestreamChannel?.slug);
		const viewerCount = readCount(livestream.viewer_count) ?? readCount(livestream.viewers);
		const startedAt = readStreamStartedAt(livestream);
		if (!channelSlug || viewerCount === void 0) return;
		return createRecord({
			capturedAt,
			channelId: readId(channel.id) ?? readId(livestream.channel_id),
			channelSlug,
			isLive: readBoolean(livestream.is_live ?? channel.is_live, true),
			livestreamId: readId(livestream.id),
			showViewCount: readBoolean(livestream.show_view_count ?? channel.show_view_count, true),
			source,
			...startedAt === void 0 ? {} : { startedAt },
			viewerCount
		});
	}
	function normalizeFollowedChannel(channel, source, capturedAt) {
		const channelSlug = normalizeChannelSlug(channel.channel_slug);
		const viewerCount = readCount(channel.viewer_count);
		const isLive = readBoolean(channel.is_live, false);
		const startedAt = readStreamStartedAt(channel);
		if (!channelSlug || viewerCount === void 0 || !isLive) return;
		return createRecord({
			capturedAt,
			channelSlug,
			isLive,
			showViewCount: readBoolean(channel.show_view_count, true),
			source,
			...startedAt === void 0 ? {} : { startedAt },
			viewerCount
		});
	}
	function normalizeUserLivestream(livestream, source, capturedAt) {
		const channel = isRecord$1(livestream.channel) ? livestream.channel : void 0;
		const channelSlug = normalizeChannelSlug(channel?.slug);
		const viewerCount = readCount(livestream.viewer_count) ?? readCount(livestream.viewers);
		const isLive = readBoolean(livestream.is_live, false);
		const startedAt = readStreamStartedAt(livestream);
		if (!channelSlug || viewerCount === void 0 || !isLive) return;
		return createRecord({
			capturedAt,
			channelId: readId(channel?.id) ?? readId(livestream.channel_id),
			channelSlug,
			isLive,
			livestreamId: readId(livestream.id),
			showViewCount: readBoolean(livestream.show_view_count, true),
			source,
			...startedAt === void 0 ? {} : { startedAt },
			viewerCount
		});
	}
	function normalizeRecommendation(livestream, source, capturedAt) {
		const channel = isRecord$1(livestream.channel) ? livestream.channel : void 0;
		const channelSlug = normalizeChannelSlug(channel?.slug);
		const viewerCount = readCount(livestream.viewer_count);
		const startedAt = readStreamStartedAt(livestream);
		if (!channelSlug || viewerCount === void 0) return;
		return createRecord({
			capturedAt,
			channelId: readId(channel?.id),
			channelSlug,
			isLive: true,
			livestreamId: readId(livestream.id),
			showViewCount: readBoolean(livestream.show_view_count, true),
			source,
			...startedAt === void 0 ? {} : { startedAt },
			viewerCount
		});
	}
	function readStreamStartedAt(stream) {
		return parseStreamStartedAt(stream.start_time) ?? parseStreamStartedAt(stream.started_at) ?? parseStreamStartedAt(stream.created_at);
	}
	function normalizeCurrentViewers(payload, capturedAt) {
		if (!Array.isArray(payload)) return [];
		return payload.map((value) => {
			if (!isRecord$1(value)) return;
			const livestreamId = readId(value.livestream_id);
			const viewerCount = readCount(value.viewers);
			if (livestreamId === void 0 || viewerCount === void 0) return;
			const showViewCount = typeof value.show_view_count === "boolean" ? value.show_view_count : void 0;
			return {
				capturedAt,
				livestreamId,
				...showViewCount === void 0 ? {} : { showViewCount },
				viewerCount
			};
		}).filter((entry) => entry !== void 0);
	}
	function createRecord(record) {
		return record;
	}
	function readNestedArray(value, ...path) {
		let current = value;
		for (const key of path) {
			if (!isRecord$1(current)) return [];
			current = current[key];
		}
		return Array.isArray(current) ? current : [];
	}
	function readCount(value) {
		if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return;
		return Math.floor(value);
	}
	function readId(value) {
		const numericValue = typeof value === "string" && /^(0|[1-9]\d*)$/.test(value) ? Number(value) : value;
		if (typeof numericValue !== "number" || !Number.isSafeInteger(numericValue) || numericValue < 0) return;
		return numericValue;
	}
	function readBoolean(value, fallback) {
		if (typeof value === "boolean") return value;
		if (value === 0 || value === "0" || value === "false") return false;
		if (value === 1 || value === "1" || value === "true") return true;
		return fallback;
	}
	function isRecord$1(value) {
		return typeof value === "object" && value !== null;
	}
	async function requestViewerJson(url, signal) {
		const startedAt = performance.now();
		try {
			const response = await fetch(url, {
				credentials: "include",
				headers: {
					Accept: "application/json",
					"x-app-platform": "web"
				},
				signal
			});
			const durationMs = performance.now() - startedAt;
			if (!response.ok) return {
				durationMs,
				httpStatus: response.status,
				kind: "failed",
				summary: `KICK returned HTTP ${response.status}.`
			};
			try {
				const payload = await response.json();
				return {
					durationMs,
					httpStatus: response.status,
					kind: "passed",
					payload
				};
			} catch (error) {
				if (signal.aborted || isAbortError(error)) throw error;
				return {
					durationMs,
					httpStatus: response.status,
					kind: "failed",
					summary: "KICK returned a response that was not valid JSON."
				};
			}
		} catch (error) {
			if (signal.aborted || isAbortError(error)) throw error;
			return {
				durationMs: performance.now() - startedAt,
				kind: "failed",
				summary: "Network request failed before KICK responded."
			};
		}
	}
	function isAbortError(error) {
		return error instanceof DOMException && error.name === "AbortError";
	}
	var VIEWER_COUNT_ENDPOINTS = [
		"CHANNEL_DETAILS",
		"CURRENT_VIEWERS",
		"FOLLOWED_CHANNELS",
		"USER_LIVESTREAMS",
		"SIDEBAR_LIVESTREAMS",
		"RECOMMENDED_LIVESTREAMS",
		"PAGINATED_RECOMMENDED_LIVESTREAMS",
		"FEATURED_LIVESTREAMS"
	];
	var VIEWER_COUNT_ENDPOINT_LABELS = {
		CHANNEL_DETAILS: "Channel details",
		CURRENT_VIEWERS: "Current viewers",
		FEATURED_LIVESTREAMS: "Featured streams",
		FOLLOWED_CHANNELS: "Followed channels",
		PAGINATED_RECOMMENDED_LIVESTREAMS: "Discovery list",
		RECOMMENDED_LIVESTREAMS: "Recommended streams",
		SIDEBAR_LIVESTREAMS: "Sidebar streams",
		USER_LIVESTREAMS: "User livestreams"
	};
	var OBSERVATION_NOTIFY_INTERVAL_MS = 200;
	var log$5 = createLogger("diagnostics");
	var observations = new Map();
	var observationListeners = new Set();
	var observationNotifyTimer;
	function recordViewerEndpointObservation(endpoint, normalized, observedAt, source) {
		const streams = normalized.kind === "streams" ? normalized.streams : [];
		const records = normalized.kind === "streams" ? streams.length : normalized.currentViewers.length;
		const observation = {
			endpoint,
			hiddenViewerCounts: normalized.kind === "streams" ? streams.filter((stream) => !stream.showViewCount).length : normalized.currentViewers.filter((entry) => entry.showViewCount === false).length,
			observedAt,
			records,
			source,
			startTimes: streams.filter((stream) => stream.startedAt !== void 0).length
		};
		observations.set(endpoint, observation);
		scheduleObservationNotification();
		return observation;
	}
	function getViewerEndpointObservations() {
		return VIEWER_COUNT_ENDPOINTS.flatMap((endpoint) => {
			const observation = observations.get(endpoint);
			return observation ? [observation] : [];
		});
	}
	function subscribeViewerEndpointObservations(listener) {
		observationListeners.add(listener);
		return () => {
			observationListeners.delete(listener);
			if (observationListeners.size === 0 && observationNotifyTimer !== void 0) {
				globalThis.clearTimeout(observationNotifyTimer);
				observationNotifyTimer = void 0;
			}
		};
	}
	function scheduleObservationNotification() {
		if (observationListeners.size === 0 || observationNotifyTimer !== void 0) return;
		observationNotifyTimer = globalThis.setTimeout(() => {
			observationNotifyTimer = void 0;
			notifyObservationListeners();
		}, OBSERVATION_NOTIFY_INTERVAL_MS);
	}
	async function runViewerEndpointChecks(rawSlug, signal) {
		const slug = normalizeChannelSlug(rawSlug);
		if (!slug) return [{
			endpoint: "CHANNEL_DETAILS",
			status: "failed",
			summary: "Enter a valid KICK channel name."
		}, unavailableCurrentViewers("Channel check did not run.")];
		log$5.info("Checks started", { slug });
		const channelResponse = await requestViewerJson(new URL(`/api/v2/channels/${encodeURIComponent(slug)}`, window.location.origin), signal);
		if (channelResponse.kind === "failed") {
			const results = [{
				durationMs: channelResponse.durationMs,
				endpoint: "CHANNEL_DETAILS",
				...channelResponse.httpStatus === void 0 ? {} : { httpStatus: channelResponse.httpStatus },
				status: "failed",
				summary: channelResponse.summary
			}, unavailableCurrentViewers("No livestream ID was available for this check.")];
			log$5.warn("Checks failed", {
				endpoint: "CHANNEL_DETAILS",
				slug
			});
			return results;
		}
		const capturedAt = Date.now();
		const normalized = normalizeViewerCountPayload("CHANNEL_DETAILS", channelResponse.payload, capturedAt);
		const stream = normalized.kind === "streams" ? normalized.streams.find((entry) => entry.channelSlug === slug && entry.isLive) : void 0;
		if (!stream) {
			const offline = isOfflineChannelPayload(channelResponse.payload);
			const results = [{
				durationMs: channelResponse.durationMs,
				endpoint: "CHANNEL_DETAILS",
				httpStatus: channelResponse.httpStatus,
				status: offline ? "unavailable" : "degraded",
				summary: offline ? "Channel resolved, but it is not live." : "Response was reachable but no usable live stream was found."
			}, unavailableCurrentViewers(offline ? "The channel is offline." : "The channel response did not expose a livestream ID.")];
			log$5.info("Checks complete", {
				status: results[0].status,
				slug
			});
			return results;
		}
		const channelCheck = {
			durationMs: channelResponse.durationMs,
			endpoint: "CHANNEL_DETAILS",
			httpStatus: channelResponse.httpStatus,
			status: stream.livestreamId === void 0 ? "degraded" : "passed",
			summary: [
				`viewers=${stream.viewerCount.toLocaleString()}`,
				`count=${stream.showViewCount ? "public" : "hidden"}`,
				`started=${stream.startedAt === void 0 ? "no" : "yes"}`,
				`livestream=${stream.livestreamId ?? "missing"}`
			].join("; ")
		};
		if (stream.livestreamId === void 0) return [channelCheck, unavailableCurrentViewers("The live response did not include a livestream ID.")];
		const viewersUrl = new URL("/current-viewers", window.location.origin);
		viewersUrl.searchParams.append("ids[]", String(stream.livestreamId));
		const viewersResponse = await requestViewerJson(viewersUrl, signal);
		if (viewersResponse.kind === "failed") {
			const result = {
				durationMs: viewersResponse.durationMs,
				endpoint: "CURRENT_VIEWERS",
				...viewersResponse.httpStatus === void 0 ? {} : { httpStatus: viewersResponse.httpStatus },
				status: "failed",
				summary: viewersResponse.summary
			};
			log$5.warn("Checks failed", {
				endpoint: "CURRENT_VIEWERS",
				slug
			});
			return [channelCheck, result];
		}
		const current = normalizeViewerCountPayload("CURRENT_VIEWERS", viewersResponse.payload, Date.now());
		const entry = current.kind === "current-viewers" ? current.currentViewers.find(({ livestreamId }) => livestreamId === stream.livestreamId) : void 0;
		const currentCheck = {
			durationMs: viewersResponse.durationMs,
			endpoint: "CURRENT_VIEWERS",
			httpStatus: viewersResponse.httpStatus,
			status: entry ? "passed" : "degraded",
			summary: entry ? `viewers=${entry.viewerCount.toLocaleString()}` : "No matching viewer record."
		};
		log$5.info("Checks complete", {
			status: currentCheck.status,
			slug
		});
		return [channelCheck, currentCheck];
	}
	function notifyObservationListeners() {
		const snapshot = getViewerEndpointObservations();
		for (const listener of observationListeners) try {
			listener(snapshot);
		} catch (error) {
			console.error("[KICK Enhancer] Endpoint observation listener failed.", error);
		}
	}
	function unavailableCurrentViewers(summary) {
		return {
			endpoint: "CURRENT_VIEWERS",
			status: "unavailable",
			summary
		};
	}
	function isOfflineChannelPayload(payload) {
		return typeof payload === "object" && payload !== null && "livestream" in payload && payload.livestream === null;
	}
	var CHANNEL_FETCH_CONCURRENCY = 5;
	var CURRENT_VIEWERS_BATCH_SIZE = 10;
	var CHANNEL_POLL_INTERVAL_MS = 30 * 1e3;
	var LIST_POLL_INTERVAL_MS = 120 * 1e3;
	var RETRY_COOLDOWN_MS = 60 * 1e3;
	var log$4 = createLogger("viewer-counts:network");
	var ViewerCountAcquisition = class {
		options;
		#inFlightSlugs = new Map();
		#pendingPollSlugs = new Set();
		#pollingSlugs = new Set();
		#queuedSlugs = new Set();
		#retryAfterBySlug = new Map();
		#targetSlugs = new Set();
		#abortController = new AbortController();
		#activeChannelSlug;
		#activeFetches = 0;
		#channelPollTimer;
		#enabled = false;
		#generation = 0;
		#lastPollWarningAt = 0;
		#listPollTimer;
		#polling = false;
		#retryTimer;
		constructor(options) {
			this.options = options;
		}
		start() {
			if (this.#enabled) return;
			this.#enabled = true;
			document.addEventListener("visibilitychange", this.#handleVisibilityChange);
			this.#channelPollTimer = window.setInterval(() => {
				this.#pollActiveChannel();
			}, CHANNEL_POLL_INTERVAL_MS);
			this.#listPollTimer = window.setInterval(() => {
				this.#pollVisibleTargets();
			}, LIST_POLL_INTERVAL_MS);
		}
		stop() {
			if (!this.#enabled) return;
			this.#enabled = false;
			this.#generation += 1;
			this.#abortController.abort();
			this.#abortController = new AbortController();
			this.#activeChannelSlug = void 0;
			this.#queuedSlugs.clear();
			this.#pendingPollSlugs.clear();
			this.#pollingSlugs.clear();
			this.#targetSlugs.clear();
			this.#inFlightSlugs.clear();
			this.#retryAfterBySlug.clear();
			document.removeEventListener("visibilitychange", this.#handleVisibilityChange);
			if (this.#channelPollTimer !== void 0) {
				window.clearInterval(this.#channelPollTimer);
				this.#channelPollTimer = void 0;
			}
			if (this.#listPollTimer !== void 0) {
				window.clearInterval(this.#listPollTimer);
				this.#listPollTimer = void 0;
			}
			if (this.#retryTimer !== void 0) {
				window.clearTimeout(this.#retryTimer);
				this.#retryTimer = void 0;
			}
		}
		beginRoute() {
			if (!this.#enabled) return;
			this.#generation += 1;
			this.#abortController.abort();
			this.#abortController = new AbortController();
			this.#activeChannelSlug = void 0;
			this.#queuedSlugs.clear();
			this.#pendingPollSlugs.clear();
			this.#pollingSlugs.clear();
			this.#targetSlugs.clear();
			this.#inFlightSlugs.clear();
		}
		syncTargets(channelSlugs, activeChannelSlug) {
			if (!this.#enabled) return;
			this.#targetSlugs.clear();
			for (const slug of channelSlugs) this.#targetSlugs.add(slug);
			this.#activeChannelSlug = activeChannelSlug;
			const now = Date.now();
			for (const slug of this.#queuedSlugs) if (!this.#targetSlugs.has(slug)) this.#queuedSlugs.delete(slug);
			for (const slug of this.#pendingPollSlugs) if (!this.#targetSlugs.has(slug)) this.#pendingPollSlugs.delete(slug);
			for (const [slug, retryAfter] of this.#retryAfterBySlug) if (retryAfter <= now && !this.#targetSlugs.has(slug) && !this.#inFlightSlugs.has(slug)) this.#retryAfterBySlug.delete(slug);
			for (const slug of channelSlugs) if (needsChannelDetails(this.options.store.get(slug), slug === activeChannelSlug)) this.#queueChannelDetails(slug);
			else this.#queuedSlugs.delete(slug);
			this.#pumpChannelQueue();
		}
		#queueChannelDetails(slug) {
			const now = Date.now();
			if (this.#queuedSlugs.has(slug) || this.#inFlightSlugs.has(slug)) return;
			const retryAfter = this.#retryAfterBySlug.get(slug);
			if (retryAfter !== void 0 && retryAfter > now) {
				this.#scheduleRetry(retryAfter - now);
				return;
			}
			this.#queuedSlugs.add(slug);
		}
		#pumpChannelQueue() {
			while (this.#enabled && this.#activeFetches < CHANNEL_FETCH_CONCURRENCY && this.#queuedSlugs.size > 0) {
				const slug = this.#queuedSlugs.values().next().value;
				if (!slug) return;
				this.#queuedSlugs.delete(slug);
				const stream = this.options.store.get(slug);
				if (!this.#targetSlugs.has(slug) || !needsChannelDetails(stream, slug === this.#activeChannelSlug)) continue;
				const generation = this.#generation;
				this.#activeFetches += 1;
				this.#inFlightSlugs.set(slug, generation);
				this.#fetchChannelDetails(slug, generation).finally(() => {
					this.#activeFetches -= 1;
					if (this.#inFlightSlugs.get(slug) === generation) this.#inFlightSlugs.delete(slug);
					this.#pumpChannelQueue();
				});
			}
		}
		async #fetchChannelDetails(slug, generation) {
			const requestUrl = new URL(`/api/v2/channels/${encodeURIComponent(slug)}`, window.location.origin);
			try {
				const response = await requestViewerJson(requestUrl, this.#abortController.signal);
				if (response.kind === "failed") throw new Error(response.summary);
				if (!this.#enabled || generation !== this.#generation) return;
				const capturedAt = Date.now();
				const normalized = normalizeViewerCountPayload("CHANNEL_DETAILS", response.payload, capturedAt);
				recordViewerEndpointObservation("CHANNEL_DETAILS", normalized, capturedAt, "fallback");
				if (normalized.kind !== "streams" || normalized.streams.length === 0 || !normalized.streams.some((stream) => stream.isLive)) {
					this.options.store.remove(slug);
					this.#setRetryCooldown(slug);
					this.options.onData();
					return;
				}
				this.#retryAfterBySlug.delete(slug);
				this.options.store.upsertStreams(normalized.streams);
				this.options.onData();
				const stream = normalized.streams.find((entry) => entry.channelSlug === slug);
				if (slug === this.#activeChannelSlug) await this.#pollSlugs(new Set([slug]));
				if (stream && !stream.showViewCount) log$4.info("Fallback resolved", {
					slug,
					viewerCount: stream.viewerCount
				});
				else log$4.debug("Channel fetched", { slug });
			} catch (error) {
				if (!isAbortError(error)) {
					this.#setRetryCooldown(slug);
					log$4.warn("Channel fetch failed", {
						error: formatError(error),
						slug
					});
				}
			}
		}
		#setRetryCooldown(slug) {
			this.#retryAfterBySlug.set(slug, Date.now() + RETRY_COOLDOWN_MS);
			this.#scheduleRetry(RETRY_COOLDOWN_MS);
		}
		#scheduleRetry(delay) {
			if (this.#retryTimer !== void 0 || !this.#enabled) return;
			this.#retryTimer = window.setTimeout(() => {
				this.#retryTimer = void 0;
				for (const slug of this.#targetSlugs) if (needsChannelDetails(this.options.store.get(slug), slug === this.#activeChannelSlug)) this.#queueChannelDetails(slug);
				else this.#queuedSlugs.delete(slug);
				this.#pumpChannelQueue();
			}, Math.max(250, delay));
		}
		async #pollActiveChannel() {
			const slug = this.#activeChannelSlug;
			if (!slug) return;
			await this.#pollSlugs(new Set([slug]));
		}
		async #pollVisibleTargets() {
			await this.#pollSlugs(this.#targetSlugs);
		}
		async #pollSlugs(slugs) {
			if (!this.#enabled || document.hidden) return;
			for (const slug of slugs) if (!this.#pollingSlugs.has(slug)) this.#pendingPollSlugs.add(slug);
			if (this.#polling || this.#pendingPollSlugs.size === 0) return;
			this.#polling = true;
			try {
				while (this.#enabled && !document.hidden && this.#pendingPollSlugs.size > 0) {
					const pendingSlugs = new Set(this.#pendingPollSlugs);
					this.#pendingPollSlugs.clear();
					this.#pollingSlugs.clear();
					for (const slug of pendingSlugs) this.#pollingSlugs.add(slug);
					await this.#pollSlugBatch(pendingSlugs);
					this.#pollingSlugs.clear();
				}
			} finally {
				this.#pollingSlugs.clear();
				this.#polling = false;
				if (this.#enabled && !document.hidden && this.#pendingPollSlugs.size > 0) this.#pollSlugs(new Set());
			}
		}
		async #pollSlugBatch(slugs) {
			this.options.store.prune();
			const livestreamIds = [...this.options.store.getLivestreamIds(slugs)];
			if (livestreamIds.length === 0) {
				this.options.onData();
				return;
			}
			const generation = this.#generation;
			let updated = 0;
			try {
				for (let index = 0; index < livestreamIds.length; index += CURRENT_VIEWERS_BATCH_SIZE) {
					if (!this.#enabled || generation !== this.#generation) return;
					const batch = livestreamIds.slice(index, index + CURRENT_VIEWERS_BATCH_SIZE);
					const requestUrl = new URL("/current-viewers", window.location.origin);
					for (const id of batch) requestUrl.searchParams.append("ids[]", String(id));
					const response = await requestViewerJson(requestUrl, this.#abortController.signal);
					if (response.kind === "failed") throw new Error(response.summary);
					if (!this.#enabled || generation !== this.#generation) return;
					const capturedAt = Date.now();
					const normalized = normalizeViewerCountPayload("CURRENT_VIEWERS", response.payload, capturedAt);
					recordViewerEndpointObservation("CURRENT_VIEWERS", normalized, capturedAt, "fallback");
					if (normalized.kind === "current-viewers") {
						const receivedIds = new Set(normalized.currentViewers.map(({ livestreamId }) => livestreamId));
						updated += this.options.store.upsertCurrentViewers(normalized.currentViewers);
						updated += this.options.store.removeLivestreamIds(batch.filter((id) => !receivedIds.has(id)));
					}
				}
				if (updated > 0) log$4.debug("Refresh complete", {
					livestreams: livestreamIds.length,
					updated
				});
			} catch (error) {
				if (!isAbortError(error) && Date.now() - this.#lastPollWarningAt >= RETRY_COOLDOWN_MS) {
					this.#lastPollWarningAt = Date.now();
					log$4.warn("Refresh failed", { error: formatError(error) });
				}
			} finally {
				if (this.#enabled && generation === this.#generation) this.options.onData();
			}
		}
		#handleVisibilityChange = () => {
			if (!document.hidden) this.#pollVisibleTargets();
		};
	};
	function needsChannelDetails(stream, isActiveChannel) {
		return !stream || stream.startedAt === void 0 || isActiveChannel && stream.livestreamId === void 0 || stream.showViewCount && stream.source !== "channel-details" && stream.source !== "current-viewers";
	}
	function formatError(error) {
		return error instanceof Error ? error.message : String(error);
	}
	var KICK_ORIGINS = new Set(["https://kick.com", "https://www.kick.com"]);
	var ENDPOINTS = [
		{
			endpoint: "SIDEBAR_LIVESTREAMS",
			matches: exactWebEndpoint("/api/v1/recommendations/livestreams/sidebar")
		},
		{
			endpoint: "RECOMMENDED_LIVESTREAMS",
			matches: exactWebEndpoint("/api/v1/recommendations/livestreams")
		},
		{
			endpoint: "PAGINATED_RECOMMENDED_LIVESTREAMS",
			matches: exactWebEndpoint("/api/v1/recommendations/livestreams/list")
		},
		{
			endpoint: "FEATURED_LIVESTREAMS",
			matches: exactWebEndpoint("/api/v1/livestreams/featured")
		},
		{
			endpoint: "FOLLOWED_CHANNELS",
			matches: exactKickEndpoint("/api/v2/channels/followed")
		},
		{
			endpoint: "CHANNEL_DETAILS",
			matches: (url) => KICK_ORIGINS.has(url.origin) && /^\/api\/v2\/channels\/[^/]+$/.test(url.pathname)
		},
		{
			endpoint: "CURRENT_VIEWERS",
			matches: exactKickEndpoint("/current-viewers")
		},
		{
			endpoint: "USER_LIVESTREAMS",
			matches: exactKickEndpoint("/api/v1/user/livestreams")
		}
	];
	function exactKickEndpoint(pathname) {
		return (url) => KICK_ORIGINS.has(url.origin) && url.pathname === pathname;
	}
	function exactWebEndpoint(pathname) {
		return (url) => url.origin === "https://web.kick.com" && url.pathname === pathname;
	}
	function classifyViewerCountEndpoint(rawUrl, baseUrl = window.location.href) {
		try {
			const url = new URL(rawUrl, baseUrl);
			return ENDPOINTS.find(({ matches }) => matches(url))?.endpoint;
		} catch {
			return;
		}
	}
	var VIEWER_COUNT_MESSAGE_SOURCE = "kick-enhancer-viewer-counts";
	var VIEWER_COUNT_MESSAGE_TYPE = "KICK_ENHANCER_API_RESPONSE";
	function isViewerCountEndpoint(value) {
		return value === "CHANNEL_DETAILS" || value === "CURRENT_VIEWERS" || value === "FEATURED_LIVESTREAMS" || value === "FOLLOWED_CHANNELS" || value === "PAGINATED_RECOMMENDED_LIVESTREAMS" || value === "RECOMMENDED_LIVESTREAMS" || value === "SIDEBAR_LIVESTREAMS" || value === "USER_LIVESTREAMS";
	}
	function isCapturedViewerCountMessage(value) {
		if (!isRecord(value)) return false;
		return value.source === "kick-enhancer-viewer-counts" && value.type === "KICK_ENHANCER_API_RESPONSE" && isViewerCountEndpoint(value.endpoint) && typeof value.url === "string" && typeof value.timestamp === "number" && Number.isFinite(value.timestamp) && "payload" in value;
	}
	function isRecord(value) {
		return typeof value === "object" && value !== null;
	}
	var log$3 = createLogger("viewer-counts:capture");
	function installViewerCountCaptureBridge() {
		const pageWindow = _unsafeWindow;
		try {
			if (pageWindow.__kickEnhancerViewerCountHookInstalled) return true;
			const originalJson = pageWindow.Response.prototype.json;
			const originalDescriptor = Object.getOwnPropertyDescriptor(pageWindow.Response.prototype, "json");
			const hookedJson = new Proxy(originalJson, { apply(target, thisArgument, argumentsList) {
				const payloadPromise = Reflect.apply(target, thisArgument, argumentsList);
				const endpoint = classifyViewerCountEndpoint(thisArgument.url, pageWindow.location.href);
				if (endpoint) payloadPromise.then((payload) => {
					const message = {
						endpoint,
						payload,
						source: VIEWER_COUNT_MESSAGE_SOURCE,
						timestamp: Date.now(),
						type: VIEWER_COUNT_MESSAGE_TYPE,
						url: thisArgument.url
					};
					pageWindow.postMessage(message, pageWindow.location.origin);
				}).catch(() => {});
				return payloadPromise;
			} });
			Object.defineProperty(pageWindow.Response.prototype, "json", {
				...originalDescriptor,
				configurable: true,
				value: hookedJson,
				writable: true
			});
			pageWindow.__kickEnhancerViewerCountHookInstalled = true;
			log$3.info("Installed");
			return true;
		} catch (error) {
			log$3.warn("Unavailable; using fallback", error);
			return false;
		}
	}
	var VIEWER_COUNT_SELECTOR = "[data-ke-viewer-count]";
	var STREAM_UPTIME_SELECTOR = "[data-ke-stream-uptime]";
	var RENDER_ELEMENT_SELECTOR = [VIEWER_COUNT_SELECTOR, STREAM_UPTIME_SELECTOR].join(", ");
	var SIDEBAR_LINK_SELECTOR = ["#sidebar-wrapper a[data-testid^=\"sidebar-following-channel-\"]", "#sidebar-wrapper a[data-testid^=\"sidebar-recommended-channel-\"]"].join(", ");
	var CARD_SELECTOR = "[data-testid=\"livestream-results-card\"]";
	var CARD_THUMBNAIL_SELECTOR = "a[data-testid=\"media-card-thumbnail\"][href]";
	var COMPACT_COUNT_PATTERN = /^(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?\s*[km]?$/i;
	function findStatusLabel(scope) {
		let best;
		let bestScore = 0;
		for (const element of scope.querySelectorAll("span, p, div")) {
			if (element.closest("[data-ke-viewer-count], [data-ke-stream-uptime]") || element.querySelector("[data-ke-viewer-count], [data-ke-stream-uptime]")) continue;
			const text = element.textContent?.trim() ?? "";
			if (text.toLowerCase() !== "live" && !isCompactCount(text)) continue;
			let score = element.childElementCount === 0 ? 2 : 1;
			const parentText = element.parentElement?.textContent ?? "";
			if (element.parentElement?.querySelector(".bg-green-500")) score += 6;
			if (parentText.trim().length <= text.length + 8 || element.parentElement?.classList.contains("items-center")) score += 2;
			if (score > bestScore) {
				best = element;
				bestScore = score;
			}
		}
		return best;
	}
	function formatViewerCount(viewerCount) {
		if (viewerCount < 1e3) return String(viewerCount);
		const divisor = viewerCount < 1e6 ? 1e3 : 1e6;
		const suffix = viewerCount < 1e6 ? "K" : "M";
		const rounded = Math.round(viewerCount / divisor * 10) / 10;
		return `${Number.isInteger(rounded) ? rounded : rounded.toFixed(1)}${suffix}`;
	}
	function isCompactCount(value) {
		return COMPACT_COUNT_PATTERN.test(value?.trim() ?? "");
	}
	function renderCardSurfaces(store, ownership, options) {
		const targetSlugs = new Set();
		let uptimes = 0;
		let viewerCounts = 0;
		for (const card of document.querySelectorAll(CARD_SELECTOR)) {
			if (isCardHiddenByEnhancer(card, options)) {
				ownership.removeCount(card, "card");
				ownership.removeUptime(card, "card");
				continue;
			}
			const thumbnail = card.querySelector(CARD_THUMBNAIL_SELECTOR);
			const slug = getChannelSlugFromHref(thumbnail?.getAttribute("href"));
			const liveBadge = thumbnail ? findCardLiveBadge(thumbnail) : void 0;
			if (!thumbnail || !slug || !liveBadge) {
				ownership.removeCount(card, "card");
				ownership.removeUptime(card, "card");
				continue;
			}
			targetSlugs.add(slug);
			const stream = store.get(slug);
			if (options.showStreamUptime) uptimes += renderCardUptime(ownership, thumbnail, liveBadge, slug, stream?.startedAt);
			else ownership.removeUptime(thumbnail, "card");
			if (!options.showHiddenViewerCounts || hasNativeCardCount(thumbnail) || !stream || stream.showViewCount) {
				ownership.removeCount(card, "card");
				continue;
			}
			const element = ownership.findCount(thumbnail, "card") ?? document.createElement("div");
			if (ownership.updateCount(element, {
				className: "ke-viewer-count-card",
				count: stream.viewerCount,
				slug,
				target: "card"
			}) || !element.querySelector(":scope > span")) {
				const count = document.createElement("span");
				count.textContent = formatViewerCount(stream.viewerCount);
				element.replaceChildren(count, " watching");
			}
			if (element.parentElement !== thumbnail) thumbnail.append(element);
			viewerCounts += 1;
		}
		return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
	}
	function renderCardUptime(ownership, thumbnail, liveBadge, slug, startedAt) {
		if (startedAt === void 0) {
			ownership.restoreNativeCardLiveBadge(liveBadge);
			ownership.removeUptime(thumbnail, "card");
			return 0;
		}
		const uptime = formatStreamUptime(startedAt);
		if (!uptime) {
			ownership.restoreNativeCardLiveBadge(liveBadge);
			ownership.removeUptime(thumbnail, "card");
			return 0;
		}
		const element = ownership.findUptime(thumbnail, "card") ?? document.createElement("div");
		ownership.updateUptime(element, {
			className: "ke-stream-uptime-card",
			label: `Live for ${uptime}`,
			slug,
			startedAt,
			target: "card",
			text: uptime
		});
		ownership.hideNativeCardLiveBadge(liveBadge, slug);
		if (element.parentElement !== thumbnail) thumbnail.append(element);
		return 1;
	}
	function hasNativeCardCount(thumbnail) {
		return [...thumbnail.querySelectorAll("[title]")].some((element) => {
			if (element.closest("[data-ke-viewer-count]")) return false;
			const title = element.getAttribute("title");
			const parentText = element.parentElement?.textContent ?? "";
			return isCompactCount(title) && /\bwatching\b/i.test(parentText);
		});
	}
	function findCardLiveBadge(thumbnail) {
		return [...thumbnail.querySelectorAll("div, span")].find((element) => !element.closest(RENDER_ELEMENT_SELECTOR) && element.childElementCount === 0 && element.textContent?.trim().toLowerCase() === "live");
	}
	function isCardHiddenByEnhancer(card, options) {
		if (options.hideGamblingStreams && card.closest("[data-testid=\"followed-livestreams\"]") && card.querySelector("a[href=\"/category/slots\"]")) return true;
		return Boolean(options.hideFollowingRecommendations && card.closest("[data-testid=\"following\"]") && !card.closest("[data-testid=\"followed-livestreams\"]"));
	}
	var DIGITS = Array.from({ length: 30 }, (_, index) => index % 10);
	var states = new WeakMap();
	function renderAnimatedNumber(container, value) {
		const formatted = Math.abs(value).toLocaleString();
		const existing = states.get(container);
		if (existing?.value === formatted) return;
		cancelState(existing);
		if (prefersReducedMotion()) {
			container.textContent = formatted;
			states.set(container, {
				animations: [],
				value: formatted
			});
			return;
		}
		const fragment = document.createDocumentFragment();
		const reels = [];
		let digitIndex = 0;
		for (const character of formatted) {
			if (!/\d/.test(character)) {
				const separator = document.createElement("span");
				separator.className = "ke-animated-number__separator";
				separator.textContent = character;
				fragment.append(separator);
				continue;
			}
			const viewport = document.createElement("span");
			viewport.className = "ke-animated-number__digit";
			const reel = document.createElement("span");
			reel.className = "ke-animated-number__reel";
			for (const digit of DIGITS) {
				const cell = document.createElement("span");
				cell.className = "ke-animated-number__cell";
				cell.textContent = String(digit);
				reel.append(cell);
			}
			viewport.append(reel);
			fragment.append(viewport);
			reels.push({
				digit: Number(character),
				element: reel,
				index: digitIndex,
				viewport
			});
			digitIndex += 1;
		}
		container.replaceChildren(fragment);
		const state = {
			animations: [],
			value: formatted
		};
		states.set(container, state);
		state.frame = window.requestAnimationFrame(() => {
			state.frame = void 0;
			if (states.get(container) !== state || !container.isConnected) return;
			for (const reel of reels) {
				const digitHeight = reel.viewport.getBoundingClientRect().height;
				if (digitHeight <= 0) continue;
				const target = -(20 + reel.digit) * digitHeight;
				const animation = reel.element.animate([
					{ transform: "translateY(0)" },
					{
						offset: .82,
						transform: `translateY(${target - digitHeight * .3}px)`
					},
					{
						offset: .93,
						transform: `translateY(${target + digitHeight * .1}px)`
					},
					{ transform: `translateY(${target}px)` }
				], {
					delay: reel.index * 35,
					duration: 520 + reel.index * 70,
					easing: "cubic-bezier(0.2, 0.8, 0.2, 1)",
					fill: "backwards"
				});
				reel.element.style.transform = `translateY(${target}px)`;
				state.animations.push(animation);
			}
		});
	}
	function cancelState(state) {
		if (!state) return;
		if (state.frame !== void 0) window.cancelAnimationFrame(state.frame);
		for (const animation of state.animations) animation.cancel();
	}
	function prefersReducedMotion() {
		return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
	}
	function renderChannelSurface(store, ownership, enabled) {
		const targetSlugs = new Set();
		const existing = document.querySelector(`${VIEWER_COUNT_SELECTOR}[data-ke-target="channel"]`);
		if (!enabled) {
			existing?.remove();
			return {
				rendered: 0,
				targetSlugs
			};
		}
		const slug = getChannelSlugFromPath(window.location.pathname);
		const title = document.querySelector("[data-testid=\"livestream-title\"]");
		if (!slug || !title) {
			existing?.remove();
			return {
				rendered: 0,
				targetSlugs
			};
		}
		if (document.querySelector("[data-testid=\"viewer-count\"]:not([data-ke-viewer-count])")) {
			existing?.remove();
			return {
				rendered: 0,
				slug,
				targetSlugs
			};
		}
		targetSlugs.add(slug);
		const stream = store.get(slug);
		if (!stream || stream.showViewCount) {
			existing?.remove();
			return {
				rendered: 0,
				slug,
				targetSlugs
			};
		}
		const element = existing ?? document.createElement("div");
		ownership.updateCount(element, {
			className: "ke-viewer-count-channel",
			count: stream.viewerCount,
			slug,
			target: "channel"
		});
		let count = element.querySelector(".ke-viewer-count-channel__value");
		if (!count) {
			const content = document.createElement("span");
			content.className = "ke-viewer-count-channel__content";
			count = document.createElement("span");
			count.className = ["ke-animated-number", "ke-viewer-count-channel__value"].join(" ");
			count.setAttribute("aria-hidden", "true");
			content.append(count, " watching");
			element.replaceChildren(createCommunityIcon(), content);
		}
		renderAnimatedNumber(count, stream.viewerCount);
		const insertionTarget = findChannelCountInsertionTarget();
		if (insertionTarget && (element.parentElement !== insertionTarget || element !== insertionTarget.firstElementChild)) insertionTarget.prepend(element);
		else if (!insertionTarget && element.parentElement !== title.parentElement) title.insertAdjacentElement("afterend", element);
		return {
			rendered: 1,
			slug,
			targetSlugs
		};
	}
	function findChannelCountInsertionTarget() {
		const mainButtons = document.querySelector("[data-testid=\"sub-button\"], [data-testid=\"gift-sub-button\"]")?.parentElement;
		const secondaryButtons = (mainButtons?.parentElement)?.lastElementChild;
		return secondaryButtons instanceof HTMLElement && secondaryButtons !== mainButtons ? secondaryButtons : void 0;
	}
	function createCommunityIcon() {
		const namespace = "http://www.w3.org/2000/svg";
		const icon = document.createElementNS(namespace, "svg");
		icon.setAttribute("aria-hidden", "true");
		icon.setAttribute("viewBox", "0 0 32 32");
		for (const pathData of [
			"M4 19V28H7V22H16V28H28V19H4Z",
			"M10.75 17.5C14.4775 17.5 17.5 14.4775 17.5 10.75C17.5 7.0225 14.4775 4 10.75 4C7.0225 4 4 7.0225 4 10.75C4 14.4775 7.0225 17.5 10.75 17.5ZM10.75 7C12.82 7 14.5 8.68 14.5 10.75C14.5 12.82 12.82 14.5 10.75 14.5C8.68 14.5 7 12.82 7 10.75C7 8.68 8.68 7 10.75 7Z",
			"M23.5 17.5C25.9853 17.5 28 15.4853 28 13C28 10.5147 25.9853 8.5 23.5 8.5C21.0147 8.5 19 10.5147 19 13C19 15.4853 21.0147 17.5 23.5 17.5Z"
		]) {
			const path = document.createElementNS(namespace, "path");
			path.setAttribute("d", pathData);
			icon.append(path);
		}
		return icon;
	}
	function updateCountElementState(element, state) {
		const count = String(state.count);
		const contentChanged = element.dataset.keCount !== count || element.dataset.keSlug !== state.slug || element.dataset.keTarget !== state.target;
		setClassName(element, state.className);
		setDatasetValue$1(element, "keCount", count);
		setDatasetValue$1(element, "keSlug", state.slug);
		setDatasetValue$1(element, "keTarget", state.target);
		setDatasetValue$1(element, "keViewerCount", "");
		if (state.text !== void 0 && element.textContent !== state.text) element.textContent = state.text;
		const accessibleLabel = `${state.count.toLocaleString()} viewers`;
		if (element.getAttribute("aria-label") !== accessibleLabel) element.setAttribute("aria-label", accessibleLabel);
		return contentChanged;
	}
	function setClassName(element, value) {
		if (element.className !== value) element.className = value;
	}
	function setDatasetValue$1(element, key, value) {
		if (element.dataset[key] !== value) element.dataset[key] = value;
	}
	var SIDEBAR_UPTIME_CONTAINER_SELECTOR = "[data-ke-sidebar-uptime-container]";
	var TOOLTIP_UPTIME_CONTAINER_SELECTOR = "[data-ke-tooltip-uptime-container]";
	var NATIVE_CARD_LIVE_HIDDEN_SELECTOR = "[data-ke-native-card-live-hidden]";
	var ViewerCountDomOwnership = class {
		#renderedElements = new Set();
		finalize() {
			this.#removeOrphanedElements();
			restoreUnusedNativeCardLiveBadges();
			restoreUnusedNativeLabels();
			restoreUnusedUptimeContainers();
		}
		findCount(scope, target) {
			return scope.querySelector(`${VIEWER_COUNT_SELECTOR}[data-ke-target="${target}"]`);
		}
		findUptime(scope, target) {
			return scope.querySelector(`${STREAM_UPTIME_SELECTOR}[data-ke-target="${target}"]`);
		}
		hideNativeCardLiveBadge(element, slug) {
			element.dataset.keNativeCardLiveHidden = slug;
		}
		hideNativeLiveLabel(element, slug) {
			if (element.textContent?.trim().toLowerCase() === "live") element.dataset.keNativeLiveHidden = slug;
		}
		markUptimeContainer(element, target, slug) {
			if (target === "sidebar") {
				element.dataset.keSidebarUptimeContainer = slug;
				return;
			}
			element.dataset.keTooltipUptimeContainer = slug;
		}
		removeCount(scope, target) {
			this.findCount(scope, target)?.remove();
		}
		removeUptime(scope, target) {
			this.findUptime(scope, target)?.remove();
		}
		restoreNativeCardLiveBadge(element) {
			element?.removeAttribute("data-ke-native-card-live-hidden");
		}
		restoreNativeLiveLabel(element) {
			element?.removeAttribute("data-ke-native-live-hidden");
		}
		updateCount(element, state) {
			const contentChanged = updateCountElementState(element, state);
			this.#renderedElements.add(element);
			return contentChanged;
		}
		updateUptime(element, state) {
			if (element.className !== state.className) element.className = state.className;
			setDatasetValue(element, "keSlug", state.slug);
			setDatasetValue(element, "keStartedAt", String(state.startedAt));
			setDatasetValue(element, "keTarget", state.target);
			setDatasetValue(element, "keStreamUptime", "");
			if (element.textContent !== state.text) element.textContent = state.text;
			if (element.getAttribute("aria-label") !== state.label) element.setAttribute("aria-label", state.label);
			this.#renderedElements.add(element);
		}
		#removeOrphanedElements() {
			for (const element of document.querySelectorAll(RENDER_ELEMENT_SELECTOR)) if (!this.#renderedElements.has(element)) element.remove();
		}
	};
	function cleanupViewerCountDom() {
		for (const element of document.querySelectorAll(RENDER_ELEMENT_SELECTOR)) element.remove();
		for (const element of document.querySelectorAll("[data-ke-native-live-hidden]")) element.removeAttribute("data-ke-native-live-hidden");
		for (const element of document.querySelectorAll(NATIVE_CARD_LIVE_HIDDEN_SELECTOR)) element.removeAttribute("data-ke-native-card-live-hidden");
		for (const element of document.querySelectorAll([SIDEBAR_UPTIME_CONTAINER_SELECTOR, TOOLTIP_UPTIME_CONTAINER_SELECTOR].join(", "))) {
			element.removeAttribute("data-ke-sidebar-uptime-container");
			element.removeAttribute("data-ke-tooltip-uptime-container");
		}
	}
	function setDatasetValue(element, key, value) {
		if (element.dataset[key] !== value) element.dataset[key] = value;
	}
	function restoreUnusedNativeLabels() {
		for (const label of document.querySelectorAll("[data-ke-native-live-hidden]")) {
			const statusContainer = label.parentElement;
			const slug = label.dataset.keNativeLiveHidden;
			const count = statusContainer?.querySelector(VIEWER_COUNT_SELECTOR);
			if (!count || count.dataset.keSlug !== slug) label.removeAttribute("data-ke-native-live-hidden");
		}
	}
	function restoreUnusedNativeCardLiveBadges() {
		for (const badge of document.querySelectorAll(NATIVE_CARD_LIVE_HIDDEN_SELECTOR)) {
			const uptime = badge.closest(CARD_THUMBNAIL_SELECTOR)?.querySelector(`${STREAM_UPTIME_SELECTOR}[data-ke-target="card"]`);
			const slug = badge.dataset.keNativeCardLiveHidden;
			if (!uptime || uptime.dataset.keSlug !== slug) badge.removeAttribute("data-ke-native-card-live-hidden");
		}
	}
	function restoreUnusedUptimeContainers() {
		restoreUptimeContainers(SIDEBAR_UPTIME_CONTAINER_SELECTOR, "data-ke-sidebar-uptime-container", "sidebar");
		restoreUptimeContainers(TOOLTIP_UPTIME_CONTAINER_SELECTOR, "data-ke-tooltip-uptime-container", "tooltip");
	}
	function restoreUptimeContainers(selector, attribute, target) {
		for (const container of document.querySelectorAll(selector)) {
			const uptime = container.querySelector(`${STREAM_UPTIME_SELECTOR}[data-ke-target="${target}"]`);
			const slug = container.getAttribute(attribute);
			if (!uptime || uptime.dataset.keSlug !== slug) container.removeAttribute(attribute);
		}
	}
	function isSidebarLinkHiddenByEnhancer(link, options) {
		if (options.hideRecommendedChannels && link.matches("a[data-testid^=\"sidebar-recommended-channel-\"]")) return true;
		return Boolean(options.hideGamblingStreams && link.closest("[data-kick-enhancer-gambling-stream]"));
	}
	function findSidebarTooltip(target, sourceLink) {
		for (const id of getTooltipIds(sourceLink)) {
			const describedElement = document.getElementById(id);
			const tooltip = describedElement?.closest("[data-radix-popper-content-wrapper]") ?? describedElement?.closest("[role=\"tooltip\"]");
			if (tooltip && !tooltip.closest("#sidebar-wrapper")) return tooltip;
		}
		const candidates = new Set();
		for (const element of document.querySelectorAll("[role=\"tooltip\"], [data-radix-popper-content-wrapper]")) {
			const candidate = element.closest("[data-radix-popper-content-wrapper]") ?? element;
			if (!candidate.closest("#sidebar-wrapper")) candidates.add(candidate);
		}
		return [...candidates].find((candidate) => containsExactText(candidate, target.displayName));
	}
	function findTooltipHeadingRow(tooltip, displayName) {
		for (const element of tooltip.querySelectorAll("span, p, div")) {
			if (element.childElementCount > 0) continue;
			if (element.textContent?.trim() !== displayName.trim()) continue;
			let row = element.parentElement;
			for (let depth = 0; row && depth < 3; depth += 1) {
				if (row.classList.contains("flex") || window.getComputedStyle(row).display === "flex") return row;
				row = row.parentElement;
			}
		}
	}
	function isSidebarExpanded() {
		if (document.querySelector("[data-sidebar][data-chat][data-theatre], [data-sidebar]")?.getAttribute("data-sidebar") === "false") return false;
		return document.querySelector("button[aria-controls=\"sidebar-wrapper\"], button[aria-label=\"Collapse sidebar\"], button[aria-label=\"Expand sidebar\"], button[data-testid=\"sidebar-collapse\"], button[data-testid=\"sidebar-expand\"]")?.getAttribute("aria-expanded") !== "false";
	}
	function getTooltipIds(sourceLink) {
		const ids = new Set();
		for (const attribute of ["aria-describedby", "aria-controls"]) for (const id of (sourceLink.getAttribute(attribute) ?? "").split(/\s+/)) if (id) ids.add(id);
		return ids;
	}
	function containsExactText(scope, expected) {
		const normalizedExpected = expected.trim().toLowerCase();
		return [...scope.querySelectorAll("span, p, div")].some((element) => !element.closest(RENDER_ELEMENT_SELECTOR) && element.childElementCount === 0 && element.textContent?.trim().toLowerCase() === normalizedExpected);
	}
	function renderSidebarSurface(store, ownership, sidebarLinks, options) {
		const targetSlugs = new Set();
		const uptimeEnabled = options.showStreamUptime && isSidebarExpanded();
		let uptimes = 0;
		let viewerCounts = 0;
		for (const link of sidebarLinks) {
			const hidden = isSidebarLinkHiddenByEnhancer(link, options);
			const slug = getChannelSlugFromHref(link.getAttribute("href"));
			const statusLabel = findStatusLabel(link);
			const statusContainer = statusLabel?.parentElement;
			const canRender = Boolean(!hidden && slug && statusLabel && statusContainer);
			const nativeCountVisible = isCompactCount(statusLabel?.textContent);
			const countEligible = canRender && options.showHiddenViewerCounts && !nativeCountVisible;
			const uptimeEligible = canRender && uptimeEnabled;
			let stream;
			if ((countEligible || uptimeEligible) && slug) {
				targetSlugs.add(slug);
				stream = store.get(slug);
			}
			if (!countEligible || !slug || !statusLabel || !statusContainer || !stream || stream.showViewCount) {
				ownership.removeCount(link, "sidebar");
				ownership.restoreNativeLiveLabel(statusLabel);
			} else {
				renderSidebarCount(ownership, link, statusLabel, statusContainer, slug, stream.viewerCount);
				viewerCounts += 1;
			}
			if (!uptimeEligible || !slug || !statusContainer || stream?.startedAt === void 0) ownership.removeUptime(link, "sidebar");
			else uptimes += renderSidebarUptime(ownership, link, statusContainer, slug, stream.startedAt);
		}
		return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
	}
	function renderSidebarCount(ownership, link, statusLabel, statusContainer, slug, viewerCount) {
		ownership.hideNativeLiveLabel(statusLabel, slug);
		const element = ownership.findCount(link, "sidebar") ?? document.createElement("span");
		ownership.updateCount(element, {
			className: "ke-viewer-count-sidebar",
			count: viewerCount,
			slug,
			target: "sidebar",
			text: formatViewerCount(viewerCount)
		});
		if (element.parentElement !== statusContainer) statusContainer.append(element);
	}
	function renderSidebarUptime(ownership, link, statusContainer, slug, startedAt) {
		const uptime = formatStreamUptime(startedAt);
		if (!uptime) {
			ownership.removeUptime(link, "sidebar");
			return 0;
		}
		const element = ownership.findUptime(link, "sidebar") ?? document.createElement("span");
		ownership.updateUptime(element, {
			className: "ke-stream-uptime-sidebar",
			label: `Live for ${uptime}`,
			slug,
			startedAt,
			target: "sidebar",
			text: uptime
		});
		ownership.markUptimeContainer(statusContainer, "sidebar", slug);
		if (element.parentElement !== statusContainer) statusContainer.append(element);
		return 1;
	}
	function renderSidebarTooltipSurface(store, ownership, sidebarLinks, target, options) {
		const targetSlugs = new Set();
		let uptimes = 0;
		let viewerCounts = 0;
		if (!target || !options.showHiddenViewerCounts && !options.showStreamUptime) return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
		const sourceLink = sidebarLinks.find((link) => getChannelSlugFromHref(link.getAttribute("href")) === target.slug);
		if (!sourceLink || isSidebarLinkHiddenByEnhancer(sourceLink, options)) return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
		targetSlugs.add(target.slug);
		const stream = store.get(target.slug);
		if (!stream) return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
		const countEligible = options.showHiddenViewerCounts && !stream.showViewCount;
		const startedAt = options.showStreamUptime ? stream.startedAt : void 0;
		const uptime = startedAt === void 0 ? void 0 : formatStreamUptime(startedAt);
		if (!countEligible && !uptime) return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
		const tooltip = findSidebarTooltip(target, sourceLink);
		if (!tooltip) return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
		const statusLabel = findStatusLabel(tooltip);
		const statusContainer = statusLabel?.parentElement ?? findTooltipHeadingRow(tooltip, target.displayName);
		if (!statusContainer) return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
		if (countEligible && !(statusLabel && isCompactCount(statusLabel.textContent))) {
			if (statusLabel) ownership.hideNativeLiveLabel(statusLabel, target.slug);
			const countElement = ownership.findCount(tooltip, "tooltip") ?? document.createElement("span");
			ownership.updateCount(countElement, {
				className: ["ke-viewer-count-tooltip", statusLabel ? "" : "ke-viewer-count-tooltip--standalone"].filter(Boolean).join(" "),
				count: stream.viewerCount,
				slug: target.slug,
				target: "tooltip",
				text: formatViewerCount(stream.viewerCount)
			});
			if (countElement.parentElement !== statusContainer) statusContainer.append(countElement);
			viewerCounts = 1;
		}
		if (uptime && startedAt !== void 0) {
			const uptimeElement = ownership.findUptime(tooltip, "tooltip") ?? document.createElement("span");
			ownership.updateUptime(uptimeElement, {
				className: "ke-stream-uptime-tooltip",
				label: `Live for ${uptime}`,
				slug: target.slug,
				startedAt,
				target: "tooltip",
				text: uptime
			});
			ownership.markUptimeContainer(statusContainer, "tooltip", target.slug);
			if (uptimeElement.parentElement !== statusContainer) statusContainer.append(uptimeElement);
			uptimes = 1;
		}
		return {
			targetSlugs,
			uptimes,
			viewerCounts
		};
	}
	var log$2 = createLogger("viewer-counts:render");
	function renderViewerCounts(store, sidebarHoverTarget, options) {
		const ownership = new ViewerCountDomOwnership();
		const sidebarLinks = [...document.querySelectorAll(SIDEBAR_LINK_SELECTOR)];
		try {
			const channel = renderSurface("channel", () => renderChannelSurface(store, ownership, options.showHiddenViewerCounts), emptyChannelResult);
			const cards = renderSurface("cards", () => renderCardSurfaces(store, ownership, options), emptySurfaceResult);
			const sidebar = renderSurface("sidebar", () => renderSidebarSurface(store, ownership, sidebarLinks, options), emptySurfaceResult);
			const tooltip = renderSurface("sidebar-tooltip", () => renderSidebarTooltipSurface(store, ownership, sidebarLinks, sidebarHoverTarget, options), emptySurfaceResult);
			return {
				...channel.slug ? { activeChannelSlug: channel.slug } : {},
				counts: {
					cardUptimes: cards.uptimes,
					cards: cards.viewerCounts,
					channel: channel.rendered,
					sidebar: sidebar.viewerCounts,
					sidebarUptimes: sidebar.uptimes,
					tooltipUptimes: tooltip.uptimes,
					tooltips: tooltip.viewerCounts
				},
				targetSlugs: collectTargetSlugs(channel, cards, sidebar, tooltip)
			};
		} finally {
			ownership.finalize();
		}
	}
	function renderSurface(name, render, fallback) {
		try {
			return render();
		} catch (error) {
			log$2.error("Surface render failed", {
				error: error instanceof Error ? error.message : String(error),
				surface: name
			});
			return fallback();
		}
	}
	function emptyChannelResult() {
		return {
			rendered: 0,
			targetSlugs: new Set()
		};
	}
	function emptySurfaceResult() {
		return {
			targetSlugs: new Set(),
			uptimes: 0,
			viewerCounts: 0
		};
	}
	function collectTargetSlugs(...results) {
		const targetSlugs = new Set();
		for (const result of results) for (const slug of result.targetSlugs) targetSlugs.add(slug);
		return targetSlugs;
	}
	var MAX_RECORD_AGE_MS = 300 * 1e3;
	var MAX_STORED_STREAMS = 500;
	var SOURCE_PRIORITY = {
		"channel-details": 6,
		"current-viewers": 7,
		featured: 2,
		"followed-channels": 4,
		recommendations: 2,
		"sidebar-recommendations": 3,
		"user-livestreams": 5
	};
	var ViewerCountStore = class {
		#currentViewersById = new Map();
		#slugByLivestreamId = new Map();
		#streamsBySlug = new Map();
		upsertStreams(streams) {
			let updated = 0;
			for (const incoming of streams) {
				const existing = this.#streamsBySlug.get(incoming.channelSlug);
				if (!existing || shouldReplace(existing, incoming)) {
					const replacement = existing ? mergeReplacement(existing, incoming) : incoming;
					if (existing?.livestreamId !== void 0 && existing.livestreamId !== replacement.livestreamId) {
						this.#slugByLivestreamId.delete(existing.livestreamId);
						this.#currentViewersById.delete(existing.livestreamId);
					}
					this.#streamsBySlug.set(replacement.channelSlug, replacement);
					updated += 1;
				}
				const stored = this.#streamsBySlug.get(incoming.channelSlug);
				if (stored?.livestreamId !== void 0) this.#slugByLivestreamId.set(stored.livestreamId, stored.channelSlug);
			}
			this.prune();
			return updated;
		}
		upsertCurrentViewers(entries) {
			let updated = 0;
			for (const entry of entries) {
				const existing = this.#currentViewersById.get(entry.livestreamId);
				if (!existing || entry.capturedAt >= existing.capturedAt) {
					this.#currentViewersById.set(entry.livestreamId, entry);
					updated += 1;
				}
			}
			this.prune();
			return updated;
		}
		get(channelSlug, now = Date.now()) {
			const stream = this.#streamsBySlug.get(channelSlug);
			if (!stream || !stream.isLive) return;
			if (stream.livestreamId === void 0) return now - stream.capturedAt <= MAX_RECORD_AGE_MS ? stream : void 0;
			const current = this.#currentViewersById.get(stream.livestreamId);
			if (!(current !== void 0 && now - current.capturedAt <= MAX_RECORD_AGE_MS) || current.capturedAt < stream.capturedAt) return now - stream.capturedAt <= MAX_RECORD_AGE_MS ? stream : void 0;
			return {
				...stream,
				capturedAt: current.capturedAt,
				showViewCount: current.showViewCount ?? stream.showViewCount,
				source: "current-viewers",
				viewerCount: current.viewerCount
			};
		}
		getLivestreamIds(channelSlugs) {
			const ids = new Set();
			for (const slug of channelSlugs) {
				const stream = this.get(slug);
				if (stream?.livestreamId !== void 0) ids.add(stream.livestreamId);
			}
			return ids;
		}
		remove(channelSlug) {
			const stream = this.#streamsBySlug.get(channelSlug);
			this.#streamsBySlug.delete(channelSlug);
			if (stream?.livestreamId !== void 0) {
				this.#slugByLivestreamId.delete(stream.livestreamId);
				this.#currentViewersById.delete(stream.livestreamId);
			}
		}
		removeLivestreamIds(livestreamIds) {
			let removed = 0;
			for (const id of livestreamIds) {
				const slug = this.#slugByLivestreamId.get(id);
				if (!slug) continue;
				this.remove(slug);
				removed += 1;
			}
			return removed;
		}
		prune(now = Date.now()) {
			for (const [slug, stream] of this.#streamsBySlug) {
				if (now - stream.capturedAt <= MAX_RECORD_AGE_MS || this.get(slug, now)) continue;
				this.remove(slug);
			}
			for (const [id, entry] of this.#currentViewersById) if (now - entry.capturedAt > MAX_RECORD_AGE_MS) this.#currentViewersById.delete(id);
			if (this.#streamsBySlug.size <= MAX_STORED_STREAMS) return;
			const oldest = [...this.#streamsBySlug.values()].sort((left, right) => left.capturedAt - right.capturedAt).slice(0, this.#streamsBySlug.size - MAX_STORED_STREAMS);
			for (const stream of oldest) this.remove(stream.channelSlug);
		}
		clear() {
			this.#currentViewersById.clear();
			this.#slugByLivestreamId.clear();
			this.#streamsBySlug.clear();
		}
	};
	function shouldReplace(existing, incoming) {
		if (incoming.capturedAt !== existing.capturedAt) return incoming.capturedAt > existing.capturedAt;
		return SOURCE_PRIORITY[incoming.source] >= SOURCE_PRIORITY[existing.source];
	}
	function mergeReplacement(existing, incoming) {
		const sameLivestream = existing.livestreamId === void 0 || incoming.livestreamId === void 0 || existing.livestreamId === incoming.livestreamId;
		const preserveHiddenState = sameLivestream && !existing.showViewCount && incoming.showViewCount && incoming.source === "channel-details";
		const startedAt = sameLivestream && incoming.startedAt === void 0 ? existing.startedAt : incoming.startedAt;
		return {
			...incoming,
			...startedAt === void 0 ? {} : { startedAt },
			...preserveHiddenState ? { showViewCount: false } : {}
		};
	}
	var viewerCounts_default = "[data-ke-viewer-count],\n[data-ke-stream-uptime] {\n  box-sizing: border-box;\n  font-family: inherit;\n  white-space: nowrap;\n}\n\n.ke-viewer-count-card,\n.ke-stream-uptime-card {\n  position: absolute;\n  z-index: 20;\n  padding: 0 0.25rem;\n  color: var(--neon-surface-onSurface, #fff);\n  font-variant-numeric: tabular-nums;\n  line-height: 1.5rem;\n  pointer-events: none;\n  border-radius: 0.25rem;\n}\n\n.ke-viewer-count-card {\n  bottom: 0.375rem;\n  left: 0.375rem;\n  font-size: 0.875rem;\n  font-weight: 600;\n  background: var(--neon-surface-lowest, #0e0f12);\n}\n\n.ke-stream-uptime-card {\n  top: 0.375rem;\n  left: 0.375rem;\n  display: inline-flex;\n  align-items: center;\n  gap: 0.25rem;\n  font-size: 0.75rem;\n  font-weight: 500;\n  background: #0b0b0c;\n}\n.ke-stream-uptime-card::before {\n  width: 0.5rem;\n  height: 0.5rem;\n  flex: 0 0 auto;\n  content: \"\";\n  background: var(--neon-primary-base, #53fc18);\n  border-radius: 9999px;\n}\n\n.ke-viewer-count-sidebar,\n.ke-viewer-count-tooltip {\n  display: inline-flex;\n  flex: 0 0 auto;\n  align-items: center;\n  color: inherit;\n  font-size: 0.875rem;\n  font-weight: 600;\n  line-height: 1.25rem;\n}\n\n.ke-stream-uptime-tooltip {\n  position: absolute;\n  top: 100%;\n  right: 0;\n  color: var(--neon-surface-onSurfaceSecondary, #9fa6ad);\n  font-size: 0.6875rem;\n  font-variant-numeric: tabular-nums;\n  font-weight: 500;\n  line-height: 1rem;\n  pointer-events: none;\n  white-space: nowrap;\n}\n\n[data-ke-tooltip-uptime-container],\n[data-ke-sidebar-uptime-container] {\n  position: relative;\n}\n\n.ke-stream-uptime-sidebar {\n  position: absolute;\n  top: 100%;\n  right: 0;\n  color: var(--neon-surface-onSurfaceSecondary, #9fa6ad);\n  font-size: 0.6875rem;\n  font-variant-numeric: tabular-nums;\n  font-weight: 500;\n  line-height: 1rem;\n  pointer-events: none;\n  white-space: nowrap;\n}\n\n.ke-viewer-count-tooltip--standalone {\n  gap: 0.25rem;\n  margin-left: auto;\n}\n.ke-viewer-count-tooltip--standalone::before {\n  width: 0.5rem;\n  height: 0.5rem;\n  content: \"\";\n  background: var(--neon-primary-base, #53fc18);\n  border-radius: 9999px;\n}\n\n.ke-viewer-count-channel {\n  display: inline-flex;\n  align-items: center;\n  min-height: 1.375rem;\n  gap: 0.25rem;\n  color: var(--neon-surface-onSurface, #fff);\n  font-size: 0.875rem;\n  font-weight: 700;\n  line-height: 1.25rem;\n}\n.ke-viewer-count-channel svg {\n  width: 1rem;\n  height: 1rem;\n  flex: 0 0 auto;\n  fill: currentcolor;\n}\n\n.ke-viewer-count-channel__content {\n  display: inline-flex;\n  align-items: center;\n  gap: 0.25rem;\n  color: var(--neon-surface-onSurfaceSecondary, #9fa6ad);\n}\n\n.ke-viewer-count-channel__value {\n  color: var(--neon-primary-base, #53fc18);\n}\n\n.ke-animated-number {\n  display: inline-flex;\n  align-items: center;\n  font-variant-numeric: tabular-nums;\n}\n\n.ke-animated-number__digit {\n  position: relative;\n  display: inline-block;\n  width: 1ch;\n  height: 1.25rem;\n  overflow: hidden;\n}\n\n.ke-animated-number__reel {\n  position: absolute;\n  top: 0;\n  left: 0;\n  display: flex;\n  width: 100%;\n  flex-direction: column;\n  will-change: transform;\n}\n\n.ke-animated-number__cell {\n  display: flex;\n  width: 100%;\n  height: 1.25rem;\n  flex: 0 0 1.25rem;\n  align-items: center;\n  justify-content: center;\n  line-height: 1.25rem;\n}\n\n.ke-animated-number__separator {\n  display: inline-block;\n  height: 1.25rem;\n  line-height: 1.25rem;\n}\n\n[data-ke-native-live-hidden] {\n  display: none !important;\n}\n\n[data-ke-native-card-live-hidden] {\n  display: none !important;\n}";
	var STYLE_ID$1 = "kick-enhancer-viewer-count-styles";
	var RENDER_DELAY_MS = 150;
	var UPTIME_REFRESH_INTERVAL_MS = 60 * 1e3;
	var log$1 = createLogger("viewer-counts");
	var store = new ViewerCountStore();
	var acquisition = new ViewerCountAcquisition({
		onData: () => scheduleRender("network"),
		store
	});
	var captureInitialized = false;
	var domFeatureActive = false;
	var cancelDomReady;
	var featureEnabled = false;
	var historyPushState;
	var historyReplaceState;
	var historyPushStateWrapper;
	var historyReplaceStateWrapper;
	var lastLogSummary = "";
	var lastUrl = window.location.href;
	var observer;
	var renderDeadline = Number.POSITIVE_INFINITY;
	var renderReason = "";
	var renderTimer;
	var sidebarHoverTarget;
	var streamUptimeEnabled = false;
	var stopActiveFeature$1;
	var stopWatchingSettings;
	var uptimeRefreshTimer;
	function initializeViewerCountCapture() {
		if (captureInitialized) return;
		captureInitialized = true;
		window.addEventListener("message", handleCaptureMessage);
		installViewerCountCaptureBridge();
	}
	function startViewerEnhancements() {
		stopActiveFeature$1?.();
		const settings = getSettings();
		setFeaturesEnabled(settings.ui.showHiddenViewerCounts, settings.ui.showStreamUptime);
		stopWatchingSettings = subscribeSettings((settings) => {
			setFeaturesEnabled(settings.ui.showHiddenViewerCounts, settings.ui.showStreamUptime);
		});
		let stopped = false;
		const stop = () => {
			if (stopped) return;
			stopped = true;
			stopWatchingSettings?.();
			stopWatchingSettings = void 0;
			featureEnabled = false;
			streamUptimeEnabled = false;
			cancelFeatureActivation();
			deactivateFeatureDom();
			if (stopActiveFeature$1 === stop) stopActiveFeature$1 = void 0;
		};
		stopActiveFeature$1 = stop;
		return stop;
	}
	function setFeaturesEnabled(showHiddenViewerCounts, showStreamUptime) {
		const wasEnabled = featureEnabled;
		featureEnabled = showHiddenViewerCounts || showStreamUptime;
		streamUptimeEnabled = showStreamUptime;
		if (featureEnabled) {
			if (!wasEnabled) {
				requestFeatureActivation();
				return;
			}
			syncUptimeRefreshTimer();
			scheduleRender("settings", 0);
			return;
		}
		if (wasEnabled) {
			cancelFeatureActivation();
			deactivateFeatureDom();
			log$1.info("Disabled");
		}
	}
	function requestFeatureActivation() {
		if (document.documentElement) {
			activateFeatureDom();
			return;
		}
		if (cancelDomReady) return;
		cancelDomReady = onDocumentElementReady(() => {
			cancelDomReady = void 0;
			activateFeatureDom();
		});
	}
	function cancelFeatureActivation() {
		cancelDomReady?.();
		cancelDomReady = void 0;
	}
	function activateFeatureDom() {
		if (!featureEnabled || domFeatureActive || !document.documentElement) return;
		cancelFeatureActivation();
		domFeatureActive = true;
		lastUrl = window.location.href;
		applyStyleToggle(STYLE_ID$1, viewerCounts_default, true);
		acquisition.start();
		installDomObserver();
		installRouteObserver();
		document.addEventListener("pointerover", handleSidebarHover, true);
		document.addEventListener("pointerout", handleSidebarHoverEnd, true);
		document.addEventListener("focusin", handleSidebarHover, true);
		document.addEventListener("focusout", handleSidebarHoverEnd, true);
		syncUptimeRefreshTimer();
		scheduleRender("enabled", 0);
		log$1.info("Enabled");
	}
	function deactivateFeatureDom() {
		if (!domFeatureActive) {
			sidebarHoverTarget = void 0;
			cleanupViewerCountDom();
			applyStyleToggle(STYLE_ID$1, viewerCounts_default, false);
			return;
		}
		domFeatureActive = false;
		acquisition.stop();
		observer?.disconnect();
		observer = void 0;
		uninstallRouteObserver();
		document.removeEventListener("pointerover", handleSidebarHover, true);
		document.removeEventListener("pointerout", handleSidebarHoverEnd, true);
		document.removeEventListener("focusin", handleSidebarHover, true);
		document.removeEventListener("focusout", handleSidebarHoverEnd, true);
		if (renderTimer !== void 0) {
			window.clearTimeout(renderTimer);
			renderTimer = void 0;
			renderDeadline = Number.POSITIVE_INFINITY;
			renderReason = "";
		}
		clearUptimeRefreshTimer();
		sidebarHoverTarget = void 0;
		cleanupViewerCountDom();
		applyStyleToggle(STYLE_ID$1, viewerCounts_default, false);
	}
	function syncUptimeRefreshTimer() {
		if (!domFeatureActive || !streamUptimeEnabled) {
			clearUptimeRefreshTimer();
			return;
		}
		if (uptimeRefreshTimer !== void 0) return;
		uptimeRefreshTimer = window.setInterval(() => {
			if (!document.hidden) scheduleRender("uptime", 0);
		}, UPTIME_REFRESH_INTERVAL_MS);
	}
	function clearUptimeRefreshTimer() {
		if (uptimeRefreshTimer === void 0) return;
		window.clearInterval(uptimeRefreshTimer);
		uptimeRefreshTimer = void 0;
	}
	function handleCaptureMessage(event) {
		if (event.source !== window && event.source !== _unsafeWindow || event.origin !== window.location.origin || !isCapturedViewerCountMessage(event.data)) return;
		const message = event.data;
		if (classifyViewerCountEndpoint(message.url, window.location.href) !== message.endpoint || Math.abs(Date.now() - message.timestamp) > 60 * 1e3) return;
		const normalized = normalizeViewerCountPayload(message.endpoint, message.payload, message.timestamp);
		recordViewerEndpointObservation(message.endpoint, normalized, message.timestamp, "captured");
		const streamCount = normalized.kind === "streams" ? normalized.streams.length : 0;
		const hiddenStreamCount = normalized.kind === "streams" ? normalized.streams.filter((stream) => !stream.showViewCount).length : 0;
		const updated = normalized.kind === "streams" ? store.upsertStreams(normalized.streams) : store.upsertCurrentViewers(normalized.currentViewers);
		if (message.endpoint === "PAGINATED_RECOMMENDED_LIVESTREAMS" && featureEnabled && hiddenStreamCount > 0) log$1.info("Hidden data captured", {
			hiddenStreams: hiddenStreamCount,
			streams: streamCount,
			updated
		});
		if (updated === 0) return;
		if (message.endpoint !== "CURRENT_VIEWERS") log$1.debug("Data captured", {
			endpoint: message.endpoint,
			updated
		});
		if (featureEnabled) scheduleRender("capture");
	}
	function installDomObserver() {
		if (observer || !document.documentElement) return;
		observer = new MutationObserver((mutations) => {
			if (window.location.href !== lastUrl) handleRouteChange();
			if (mutations.some((mutation) => !isIgnoredMutation(mutation))) scheduleRender("mutation");
		});
		observer.observe(document.documentElement, {
			attributeFilter: [
				"data-sidebar",
				"data-testid",
				"href"
			],
			attributes: true,
			characterData: true,
			childList: true,
			subtree: true
		});
	}
	function scheduleRender(reason, delay = RENDER_DELAY_MS) {
		if (!featureEnabled || !domFeatureActive) return;
		const deadline = performance.now() + Math.max(0, delay);
		if (renderTimer !== void 0 && deadline >= renderDeadline) return;
		if (renderTimer !== void 0) window.clearTimeout(renderTimer);
		renderDeadline = deadline;
		renderReason = reason;
		renderTimer = window.setTimeout(() => {
			const scheduledReason = renderReason;
			renderTimer = void 0;
			renderDeadline = Number.POSITIVE_INFINITY;
			renderReason = "";
			runRender(scheduledReason);
		}, Math.max(0, deadline - performance.now()));
	}
	function runRender(reason) {
		if (!featureEnabled) return;
		const result = renderViewerCounts(store, sidebarHoverTarget, getSettings().ui);
		acquisition.syncTargets(result.targetSlugs, result.activeChannelSlug);
		const summary = JSON.stringify(result.counts);
		if (summary !== lastLogSummary) {
			lastLogSummary = summary;
			const details = {
				reason,
				...result.counts,
				targets: result.targetSlugs.size
			};
			if (result.counts.cardUptimes + result.counts.cards + result.counts.channel + result.counts.sidebar + result.counts.sidebarUptimes + result.counts.tooltipUptimes + result.counts.tooltips > 0) log$1.info("Rendered", details);
			else log$1.debug("Surfaces updated", details);
		}
	}
	function handleSidebarHover(event) {
		if (!(event.target instanceof Element)) return;
		const link = event.target.closest(SIDEBAR_LINK_SELECTOR);
		const slug = getChannelSlugFromHref(link?.getAttribute("href"));
		if (!link || !slug) return;
		const displayName = link.querySelector("img[alt]")?.alt.trim() || findSidebarDisplayName(link);
		if (!displayName) return;
		sidebarHoverTarget = {
			displayName,
			slug
		};
		scheduleRender("sidebar-hover", 0);
	}
	function handleSidebarHoverEnd(event) {
		if (!(event.target instanceof Element)) return;
		const link = event.target.closest(SIDEBAR_LINK_SELECTOR);
		const slug = getChannelSlugFromHref(link?.getAttribute("href"));
		if (!link || !slug || sidebarHoverTarget?.slug !== slug) return;
		const relatedTarget = event.relatedTarget;
		if (relatedTarget instanceof Node && link.contains(relatedTarget)) return;
		sidebarHoverTarget = void 0;
		scheduleRender("sidebar-hover-end", 0);
	}
	function findSidebarDisplayName(link) {
		for (const element of link.querySelectorAll("span")) {
			const text = element.textContent?.trim();
			if (text && text.toLowerCase() !== "live" && !/^\d+(?:\.\d+)?[km]?$/i.test(text)) return text;
		}
	}
	function installRouteObserver() {
		if (historyPushStateWrapper || historyReplaceStateWrapper) return;
		historyPushState = window.history.pushState;
		historyReplaceState = window.history.replaceState;
		historyPushStateWrapper = function(...argumentsList) {
			Reflect.apply(historyPushState, this, argumentsList);
			handleRouteChange();
		};
		historyReplaceStateWrapper = function(...argumentsList) {
			Reflect.apply(historyReplaceState, this, argumentsList);
			handleRouteChange();
		};
		window.history.pushState = historyPushStateWrapper;
		window.history.replaceState = historyReplaceStateWrapper;
		window.addEventListener("popstate", handleRouteChange);
	}
	function uninstallRouteObserver() {
		window.removeEventListener("popstate", handleRouteChange);
		if (historyPushState && window.history.pushState === historyPushStateWrapper) window.history.pushState = historyPushState;
		if (historyReplaceState && window.history.replaceState === historyReplaceStateWrapper) window.history.replaceState = historyReplaceState;
		historyPushState = void 0;
		historyReplaceState = void 0;
		historyPushStateWrapper = void 0;
		historyReplaceStateWrapper = void 0;
	}
	function handleRouteChange() {
		if (window.location.href === lastUrl) return;
		lastUrl = window.location.href;
		sidebarHoverTarget = void 0;
		acquisition.beginRoute();
		scheduleRender("route", 0);
		log$1.debug("Route changed", { pathname: window.location.pathname });
	}
	function isIgnoredMutation(mutation) {
		if ((mutation.target instanceof Element ? mutation.target : mutation.target.parentElement)?.closest("#chatroom-messages, #channel-chatroom, [data-ke-viewer-count], [data-ke-stream-uptime]")) return true;
		const changedNodes = [...mutation.addedNodes, ...mutation.removedNodes];
		return changedNodes.length > 0 && changedNodes.every((node) => node instanceof Element && (node.matches("[data-ke-viewer-count], [data-ke-stream-uptime]") || Boolean(node.closest("[data-ke-viewer-count], [data-ke-stream-uptime]"))));
	}
	function composeDisposers(...disposers) {
		let disposed = false;
		return () => {
			if (disposed) return;
			disposed = true;
			for (let index = disposers.length - 1; index >= 0; index -= 1) disposers[index]?.();
		};
	}
	function ConfirmationDialog({ cancelLabel = "Cancel", confirmLabel = "OK", confirmTone = "primary", description, onCancel, onConfirm, onDismiss, open, title }) {
		const dialogRef = (0, preact_hooks.useRef)(null);
		const titleId = (0, preact_hooks.useId)();
		const descriptionId = (0, preact_hooks.useId)();
		(0, preact_hooks.useEffect)(() => {
			if (!open) return;
			const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
			dialogRef.current?.querySelector("button")?.focus();
			return () => {
				if (previousFocus?.isConnected) previousFocus.focus();
			};
		}, [open]);
		if (!open) return null;
		const dismiss = onDismiss ?? onCancel;
		const handleKeyDown = (event) => {
			if (event.key === "Escape") {
				if (dismiss) {
					event.preventDefault();
					event.stopPropagation();
					dismiss();
				}
				return;
			}
			if (event.key !== "Tab") return;
			const buttons = dialogRef.current?.querySelectorAll("button:not(:disabled)");
			const firstButton = buttons?.item(0);
			const lastButton = buttons?.item((buttons?.length ?? 1) - 1);
			if (!firstButton || !lastButton) return;
			if (event.shiftKey && document.activeElement === firstButton) {
				event.preventDefault();
				lastButton.focus();
			} else if (!event.shiftKey && document.activeElement === lastButton) {
				event.preventDefault();
				firstButton.focus();
			}
		};
		return (0, preact_jsx_runtime.jsx)("div", {
			className: "ke-confirmation-layer",
			children: (0, preact_jsx_runtime.jsxs)("div", {
				"aria-describedby": descriptionId,
				"aria-labelledby": titleId,
				"aria-modal": "true",
				className: "ke-confirmation-dialog",
				onKeyDown: handleKeyDown,
				ref: dialogRef,
				role: "alertdialog",
				children: [(0, preact_jsx_runtime.jsxs)("div", {
					className: "ke-confirmation-dialog__copy",
					children: [(0, preact_jsx_runtime.jsx)("h3", {
						className: "ke-confirmation-dialog__title",
						id: titleId,
						children: title
					}), (0, preact_jsx_runtime.jsx)("p", {
						className: "ke-confirmation-dialog__description",
						id: descriptionId,
						children: description
					})]
				}), (0, preact_jsx_runtime.jsxs)("div", {
					className: "ke-confirmation-dialog__actions",
					children: [onCancel ? (0, preact_jsx_runtime.jsx)(Button, {
						onClick: onCancel,
						children: cancelLabel
					}) : null, (0, preact_jsx_runtime.jsx)(Button, {
						onClick: onConfirm,
						tone: confirmTone,
						children: confirmLabel
					})]
				})]
			})
		});
	}
	var package_default = {
		name: "kick-enhancer",
		version: "0.1.1",
		"private": true,
		description: "Enhances KICK with viewer counts, stream uptime, content controls, and direct clip downloads.",
		homepage: "https://github.com/sixem/kick-enhancer#readme",
		repository: {
			"type": "git",
			"url": "https://github.com/sixem/kick-enhancer.git"
		},
		bugs: { "url": "https://github.com/sixem/kick-enhancer/issues" },
		type: "module",
		packageManager: "[email protected]",
		scripts: {
			"dev": "node scripts/dev.mjs",
			"build": "pnpm typecheck && vite build",
			"build:greasyfork": "pnpm typecheck && vite build --mode greasyfork",
			"preview": "vite preview",
			"test": "node --test --experimental-transform-types tests/*.test.mjs",
			"typecheck": "tsc --noEmit"
		},
		dependencies: {
			"mux.js": "6.3.0",
			"preact": "^10.29.7"
		},
		devDependencies: {
			"@preact/preset-vite": "^2.10.6",
			"happy-dom": "^20.11.1",
			"sass-embedded": "^1.100.0",
			"typescript": "^6.0.2",
			"vite": "^8.1.5",
			"vite-plugin-monkey": "^8.1.0"
		}
	};
	function AboutTab({ onImportError, onImportRequest }) {
		const fileInputRef = (0, preact_hooks.useRef)(null);
		const rejectImport = () => onImportError();
		const handleImportSelection = async (event) => {
			const input = event.currentTarget;
			const file = input.files?.[0];
			input.value = "";
			if (!file) return;
			if (file.size > 64 * 1024) return rejectImport();
			let text;
			try {
				text = await file.text();
			} catch {
				return rejectImport();
			}
			const result = parseSettingsFile(text);
			if (!result.ok) return rejectImport();
			onImportRequest(result.settings, result.compatibilityWarning);
		};
		const exportSettings = () => {
			triggerDownload(new Blob([serializeSettings(getSettings())], { type: "application/json;charset=utf-8" }), `kick-enhancer-settings-v5.json`);
		};
		return (0, preact_jsx_runtime.jsxs)("section", {
			className: "ke-about",
			"aria-labelledby": "ke-about-title",
			children: [
				(0, preact_jsx_runtime.jsx)("img", {
					alt: "",
					className: "ke-about__icon",
					draggable: false,
					src: icon_default
				}),
				(0, preact_jsx_runtime.jsxs)("div", {
					className: "ke-about__identity",
					children: [(0, preact_jsx_runtime.jsx)("h3", {
						className: "ke-about__title",
						id: "ke-about-title",
						children: "KICK Enhancer"
					}), (0, preact_jsx_runtime.jsxs)("p", {
						className: "ke-about__version",
						children: ["Version ", package_default.version]
					})]
				}),
				(0, preact_jsx_runtime.jsx)("p", {
					className: "ke-about__description",
					children: "A userscript that makes KICK cleaner and puts useful viewing information back in sight."
				}),
				(0, preact_jsx_runtime.jsxs)("div", {
					className: "ke-about__actions",
					children: [
						(0, preact_jsx_runtime.jsx)(Button, {
							onClick: () => fileInputRef.current?.click(),
							children: "Import settings"
						}),
						(0, preact_jsx_runtime.jsx)(Button, {
							onClick: exportSettings,
							children: "Export settings"
						}),
						(0, preact_jsx_runtime.jsx)("input", {
							accept: ".json,application/json",
							hidden: true,
							onChange: (event) => void handleImportSelection(event),
							ref: fileInputRef,
							type: "file"
						})
					]
				})
			]
		});
	}
	function triggerDownload(blob, filename) {
		const url = URL.createObjectURL(blob);
		const anchor = document.createElement("a");
		anchor.download = filename;
		anchor.href = url;
		anchor.hidden = true;
		document.body.append(anchor);
		anchor.click();
		anchor.remove();
		window.setTimeout(() => URL.revokeObjectURL(url), 0);
	}
	var MAX_ARRAY_ITEMS = 20;
	var MAX_DEPTH = 3;
	var MAX_STRING_LENGTH = 500;
	var REDACTED_KEY_PATTERN = /authorization|cookie|credential|password|playback|secret|session|signature|token/i;
	var URL_PATTERN = /https?:\/\/[^\s"'<>]+/gi;
	function formatLogEntry(entry) {
		const time = new Date(entry.timestamp);
		const timestamp = Number.isNaN(time.getTime()) ? "Invalid time" : time.toISOString();
		const message = entry.arguments.map((value) => formatLogValue(value)).join(" ");
		return `${timestamp} [${entry.level.toUpperCase()}] [${entry.scope}] ${message}`;
	}
	function formatLogMessage(entry) {
		return entry.arguments.map(formatCompactLogValue).join("; ");
	}
	function formatLogValue(value) {
		if (typeof value === "string") return sanitizeText(value);
		if (value === null || typeof value === "number" || typeof value === "boolean" || typeof value === "undefined") return String(value);
		if (typeof value === "bigint") return `${value}n`;
		if (typeof value === "symbol") return value.description ? `Symbol(${value.description})` : "Symbol()";
		if (typeof value === "function") return `[Function ${value.name || "anonymous"}]`;
		try {
			return JSON.stringify(sanitizeValue(value, 0, new WeakSet()));
		} catch {
			return "[Unserializable value]";
		}
	}
	function formatCompactLogValue(value) {
		if (value instanceof Error) return `${value.name}: ${sanitizeText(value.message)}`;
		if (typeof value !== "object" || value === null || Array.isArray(value)) return formatLogValue(value);
		const prototype = Object.getPrototypeOf(value);
		if (prototype !== Object.prototype && prototype !== null) return formatLogValue(value);
		const sanitized = sanitizeValue(value, 0, new WeakSet());
		const entries = typeof sanitized === "object" && sanitized !== null ? Object.entries(sanitized) : [];
		return entries.length === 0 ? "{}" : entries.map(([key, entry]) => `${key}=${formatCompactDataValue(entry)}`).join("; ");
	}
	function formatCompactDataValue(value) {
		if (typeof value === "string") return value;
		if (value === null || typeof value === "number" || typeof value === "boolean" || typeof value === "undefined") return String(value);
		return JSON.stringify(value);
	}
	function sanitizeValue(value, depth, seen) {
		if (typeof value === "string") return sanitizeText(value);
		if (value === null || typeof value === "number" || typeof value === "boolean" || typeof value === "undefined") return value;
		if (typeof value === "bigint") return `${value}n`;
		if (typeof value !== "object") return String(value);
		if (value instanceof Error) return {
			message: sanitizeText(value.message),
			name: value.name
		};
		if (depth >= MAX_DEPTH) return "[Max depth]";
		if (seen.has(value)) return "[Circular]";
		seen.add(value);
		if (Array.isArray(value)) {
			const values = value.slice(0, MAX_ARRAY_ITEMS).map((entry) => sanitizeValue(entry, depth + 1, seen));
			if (value.length > MAX_ARRAY_ITEMS) values.push(`[${value.length - MAX_ARRAY_ITEMS} more items]`);
			return values;
		}
		const sanitized = {};
		for (const [key, entry] of Object.entries(value)) sanitized[key] = REDACTED_KEY_PATTERN.test(key) ? "[Redacted]" : sanitizeValue(entry, depth + 1, seen);
		return sanitized;
	}
	function sanitizeText(value) {
		const withoutCredentials = value.replace(/\bBearer\s+\S+/gi, "Bearer [Redacted]").replace(URL_PATTERN, sanitizeUrl);
		return withoutCredentials.length > MAX_STRING_LENGTH ? `${withoutCredentials.slice(0, MAX_STRING_LENGTH)}…` : withoutCredentials;
	}
	function sanitizeUrl(rawUrl) {
		try {
			const url = new URL(rawUrl);
			const suffix = url.search || url.hash ? "?[redacted]" : "";
			return `${url.origin}${url.pathname}${suffix}`;
		} catch {
			return "[Invalid URL]";
		}
	}
	var EMPTY_LOGS = [];
	var EMPTY_OBSERVATIONS = [];
	var LOG_LEVEL_OPTIONS = [
		{
			label: "All levels",
			value: "all"
		},
		{
			label: "Debug",
			value: "debug"
		},
		{
			label: "Info",
			value: "info"
		},
		{
			label: "Warnings",
			value: "warn"
		},
		{
			label: "Errors",
			value: "error"
		}
	];
	var TIME_FORMATTER = new Intl.DateTimeFormat(void 0, {
		hour: "2-digit",
		hourCycle: "h23",
		minute: "2-digit",
		second: "2-digit"
	});
	var CHECK_COLUMNS = [
		{
			header: "Endpoint",
			id: "endpoint",
			renderCell: (result) => VIEWER_COUNT_ENDPOINT_LABELS[result.endpoint],
			width: "7.5rem"
		},
		{
			align: "center",
			header: "Status",
			id: "status",
			renderCell: (result) => (0, preact_jsx_runtime.jsx)(DiagnosticsPill, {
				label: result.status,
				tone: result.status
			}),
			width: "7.2rem"
		},
		{
			align: "center",
			header: "Response",
			id: "response",
			renderCell: formatCheckResponse,
			width: "6.6rem"
		},
		{
			cellClassName: "ke-diagnostics__details-cell",
			header: "Details",
			id: "details",
			renderCell: (result) => result.summary,
			width: "minmax(12rem, 1fr)"
		}
	];
	var PASSIVE_COLUMNS = [
		{
			header: "Endpoint",
			id: "endpoint",
			renderCell: (row) => VIEWER_COUNT_ENDPOINT_LABELS[row.endpoint],
			width: "9rem"
		},
		{
			align: "center",
			header: "State",
			id: "state",
			renderCell: (row) => (0, preact_jsx_runtime.jsx)(DiagnosticsPill, {
				label: row.observation ? "observed" : "not seen",
				tone: row.observation ? "observed" : "not-seen"
			}),
			width: "7.2rem"
		},
		{
			align: "center",
			header: "Last seen",
			id: "last-seen",
			renderCell: (row) => row.observation ? formatTime(row.observation.observedAt) : "—",
			width: "6.2rem"
		},
		{
			cellClassName: "ke-diagnostics__details-cell",
			header: "Normalized result",
			id: "details",
			renderCell: (row) => formatObservation(row.observation),
			width: "minmax(12rem, 1fr)"
		}
	];
	var LOG_COLUMNS = [
		{
			align: "center",
			header: "Level",
			id: "level",
			renderCell: (entry) => (0, preact_jsx_runtime.jsx)(DiagnosticsPill, {
				label: entry.level,
				tone: entry.level
			}),
			width: "6.25rem"
		},
		{
			align: "center",
			header: "Time",
			id: "time",
			renderCell: (entry) => formatTime(entry.timestamp),
			width: "5.3rem"
		},
		{
			align: "center",
			header: "Scope",
			id: "scope",
			renderCell: (entry) => (0, preact_jsx_runtime.jsx)(DiagnosticsPill, {
				label: entry.scope,
				tone: getScopeTone(entry.scope)
			}),
			width: "10rem"
		},
		{
			cellClassName: "ke-diagnostics__log-message",
			header: "Message",
			id: "message",
			renderCell: formatLogMessage,
			width: "minmax(14rem, 1fr)"
		}
	];
	function DiagnosticsTab({ active, onShowMessage }) {
		const abortControllerRef = (0, preact_hooks.useRef)(null);
		const [channelSlug, setChannelSlug] = (0, preact_hooks.useState)(() => getChannelSlugFromPath(window.location.pathname) ?? "");
		const [checks, setChecks] = (0, preact_hooks.useState)([]);
		const [checksRunning, setChecksRunning] = (0, preact_hooks.useState)(false);
		const [observations, setObservations] = (0, preact_hooks.useState)(() => active ? getViewerEndpointObservations() : EMPTY_OBSERVATIONS);
		const [logs, setLogs] = (0, preact_hooks.useState)(() => active ? getLogHistory() : EMPTY_LOGS);
		const [logLevel, setLogLevel] = (0, preact_hooks.useState)("all");
		const [logScope, setLogScope] = (0, preact_hooks.useState)("all");
		(0, preact_hooks.useEffect)(() => {
			if (!active) {
				setLogs(EMPTY_LOGS);
				setObservations(EMPTY_OBSERVATIONS);
				abortControllerRef.current?.abort();
				return;
			}
			setLogs(getLogHistory());
			setObservations(getViewerEndpointObservations());
			const unsubscribeLogs = subscribeLogHistory(setLogs);
			const unsubscribeObservations = subscribeViewerEndpointObservations(setObservations);
			return () => {
				unsubscribeLogs();
				unsubscribeObservations();
				abortControllerRef.current?.abort();
			};
		}, [active]);
		const passiveRows = (0, preact_hooks.useMemo)(() => {
			const byEndpoint = new Map(observations.map((observation) => [observation.endpoint, observation]));
			return VIEWER_COUNT_ENDPOINTS.map((endpoint) => ({
				endpoint,
				observation: byEndpoint.get(endpoint)
			}));
		}, [observations]);
		const scopeOptions = (0, preact_hooks.useMemo)(() => {
			return [{
				label: "All scopes",
				value: "all"
			}, ...[...new Set(logs.map((entry) => entry.scope))].sort().map((scope) => ({
				label: scope,
				value: scope
			}))];
		}, [logs]);
		const filteredLogs = (0, preact_hooks.useMemo)(() => {
			return logs.filter((entry) => (logLevel === "all" || entry.level === logLevel) && (logScope === "all" || entry.scope === logScope)).reverse();
		}, [
			logLevel,
			logScope,
			logs
		]);
		const runChecks = async () => {
			abortControllerRef.current?.abort();
			const controller = new AbortController();
			abortControllerRef.current = controller;
			setChecksRunning(true);
			try {
				setChecks(await runViewerEndpointChecks(channelSlug, controller.signal));
			} catch {
				if (!controller.signal.aborted) setChecks([{
					endpoint: "CHANNEL_DETAILS",
					status: "failed",
					summary: "The endpoint check stopped unexpectedly."
				}, {
					endpoint: "CURRENT_VIEWERS",
					status: "unavailable",
					summary: "The channel check did not complete."
				}]);
			} finally {
				if (abortControllerRef.current === controller) {
					abortControllerRef.current = null;
					setChecksRunning(false);
				}
			}
		};
		const copyLogs = async () => {
			if (filteredLogs.length === 0) {
				onShowMessage("No logs to copy", "No visible log entries match the current filters.");
				return;
			}
			const text = filteredLogs.map(formatLogEntry).reverse().join("\n");
			try {
				await navigator.clipboard.writeText(text);
				onShowMessage("Session log copied", `Copied ${filteredLogs.length} log ${filteredLogs.length === 1 ? "entry" : "entries"} to the clipboard.`);
			} catch {
				onShowMessage("Could not copy session log", "Could not access the clipboard. Check your browser permissions and try again.");
			}
		};
		return (0, preact_jsx_runtime.jsxs)("div", {
			className: "ke-diagnostics",
			children: [
				(0, preact_jsx_runtime.jsxs)("section", {
					"aria-labelledby": "ke-diagnostics-checks-title",
					className: "ke-diagnostics__section",
					children: [
						(0, preact_jsx_runtime.jsx)("div", {
							className: "ke-diagnostics__section-heading",
							children: (0, preact_jsx_runtime.jsxs)("div", { children: [(0, preact_jsx_runtime.jsx)("h3", {
								className: "ke-diagnostics__title",
								id: "ke-diagnostics-checks-title",
								children: "Endpoint health"
							}), (0, preact_jsx_runtime.jsx)("p", {
								className: "ke-diagnostics__description",
								children: "Run the same channel and viewer requests used by stream enhancements. Checks only run when requested."
							})] })
						}),
						(0, preact_jsx_runtime.jsxs)("form", {
							className: "ke-diagnostics__check-controls",
							onSubmit: (event) => {
								event.preventDefault();
								if (!checksRunning) runChecks();
							},
							children: [(0, preact_jsx_runtime.jsx)(TextField, {
								autoComplete: "off",
								label: "KICK channel",
								onValueChange: setChannelSlug,
								placeholder: "channel-name",
								spellcheck: false,
								value: channelSlug
							}), (0, preact_jsx_runtime.jsx)(Button, {
								className: "ke-button--primary",
								disabled: checksRunning,
								type: "submit",
								children: checksRunning ? "Checking…" : "Run checks"
							})]
						}),
						(0, preact_jsx_runtime.jsx)(ListView, {
							ariaLabel: "Endpoint check results",
							ariaLive: "polite",
							className: "ke-diagnostics__check-list",
							columns: CHECK_COLUMNS,
							emptyContent: checksRunning ? "Contacting KICK…" : "Run checks to test endpoints.",
							getItemKey: (result) => result.endpoint,
							heightMode: "content",
							items: checks
						})
					]
				}),
				(0, preact_jsx_runtime.jsxs)("section", {
					"aria-labelledby": "ke-diagnostics-observed-title",
					className: "ke-diagnostics__section",
					children: [(0, preact_jsx_runtime.jsx)("div", {
						className: "ke-diagnostics__section-heading",
						children: (0, preact_jsx_runtime.jsxs)("div", { children: [(0, preact_jsx_runtime.jsx)("h3", {
							className: "ke-diagnostics__title",
							id: "ke-diagnostics-observed-title",
							children: "Observed responses"
						}), (0, preact_jsx_runtime.jsx)("p", {
							className: "ke-diagnostics__description",
							children: "Passive summaries from KICK responses already used by the page or Enhancer. No response bodies are retained."
						})] })
					}), (0, preact_jsx_runtime.jsx)(ListView, {
						ariaLabel: "Observed viewer endpoint responses",
						className: "ke-diagnostics__observation-list",
						columns: PASSIVE_COLUMNS,
						getItemKey: (row) => row.endpoint,
						items: passiveRows
					})]
				}),
				(0, preact_jsx_runtime.jsxs)("section", {
					"aria-labelledby": "ke-diagnostics-logs-title",
					className: "ke-diagnostics__section",
					children: [
						(0, preact_jsx_runtime.jsx)("div", {
							className: "ke-diagnostics__section-heading",
							children: (0, preact_jsx_runtime.jsxs)("div", { children: [(0, preact_jsx_runtime.jsx)("h3", {
								className: "ke-diagnostics__title",
								id: "ke-diagnostics-logs-title",
								children: "Session log"
							}), (0, preact_jsx_runtime.jsx)("p", {
								className: "ke-diagnostics__description",
								children: "Latest 250 entries from this page load. Sensitive fields and URL queries are redacted when displayed or copied."
							})] })
						}),
						(0, preact_jsx_runtime.jsxs)("div", {
							className: "ke-diagnostics__log-controls",
							children: [
								(0, preact_jsx_runtime.jsx)(SelectBox, {
									label: "Level",
									onValueChange: setLogLevel,
									options: LOG_LEVEL_OPTIONS,
									value: logLevel
								}),
								(0, preact_jsx_runtime.jsx)(SelectBox, {
									label: "Scope",
									onValueChange: setLogScope,
									options: scopeOptions,
									value: logScope
								}),
								(0, preact_jsx_runtime.jsxs)("div", {
									className: "ke-diagnostics__actions",
									children: [(0, preact_jsx_runtime.jsx)(Button, {
										onClick: () => void copyLogs(),
										children: "Copy"
									}), (0, preact_jsx_runtime.jsx)(Button, {
										onClick: () => {
											clearLogHistory();
											setLogScope("all");
										},
										tone: "danger",
										children: "Clear"
									})]
								})
							]
						}),
						(0, preact_jsx_runtime.jsx)(ListView, {
							ariaLabel: "KICK Enhancer session logs",
							ariaLive: "polite",
							className: "ke-diagnostics__log-list",
							columns: LOG_COLUMNS,
							emptyContent: "No log entries match these filters.",
							getItemKey: (entry) => entry.id,
							items: filteredLogs,
							rowHeight: 36
						})
					]
				})
			]
		});
	}
	function DiagnosticsPill({ label, tone }) {
		return (0, preact_jsx_runtime.jsx)("span", {
			className: "ke-diagnostics__pill",
			"data-tone": tone,
			children: (0, preact_jsx_runtime.jsx)("span", {
				className: "ke-diagnostics__pill-label",
				children: label
			})
		});
	}
	var SCOPE_TONES = [
		"scope-blue",
		"scope-cyan",
		"scope-green",
		"scope-amber",
		"scope-violet",
		"scope-rose"
	];
	function getScopeTone(scope) {
		let hash = 0;
		for (const character of scope) hash = hash * 31 + character.charCodeAt(0) >>> 0;
		return SCOPE_TONES[hash % SCOPE_TONES.length] ?? SCOPE_TONES[0];
	}
	function formatCheckResponse(result) {
		const duration = result.durationMs === void 0 ? void 0 : `${Math.round(result.durationMs)}ms`;
		if (result.httpStatus !== void 0) return duration ? `${result.httpStatus} (${duration})` : String(result.httpStatus);
		return duration ?? "—";
	}
	function formatObservation(observation) {
		if (!observation) return "No matching response seen this session.";
		const source = observation.source === "captured" ? "page traffic" : "fallback request";
		return [
			`normalized=${observation.records}`,
			`hidden=${observation.hiddenViewerCounts}`,
			`startTimes=${observation.startTimes}`,
			`source=${source}`
		].join("; ");
	}
	function formatTime(timestamp) {
		const date = new Date(timestamp);
		if (Number.isNaN(date.getTime())) return "Unknown";
		return TIME_FORMATTER.format(date);
	}
	function setChatFontSize(value) {
		return updateChatSetting("fontSize", value === null ? null : normalizeChatValue(value, 10, 24));
	}
	function setChatFontFamily(value) {
		return updateChatSetting("fontFamily", normalizeChatFontFamily(value));
	}
	function setChatFontWeight(value) {
		return updateChatSetting("fontWeight", normalizeChatFontWeight(value));
	}
	function setChatMessageDividers(enabled) {
		return updateChatSetting("messageDividers", enabled);
	}
	function setChatMessageSpacing(value) {
		return updateChatSetting("messageSpacing", value === null ? null : normalizeChatValue(value, 0, 12));
	}
	function resetChatAppearance() {
		return updateSettings((settings) => {
			if (settings.chat.fontFamily === null && settings.chat.fontSize === null && settings.chat.fontWeight === null && !settings.chat.messageDividers && settings.chat.messageSpacing === null) return settings;
			return {
				...settings,
				chat: {
					fontFamily: null,
					fontSize: null,
					fontWeight: null,
					messageDividers: false,
					messageSpacing: null
				}
			};
		});
	}
	function setShowClipDownloadButtons(visible) {
		return updateUiSetting("showClipDownloadButtons", visible);
	}
	function setShowHiddenViewerCounts(visible) {
		return updateUiSetting("showHiddenViewerCounts", visible);
	}
	function setShowStreamUptime(visible) {
		return updateUiSetting("showStreamUptime", visible);
	}
	function setHideFollowingRecommendations(hidden) {
		return updateUiSetting("hideFollowingRecommendations", hidden);
	}
	function setHideGamblingStreams(hidden) {
		return updateUiSetting("hideGamblingStreams", hidden);
	}
	function setHideHomepageCarousel(hidden) {
		return updateUiSetting("hideHomepageCarousel", hidden);
	}
	function setHideRecommendedChannels(hidden) {
		return updateUiSetting("hideRecommendedChannels", hidden);
	}
	function updateChatSetting(key, value) {
		return updateSettings((settings) => ({
			...settings,
			chat: {
				...settings.chat,
				[key]: value
			}
		}));
	}
	function updateUiSetting(key, value) {
		return updateSettings((settings) => ({
			...settings,
			ui: {
				...settings.ui,
				[key]: value
			}
		}));
	}
	function StreamAndClipSettingsSection({ settings }) {
		return (0, preact_jsx_runtime.jsxs)("div", {
			className: "ke-settings",
			children: [
				(0, preact_jsx_runtime.jsx)(Toggle, {
					checked: settings.showHiddenViewerCounts,
					description: "Restore KICK-reported viewer counts on live channels.",
					label: "Show hidden viewer counts",
					onCheckedChange: (visible) => {
						setShowHiddenViewerCounts(visible);
					}
				}),
				(0, preact_jsx_runtime.jsx)(Toggle, {
					checked: settings.showStreamUptime,
					description: "Show how long live streams have been running on thumbnails and sidebar tooltips.",
					label: "Show stream uptime",
					onCheckedChange: (visible) => {
						setShowStreamUptime(visible);
					}
				}),
				(0, preact_jsx_runtime.jsx)(Toggle, {
					checked: settings.showClipDownloadButtons,
					description: "Show KICK Enhancer download actions on clip cards and clip pages.",
					label: "Show clip download buttons",
					onCheckedChange: (visible) => {
						setShowClipDownloadButtons(visible);
					}
				})
			]
		});
	}
	function ChatSettingsSection({ open, settings }) {
		const kickDefaults = (0, preact_hooks.useMemo)(() => ({
			fontSize: readKickChatValue("--chatroom-font-size", 14, 10, 24),
			messageSpacing: readKickChatValue("--chatroom-message-spacing", 4, 0, 12)
		}), [open]);
		return (0, preact_jsx_runtime.jsxs)("div", {
			className: "ke-settings",
			children: [
				(0, preact_jsx_runtime.jsx)(SelectBox, {
					description: "Change the typeface used throughout the chatroom.",
					label: "Chat font",
					onValueChange: (value) => {
						setChatFontFamily(value === "default" ? null : value);
					},
					options: CHAT_FONT_FAMILY_OPTIONS,
					value: settings.fontFamily ?? "default"
				}),
				(0, preact_jsx_runtime.jsx)(TrackBar, {
					description: "Adjust message text without changing usernames, timestamps, or controls.",
					formatValue: (value) => settings.fontWeight === null ? `KICK default (${value})` : String(value),
					label: "Message font weight",
					max: 900,
					min: 100,
					onValueChange: (value) => {
						setChatFontWeight(value);
					},
					step: 100,
					value: settings.fontWeight ?? 400
				}),
				(0, preact_jsx_runtime.jsx)(TrackBar, {
					description: "Adjust chat messages, timestamps, replies, and emotes together.",
					formatValue: (value) => settings.fontSize === null ? `KICK default (${value}px)` : `${value}px`,
					label: "Chat font size",
					max: 24,
					min: 10,
					onValueChange: (value) => {
						setChatFontSize(value);
					},
					step: 1,
					value: settings.fontSize ?? kickDefaults.fontSize
				}),
				(0, preact_jsx_runtime.jsx)(TrackBar, {
					description: "Adjust the vertical space inside each chat message.",
					formatValue: (value) => settings.messageSpacing === null ? `KICK default (${value}px)` : `${value}px`,
					label: "Message spacing",
					max: 12,
					min: 0,
					onValueChange: (value) => {
						setChatMessageSpacing(value);
					},
					step: 1,
					value: settings.messageSpacing ?? kickDefaults.messageSpacing
				}),
				(0, preact_jsx_runtime.jsx)(Toggle, {
					checked: settings.messageDividers,
					description: "Add a subtle divider between chat messages.",
					label: "Message dividers",
					onCheckedChange: (enabled) => {
						setChatMessageDividers(enabled);
					}
				}),
				(0, preact_jsx_runtime.jsx)("div", {
					className: "ke-settings__actions",
					children: (0, preact_jsx_runtime.jsx)(Button, {
						density: "compact",
						disabled: settings.fontFamily === null && settings.fontSize === null && settings.fontWeight === null && !settings.messageDividers && settings.messageSpacing === null,
						onClick: () => {
							resetChatAppearance();
						},
						children: "Use KICK defaults"
					})
				})
			]
		});
	}
	function ContentSettingsSection({ settings }) {
		return (0, preact_jsx_runtime.jsxs)("div", {
			className: "ke-settings",
			children: [
				(0, preact_jsx_runtime.jsx)(Toggle, {
					checked: settings.hideHomepageCarousel,
					description: "Remove the featured autoplaying stream and chat from the homepage.",
					label: "Hide homepage carousel",
					onCheckedChange: (hidden) => {
						setHideHomepageCarousel(hidden);
					}
				}),
				(0, preact_jsx_runtime.jsx)(Toggle, {
					checked: settings.hideGamblingStreams,
					description: "Hide live followed gambling streams.",
					label: "Hide followed gambling streams",
					onCheckedChange: (hidden) => {
						setHideGamblingStreams(hidden);
					}
				}),
				(0, preact_jsx_runtime.jsx)(Toggle, {
					checked: settings.hideFollowingRecommendations,
					description: "Remove the \"Channels you might like\" section from the Following page.",
					label: "Hide \"Channels you might like\"",
					onCheckedChange: (hidden) => {
						setHideFollowingRecommendations(hidden);
					}
				})
			]
		});
	}
	function SidebarSettingsSection({ settings }) {
		return (0, preact_jsx_runtime.jsxs)("div", {
			className: "ke-settings",
			children: [(0, preact_jsx_runtime.jsx)(Toggle, {
				checked: settings.hideRecommendedChannels,
				description: "Remove recommended channels and their controls from the sidebar.",
				label: "Hide recommended channels",
				onCheckedChange: (hidden) => {
					setHideRecommendedChannels(hidden);
				}
			}), (0, preact_jsx_runtime.jsx)(Toggle, {
				checked: settings.rememberSidebarState,
				description: "Restore the sidebar to its last expanded or collapsed state on reloads.",
				label: "Remember sidebar state",
				onCheckedChange: (enabled) => {
					setRememberSidebarState(enabled);
				}
			})]
		});
	}
	var CHAT_FONT_FAMILY_OPTIONS = [
		{
			label: "KICK default",
			value: "default"
		},
		{
			label: "Arial",
			value: "arial"
		},
		{
			label: "Verdana",
			value: "verdana"
		},
		{
			label: "Tahoma",
			value: "tahoma"
		},
		{
			label: "Trebuchet MS",
			value: "trebuchet"
		},
		{
			label: "Georgia",
			value: "georgia"
		},
		{
			label: "Monospace",
			value: "monospace"
		}
	];
	function readKickChatValue(property, fallback, min, max) {
		return normalizeChatValue(Number.parseFloat(getComputedStyle(document.documentElement).getPropertyValue(property)), min, max) ?? fallback;
	}
	var PROJECT_URL = "https://github.com/sixem/kick-enhancer";
	function SettingsModal({ onRequestClose, open, settings }) {
		const [activeTab, setActiveTab] = (0, preact_hooks.useState)("about");
		const [dialog, setDialog] = (0, preact_hooks.useState)(null);
		const dialogOpen = dialog !== null;
		const closeDialog = () => setDialog(null);
		(0, preact_hooks.useEffect)(() => {
			if (!open) setDialog(null);
		}, [open]);
		const showMessage = (title, description) => {
			setDialog({
				description,
				onConfirm: closeDialog,
				onDismiss: closeDialog,
				title
			});
		};
		const showImportError = () => showMessage("Could not import settings", "Choose a valid KICK Enhancer settings JSON file and try again.");
		const showImportConfirmation = (importedSettings, compatibilityWarning) => {
			setDialog({
				confirmLabel: "Import settings",
				description: compatibilityWarning ? "Some values are missing, unknown, or invalid. Compatible settings will be imported and unsupported values will use current defaults." : "This will replace every current setting with the values from this file.",
				onCancel: closeDialog,
				onConfirm: () => {
					replaceSettings(importedSettings);
					closeDialog();
				},
				title: compatibilityWarning ? "Import settings with warnings?" : "Import settings?"
			});
		};
		const showResetConfirmation = () => {
			setDialog({
				confirmLabel: "Reset settings",
				confirmTone: "danger",
				description: "This restores every KICK Enhancer setting to its default value.",
				onCancel: closeDialog,
				onConfirm: () => {
					resetSettings();
					closeDialog();
				},
				title: "Reset all settings?"
			});
		};
		return (0, preact_jsx_runtime.jsx)(Modal, {
			className: "ke-workspace-modal ke-settings-modal",
			description: "Customize how KICK behaves and looks.",
			dismissDisabled: dialogOpen,
			footer: (0, preact_jsx_runtime.jsxs)(preact_jsx_runtime.Fragment, { children: [
				(0, preact_jsx_runtime.jsxs)(Button, {
					"aria-label": "Open KICK Enhancer on GitHub",
					className: "ke-settings-modal__github",
					disabled: dialogOpen,
					onClick: () => {
						window.open(PROJECT_URL, "_blank", "noopener,noreferrer");
					},
					children: [(0, preact_jsx_runtime.jsx)(GitHubIcon, { class: "ke-settings-modal__github-icon" }), "GitHub"]
				}),
				(0, preact_jsx_runtime.jsx)(Button, {
					disabled: dialogOpen,
					onClick: showResetConfirmation,
					tone: "danger",
					children: "Reset to defaults"
				}),
				(0, preact_jsx_runtime.jsx)(Button, {
					className: "ke-button--primary",
					disabled: dialogOpen,
					onClick: onRequestClose,
					children: "Done"
				})
			] }),
			icon: icon_default,
			onRequestClose,
			open,
			title: "KICK Enhancer",
			children: (0, preact_jsx_runtime.jsxs)("div", {
				className: "ke-confirmation-host",
				children: [(0, preact_jsx_runtime.jsx)("div", {
					"aria-hidden": dialogOpen || void 0,
					className: "ke-settings-modal__tabs",
					inert: dialogOpen,
					children: (0, preact_jsx_runtime.jsx)(Tabs, {
						ariaLabel: "KICK Enhancer settings",
						onChange: setActiveTab,
						tabs: [
							{
								content: (0, preact_jsx_runtime.jsx)(AboutTab, {
									onImportError: showImportError,
									onImportRequest: showImportConfirmation
								}),
								contentClassName: "ke-tabs__panel-content--centered",
								id: "about",
								label: "About"
							},
							{
								content: (0, preact_jsx_runtime.jsx)(StreamAndClipSettingsSection, { settings: settings.ui }),
								id: "streams",
								label: "Streams / Clips"
							},
							{
								content: (0, preact_jsx_runtime.jsx)(ChatSettingsSection, {
									open,
									settings: settings.chat
								}),
								id: "chat",
								label: "Chat"
							},
							{
								content: (0, preact_jsx_runtime.jsx)(ContentSettingsSection, { settings: settings.ui }),
								id: "content",
								label: "Content"
							},
							{
								content: (0, preact_jsx_runtime.jsx)(SidebarSettingsSection, { settings: settings.ui }),
								id: "sidebar",
								label: "Sidebar"
							},
							{
								content: (0, preact_jsx_runtime.jsx)(DiagnosticsTab, {
									active: activeTab === "diagnostics",
									onShowMessage: showMessage
								}),
								id: "diagnostics",
								label: "Diagnostics"
							}
						],
						value: activeTab
					})
				}), dialog ? (0, preact_jsx_runtime.jsx)(ConfirmationDialog, {
					...dialog,
					open: true
				}) : null]
			})
		});
	}
	function useSettings() {
		const [settings, setSettings] = (0, preact_hooks.useState)(getSettings);
		(0, preact_hooks.useEffect)(() => subscribeSettings(setSettings), []);
		return settings;
	}
	var app_default = ".ke-about {\n  display: grid;\n  justify-items: center;\n  gap: 1rem;\n  text-align: center;\n}\n\n.ke-about__icon {\n  width: 4rem;\n  height: 4rem;\n  object-fit: contain;\n}\n\n.ke-about__identity {\n  display: grid;\n  gap: 0.2rem;\n}\n\n.ke-about__title {\n  margin: 0;\n  color: #f2f2f2;\n  font-size: 1.2rem;\n  font-weight: 750;\n  line-height: 1.25;\n}\n\n.ke-about__version {\n  margin: 0;\n  color: #8c8c8c;\n  font-size: 0.75rem;\n  font-variant-numeric: tabular-nums;\n}\n\n.ke-about__description {\n  margin: 0;\n  color: #747474;\n  font-size: 0.825rem;\n  font-weight: 500;\n  line-height: 1.5;\n}\n\n.ke-about__actions {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n  gap: 0.65rem;\n}\n\n.ke-diagnostics {\n  display: grid;\n  gap: 1.5rem;\n}\n\n.ke-diagnostics__section {\n  min-width: 0;\n  display: grid;\n  gap: 0.8rem;\n}\n\n.ke-diagnostics__section-heading {\n  min-width: 0;\n  display: flex;\n  align-items: flex-start;\n  justify-content: space-between;\n  gap: 1rem;\n}\n\n.ke-diagnostics__title {\n  margin: 0;\n  color: #f2f2f2;\n  font-size: 0.9rem;\n  font-weight: 750;\n  line-height: 1.3;\n}\n\n.ke-diagnostics__description {\n  margin: 0.25rem 0 0;\n  color: #747474;\n  font-size: 0.76rem;\n  font-weight: 500;\n  line-height: 1.45;\n}\n\n.ke-diagnostics__check-controls {\n  display: grid;\n  grid-template-columns: minmax(0, 1fr) auto;\n  align-items: end;\n  gap: 0.65rem;\n}\n\n.ke-diagnostics__actions {\n  display: flex;\n  flex: none;\n  gap: 0.45rem;\n}\n\n.ke-diagnostics__check-list {\n  max-height: 8.5rem;\n}\n.ke-diagnostics__check-list .ke-list-view__empty {\n  min-height: 2.125rem;\n  padding: 0.42rem 0.6rem;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.ke-diagnostics__observation-list {\n  height: 13rem;\n}\n\n.ke-diagnostics__log-list {\n  height: 13.25rem;\n}\n\n.ke-diagnostics__pill {\n  max-width: 100%;\n  display: inline-flex;\n  box-sizing: border-box;\n  min-width: 4.8rem;\n  align-items: center;\n  justify-content: center;\n  padding: 0.12rem 0.42rem;\n  overflow: hidden;\n  border: 1px solid #303030;\n  border-radius: 0.3rem;\n  color: #8c8c8c;\n  font-size: 0.68rem;\n  font-weight: 750;\n  letter-spacing: 0.03em;\n  line-height: 1.35;\n  text-transform: capitalize;\n}\n.ke-diagnostics__pill[data-tone=passed], .ke-diagnostics__pill[data-tone=observed] {\n  border-color: rgba(83, 252, 24, 0.4);\n  color: #53fc18;\n}\n.ke-diagnostics__pill[data-tone=degraded], .ke-diagnostics__pill[data-tone=unavailable], .ke-diagnostics__pill[data-tone=warn] {\n  border-color: rgba(245, 196, 81, 0.4);\n  color: #f5c451;\n}\n.ke-diagnostics__pill[data-tone=failed], .ke-diagnostics__pill[data-tone=error] {\n  border-color: rgba(255, 107, 107, 0.45);\n  color: #ff6b6b;\n}\n.ke-diagnostics__pill[data-tone=debug], .ke-diagnostics__pill[data-tone=info], .ke-diagnostics__pill[data-tone=warn], .ke-diagnostics__pill[data-tone=error] {\n  text-transform: uppercase;\n}\n.ke-diagnostics__pill[data-tone=info], .ke-diagnostics__pill[data-tone=scope-blue] {\n  border-color: rgba(117, 178, 255, 0.42);\n  color: #a9cfff;\n}\n.ke-diagnostics__pill[data-tone^=scope-] {\n  text-transform: none;\n}\n.ke-diagnostics__pill[data-tone=scope-cyan] {\n  border-color: rgba(95, 214, 225, 0.42);\n  color: #8bdce4;\n}\n.ke-diagnostics__pill[data-tone=scope-green] {\n  border-color: rgba(83, 252, 24, 0.36);\n  color: #8eea70;\n}\n.ke-diagnostics__pill[data-tone=scope-amber] {\n  border-color: rgba(245, 196, 81, 0.4);\n  color: #f5c451;\n}\n.ke-diagnostics__pill[data-tone=scope-violet] {\n  border-color: rgba(179, 142, 255, 0.42);\n  color: #c6a9ff;\n}\n.ke-diagnostics__pill[data-tone=scope-rose] {\n  border-color: rgba(242, 128, 170, 0.42);\n  color: #f09bbb;\n}\n\n.ke-diagnostics__pill-label {\n  min-width: 0;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.ke-diagnostics__details-cell {\n  align-items: flex-start;\n}\n\n.ke-diagnostics__details-cell .ke-list-view__cell-content {\n  overflow: visible;\n  line-height: 1.4;\n  text-overflow: clip;\n  white-space: normal;\n}\n\n.ke-diagnostics__log-controls {\n  display: grid;\n  grid-template-columns: 8rem minmax(0, 1fr) auto;\n  align-items: end;\n  gap: 0.65rem;\n}\n\n.ke-diagnostics__log-message .ke-list-view__cell-content {\n  line-height: 1.4;\n}\n\n@media (max-width: 36rem) {\n  .ke-diagnostics__section-heading {\n    display: grid;\n  }\n  .ke-diagnostics__actions {\n    justify-content: flex-start;\n  }\n  .ke-diagnostics__check-controls,\n  .ke-diagnostics__log-controls {\n    grid-template-columns: 1fr;\n  }\n}\n.kick-enhancer-host {\n  display: contents;\n}\n\n.kick-enhancer-button {\n  position: relative;\n  display: flex;\n  flex: 0 0 auto;\n  box-sizing: border-box;\n  align-items: center;\n  justify-content: center;\n  width: 2.25rem;\n  height: 2.25rem;\n  padding: 0;\n  overflow: hidden;\n  color: var(--neon-secondary-onSecondary, #fff);\n  cursor: pointer;\n  user-select: none;\n  background: var(--neon-secondary-base, #42474d);\n  border: 0;\n  border-radius: 0.25rem;\n  outline: 0;\n  transition: background-color 150ms ease, transform 100ms ease;\n}\n.kick-enhancer-button::after {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n  content: \"\";\n  background: transparent;\n  border-radius: inherit;\n}\n.kick-enhancer-button:hover::after {\n  background: var(--neon-stateLayer-surfaceHover, rgba(240, 241, 242, 0.0392156863));\n}\n.kick-enhancer-button:focus-visible {\n  outline: 2px solid var(--neon-focusLight, #fff);\n  outline-offset: 2px;\n}\n.kick-enhancer-button:active {\n  transform: scale(0.95);\n}\n.kick-enhancer-button__icon {\n  display: block;\n  width: 1.25rem;\n  height: 1.25rem;\n  pointer-events: none;\n  object-fit: contain;\n}\n\n.kick-enhancer-download-button {\n  overflow: visible;\n}\n.kick-enhancer-download-button__icon {\n  width: 1.25rem;\n  height: 1.25rem;\n  pointer-events: none;\n}\n.kick-enhancer-download-button__badge {\n  position: absolute;\n  top: -0.3rem;\n  right: -0.3rem;\n  display: grid;\n  min-width: 1rem;\n  height: 1rem;\n  padding-inline: 0.2rem;\n  place-items: center;\n  border: 1px solid #050505;\n  border-radius: 0.3rem;\n  background: #53fc18;\n  color: #071402;\n  font-size: 0.625rem;\n  font-weight: 800;\n  line-height: 1;\n}\n.kick-enhancer-download-button.needs-attention {\n  box-shadow: inset 0 0 0 1px #53fc18;\n}\n.kick-enhancer-download-button.is-error {\n  box-shadow: inset 0 0 0 1px #ff6b6b;\n}\n\n#sidebar-wrapper .bg-outline-decorative.h-px {\n  display: none !important;\n}\n\n#main-container :where(a[href^=\"/category/\"].bg-secondary-base,\na[href^=\"/category/\"] .bg-secondary-base,\n:has(> a[href^=\"/category/\"]) > .bg-secondary-base,\nspan.bg-secondary-base.rounded-full) {\n  border-radius: 0.3rem;\n  background-color: #212931;\n}";
	var LOGGED_IN_ANCHOR_SELECTOR = "button[data-testid=\"kicks-top-nav\"]";
	var LOGGED_OUT_ANCHOR_SELECTOR = "nav button[data-testid=\"login\"]";
	function findTopNavActions(ownerDocument = document) {
		return (ownerDocument.querySelector(LOGGED_IN_ANCHOR_SELECTOR) ?? ownerDocument.querySelector(LOGGED_OUT_ANCHOR_SELECTOR))?.parentElement ?? null;
	}
	function App() {
		const [settingsOpen, setSettingsOpen] = (0, preact_hooks.useState)(false);
		const downloadActivity = useDownloadActivity();
		const settings = useSettings();
		const downloadCount = downloadActivity.activeCount + downloadActivity.queuedCount;
		return (0, preact_jsx_runtime.jsxs)(preact_jsx_runtime.Fragment, { children: [
			downloadActivity.visible ? (0, preact_jsx_runtime.jsxs)("button", {
				"aria-label": downloadActivity.attention ? "Open Download Manager; a download needs attention" : "Open Download Manager",
				class: `kick-enhancer-button kick-enhancer-download-button${downloadActivity.error ? " is-error" : ""}${downloadActivity.attention ? " needs-attention" : ""}`,
				"data-kick-enhancer": "download-activity",
				onClick: () => openDownloadCenter(),
				type: "button",
				children: [downloadActivity.activeCount > 0 ? (0, preact_jsx_runtime.jsx)(LoadingSpinnerIcon, { class: "ke-icon kick-enhancer-download-button__icon ke-icon--spinner" }) : (0, preact_jsx_runtime.jsx)(DownloadIcon, { class: "ke-icon kick-enhancer-download-button__icon" }), downloadCount > 0 ? (0, preact_jsx_runtime.jsx)("span", {
					"aria-label": `${downloadCount} active or queued downloads`,
					className: "kick-enhancer-download-button__badge",
					children: downloadCount > 9 ? "9+" : downloadCount
				}) : null]
			}) : null,
			(0, preact_jsx_runtime.jsx)("button", {
				"aria-label": "Open KICK Enhancer settings",
				class: "kick-enhancer-button",
				"data-kick-enhancer": "top-nav-button",
				onClick: () => setSettingsOpen(true),
				type: "button",
				children: (0, preact_jsx_runtime.jsx)("img", {
					alt: "",
					class: "kick-enhancer-button__icon",
					draggable: false,
					src: icon_default
				})
			}),
			(0, preact_jsx_runtime.jsx)(SettingsModal, {
				onRequestClose: () => setSettingsOpen(false),
				open: settingsOpen,
				settings
			})
		] });
	}
	var HOST_ID = "kick-enhancer-top-nav";
	var STYLE_ID = "kick-enhancer-styles";
	var mountedHost = null;
	var stopActiveFeature;
	function installStyles() {
		installSharedUiStyles();
		if (document.getElementById(STYLE_ID)) return;
		const style = document.createElement("style");
		style.id = STYLE_ID;
		style.textContent = app_default;
		document.documentElement.append(style);
	}
	function mountButton() {
		if (mountedHost && !mountedHost.isConnected) {
			(0, preact.render)(null, mountedHost);
			mountedHost = null;
		}
		if (document.getElementById(HOST_ID)) return;
		const actions = findTopNavActions();
		if (!actions) return;
		const host = document.createElement("span");
		host.id = HOST_ID;
		host.className = "kick-enhancer-host";
		actions.prepend(host);
		mountedHost = host;
		(0, preact.render)((0, preact_jsx_runtime.jsx)(App, {}), host);
	}
	function startTopNavButton() {
		stopActiveFeature?.();
		installStyles();
		mountButton();
		let mountScheduled = false;
		let stopped = false;
		const observer = new MutationObserver(() => {
			if (stopped || mountScheduled || document.getElementById(HOST_ID)) return;
			mountScheduled = true;
			queueMicrotask(() => {
				mountScheduled = false;
				if (!stopped) mountButton();
			});
		});
		observer.observe(document.documentElement, {
			childList: true,
			subtree: true
		});
		const stop = () => {
			if (stopped) return;
			stopped = true;
			observer.disconnect();
			const host = mountedHost ?? document.getElementById(HOST_ID);
			if (host) {
				(0, preact.render)(null, host);
				host.remove();
			}
			mountedHost = null;
			document.getElementById(STYLE_ID)?.remove();
			if (stopActiveFeature === stop) stopActiveFeature = void 0;
		};
		stopActiveFeature = stop;
		return stop;
	}
	var log = createLogger("app");
	var stopFeatures;
	initializeViewerCountCapture();
	async function start() {
		await initializeSettings();
		stopFeatures?.();
		stopFeatures = composeDisposers(startChatAppearance(), startClipDownloadActions(), startViewerEnhancements(), startFollowingRecommendationsVisibility(), startGamblingStreamsVisibility(), startHomepageCarouselVisibility(), startRecommendedChannelsVisibility(), startSidebarStateMemory(), startTopNavButton());
		log.info("Ready");
	}
	start();
})(preact, jsxRuntime, preactHooks, preactCompat);