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);