diff --git a/dist/better-xcloud.pretty.user.js b/dist/better-xcloud.pretty.user.js
index e6d2ef7..0a17c73 100644
--- a/dist/better-xcloud.pretty.user.js
+++ b/dist/better-xcloud.pretty.user.js
@@ -84,6 +84,7 @@ var ALL_PREFS = {
"ui.hideScrollbar",
"ui.streamMenu.simplify",
"ui.splashVideo.skip",
+ "ui.theme",
"version.current",
"version.lastCheck",
"version.latest",
@@ -403,6 +404,8 @@ var SUPPORTED_LANGUAGES = {
"section-recently-added": "Recently added",
"section-leaving-soon": "Leaving soon",
"section-genres": "Genres",
+ oled: "OLED",
+ theme: "Theme",
achievements: "Achievements",
activate: "Activate",
activated: "Activated",
@@ -1443,6 +1446,14 @@ class GlobalSettingsStorage extends BaseSettingsStorage {
}
}
},
+ "ui.theme": {
+ label: t("theme"),
+ default: "default",
+ options: {
+ default: t("default"),
+ "dark-oled": t("oled")
+ }
+ },
"stream.video.combineAudio": {
requiredVariants: "full",
label: t("combine-audio-video-streams"),
@@ -7268,6 +7279,7 @@ class SettingsDialog extends NavigationDialog {
label: t("ui"),
items: [
"ui.layout",
+ "ui.theme",
"ui.imageQuality",
"ui.gameCard.waitTime.show",
"ui.controllerStatus.show",
@@ -9313,6 +9325,7 @@ function addCss() {
if (containsAll(PREF_HIDE_SECTIONS, ["recently-added", "leaving-soon", "genres", "all-games"])) selectorToHide.push("#BodyContent div[class*=GamePassPromoSection-module__container]");
if (getGlobalPref("block.features").includes("friends")) selectorToHide.push("#gamepass-dialog-root div[class^=AchievementsPreview-module__container] + button[class*=HomeLandingPage-module__button]");
if (selectorToHide) css += selectorToHide.join(",") + "{ display: none; }";
+ if (getGlobalPref("ui.theme") === "dark-oled") css += 'body[data-theme=dark]{--gds-containerSolidAppBackground:#000 !important}div[class*="ProductDetailPage-module__backgroundImageGradient"]:after{background:radial-gradient(ellipse 100% 100% at 50% 0,rgba(21,21,23,0.549) 0,rgba(26,27,30,0.651) 32%,#000 100%) !important}';
if (getGlobalPref("ui.reduceAnimations")) css += "div[class*=GameCard-module__gameTitleInnerWrapper],div[class*=GameCard-module__card],div[class*=ScrollArrows-module]{transition:none !important}";
if (getGlobalPref("ui.systemMenu.hideHandle")) css += "div[class*=Grip-module__container]{visibility:hidden}@media (hover:hover){button[class*=GripHandle-module__container]:hover div[class*=Grip-module__container]{visibility:visible}}button[class*=GripHandle-module__container][aria-expanded=true] div[class*=Grip-module__container]{visibility:visible}button[class*=GripHandle-module__container][aria-expanded=false]{background-color:transparent !important}div[class*=StreamHUD-module__buttonsContainer]{padding:0 !important}";
if (css += "div[class*=StreamMenu-module__menu]{min-width:100vw !important}", getGlobalPref("ui.streamMenu.simplify")) css += "div[class*=Menu-module__scrollable]{--bxStreamMenuItemSize:80px;--streamMenuItemSize:calc(var(--bxStreamMenuItemSize) + 40px) !important}.bx-badges{top:calc(var(--streamMenuItemSize) - 20px)}body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) - 10px) !important}button[class*=MenuItem-module__container]{min-width:auto !important;min-height:auto !important;width:var(--bxStreamMenuItemSize) !important;height:var(--bxStreamMenuItemSize) !important}div[class*=MenuItem-module__label]{display:none !important}svg[class*=MenuItem-module__icon]{width:36px;height:100% !important;padding:0 !important;margin:0 !important}";
diff --git a/dist/better-xcloud.user.js b/dist/better-xcloud.user.js
index 182f603..3e8bf25 100755
--- a/dist/better-xcloud.user.js
+++ b/dist/better-xcloud.user.js
@@ -21,7 +21,7 @@ try {delete window.BX_FLAGS;} catch (e) {}
if (!BX_FLAGS.DeviceInfo.userAgent) BX_FLAGS.DeviceInfo.userAgent = window.navigator.userAgent;
BxLogger.info("BxFlags", BX_FLAGS);
var NATIVE_FETCH = window.fetch;
-var ALL_PREFS = {global: ["audio.mic.onPlaying","audio.volume.booster.enabled","block.features","block.tracking","gameBar.position","game.fortnite.forceConsole","loadingScreen.gameArt.show","loadingScreen.rocket","loadingScreen.waitTime.show","mkb.enabled","mkb.cursor.hideIdle","nativeMkb.forcedGames","nativeMkb.mode","xhome.enabled","xhome.video.resolution","screenshot.applyFilters","server.bypassRestriction","server.ipv6.prefer","server.region","stream.video.codecProfile","stream.video.combineAudio","stream.video.maxBitrate","stream.locale","stream.video.resolution","touchController.autoOff","touchController.opacity.default","touchController.mode","touchController.style.custom","touchController.style.standard","ui.controllerFriendly","ui.controllerStatus.show","ui.feedbackDialog.disabled","ui.gameCard.waitTime.show","ui.hideSections","ui.systemMenu.hideHandle","ui.imageQuality","ui.layout","ui.reduceAnimations","ui.hideScrollbar","ui.streamMenu.simplify","ui.splashVideo.skip","version.current","version.lastCheck","version.latest","bx.locale","userAgent.profile"],stream: ["audio.volume","controller.pollingRate","controller.settings","deviceVibration.intensity","deviceVibration.mode","keyboardShortcuts.preset.inGameId","localCoOp.enabled","mkb.p1.preset.mappingId","mkb.p1.slot","mkb.p2.preset.mappingId","mkb.p2.slot","nativeMkb.scroll.sensitivityX","nativeMkb.scroll.sensitivityY","stats.colors","stats.items","stats.opacity.all","stats.opacity.background","stats.position","stats.quickGlance.enabled","stats.showWhenPlaying","stats.textSize","video.brightness","video.contrast","video.maxFps","video.player.type","video.position","video.player.powerPreference","video.processing","video.ratio","video.saturation","video.processing.sharpness"]};
+var ALL_PREFS = {global: ["audio.mic.onPlaying","audio.volume.booster.enabled","block.features","block.tracking","gameBar.position","game.fortnite.forceConsole","loadingScreen.gameArt.show","loadingScreen.rocket","loadingScreen.waitTime.show","mkb.enabled","mkb.cursor.hideIdle","nativeMkb.forcedGames","nativeMkb.mode","xhome.enabled","xhome.video.resolution","screenshot.applyFilters","server.bypassRestriction","server.ipv6.prefer","server.region","stream.video.codecProfile","stream.video.combineAudio","stream.video.maxBitrate","stream.locale","stream.video.resolution","touchController.autoOff","touchController.opacity.default","touchController.mode","touchController.style.custom","touchController.style.standard","ui.controllerFriendly","ui.controllerStatus.show","ui.feedbackDialog.disabled","ui.gameCard.waitTime.show","ui.hideSections","ui.systemMenu.hideHandle","ui.imageQuality","ui.layout","ui.reduceAnimations","ui.hideScrollbar","ui.streamMenu.simplify","ui.splashVideo.skip","ui.theme","version.current","version.lastCheck","version.latest","bx.locale","userAgent.profile"],stream: ["audio.volume","controller.pollingRate","controller.settings","deviceVibration.intensity","deviceVibration.mode","keyboardShortcuts.preset.inGameId","localCoOp.enabled","mkb.p1.preset.mappingId","mkb.p1.slot","mkb.p2.preset.mappingId","mkb.p2.slot","nativeMkb.scroll.sensitivityX","nativeMkb.scroll.sensitivityY","stats.colors","stats.items","stats.opacity.all","stats.opacity.background","stats.position","stats.quickGlance.enabled","stats.showWhenPlaying","stats.textSize","video.brightness","video.contrast","video.maxFps","video.player.type","video.position","video.player.powerPreference","video.processing","video.ratio","video.saturation","video.processing.sharpness"]};
var SMART_TV_UNIQUE_ID = "FC4A1DA2-711C-4E9C-BC7F-047AF8A672EA", CHROMIUM_VERSION = "125.0.0.0";
if (!!window.chrome || window.navigator.userAgent.includes("Chrome")) {let match = window.navigator.userAgent.match(/\s(?:Chrome|Edg)\/([\d\.]+)/);if (match) CHROMIUM_VERSION = match[1];}
class UserAgent {static STORAGE_KEY = "BetterXcloud.UserAgent";static #config;static #isMobile = null;static #isSafari = null;static #isSafariMobile = null;static #USER_AGENTS = {"windows-edge": `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${CHROMIUM_VERSION} Safari/537.36 Edg/${CHROMIUM_VERSION}`,"macos-safari": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.2 Safari/605.1.1","smarttv-generic": `${window.navigator.userAgent} Smart-TV`,"smarttv-tizen": `Mozilla/5.0 (SMART-TV; LINUX; Tizen 7.0) AppleWebKit/537.36 (KHTML, like Gecko) ${CHROMIUM_VERSION}/7.0 TV Safari/537.36 ${SMART_TV_UNIQUE_ID}`,"vr-oculus": window.navigator.userAgent + " OculusBrowser VR"};static init() {if (UserAgent.#config = JSON.parse(window.localStorage.getItem(UserAgent.STORAGE_KEY) || "{}"), !UserAgent.#config.profile) UserAgent.#config.profile = BX_FLAGS.DeviceInfo.deviceType === "android-tv" || BX_FLAGS.DeviceInfo.deviceType === "webos" ? "vr-oculus" : "default";if (!UserAgent.#config.custom) UserAgent.#config.custom = "";UserAgent.spoof();}static updateStorage(profile, custom) {let config = UserAgent.#config;if (config.profile = profile, profile === "custom" && typeof custom !== "undefined") config.custom = custom;window.localStorage.setItem(UserAgent.STORAGE_KEY, JSON.stringify(config));}static getDefault() {return window.navigator.orgUserAgent || window.navigator.userAgent;}static get(profile) {let defaultUserAgent = window.navigator.userAgent;switch (profile) {case "default":return defaultUserAgent;case "custom":return UserAgent.#config.custom || defaultUserAgent;default:return UserAgent.#USER_AGENTS[profile] || defaultUserAgent;}}static isSafari() {if (this.#isSafari !== null) return this.#isSafari;let userAgent = UserAgent.getDefault().toLowerCase(), result = userAgent.includes("safari") && !userAgent.includes("chrom");return this.#isSafari = result, result;}static isSafariMobile() {if (this.#isSafariMobile !== null) return this.#isSafariMobile;let userAgent = UserAgent.getDefault().toLowerCase(), result = this.isSafari() && userAgent.includes("mobile");return this.#isSafariMobile = result, result;}static isMobile() {if (this.#isMobile !== null) return this.#isMobile;let userAgent = UserAgent.getDefault().toLowerCase(), result = /iphone|ipad|android/.test(userAgent);return this.#isMobile = result, result;}static spoof() {let profile = UserAgent.#config.profile;if (profile === "default") return;let newUserAgent = UserAgent.get(profile);if ("userAgentData" in window.navigator) window.navigator.orgUserAgentData = window.navigator.userAgentData, Object.defineProperty(window.navigator, "userAgentData", {});window.navigator.orgUserAgent = window.navigator.userAgent, Object.defineProperty(window.navigator, "userAgent", {value: newUserAgent});}}
@@ -36,7 +36,7 @@ var GamepadKeyName = {0: ["A", "⇓"],1: ["B", "⇒"],2: ["X", "⇐"],3: ["Y", "
class BxEventBus {listeners = new Map;group;appJsInterfaces;static Script = new BxEventBus("script", {"dialog.shown": "onDialogShown","dialog.dismissed": "onDialogDismissed"});static Stream = new BxEventBus("stream", {"state.loading": "onStreamPlaying","state.playing": "onStreamPlaying","state.stopped": "onStreamStopped"});constructor(group, appJsInterfaces) {this.group = group, this.appJsInterfaces = appJsInterfaces;}on(event, callback) {if (!this.listeners.has(event)) this.listeners.set(event, new Set);this.listeners.get(event).add(callback), BX_FLAGS.Debug && BxLogger.warning("EventBus", "on", event, callback);}once(event, callback) {let wrapper = (...args) => {callback(...args), this.off(event, wrapper);};this.on(event, wrapper);}off(event, callback) {if (BX_FLAGS.Debug && BxLogger.warning("EventBus", "off", event, callback), !callback) {this.listeners.delete(event);return;}let callbacks = this.listeners.get(event);if (!callbacks) return;if (callbacks.delete(callback), callbacks.size === 0) this.listeners.delete(event);}offAll() {this.listeners.clear();}emit(event, payload) {let callbacks = this.listeners.get(event) || [];for (let callback of callbacks)callback(payload);if (AppInterface) try {if (event in this.appJsInterfaces) {let method = this.appJsInterfaces[event];AppInterface[method] && AppInterface[method]();} else AppInterface.onEventBus(this.group + "." + event);} catch (e) {console.log(e);}BX_FLAGS.Debug && BxLogger.warning("EventBus", "emit", `${this.group}.${event}`, payload);}}
window.BxEventBus = BxEventBus;
class GhPagesUtils {static fetchLatestCommit() {NATIVE_FETCH("https://api.github.com/repos/redphx/better-xcloud/branches/gh-pages", {method: "GET",headers: {Accept: "application/vnd.github.v3+json"}}).then((response) => response.json()).then((data) => {let latestCommitHash = data.commit.sha;window.localStorage.setItem("BetterXcloud.GhPages.CommitHash", latestCommitHash);}).catch((error) => {BxLogger.error("GhPagesUtils", "Error fetching the latest commit:", error);});}static getUrl(path) {if (path[0] === "/") alert('`path` must not starts with "/"');let prefix = "https://raw.githubusercontent.com/redphx/better-xcloud", latestCommitHash = window.localStorage.getItem("BetterXcloud.GhPages.CommitHash");if (latestCommitHash) return `${prefix}/${latestCommitHash}/${path}`;else return `${prefix}/refs/heads/gh-pages/${path}`;}static getNativeMkbCustomList(update = !1) {let key = "BetterXcloud.GhPages.ForceNativeMkb";update && NATIVE_FETCH(GhPagesUtils.getUrl("native-mkb/ids.json")).then((response) => response.json()).then((json) => {if (json.$schemaVersion === 1) window.localStorage.setItem(key, JSON.stringify(json)), BxEventBus.Script.emit("list.forcedNativeMkb.updated", {data: json});else window.localStorage.removeItem(key);});let info = JSON.parse(window.localStorage.getItem(key) || "{}");if (info.$schemaVersion !== 1) return window.localStorage.removeItem(key), {};return info.data;}static getTouchControlCustomList() {let key = "BetterXcloud.GhPages.CustomTouchLayouts";return NATIVE_FETCH(GhPagesUtils.getUrl("touch-layouts/ids.json")).then((response) => response.json()).then((json) => {if (Array.isArray(json)) window.localStorage.setItem(key, JSON.stringify(json));}), JSON.parse(window.localStorage.getItem(key) || "[]");}static getLocalCoOpList() {let key = "BetterXcloud.GhPages.LocalCoOp";NATIVE_FETCH(GhPagesUtils.getUrl("local-co-op/ids.json")).then((response) => response.json()).then((json) => {if (json.$schemaVersion === 1) {window.localStorage.setItem(key, JSON.stringify(json));let ids = new Set(Object.keys(json.data));BxEventBus.Script.emit("list.localCoOp.updated", { ids });} else window.localStorage.removeItem(key), BxEventBus.Script.emit("list.localCoOp.updated", { ids: new Set });});let info = JSON.parse(window.localStorage.getItem(key) || "{}");if (info.$schemaVersion !== 1) return window.localStorage.removeItem(key), new Set;return new Set(Object.keys(info.data || {}));}}
-var SUPPORTED_LANGUAGES = {"en-US": "English (US)","ca-CA": "Català","da-DK": "dansk","de-DE": "Deutsch","en-ID": "Bahasa Indonesia","es-ES": "español (España)","fr-FR": "français","it-IT": "italiano","ja-JP": "日本語","ko-KR": "한국어","pl-PL": "polski","pt-BR": "português (Brasil)","ru-RU": "русский","th-TH": "ภาษาไทย","tr-TR": "Türkçe","uk-UA": "українська","vi-VN": "Tiếng Việt","zh-CN": "中文(简体)","zh-TW": "中文(繁體)"}, Texts = {webgpu: "WebGPU","section-recently-added": "Recently added","section-leaving-soon": "Leaving soon","section-genres": "Genres",achievements: "Achievements",activate: "Activate",activated: "Activated",active: "Active",advanced: "Advanced","all-games": "All games","always-off": "Always off","always-on": "Always on","amd-fidelity-cas": "AMD FidelityFX CAS","app-settings": "App settings",apply: "Apply","aspect-ratio": "Aspect ratio","aspect-ratio-note": "Don't use with native touch games",audio: "Audio",auto: "Auto",availability: "Availability","back-to-home": "Back to home","back-to-home-confirm": "Do you want to go back to the home page (without disconnecting)?","background-opacity": "Background opacity",battery: "Battery","battery-saving": "Battery saving","better-xcloud": "Better xCloud","bitrate-audio-maximum": "Maximum audio bitrate","bitrate-video-maximum": "Maximum video bitrate",bottom: "Bottom","bottom-half": "Bottom half","bottom-left": "Bottom-left","bottom-right": "Bottom-right",brazil: "Brazil",brightness: "Brightness","browser-unsupported-feature": "Your browser doesn't support this feature","button-xbox": "Xbox button","bypass-region-restriction": "Bypass region restriction","can-stream-xbox-360-games": "Can stream Xbox 360 games",cancel: "Cancel","cant-stream-xbox-360-games": "Can't stream Xbox 360 games",center: "Center",chat: "Chat","clarity-boost": "Clarity boost","clarity-boost-warning": "These settings don't work when the Clarity Boost mode is ON",clear: "Clear","clear-data": "Clear data","clear-data-confirm": "Do you want to clear all Better xCloud settings and data?","clear-data-success": "Data cleared! Refresh the page to apply the changes.",clock: "Clock",close: "Close","close-app": "Close app","combine-audio-video-streams": "Combine audio & video streams","combine-audio-video-streams-summary": "May fix the laggy audio problem","conditional-formatting": "Conditional formatting text color","confirm-delete-preset": "Do you want to delete this preset?","confirm-reload-stream": "Do you want to refresh the stream?",connected: "Connected","console-connect": "Connect","continent-asia": "Asia","continent-australia": "Australia","continent-europe": "Europe","continent-north-america": "North America","continent-south-america": "South America",contrast: "Contrast",controller: "Controller","controller-customization": "Controller customization","controller-customization-input-latency-note": "May slightly increase input latency","controller-friendly-ui": "Controller-friendly UI","controller-shortcuts": "Controller shortcuts","controller-shortcuts-connect-note": "Connect a controller to use this feature","controller-shortcuts-xbox-note": "Button to open the Guide menu","controller-vibration": "Controller vibration",copy: "Copy","create-shortcut": "Shortcut",custom: "Custom","deadzone-counterweight": "Deadzone counterweight",decrease: "Decrease",default: "Default","default-opacity": "Default opacity","default-preset-note": "You can't modify default presets. Create a new one to customize it.",delete: "Delete","detect-controller-button": "Detect controller button",device: "Device","device-unsupported-touch": "Your device doesn't have touch support","device-vibration": "Device vibration","device-vibration-not-using-gamepad": "On when not using gamepad",disable: "Disable","disable-features": "Disable features","disable-home-context-menu": "Disable context menu in Home page","disable-post-stream-feedback-dialog": "Disable post-stream feedback dialog","disable-social-features": "Disable social features","disable-xcloud-analytics": "Disable xCloud analytics",disabled: "Disabled",disconnected: "Disconnected",download: "Download",downloaded: "Downloaded",edit: "Edit","enable-controller-shortcuts": "Enable controller shortcuts","enable-local-co-op-support": "Enable local co-op support","enable-local-co-op-support-note": "Only works with some games","enable-mic-on-startup": "Enable microphone on game launch","enable-mkb": "Emulate controller with Mouse & Keyboard","enable-quick-glance-mode": 'Enable "Quick Glance" mode',"enable-remote-play-feature": 'Enable the "Remote Play" feature',"enable-volume-control": "Enable volume control feature",enabled: "Enabled",experimental: "Experimental",export: "Export",fast: "Fast","force-native-mkb-games": "Force native Mouse & Keyboard for these games","fortnite-allow-stw-mode": 'Allows playing "Save the World" mode on mobile',"fortnite-force-console-version": "Fortnite: force console version","friends-followers": "Friends and followers","game-bar": "Game Bar","getting-consoles-list": "Getting the list of consoles...",guide: "Guide",help: "Help",hide: "Hide","hide-idle-cursor": "Hide mouse cursor on idle","hide-scrollbar": "Hide web page's scrollbar","hide-sections": "Hide sections","hide-system-menu-icon": "Hide System menu's icon","hide-touch-controller": "Hide touch controller","high-performance": "High performance","highest-quality": "Highest quality","highest-quality-note": "Your device may not be powerful enough to use these settings","horizontal-scroll-sensitivity": "Horizontal scroll sensitivity","horizontal-sensitivity": "Horizontal sensitivity","how-to-fix": "How to fix","how-to-improve-app-performance": "How to improve app's performance",ignore: "Ignore","image-quality": "Website's image quality",import: "Import","in-game-controller-customization": "In-game controller customization","in-game-controller-shortcuts": "In-game controller shortcuts","in-game-keyboard-shortcuts": "In-game keyboard shortcuts","in-game-shortcuts": "In-game shortcuts",increase: "Increase","install-android": "Better xCloud app for Android",invites: "Invites",japan: "Japan",jitter: "Jitter","keyboard-key": "Keyboard key","keyboard-shortcuts": "Keyboard shortcuts",korea: "Korea",language: "Language",large: "Large",layout: "Layout","left-stick": "Left stick","left-stick-deadzone": "Left stick deadzone","left-trigger-range": "Left trigger range","limit-fps": "Limit FPS","load-failed-message": "Failed to run Better xCloud","loading-screen": "Loading screen","local-co-op": "Local co-op","lowest-quality": "Lowest quality",manage: "Manage","map-mouse-to": "Map mouse to","may-not-work-properly": "May not work properly!",menu: "Menu",microphone: "Microphone","mkb-adjust-ingame-settings": "You may also need to adjust the in-game sensitivity & deadzone settings","mkb-click-to-activate": "Click to activate","mkb-disclaimer": "This could be viewed as cheating when playing online","modifiers-note": "To use more than one key, include Ctrl, Alt or Shift in your shortcut. Command key is not allowed.","mouse-and-keyboard": "Mouse & Keyboard","mouse-click": "Mouse click","mouse-wheel": "Mouse wheel",muted: "Muted",name: "Name","native-mkb": "Native Mouse & Keyboard",new: "New","new-version-available": [e => `Version ${e.version} available`,e => `Versió ${e.version} disponible`,,e => `Version ${e.version} verfügbar`,e => `Versi ${e.version} tersedia`,e => `Versión ${e.version} disponible`,e => `Version ${e.version} disponible`,e => `Disponibile la versione ${e.version}`,e => `Ver ${e.version} が利用可能です`,e => `${e.version} 버전 사용가능`,e => `Dostępna jest nowa wersja ${e.version}`,e => `Versão ${e.version} disponível`,e => `Версия ${e.version} доступна`,e => `เวอร์ชัน ${e.version} พร้อมใช้งานแล้ว`,e => `${e.version} sayılı yeni sürüm mevcut`,e => `Доступна версія ${e.version}`,e => `Đã có phiên bản ${e.version}`,e => `版本 ${e.version} 可供更新`,e => `已可更新為 ${e.version} 版`],"no-consoles-found": "No consoles found","no-controllers-connected": "No controllers connected",normal: "Normal",notifications: "Notifications",off: "Off",official: "Official",on: "On","only-supports-some-games": "Only supports some games",opacity: "Opacity",other: "Other",playing: "Playing",playtime: "Playtime",poland: "Poland","polling-rate": "Polling rate",position: "Position","powered-off": "Powered off","powered-on": "Powered on","prefer-ipv6-server": "Prefer IPv6 server","preferred-game-language": "Preferred game's language",preset: "Preset",press: "Press","press-any-button": "Press any button...","press-esc-to-cancel": "Press Esc to cancel","press-key-to-toggle-mkb": [e => `Press ${e.key} to toggle this feature`,e => `Premeu ${e.key} per alternar aquesta funció`,e => `Tryk på ${e.key} for at slå denne funktion til`,e => `${e.key}: Funktion an-/ausschalten`,e => `Tekan ${e.key} untuk mengaktifkan fitur ini`,e => `Pulsa ${e.key} para alternar esta función`,e => `Appuyez sur ${e.key} pour activer cette fonctionnalité`,e => `Premi ${e.key} per attivare questa funzionalità`,e => `${e.key} でこの機能を切替`,e => `${e.key} 키를 눌러 이 기능을 켜고 끄세요`,e => `Naciśnij ${e.key} aby przełączyć tę funkcję`,e => `Pressione ${e.key} para alternar este recurso`,e => `Нажмите ${e.key} для переключения этой функции`,e => `กด ${e.key} เพื่อสลับคุณสมบัตินี้`,e => `Etkinleştirmek için ${e.key} tuşuna basın`,e => `Натисніть ${e.key} щоб перемкнути цю функцію`,e => `Nhấn ${e.key} để bật/tắt tính năng này`,e => `按下 ${e.key} 来切换此功能`,e => `按下 ${e.key} 來啟用此功能`],"press-to-bind": "Press a key or do a mouse click to bind...","prompt-preset-name": "Preset's name:",recommended: "Recommended","recommended-settings-for-device": [e => `Recommended settings for ${e.device}`,e => `Configuració recomanada per a ${e.device}`,,e => `Empfohlene Einstellungen für ${e.device}`,e => `Rekomendasi pengaturan untuk ${e.device}`,e => `Ajustes recomendados para ${e.device}`,e => `Paramètres recommandés pour ${e.device}`,e => `Configurazioni consigliate per ${e.device}`,e => `${e.device} の推奨設定`,e => `다음 기기에서 권장되는 설정: ${e.device}`,e => `Zalecane ustawienia dla ${e.device}`,e => `Configurações recomendadas para ${e.device}`,e => `Рекомендуемые настройки для ${e.device}`,e => `การตั้งค่าที่แนะนำสำหรับ ${e.device}`,e => `${e.device} için önerilen ayarlar`,e => `Рекомендовані налаштування для ${e.device}`,e => `Cấu hình được đề xuất cho ${e.device}`,e => `${e.device} 的推荐设置`,e => `${e.device} 推薦的設定`],"reduce-animations": "Reduce UI animations",region: "Region","reload-page": "Reload page","remote-play": "Remote Play",rename: "Rename",renderer: "Renderer","renderer-configuration": "Renderer configuration","reset-highlighted-setting": "Reset highlighted setting","right-click-to-unbind": "Right-click on a key to unbind it","right-stick": "Right stick","right-stick-deadzone": "Right stick deadzone","right-trigger-range": "Right trigger range","rocket-always-hide": "Always hide","rocket-always-show": "Always show","rocket-animation": "Rocket animation","rocket-hide-queue": "Hide when queuing",saturation: "Saturation",save: "Save",screen: "Screen","screenshot-apply-filters": "Apply video filters to screenshots","section-all-games": "All games","section-most-popular": "Most popular","section-native-mkb": "Play with mouse & keyboard","section-news": "News","section-play-with-friends": "Play with friends","section-touch": "Play with touch","separate-touch-controller": "Separate Touch controller & Controller #1","separate-touch-controller-note": "Touch controller is Player 1, Controller #1 is Player 2",server: "Server","server-locations": "Server locations",settings: "Settings","settings-for": "Settings for","settings-reload": "Reload page to reflect changes","settings-reload-note": "Settings in this tab only go into effect on the next page load","settings-reloading": "Reloading...",sharpness: "Sharpness","shortcut-keys": "Shortcut keys",show: "Show","show-controller-connection-status": "Show controller connection status","show-game-art": "Show game art","show-hide": "Show/hide","show-stats-on-startup": "Show stats when starting the game","show-touch-controller": "Show touch controller","show-wait-time": "Show the estimated wait time","show-wait-time-in-game-card": "Show wait time in game card","simplify-stream-menu": "Simplify Stream's menu","skip-splash-video": "Skip Xbox splash video",slow: "Slow",small: "Small","smart-tv": "Smart TV",sound: "Sound",standard: "Standard",standby: "Standby","stat-bitrate": "Bitrate","stat-decode-time": "Decode time","stat-fps": "FPS","stat-frames-lost": "Frames lost","stat-packets-lost": "Packets lost","stat-ping": "Ping",stats: "Stats","stick-decay-minimum": "Stick decay minimum","stick-decay-strength": "Stick decay strength",stream: "Stream","stream-settings": "Stream settings","stream-stats": "Stream stats","stream-your-own-game": "Stream your own game",stretch: "Stretch","suggest-settings": "Suggest settings","suggest-settings-link": "Suggest recommended settings for this device","support-better-xcloud": "Support Better xCloud","swap-buttons": "Swap buttons","take-screenshot": "Take screenshot","target-resolution": "Target resolution","tc-all-white": "All white","tc-auto-off": "Off when controller found","tc-custom-layout-style": "Custom layout's button style","tc-muted-colors": "Muted colors","tc-standard-layout-style": "Standard layout's button style","text-size": "Text size",toggle: "Toggle",top: "Top","top-center": "Top-center","top-half": "Top half","top-left": "Top-left","top-right": "Top-right","touch-control-layout": "Touch control layout","touch-control-layout-by": [e => `Touch control layout by ${e.name}`,e => `Format del control tàctil per ${e.name}`,e => `Touch-kontrol layout af ${e.name}`,e => `Touch-Steuerungslayout von ${e.name}`,e => `Tata letak Sentuhan layar oleh ${e.name}`,e => `Disposición del control táctil por ${e.nombre}`,e => `Disposition du contrôleur tactile par ${e.name}`,e => `Configurazione dei comandi su schermo creata da ${e.name}`,e => `タッチ操作レイアウト作成者: ${e.name}`,e => `${e.name} 제작, 터치 컨트롤 레이아웃`,e => `Układ sterowania dotykowego stworzony przez ${e.name}`,e => `Disposição de controle por toque feito por ${e.name}`,e => `Сенсорная раскладка по ${e.name}`,e => `รูปแบบการควบคุมแบบสัมผัสโดย ${e.name}`,e => `${e.name} kişisinin dokunmatik kontrolcü tuş şeması`,e => `Розташування сенсорного керування від ${e.name}`,e => `Bố cục điều khiển cảm ứng tạo bởi ${e.name}`,e => `由 ${e.name} 提供的虚拟按键样式`,e => `觸控遊玩佈局由 ${e.name} 提供`],"touch-controller": "Touch controller","true-achievements": "TrueAchievements",ui: "UI","unexpected-behavior": "May cause unexpected behavior","united-states": "United States",unknown: "Unknown",unlimited: "Unlimited",unmuted: "Unmuted",unofficial: "Unofficial","unofficial-game-list": "Unofficial game list","unsharp-masking": "Unsharp masking",upload: "Upload",uploaded: "Uploaded","use-mouse-absolute-position": "Use mouse's absolute position","use-this-at-your-own-risk": "Use this at your own risk","user-agent-profile": "User-Agent profile","vertical-scroll-sensitivity": "Vertical scroll sensitivity","vertical-sensitivity": "Vertical sensitivity","vibration-intensity": "Vibration intensity","vibration-status": "Vibration",video: "Video","virtual-controller": "Virtual controller","virtual-controller-slot": "Virtual controller slot","visual-quality": "Visual quality","visual-quality-high": "High","visual-quality-low": "Low","visual-quality-normal": "Normal",volume: "Volume","wait-time-countdown": "Countdown","wait-time-estimated": "Estimated finish time","waiting-for-input": "Waiting for input...",wallpaper: "Wallpaper",webgl2: "WebGL2"};
+var SUPPORTED_LANGUAGES = {"en-US": "English (US)","ca-CA": "Català","da-DK": "dansk","de-DE": "Deutsch","en-ID": "Bahasa Indonesia","es-ES": "español (España)","fr-FR": "français","it-IT": "italiano","ja-JP": "日本語","ko-KR": "한국어","pl-PL": "polski","pt-BR": "português (Brasil)","ru-RU": "русский","th-TH": "ภาษาไทย","tr-TR": "Türkçe","uk-UA": "українська","vi-VN": "Tiếng Việt","zh-CN": "中文(简体)","zh-TW": "中文(繁體)"}, Texts = {webgpu: "WebGPU","section-recently-added": "Recently added","section-leaving-soon": "Leaving soon","section-genres": "Genres",oled: "OLED",theme: "Theme",achievements: "Achievements",activate: "Activate",activated: "Activated",active: "Active",advanced: "Advanced","all-games": "All games","always-off": "Always off","always-on": "Always on","amd-fidelity-cas": "AMD FidelityFX CAS","app-settings": "App settings",apply: "Apply","aspect-ratio": "Aspect ratio","aspect-ratio-note": "Don't use with native touch games",audio: "Audio",auto: "Auto",availability: "Availability","back-to-home": "Back to home","back-to-home-confirm": "Do you want to go back to the home page (without disconnecting)?","background-opacity": "Background opacity",battery: "Battery","battery-saving": "Battery saving","better-xcloud": "Better xCloud","bitrate-audio-maximum": "Maximum audio bitrate","bitrate-video-maximum": "Maximum video bitrate",bottom: "Bottom","bottom-half": "Bottom half","bottom-left": "Bottom-left","bottom-right": "Bottom-right",brazil: "Brazil",brightness: "Brightness","browser-unsupported-feature": "Your browser doesn't support this feature","button-xbox": "Xbox button","bypass-region-restriction": "Bypass region restriction","can-stream-xbox-360-games": "Can stream Xbox 360 games",cancel: "Cancel","cant-stream-xbox-360-games": "Can't stream Xbox 360 games",center: "Center",chat: "Chat","clarity-boost": "Clarity boost","clarity-boost-warning": "These settings don't work when the Clarity Boost mode is ON",clear: "Clear","clear-data": "Clear data","clear-data-confirm": "Do you want to clear all Better xCloud settings and data?","clear-data-success": "Data cleared! Refresh the page to apply the changes.",clock: "Clock",close: "Close","close-app": "Close app","combine-audio-video-streams": "Combine audio & video streams","combine-audio-video-streams-summary": "May fix the laggy audio problem","conditional-formatting": "Conditional formatting text color","confirm-delete-preset": "Do you want to delete this preset?","confirm-reload-stream": "Do you want to refresh the stream?",connected: "Connected","console-connect": "Connect","continent-asia": "Asia","continent-australia": "Australia","continent-europe": "Europe","continent-north-america": "North America","continent-south-america": "South America",contrast: "Contrast",controller: "Controller","controller-customization": "Controller customization","controller-customization-input-latency-note": "May slightly increase input latency","controller-friendly-ui": "Controller-friendly UI","controller-shortcuts": "Controller shortcuts","controller-shortcuts-connect-note": "Connect a controller to use this feature","controller-shortcuts-xbox-note": "Button to open the Guide menu","controller-vibration": "Controller vibration",copy: "Copy","create-shortcut": "Shortcut",custom: "Custom","deadzone-counterweight": "Deadzone counterweight",decrease: "Decrease",default: "Default","default-opacity": "Default opacity","default-preset-note": "You can't modify default presets. Create a new one to customize it.",delete: "Delete","detect-controller-button": "Detect controller button",device: "Device","device-unsupported-touch": "Your device doesn't have touch support","device-vibration": "Device vibration","device-vibration-not-using-gamepad": "On when not using gamepad",disable: "Disable","disable-features": "Disable features","disable-home-context-menu": "Disable context menu in Home page","disable-post-stream-feedback-dialog": "Disable post-stream feedback dialog","disable-social-features": "Disable social features","disable-xcloud-analytics": "Disable xCloud analytics",disabled: "Disabled",disconnected: "Disconnected",download: "Download",downloaded: "Downloaded",edit: "Edit","enable-controller-shortcuts": "Enable controller shortcuts","enable-local-co-op-support": "Enable local co-op support","enable-local-co-op-support-note": "Only works with some games","enable-mic-on-startup": "Enable microphone on game launch","enable-mkb": "Emulate controller with Mouse & Keyboard","enable-quick-glance-mode": 'Enable "Quick Glance" mode',"enable-remote-play-feature": 'Enable the "Remote Play" feature',"enable-volume-control": "Enable volume control feature",enabled: "Enabled",experimental: "Experimental",export: "Export",fast: "Fast","force-native-mkb-games": "Force native Mouse & Keyboard for these games","fortnite-allow-stw-mode": 'Allows playing "Save the World" mode on mobile',"fortnite-force-console-version": "Fortnite: force console version","friends-followers": "Friends and followers","game-bar": "Game Bar","getting-consoles-list": "Getting the list of consoles...",guide: "Guide",help: "Help",hide: "Hide","hide-idle-cursor": "Hide mouse cursor on idle","hide-scrollbar": "Hide web page's scrollbar","hide-sections": "Hide sections","hide-system-menu-icon": "Hide System menu's icon","hide-touch-controller": "Hide touch controller","high-performance": "High performance","highest-quality": "Highest quality","highest-quality-note": "Your device may not be powerful enough to use these settings","horizontal-scroll-sensitivity": "Horizontal scroll sensitivity","horizontal-sensitivity": "Horizontal sensitivity","how-to-fix": "How to fix","how-to-improve-app-performance": "How to improve app's performance",ignore: "Ignore","image-quality": "Website's image quality",import: "Import","in-game-controller-customization": "In-game controller customization","in-game-controller-shortcuts": "In-game controller shortcuts","in-game-keyboard-shortcuts": "In-game keyboard shortcuts","in-game-shortcuts": "In-game shortcuts",increase: "Increase","install-android": "Better xCloud app for Android",invites: "Invites",japan: "Japan",jitter: "Jitter","keyboard-key": "Keyboard key","keyboard-shortcuts": "Keyboard shortcuts",korea: "Korea",language: "Language",large: "Large",layout: "Layout","left-stick": "Left stick","left-stick-deadzone": "Left stick deadzone","left-trigger-range": "Left trigger range","limit-fps": "Limit FPS","load-failed-message": "Failed to run Better xCloud","loading-screen": "Loading screen","local-co-op": "Local co-op","lowest-quality": "Lowest quality",manage: "Manage","map-mouse-to": "Map mouse to","may-not-work-properly": "May not work properly!",menu: "Menu",microphone: "Microphone","mkb-adjust-ingame-settings": "You may also need to adjust the in-game sensitivity & deadzone settings","mkb-click-to-activate": "Click to activate","mkb-disclaimer": "This could be viewed as cheating when playing online","modifiers-note": "To use more than one key, include Ctrl, Alt or Shift in your shortcut. Command key is not allowed.","mouse-and-keyboard": "Mouse & Keyboard","mouse-click": "Mouse click","mouse-wheel": "Mouse wheel",muted: "Muted",name: "Name","native-mkb": "Native Mouse & Keyboard",new: "New","new-version-available": [e => `Version ${e.version} available`,e => `Versió ${e.version} disponible`,,e => `Version ${e.version} verfügbar`,e => `Versi ${e.version} tersedia`,e => `Versión ${e.version} disponible`,e => `Version ${e.version} disponible`,e => `Disponibile la versione ${e.version}`,e => `Ver ${e.version} が利用可能です`,e => `${e.version} 버전 사용가능`,e => `Dostępna jest nowa wersja ${e.version}`,e => `Versão ${e.version} disponível`,e => `Версия ${e.version} доступна`,e => `เวอร์ชัน ${e.version} พร้อมใช้งานแล้ว`,e => `${e.version} sayılı yeni sürüm mevcut`,e => `Доступна версія ${e.version}`,e => `Đã có phiên bản ${e.version}`,e => `版本 ${e.version} 可供更新`,e => `已可更新為 ${e.version} 版`],"no-consoles-found": "No consoles found","no-controllers-connected": "No controllers connected",normal: "Normal",notifications: "Notifications",off: "Off",official: "Official",on: "On","only-supports-some-games": "Only supports some games",opacity: "Opacity",other: "Other",playing: "Playing",playtime: "Playtime",poland: "Poland","polling-rate": "Polling rate",position: "Position","powered-off": "Powered off","powered-on": "Powered on","prefer-ipv6-server": "Prefer IPv6 server","preferred-game-language": "Preferred game's language",preset: "Preset",press: "Press","press-any-button": "Press any button...","press-esc-to-cancel": "Press Esc to cancel","press-key-to-toggle-mkb": [e => `Press ${e.key} to toggle this feature`,e => `Premeu ${e.key} per alternar aquesta funció`,e => `Tryk på ${e.key} for at slå denne funktion til`,e => `${e.key}: Funktion an-/ausschalten`,e => `Tekan ${e.key} untuk mengaktifkan fitur ini`,e => `Pulsa ${e.key} para alternar esta función`,e => `Appuyez sur ${e.key} pour activer cette fonctionnalité`,e => `Premi ${e.key} per attivare questa funzionalità`,e => `${e.key} でこの機能を切替`,e => `${e.key} 키를 눌러 이 기능을 켜고 끄세요`,e => `Naciśnij ${e.key} aby przełączyć tę funkcję`,e => `Pressione ${e.key} para alternar este recurso`,e => `Нажмите ${e.key} для переключения этой функции`,e => `กด ${e.key} เพื่อสลับคุณสมบัตินี้`,e => `Etkinleştirmek için ${e.key} tuşuna basın`,e => `Натисніть ${e.key} щоб перемкнути цю функцію`,e => `Nhấn ${e.key} để bật/tắt tính năng này`,e => `按下 ${e.key} 来切换此功能`,e => `按下 ${e.key} 來啟用此功能`],"press-to-bind": "Press a key or do a mouse click to bind...","prompt-preset-name": "Preset's name:",recommended: "Recommended","recommended-settings-for-device": [e => `Recommended settings for ${e.device}`,e => `Configuració recomanada per a ${e.device}`,,e => `Empfohlene Einstellungen für ${e.device}`,e => `Rekomendasi pengaturan untuk ${e.device}`,e => `Ajustes recomendados para ${e.device}`,e => `Paramètres recommandés pour ${e.device}`,e => `Configurazioni consigliate per ${e.device}`,e => `${e.device} の推奨設定`,e => `다음 기기에서 권장되는 설정: ${e.device}`,e => `Zalecane ustawienia dla ${e.device}`,e => `Configurações recomendadas para ${e.device}`,e => `Рекомендуемые настройки для ${e.device}`,e => `การตั้งค่าที่แนะนำสำหรับ ${e.device}`,e => `${e.device} için önerilen ayarlar`,e => `Рекомендовані налаштування для ${e.device}`,e => `Cấu hình được đề xuất cho ${e.device}`,e => `${e.device} 的推荐设置`,e => `${e.device} 推薦的設定`],"reduce-animations": "Reduce UI animations",region: "Region","reload-page": "Reload page","remote-play": "Remote Play",rename: "Rename",renderer: "Renderer","renderer-configuration": "Renderer configuration","reset-highlighted-setting": "Reset highlighted setting","right-click-to-unbind": "Right-click on a key to unbind it","right-stick": "Right stick","right-stick-deadzone": "Right stick deadzone","right-trigger-range": "Right trigger range","rocket-always-hide": "Always hide","rocket-always-show": "Always show","rocket-animation": "Rocket animation","rocket-hide-queue": "Hide when queuing",saturation: "Saturation",save: "Save",screen: "Screen","screenshot-apply-filters": "Apply video filters to screenshots","section-all-games": "All games","section-most-popular": "Most popular","section-native-mkb": "Play with mouse & keyboard","section-news": "News","section-play-with-friends": "Play with friends","section-touch": "Play with touch","separate-touch-controller": "Separate Touch controller & Controller #1","separate-touch-controller-note": "Touch controller is Player 1, Controller #1 is Player 2",server: "Server","server-locations": "Server locations",settings: "Settings","settings-for": "Settings for","settings-reload": "Reload page to reflect changes","settings-reload-note": "Settings in this tab only go into effect on the next page load","settings-reloading": "Reloading...",sharpness: "Sharpness","shortcut-keys": "Shortcut keys",show: "Show","show-controller-connection-status": "Show controller connection status","show-game-art": "Show game art","show-hide": "Show/hide","show-stats-on-startup": "Show stats when starting the game","show-touch-controller": "Show touch controller","show-wait-time": "Show the estimated wait time","show-wait-time-in-game-card": "Show wait time in game card","simplify-stream-menu": "Simplify Stream's menu","skip-splash-video": "Skip Xbox splash video",slow: "Slow",small: "Small","smart-tv": "Smart TV",sound: "Sound",standard: "Standard",standby: "Standby","stat-bitrate": "Bitrate","stat-decode-time": "Decode time","stat-fps": "FPS","stat-frames-lost": "Frames lost","stat-packets-lost": "Packets lost","stat-ping": "Ping",stats: "Stats","stick-decay-minimum": "Stick decay minimum","stick-decay-strength": "Stick decay strength",stream: "Stream","stream-settings": "Stream settings","stream-stats": "Stream stats","stream-your-own-game": "Stream your own game",stretch: "Stretch","suggest-settings": "Suggest settings","suggest-settings-link": "Suggest recommended settings for this device","support-better-xcloud": "Support Better xCloud","swap-buttons": "Swap buttons","take-screenshot": "Take screenshot","target-resolution": "Target resolution","tc-all-white": "All white","tc-auto-off": "Off when controller found","tc-custom-layout-style": "Custom layout's button style","tc-muted-colors": "Muted colors","tc-standard-layout-style": "Standard layout's button style","text-size": "Text size",toggle: "Toggle",top: "Top","top-center": "Top-center","top-half": "Top half","top-left": "Top-left","top-right": "Top-right","touch-control-layout": "Touch control layout","touch-control-layout-by": [e => `Touch control layout by ${e.name}`,e => `Format del control tàctil per ${e.name}`,e => `Touch-kontrol layout af ${e.name}`,e => `Touch-Steuerungslayout von ${e.name}`,e => `Tata letak Sentuhan layar oleh ${e.name}`,e => `Disposición del control táctil por ${e.nombre}`,e => `Disposition du contrôleur tactile par ${e.name}`,e => `Configurazione dei comandi su schermo creata da ${e.name}`,e => `タッチ操作レイアウト作成者: ${e.name}`,e => `${e.name} 제작, 터치 컨트롤 레이아웃`,e => `Układ sterowania dotykowego stworzony przez ${e.name}`,e => `Disposição de controle por toque feito por ${e.name}`,e => `Сенсорная раскладка по ${e.name}`,e => `รูปแบบการควบคุมแบบสัมผัสโดย ${e.name}`,e => `${e.name} kişisinin dokunmatik kontrolcü tuş şeması`,e => `Розташування сенсорного керування від ${e.name}`,e => `Bố cục điều khiển cảm ứng tạo bởi ${e.name}`,e => `由 ${e.name} 提供的虚拟按键样式`,e => `觸控遊玩佈局由 ${e.name} 提供`],"touch-controller": "Touch controller","true-achievements": "TrueAchievements",ui: "UI","unexpected-behavior": "May cause unexpected behavior","united-states": "United States",unknown: "Unknown",unlimited: "Unlimited",unmuted: "Unmuted",unofficial: "Unofficial","unofficial-game-list": "Unofficial game list","unsharp-masking": "Unsharp masking",upload: "Upload",uploaded: "Uploaded","use-mouse-absolute-position": "Use mouse's absolute position","use-this-at-your-own-risk": "Use this at your own risk","user-agent-profile": "User-Agent profile","vertical-scroll-sensitivity": "Vertical scroll sensitivity","vertical-sensitivity": "Vertical sensitivity","vibration-intensity": "Vibration intensity","vibration-status": "Vibration",video: "Video","virtual-controller": "Virtual controller","virtual-controller-slot": "Virtual controller slot","visual-quality": "Visual quality","visual-quality-high": "High","visual-quality-low": "Low","visual-quality-normal": "Normal",volume: "Volume","wait-time-countdown": "Countdown","wait-time-estimated": "Estimated finish time","waiting-for-input": "Waiting for input...",wallpaper: "Wallpaper",webgl2: "WebGL2"};
class Translations {static EN_US = "en-US";static KEY_LOCALE = "BetterXcloud.Locale";static KEY_TRANSLATIONS = "BetterXcloud.Locale.Translations";static selectedLocaleIndex = -1;static selectedLocale = "en-US";static supportedLocales = Object.keys(SUPPORTED_LANGUAGES);static foreignTranslations = {};static enUsIndex = Translations.supportedLocales.indexOf(Translations.EN_US);static async init() {Translations.refreshLocale(), await Translations.loadTranslations();}static refreshLocale(newLocale) {let locale;if (newLocale) localStorage.setItem(Translations.KEY_LOCALE, newLocale), locale = newLocale;else locale = localStorage.getItem(Translations.KEY_LOCALE);let supportedLocales = Translations.supportedLocales;if (!locale) {if (locale = window.navigator.language || Translations.EN_US, supportedLocales.indexOf(locale) === -1) locale = Translations.EN_US;localStorage.setItem(Translations.KEY_LOCALE, locale);}Translations.selectedLocale = locale, Translations.selectedLocaleIndex = supportedLocales.indexOf(locale);}static get(key, values) {let text = null;if (Translations.foreignTranslations && Translations.selectedLocale !== Translations.EN_US) text = Translations.foreignTranslations[key];if (!text) text = Texts[key] || alert(`Missing translation key: ${key}`);let translation;if (Array.isArray(text)) return translation = text[Translations.selectedLocaleIndex] || text[Translations.enUsIndex], translation(values);return translation = text, translation;}static async loadTranslations() {if (Translations.selectedLocale === Translations.EN_US) return;try {Translations.foreignTranslations = JSON.parse(window.localStorage.getItem(Translations.KEY_TRANSLATIONS));} catch (e) {}if (!Translations.foreignTranslations) await this.downloadTranslations(Translations.selectedLocale);}static async updateTranslations(async = !1) {if (Translations.selectedLocale === Translations.EN_US) {localStorage.removeItem(Translations.KEY_TRANSLATIONS);return;}if (async) Translations.downloadTranslationsAsync(Translations.selectedLocale);else await Translations.downloadTranslations(Translations.selectedLocale);}static async downloadTranslations(locale) {try {let translations = await (await NATIVE_FETCH(GhPagesUtils.getUrl(`translations/${locale}.json`))).json();if (localStorage.getItem(Translations.KEY_LOCALE) === locale) window.localStorage.setItem(Translations.KEY_TRANSLATIONS, JSON.stringify(translations)), Translations.foreignTranslations = translations;return !0;} catch (e) {debugger;}return !1;}static downloadTranslationsAsync(locale) {NATIVE_FETCH(GhPagesUtils.getUrl(`translations/${locale}.json`)).then((resp) => resp.json()).then((translations) => {window.localStorage.setItem(Translations.KEY_TRANSLATIONS, JSON.stringify(translations)), Translations.foreignTranslations = translations;});}static switchLocale(locale) {localStorage.setItem(Translations.KEY_LOCALE, locale);}}
var t = Translations.get;
Translations.init();
@@ -69,7 +69,7 @@ var BypassServers = {br: t("brazil"),jp: t("japan"),kr: t("korea"),pl: t("poland
class BaseSettingsStorage {storage;storageKey;_settings;definitions;constructor(storageKey, definitions) {this.storage = window.localStorage, this.storageKey = storageKey;for (let [_, setting] of Object.entries(definitions)) {if (typeof setting.requiredVariants === "string") setting.requiredVariants = [setting.requiredVariants];if (setting.ready) setting.ready.call(this, setting), delete setting.ready;}this.definitions = definitions, this._settings = null;}get settings() {if (this._settings) return this._settings;let settings = JSON.parse(this.storage.getItem(this.storageKey) || "{}");for (let key in settings)settings[key] = this.validateValue("get", key, settings[key]);return this._settings = settings, settings;}getDefinition(key) {if (!this.definitions[key]) return alert("Request invalid definition: " + key), {};return this.definitions[key];}hasSetting(key) {return key in this.settings;}getSetting(key, checkUnsupported = !0) {let definition = this.definitions[key];if (definition.requiredVariants && !definition.requiredVariants.includes(SCRIPT_VARIANT)) return isPlainObject(definition.default) ? deepClone(definition.default) : definition.default;if (checkUnsupported && definition.unsupported) if ("unsupportedValue" in definition) return definition.unsupportedValue;else return isPlainObject(definition.default) ? deepClone(definition.default) : definition.default;if (!(key in this.settings)) this.settings[key] = this.validateValue("get", key, null);return isPlainObject(this.settings[key]) ? deepClone(this.settings[key]) : this.settings[key];}setSetting(key, value, origin) {if (value = this.validateValue("set", key, value), this.settings[key] = this.validateValue("get", key, value), this.saveSettings(), origin === "ui") if (isStreamPref(key)) BxEventBus.Stream.emit("setting.changed", {storageKey: this.storageKey,settingKey: key});else BxEventBus.Script.emit("setting.changed", {storageKey: this.storageKey,settingKey: key});return value;}saveSettings() {this.storage.setItem(this.storageKey, JSON.stringify(this.settings));}validateValue(action, key, value) {let def = this.definitions[key];if (!def) return value;if (typeof value === "undefined" || value === null) value = def.default;if (def.transformValue && action === "get") value = def.transformValue.get.call(def, value);if ("min" in def) value = Math.max(def.min, value);if ("max" in def) value = Math.min(def.max, value);if ("options" in def) {if (!(value in def.options)) value = def.default;} else if ("multipleOptions" in def) {if (value.length) {let validOptions = Object.keys(def.multipleOptions);value.forEach((item2, idx) => {validOptions.indexOf(item2) === -1 && value.splice(idx, 1);});}if (!value.length) value = def.default;}if (def.transformValue && action === "set") value = def.transformValue.set.call(def, value);return value;}getLabel(key) {return this.definitions[key].label || key;}getValueText(key, value) {let definition = this.definitions[key];if ("min" in definition) {let params = definition.params;if (params.customTextValue) {if (definition.transformValue) value = definition.transformValue.get.call(definition, value);let text = params.customTextValue(value, definition.min, definition.max);if (text) return text;}return value.toString();} else if ("options" in definition) {let options = definition.options;if (value in options) return options[value];} else if (typeof value === "boolean") return value ? t("on") : t("off");return value.toString();}deleteSetting(pref) {if (this.hasSetting(pref)) return delete this.settings[pref], this.saveSettings(), !0;return !1;}}
var BxIcon = {BETTER_XCLOUD: "",TRUE_ACHIEVEMENTS: "",STREAM_SETTINGS: "",STREAM_STATS: "",CLOSE: "",CONTROLLER: "",CREATE_SHORTCUT: "",DISPLAY: "",EYE: "",EYE_SLASH: "",HOME: "",LOCAL_CO_OP: "",NATIVE_MKB: "",NEW: "",MANAGE: "",COPY: "",TRASH: "",CURSOR_TEXT: "",POWER: "",QUESTION: "",REFRESH: "",REMOTE_PLAY: "",CARET_LEFT: "",CARET_RIGHT: "",SCREENSHOT: "",SPEAKER_MUTED: "",TOUCH_CONTROL_ENABLE: "",TOUCH_CONTROL_DISABLE: "",MICROPHONE: "",MICROPHONE_MUTED: "",BATTERY: "",PLAYTIME: "",SERVER: "",DOWNLOAD: "",UPLOAD: "",AUDIO: ""};
function getSupportedCodecProfiles() {let options = {default: t("default")};if (!("getCapabilities" in RTCRtpReceiver)) return options;let hasLowCodec = !1, hasNormalCodec = !1, hasHighCodec = !1, codecs = RTCRtpReceiver.getCapabilities("video").codecs;for (let codec of codecs) {if (codec.mimeType.toLowerCase() !== "video/h264" || !codec.sdpFmtpLine) continue;let fmtp = codec.sdpFmtpLine.toLowerCase();if (fmtp.includes("profile-level-id=4d")) hasHighCodec = !0;else if (fmtp.includes("profile-level-id=42e")) hasNormalCodec = !0;else if (fmtp.includes("profile-level-id=420")) hasLowCodec = !0;}if (hasLowCodec) if (!hasNormalCodec && !hasHighCodec) options["default"] = `${t("visual-quality-low")} (${t("default")})`;else options["low"] = t("visual-quality-low");if (hasNormalCodec) if (!hasLowCodec && !hasHighCodec) options["default"] = `${t("visual-quality-normal")} (${t("default")})`;else options["normal"] = t("visual-quality-normal");if (hasHighCodec) if (!hasLowCodec && !hasNormalCodec) options["default"] = `${t("visual-quality-high")} (${t("default")})`;else options["high"] = t("visual-quality-high");return options;}
-class GlobalSettingsStorage extends BaseSettingsStorage {static DEFINITIONS = {"version.lastCheck": {default: 0},"version.latest": {default: ""},"version.current": {default: ""},"bx.locale": {label: t("language"),default: localStorage.getItem("BetterXcloud.Locale") || "en-US",options: SUPPORTED_LANGUAGES},"server.region": {label: t("region"),note: CE("a", { target: "_blank", href: "https://umap.openstreetmap.fr/en/map/xbox-cloud-gaming-servers_1135022" }, t("server-locations")),default: "default"},"server.bypassRestriction": {label: t("bypass-region-restriction"),note: "⚠️ " + t("use-this-at-your-own-risk"),default: "off",optionsGroup: t("region"),options: Object.assign({off: t("off")}, BypassServers)},"stream.locale": {label: t("preferred-game-language"),default: "default",options: {default: t("default"),"ar-SA": "العربية","bg-BG": "Български","cs-CZ": "čeština","da-DK": "dansk","de-DE": "Deutsch","el-GR": "Ελληνικά","en-GB": "English (UK)","en-US": "English (US)","es-ES": "español (España)","es-MX": "español (Latinoamérica)","fi-FI": "suomi","fr-FR": "français","he-IL": "עברית","hu-HU": "magyar","it-IT": "italiano","ja-JP": "日本語","ko-KR": "한국어","nb-NO": "norsk bokmål","nl-NL": "Nederlands","pl-PL": "polski","pt-BR": "português (Brasil)","pt-PT": "português (Portugal)","ro-RO": "Română","ru-RU": "русский","sk-SK": "slovenčina","sv-SE": "svenska","th-TH": "ไทย","tr-TR": "Türkçe","zh-CN": "中文(简体)","zh-TW": "中文 (繁體)"}},"stream.video.resolution": {label: t("target-resolution"),default: "auto",options: {auto: t("default"),"720p": "720p","1080p": "1080p","1080p-hq": "1080p (HQ)"},suggest: {lowest: "720p",highest: "1080p-hq"}},"stream.video.codecProfile": {label: t("visual-quality"),default: "default",options: getSupportedCodecProfiles(),ready: (setting) => {let options = setting.options, keys = Object.keys(options);if (keys.length <= 1) setting.unsupported = !0, setting.unsupportedNote = "⚠️ " + t("browser-unsupported-feature");setting.suggest = {lowest: keys.length === 1 ? keys[0] : keys[1],highest: keys[keys.length - 1]};}},"server.ipv6.prefer": {label: t("prefer-ipv6-server"),default: !1},"screenshot.applyFilters": {requiredVariants: "full",label: t("screenshot-apply-filters"),default: !1},"ui.splashVideo.skip": {label: t("skip-splash-video"),default: !1},"ui.systemMenu.hideHandle": {label: "⣿ " + t("hide-system-menu-icon"),default: !1},"ui.imageQuality": {requiredVariants: "full",label: t("image-quality"),default: 90,min: 10,max: 90,params: {steps: 10,exactTicks: 20,hideSlider: !0,customTextValue(value, min, max) {if (value === 90) return t("default");return value + "%";}}},"stream.video.combineAudio": {requiredVariants: "full",label: t("combine-audio-video-streams"),default: !1,experimental: !0,note: t("combine-audio-video-streams-summary")},"touchController.mode": {requiredVariants: "full",label: t("availability"),default: "all",options: {default: t("default"),off: t("off"),all: t("all-games")},unsupported: !STATES.userAgent.capabilities.touch,unsupportedValue: "default"},"touchController.autoOff": {requiredVariants: "full",label: t("tc-auto-off"),default: !1,unsupported: !STATES.userAgent.capabilities.touch},"touchController.opacity.default": {requiredVariants: "full",label: t("default-opacity"),default: 100,min: 10,max: 100,params: {steps: 10,suffix: "%",ticks: 10,hideSlider: !0},unsupported: !STATES.userAgent.capabilities.touch},"touchController.style.standard": {requiredVariants: "full",label: t("tc-standard-layout-style"),default: "default",options: {default: t("default"),white: t("tc-all-white"),muted: t("tc-muted-colors")},unsupported: !STATES.userAgent.capabilities.touch},"touchController.style.custom": {requiredVariants: "full",label: t("tc-custom-layout-style"),default: "default",options: {default: t("default"),muted: t("tc-muted-colors")},unsupported: !STATES.userAgent.capabilities.touch},"ui.streamMenu.simplify": {label: t("simplify-stream-menu"),default: !1},"mkb.cursor.hideIdle": {requiredVariants: "full",label: t("hide-idle-cursor"),default: !1},"ui.feedbackDialog.disabled": {requiredVariants: "full",label: t("disable-post-stream-feedback-dialog"),default: !1},"stream.video.maxBitrate": {requiredVariants: "full",label: t("bitrate-video-maximum"),note: "⚠️ " + t("unexpected-behavior"),default: 0,min: 102400,max: 15360000,transformValue: {get(value) {return value === 0 ? this.max : value;},set(value) {return value === this.max ? 0 : value;}},params: {steps: 102400,exactTicks: 5120000,customTextValue: (value, min, max) => {if (value = parseInt(value), value === max) return t("unlimited");else return (value / 1024000).toFixed(1) + " Mb/s";}},suggest: {highest: 0}},"gameBar.position": {requiredVariants: "full",label: t("position"),default: "bottom-left",options: {off: t("off"),"bottom-left": t("bottom-left"),"bottom-right": t("bottom-right")}},"ui.controllerStatus.show": {label: t("show-controller-connection-status"),default: !0},"mkb.enabled": {requiredVariants: "full",label: t("enable-mkb"),default: !1,unsupported: !STATES.userAgent.capabilities.mkb || !STATES.browser.capabilities.mkb,ready: (setting) => {let note, url;if (setting.unsupported) note = t("browser-unsupported-feature"), url = "https://github.com/redphx/better-xcloud/issues/206#issuecomment-1920475657";else note = t("mkb-disclaimer"), url = "https://better-xcloud.github.io/mouse-and-keyboard/#disclaimer";setting.unsupportedNote = () => CE("a", {href: url,target: "_blank"}, "⚠️ " + note);}},"nativeMkb.mode": {requiredVariants: "full",label: t("native-mkb"),default: "default",options: {default: t("default"),off: t("off"),on: t("on")},ready: (setting) => {if (STATES.browser.capabilities.emulatedNativeMkb) ;else if (UserAgent.isMobile()) setting.unsupported = !0, setting.unsupportedValue = "off", delete setting.options["default"], delete setting.options["on"];else delete setting.options["on"];}},"nativeMkb.forcedGames": {label: t("force-native-mkb-games"),default: [],unsupported: !AppInterface && UserAgent.isMobile(),ready: (setting) => {if (!setting.unsupported) setting.multipleOptions = GhPagesUtils.getNativeMkbCustomList(!0), BxEventBus.Script.once("list.forcedNativeMkb.updated", (payload) => {setting.multipleOptions = payload.data.data;});},params: {size: 6}},"ui.reduceAnimations": {label: t("reduce-animations"),default: !1},"loadingScreen.gameArt.show": {requiredVariants: "full",label: t("show-game-art"),default: !0},"loadingScreen.waitTime.show": {label: t("show-wait-time"),default: !0},"loadingScreen.rocket": {label: t("rocket-animation"),default: "show",options: {show: t("rocket-always-show"),"hide-queue": t("rocket-hide-queue"),hide: t("rocket-always-hide")}},"ui.controllerFriendly": {label: t("controller-friendly-ui"),default: BX_FLAGS.DeviceInfo.deviceType !== "unknown"},"ui.layout": {requiredVariants: "full",label: t("layout"),default: "default",options: {default: t("default"),normal: t("normal"),tv: t("smart-tv")}},"ui.hideScrollbar": {label: t("hide-scrollbar"),default: !1},"ui.hideSections": {requiredVariants: "full",label: t("hide-sections"),default: [],multipleOptions: {news: t("section-news"),friends: t("section-play-with-friends"),"native-mkb": t("section-native-mkb"),touch: t("section-touch"),"most-popular": t("section-most-popular"),"recently-added": t("section-recently-added"),"leaving-soon": t("section-leaving-soon"),genres: t("section-genres"),"all-games": t("section-all-games")},params: {size: 0}},"ui.gameCard.waitTime.show": {requiredVariants: "full",label: t("show-wait-time-in-game-card"),default: !0},"block.tracking": {label: t("disable-xcloud-analytics"),default: !1},"block.features": {requiredVariants: "full",label: t("disable-features"),default: [],multipleOptions: {chat: t("chat"),friends: t("friends-followers"),byog: t("stream-your-own-game"),"notifications-invites": t("notifications") + ": " + t("invites"),"notifications-achievements": t("notifications") + ": " + t("achievements")}},"userAgent.profile": {label: t("user-agent-profile"),note: "⚠️ " + t("unexpected-behavior"),default: BX_FLAGS.DeviceInfo.deviceType === "android-tv" || BX_FLAGS.DeviceInfo.deviceType === "webos" ? "vr-oculus" : "default",options: {default: t("default"),"windows-edge": "Edge + Windows","macos-safari": "Safari + macOS","vr-oculus": "Android TV","smarttv-generic": "Smart TV","smarttv-tizen": "Samsung Smart TV",custom: t("custom")}},"audio.mic.onPlaying": {label: t("enable-mic-on-startup"),default: !1},"audio.volume.booster.enabled": {requiredVariants: "full",label: t("enable-volume-control"),default: !1},"xhome.enabled": {requiredVariants: "full",label: t("enable-remote-play-feature"),labelIcon: BxIcon.REMOTE_PLAY,default: !1},"xhome.video.resolution": {requiredVariants: "full",default: "1080p",options: {"720p": "720p","1080p": "1080p","1080p-hq": "1080p (HQ)"}},"game.fortnite.forceConsole": {requiredVariants: "full",label: "🎮 " + t("fortnite-force-console-version"),default: !1,note: t("fortnite-allow-stw-mode")}};constructor() {super("BetterXcloud", GlobalSettingsStorage.DEFINITIONS);}}
+class GlobalSettingsStorage extends BaseSettingsStorage {static DEFINITIONS = {"version.lastCheck": {default: 0},"version.latest": {default: ""},"version.current": {default: ""},"bx.locale": {label: t("language"),default: localStorage.getItem("BetterXcloud.Locale") || "en-US",options: SUPPORTED_LANGUAGES},"server.region": {label: t("region"),note: CE("a", { target: "_blank", href: "https://umap.openstreetmap.fr/en/map/xbox-cloud-gaming-servers_1135022" }, t("server-locations")),default: "default"},"server.bypassRestriction": {label: t("bypass-region-restriction"),note: "⚠️ " + t("use-this-at-your-own-risk"),default: "off",optionsGroup: t("region"),options: Object.assign({off: t("off")}, BypassServers)},"stream.locale": {label: t("preferred-game-language"),default: "default",options: {default: t("default"),"ar-SA": "العربية","bg-BG": "Български","cs-CZ": "čeština","da-DK": "dansk","de-DE": "Deutsch","el-GR": "Ελληνικά","en-GB": "English (UK)","en-US": "English (US)","es-ES": "español (España)","es-MX": "español (Latinoamérica)","fi-FI": "suomi","fr-FR": "français","he-IL": "עברית","hu-HU": "magyar","it-IT": "italiano","ja-JP": "日本語","ko-KR": "한국어","nb-NO": "norsk bokmål","nl-NL": "Nederlands","pl-PL": "polski","pt-BR": "português (Brasil)","pt-PT": "português (Portugal)","ro-RO": "Română","ru-RU": "русский","sk-SK": "slovenčina","sv-SE": "svenska","th-TH": "ไทย","tr-TR": "Türkçe","zh-CN": "中文(简体)","zh-TW": "中文 (繁體)"}},"stream.video.resolution": {label: t("target-resolution"),default: "auto",options: {auto: t("default"),"720p": "720p","1080p": "1080p","1080p-hq": "1080p (HQ)"},suggest: {lowest: "720p",highest: "1080p-hq"}},"stream.video.codecProfile": {label: t("visual-quality"),default: "default",options: getSupportedCodecProfiles(),ready: (setting) => {let options = setting.options, keys = Object.keys(options);if (keys.length <= 1) setting.unsupported = !0, setting.unsupportedNote = "⚠️ " + t("browser-unsupported-feature");setting.suggest = {lowest: keys.length === 1 ? keys[0] : keys[1],highest: keys[keys.length - 1]};}},"server.ipv6.prefer": {label: t("prefer-ipv6-server"),default: !1},"screenshot.applyFilters": {requiredVariants: "full",label: t("screenshot-apply-filters"),default: !1},"ui.splashVideo.skip": {label: t("skip-splash-video"),default: !1},"ui.systemMenu.hideHandle": {label: "⣿ " + t("hide-system-menu-icon"),default: !1},"ui.imageQuality": {requiredVariants: "full",label: t("image-quality"),default: 90,min: 10,max: 90,params: {steps: 10,exactTicks: 20,hideSlider: !0,customTextValue(value, min, max) {if (value === 90) return t("default");return value + "%";}}},"ui.theme": {label: t("theme"),default: "default",options: {default: t("default"),"dark-oled": t("oled")}},"stream.video.combineAudio": {requiredVariants: "full",label: t("combine-audio-video-streams"),default: !1,experimental: !0,note: t("combine-audio-video-streams-summary")},"touchController.mode": {requiredVariants: "full",label: t("availability"),default: "all",options: {default: t("default"),off: t("off"),all: t("all-games")},unsupported: !STATES.userAgent.capabilities.touch,unsupportedValue: "default"},"touchController.autoOff": {requiredVariants: "full",label: t("tc-auto-off"),default: !1,unsupported: !STATES.userAgent.capabilities.touch},"touchController.opacity.default": {requiredVariants: "full",label: t("default-opacity"),default: 100,min: 10,max: 100,params: {steps: 10,suffix: "%",ticks: 10,hideSlider: !0},unsupported: !STATES.userAgent.capabilities.touch},"touchController.style.standard": {requiredVariants: "full",label: t("tc-standard-layout-style"),default: "default",options: {default: t("default"),white: t("tc-all-white"),muted: t("tc-muted-colors")},unsupported: !STATES.userAgent.capabilities.touch},"touchController.style.custom": {requiredVariants: "full",label: t("tc-custom-layout-style"),default: "default",options: {default: t("default"),muted: t("tc-muted-colors")},unsupported: !STATES.userAgent.capabilities.touch},"ui.streamMenu.simplify": {label: t("simplify-stream-menu"),default: !1},"mkb.cursor.hideIdle": {requiredVariants: "full",label: t("hide-idle-cursor"),default: !1},"ui.feedbackDialog.disabled": {requiredVariants: "full",label: t("disable-post-stream-feedback-dialog"),default: !1},"stream.video.maxBitrate": {requiredVariants: "full",label: t("bitrate-video-maximum"),note: "⚠️ " + t("unexpected-behavior"),default: 0,min: 102400,max: 15360000,transformValue: {get(value) {return value === 0 ? this.max : value;},set(value) {return value === this.max ? 0 : value;}},params: {steps: 102400,exactTicks: 5120000,customTextValue: (value, min, max) => {if (value = parseInt(value), value === max) return t("unlimited");else return (value / 1024000).toFixed(1) + " Mb/s";}},suggest: {highest: 0}},"gameBar.position": {requiredVariants: "full",label: t("position"),default: "bottom-left",options: {off: t("off"),"bottom-left": t("bottom-left"),"bottom-right": t("bottom-right")}},"ui.controllerStatus.show": {label: t("show-controller-connection-status"),default: !0},"mkb.enabled": {requiredVariants: "full",label: t("enable-mkb"),default: !1,unsupported: !STATES.userAgent.capabilities.mkb || !STATES.browser.capabilities.mkb,ready: (setting) => {let note, url;if (setting.unsupported) note = t("browser-unsupported-feature"), url = "https://github.com/redphx/better-xcloud/issues/206#issuecomment-1920475657";else note = t("mkb-disclaimer"), url = "https://better-xcloud.github.io/mouse-and-keyboard/#disclaimer";setting.unsupportedNote = () => CE("a", {href: url,target: "_blank"}, "⚠️ " + note);}},"nativeMkb.mode": {requiredVariants: "full",label: t("native-mkb"),default: "default",options: {default: t("default"),off: t("off"),on: t("on")},ready: (setting) => {if (STATES.browser.capabilities.emulatedNativeMkb) ;else if (UserAgent.isMobile()) setting.unsupported = !0, setting.unsupportedValue = "off", delete setting.options["default"], delete setting.options["on"];else delete setting.options["on"];}},"nativeMkb.forcedGames": {label: t("force-native-mkb-games"),default: [],unsupported: !AppInterface && UserAgent.isMobile(),ready: (setting) => {if (!setting.unsupported) setting.multipleOptions = GhPagesUtils.getNativeMkbCustomList(!0), BxEventBus.Script.once("list.forcedNativeMkb.updated", (payload) => {setting.multipleOptions = payload.data.data;});},params: {size: 6}},"ui.reduceAnimations": {label: t("reduce-animations"),default: !1},"loadingScreen.gameArt.show": {requiredVariants: "full",label: t("show-game-art"),default: !0},"loadingScreen.waitTime.show": {label: t("show-wait-time"),default: !0},"loadingScreen.rocket": {label: t("rocket-animation"),default: "show",options: {show: t("rocket-always-show"),"hide-queue": t("rocket-hide-queue"),hide: t("rocket-always-hide")}},"ui.controllerFriendly": {label: t("controller-friendly-ui"),default: BX_FLAGS.DeviceInfo.deviceType !== "unknown"},"ui.layout": {requiredVariants: "full",label: t("layout"),default: "default",options: {default: t("default"),normal: t("normal"),tv: t("smart-tv")}},"ui.hideScrollbar": {label: t("hide-scrollbar"),default: !1},"ui.hideSections": {requiredVariants: "full",label: t("hide-sections"),default: [],multipleOptions: {news: t("section-news"),friends: t("section-play-with-friends"),"native-mkb": t("section-native-mkb"),touch: t("section-touch"),"most-popular": t("section-most-popular"),"recently-added": t("section-recently-added"),"leaving-soon": t("section-leaving-soon"),genres: t("section-genres"),"all-games": t("section-all-games")},params: {size: 0}},"ui.gameCard.waitTime.show": {requiredVariants: "full",label: t("show-wait-time-in-game-card"),default: !0},"block.tracking": {label: t("disable-xcloud-analytics"),default: !1},"block.features": {requiredVariants: "full",label: t("disable-features"),default: [],multipleOptions: {chat: t("chat"),friends: t("friends-followers"),byog: t("stream-your-own-game"),"notifications-invites": t("notifications") + ": " + t("invites"),"notifications-achievements": t("notifications") + ": " + t("achievements")}},"userAgent.profile": {label: t("user-agent-profile"),note: "⚠️ " + t("unexpected-behavior"),default: BX_FLAGS.DeviceInfo.deviceType === "android-tv" || BX_FLAGS.DeviceInfo.deviceType === "webos" ? "vr-oculus" : "default",options: {default: t("default"),"windows-edge": "Edge + Windows","macos-safari": "Safari + macOS","vr-oculus": "Android TV","smarttv-generic": "Smart TV","smarttv-tizen": "Samsung Smart TV",custom: t("custom")}},"audio.mic.onPlaying": {label: t("enable-mic-on-startup"),default: !1},"audio.volume.booster.enabled": {requiredVariants: "full",label: t("enable-volume-control"),default: !1},"xhome.enabled": {requiredVariants: "full",label: t("enable-remote-play-feature"),labelIcon: BxIcon.REMOTE_PLAY,default: !1},"xhome.video.resolution": {requiredVariants: "full",default: "1080p",options: {"720p": "720p","1080p": "1080p","1080p-hq": "1080p (HQ)"}},"game.fortnite.forceConsole": {requiredVariants: "full",label: "🎮 " + t("fortnite-force-console-version"),default: !1,note: t("fortnite-allow-stw-mode")}};constructor() {super("BetterXcloud", GlobalSettingsStorage.DEFINITIONS);}}
class BaseLocalTable {tableName;constructor(tableName) {this.tableName = tableName;}async prepareTable(type = "readonly") {return (await LocalDb.getInstance().open()).transaction(this.tableName, type).objectStore(this.tableName);}call(method) {return new Promise((resolve) => {let request = method.call(null, ...Array.from(arguments).slice(1));request.onsuccess = (e) => {resolve(e.target.result);};});}async count() {let table = await this.prepareTable();return this.call(table.count.bind(table));}async add(data) {let table = await this.prepareTable("readwrite");return this.call(table.add.bind(table), ...arguments);}async put(data) {let table = await this.prepareTable("readwrite");return this.call(table.put.bind(table), ...arguments);}async delete(id) {let table = await this.prepareTable("readwrite");return this.call(table.delete.bind(table), ...arguments);}async get(id) {let table = await this.prepareTable();return this.call(table.get.bind(table), ...arguments);}async getAll() {let table = await this.prepareTable(), all = await this.call(table.getAll.bind(table), ...arguments), results = {};return all.forEach((item2) => {results[item2.id] = item2;}), results;}}
class BasePresetsTable extends BaseLocalTable {async newPreset(name, data) {let newRecord = { name, data };return await this.add(newRecord);}async updatePreset(preset) {return await this.put(preset);}async deletePreset(id) {return this.delete(id);}async getPreset(id) {if (id === 0) return null;if (id < 0) return this.DEFAULT_PRESETS[id];let preset = await this.get(id);if (!preset) preset = this.DEFAULT_PRESETS[this.DEFAULT_PRESET_ID];return preset;}async getPresets() {let all = deepClone(this.DEFAULT_PRESETS), presets = {default: Object.keys(this.DEFAULT_PRESETS).map((key) => parseInt(key)),custom: [],data: {}};if (await this.count() > 0) {let items = await this.getAll(), id;for (id in items) {let item2 = items[id];presets.custom.push(item2.id), all[item2.id] = item2;}}return presets.data = all, presets;}async getPresetsData() {let presetsData = {};for (let id in this.DEFAULT_PRESETS) {let preset = this.DEFAULT_PRESETS[id];presetsData[id] = deepClone(preset.data);}if (await this.count() > 0) {let items = await this.getAll(), id;for (id in items) {let item2 = items[id];presetsData[item2.id] = item2.data;}}return presetsData;}}
class KeyboardShortcutsTable extends BasePresetsTable {static instance;static getInstance = () => KeyboardShortcutsTable.instance ?? (KeyboardShortcutsTable.instance = new KeyboardShortcutsTable);LOG_TAG = "KeyboardShortcutsTable";TABLE_PRESETS = LocalDb.TABLE_KEYBOARD_SHORTCUTS;DEFAULT_PRESETS = {[-1]: {id: -1,name: t("standard"),data: {mapping: {"mkb.toggle": {code: "F8"},"stream.screenshot.capture": {code: "Slash"}}}}};BLANK_PRESET_DATA = {mapping: {}};DEFAULT_PRESET_ID = -1;constructor() {super(LocalDb.TABLE_KEYBOARD_SHORTCUTS);BxLogger.info(this.LOG_TAG, "constructor()");}}
@@ -269,7 +269,7 @@ class KeyBindingDialog {static instance;static getInstance = () => KeyBindingDia
class MkbMappingManagerDialog extends BaseProfileManagerDialog {static instance;static getInstance = () => MkbMappingManagerDialog.instance ?? (MkbMappingManagerDialog.instance = new MkbMappingManagerDialog(t("virtual-controller")));KEYS_PER_BUTTON = 2;BUTTONS_ORDER = [16,12,13,14,15,0,1,2,3,4,5,6,7,8,9,10,100,101,102,103,11,200,201,202,203];allKeyElements = [];$mouseMapTo;$mouseSensitivityX;$mouseSensitivityY;$mouseDeadzone;$unbindNote;constructor(title) {super(title, MkbMappingPresetsTable.getInstance());this.render();}onBindingKey = (e) => {if (e.target.disabled) return;if (e.button !== 0) return;};parseDataset($btn) {let dataset = $btn.dataset;return {keySlot: parseInt(dataset.keySlot),buttonIndex: parseInt(dataset.buttonIndex)};}onKeyChanged = (e) => {let $current = e.target, keyInfo = $current.keyInfo;if (keyInfo) {for (let $elm of this.allKeyElements)if ($elm !== $current && $elm.keyInfo?.code === keyInfo.code) $elm.unbindKey(!0);}this.savePreset();};render() {let $rows = CE("div", !1, this.$unbindNote = CE("i", { class: "bx-mkb-note" }, t("right-click-to-unbind")));for (let buttonIndex of this.BUTTONS_ORDER) {let [buttonName, buttonPrompt] = GamepadKeyName[buttonIndex], $elm, $fragment = document.createDocumentFragment();for (let i = 0;i < this.KEYS_PER_BUTTON; i++)$elm = BxKeyBindingButton.create({title: buttonPrompt,isPrompt: !0,allowedFlags: [1, 4, 8],onChanged: this.onKeyChanged}), $elm.dataset.buttonIndex = buttonIndex.toString(), $elm.dataset.keySlot = i.toString(), $elm.addEventListener("mouseup", this.onBindingKey), $fragment.appendChild($elm), this.allKeyElements.push($elm);let $keyRow = CE("div", {class: "bx-mkb-key-row",_nearby: { orientation: "horizontal" }}, CE("label", { title: buttonName }, buttonPrompt), $fragment);$rows.appendChild($keyRow);}let savePreset = () => this.savePreset(), $extraSettings = CE("div", !1, createSettingRow(t("map-mouse-to"), this.$mouseMapTo = BxSelectElement.create(CE("select", { _on: { input: savePreset } }, CE("option", { value: 2 }, t("right-stick")), CE("option", { value: 1 }, t("left-stick")), CE("option", { value: 0 }, t("off"))))), createSettingRow(t("horizontal-sensitivity"), this.$mouseSensitivityX = BxNumberStepper.create("hor_sensitivity", 0, 1, 300, {suffix: "%",exactTicks: 50}, savePreset)), createSettingRow(t("vertical-sensitivity"), this.$mouseSensitivityY = BxNumberStepper.create("ver_sensitivity", 0, 1, 300, {suffix: "%",exactTicks: 50}, savePreset)), createSettingRow(t("deadzone-counterweight"), this.$mouseDeadzone = BxNumberStepper.create("deadzone_counterweight", 0, 1, 50, {suffix: "%",exactTicks: 10}, savePreset)));this.$content = CE("div", !1, $rows, $extraSettings);}switchPreset(id) {let preset = this.allPresets.data[id];if (!preset) {this.currentPresetId = 0;return;}let presetData = preset.data;this.currentPresetId = id;let isDefaultPreset = id <= 0;this.updateButtonStates(), this.$unbindNote.classList.toggle("bx-gone", isDefaultPreset);for (let $elm of this.allKeyElements) {let { buttonIndex, keySlot } = this.parseDataset($elm), buttonKeys = presetData.mapping[buttonIndex];if (buttonKeys && buttonKeys[keySlot]) $elm.bindKey({code: buttonKeys[keySlot]}, !0);else $elm.unbindKey(!0);$elm.disabled = isDefaultPreset;}let mouse = presetData.mouse;this.$mouseMapTo.value = mouse.mapTo.toString(), this.$mouseSensitivityX.value = mouse.sensitivityX.toString(), this.$mouseSensitivityY.value = mouse.sensitivityY.toString(), this.$mouseDeadzone.value = mouse.deadzoneCounterweight.toString(), this.$mouseMapTo.disabled = isDefaultPreset, this.$mouseSensitivityX.dataset.disabled = isDefaultPreset.toString(), this.$mouseSensitivityY.dataset.disabled = isDefaultPreset.toString(), this.$mouseDeadzone.dataset.disabled = isDefaultPreset.toString();}savePreset() {let presetData = deepClone(this.presetsDb.BLANK_PRESET_DATA);for (let $elm of this.allKeyElements) {let { buttonIndex, keySlot } = this.parseDataset($elm), mapping = presetData.mapping;if (!mapping[buttonIndex]) mapping[buttonIndex] = [];if (!$elm.keyInfo) delete mapping[buttonIndex][keySlot];else mapping[buttonIndex][keySlot] = $elm.keyInfo.code;}let mouse = presetData.mouse;mouse.mapTo = parseInt(this.$mouseMapTo.value), mouse.sensitivityX = parseInt(this.$mouseSensitivityX.value), mouse.sensitivityY = parseInt(this.$mouseSensitivityY.value), mouse.deadzoneCounterweight = parseInt(this.$mouseDeadzone.value);let oldPreset = this.allPresets.data[this.currentPresetId], newPreset = {id: this.currentPresetId,name: oldPreset.name,data: presetData};this.presetsDb.updatePreset(newPreset), this.allPresets.data[this.currentPresetId] = newPreset;}onBeforeUnmount() {StreamSettings.refreshMkbSettings(), super.onBeforeUnmount();}}
class KeyboardShortcutsManagerDialog extends BaseProfileManagerDialog {static instance;static getInstance = () => KeyboardShortcutsManagerDialog.instance ?? (KeyboardShortcutsManagerDialog.instance = new KeyboardShortcutsManagerDialog(t("keyboard-shortcuts")));$content;$unbindNote;allKeyElements = [];constructor(title) {super(title, KeyboardShortcutsTable.getInstance());let $rows = CE("div", { class: "bx-keyboard-shortcuts-manager-container" });for (let groupLabel in SHORTCUT_ACTIONS) {let items = SHORTCUT_ACTIONS[groupLabel];if (!items) continue;let $fieldSet = CE("fieldset", !1, CE("legend", !1, groupLabel));for (let action in items) {let crumbs = items[action];if (!crumbs) continue;let label = crumbs.join(" ❯ "), $btn = BxKeyBindingButton.create({title: label,isPrompt: !1,onChanged: this.onKeyChanged,allowedFlags: [1, 2]});$btn.classList.add("bx-full-width"), $btn.dataset.action = action, this.allKeyElements.push($btn);let $row = createSettingRow(label, CE("div", { class: "bx-binding-button-wrapper" }, $btn));$fieldSet.appendChild($row);}if ($fieldSet.childElementCount > 1) $rows.appendChild($fieldSet);}this.$content = CE("div", !1, this.$unbindNote = CE("i", { class: "bx-mkb-note" }, t("right-click-to-unbind")), $rows);}onKeyChanged = (e) => {let $current = e.target, keyInfo = $current.keyInfo;if (keyInfo) for (let $elm of this.allKeyElements) {if ($elm === $current) continue;if ($elm.keyInfo?.code === keyInfo.code && $elm.keyInfo?.modifiers === keyInfo.modifiers) $elm.unbindKey(!0);}this.savePreset();};parseDataset($btn) {return {action: $btn.dataset.action};}switchPreset(id) {let preset = this.allPresets.data[id];if (!preset) {this.currentPresetId = 0;return;}let presetData = preset.data;this.currentPresetId = id;let isDefaultPreset = id <= 0;this.updateButtonStates(), this.$unbindNote.classList.toggle("bx-gone", isDefaultPreset);for (let $elm of this.allKeyElements) {let { action } = this.parseDataset($elm), keyInfo = presetData.mapping[action];if (keyInfo) $elm.bindKey(keyInfo, !0);else $elm.unbindKey(!0);$elm.disabled = isDefaultPreset;}}savePreset() {let presetData = deepClone(this.presetsDb.BLANK_PRESET_DATA);for (let $elm of this.allKeyElements) {let { action } = this.parseDataset($elm), mapping = presetData.mapping;if ($elm.keyInfo) mapping[action] = $elm.keyInfo;}let oldPreset = this.allPresets.data[this.currentPresetId], newPreset = {id: this.currentPresetId,name: oldPreset.name,data: presetData};this.presetsDb.updatePreset(newPreset), this.allPresets.data[this.currentPresetId] = newPreset;}onBeforeUnmount() {StreamSettings.refreshKeyboardShortcuts(), super.onBeforeUnmount();}}
class MkbExtraSettings extends HTMLElement {$mappingPresets;$shortcutsPresets;updateLayout;saveMkbSettings;saveShortcutsSettings;static renderSettings() {let $container = document.createDocumentFragment();$container.updateLayout = MkbExtraSettings.updateLayout.bind($container), $container.saveMkbSettings = MkbExtraSettings.saveMkbSettings.bind($container), $container.saveShortcutsSettings = MkbExtraSettings.saveShortcutsSettings.bind($container);let $mappingPresets = BxSelectElement.create(CE("select", {autocomplete: "off",_on: {input: $container.saveMkbSettings}})), $shortcutsPresets = BxSelectElement.create(CE("select", {autocomplete: "off",_on: {input: $container.saveShortcutsSettings}}));return $container.append(...getGlobalPref("mkb.enabled") ? [createSettingRow(t("virtual-controller"), CE("div", {class: "bx-preset-row",_nearby: {orientation: "horizontal"}}, $mappingPresets, createButton({title: t("manage"),icon: BxIcon.MANAGE,style: 64 | 1 | 512,onClick: () => MkbMappingManagerDialog.getInstance().show({id: parseInt($container.$mappingPresets.value)})})), {multiLines: !0,onContextMenu: this.boundOnContextMenu,pref: "mkb.p1.preset.mappingId"}),createSettingRow(t("virtual-controller-slot"), this.settingsManager.getElement("mkb.p1.slot"), {onContextMenu: this.boundOnContextMenu,pref: "mkb.p1.slot"})] : [], createSettingRow(t("in-game-keyboard-shortcuts"), CE("div", {class: "bx-preset-row",_nearby: {orientation: "horizontal"}}, $shortcutsPresets, createButton({title: t("manage"),icon: BxIcon.MANAGE,style: 64 | 1 | 512,onClick: () => KeyboardShortcutsManagerDialog.getInstance().show({id: parseInt($container.$shortcutsPresets.value)})})), {multiLines: !0,onContextMenu: this.boundOnContextMenu,pref: "keyboardShortcuts.preset.inGameId"})), $container.$mappingPresets = $mappingPresets, $container.$shortcutsPresets = $shortcutsPresets, this.settingsManager.setElement("keyboardShortcuts.preset.inGameId", $shortcutsPresets), this.settingsManager.setElement("mkb.p1.preset.mappingId", $mappingPresets), $container.updateLayout(), this.onMountedCallbacks.push(() => {$container.updateLayout();}), $container;}static async updateLayout() {let mappingPresets = await MkbMappingPresetsTable.getInstance().getPresets();renderPresetsList(this.$mappingPresets, mappingPresets, getStreamPref("mkb.p1.preset.mappingId"));let shortcutsPresets = await KeyboardShortcutsTable.getInstance().getPresets();renderPresetsList(this.$shortcutsPresets, shortcutsPresets, getStreamPref("keyboardShortcuts.preset.inGameId"), { addOffValue: !0 });}static async saveMkbSettings() {let presetId = parseInt(this.$mappingPresets.value);setStreamPref("mkb.p1.preset.mappingId", presetId, "ui");}static async saveShortcutsSettings() {let presetId = parseInt(this.$shortcutsPresets.value);setStreamPref("keyboardShortcuts.preset.inGameId", presetId, "ui");}}
-class SettingsDialog extends NavigationDialog {static instance;static getInstance = () => SettingsDialog.instance ?? (SettingsDialog.instance = new SettingsDialog);LOG_TAG = "SettingsNavigationDialog";$container;$tabs;$tabContents;$btnReload;$btnGlobalReload;$noteGlobalReload;$btnSuggestion;$streamSettingsSelection;renderFullSettings;boundOnContextMenu;suggestedSettings = {recommended: {},default: {},lowest: {},highest: {}};settingLabels = {};settingsManager;TAB_GLOBAL_ITEMS = [{group: "general",label: t("better-xcloud"),helpUrl: "https://better-xcloud.github.io/features/",items: [($parent) => {let PREF_LATEST_VERSION = getGlobalPref("version.latest"), topButtons = [];if (!SCRIPT_VERSION.includes("beta") && PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {let opts = {label: "🌟 " + t("new-version-available", { version: PREF_LATEST_VERSION }),style: 1 | 64 | 128};if (AppInterface && AppInterface.updateLatestScript) opts.onClick = (e) => AppInterface.updateLatestScript();else opts.url = "https://github.com/redphx/better-xcloud/releases/latest";topButtons.push(createButton(opts));}if (AppInterface) topButtons.push(createButton({label: t("app-settings"),icon: BxIcon.STREAM_SETTINGS,style: 128 | 64,onClick: (e) => {AppInterface.openAppSettings && AppInterface.openAppSettings(), this.hide();}}));else if (UserAgent.getDefault().toLowerCase().includes("android")) topButtons.push(createButton({label: "🔥 " + t("install-android"),style: 128 | 64,url: "https://better-xcloud.github.io/android"}));this.$btnGlobalReload = createButton({label: t("settings-reload"),classes: ["bx-settings-reload-button", "bx-gone"],style: 64 | 128,onClick: (e) => {this.reloadPage();}}), topButtons.push(this.$btnGlobalReload), this.$noteGlobalReload = CE("span", {class: "bx-settings-reload-note"}, t("settings-reload-note")), topButtons.push(this.$noteGlobalReload), this.$btnSuggestion = CE("div", {class: "bx-suggest-toggler bx-focusable",tabindex: 0}, CE("label", !1, t("suggest-settings")), CE("span", !1, "❯")), this.$btnSuggestion.addEventListener("click", SuggestionsSetting.renderSuggestions.bind(this)), topButtons.push(this.$btnSuggestion);let $div = CE("div", {class: "bx-top-buttons",_nearby: {orientation: "vertical"}}, ...topButtons);$parent.appendChild($div);},{pref: "bx.locale",multiLines: !0},"server.bypassRestriction","ui.controllerFriendly","xhome.enabled"]}, {group: "server",label: t("server"),items: [{pref: "server.region",multiLines: !0},{pref: "stream.locale",multiLines: !0},"server.ipv6.prefer"]}, {group: "stream",label: t("stream"),items: ["stream.video.resolution","stream.video.codecProfile","stream.video.maxBitrate","audio.volume.booster.enabled","screenshot.applyFilters","audio.mic.onPlaying","game.fortnite.forceConsole","stream.video.combineAudio"]}, {requiredVariants: "full",group: "mkb",label: t("mouse-and-keyboard"),items: ["nativeMkb.mode",{pref: "nativeMkb.forcedGames",multiLines: !0,note: CE("a", { href: "https://github.com/redphx/better-xcloud/discussions/574", target: "_blank" }, t("unofficial-game-list"))},"mkb.enabled","mkb.cursor.hideIdle"],...!STATES.browser.capabilities.emulatedNativeMkb && (!STATES.userAgent.capabilities.mkb || !STATES.browser.capabilities.mkb) ? {unsupported: !0,unsupportedNote: CE("a", {href: "https://github.com/redphx/better-xcloud/issues/206#issuecomment-1920475657",target: "_blank"}, "⚠️ " + t("browser-unsupported-feature"))} : {}}, {requiredVariants: "full",group: "touch-control",label: t("touch-controller"),items: [{pref: "touchController.mode",note: CE("a", { href: "https://github.com/redphx/better-xcloud/discussions/241", target: "_blank" }, t("unofficial-game-list"))},"touchController.autoOff","touchController.opacity.default","touchController.style.standard","touchController.style.custom"],...!STATES.userAgent.capabilities.touch ? {unsupported: !0,unsupportedNote: "⚠️ " + t("device-unsupported-touch")} : {}}, {group: "ui",label: t("ui"),items: ["ui.layout","ui.imageQuality","ui.gameCard.waitTime.show","ui.controllerStatus.show","ui.streamMenu.simplify","ui.splashVideo.skip",!AppInterface && "ui.hideScrollbar","ui.systemMenu.hideHandle","ui.feedbackDialog.disabled","ui.reduceAnimations",{pref: "ui.hideSections",multiLines: !0},{pref: "block.features",multiLines: !0}]}, {requiredVariants: "full",group: "game-bar",label: t("game-bar"),items: ["gameBar.position"]}, {group: "loading-screen",label: t("loading-screen"),items: ["loadingScreen.gameArt.show","loadingScreen.waitTime.show","loadingScreen.rocket"]}, {group: "other",label: t("other"),items: ["block.tracking"]}, {group: "advanced",label: t("advanced"),items: [{pref: "userAgent.profile",multiLines: !0,onCreated: (setting, $control) => {let defaultUserAgent = window.navigator.orgUserAgent || window.navigator.userAgent, $inpCustomUserAgent = CE("input", {type: "text",placeholder: defaultUserAgent,autocomplete: "off",class: "bx-settings-custom-user-agent",tabindex: 0});$inpCustomUserAgent.addEventListener("input", (e) => {let profile = $control.value, custom = e.target.value.trim();UserAgent.updateStorage(profile, custom), this.onGlobalSettingChanged(e);}), $control.insertAdjacentElement("afterend", $inpCustomUserAgent), setNearby($inpCustomUserAgent.parentElement, {orientation: "vertical"});}}]}, {group: "footer",items: [($parent) => {try {let appVersion = document.querySelector("meta[name=gamepass-app-version]").content, appDate = new Date(document.querySelector("meta[name=gamepass-app-date]").content).toISOString().substring(0, 10);$parent.appendChild(CE("div", {class: "bx-settings-app-version"}, `xCloud website version ${appVersion} (${appDate})`));} catch (e) {}},($parent) => {$parent.appendChild(CE("a", {class: "bx-donation-link",href: "https://ko-fi.com/redphx",target: "_blank",tabindex: 0}, `❤️ ${t("support-better-xcloud")}`));},($parent) => {$parent.appendChild(createButton({label: t("clear-data"),style: 8 | 128 | 64,onClick: (e) => {if (confirm(t("clear-data-confirm"))) clearAllData();}}));},($parent) => {$parent.appendChild(CE("div", { class: "bx-debug-info" }, createButton({label: "Debug info",style: 8 | 128 | 64,onClick: (e) => {let $button = e.target.closest("button");if (!$button) return;let $pre = $button.nextElementSibling;if (!$pre) {let debugInfo = deepClone(BX_FLAGS.DeviceInfo);debugInfo.settings = JSON.parse(window.localStorage.getItem("BetterXcloud") || "{}"), $pre = CE("pre", {class: "bx-focusable bx-gone",tabindex: 0,_on: {click: async (e2) => {await copyToClipboard(e2.target.innerText);}}}, "```\n" + JSON.stringify(debugInfo, null, " ") + "\n```"), $button.insertAdjacentElement("afterend", $pre);}$pre.classList.toggle("bx-gone"), $pre.scrollIntoView();}})));}]}];TAB_DISPLAY_ITEMS = [{requiredVariants: "full",group: "audio",label: t("audio"),helpUrl: "https://better-xcloud.github.io/ingame-features/#audio",items: [{pref: "audio.volume",params: {disabled: !getGlobalPref("audio.volume.booster.enabled")},onCreated: (setting, $elm) => {let $range = $elm.querySelector("input[type=range");BxEventBus.Stream.on("setting.changed", (payload) => {let { settingKey } = payload;if (settingKey === "audio.volume") $range.value = getStreamPref(settingKey).toString(), BxEvent.dispatch($range, "input", { ignoreOnChange: !0 });});}}]}, {group: "video",label: t("video"),helpUrl: "https://better-xcloud.github.io/ingame-features/#video",items: ["video.player.type","video.maxFps","video.player.powerPreference","video.processing","video.ratio","video.position","video.processing.sharpness","video.saturation","video.contrast","video.brightness"]}];TAB_CONTROLLER_ITEMS = [{group: "controller",label: t("controller"),helpUrl: "https://better-xcloud.github.io/ingame-features/#controller",items: ["localCoOp.enabled","controller.pollingRate",($parent) => {$parent.appendChild(ControllerExtraSettings.renderSettings.apply(this));}]},STATES.userAgent.capabilities.touch && {group: "touch-control",label: t("touch-controller"),items: [{label: t("layout"),content: CE("select", {disabled: !0}, CE("option", !1, t("default"))),onCreated: (setting, $elm) => {$elm.addEventListener("input", (e) => {TouchController.applyCustomLayout($elm.value, 1000);}), window.addEventListener(BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED, (e) => {let customLayouts = TouchController.getCustomLayouts();while ($elm.firstChild)$elm.removeChild($elm.firstChild);if ($elm.disabled = !customLayouts, !customLayouts) {$elm.appendChild(CE("option", { value: "" }, t("default"))), $elm.value = "", $elm.dispatchEvent(new Event("input"));return;}let $fragment = document.createDocumentFragment();for (let key in customLayouts.layouts) {let layout = customLayouts.layouts[key], name;if (layout.author) name = `${layout.name} (${layout.author})`;else name = layout.name;let $option = CE("option", { value: key }, name);$fragment.appendChild($option);}$elm.appendChild($fragment), $elm.value = customLayouts.default_layout;});}}]},STATES.browser.capabilities.deviceVibration && {group: "device",label: t("device"),items: [{pref: "deviceVibration.mode",multiLines: !0,unsupported: !STATES.browser.capabilities.deviceVibration}, {pref: "deviceVibration.intensity",unsupported: !STATES.browser.capabilities.deviceVibration}]}];TAB_MKB_ITEMS = [{requiredVariants: "full",group: "mkb",label: t("mouse-and-keyboard"),helpUrl: "https://better-xcloud.github.io/mouse-and-keyboard/",items: [($parent) => {$parent.appendChild(MkbExtraSettings.renderSettings.apply(this));}]},NativeMkbHandler.isAllowed() && {requiredVariants: "full",group: "native-mkb",label: t("native-mkb"),items: ["nativeMkb.scroll.sensitivityY","nativeMkb.scroll.sensitivityX"]}];TAB_STATS_ITEMS = [{group: "stats",label: t("stream-stats"),helpUrl: "https://better-xcloud.github.io/stream-stats/",items: ["stats.showWhenPlaying","stats.quickGlance.enabled","stats.items","stats.position","stats.textSize","stats.opacity.all","stats.opacity.background","stats.colors"]}];SETTINGS_UI = {global: {group: "global",icon: BxIcon.HOME,items: this.TAB_GLOBAL_ITEMS},stream: {group: "stream",icon: BxIcon.DISPLAY,items: this.TAB_DISPLAY_ITEMS},controller: {group: "controller",icon: BxIcon.CONTROLLER,items: this.TAB_CONTROLLER_ITEMS,requiredVariants: "full"},mkb: {group: "mkb",icon: BxIcon.NATIVE_MKB,items: this.TAB_MKB_ITEMS,requiredVariants: "full"},stats: {group: "stats",icon: BxIcon.STREAM_STATS,items: this.TAB_STATS_ITEMS}};constructor() {super();BxLogger.info(this.LOG_TAG, "constructor()"), this.boundOnContextMenu = this.onContextMenu.bind(this), this.settingsManager = SettingsManager.getInstance(), this.renderFullSettings = STATES.supportedRegion && STATES.isSignedIn, this.setupDialog(), this.onMountedCallbacks.push(() => {if (onChangeVideoPlayerType(), STATES.userAgent.capabilities.touch) BxEvent.dispatch(window, BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED);let $selectUserAgent = document.querySelector(`#bx_setting_${escapeCssSelector("userAgent.profile")}`);if ($selectUserAgent) $selectUserAgent.disabled = !0, BxEvent.dispatch($selectUserAgent, "input", {}), $selectUserAgent.disabled = !1;}), BxEventBus.Stream.on("gameSettings.switched", ({ id }) => {this.$tabContents.dataset.gameId = id.toString();});}getDialog() {return this;}getContent() {return this.$container;}onMounted() {super.onMounted();}isOverlayVisible() {return !STATES.isPlaying;}reloadPage() {this.$btnGlobalReload.disabled = !0, this.$btnGlobalReload.firstElementChild.textContent = t("settings-reloading"), this.hide(), FullscreenText.getInstance().show(t("settings-reloading")), window.location.reload();}isSupportedVariant(requiredVariants) {if (typeof requiredVariants === "undefined") return !0;return requiredVariants = typeof requiredVariants === "string" ? [requiredVariants] : requiredVariants, requiredVariants.includes(SCRIPT_VARIANT);}onTabClicked = (e) => {let $svg = e.target.closest("svg"), $child, children = Array.from(this.$tabContents.children);for ($child of children)if ($child.dataset.tabGroup === $svg.dataset.group) $child.classList.remove("bx-gone"), calculateSelectBoxes($child);else if ($child.dataset.tabGroup) $child.classList.add("bx-gone");this.$streamSettingsSelection.classList.toggle("bx-gone", $svg.dataset.group === "global");for (let $child2 of Array.from(this.$tabs.children))$child2.classList.remove("bx-active");$svg.classList.add("bx-active");};renderTab(settingTab) {let $svg = createSvgIcon(settingTab.icon);return $svg.dataset.group = settingTab.group, $svg.tabIndex = 0, $svg.addEventListener("click", this.onTabClicked), $svg;}onGlobalSettingChanged = (e) => {PatcherCache.getInstance().clear(), this.$btnReload.classList.add("bx-danger"), this.$noteGlobalReload.classList.add("bx-gone"), this.$btnGlobalReload.classList.remove("bx-gone"), this.$btnGlobalReload.classList.add("bx-danger");};onContextMenu(e) {e.preventDefault();let $elm = e.target;$elm instanceof HTMLElement && this.resetHighlightedSetting($elm);}renderServerSetting(setting) {let selectedValue = getGlobalPref("server.region"), continents = {"america-north": {label: t("continent-north-america")},"america-south": {label: t("continent-south-america")},asia: {label: t("continent-asia")},australia: {label: t("continent-australia")},europe: {label: t("continent-europe")},other: {label: t("other")}}, $control = CE("select", {id: `bx_setting_${escapeCssSelector(setting.pref)}`,tabindex: 0});$control.name = $control.id, $control.addEventListener("input", (e) => {setGlobalPref(setting.pref, e.target.value, "ui"), this.onGlobalSettingChanged(e);}), setting.options = {};for (let regionName in STATES.serverRegions) {let region = STATES.serverRegions[regionName], value = regionName, label = `${region.shortName} - ${regionName}`;if (region.isDefault) {if (label += ` (${t("default")})`, value = "default", selectedValue === regionName) selectedValue = "default";}setting.options[value] = label;let $option = CE("option", { value }, label), continent = continents[region.contintent];if (!continent.children) continent.children = [];continent.children.push($option);}let fragment = document.createDocumentFragment(), key;for (key in continents) {let continent = continents[key];if (!continent.children) continue;fragment.appendChild(CE("optgroup", {label: continent.label}, ...continent.children));}return $control.appendChild(fragment), $control.disabled = Object.keys(STATES.serverRegions).length === 0, $control.value = selectedValue, $control;}renderSettingRow(settingTab, $tabContent, settingTabContent, setting) {if (typeof setting === "string") setting = {pref: setting};let pref = setting.pref, $control;if (setting.content) if (typeof setting.content === "function") $control = setting.content.apply(this);else $control = setting.content;else if (!setting.unsupported) {if (pref === "server.region") $control = this.renderServerSetting(setting);else if (pref === "bx.locale") $control = SettingElement.fromPref(pref, async (e) => {let newLocale = e.target.value;if (getGlobalPref("ui.controllerFriendly")) {let timeoutId = e.target.timeoutId;timeoutId && window.clearTimeout(timeoutId), e.target.timeoutId = window.setTimeout(() => {Translations.refreshLocale(newLocale), Translations.updateTranslations();}, 500);} else Translations.refreshLocale(newLocale), Translations.updateTranslations();this.onGlobalSettingChanged(e);});else if (pref === "userAgent.profile") $control = SettingElement.fromPref("userAgent.profile", (e) => {let value = e.target.value, isCustom = value === "custom", userAgent2 = UserAgent.get(value);UserAgent.updateStorage(value);let $inp = $control.nextElementSibling;$inp.value = userAgent2, $inp.readOnly = !isCustom, $inp.disabled = !isCustom, !e.target.disabled && this.onGlobalSettingChanged(e);});else if ($control = this.settingsManager.getElement(pref, setting.params), settingTab.group === "global") $control.addEventListener("input", this.onGlobalSettingChanged);if ($control instanceof HTMLSelectElement) $control = BxSelectElement.create($control);}let prefDefinition = null;if (pref) prefDefinition = getPrefInfo(pref).definition;if (prefDefinition && !this.isSupportedVariant(prefDefinition.requiredVariants)) return;let label = prefDefinition?.label || setting.label || "", note = prefDefinition?.note || setting.note, unsupportedNote = prefDefinition?.unsupportedNote || setting.unsupportedNote, experimental = prefDefinition?.experimental || setting.experimental;if (typeof note === "function") note = note();if (typeof unsupportedNote === "function") unsupportedNote = unsupportedNote();if (settingTabContent.label && setting.pref) {if (prefDefinition?.suggest) typeof prefDefinition.suggest.lowest !== "undefined" && (this.suggestedSettings.lowest[setting.pref] = prefDefinition.suggest.lowest), typeof prefDefinition.suggest.highest !== "undefined" && (this.suggestedSettings.highest[setting.pref] = prefDefinition.suggest.highest);}if (experimental) if (label = "🧪 " + label, !note) note = t("experimental");else note = `${t("experimental")}: ${note}`;let $note;if (unsupportedNote) $note = CE("div", { class: "bx-settings-dialog-note" }, unsupportedNote);else if (note) $note = CE("div", { class: "bx-settings-dialog-note" }, note);let $row = createSettingRow(label, !prefDefinition?.unsupported && $control, {$note,multiLines: setting.multiLines,icon: prefDefinition?.labelIcon,onContextMenu: this.boundOnContextMenu,pref});if (pref) $row.htmlFor = `bx_setting_${escapeCssSelector(pref)}`;$row.dataset.type = settingTabContent.group, $tabContent.appendChild($row), !prefDefinition?.unsupported && setting.onCreated && setting.onCreated(setting, $control);}renderSettingsSection(settingTab, sections) {let $tabContent = CE("div", {class: "bx-gone",_dataset: {tabGroup: settingTab.group}});for (let section of sections) {if (!section) continue;if (section instanceof HTMLElement) {$tabContent.appendChild(section);continue;}if (!this.isSupportedVariant(section.requiredVariants)) continue;if (!this.renderFullSettings && settingTab.group === "global" && section.group !== "general" && section.group !== "footer") continue;let label = section.label;if (label === t("better-xcloud")) {if (label += " " + SCRIPT_VERSION, SCRIPT_VARIANT === "lite") label += " (Lite)";label = createButton({label,url: "https://github.com/redphx/better-xcloud/releases",style: 4096 | 16 | 64});}if (label) {let $title = CE("h2", {_nearby: {orientation: "horizontal"}}, CE("span", !1, label), section.helpUrl && createButton({icon: BxIcon.QUESTION,style: 8 | 64,url: section.helpUrl,title: t("help")}));$tabContent.appendChild($title);}if (section.unsupportedNote) {let $note = CE("b", { class: "bx-note-unsupported" }, section.unsupportedNote);$tabContent.appendChild($note);}if (section.unsupported) continue;if (section.content) {$tabContent.appendChild(section.content);continue;}section.items = section.items || [];for (let setting of section.items) {if (setting === !1) continue;if (typeof setting === "function") {setting.apply(this, [$tabContent]);continue;}this.renderSettingRow(settingTab, $tabContent, section, setting);}}return $tabContent;}setupDialog() {let $tabs, $tabContents, $container = CE("div", {class: "bx-settings-dialog",_nearby: {orientation: "horizontal"}}, CE("div", {class: "bx-settings-tabs-container",_nearby: {orientation: "vertical",focus: () => {return this.dialogManager.focus($tabs);},loop: (direction) => {if (direction === 1 || direction === 3) return this.focusVisibleTab(direction === 1 ? "last" : "first"), !0;return !1;}}}, $tabs = CE("div", {class: "bx-settings-tabs bx-hide-scroll-bar",_nearby: {focus: () => this.focusActiveTab()}}), CE("div", !1, this.$btnReload = createButton({icon: BxIcon.REFRESH,style: 64 | 32,onClick: (e) => {this.reloadPage();}}), createButton({icon: BxIcon.CLOSE,style: 64 | 32,onClick: (e) => {this.dialogManager.hide();}}))), CE("div", {class: "bx-settings-tab-contents",_nearby: {orientation: "vertical",loop: (direction) => {if (direction === 1 || direction === 3) return this.focusVisibleSetting(direction === 1 ? "last" : "first"), !0;return !1;}}}, this.$streamSettingsSelection = SettingsManager.getInstance().getStreamSettingsSelection(), $tabContents = CE("div", {class: "bx-settings-tab-content",_nearby: {orientation: "vertical",focus: () => this.jumpToSettingGroup("next")}})));this.$container = $container, this.$tabs = $tabs, this.$tabContents = $tabContents, $container.addEventListener("click", (e) => {if (e.target === $container) e.preventDefault(), e.stopPropagation(), this.hide();});let settingTabGroup;for (settingTabGroup in this.SETTINGS_UI) {let settingTab = this.SETTINGS_UI[settingTabGroup];if (!settingTab) continue;if (!this.isSupportedVariant(settingTab.requiredVariants)) continue;if (settingTab.group !== "global" && !this.renderFullSettings) continue;let $svg = this.renderTab(settingTab);$tabs.appendChild($svg);let $tabContent = this.renderSettingsSection.call(this, settingTab, settingTab.items);$tabContents.appendChild($tabContent);}$tabs.firstElementChild.dispatchEvent(new Event("click"));}focusTab(tabId) {let $tab = this.$container.querySelector(`.bx-settings-tabs svg[data-group=${tabId}]`);$tab && $tab.dispatchEvent(new Event("click"));}focusIfNeeded() {this.jumpToSettingGroup("next");}focusActiveTab() {let $currentTab = this.$tabs.querySelector(".bx-active");return $currentTab && $currentTab.focus(), !0;}focusVisibleSetting(type = "first") {let controls = Array.from(this.$tabContents.querySelectorAll("div[data-tab-group]:not(.bx-gone) > *"));if (!controls.length) return !1;if (type === "last") controls.reverse();for (let $control of controls) {if (!($control instanceof HTMLElement)) continue;let $focusable = this.dialogManager.findFocusableElement($control);if ($focusable) {if (this.dialogManager.focus($focusable)) return !0;}}return !1;}focusVisibleTab(type = "first") {let tabs = Array.from(this.$tabs.querySelectorAll("svg:not(.bx-gone)"));if (!tabs.length) return !1;if (type === "last") tabs.reverse();for (let $tab of tabs)if (this.dialogManager.focus($tab)) return !0;return !1;}jumpToSettingGroup(direction) {let $tabContent = this.$tabContents.querySelector("div[data-tab-group]:not(.bx-gone)");if (!$tabContent) return !1;let $header, $focusing = document.activeElement;if (!$focusing || !$tabContent.contains($focusing)) $header = $tabContent.querySelector("h2");else {let $parent = $focusing.closest("[data-tab-group] > *"), siblingProperty = direction === "next" ? "nextSibling" : "previousSibling", $tmp = $parent, times = 0;while (!0) {if (!$tmp) break;if ($tmp.tagName === "H2") {if ($header = $tmp, !$tmp.nextElementSibling?.classList.contains("bx-note-unsupported")) {if (++times, direction === "next" || times >= 2) break;}}$tmp = $tmp[siblingProperty];}}let $target;if ($header) $target = this.dialogManager.findNextTarget($header, 3, !1);if ($target) return this.dialogManager.focus($target);return !1;}resetHighlightedSetting($elm) {let targetGameId = SettingsManager.getInstance().getTargetGameId();if (targetGameId < 0) return;if (!$elm) $elm = document.activeElement instanceof HTMLElement ? document.activeElement : void 0;let $row = $elm?.closest("div[data-tab-group] > .bx-settings-row");if (!$row) return;let pref = $row.prefKey;if (!pref) alert("Pref not found: " + $row.id);if (!isStreamPref(pref)) return;let deleted = STORAGE.Stream.deleteSettingByGame(targetGameId, pref);if (deleted) BxEventBus.Stream.emit("setting.changed", {storageKey: `${"BetterXcloud.Stream"}.${targetGameId}`,settingKey: pref});return deleted;}handleKeyPress(key) {let handled = !0;switch (key) {case "Tab":this.focusActiveTab();break;case "Home":this.focusVisibleSetting("first");break;case "End":this.focusVisibleSetting("last");break;case "PageUp":this.jumpToSettingGroup("previous");break;case "PageDown":this.jumpToSettingGroup("next");break;case "KeyQ":this.resetHighlightedSetting();break;default:handled = !1;break;}return handled;}handleGamepad(button) {let handled = !0;switch (button) {case 1:let $focusing = document.activeElement;if ($focusing && this.$tabs.contains($focusing)) this.hide();else this.focusActiveTab();break;case 4:case 5:this.focusActiveTab();break;case 6:this.jumpToSettingGroup("previous");break;case 7:this.jumpToSettingGroup("next");break;case 2:this.resetHighlightedSetting();break;default:handled = !1;break;}return handled;}}
+class SettingsDialog extends NavigationDialog {static instance;static getInstance = () => SettingsDialog.instance ?? (SettingsDialog.instance = new SettingsDialog);LOG_TAG = "SettingsNavigationDialog";$container;$tabs;$tabContents;$btnReload;$btnGlobalReload;$noteGlobalReload;$btnSuggestion;$streamSettingsSelection;renderFullSettings;boundOnContextMenu;suggestedSettings = {recommended: {},default: {},lowest: {},highest: {}};settingLabels = {};settingsManager;TAB_GLOBAL_ITEMS = [{group: "general",label: t("better-xcloud"),helpUrl: "https://better-xcloud.github.io/features/",items: [($parent) => {let PREF_LATEST_VERSION = getGlobalPref("version.latest"), topButtons = [];if (!SCRIPT_VERSION.includes("beta") && PREF_LATEST_VERSION && PREF_LATEST_VERSION != SCRIPT_VERSION) {let opts = {label: "🌟 " + t("new-version-available", { version: PREF_LATEST_VERSION }),style: 1 | 64 | 128};if (AppInterface && AppInterface.updateLatestScript) opts.onClick = (e) => AppInterface.updateLatestScript();else opts.url = "https://github.com/redphx/better-xcloud/releases/latest";topButtons.push(createButton(opts));}if (AppInterface) topButtons.push(createButton({label: t("app-settings"),icon: BxIcon.STREAM_SETTINGS,style: 128 | 64,onClick: (e) => {AppInterface.openAppSettings && AppInterface.openAppSettings(), this.hide();}}));else if (UserAgent.getDefault().toLowerCase().includes("android")) topButtons.push(createButton({label: "🔥 " + t("install-android"),style: 128 | 64,url: "https://better-xcloud.github.io/android"}));this.$btnGlobalReload = createButton({label: t("settings-reload"),classes: ["bx-settings-reload-button", "bx-gone"],style: 64 | 128,onClick: (e) => {this.reloadPage();}}), topButtons.push(this.$btnGlobalReload), this.$noteGlobalReload = CE("span", {class: "bx-settings-reload-note"}, t("settings-reload-note")), topButtons.push(this.$noteGlobalReload), this.$btnSuggestion = CE("div", {class: "bx-suggest-toggler bx-focusable",tabindex: 0}, CE("label", !1, t("suggest-settings")), CE("span", !1, "❯")), this.$btnSuggestion.addEventListener("click", SuggestionsSetting.renderSuggestions.bind(this)), topButtons.push(this.$btnSuggestion);let $div = CE("div", {class: "bx-top-buttons",_nearby: {orientation: "vertical"}}, ...topButtons);$parent.appendChild($div);},{pref: "bx.locale",multiLines: !0},"server.bypassRestriction","ui.controllerFriendly","xhome.enabled"]}, {group: "server",label: t("server"),items: [{pref: "server.region",multiLines: !0},{pref: "stream.locale",multiLines: !0},"server.ipv6.prefer"]}, {group: "stream",label: t("stream"),items: ["stream.video.resolution","stream.video.codecProfile","stream.video.maxBitrate","audio.volume.booster.enabled","screenshot.applyFilters","audio.mic.onPlaying","game.fortnite.forceConsole","stream.video.combineAudio"]}, {requiredVariants: "full",group: "mkb",label: t("mouse-and-keyboard"),items: ["nativeMkb.mode",{pref: "nativeMkb.forcedGames",multiLines: !0,note: CE("a", { href: "https://github.com/redphx/better-xcloud/discussions/574", target: "_blank" }, t("unofficial-game-list"))},"mkb.enabled","mkb.cursor.hideIdle"],...!STATES.browser.capabilities.emulatedNativeMkb && (!STATES.userAgent.capabilities.mkb || !STATES.browser.capabilities.mkb) ? {unsupported: !0,unsupportedNote: CE("a", {href: "https://github.com/redphx/better-xcloud/issues/206#issuecomment-1920475657",target: "_blank"}, "⚠️ " + t("browser-unsupported-feature"))} : {}}, {requiredVariants: "full",group: "touch-control",label: t("touch-controller"),items: [{pref: "touchController.mode",note: CE("a", { href: "https://github.com/redphx/better-xcloud/discussions/241", target: "_blank" }, t("unofficial-game-list"))},"touchController.autoOff","touchController.opacity.default","touchController.style.standard","touchController.style.custom"],...!STATES.userAgent.capabilities.touch ? {unsupported: !0,unsupportedNote: "⚠️ " + t("device-unsupported-touch")} : {}}, {group: "ui",label: t("ui"),items: ["ui.layout","ui.theme","ui.imageQuality","ui.gameCard.waitTime.show","ui.controllerStatus.show","ui.streamMenu.simplify","ui.splashVideo.skip",!AppInterface && "ui.hideScrollbar","ui.systemMenu.hideHandle","ui.feedbackDialog.disabled","ui.reduceAnimations",{pref: "ui.hideSections",multiLines: !0},{pref: "block.features",multiLines: !0}]}, {requiredVariants: "full",group: "game-bar",label: t("game-bar"),items: ["gameBar.position"]}, {group: "loading-screen",label: t("loading-screen"),items: ["loadingScreen.gameArt.show","loadingScreen.waitTime.show","loadingScreen.rocket"]}, {group: "other",label: t("other"),items: ["block.tracking"]}, {group: "advanced",label: t("advanced"),items: [{pref: "userAgent.profile",multiLines: !0,onCreated: (setting, $control) => {let defaultUserAgent = window.navigator.orgUserAgent || window.navigator.userAgent, $inpCustomUserAgent = CE("input", {type: "text",placeholder: defaultUserAgent,autocomplete: "off",class: "bx-settings-custom-user-agent",tabindex: 0});$inpCustomUserAgent.addEventListener("input", (e) => {let profile = $control.value, custom = e.target.value.trim();UserAgent.updateStorage(profile, custom), this.onGlobalSettingChanged(e);}), $control.insertAdjacentElement("afterend", $inpCustomUserAgent), setNearby($inpCustomUserAgent.parentElement, {orientation: "vertical"});}}]}, {group: "footer",items: [($parent) => {try {let appVersion = document.querySelector("meta[name=gamepass-app-version]").content, appDate = new Date(document.querySelector("meta[name=gamepass-app-date]").content).toISOString().substring(0, 10);$parent.appendChild(CE("div", {class: "bx-settings-app-version"}, `xCloud website version ${appVersion} (${appDate})`));} catch (e) {}},($parent) => {$parent.appendChild(CE("a", {class: "bx-donation-link",href: "https://ko-fi.com/redphx",target: "_blank",tabindex: 0}, `❤️ ${t("support-better-xcloud")}`));},($parent) => {$parent.appendChild(createButton({label: t("clear-data"),style: 8 | 128 | 64,onClick: (e) => {if (confirm(t("clear-data-confirm"))) clearAllData();}}));},($parent) => {$parent.appendChild(CE("div", { class: "bx-debug-info" }, createButton({label: "Debug info",style: 8 | 128 | 64,onClick: (e) => {let $button = e.target.closest("button");if (!$button) return;let $pre = $button.nextElementSibling;if (!$pre) {let debugInfo = deepClone(BX_FLAGS.DeviceInfo);debugInfo.settings = JSON.parse(window.localStorage.getItem("BetterXcloud") || "{}"), $pre = CE("pre", {class: "bx-focusable bx-gone",tabindex: 0,_on: {click: async (e2) => {await copyToClipboard(e2.target.innerText);}}}, "```\n" + JSON.stringify(debugInfo, null, " ") + "\n```"), $button.insertAdjacentElement("afterend", $pre);}$pre.classList.toggle("bx-gone"), $pre.scrollIntoView();}})));}]}];TAB_DISPLAY_ITEMS = [{requiredVariants: "full",group: "audio",label: t("audio"),helpUrl: "https://better-xcloud.github.io/ingame-features/#audio",items: [{pref: "audio.volume",params: {disabled: !getGlobalPref("audio.volume.booster.enabled")},onCreated: (setting, $elm) => {let $range = $elm.querySelector("input[type=range");BxEventBus.Stream.on("setting.changed", (payload) => {let { settingKey } = payload;if (settingKey === "audio.volume") $range.value = getStreamPref(settingKey).toString(), BxEvent.dispatch($range, "input", { ignoreOnChange: !0 });});}}]}, {group: "video",label: t("video"),helpUrl: "https://better-xcloud.github.io/ingame-features/#video",items: ["video.player.type","video.maxFps","video.player.powerPreference","video.processing","video.ratio","video.position","video.processing.sharpness","video.saturation","video.contrast","video.brightness"]}];TAB_CONTROLLER_ITEMS = [{group: "controller",label: t("controller"),helpUrl: "https://better-xcloud.github.io/ingame-features/#controller",items: ["localCoOp.enabled","controller.pollingRate",($parent) => {$parent.appendChild(ControllerExtraSettings.renderSettings.apply(this));}]},STATES.userAgent.capabilities.touch && {group: "touch-control",label: t("touch-controller"),items: [{label: t("layout"),content: CE("select", {disabled: !0}, CE("option", !1, t("default"))),onCreated: (setting, $elm) => {$elm.addEventListener("input", (e) => {TouchController.applyCustomLayout($elm.value, 1000);}), window.addEventListener(BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED, (e) => {let customLayouts = TouchController.getCustomLayouts();while ($elm.firstChild)$elm.removeChild($elm.firstChild);if ($elm.disabled = !customLayouts, !customLayouts) {$elm.appendChild(CE("option", { value: "" }, t("default"))), $elm.value = "", $elm.dispatchEvent(new Event("input"));return;}let $fragment = document.createDocumentFragment();for (let key in customLayouts.layouts) {let layout = customLayouts.layouts[key], name;if (layout.author) name = `${layout.name} (${layout.author})`;else name = layout.name;let $option = CE("option", { value: key }, name);$fragment.appendChild($option);}$elm.appendChild($fragment), $elm.value = customLayouts.default_layout;});}}]},STATES.browser.capabilities.deviceVibration && {group: "device",label: t("device"),items: [{pref: "deviceVibration.mode",multiLines: !0,unsupported: !STATES.browser.capabilities.deviceVibration}, {pref: "deviceVibration.intensity",unsupported: !STATES.browser.capabilities.deviceVibration}]}];TAB_MKB_ITEMS = [{requiredVariants: "full",group: "mkb",label: t("mouse-and-keyboard"),helpUrl: "https://better-xcloud.github.io/mouse-and-keyboard/",items: [($parent) => {$parent.appendChild(MkbExtraSettings.renderSettings.apply(this));}]},NativeMkbHandler.isAllowed() && {requiredVariants: "full",group: "native-mkb",label: t("native-mkb"),items: ["nativeMkb.scroll.sensitivityY","nativeMkb.scroll.sensitivityX"]}];TAB_STATS_ITEMS = [{group: "stats",label: t("stream-stats"),helpUrl: "https://better-xcloud.github.io/stream-stats/",items: ["stats.showWhenPlaying","stats.quickGlance.enabled","stats.items","stats.position","stats.textSize","stats.opacity.all","stats.opacity.background","stats.colors"]}];SETTINGS_UI = {global: {group: "global",icon: BxIcon.HOME,items: this.TAB_GLOBAL_ITEMS},stream: {group: "stream",icon: BxIcon.DISPLAY,items: this.TAB_DISPLAY_ITEMS},controller: {group: "controller",icon: BxIcon.CONTROLLER,items: this.TAB_CONTROLLER_ITEMS,requiredVariants: "full"},mkb: {group: "mkb",icon: BxIcon.NATIVE_MKB,items: this.TAB_MKB_ITEMS,requiredVariants: "full"},stats: {group: "stats",icon: BxIcon.STREAM_STATS,items: this.TAB_STATS_ITEMS}};constructor() {super();BxLogger.info(this.LOG_TAG, "constructor()"), this.boundOnContextMenu = this.onContextMenu.bind(this), this.settingsManager = SettingsManager.getInstance(), this.renderFullSettings = STATES.supportedRegion && STATES.isSignedIn, this.setupDialog(), this.onMountedCallbacks.push(() => {if (onChangeVideoPlayerType(), STATES.userAgent.capabilities.touch) BxEvent.dispatch(window, BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED);let $selectUserAgent = document.querySelector(`#bx_setting_${escapeCssSelector("userAgent.profile")}`);if ($selectUserAgent) $selectUserAgent.disabled = !0, BxEvent.dispatch($selectUserAgent, "input", {}), $selectUserAgent.disabled = !1;}), BxEventBus.Stream.on("gameSettings.switched", ({ id }) => {this.$tabContents.dataset.gameId = id.toString();});}getDialog() {return this;}getContent() {return this.$container;}onMounted() {super.onMounted();}isOverlayVisible() {return !STATES.isPlaying;}reloadPage() {this.$btnGlobalReload.disabled = !0, this.$btnGlobalReload.firstElementChild.textContent = t("settings-reloading"), this.hide(), FullscreenText.getInstance().show(t("settings-reloading")), window.location.reload();}isSupportedVariant(requiredVariants) {if (typeof requiredVariants === "undefined") return !0;return requiredVariants = typeof requiredVariants === "string" ? [requiredVariants] : requiredVariants, requiredVariants.includes(SCRIPT_VARIANT);}onTabClicked = (e) => {let $svg = e.target.closest("svg"), $child, children = Array.from(this.$tabContents.children);for ($child of children)if ($child.dataset.tabGroup === $svg.dataset.group) $child.classList.remove("bx-gone"), calculateSelectBoxes($child);else if ($child.dataset.tabGroup) $child.classList.add("bx-gone");this.$streamSettingsSelection.classList.toggle("bx-gone", $svg.dataset.group === "global");for (let $child2 of Array.from(this.$tabs.children))$child2.classList.remove("bx-active");$svg.classList.add("bx-active");};renderTab(settingTab) {let $svg = createSvgIcon(settingTab.icon);return $svg.dataset.group = settingTab.group, $svg.tabIndex = 0, $svg.addEventListener("click", this.onTabClicked), $svg;}onGlobalSettingChanged = (e) => {PatcherCache.getInstance().clear(), this.$btnReload.classList.add("bx-danger"), this.$noteGlobalReload.classList.add("bx-gone"), this.$btnGlobalReload.classList.remove("bx-gone"), this.$btnGlobalReload.classList.add("bx-danger");};onContextMenu(e) {e.preventDefault();let $elm = e.target;$elm instanceof HTMLElement && this.resetHighlightedSetting($elm);}renderServerSetting(setting) {let selectedValue = getGlobalPref("server.region"), continents = {"america-north": {label: t("continent-north-america")},"america-south": {label: t("continent-south-america")},asia: {label: t("continent-asia")},australia: {label: t("continent-australia")},europe: {label: t("continent-europe")},other: {label: t("other")}}, $control = CE("select", {id: `bx_setting_${escapeCssSelector(setting.pref)}`,tabindex: 0});$control.name = $control.id, $control.addEventListener("input", (e) => {setGlobalPref(setting.pref, e.target.value, "ui"), this.onGlobalSettingChanged(e);}), setting.options = {};for (let regionName in STATES.serverRegions) {let region = STATES.serverRegions[regionName], value = regionName, label = `${region.shortName} - ${regionName}`;if (region.isDefault) {if (label += ` (${t("default")})`, value = "default", selectedValue === regionName) selectedValue = "default";}setting.options[value] = label;let $option = CE("option", { value }, label), continent = continents[region.contintent];if (!continent.children) continent.children = [];continent.children.push($option);}let fragment = document.createDocumentFragment(), key;for (key in continents) {let continent = continents[key];if (!continent.children) continue;fragment.appendChild(CE("optgroup", {label: continent.label}, ...continent.children));}return $control.appendChild(fragment), $control.disabled = Object.keys(STATES.serverRegions).length === 0, $control.value = selectedValue, $control;}renderSettingRow(settingTab, $tabContent, settingTabContent, setting) {if (typeof setting === "string") setting = {pref: setting};let pref = setting.pref, $control;if (setting.content) if (typeof setting.content === "function") $control = setting.content.apply(this);else $control = setting.content;else if (!setting.unsupported) {if (pref === "server.region") $control = this.renderServerSetting(setting);else if (pref === "bx.locale") $control = SettingElement.fromPref(pref, async (e) => {let newLocale = e.target.value;if (getGlobalPref("ui.controllerFriendly")) {let timeoutId = e.target.timeoutId;timeoutId && window.clearTimeout(timeoutId), e.target.timeoutId = window.setTimeout(() => {Translations.refreshLocale(newLocale), Translations.updateTranslations();}, 500);} else Translations.refreshLocale(newLocale), Translations.updateTranslations();this.onGlobalSettingChanged(e);});else if (pref === "userAgent.profile") $control = SettingElement.fromPref("userAgent.profile", (e) => {let value = e.target.value, isCustom = value === "custom", userAgent2 = UserAgent.get(value);UserAgent.updateStorage(value);let $inp = $control.nextElementSibling;$inp.value = userAgent2, $inp.readOnly = !isCustom, $inp.disabled = !isCustom, !e.target.disabled && this.onGlobalSettingChanged(e);});else if ($control = this.settingsManager.getElement(pref, setting.params), settingTab.group === "global") $control.addEventListener("input", this.onGlobalSettingChanged);if ($control instanceof HTMLSelectElement) $control = BxSelectElement.create($control);}let prefDefinition = null;if (pref) prefDefinition = getPrefInfo(pref).definition;if (prefDefinition && !this.isSupportedVariant(prefDefinition.requiredVariants)) return;let label = prefDefinition?.label || setting.label || "", note = prefDefinition?.note || setting.note, unsupportedNote = prefDefinition?.unsupportedNote || setting.unsupportedNote, experimental = prefDefinition?.experimental || setting.experimental;if (typeof note === "function") note = note();if (typeof unsupportedNote === "function") unsupportedNote = unsupportedNote();if (settingTabContent.label && setting.pref) {if (prefDefinition?.suggest) typeof prefDefinition.suggest.lowest !== "undefined" && (this.suggestedSettings.lowest[setting.pref] = prefDefinition.suggest.lowest), typeof prefDefinition.suggest.highest !== "undefined" && (this.suggestedSettings.highest[setting.pref] = prefDefinition.suggest.highest);}if (experimental) if (label = "🧪 " + label, !note) note = t("experimental");else note = `${t("experimental")}: ${note}`;let $note;if (unsupportedNote) $note = CE("div", { class: "bx-settings-dialog-note" }, unsupportedNote);else if (note) $note = CE("div", { class: "bx-settings-dialog-note" }, note);let $row = createSettingRow(label, !prefDefinition?.unsupported && $control, {$note,multiLines: setting.multiLines,icon: prefDefinition?.labelIcon,onContextMenu: this.boundOnContextMenu,pref});if (pref) $row.htmlFor = `bx_setting_${escapeCssSelector(pref)}`;$row.dataset.type = settingTabContent.group, $tabContent.appendChild($row), !prefDefinition?.unsupported && setting.onCreated && setting.onCreated(setting, $control);}renderSettingsSection(settingTab, sections) {let $tabContent = CE("div", {class: "bx-gone",_dataset: {tabGroup: settingTab.group}});for (let section of sections) {if (!section) continue;if (section instanceof HTMLElement) {$tabContent.appendChild(section);continue;}if (!this.isSupportedVariant(section.requiredVariants)) continue;if (!this.renderFullSettings && settingTab.group === "global" && section.group !== "general" && section.group !== "footer") continue;let label = section.label;if (label === t("better-xcloud")) {if (label += " " + SCRIPT_VERSION, SCRIPT_VARIANT === "lite") label += " (Lite)";label = createButton({label,url: "https://github.com/redphx/better-xcloud/releases",style: 4096 | 16 | 64});}if (label) {let $title = CE("h2", {_nearby: {orientation: "horizontal"}}, CE("span", !1, label), section.helpUrl && createButton({icon: BxIcon.QUESTION,style: 8 | 64,url: section.helpUrl,title: t("help")}));$tabContent.appendChild($title);}if (section.unsupportedNote) {let $note = CE("b", { class: "bx-note-unsupported" }, section.unsupportedNote);$tabContent.appendChild($note);}if (section.unsupported) continue;if (section.content) {$tabContent.appendChild(section.content);continue;}section.items = section.items || [];for (let setting of section.items) {if (setting === !1) continue;if (typeof setting === "function") {setting.apply(this, [$tabContent]);continue;}this.renderSettingRow(settingTab, $tabContent, section, setting);}}return $tabContent;}setupDialog() {let $tabs, $tabContents, $container = CE("div", {class: "bx-settings-dialog",_nearby: {orientation: "horizontal"}}, CE("div", {class: "bx-settings-tabs-container",_nearby: {orientation: "vertical",focus: () => {return this.dialogManager.focus($tabs);},loop: (direction) => {if (direction === 1 || direction === 3) return this.focusVisibleTab(direction === 1 ? "last" : "first"), !0;return !1;}}}, $tabs = CE("div", {class: "bx-settings-tabs bx-hide-scroll-bar",_nearby: {focus: () => this.focusActiveTab()}}), CE("div", !1, this.$btnReload = createButton({icon: BxIcon.REFRESH,style: 64 | 32,onClick: (e) => {this.reloadPage();}}), createButton({icon: BxIcon.CLOSE,style: 64 | 32,onClick: (e) => {this.dialogManager.hide();}}))), CE("div", {class: "bx-settings-tab-contents",_nearby: {orientation: "vertical",loop: (direction) => {if (direction === 1 || direction === 3) return this.focusVisibleSetting(direction === 1 ? "last" : "first"), !0;return !1;}}}, this.$streamSettingsSelection = SettingsManager.getInstance().getStreamSettingsSelection(), $tabContents = CE("div", {class: "bx-settings-tab-content",_nearby: {orientation: "vertical",focus: () => this.jumpToSettingGroup("next")}})));this.$container = $container, this.$tabs = $tabs, this.$tabContents = $tabContents, $container.addEventListener("click", (e) => {if (e.target === $container) e.preventDefault(), e.stopPropagation(), this.hide();});let settingTabGroup;for (settingTabGroup in this.SETTINGS_UI) {let settingTab = this.SETTINGS_UI[settingTabGroup];if (!settingTab) continue;if (!this.isSupportedVariant(settingTab.requiredVariants)) continue;if (settingTab.group !== "global" && !this.renderFullSettings) continue;let $svg = this.renderTab(settingTab);$tabs.appendChild($svg);let $tabContent = this.renderSettingsSection.call(this, settingTab, settingTab.items);$tabContents.appendChild($tabContent);}$tabs.firstElementChild.dispatchEvent(new Event("click"));}focusTab(tabId) {let $tab = this.$container.querySelector(`.bx-settings-tabs svg[data-group=${tabId}]`);$tab && $tab.dispatchEvent(new Event("click"));}focusIfNeeded() {this.jumpToSettingGroup("next");}focusActiveTab() {let $currentTab = this.$tabs.querySelector(".bx-active");return $currentTab && $currentTab.focus(), !0;}focusVisibleSetting(type = "first") {let controls = Array.from(this.$tabContents.querySelectorAll("div[data-tab-group]:not(.bx-gone) > *"));if (!controls.length) return !1;if (type === "last") controls.reverse();for (let $control of controls) {if (!($control instanceof HTMLElement)) continue;let $focusable = this.dialogManager.findFocusableElement($control);if ($focusable) {if (this.dialogManager.focus($focusable)) return !0;}}return !1;}focusVisibleTab(type = "first") {let tabs = Array.from(this.$tabs.querySelectorAll("svg:not(.bx-gone)"));if (!tabs.length) return !1;if (type === "last") tabs.reverse();for (let $tab of tabs)if (this.dialogManager.focus($tab)) return !0;return !1;}jumpToSettingGroup(direction) {let $tabContent = this.$tabContents.querySelector("div[data-tab-group]:not(.bx-gone)");if (!$tabContent) return !1;let $header, $focusing = document.activeElement;if (!$focusing || !$tabContent.contains($focusing)) $header = $tabContent.querySelector("h2");else {let $parent = $focusing.closest("[data-tab-group] > *"), siblingProperty = direction === "next" ? "nextSibling" : "previousSibling", $tmp = $parent, times = 0;while (!0) {if (!$tmp) break;if ($tmp.tagName === "H2") {if ($header = $tmp, !$tmp.nextElementSibling?.classList.contains("bx-note-unsupported")) {if (++times, direction === "next" || times >= 2) break;}}$tmp = $tmp[siblingProperty];}}let $target;if ($header) $target = this.dialogManager.findNextTarget($header, 3, !1);if ($target) return this.dialogManager.focus($target);return !1;}resetHighlightedSetting($elm) {let targetGameId = SettingsManager.getInstance().getTargetGameId();if (targetGameId < 0) return;if (!$elm) $elm = document.activeElement instanceof HTMLElement ? document.activeElement : void 0;let $row = $elm?.closest("div[data-tab-group] > .bx-settings-row");if (!$row) return;let pref = $row.prefKey;if (!pref) alert("Pref not found: " + $row.id);if (!isStreamPref(pref)) return;let deleted = STORAGE.Stream.deleteSettingByGame(targetGameId, pref);if (deleted) BxEventBus.Stream.emit("setting.changed", {storageKey: `${"BetterXcloud.Stream"}.${targetGameId}`,settingKey: pref});return deleted;}handleKeyPress(key) {let handled = !0;switch (key) {case "Tab":this.focusActiveTab();break;case "Home":this.focusVisibleSetting("first");break;case "End":this.focusVisibleSetting("last");break;case "PageUp":this.jumpToSettingGroup("previous");break;case "PageDown":this.jumpToSettingGroup("next");break;case "KeyQ":this.resetHighlightedSetting();break;default:handled = !1;break;}return handled;}handleGamepad(button) {let handled = !0;switch (button) {case 1:let $focusing = document.activeElement;if ($focusing && this.$tabs.contains($focusing)) this.hide();else this.focusActiveTab();break;case 4:case 5:this.focusActiveTab();break;case 6:this.jumpToSettingGroup("previous");break;case 7:this.jumpToSettingGroup("next");break;case 2:this.resetHighlightedSetting();break;default:handled = !1;break;}return handled;}}
class ScreenshotManager {static instance;static getInstance = () => ScreenshotManager.instance ?? (ScreenshotManager.instance = new ScreenshotManager);LOG_TAG = "ScreenshotManager";$download;$canvas;canvasContext;constructor() {BxLogger.info(this.LOG_TAG, "constructor()"), this.$download = CE("a"), this.$canvas = CE("canvas", { class: "bx-gone" }), this.canvasContext = this.$canvas.getContext("2d", {alpha: !1,willReadFrequently: !1});}updateCanvasSize(width, height) {this.$canvas.width = width, this.$canvas.height = height;}updateCanvasFilters(filters) {this.canvasContext.filter = filters;}onAnimationEnd(e) {e.target.classList.remove("bx-taking-screenshot");}takeScreenshot(callback) {let currentStream = STATES.currentStream, streamPlayerManager = currentStream.streamPlayerManager, $canvas = this.$canvas;if (!streamPlayerManager || !$canvas) return;let $player;if (getGlobalPref("screenshot.applyFilters")) $player = streamPlayerManager.getPlayerElement();else $player = streamPlayerManager.getPlayerElement("video");if (!$player || !$player.isConnected) return;let canvasContext = this.canvasContext;if ($player instanceof HTMLCanvasElement) streamPlayerManager.getCanvasPlayer()?.updateFrame();canvasContext.drawImage($player, 0, 0);let $gameStream = $player.closest("#game-stream");if ($gameStream) $gameStream.addEventListener("animationend", this.onAnimationEnd, { once: !0 }), $gameStream.classList.add("bx-taking-screenshot");if (AppInterface) {let data = $canvas.toDataURL("image/png").split(";base64,")[1];AppInterface.saveScreenshot(currentStream.titleSlug, data), canvasContext.clearRect(0, 0, $canvas.width, $canvas.height), callback && callback();return;}$canvas.toBlob((blob) => {if (!blob) return;let now = +new Date, $download = this.$download;$download.download = `${currentStream.titleSlug}-${now}.png`, $download.href = URL.createObjectURL(blob), $download.click(), URL.revokeObjectURL($download.href), $download.href = "", $download.download = "", canvasContext.clearRect(0, 0, $canvas.width, $canvas.height), callback && callback();}, "image/png");}}
class RendererShortcut {static toggleVisibility() {let $mediaContainer = document.querySelector('#game-stream div[data-testid="media-container"]');if (!$mediaContainer) {BxEventBus.Stream.emit("video.visibility.changed", { isVisible: !0 });return;}$mediaContainer.classList.toggle("bx-gone");let isVisible = !$mediaContainer.classList.contains("bx-gone");limitVideoPlayerFps(isVisible ? getStreamPref("video.maxFps") : 0), BxEventBus.Stream.emit("video.visibility.changed", { isVisible });}}
class TrueAchievements {static instance;static getInstance = () => TrueAchievements.instance ?? (TrueAchievements.instance = new TrueAchievements);LOG_TAG = "TrueAchievements";$link;$button;$hiddenLink;constructor() {BxLogger.info(this.LOG_TAG, "constructor()"), this.$link = createButton({label: t("true-achievements"),url: "#",icon: BxIcon.TRUE_ACHIEVEMENTS,style: 64 | 8 | 128 | 8192,onClick: this.onClick}), this.$button = createButton({label: t("true-achievements"),title: t("true-achievements"),icon: BxIcon.TRUE_ACHIEVEMENTS,style: 64,onClick: this.onClick}), this.$hiddenLink = CE("a", {target: "_blank"});}onClick = (e) => {e.preventDefault(), window.BX_EXPOSED.dialogRoutes?.closeAll();let dataset = this.$link.dataset;this.open(!0, dataset.xboxTitleId, dataset.id);};updateIds(xboxTitleId, id) {let $link = this.$link, $button = this.$button;if (clearDataSet($link), clearDataSet($button), xboxTitleId) $link.dataset.xboxTitleId = xboxTitleId, $button.dataset.xboxTitleId = xboxTitleId;if (id) $link.dataset.id = id, $button.dataset.id = id;}injectAchievementsProgress($elm) {if (SCRIPT_VARIANT !== "full") return;let $parent = $elm.parentElement, $div = CE("div", {class: "bx-guide-home-achievements-progress"}, $elm), xboxTitleId;try {let $container = $parent.closest("div[class*=AchievementsPreview-module__container]");if ($container) xboxTitleId = getReactProps($container).children.props.data.data.xboxTitleId;} catch (e) {}if (!xboxTitleId) xboxTitleId = this.getStreamXboxTitleId();if (typeof xboxTitleId !== "undefined") xboxTitleId = xboxTitleId.toString();if (this.updateIds(xboxTitleId), document.body.dataset.mediaType === "tv") $div.appendChild(this.$link);else $div.appendChild(this.$button);$parent.appendChild($div);}injectAchievementDetailPage($parent) {if (SCRIPT_VARIANT !== "full") return;let props = getReactProps($parent);if (!props) return;try {let achievementList = props.children.props.data.data, $header = $parent.querySelector("div[class*=AchievementDetailHeader]"), achievementName = getReactProps($header).children[0].props.achievementName, id, xboxTitleId;for (let achiev of achievementList)if (achiev.name === achievementName) {id = achiev.id, xboxTitleId = achiev.title.id;break;}if (id) this.updateIds(xboxTitleId, id), $parent.appendChild(this.$link);} catch (e) {}}getStreamXboxTitleId() {return STATES.currentStream.xboxTitleId || STATES.currentStream.titleInfo?.details.xboxTitleId;}open(override, xboxTitleId, id) {if (!xboxTitleId || xboxTitleId === "undefined") xboxTitleId = this.getStreamXboxTitleId();if (AppInterface && AppInterface.openTrueAchievementsLink) {AppInterface.openTrueAchievementsLink(override, xboxTitleId?.toString(), id?.toString());return;}let url = "https://www.trueachievements.com";if (xboxTitleId) {if (url += `/deeplink/${xboxTitleId}`, id) url += `/${id}`;}this.$hiddenLink.href = url, this.$hiddenLink.click();}}
@@ -304,7 +304,7 @@ async function patchIceCandidates(request, consoleAddrs) {let response = await N
function interceptHttpRequests() {let BLOCKED_URLS = [];if (getGlobalPref("block.tracking")) clearAllLogs(), BLOCKED_URLS.push("https://arc.msn.com", "https://browser.events.data.microsoft.com", "https://dc.services.visualstudio.com", "https://2c06dea3f26c40c69b8456d319791fd0@o427368.ingest.sentry.io", "https://mscom.demdex.net");let blockFeatures2 = getGlobalPref("block.features");if (blockFeatures2.includes("chat")) BLOCKED_URLS.push("https://xblmessaging.xboxlive.com/network/xbox/users/me/inbox");if (blockFeatures2.includes("friends")) BLOCKED_URLS.push("https://peoplehub.xboxlive.com/users/me/people/social", "https://peoplehub.xboxlive.com/users/me/people/recommendations");if (blockAllNotifications()) BLOCKED_URLS.push("https://notificationinbox.xboxlive.com/");let xhrPrototype = XMLHttpRequest.prototype, nativeXhrOpen = xhrPrototype.open, nativeXhrSend = xhrPrototype.send;xhrPrototype.open = function(method, url) {return this._url = url, nativeXhrOpen.apply(this, arguments);}, xhrPrototype.send = function(...arg) {for (let url of BLOCKED_URLS)if (this._url.startsWith(url)) {if (url === "https://dc.services.visualstudio.com") window.setTimeout(clearAllLogs, 1000);return BxLogger.warning("Blocked URL", url), !1;}return nativeXhrSend.apply(this, arguments);};let gamepassAllGames = [], IGNORED_DOMAINS = ["accounts.xboxlive.com","chat.xboxlive.com","notificationinbox.xboxlive.com","peoplehub.xboxlive.com","peoplehub-public.xboxlive.com","rta.xboxlive.com","userpresence.xboxlive.com","xblmessaging.xboxlive.com","consent.config.office.com","arc.msn.com","browser.events.data.microsoft.com","dc.services.visualstudio.com","2c06dea3f26c40c69b8456d319791fd0@o427368.ingest.sentry.io"];window.BX_FETCH = window.fetch = async (request, init) => {let url = typeof request === "string" ? request : request.url;for (let blocked of BLOCKED_URLS)if (url.startsWith(blocked)) return BxLogger.warning("Blocked URL", url), new Response('{"acc":1,"webResult":{}}', {status: 200,statusText: "200 OK"});try {let domain = new URL(url).hostname;if (IGNORED_DOMAINS.includes(domain)) return NATIVE_FETCH(request, init);} catch (e) {return NATIVE_FETCH(request, init);}if (url.startsWith("https://emerald.xboxservices.com/xboxcomfd/experimentation")) try {let response = await NATIVE_FETCH(request, init), json = await response.json();if (json && json.exp && json.exp.treatments) for (let key in FeatureGates)json.exp.treatments[key] = FeatureGates[key];return response.json = () => Promise.resolve(json), response;} catch (e) {return console.log(e), NATIVE_FETCH(request, init);}if (STATES.userAgent.capabilities.touch && url.includes("catalog.gamepass.com/sigls/")) {let response = await NATIVE_FETCH(request, init), obj = await response.clone().json();if (url.includes("29a81209-df6f-41fd-a528-2ae6b91f719c") || url.includes("ce573635-7c18-4d0c-9d68-90b932393470")) for (let i = 1;i < obj.length; i++)gamepassAllGames.push(obj[i].id);else if (url.includes("9c86f07a-f3e8-45ad-82a0-a1f759597059")) try {let customList = TouchController.getCustomList();customList = customList.filter((id) => gamepassAllGames.includes(id));let newCustomList = customList.map((item2) => ({ id: item2 }));obj.push(...newCustomList);} catch (e) {console.log(e);}return response.json = () => Promise.resolve(obj), response;}if (BX_FLAGS.ForceNativeMkbTitles && url.includes("catalog.gamepass.com/sigls/") && url.includes("8fa264dd-124f-4af3-97e8-596fcdf4b486")) {let response = await NATIVE_FETCH(request, init), obj = await response.clone().json();try {let newCustomList = BX_FLAGS.ForceNativeMkbTitles.map((item2) => ({ id: item2 }));obj.push(...newCustomList);} catch (e) {console.log(e);}return response.json = () => Promise.resolve(obj), response;}let requestType;if (url.includes("/sessions/home") || url.includes("xhome.") || STATES.remotePlay.isPlaying && url.endsWith("/inputconfigs")) requestType = "xhome";else requestType = "xcloud";if (requestType === "xhome") return XhomeInterceptor.handle(request);return XcloudInterceptor.handle(request, init);};}
function generateMsDeviceInfo(osName) {return {appInfo: {env: {clientAppId: window.location.host,clientAppType: "browser",clientAppVersion: "26.1.97",clientSdkVersion: "10.3.7",httpEnvironment: "prod",sdkInstallId: ""}},dev: {os: { name: osName, ver: "22631.2715", platform: "desktop" },hw: { make: "Microsoft", model: "unknown", sdktype: "web" },browser: { browserName: "chrome", browserVersion: "130.0" },displayInfo: {dimensions: { widthInPixels: 1920, heightInPixels: 1080 },pixelDensity: { dpiX: 1, dpiY: 1 }}}};}
function getOsNameFromResolution(resolution) {let osName;switch (resolution) {case "1080p-hq":osName = "tizen";break;case "1080p":osName = "windows";break;default:osName = "android";break;}return osName;}
-function addCss() {let css = ':root{--bx-title-font:Bahnschrift,Arial,Helvetica,sans-serif;--bx-title-font-semibold:Bahnschrift Semibold,Arial,Helvetica,sans-serif;--bx-normal-font:"Segoe UI",Arial,Helvetica,sans-serif;--bx-monospaced-font:Consolas,"Courier New",Courier,monospace;--bx-promptfont-font:promptfont;--bx-button-height:40px;--bx-default-button-color:#2d3036;--bx-default-button-rgb:45,48,54;--bx-default-button-hover-color:#515863;--bx-default-button-hover-rgb:81,88,99;--bx-default-button-active-color:#222428;--bx-default-button-active-rgb:34,36,40;--bx-default-button-disabled-color:#8e8e8e;--bx-default-button-disabled-rgb:142,142,142;--bx-primary-button-color:#008746;--bx-primary-button-rgb:0,135,70;--bx-primary-button-hover-color:#04b358;--bx-primary-button-hover-rgb:4,179,88;--bx-primary-button-active-color:#044e2a;--bx-primary-button-active-rgb:4,78,42;--bx-primary-button-disabled-color:#448262;--bx-primary-button-disabled-rgb:68,130,98;--bx-warning-button-color:#c16e04;--bx-warning-button-rgb:193,110,4;--bx-warning-button-hover-color:#fa9005;--bx-warning-button-hover-rgb:250,144,5;--bx-warning-button-active-color:#965603;--bx-warning-button-active-rgb:150,86,3;--bx-warning-button-disabled-color:#a2816c;--bx-warning-button-disabled-rgb:162,129,108;--bx-danger-button-color:#c10404;--bx-danger-button-rgb:193,4,4;--bx-danger-button-hover-color:#e61d1d;--bx-danger-button-hover-rgb:230,29,29;--bx-danger-button-active-color:#a26c6c;--bx-danger-button-active-rgb:162,108,108;--bx-danger-button-disabled-color:#bd8282;--bx-danger-button-disabled-rgb:189,130,130;--bx-fullscreen-text-z-index:9999;--bx-toast-z-index:6000;--bx-key-binding-dialog-z-index:5010;--bx-key-binding-dialog-overlay-z-index:5000;--bx-stats-bar-z-index:4010;--bx-navigation-dialog-z-index:3010;--bx-navigation-dialog-overlay-z-index:3000;--bx-mkb-pointer-lock-msg-z-index:2000;--bx-game-bar-z-index:1000;--bx-screenshot-animation-z-index:200;--bx-wait-time-box-z-index:100}@font-face{font-family:\'promptfont\';src:url("https://redphx.github.io/better-xcloud/fonts/promptfont.otf");unicode-range:U+2196-E011,U+27F6,U+FF31}div[class^=HUDButton-module__hiddenContainer] ~ div:not([class^=HUDButton-module__hiddenContainer]){opacity:0;pointer-events:none !important;position:absolute;top:-9999px;left:-9999px}@media screen and (max-width:640px){header a[href="/play"]{display:none}}.bx-full-width{width:100% !important}.bx-full-height{height:100% !important}.bx-auto-height{height:auto !important}.bx-no-scroll{overflow:hidden !important}.bx-hide-scroll-bar{scrollbar-width:none}.bx-hide-scroll-bar::-webkit-scrollbar{display:none}.bx-gone{display:none !important}.bx-offscreen{position:absolute !important;top:-9999px !important;left:-9999px !important;visibility:hidden !important}.bx-hidden{visibility:hidden !important}.bx-invisible{opacity:0}.bx-unclickable{pointer-events:none}.bx-pixel{width:1px !important;height:1px !important}.bx-no-margin{margin:0 !important}.bx-no-padding{padding:0 !important}.bx-prompt{font-family:var(--bx-promptfont-font) !important}.bx-monospaced{font-family:var(--bx-monospaced-font) !important}.bx-line-through{text-decoration:line-through !important}.bx-normal-case{text-transform:none !important}.bx-normal-link{text-transform:none !important;text-align:left !important;font-weight:400 !important;font-family:var(--bx-normal-font) !important}.bx-frosted{backdrop-filter:blur(4px) brightness(1.5)}select[multiple],select[multiple]:focus{overflow:auto;border:none}select[multiple] option,select[multiple]:focus option{padding:4px 6px}select[multiple] option:checked,select[multiple]:focus option:checked{background:#1a7bc0 linear-gradient(0deg,#1a7bc0 0%,#1a7bc0 100%)}select[multiple] option:checked::before,select[multiple]:focus option:checked::before{content:\'☑️\';font-size:12px;display:inline-block;margin-right:6px;height:100%;line-height:100%;vertical-align:middle}#headerArea,#uhfSkipToMain,.uhf-footer{display:none}div[class*=NotFocusedDialog]{position:absolute !important;top:-9999px !important;left:-9999px !important;width:0 !important;height:0 !important}#game-stream video:not([src]){visibility:hidden}.bx-game-tile-wait-time{position:absolute;top:0;left:0;z-index:1;background:rgba(0,0,0,0.5);display:flex;border-radius:4px 0 4px 0;align-items:center;padding:4px 8px}.bx-game-tile-wait-time svg{width:14px;height:16px;margin-right:2px}.bx-game-tile-wait-time span{display:inline-block;height:16px;line-height:16px;font-size:12px;font-weight:bold;margin-left:2px}.bx-game-tile-wait-time[data-duration=short]{background-color:rgba(0,133,133,0.75)}.bx-game-tile-wait-time[data-duration=medium]{background-color:rgba(213,133,0,0.75)}.bx-game-tile-wait-time[data-duration=long]{background-color:rgba(150,0,0,0.75)}.bx-fullscreen-text{position:fixed;top:0;bottom:0;left:0;right:0;background:rgba(0,0,0,0.8);z-index:var(--bx-fullscreen-text-z-index);line-height:100vh;color:#fff;text-align:center;font-weight:400;font-family:var(--bx-normal-font);font-size:1.3rem;user-select:none;-webkit-user-select:none}#root section[class*=DeviceCodePage-module__page]{margin-left:20px !important;margin-right:20px !important;margin-top:20px !important;max-width:800px !important}#root div[class*=DeviceCodePage-module__back]{display:none}.bx-blink-me{animation:bx-blinker 1s linear infinite}.bx-horizontal-shaking{animation:bx-horizontal-shaking .4s ease-in-out 2}@-moz-keyframes bx-blinker{100%{opacity:0}}@-webkit-keyframes bx-blinker{100%{opacity:0}}@-o-keyframes bx-blinker{100%{opacity:0}}@keyframes bx-blinker{100%{opacity:0}}@-moz-keyframes bx-horizontal-shaking{0%{transform:translateX(0)}25%{transform:translateX(5px)}50%{transform:translateX(-5px)}75%{transform:translateX(5px)}100%{transform:translateX(0)}}@-webkit-keyframes bx-horizontal-shaking{0%{transform:translateX(0)}25%{transform:translateX(5px)}50%{transform:translateX(-5px)}75%{transform:translateX(5px)}100%{transform:translateX(0)}}@-o-keyframes bx-horizontal-shaking{0%{transform:translateX(0)}25%{transform:translateX(5px)}50%{transform:translateX(-5px)}75%{transform:translateX(5px)}100%{transform:translateX(0)}}@keyframes bx-horizontal-shaking{0%{transform:translateX(0)}25%{transform:translateX(5px)}50%{transform:translateX(-5px)}75%{transform:translateX(5px)}100%{transform:translateX(0)}}.bx-button{--button-rgb:var(--bx-default-button-rgb);--button-hover-rgb:var(--bx-default-button-hover-rgb);--button-active-rgb:var(--bx-default-button-active-rgb);--button-disabled-rgb:var(--bx-default-button-disabled-rgb);background-color:rgb(var(--button-rgb));user-select:none;-webkit-user-select:none;color:#fff;font-family:var(--bx-title-font-semibold);font-size:14px;border:none;font-weight:400;height:var(--bx-button-height);border-radius:4px;padding:0 8px;text-transform:uppercase;cursor:pointer;overflow:hidden}.bx-button:not([disabled]):active{background-color:rgb(var(--button-active-rgb))}.bx-button:focus{outline:none !important}.bx-button:not([disabled]):not(:active):hover,.bx-button:not([disabled]):not(:active).bx-focusable:focus{background-color:rgb(var(--button-hover-rgb))}.bx-button:disabled{cursor:default;background-color:rgb(var(--button-disabled-rgb));opacity:.5}.bx-button.bx-ghost{background-color:transparent}.bx-button.bx-ghost:not([disabled]):not(:active):hover,.bx-button.bx-ghost:not([disabled]):not(:active).bx-focusable:focus{background-color:rgb(var(--button-hover-rgb))}.bx-button.bx-primary{--button-rgb:var(--bx-primary-button-rgb)}.bx-button.bx-primary:not([disabled]):active{--button-active-rgb:var(--bx-primary-button-active-rgb)}.bx-button.bx-primary:not([disabled]):not(:active):hover,.bx-button.bx-primary:not([disabled]):not(:active).bx-focusable:focus{--button-hover-rgb:var(--bx-primary-button-hover-rgb)}.bx-button.bx-primary:disabled{--button-disabled-rgb:var(--bx-primary-button-disabled-rgb)}.bx-button.bx-warning{--button-rgb:var(--bx-warning-button-rgb)}.bx-button.bx-warning:not([disabled]):active{--button-active-rgb:var(--bx-warning-button-active-rgb)}.bx-button.bx-warning:not([disabled]):not(:active):hover,.bx-button.bx-warning:not([disabled]):not(:active).bx-focusable:focus{--button-hover-rgb:var(--bx-warning-button-hover-rgb)}.bx-button.bx-warning:disabled{--button-disabled-rgb:var(--bx-warning-button-disabled-rgb)}.bx-button.bx-danger{--button-rgb:var(--bx-danger-button-rgb)}.bx-button.bx-danger:not([disabled]):active{--button-active-rgb:var(--bx-danger-button-active-rgb)}.bx-button.bx-danger:not([disabled]):not(:active):hover,.bx-button.bx-danger:not([disabled]):not(:active).bx-focusable:focus{--button-hover-rgb:var(--bx-danger-button-hover-rgb)}.bx-button.bx-danger:disabled{--button-disabled-rgb:var(--bx-danger-button-disabled-rgb)}.bx-button.bx-frosted{--button-alpha:.2;background-color:rgba(var(--button-rgb), var(--button-alpha))}.bx-button.bx-frosted:not([disabled]):not(:active):hover,.bx-button.bx-frosted:not([disabled]):not(:active).bx-focusable:focus{background-color:rgba(var(--button-hover-rgb), var(--button-alpha))}.bx-button.bx-drop-shadow{box-shadow:0 0 4px rgba(0,0,0,0.502)}.bx-button.bx-tall{height:calc(var(--bx-button-height) * 1.5) !important}.bx-button.bx-circular{border-radius:var(--bx-button-height);width:var(--bx-button-height);height:var(--bx-button-height)}.bx-button svg{display:inline-block;width:16px;height:var(--bx-button-height)}.bx-button span{display:inline-block;line-height:var(--bx-button-height);vertical-align:middle;color:#fff;overflow:hidden;white-space:nowrap}.bx-button span:not(:only-child){margin-inline-start:8px}.bx-button.bx-button-multi-lines{height:auto;text-align:left;padding:10px}.bx-button.bx-button-multi-lines span{line-height:unset;display:block}.bx-button.bx-button-multi-lines span:last-of-type{text-transform:none;font-weight:normal;font-family:"Segoe Sans Variable Text";font-size:12px;margin-top:4px}.bx-focusable{position:relative;overflow:visible}.bx-focusable::after{border:2px solid transparent;border-radius:10px}.bx-focusable:focus::after{content:\'\';border-color:#fff;position:absolute;top:-6px;left:-6px;right:-6px;bottom:-6px}html[data-active-input=touch] .bx-focusable:focus::after,html[data-active-input=mouse] .bx-focusable:focus::after{border-color:transparent !important}.bx-focusable.bx-circular::after{border-radius:var(--bx-button-height)}a.bx-button{display:inline-block}a.bx-button.bx-full-width{text-align:center}button.bx-inactive{pointer-events:none;opacity:.2;background:transparent !important}.bx-header-remote-play-button{height:auto;margin-right:8px !important}.bx-header-remote-play-button svg{width:24px;height:24px}.bx-header-settings-button{line-height:30px;font-size:14px;text-transform:uppercase;position:relative}.bx-header-settings-button[data-update-available]::before{content:\'🌟\' !important;line-height:var(--bx-button-height);display:inline-block;margin-left:4px}.bx-key-binding-dialog-overlay{position:fixed;inset:0;z-index:var(--bx-key-binding-dialog-overlay-z-index);background:#000;opacity:50%}.bx-key-binding-dialog{display:flex;flex-flow:column;max-height:90vh;position:fixed;top:50%;left:50%;margin-right:-50%;transform:translate(-50%,-50%);min-width:420px;padding:16px;border-radius:8px;z-index:var(--bx-key-binding-dialog-z-index);background:#1a1b1e;color:#fff;font-weight:400;font-size:16px;font-family:var(--bx-normal-font);box-shadow:0 0 6px #000;user-select:none;-webkit-user-select:none}.bx-key-binding-dialog *:focus{outline:none !important}.bx-key-binding-dialog h2{margin-bottom:12px;color:#fff;display:block;font-family:var(--bx-title-font);font-size:32px;font-weight:400;line-height:var(--bx-button-height)}.bx-key-binding-dialog > div{overflow:auto;padding:2px 0}.bx-key-binding-dialog > button{padding:8px 32px;margin:10px auto 0;border:none;border-radius:4px;display:block;background-color:#2d3036;text-align:center;color:#fff;text-transform:uppercase;font-family:var(--bx-title-font);font-weight:400;line-height:18px;font-size:14px}@media (hover:hover){.bx-key-binding-dialog > button:hover{background-color:#515863}}.bx-key-binding-dialog > button:focus{background-color:#515863}.bx-key-binding-dialog ul{margin-bottom:1rem}.bx-key-binding-dialog ul li{display:none}.bx-key-binding-dialog ul[data-flags*="[1]"] > li[data-flag="1"],.bx-key-binding-dialog ul[data-flags*="[2]"] > li[data-flag="2"],.bx-key-binding-dialog ul[data-flags*="[4]"] > li[data-flag="4"],.bx-key-binding-dialog ul[data-flags*="[8]"] > li[data-flag="8"]{display:list-item}@media screen and (max-width:450px){.bx-key-binding-dialog{min-width:100%}}.bx-navigation-dialog{position:absolute;z-index:var(--bx-navigation-dialog-z-index);font-family:var(--bx-title-font)}.bx-navigation-dialog *:focus{outline:none !important}.bx-navigation-dialog select:disabled{-webkit-appearance:none;text-align-last:right;text-align:right;color:#fff;background:#131416;border:none;border-radius:4px;padding:0 5px}.bx-navigation-dialog .bx-focusable::after{border-radius:4px}.bx-navigation-dialog .bx-focusable:focus::after{top:0;left:0;right:0;bottom:0}.bx-navigation-dialog-overlay{position:fixed;background:rgba(11,11,11,0.89);top:0;left:0;right:0;bottom:0;z-index:var(--bx-navigation-dialog-overlay-z-index)}.bx-navigation-dialog-overlay[data-is-playing="true"]{background:transparent}.bx-centered-dialog{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;background:#1a1b1e;border-radius:10px;min-width:min(calc(100vw - 20px), 500px);max-width:calc(100vw - 20px);margin:0 0 0 auto;padding:16px;max-height:95vh;flex-direction:column;overflow:hidden;display:flex;flex-direction:column}.bx-centered-dialog .bx-dialog-title{display:flex;flex-direction:row;align-items:center;margin-bottom:10px}.bx-centered-dialog .bx-dialog-title p{padding:0;margin:0;flex:1;font-size:1.5rem;font-weight:bold}.bx-centered-dialog .bx-dialog-title button{flex-shrink:0}.bx-centered-dialog .bx-dialog-content{flex:1;padding:6px;overflow:auto;overflow-x:hidden}.bx-centered-dialog .bx-dialog-preset-tools{display:flex;margin-bottom:12px;gap:6px}.bx-centered-dialog .bx-dialog-preset-tools button{align-self:center;min-height:50px}.bx-centered-dialog .bx-default-preset-note{font-size:12px;font-style:italic;text-align:center;margin-bottom:10px}.bx-centered-dialog input,.bx-settings-dialog input{accent-color:var(--bx-primary-button-color)}.bx-centered-dialog input:focus,.bx-settings-dialog input:focus{accent-color:var(--bx-danger-button-color)}.bx-centered-dialog select:disabled,.bx-settings-dialog select:disabled{-webkit-appearance:none;background:transparent;text-align-last:right;border:none;color:#fff}.bx-centered-dialog select option:disabled,.bx-settings-dialog select option:disabled{display:none}.bx-centered-dialog input[type=checkbox]:focus,.bx-settings-dialog input[type=checkbox]:focus,.bx-centered-dialog select:focus,.bx-settings-dialog select:focus{filter:drop-shadow(1px 0 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 1px 0 #fff) drop-shadow(0 -1px 0 #fff)}.bx-centered-dialog a,.bx-settings-dialog a{color:#1c9d1c;text-decoration:none}.bx-centered-dialog a:hover,.bx-settings-dialog a:hover,.bx-centered-dialog a:focus,.bx-settings-dialog a:focus{color:#5dc21e}.bx-centered-dialog label,.bx-settings-dialog label{margin:0}.bx-controller-shortcuts-manager-container .bx-shortcut-note{margin-top:10px;font-size:14px;text-align:center}.bx-controller-shortcuts-manager-container .bx-shortcut-row{display:flex;gap:10px;margin-bottom:10px;align-items:center}.bx-controller-shortcuts-manager-container .bx-shortcut-row label.bx-prompt{flex-shrink:0;font-size:32px;margin:0}.bx-controller-shortcuts-manager-container .bx-shortcut-row label.bx-prompt::first-letter{letter-spacing:6px}.bx-controller-shortcuts-manager-container select:disabled{text-align:left;text-align-last:left}.bx-keyboard-shortcuts-manager-container{display:flex;flex-direction:column;gap:16px}.bx-keyboard-shortcuts-manager-container fieldset{background:#2a2a2a;border:1px solid #2a2a2a;border-radius:4px;padding:4px}.bx-keyboard-shortcuts-manager-container legend{width:auto;padding:4px 8px;margin:0 4px 4px;background:#004f87;box-shadow:0 2px 0 #071e3d;border-radius:4px;font-size:14px;font-weight:bold;text-transform:uppercase}.bx-keyboard-shortcuts-manager-container .bx-settings-row{background:none;padding:10px}.bx-settings-dialog{display:flex;position:fixed;top:0;right:0;bottom:0;opacity:.98;user-select:none;-webkit-user-select:none}.bx-settings-dialog .bx-settings-reload-note{font-size:.8rem;display:block;padding:8px;font-style:italic;font-weight:normal;height:var(--bx-button-height)}.bx-settings-tabs-container{position:fixed;width:48px;max-height:100vh;display:flex;flex-direction:column}.bx-settings-tabs-container > div:last-of-type{display:flex;flex-direction:column;align-items:end}.bx-settings-tabs-container > div:last-of-type button{flex-shrink:0;border-top-right-radius:0;border-bottom-right-radius:0;margin-top:8px;height:unset;padding:8px 10px}.bx-settings-tabs-container > div:last-of-type button svg{width:16px;height:16px}.bx-settings-tabs{display:flex;flex-direction:column;border-radius:0 0 0 8px;box-shadow:0 0 6px #000;overflow:overlay;flex:1}.bx-settings-tabs svg{width:24px;height:24px;padding:10px;flex-shrink:0;box-sizing:content-box;background:#131313;cursor:pointer;border-left:4px solid #1e1e1e}.bx-settings-tabs svg.bx-active{background:#222;border-color:#008746}.bx-settings-tabs svg:not(.bx-active):hover{background:#2f2f2f;border-color:#484848}.bx-settings-tabs svg:focus{border-color:#fff}.bx-settings-tabs svg[data-group=global][data-need-refresh=true]{background:var(--bx-danger-button-color) !important}.bx-settings-tabs svg[data-group=global][data-need-refresh=true]:hover{background:var(--bx-danger-button-hover-color) !important}.bx-settings-tab-contents{flex-direction:column;margin-left:48px;width:450px;background:#1a1b1e;color:#fff;font-weight:400;font-size:16px;font-family:var(--bx-title-font);text-align:center;box-shadow:0 0 6px #000;overflow:overlay;z-index:1}.bx-settings-tab-contents .bx-top-buttons{display:flex;flex-direction:column;gap:8px;margin-bottom:8px}.bx-settings-tab-contents .bx-top-buttons .bx-button{display:block}.bx-settings-tab-contents h2{margin:16px 0 8px 0;display:flex;align-items:center}.bx-settings-tab-contents h2:first-of-type{margin-top:0}.bx-settings-tab-contents h2 span{display:inline-block;font-size:20px;font-weight:bold;text-align:left;flex:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;min-height:var(--bx-button-height);align-content:center}@media (max-width:500px){.bx-settings-tab-contents{width:calc(100vw - 48px)}}.bx-settings-row{display:flex;gap:10px;padding:16px 10px;background:#2a2a2a;border-bottom:1px solid #343434}.bx-settings-row:hover,.bx-settings-row:focus-within{background-color:#242424}.bx-settings-row:not(:has(> input[type=checkbox])){flex-wrap:wrap}.bx-settings-row > span.bx-settings-label{font-size:14px;display:block;text-align:left;align-self:center;margin-bottom:0 !important;flex:1}.bx-settings-row > span.bx-settings-label svg{width:20px;height:20px;margin-inline-end:8px}.bx-settings-row > span.bx-settings-label + *{margin:0 0 0 auto}.bx-settings-row[data-multi-lines="true"]{flex-direction:column}.bx-settings-row[data-multi-lines="true"] > span.bx-settings-label{align-self:start}.bx-settings-row[data-multi-lines="true"] > span.bx-settings-label + *{margin:unset}.bx-settings-dialog-note{display:block;color:#afafb0;font-size:12px;font-weight:lighter;font-style:italic}.bx-settings-dialog-note:not(:has(a)){margin-top:4px}.bx-settings-dialog-note a{display:inline-block;padding:4px}.bx-settings-custom-user-agent{display:block;width:100%;padding:6px}.bx-donation-link{display:block;text-align:center;text-decoration:none;height:20px;line-height:20px;font-size:14px;margin-top:10px;margin-bottom:10px}.bx-debug-info button{margin-top:10px}.bx-debug-info pre{margin-top:10px;cursor:copy;color:#fff;padding:8px;border:1px solid #2d2d2d;background:#212121;white-space:break-spaces;text-align:left}.bx-debug-info pre:hover{background:#272727}.bx-settings-app-version{margin-top:10px;text-align:center;color:#747474;font-size:12px}.bx-note-unsupported{display:block;font-size:12px;font-style:italic;font-weight:normal;color:#828282}.bx-settings-tab-content{padding:10px}.bx-settings-tab-content > div *:not(.bx-settings-row):has(+ .bx-settings-row) + .bx-settings-row:has(+ .bx-settings-row){border-top-left-radius:6px;border-top-right-radius:6px}.bx-settings-tab-content > div .bx-settings-row:not(:has(+ .bx-settings-row)){border:none;border-bottom-left-radius:6px;border-bottom-right-radius:6px}.bx-settings-tab-content > div *:not(.bx-settings-row):has(+ .bx-settings-row) + .bx-settings-row:not(:has(+ .bx-settings-row)){border:none;border-radius:6px}.bx-settings-tab-content:not([data-game-id="-1"]) .bx-settings-row[data-override=true],.bx-settings-tab-content:not([data-game-id="-1"]) .bx-settings-row:has(*[data-override=true]){border-left:4px solid #ffa500 !important;border-top-left-radius:0 !important;border-bottom-left-radius:0 !important;padding-left:6px !important}.bx-suggest-toggler{text-align:left;display:flex;border-radius:4px;overflow:hidden;background:#003861;height:45px;align-items:center}.bx-suggest-toggler label{flex:1;align-content:center;padding:0 10px;background:#004f87;height:100%}.bx-suggest-toggler span{display:inline-block;align-self:center;padding:10px;width:45px;text-align:center}.bx-suggest-toggler:hover,.bx-suggest-toggler:focus{cursor:pointer;background:#005da1}.bx-suggest-toggler:hover label,.bx-suggest-toggler:focus label{background:#006fbe}.bx-suggest-toggler[bx-open] span{transform:rotate(90deg)}.bx-suggest-toggler[bx-open]+ .bx-suggest-box{display:block}.bx-suggest-box{display:none}.bx-suggest-wrapper{display:flex;flex-direction:column;gap:10px;margin:10px}.bx-suggest-note{font-size:11px;color:#8c8c8c;font-style:italic;font-weight:100}.bx-suggest-link{font-size:14px;display:inline-block;margin-top:4px;padding:4px}.bx-suggest-row{display:flex;flex-direction:row;gap:10px}.bx-suggest-row label{flex:1;overflow:overlay;border-radius:4px}.bx-suggest-row label .bx-suggest-label{background:#323232;padding:4px 10px;font-size:12px;text-align:left}.bx-suggest-row label .bx-suggest-value{padding:6px;font-size:14px}.bx-suggest-row label .bx-suggest-value.bx-suggest-change{background-color:var(--bx-warning-color)}.bx-suggest-row.bx-suggest-ok input{visibility:hidden}.bx-suggest-row.bx-suggest-ok .bx-suggest-label{background-color:#008114}.bx-suggest-row.bx-suggest-ok .bx-suggest-value{background-color:#13a72a}.bx-suggest-row.bx-suggest-change .bx-suggest-label{background-color:#a65e08}.bx-suggest-row.bx-suggest-change .bx-suggest-value{background-color:#d57f18}.bx-suggest-row.bx-suggest-change:hover label{cursor:pointer}.bx-suggest-row.bx-suggest-change:hover .bx-suggest-label{background-color:#995707}.bx-suggest-row.bx-suggest-change:hover .bx-suggest-value{background-color:#bd7115}.bx-suggest-row.bx-suggest-change input:not(:checked) + label{opacity:.5}.bx-suggest-row.bx-suggest-change input:not(:checked) + label .bx-suggest-label{background-color:#2a2a2a}.bx-suggest-row.bx-suggest-change input:not(:checked) + label .bx-suggest-value{background-color:#393939}.bx-suggest-row.bx-suggest-change:hover input:not(:checked) + label{opacity:1}.bx-suggest-row.bx-suggest-change:hover input:not(:checked) + label .bx-suggest-label{background-color:#202020}.bx-suggest-row.bx-suggest-change:hover input:not(:checked) + label .bx-suggest-value{background-color:#303030}.bx-sub-content-box{background:#161616;padding:10px;box-shadow:0 0 12px #0f0f0f inset;border-radius:10px}.bx-settings-row .bx-sub-content-box{background:#202020;padding:12px;box-shadow:0 0 4px #000 inset;border-radius:6px}.bx-controller-extra-settings[data-has-gamepad=true] > :first-child{display:none}.bx-controller-extra-settings[data-has-gamepad=true] > :last-child{display:block}.bx-controller-extra-settings[data-has-gamepad=false] > :first-child{display:block}.bx-controller-extra-settings[data-has-gamepad=false] > :last-child{display:none}.bx-controller-extra-settings .bx-controller-extra-wrapper{flex:1;min-width:1px}.bx-controller-extra-settings .bx-sub-content-box{flex:1;text-align:left;display:flex;flex-direction:column;margin-top:10px}.bx-controller-extra-settings .bx-sub-content-box > label{font-size:14px}.bx-preset-row{display:flex;gap:8px}.bx-preset-row .bx-select{flex:1}.bx-stream-settings-selection{margin-bottom:8px;position:sticky;z-index:1000;top:0}.bx-stream-settings-selection > div{display:flex;gap:8px;background:#222;padding:10px;border-bottom:4px solid #353638;box-shadow:0 0 6px #000;position:relative;z-index:1}.bx-stream-settings-selection > div .bx-select{flex:1}.bx-stream-settings-selection > div .bx-select label{font-weight:bold;font-size:1.1rem;line-height:initial}.bx-stream-settings-selection > div .bx-select label span{line-height:initial}.bx-stream-settings-selection > div .bx-select .bx-select-indicators{display:none}.bx-stream-settings-selection p{font-family:var(--bx-promptfont-font),var(--bx-normal-font);margin:0;font-size:13px;background:rgba(80,80,80,0.949);height:25px;line-height:23px;position:absolute;bottom:-25px;left:0;right:0;text-shadow:0 1px #000}.bx-toast{user-select:none;-webkit-user-select:none;position:fixed;left:50%;top:24px;transform:translate(-50%,0);background:#212121;border-radius:10px;color:#fff;z-index:var(--bx-toast-z-index);font-family:var(--bx-normal-font);border:2px solid #fff;display:flex;align-items:center;opacity:0;overflow:clip;transition:opacity .2s ease-in;box-shadow:0 0 6px #000}.bx-toast.bx-show{opacity:.95}.bx-toast.bx-hide{opacity:0;pointer-events:none}.bx-toast-msg{font-size:14px;display:inline-block;padding:12px 16px;white-space:pre}.bx-toast-status{font-weight:bold;font-size:14px;text-transform:uppercase;display:inline-block;background:#fff;padding:12px 16px;color:#212121;white-space:pre}.bx-wait-time-box{position:fixed;top:0;right:0;background-color:rgba(0,0,0,0.8);color:#fff;z-index:var(--bx-wait-time-box-z-index);padding:12px;border-radius:0 0 0 8px}.bx-wait-time-box label{display:block;text-transform:uppercase;text-align:right;font-size:12px;font-weight:bold;margin:0}.bx-wait-time-box span{display:block;font-family:var(--bx-monospaced-font);text-align:right;font-size:16px;margin-bottom:10px}.bx-wait-time-box span:last-of-type{margin-bottom:0}.bx-remote-play-settings{margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid #2d2d2d}.bx-remote-play-settings > div{display:flex}.bx-remote-play-settings label{flex:1;font-size:14px}.bx-remote-play-settings label p{margin:4px 0 0;padding:0;color:#888;font-size:12px}.bx-remote-play-resolution{display:block}.bx-remote-play-resolution input[type="radio"]{accent-color:var(--bx-primary-button-color);margin-right:6px}.bx-remote-play-resolution input[type="radio"]:focus{accent-color:var(--bx-primary-button-hover-color)}.bx-remote-play-device-wrapper{display:flex;margin-bottom:12px}.bx-remote-play-device-wrapper:last-child{margin-bottom:2px}.bx-remote-play-device-info{flex:1;align-self:center;padding:4px 0}.bx-remote-play-device-name{font-size:14px;font-weight:bold;display:inline-block;vertical-align:middle}.bx-remote-play-console-type{font-size:8px;background:#004c87;color:#fff;display:inline-block;border-radius:8px;padding:2px 6px;margin-left:8px;vertical-align:middle}.bx-remote-play-power-state{color:#888;font-size:12px}.bx-remote-play-connect-button{min-height:100%;margin:4px 0}.bx-remote-play-buttons{display:flex;justify-content:space-between}select.bx-select{min-height:30px}div.bx-select{display:flex;align-items:stretch;flex:0 1 auto;gap:8px}div.bx-select select:disabled ~ button{display:none}div.bx-select select:disabled ~ div{background:#131416;color:#fff;pointer-events:none}div.bx-select select:disabled ~ div .bx-select-indicators{visibility:hidden}div.bx-select > div,div.bx-select button.bx-select-value{min-width:120px;text-align:left;line-height:24px;vertical-align:middle;background:#fff;color:#000;border-radius:4px;padding:2px 8px;display:flex;flex:1;flex-direction:column}div.bx-select > div{min-height:24px}div.bx-select > div input{display:inline-block;margin-right:8px}div.bx-select > div label{margin-bottom:0;font-size:14px;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;min-height:15px}div.bx-select > div label span{display:block;font-size:10px;font-weight:bold;text-align:left;line-height:20px;white-space:pre;min-height:15px;align-content:center}div.bx-select button.bx-select-value{border:none;cursor:pointer;min-height:30px;font-size:.9rem;align-items:center}div.bx-select button.bx-select-value > div{display:flex;width:100%}div.bx-select button.bx-select-value span{flex:1;text-align:left;display:inline-block}div.bx-select button.bx-select-value input{margin:0 4px;accent-color:var(--bx-primary-button-color);pointer-events:none}div.bx-select button.bx-select-value:hover input,div.bx-select button.bx-select-value:focus input{accent-color:var(--bx-danger-button-color)}div.bx-select button.bx-select-value:hover::after,div.bx-select button.bx-select-value:focus::after{border-color:#4d4d4d !important}div.bx-select button.bx-button{border:none;width:24px;height:auto;padding:0;color:#fff;border-radius:4px;font-weight:bold;font-size:12px;font-family:var(--bx-monospaced-font);flex-shrink:0}div.bx-select button.bx-button span{line-height:unset}div.bx-select[data-controller-friendly=true] > div{box-sizing:content-box}div.bx-select[data-controller-friendly=true] select{position:absolute !important;top:-9999px !important;left:-9999px !important;visibility:hidden !important}div.bx-select[data-controller-friendly=false]{position:relative}div.bx-select[data-controller-friendly=false] > div{box-sizing:border-box}div.bx-select[data-controller-friendly=false] > div label{margin-right:24px}div.bx-select[data-controller-friendly=false] select:disabled{display:none}div.bx-select[data-controller-friendly=false] select:not(:disabled){cursor:pointer;position:absolute;top:0;right:0;bottom:0;display:block;opacity:0;z-index:calc(var(--bx-settings-z-index) + 1)}div.bx-select[data-controller-friendly=false] select:not(:disabled):hover + div{background:#f0f0f0}div.bx-select[data-controller-friendly=false] select:not(:disabled) + div label::after{content:\'▾\';font-size:14px;position:absolute;right:8px;pointer-events:none}.bx-select-indicators{display:flex;height:4px;gap:2px;margin-bottom:2px}.bx-select-indicators span{content:\' \';display:inline-block;flex:1;background:#cfcfcf;border-radius:4px;min-width:1px}.bx-select-indicators span[data-highlighted]{background:#9c9c9c;min-width:6px}.bx-select-indicators span[data-selected]{background:#aacfe7}.bx-select-indicators span[data-highlighted][data-selected]{background:#5fa3d0}.bx-guide-home-achievements-progress{display:flex;gap:10px;flex-direction:row}.bx-guide-home-achievements-progress .bx-button{margin-bottom:0 !important}body[data-bx-media-type=tv] .bx-guide-home-achievements-progress{flex-direction:column}body:not([data-bx-media-type=tv]) .bx-guide-home-achievements-progress{flex-direction:row}body:not([data-bx-media-type=tv]) .bx-guide-home-achievements-progress > button:first-of-type{flex:1}body:not([data-bx-media-type=tv]) .bx-guide-home-achievements-progress > button:last-of-type{width:40px}body:not([data-bx-media-type=tv]) .bx-guide-home-achievements-progress > button:last-of-type span{display:none}.bx-guide-home-buttons > div{display:flex;flex-direction:row;gap:12px}body[data-bx-media-type=tv] .bx-guide-home-buttons > div{flex-direction:column}body[data-bx-media-type=tv] .bx-guide-home-buttons > div button{margin-bottom:0 !important}body:not([data-bx-media-type=tv]) .bx-guide-home-buttons > div button span{display:none}.bx-guide-home-buttons[data-is-playing="true"] button[data-state=\'normal\']{display:none}.bx-guide-home-buttons[data-is-playing="false"] button[data-state=\'playing\']{display:none}div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module]{overflow:visible}.bx-stream-menu-button-on{fill:#000 !important;background-color:#2d2d2d !important;color:#000 !important}.bx-stream-refresh-button{top:calc(env(safe-area-inset-top, 0px) + 10px + 50px) !important}body[data-media-type=default] .bx-stream-refresh-button{left:calc(env(safe-area-inset-left, 0px) + 11px) !important}body[data-media-type=tv] .bx-stream-refresh-button{top:calc(var(--gds-focus-borderSize) + 80px) !important}.bx-stream-home-button{top:calc(env(safe-area-inset-top, 0px) + 10px + 50px * 2) !important}body[data-media-type=default] .bx-stream-home-button{left:calc(env(safe-area-inset-left, 0px) + 12px) !important}body[data-media-type=tv] .bx-stream-home-button{top:calc(var(--gds-focus-borderSize) + 80px * 2) !important}div[data-testid=media-container][data-position=center]{display:flex}div[data-testid=media-container][data-position=top] video,div[data-testid=media-container][data-position=top] canvas{top:0}div[data-testid=media-container][data-position=bottom] video,div[data-testid=media-container][data-position=bottom] canvas{bottom:0}#game-stream video{margin:auto;align-self:center;background:#000;position:absolute;left:0;right:0}#game-stream canvas{align-self:center;margin:auto;position:absolute;left:0;right:0}#game-stream.bx-taking-screenshot:before{animation:bx-anim-taking-screenshot .5s ease;content:\' \';position:absolute;width:100%;height:100%;z-index:var(--bx-screenshot-animation-z-index)}#gamepass-dialog-root div[class^=Guide-module__guide] .bx-button{overflow:visible;margin-bottom:12px}@-moz-keyframes bx-anim-taking-screenshot{0%{border:0 solid rgba(255,255,255,0.502)}50%{border:8px solid rgba(255,255,255,0.502)}100%{border:0 solid rgba(255,255,255,0.502)}}@-webkit-keyframes bx-anim-taking-screenshot{0%{border:0 solid rgba(255,255,255,0.502)}50%{border:8px solid rgba(255,255,255,0.502)}100%{border:0 solid rgba(255,255,255,0.502)}}@-o-keyframes bx-anim-taking-screenshot{0%{border:0 solid rgba(255,255,255,0.502)}50%{border:8px solid rgba(255,255,255,0.502)}100%{border:0 solid rgba(255,255,255,0.502)}}@keyframes bx-anim-taking-screenshot{0%{border:0 solid rgba(255,255,255,0.502)}50%{border:8px solid rgba(255,255,255,0.502)}100%{border:0 solid rgba(255,255,255,0.502)}}.bx-number-stepper{text-align:center}.bx-number-stepper > div{display:flex;align-items:center}.bx-number-stepper > div span{flex:1;display:inline-block;min-width:40px;font-family:var(--bx-monospaced-font);white-space:pre;font-size:13px;margin:0 4px}.bx-number-stepper > div button{flex-shrink:0;border:none;width:24px;height:24px;margin:0;line-height:24px;background-color:var(--bx-default-button-color);color:#fff;border-radius:4px;font-weight:bold;font-size:14px;font-family:var(--bx-monospaced-font)}@media (hover:hover){.bx-number-stepper > div button:hover{background-color:var(--bx-default-button-hover-color)}}.bx-number-stepper > div button:active{background-color:var(--bx-default-button-hover-color)}.bx-number-stepper > div button:disabled + span{font-family:var(--bx-title-font)}.bx-number-stepper input[type=range]{display:block;margin:8px 0 2px auto;min-width:180px;width:100%;color:#959595 !important}.bx-number-stepper input[type=range]:disabled,.bx-number-stepper button:disabled{display:none}.bx-number-stepper[data-disabled=true] input[type=range],.bx-number-stepper[disabled=true] input[type=range],.bx-number-stepper[data-disabled=true] button,.bx-number-stepper[disabled=true] button{display:none}.bx-dual-number-stepper > span{display:block;font-family:var(--bx-monospaced-font);font-size:13px;white-space:pre;margin:0 4px;text-align:center}.bx-dual-number-stepper > div input[type=range]{display:block;width:100%;min-width:180px;background:transparent;color:#959595 !important;appearance:none;padding:8px 0}.bx-dual-number-stepper > div input[type=range]::-webkit-slider-runnable-track{background:linear-gradient(90deg,#fff var(--from),var(--bx-primary-button-color) var(--from) var(--to),#fff var(--to) 100%);height:8px;border-radius:2px}.bx-dual-number-stepper > div input[type=range]::-moz-range-track{background:linear-gradient(90deg,#fff var(--from),var(--bx-primary-button-color) var(--from) var(--to),#fff var(--to) 100%);height:8px;border-radius:2px}.bx-dual-number-stepper > div input[type=range]::-webkit-slider-thumb{margin-top:-4px;appearance:none;width:4px;height:16px;background:#00b85f;border:none;border-radius:2px}.bx-dual-number-stepper > div input[type=range]::-moz-range-thumb{margin-top:-4px;appearance:none;width:4px;height:16px;background:#00b85f;border:none;border-radius:2px}.bx-dual-number-stepper > div input[type=range]:hover::-webkit-slider-runnable-track,.bx-dual-number-stepper > div input[type=range].bx-dual-number-stepper > div input[type=range]:active::-webkit-slider-runnable-track,.bx-dual-number-stepper > div input[type=range]:focus::-webkit-slider-runnable-track{background:linear-gradient(90deg,#fff var(--from),#006635 var(--from) var(--to),#fff var(--to) 100%)}.bx-dual-number-stepper > div input[type=range]:hover::-moz-range-track,.bx-dual-number-stepper > div input[type=range].bx-dual-number-stepper > div input[type=range]:active::-moz-range-track,.bx-dual-number-stepper > div input[type=range]:focus::-moz-range-track{background:linear-gradient(90deg,#fff var(--from),#006635 var(--from) var(--to),#fff var(--to) 100%)}.bx-dual-number-stepper > div input[type=range]:hover::-webkit-slider-thumb,.bx-dual-number-stepper > div input[type=range].bx-dual-number-stepper > div input[type=range]:active::-webkit-slider-thumb,.bx-dual-number-stepper > div input[type=range]:focus::-webkit-slider-thumb{background:#fb3232}.bx-dual-number-stepper > div input[type=range]:hover::-moz-range-thumb,.bx-dual-number-stepper > div input[type=range].bx-dual-number-stepper > div input[type=range]:active::-moz-range-thumb,.bx-dual-number-stepper > div input[type=range]:focus::-moz-range-thumb{background:#fb3232}.bx-dual-number-stepper[data-disabled=true] input[type=range],.bx-dual-number-stepper[disabled=true] input[type=range]{display:none}#bx-game-bar{z-index:var(--bx-game-bar-z-index);position:fixed;bottom:0;width:40px;height:90px;overflow:visible;cursor:pointer}#bx-game-bar > svg{display:none;pointer-events:none;position:absolute;height:28px;margin-top:16px}@media (hover:hover){#bx-game-bar:hover > svg{display:block}}#bx-game-bar .bx-game-bar-container{opacity:0;position:absolute;display:flex;overflow:hidden;background:rgba(26,27,30,0.91);box-shadow:0 0 6px #1c1c1c;transition:opacity .1s ease-in}#bx-game-bar .bx-game-bar-container.bx-show{opacity:.9}#bx-game-bar .bx-game-bar-container.bx-show + svg{display:none !important}#bx-game-bar .bx-game-bar-container.bx-hide{opacity:0;pointer-events:none}#bx-game-bar .bx-game-bar-container button{width:60px;height:60px;border-radius:0}#bx-game-bar .bx-game-bar-container button svg{width:28px;height:28px;transition:transform .08s ease 0s}#bx-game-bar .bx-game-bar-container button:hover{border-radius:0}#bx-game-bar .bx-game-bar-container button:active svg{transform:scale(.75)}#bx-game-bar .bx-game-bar-container button.bx-activated{background-color:#fff}#bx-game-bar .bx-game-bar-container button.bx-activated svg{filter:invert(1)}#bx-game-bar .bx-game-bar-container div[data-activated] button{display:none}#bx-game-bar .bx-game-bar-container div[data-activated=\'false\'] button:first-of-type{display:block}#bx-game-bar .bx-game-bar-container div[data-activated=\'true\'] button:last-of-type{display:block}#bx-game-bar[data-position="bottom-left"]{left:0;direction:ltr}#bx-game-bar[data-position="bottom-left"] .bx-game-bar-container{border-radius:0 10px 10px 0}#bx-game-bar[data-position="bottom-right"]{right:0;direction:rtl}#bx-game-bar[data-position="bottom-right"] .bx-game-bar-container{direction:ltr;border-radius:10px 0 0 10px}.bx-badges{margin-left:0;user-select:none;-webkit-user-select:none}.bx-badge{border:none;display:inline-block;line-height:24px;color:#fff;font-family:var(--bx-title-font-semibold);font-size:14px;font-weight:400;margin:0 8px 8px 0;box-shadow:0 0 6px #000;border-radius:4px}.bx-badge-name{background-color:#2d3036;border-radius:4px 0 0 4px}.bx-badge-name svg{width:16px;height:16px}.bx-badge-value{background-color:#808080;border-radius:0 4px 4px 0}.bx-badge-name,.bx-badge-value{display:inline-block;padding:0 8px;line-height:30px;vertical-align:bottom}.bx-badge-battery[data-charging=true] span:first-of-type::after{content:\' ⚡️\'}div[class^=StreamMenu-module__container] .bx-badges{position:absolute;max-width:500px}#gamepass-dialog-root .bx-badges{position:fixed;top:60px;left:460px;max-width:500px}@media (min-width:568px) and (max-height:480px){#gamepass-dialog-root .bx-badges{position:unset;top:unset;left:unset;margin:8px 0}}.bx-stats-bar{display:flex;flex-direction:row;gap:8px;user-select:none;-webkit-user-select:none;position:fixed;top:0;background-color:#000;color:#fff;font-family:var(--bx-monospaced-font);font-size:.9rem;padding-left:8px;z-index:var(--bx-stats-bar-z-index);text-wrap:nowrap}.bx-stats-bar[data-stats*="[time]"] > .bx-stat-time,.bx-stats-bar[data-stats*="[play]"] > .bx-stat-play,.bx-stats-bar[data-stats*="[batt]"] > .bx-stat-batt,.bx-stats-bar[data-stats*="[fps]"] > .bx-stat-fps,.bx-stats-bar[data-stats*="[ping]"] > .bx-stat-ping,.bx-stats-bar[data-stats*="[jit]"] > .bx-stat-jit,.bx-stats-bar[data-stats*="[btr]"] > .bx-stat-btr,.bx-stats-bar[data-stats*="[dt]"] > .bx-stat-dt,.bx-stats-bar[data-stats*="[pl]"] > .bx-stat-pl,.bx-stats-bar[data-stats*="[fl]"] > .bx-stat-fl,.bx-stats-bar[data-stats*="[dl]"] > .bx-stat-dl,.bx-stats-bar[data-stats*="[ul]"] > .bx-stat-ul{display:inline-flex;align-items:baseline}.bx-stats-bar[data-stats$="[time]"] > .bx-stat-time,.bx-stats-bar[data-stats$="[play]"] > .bx-stat-play,.bx-stats-bar[data-stats$="[batt]"] > .bx-stat-batt,.bx-stats-bar[data-stats$="[fps]"] > .bx-stat-fps,.bx-stats-bar[data-stats$="[ping]"] > .bx-stat-ping,.bx-stats-bar[data-stats$="[jit]"] > .bx-stat-jit,.bx-stats-bar[data-stats$="[btr]"] > .bx-stat-btr,.bx-stats-bar[data-stats$="[dt]"] > .bx-stat-dt,.bx-stats-bar[data-stats$="[pl]"] > .bx-stat-pl,.bx-stats-bar[data-stats$="[fl]"] > .bx-stat-fl,.bx-stats-bar[data-stats$="[dl]"] > .bx-stat-dl,.bx-stats-bar[data-stats$="[ul]"] > .bx-stat-ul{border-right:none}.bx-stats-bar::before{display:none;content:\'👀\';vertical-align:middle;margin-right:8px}.bx-stats-bar[data-display=glancing]::before{display:inline-block}.bx-stats-bar[data-position=top-left]{left:0;border-radius:0 0 4px 0}.bx-stats-bar[data-position=top-right]{right:0;border-radius:0 0 0 4px}.bx-stats-bar[data-position=top-center]{transform:translate(-50%,0);left:50%;border-radius:0 0 4px 4px}.bx-stats-bar[data-shadow=true]{background:none;filter:drop-shadow(1px 0 0 rgba(0,0,0,0.941)) drop-shadow(-1px 0 0 rgba(0,0,0,0.941)) drop-shadow(0 1px 0 rgba(0,0,0,0.941)) drop-shadow(0 -1px 0 rgba(0,0,0,0.941))}.bx-stats-bar > div{display:none;border-right:1px solid #fff;padding-right:8px}.bx-stats-bar label{margin:0 8px 0 0;font-family:var(--bx-title-font);font-size:70%;font-weight:bold;vertical-align:middle;cursor:help}.bx-stats-bar span{display:inline-block;text-align:right;vertical-align:middle;white-space:pre}.bx-stats-bar span[data-grade=good]{color:#6bffff}.bx-stats-bar span[data-grade=ok]{color:#fff16b}.bx-stats-bar span[data-grade=bad]{color:#ff5f5f}.bx-mkb-settings{display:flex;flex-direction:column;flex:1;padding-bottom:10px;overflow:hidden}.bx-mkb-pointer-lock-msg{user-select:none;-webkit-user-select:none;position:fixed;left:50%;bottom:40px;transform:translateX(-50%);margin:auto;background:#151515;z-index:var(--bx-mkb-pointer-lock-msg-z-index);color:#fff;font-weight:400;font-family:"Segoe UI",Arial,Helvetica,sans-serif;font-size:1.3rem;padding:12px;border-radius:8px;align-items:center;box-shadow:0 0 6px #000;min-width:300px;opacity:.9;display:flex;flex-direction:column;gap:10px}.bx-mkb-pointer-lock-msg:hover{opacity:1}.bx-mkb-pointer-lock-msg > p{margin:0;width:100%;font-size:22px;margin-bottom:4px;font-weight:bold;text-align:left}.bx-mkb-pointer-lock-msg > div{width:100%;display:flex;flex-direction:row;gap:10px}.bx-mkb-pointer-lock-msg > div button:first-of-type{flex-shrink:1}.bx-mkb-pointer-lock-msg > div button:last-of-type{flex-grow:1}.bx-mkb-key-row{display:flex;margin-bottom:10px;align-items:center;gap:20px}.bx-mkb-key-row label{margin-bottom:0;font-family:var(--bx-promptfont-font);font-size:32px;text-align:center}.bx-mkb-settings.bx-editing .bx-mkb-key-row button{background:#393939;border-radius:4px;border:none}.bx-mkb-settings.bx-editing .bx-mkb-key-row button:hover{background:#333;cursor:pointer}.bx-mkb-action-buttons > div{text-align:right;display:none}.bx-mkb-action-buttons button{margin-left:8px}.bx-mkb-settings:not(.bx-editing) .bx-mkb-action-buttons > div:first-child{display:block}.bx-mkb-settings.bx-editing .bx-mkb-action-buttons > div:last-child{display:block}.bx-mkb-note{display:block;margin:0 0 10px;font-size:12px;text-align:center}button.bx-binding-button{flex:1;min-height:38px;border:none;border-radius:4px;font-size:14px;color:#fff;display:flex;align-items:center;align-self:center;padding:0 6px}button.bx-binding-button:disabled{background:#131416;padding:0 8px}button.bx-binding-button:not(:disabled){border:2px solid transparent;border-top:none;border-bottom:4px solid #252525;background:#3b3b3b;cursor:pointer}button.bx-binding-button:not(:disabled):hover,button.bx-binding-button:not(:disabled).bx-focusable:focus{background:#20b217;border-bottom-color:#186c13}button.bx-binding-button:not(:disabled):active{background:#16900f;border-bottom:3px solid #0c4e08;border-left-width:2px;border-right-width:2px}button.bx-binding-button:not(:disabled).bx-focusable:focus::after{top:-6px;left:-8px;right:-8px;bottom:-10px}.bx-settings-row .bx-binding-button-wrapper button.bx-binding-button{min-width:60px}.bx-controller-customizations-container .bx-btn-detect{display:block;margin-bottom:20px}.bx-controller-customizations-container .bx-btn-detect.bx-monospaced{background:none;font-weight:bold;font-size:12px}.bx-controller-customizations-container .bx-buttons-grid{display:grid;grid-template-columns:auto auto;column-gap:20px;row-gap:10px;margin-bottom:20px}.bx-controller-key-row{display:flex;align-items:stretch}.bx-controller-key-row > label{margin-bottom:0;font-family:var(--bx-promptfont-font);font-size:32px;text-align:center;min-width:50px;flex-shrink:0;display:flex;align-self:center}.bx-controller-key-row > label::after{content:\'❯\';margin:0 12px;font-size:16px;align-self:center}.bx-controller-key-row .bx-select{width:100% !important}.bx-controller-key-row .bx-select > div{min-width:50px}.bx-controller-key-row .bx-select label{font-family:var(--bx-promptfont-font),var(--bx-normal-font);font-size:32px;text-align:center;margin-bottom:6px;height:40px;line-height:40px}.bx-controller-key-row:hover > label{color:#ffe64b}.bx-controller-key-row:hover > label::after{color:#fff}.bx-controller-customization-summary{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:10px}.bx-controller-customization-summary span{font-family:var(--bx-promptfont);font-size:24px;border-radius:6px;background:#131313;color:#fff;display:inline-block;padding:2px;text-align:center}.bx-product-details-icons{padding:8px;border-radius:4px}.bx-product-details-icons svg{margin-right:8px}.bx-product-details-buttons{display:flex;gap:10px;flex-direction:row}.bx-product-details-buttons button{max-width:max-content;margin:10px 0 0 0;display:flex}@media (min-width:568px) and (max-height:480px){.bx-product-details-buttons{flex-direction:column}.bx-product-details-buttons button{margin:8px 0 0 10px}}', PREF_HIDE_SECTIONS = getGlobalPref("ui.hideSections"), selectorToHide = [];if (PREF_HIDE_SECTIONS.includes("news")) selectorToHide.push("#BodyContent > div[class*=CarouselRow-module]");if (getGlobalPref("block.features").includes("byog")) selectorToHide.push("#BodyContent > div[class*=ByogRow-module__container___]");if (PREF_HIDE_SECTIONS.includes("all-games")) selectorToHide.push("#BodyContent div[class*=AllGamesRow-module__gridContainer]"), selectorToHide.push("#BodyContent div[class*=AllGamesRow-module__rowHeader]");if (PREF_HIDE_SECTIONS.includes("most-popular")) selectorToHide.push('#BodyContent div[class*=HomePage-module__bottomSpacing]:has(a[href="/play/gallery/popular"])');if (PREF_HIDE_SECTIONS.includes("touch")) selectorToHide.push('#BodyContent div[class*=HomePage-module__bottomSpacing]:has(a[href="/play/gallery/touch"])');if (PREF_HIDE_SECTIONS.includes("recently-added")) selectorToHide.push('#BodyContent div[class*=HomePage-module__bottomSpacing]:has(a[href="/play/gallery/recently-added"])');if (PREF_HIDE_SECTIONS.includes("genres")) selectorToHide.push("#BodyContent div[class*=HomePage-module__genresRow]");if (containsAll(PREF_HIDE_SECTIONS, ["recently-added", "leaving-soon", "genres", "all-games"])) selectorToHide.push("#BodyContent div[class*=GamePassPromoSection-module__container]");if (getGlobalPref("block.features").includes("friends")) selectorToHide.push("#gamepass-dialog-root div[class^=AchievementsPreview-module__container] + button[class*=HomeLandingPage-module__button]");if (selectorToHide) css += selectorToHide.join(",") + "{ display: none; }";if (getGlobalPref("ui.reduceAnimations")) css += "div[class*=GameCard-module__gameTitleInnerWrapper],div[class*=GameCard-module__card],div[class*=ScrollArrows-module]{transition:none !important}";if (getGlobalPref("ui.systemMenu.hideHandle")) css += "div[class*=Grip-module__container]{visibility:hidden}@media (hover:hover){button[class*=GripHandle-module__container]:hover div[class*=Grip-module__container]{visibility:visible}}button[class*=GripHandle-module__container][aria-expanded=true] div[class*=Grip-module__container]{visibility:visible}button[class*=GripHandle-module__container][aria-expanded=false]{background-color:transparent !important}div[class*=StreamHUD-module__buttonsContainer]{padding:0 !important}";if (css += "div[class*=StreamMenu-module__menu]{min-width:100vw !important}", getGlobalPref("ui.streamMenu.simplify")) css += "div[class*=Menu-module__scrollable]{--bxStreamMenuItemSize:80px;--streamMenuItemSize:calc(var(--bxStreamMenuItemSize) + 40px) !important}.bx-badges{top:calc(var(--streamMenuItemSize) - 20px)}body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) - 10px) !important}button[class*=MenuItem-module__container]{min-width:auto !important;min-height:auto !important;width:var(--bxStreamMenuItemSize) !important;height:var(--bxStreamMenuItemSize) !important}div[class*=MenuItem-module__label]{display:none !important}svg[class*=MenuItem-module__icon]{width:36px;height:100% !important;padding:0 !important;margin:0 !important}";else css += "body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) + 30px)}body:not([data-media-type=tv]) .bx-badges{top:calc(var(--streamMenuItemSize) + 20px)}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]{min-width:auto !important;width:100px !important}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]:nth-child(n+2){margin-left:10px !important}body:not([data-media-type=tv]) div[class*=MenuItem-module__label]{margin-left:8px !important;margin-right:8px !important}";if (getGlobalPref("ui.hideScrollbar")) css += "html{scrollbar-width:none}body::-webkit-scrollbar{display:none}";let $style = CE("style", !1, css);document.documentElement.appendChild($style);}
+function addCss() {let css = ':root{--bx-title-font:Bahnschrift,Arial,Helvetica,sans-serif;--bx-title-font-semibold:Bahnschrift Semibold,Arial,Helvetica,sans-serif;--bx-normal-font:"Segoe UI",Arial,Helvetica,sans-serif;--bx-monospaced-font:Consolas,"Courier New",Courier,monospace;--bx-promptfont-font:promptfont;--bx-button-height:40px;--bx-default-button-color:#2d3036;--bx-default-button-rgb:45,48,54;--bx-default-button-hover-color:#515863;--bx-default-button-hover-rgb:81,88,99;--bx-default-button-active-color:#222428;--bx-default-button-active-rgb:34,36,40;--bx-default-button-disabled-color:#8e8e8e;--bx-default-button-disabled-rgb:142,142,142;--bx-primary-button-color:#008746;--bx-primary-button-rgb:0,135,70;--bx-primary-button-hover-color:#04b358;--bx-primary-button-hover-rgb:4,179,88;--bx-primary-button-active-color:#044e2a;--bx-primary-button-active-rgb:4,78,42;--bx-primary-button-disabled-color:#448262;--bx-primary-button-disabled-rgb:68,130,98;--bx-warning-button-color:#c16e04;--bx-warning-button-rgb:193,110,4;--bx-warning-button-hover-color:#fa9005;--bx-warning-button-hover-rgb:250,144,5;--bx-warning-button-active-color:#965603;--bx-warning-button-active-rgb:150,86,3;--bx-warning-button-disabled-color:#a2816c;--bx-warning-button-disabled-rgb:162,129,108;--bx-danger-button-color:#c10404;--bx-danger-button-rgb:193,4,4;--bx-danger-button-hover-color:#e61d1d;--bx-danger-button-hover-rgb:230,29,29;--bx-danger-button-active-color:#a26c6c;--bx-danger-button-active-rgb:162,108,108;--bx-danger-button-disabled-color:#bd8282;--bx-danger-button-disabled-rgb:189,130,130;--bx-fullscreen-text-z-index:9999;--bx-toast-z-index:6000;--bx-key-binding-dialog-z-index:5010;--bx-key-binding-dialog-overlay-z-index:5000;--bx-stats-bar-z-index:4010;--bx-navigation-dialog-z-index:3010;--bx-navigation-dialog-overlay-z-index:3000;--bx-mkb-pointer-lock-msg-z-index:2000;--bx-game-bar-z-index:1000;--bx-screenshot-animation-z-index:200;--bx-wait-time-box-z-index:100}@font-face{font-family:\'promptfont\';src:url("https://redphx.github.io/better-xcloud/fonts/promptfont.otf");unicode-range:U+2196-E011,U+27F6,U+FF31}div[class^=HUDButton-module__hiddenContainer] ~ div:not([class^=HUDButton-module__hiddenContainer]){opacity:0;pointer-events:none !important;position:absolute;top:-9999px;left:-9999px}@media screen and (max-width:640px){header a[href="/play"]{display:none}}.bx-full-width{width:100% !important}.bx-full-height{height:100% !important}.bx-auto-height{height:auto !important}.bx-no-scroll{overflow:hidden !important}.bx-hide-scroll-bar{scrollbar-width:none}.bx-hide-scroll-bar::-webkit-scrollbar{display:none}.bx-gone{display:none !important}.bx-offscreen{position:absolute !important;top:-9999px !important;left:-9999px !important;visibility:hidden !important}.bx-hidden{visibility:hidden !important}.bx-invisible{opacity:0}.bx-unclickable{pointer-events:none}.bx-pixel{width:1px !important;height:1px !important}.bx-no-margin{margin:0 !important}.bx-no-padding{padding:0 !important}.bx-prompt{font-family:var(--bx-promptfont-font) !important}.bx-monospaced{font-family:var(--bx-monospaced-font) !important}.bx-line-through{text-decoration:line-through !important}.bx-normal-case{text-transform:none !important}.bx-normal-link{text-transform:none !important;text-align:left !important;font-weight:400 !important;font-family:var(--bx-normal-font) !important}.bx-frosted{backdrop-filter:blur(4px) brightness(1.5)}select[multiple],select[multiple]:focus{overflow:auto;border:none}select[multiple] option,select[multiple]:focus option{padding:4px 6px}select[multiple] option:checked,select[multiple]:focus option:checked{background:#1a7bc0 linear-gradient(0deg,#1a7bc0 0%,#1a7bc0 100%)}select[multiple] option:checked::before,select[multiple]:focus option:checked::before{content:\'☑️\';font-size:12px;display:inline-block;margin-right:6px;height:100%;line-height:100%;vertical-align:middle}#headerArea,#uhfSkipToMain,.uhf-footer{display:none}div[class*=NotFocusedDialog]{position:absolute !important;top:-9999px !important;left:-9999px !important;width:0 !important;height:0 !important}#game-stream video:not([src]){visibility:hidden}.bx-game-tile-wait-time{position:absolute;top:0;left:0;z-index:1;background:rgba(0,0,0,0.5);display:flex;border-radius:4px 0 4px 0;align-items:center;padding:4px 8px}.bx-game-tile-wait-time svg{width:14px;height:16px;margin-right:2px}.bx-game-tile-wait-time span{display:inline-block;height:16px;line-height:16px;font-size:12px;font-weight:bold;margin-left:2px}.bx-game-tile-wait-time[data-duration=short]{background-color:rgba(0,133,133,0.75)}.bx-game-tile-wait-time[data-duration=medium]{background-color:rgba(213,133,0,0.75)}.bx-game-tile-wait-time[data-duration=long]{background-color:rgba(150,0,0,0.75)}.bx-fullscreen-text{position:fixed;top:0;bottom:0;left:0;right:0;background:rgba(0,0,0,0.8);z-index:var(--bx-fullscreen-text-z-index);line-height:100vh;color:#fff;text-align:center;font-weight:400;font-family:var(--bx-normal-font);font-size:1.3rem;user-select:none;-webkit-user-select:none}#root section[class*=DeviceCodePage-module__page]{margin-left:20px !important;margin-right:20px !important;margin-top:20px !important;max-width:800px !important}#root div[class*=DeviceCodePage-module__back]{display:none}.bx-blink-me{animation:bx-blinker 1s linear infinite}.bx-horizontal-shaking{animation:bx-horizontal-shaking .4s ease-in-out 2}@-moz-keyframes bx-blinker{100%{opacity:0}}@-webkit-keyframes bx-blinker{100%{opacity:0}}@-o-keyframes bx-blinker{100%{opacity:0}}@keyframes bx-blinker{100%{opacity:0}}@-moz-keyframes bx-horizontal-shaking{0%{transform:translateX(0)}25%{transform:translateX(5px)}50%{transform:translateX(-5px)}75%{transform:translateX(5px)}100%{transform:translateX(0)}}@-webkit-keyframes bx-horizontal-shaking{0%{transform:translateX(0)}25%{transform:translateX(5px)}50%{transform:translateX(-5px)}75%{transform:translateX(5px)}100%{transform:translateX(0)}}@-o-keyframes bx-horizontal-shaking{0%{transform:translateX(0)}25%{transform:translateX(5px)}50%{transform:translateX(-5px)}75%{transform:translateX(5px)}100%{transform:translateX(0)}}@keyframes bx-horizontal-shaking{0%{transform:translateX(0)}25%{transform:translateX(5px)}50%{transform:translateX(-5px)}75%{transform:translateX(5px)}100%{transform:translateX(0)}}.bx-button{--button-rgb:var(--bx-default-button-rgb);--button-hover-rgb:var(--bx-default-button-hover-rgb);--button-active-rgb:var(--bx-default-button-active-rgb);--button-disabled-rgb:var(--bx-default-button-disabled-rgb);background-color:rgb(var(--button-rgb));user-select:none;-webkit-user-select:none;color:#fff;font-family:var(--bx-title-font-semibold);font-size:14px;border:none;font-weight:400;height:var(--bx-button-height);border-radius:4px;padding:0 8px;text-transform:uppercase;cursor:pointer;overflow:hidden}.bx-button:not([disabled]):active{background-color:rgb(var(--button-active-rgb))}.bx-button:focus{outline:none !important}.bx-button:not([disabled]):not(:active):hover,.bx-button:not([disabled]):not(:active).bx-focusable:focus{background-color:rgb(var(--button-hover-rgb))}.bx-button:disabled{cursor:default;background-color:rgb(var(--button-disabled-rgb));opacity:.5}.bx-button.bx-ghost{background-color:transparent}.bx-button.bx-ghost:not([disabled]):not(:active):hover,.bx-button.bx-ghost:not([disabled]):not(:active).bx-focusable:focus{background-color:rgb(var(--button-hover-rgb))}.bx-button.bx-primary{--button-rgb:var(--bx-primary-button-rgb)}.bx-button.bx-primary:not([disabled]):active{--button-active-rgb:var(--bx-primary-button-active-rgb)}.bx-button.bx-primary:not([disabled]):not(:active):hover,.bx-button.bx-primary:not([disabled]):not(:active).bx-focusable:focus{--button-hover-rgb:var(--bx-primary-button-hover-rgb)}.bx-button.bx-primary:disabled{--button-disabled-rgb:var(--bx-primary-button-disabled-rgb)}.bx-button.bx-warning{--button-rgb:var(--bx-warning-button-rgb)}.bx-button.bx-warning:not([disabled]):active{--button-active-rgb:var(--bx-warning-button-active-rgb)}.bx-button.bx-warning:not([disabled]):not(:active):hover,.bx-button.bx-warning:not([disabled]):not(:active).bx-focusable:focus{--button-hover-rgb:var(--bx-warning-button-hover-rgb)}.bx-button.bx-warning:disabled{--button-disabled-rgb:var(--bx-warning-button-disabled-rgb)}.bx-button.bx-danger{--button-rgb:var(--bx-danger-button-rgb)}.bx-button.bx-danger:not([disabled]):active{--button-active-rgb:var(--bx-danger-button-active-rgb)}.bx-button.bx-danger:not([disabled]):not(:active):hover,.bx-button.bx-danger:not([disabled]):not(:active).bx-focusable:focus{--button-hover-rgb:var(--bx-danger-button-hover-rgb)}.bx-button.bx-danger:disabled{--button-disabled-rgb:var(--bx-danger-button-disabled-rgb)}.bx-button.bx-frosted{--button-alpha:.2;background-color:rgba(var(--button-rgb), var(--button-alpha))}.bx-button.bx-frosted:not([disabled]):not(:active):hover,.bx-button.bx-frosted:not([disabled]):not(:active).bx-focusable:focus{background-color:rgba(var(--button-hover-rgb), var(--button-alpha))}.bx-button.bx-drop-shadow{box-shadow:0 0 4px rgba(0,0,0,0.502)}.bx-button.bx-tall{height:calc(var(--bx-button-height) * 1.5) !important}.bx-button.bx-circular{border-radius:var(--bx-button-height);width:var(--bx-button-height);height:var(--bx-button-height)}.bx-button svg{display:inline-block;width:16px;height:var(--bx-button-height)}.bx-button span{display:inline-block;line-height:var(--bx-button-height);vertical-align:middle;color:#fff;overflow:hidden;white-space:nowrap}.bx-button span:not(:only-child){margin-inline-start:8px}.bx-button.bx-button-multi-lines{height:auto;text-align:left;padding:10px}.bx-button.bx-button-multi-lines span{line-height:unset;display:block}.bx-button.bx-button-multi-lines span:last-of-type{text-transform:none;font-weight:normal;font-family:"Segoe Sans Variable Text";font-size:12px;margin-top:4px}.bx-focusable{position:relative;overflow:visible}.bx-focusable::after{border:2px solid transparent;border-radius:10px}.bx-focusable:focus::after{content:\'\';border-color:#fff;position:absolute;top:-6px;left:-6px;right:-6px;bottom:-6px}html[data-active-input=touch] .bx-focusable:focus::after,html[data-active-input=mouse] .bx-focusable:focus::after{border-color:transparent !important}.bx-focusable.bx-circular::after{border-radius:var(--bx-button-height)}a.bx-button{display:inline-block}a.bx-button.bx-full-width{text-align:center}button.bx-inactive{pointer-events:none;opacity:.2;background:transparent !important}.bx-header-remote-play-button{height:auto;margin-right:8px !important}.bx-header-remote-play-button svg{width:24px;height:24px}.bx-header-settings-button{line-height:30px;font-size:14px;text-transform:uppercase;position:relative}.bx-header-settings-button[data-update-available]::before{content:\'🌟\' !important;line-height:var(--bx-button-height);display:inline-block;margin-left:4px}.bx-key-binding-dialog-overlay{position:fixed;inset:0;z-index:var(--bx-key-binding-dialog-overlay-z-index);background:#000;opacity:50%}.bx-key-binding-dialog{display:flex;flex-flow:column;max-height:90vh;position:fixed;top:50%;left:50%;margin-right:-50%;transform:translate(-50%,-50%);min-width:420px;padding:16px;border-radius:8px;z-index:var(--bx-key-binding-dialog-z-index);background:#1a1b1e;color:#fff;font-weight:400;font-size:16px;font-family:var(--bx-normal-font);box-shadow:0 0 6px #000;user-select:none;-webkit-user-select:none}.bx-key-binding-dialog *:focus{outline:none !important}.bx-key-binding-dialog h2{margin-bottom:12px;color:#fff;display:block;font-family:var(--bx-title-font);font-size:32px;font-weight:400;line-height:var(--bx-button-height)}.bx-key-binding-dialog > div{overflow:auto;padding:2px 0}.bx-key-binding-dialog > button{padding:8px 32px;margin:10px auto 0;border:none;border-radius:4px;display:block;background-color:#2d3036;text-align:center;color:#fff;text-transform:uppercase;font-family:var(--bx-title-font);font-weight:400;line-height:18px;font-size:14px}@media (hover:hover){.bx-key-binding-dialog > button:hover{background-color:#515863}}.bx-key-binding-dialog > button:focus{background-color:#515863}.bx-key-binding-dialog ul{margin-bottom:1rem}.bx-key-binding-dialog ul li{display:none}.bx-key-binding-dialog ul[data-flags*="[1]"] > li[data-flag="1"],.bx-key-binding-dialog ul[data-flags*="[2]"] > li[data-flag="2"],.bx-key-binding-dialog ul[data-flags*="[4]"] > li[data-flag="4"],.bx-key-binding-dialog ul[data-flags*="[8]"] > li[data-flag="8"]{display:list-item}@media screen and (max-width:450px){.bx-key-binding-dialog{min-width:100%}}.bx-navigation-dialog{position:absolute;z-index:var(--bx-navigation-dialog-z-index);font-family:var(--bx-title-font)}.bx-navigation-dialog *:focus{outline:none !important}.bx-navigation-dialog select:disabled{-webkit-appearance:none;text-align-last:right;text-align:right;color:#fff;background:#131416;border:none;border-radius:4px;padding:0 5px}.bx-navigation-dialog .bx-focusable::after{border-radius:4px}.bx-navigation-dialog .bx-focusable:focus::after{top:0;left:0;right:0;bottom:0}.bx-navigation-dialog-overlay{position:fixed;background:rgba(11,11,11,0.89);top:0;left:0;right:0;bottom:0;z-index:var(--bx-navigation-dialog-overlay-z-index)}.bx-navigation-dialog-overlay[data-is-playing="true"]{background:transparent}.bx-centered-dialog{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;background:#1a1b1e;border-radius:10px;min-width:min(calc(100vw - 20px), 500px);max-width:calc(100vw - 20px);margin:0 0 0 auto;padding:16px;max-height:95vh;flex-direction:column;overflow:hidden;display:flex;flex-direction:column}.bx-centered-dialog .bx-dialog-title{display:flex;flex-direction:row;align-items:center;margin-bottom:10px}.bx-centered-dialog .bx-dialog-title p{padding:0;margin:0;flex:1;font-size:1.5rem;font-weight:bold}.bx-centered-dialog .bx-dialog-title button{flex-shrink:0}.bx-centered-dialog .bx-dialog-content{flex:1;padding:6px;overflow:auto;overflow-x:hidden}.bx-centered-dialog .bx-dialog-preset-tools{display:flex;margin-bottom:12px;gap:6px}.bx-centered-dialog .bx-dialog-preset-tools button{align-self:center;min-height:50px}.bx-centered-dialog .bx-default-preset-note{font-size:12px;font-style:italic;text-align:center;margin-bottom:10px}.bx-centered-dialog input,.bx-settings-dialog input{accent-color:var(--bx-primary-button-color)}.bx-centered-dialog input:focus,.bx-settings-dialog input:focus{accent-color:var(--bx-danger-button-color)}.bx-centered-dialog select:disabled,.bx-settings-dialog select:disabled{-webkit-appearance:none;background:transparent;text-align-last:right;border:none;color:#fff}.bx-centered-dialog select option:disabled,.bx-settings-dialog select option:disabled{display:none}.bx-centered-dialog input[type=checkbox]:focus,.bx-settings-dialog input[type=checkbox]:focus,.bx-centered-dialog select:focus,.bx-settings-dialog select:focus{filter:drop-shadow(1px 0 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 1px 0 #fff) drop-shadow(0 -1px 0 #fff)}.bx-centered-dialog a,.bx-settings-dialog a{color:#1c9d1c;text-decoration:none}.bx-centered-dialog a:hover,.bx-settings-dialog a:hover,.bx-centered-dialog a:focus,.bx-settings-dialog a:focus{color:#5dc21e}.bx-centered-dialog label,.bx-settings-dialog label{margin:0}.bx-controller-shortcuts-manager-container .bx-shortcut-note{margin-top:10px;font-size:14px;text-align:center}.bx-controller-shortcuts-manager-container .bx-shortcut-row{display:flex;gap:10px;margin-bottom:10px;align-items:center}.bx-controller-shortcuts-manager-container .bx-shortcut-row label.bx-prompt{flex-shrink:0;font-size:32px;margin:0}.bx-controller-shortcuts-manager-container .bx-shortcut-row label.bx-prompt::first-letter{letter-spacing:6px}.bx-controller-shortcuts-manager-container select:disabled{text-align:left;text-align-last:left}.bx-keyboard-shortcuts-manager-container{display:flex;flex-direction:column;gap:16px}.bx-keyboard-shortcuts-manager-container fieldset{background:#2a2a2a;border:1px solid #2a2a2a;border-radius:4px;padding:4px}.bx-keyboard-shortcuts-manager-container legend{width:auto;padding:4px 8px;margin:0 4px 4px;background:#004f87;box-shadow:0 2px 0 #071e3d;border-radius:4px;font-size:14px;font-weight:bold;text-transform:uppercase}.bx-keyboard-shortcuts-manager-container .bx-settings-row{background:none;padding:10px}.bx-settings-dialog{display:flex;position:fixed;top:0;right:0;bottom:0;opacity:.98;user-select:none;-webkit-user-select:none}.bx-settings-dialog .bx-settings-reload-note{font-size:.8rem;display:block;padding:8px;font-style:italic;font-weight:normal;height:var(--bx-button-height)}.bx-settings-tabs-container{position:fixed;width:48px;max-height:100vh;display:flex;flex-direction:column}.bx-settings-tabs-container > div:last-of-type{display:flex;flex-direction:column;align-items:end}.bx-settings-tabs-container > div:last-of-type button{flex-shrink:0;border-top-right-radius:0;border-bottom-right-radius:0;margin-top:8px;height:unset;padding:8px 10px}.bx-settings-tabs-container > div:last-of-type button svg{width:16px;height:16px}.bx-settings-tabs{display:flex;flex-direction:column;border-radius:0 0 0 8px;box-shadow:0 0 6px #000;overflow:overlay;flex:1}.bx-settings-tabs svg{width:24px;height:24px;padding:10px;flex-shrink:0;box-sizing:content-box;background:#131313;cursor:pointer;border-left:4px solid #1e1e1e}.bx-settings-tabs svg.bx-active{background:#222;border-color:#008746}.bx-settings-tabs svg:not(.bx-active):hover{background:#2f2f2f;border-color:#484848}.bx-settings-tabs svg:focus{border-color:#fff}.bx-settings-tabs svg[data-group=global][data-need-refresh=true]{background:var(--bx-danger-button-color) !important}.bx-settings-tabs svg[data-group=global][data-need-refresh=true]:hover{background:var(--bx-danger-button-hover-color) !important}.bx-settings-tab-contents{flex-direction:column;margin-left:48px;width:450px;background:#1a1b1e;color:#fff;font-weight:400;font-size:16px;font-family:var(--bx-title-font);text-align:center;box-shadow:0 0 6px #000;overflow:overlay;z-index:1}.bx-settings-tab-contents .bx-top-buttons{display:flex;flex-direction:column;gap:8px;margin-bottom:8px}.bx-settings-tab-contents .bx-top-buttons .bx-button{display:block}.bx-settings-tab-contents h2{margin:16px 0 8px 0;display:flex;align-items:center}.bx-settings-tab-contents h2:first-of-type{margin-top:0}.bx-settings-tab-contents h2 span{display:inline-block;font-size:20px;font-weight:bold;text-align:left;flex:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;min-height:var(--bx-button-height);align-content:center}@media (max-width:500px){.bx-settings-tab-contents{width:calc(100vw - 48px)}}.bx-settings-row{display:flex;gap:10px;padding:16px 10px;background:#2a2a2a;border-bottom:1px solid #343434}.bx-settings-row:hover,.bx-settings-row:focus-within{background-color:#242424}.bx-settings-row:not(:has(> input[type=checkbox])){flex-wrap:wrap}.bx-settings-row > span.bx-settings-label{font-size:14px;display:block;text-align:left;align-self:center;margin-bottom:0 !important;flex:1}.bx-settings-row > span.bx-settings-label svg{width:20px;height:20px;margin-inline-end:8px}.bx-settings-row > span.bx-settings-label + *{margin:0 0 0 auto}.bx-settings-row[data-multi-lines="true"]{flex-direction:column}.bx-settings-row[data-multi-lines="true"] > span.bx-settings-label{align-self:start}.bx-settings-row[data-multi-lines="true"] > span.bx-settings-label + *{margin:unset}.bx-settings-dialog-note{display:block;color:#afafb0;font-size:12px;font-weight:lighter;font-style:italic}.bx-settings-dialog-note:not(:has(a)){margin-top:4px}.bx-settings-dialog-note a{display:inline-block;padding:4px}.bx-settings-custom-user-agent{display:block;width:100%;padding:6px}.bx-donation-link{display:block;text-align:center;text-decoration:none;height:20px;line-height:20px;font-size:14px;margin-top:10px;margin-bottom:10px}.bx-debug-info button{margin-top:10px}.bx-debug-info pre{margin-top:10px;cursor:copy;color:#fff;padding:8px;border:1px solid #2d2d2d;background:#212121;white-space:break-spaces;text-align:left}.bx-debug-info pre:hover{background:#272727}.bx-settings-app-version{margin-top:10px;text-align:center;color:#747474;font-size:12px}.bx-note-unsupported{display:block;font-size:12px;font-style:italic;font-weight:normal;color:#828282}.bx-settings-tab-content{padding:10px}.bx-settings-tab-content > div *:not(.bx-settings-row):has(+ .bx-settings-row) + .bx-settings-row:has(+ .bx-settings-row){border-top-left-radius:6px;border-top-right-radius:6px}.bx-settings-tab-content > div .bx-settings-row:not(:has(+ .bx-settings-row)){border:none;border-bottom-left-radius:6px;border-bottom-right-radius:6px}.bx-settings-tab-content > div *:not(.bx-settings-row):has(+ .bx-settings-row) + .bx-settings-row:not(:has(+ .bx-settings-row)){border:none;border-radius:6px}.bx-settings-tab-content:not([data-game-id="-1"]) .bx-settings-row[data-override=true],.bx-settings-tab-content:not([data-game-id="-1"]) .bx-settings-row:has(*[data-override=true]){border-left:4px solid #ffa500 !important;border-top-left-radius:0 !important;border-bottom-left-radius:0 !important;padding-left:6px !important}.bx-suggest-toggler{text-align:left;display:flex;border-radius:4px;overflow:hidden;background:#003861;height:45px;align-items:center}.bx-suggest-toggler label{flex:1;align-content:center;padding:0 10px;background:#004f87;height:100%}.bx-suggest-toggler span{display:inline-block;align-self:center;padding:10px;width:45px;text-align:center}.bx-suggest-toggler:hover,.bx-suggest-toggler:focus{cursor:pointer;background:#005da1}.bx-suggest-toggler:hover label,.bx-suggest-toggler:focus label{background:#006fbe}.bx-suggest-toggler[bx-open] span{transform:rotate(90deg)}.bx-suggest-toggler[bx-open]+ .bx-suggest-box{display:block}.bx-suggest-box{display:none}.bx-suggest-wrapper{display:flex;flex-direction:column;gap:10px;margin:10px}.bx-suggest-note{font-size:11px;color:#8c8c8c;font-style:italic;font-weight:100}.bx-suggest-link{font-size:14px;display:inline-block;margin-top:4px;padding:4px}.bx-suggest-row{display:flex;flex-direction:row;gap:10px}.bx-suggest-row label{flex:1;overflow:overlay;border-radius:4px}.bx-suggest-row label .bx-suggest-label{background:#323232;padding:4px 10px;font-size:12px;text-align:left}.bx-suggest-row label .bx-suggest-value{padding:6px;font-size:14px}.bx-suggest-row label .bx-suggest-value.bx-suggest-change{background-color:var(--bx-warning-color)}.bx-suggest-row.bx-suggest-ok input{visibility:hidden}.bx-suggest-row.bx-suggest-ok .bx-suggest-label{background-color:#008114}.bx-suggest-row.bx-suggest-ok .bx-suggest-value{background-color:#13a72a}.bx-suggest-row.bx-suggest-change .bx-suggest-label{background-color:#a65e08}.bx-suggest-row.bx-suggest-change .bx-suggest-value{background-color:#d57f18}.bx-suggest-row.bx-suggest-change:hover label{cursor:pointer}.bx-suggest-row.bx-suggest-change:hover .bx-suggest-label{background-color:#995707}.bx-suggest-row.bx-suggest-change:hover .bx-suggest-value{background-color:#bd7115}.bx-suggest-row.bx-suggest-change input:not(:checked) + label{opacity:.5}.bx-suggest-row.bx-suggest-change input:not(:checked) + label .bx-suggest-label{background-color:#2a2a2a}.bx-suggest-row.bx-suggest-change input:not(:checked) + label .bx-suggest-value{background-color:#393939}.bx-suggest-row.bx-suggest-change:hover input:not(:checked) + label{opacity:1}.bx-suggest-row.bx-suggest-change:hover input:not(:checked) + label .bx-suggest-label{background-color:#202020}.bx-suggest-row.bx-suggest-change:hover input:not(:checked) + label .bx-suggest-value{background-color:#303030}.bx-sub-content-box{background:#161616;padding:10px;box-shadow:0 0 12px #0f0f0f inset;border-radius:10px}.bx-settings-row .bx-sub-content-box{background:#202020;padding:12px;box-shadow:0 0 4px #000 inset;border-radius:6px}.bx-controller-extra-settings[data-has-gamepad=true] > :first-child{display:none}.bx-controller-extra-settings[data-has-gamepad=true] > :last-child{display:block}.bx-controller-extra-settings[data-has-gamepad=false] > :first-child{display:block}.bx-controller-extra-settings[data-has-gamepad=false] > :last-child{display:none}.bx-controller-extra-settings .bx-controller-extra-wrapper{flex:1;min-width:1px}.bx-controller-extra-settings .bx-sub-content-box{flex:1;text-align:left;display:flex;flex-direction:column;margin-top:10px}.bx-controller-extra-settings .bx-sub-content-box > label{font-size:14px}.bx-preset-row{display:flex;gap:8px}.bx-preset-row .bx-select{flex:1}.bx-stream-settings-selection{margin-bottom:8px;position:sticky;z-index:1000;top:0}.bx-stream-settings-selection > div{display:flex;gap:8px;background:#222;padding:10px;border-bottom:4px solid #353638;box-shadow:0 0 6px #000;position:relative;z-index:1}.bx-stream-settings-selection > div .bx-select{flex:1}.bx-stream-settings-selection > div .bx-select label{font-weight:bold;font-size:1.1rem;line-height:initial}.bx-stream-settings-selection > div .bx-select label span{line-height:initial}.bx-stream-settings-selection > div .bx-select .bx-select-indicators{display:none}.bx-stream-settings-selection p{font-family:var(--bx-promptfont-font),var(--bx-normal-font);margin:0;font-size:13px;background:rgba(80,80,80,0.949);height:25px;line-height:23px;position:absolute;bottom:-25px;left:0;right:0;text-shadow:0 1px #000}.bx-toast{user-select:none;-webkit-user-select:none;position:fixed;left:50%;top:24px;transform:translate(-50%,0);background:#212121;border-radius:10px;color:#fff;z-index:var(--bx-toast-z-index);font-family:var(--bx-normal-font);border:2px solid #fff;display:flex;align-items:center;opacity:0;overflow:clip;transition:opacity .2s ease-in;box-shadow:0 0 6px #000}.bx-toast.bx-show{opacity:.95}.bx-toast.bx-hide{opacity:0;pointer-events:none}.bx-toast-msg{font-size:14px;display:inline-block;padding:12px 16px;white-space:pre}.bx-toast-status{font-weight:bold;font-size:14px;text-transform:uppercase;display:inline-block;background:#fff;padding:12px 16px;color:#212121;white-space:pre}.bx-wait-time-box{position:fixed;top:0;right:0;background-color:rgba(0,0,0,0.8);color:#fff;z-index:var(--bx-wait-time-box-z-index);padding:12px;border-radius:0 0 0 8px}.bx-wait-time-box label{display:block;text-transform:uppercase;text-align:right;font-size:12px;font-weight:bold;margin:0}.bx-wait-time-box span{display:block;font-family:var(--bx-monospaced-font);text-align:right;font-size:16px;margin-bottom:10px}.bx-wait-time-box span:last-of-type{margin-bottom:0}.bx-remote-play-settings{margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid #2d2d2d}.bx-remote-play-settings > div{display:flex}.bx-remote-play-settings label{flex:1;font-size:14px}.bx-remote-play-settings label p{margin:4px 0 0;padding:0;color:#888;font-size:12px}.bx-remote-play-resolution{display:block}.bx-remote-play-resolution input[type="radio"]{accent-color:var(--bx-primary-button-color);margin-right:6px}.bx-remote-play-resolution input[type="radio"]:focus{accent-color:var(--bx-primary-button-hover-color)}.bx-remote-play-device-wrapper{display:flex;margin-bottom:12px}.bx-remote-play-device-wrapper:last-child{margin-bottom:2px}.bx-remote-play-device-info{flex:1;align-self:center;padding:4px 0}.bx-remote-play-device-name{font-size:14px;font-weight:bold;display:inline-block;vertical-align:middle}.bx-remote-play-console-type{font-size:8px;background:#004c87;color:#fff;display:inline-block;border-radius:8px;padding:2px 6px;margin-left:8px;vertical-align:middle}.bx-remote-play-power-state{color:#888;font-size:12px}.bx-remote-play-connect-button{min-height:100%;margin:4px 0}.bx-remote-play-buttons{display:flex;justify-content:space-between}select.bx-select{min-height:30px}div.bx-select{display:flex;align-items:stretch;flex:0 1 auto;gap:8px}div.bx-select select:disabled ~ button{display:none}div.bx-select select:disabled ~ div{background:#131416;color:#fff;pointer-events:none}div.bx-select select:disabled ~ div .bx-select-indicators{visibility:hidden}div.bx-select > div,div.bx-select button.bx-select-value{min-width:120px;text-align:left;line-height:24px;vertical-align:middle;background:#fff;color:#000;border-radius:4px;padding:2px 8px;display:flex;flex:1;flex-direction:column}div.bx-select > div{min-height:24px}div.bx-select > div input{display:inline-block;margin-right:8px}div.bx-select > div label{margin-bottom:0;font-size:14px;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;min-height:15px}div.bx-select > div label span{display:block;font-size:10px;font-weight:bold;text-align:left;line-height:20px;white-space:pre;min-height:15px;align-content:center}div.bx-select button.bx-select-value{border:none;cursor:pointer;min-height:30px;font-size:.9rem;align-items:center}div.bx-select button.bx-select-value > div{display:flex;width:100%}div.bx-select button.bx-select-value span{flex:1;text-align:left;display:inline-block}div.bx-select button.bx-select-value input{margin:0 4px;accent-color:var(--bx-primary-button-color);pointer-events:none}div.bx-select button.bx-select-value:hover input,div.bx-select button.bx-select-value:focus input{accent-color:var(--bx-danger-button-color)}div.bx-select button.bx-select-value:hover::after,div.bx-select button.bx-select-value:focus::after{border-color:#4d4d4d !important}div.bx-select button.bx-button{border:none;width:24px;height:auto;padding:0;color:#fff;border-radius:4px;font-weight:bold;font-size:12px;font-family:var(--bx-monospaced-font);flex-shrink:0}div.bx-select button.bx-button span{line-height:unset}div.bx-select[data-controller-friendly=true] > div{box-sizing:content-box}div.bx-select[data-controller-friendly=true] select{position:absolute !important;top:-9999px !important;left:-9999px !important;visibility:hidden !important}div.bx-select[data-controller-friendly=false]{position:relative}div.bx-select[data-controller-friendly=false] > div{box-sizing:border-box}div.bx-select[data-controller-friendly=false] > div label{margin-right:24px}div.bx-select[data-controller-friendly=false] select:disabled{display:none}div.bx-select[data-controller-friendly=false] select:not(:disabled){cursor:pointer;position:absolute;top:0;right:0;bottom:0;display:block;opacity:0;z-index:calc(var(--bx-settings-z-index) + 1)}div.bx-select[data-controller-friendly=false] select:not(:disabled):hover + div{background:#f0f0f0}div.bx-select[data-controller-friendly=false] select:not(:disabled) + div label::after{content:\'▾\';font-size:14px;position:absolute;right:8px;pointer-events:none}.bx-select-indicators{display:flex;height:4px;gap:2px;margin-bottom:2px}.bx-select-indicators span{content:\' \';display:inline-block;flex:1;background:#cfcfcf;border-radius:4px;min-width:1px}.bx-select-indicators span[data-highlighted]{background:#9c9c9c;min-width:6px}.bx-select-indicators span[data-selected]{background:#aacfe7}.bx-select-indicators span[data-highlighted][data-selected]{background:#5fa3d0}.bx-guide-home-achievements-progress{display:flex;gap:10px;flex-direction:row}.bx-guide-home-achievements-progress .bx-button{margin-bottom:0 !important}body[data-bx-media-type=tv] .bx-guide-home-achievements-progress{flex-direction:column}body:not([data-bx-media-type=tv]) .bx-guide-home-achievements-progress{flex-direction:row}body:not([data-bx-media-type=tv]) .bx-guide-home-achievements-progress > button:first-of-type{flex:1}body:not([data-bx-media-type=tv]) .bx-guide-home-achievements-progress > button:last-of-type{width:40px}body:not([data-bx-media-type=tv]) .bx-guide-home-achievements-progress > button:last-of-type span{display:none}.bx-guide-home-buttons > div{display:flex;flex-direction:row;gap:12px}body[data-bx-media-type=tv] .bx-guide-home-buttons > div{flex-direction:column}body[data-bx-media-type=tv] .bx-guide-home-buttons > div button{margin-bottom:0 !important}body:not([data-bx-media-type=tv]) .bx-guide-home-buttons > div button span{display:none}.bx-guide-home-buttons[data-is-playing="true"] button[data-state=\'normal\']{display:none}.bx-guide-home-buttons[data-is-playing="false"] button[data-state=\'playing\']{display:none}div[class*=StreamMenu-module__menuContainer] > div[class*=Menu-module]{overflow:visible}.bx-stream-menu-button-on{fill:#000 !important;background-color:#2d2d2d !important;color:#000 !important}.bx-stream-refresh-button{top:calc(env(safe-area-inset-top, 0px) + 10px + 50px) !important}body[data-media-type=default] .bx-stream-refresh-button{left:calc(env(safe-area-inset-left, 0px) + 11px) !important}body[data-media-type=tv] .bx-stream-refresh-button{top:calc(var(--gds-focus-borderSize) + 80px) !important}.bx-stream-home-button{top:calc(env(safe-area-inset-top, 0px) + 10px + 50px * 2) !important}body[data-media-type=default] .bx-stream-home-button{left:calc(env(safe-area-inset-left, 0px) + 12px) !important}body[data-media-type=tv] .bx-stream-home-button{top:calc(var(--gds-focus-borderSize) + 80px * 2) !important}div[data-testid=media-container][data-position=center]{display:flex}div[data-testid=media-container][data-position=top] video,div[data-testid=media-container][data-position=top] canvas{top:0}div[data-testid=media-container][data-position=bottom] video,div[data-testid=media-container][data-position=bottom] canvas{bottom:0}#game-stream video{margin:auto;align-self:center;background:#000;position:absolute;left:0;right:0}#game-stream canvas{align-self:center;margin:auto;position:absolute;left:0;right:0}#game-stream.bx-taking-screenshot:before{animation:bx-anim-taking-screenshot .5s ease;content:\' \';position:absolute;width:100%;height:100%;z-index:var(--bx-screenshot-animation-z-index)}#gamepass-dialog-root div[class^=Guide-module__guide] .bx-button{overflow:visible;margin-bottom:12px}@-moz-keyframes bx-anim-taking-screenshot{0%{border:0 solid rgba(255,255,255,0.502)}50%{border:8px solid rgba(255,255,255,0.502)}100%{border:0 solid rgba(255,255,255,0.502)}}@-webkit-keyframes bx-anim-taking-screenshot{0%{border:0 solid rgba(255,255,255,0.502)}50%{border:8px solid rgba(255,255,255,0.502)}100%{border:0 solid rgba(255,255,255,0.502)}}@-o-keyframes bx-anim-taking-screenshot{0%{border:0 solid rgba(255,255,255,0.502)}50%{border:8px solid rgba(255,255,255,0.502)}100%{border:0 solid rgba(255,255,255,0.502)}}@keyframes bx-anim-taking-screenshot{0%{border:0 solid rgba(255,255,255,0.502)}50%{border:8px solid rgba(255,255,255,0.502)}100%{border:0 solid rgba(255,255,255,0.502)}}.bx-number-stepper{text-align:center}.bx-number-stepper > div{display:flex;align-items:center}.bx-number-stepper > div span{flex:1;display:inline-block;min-width:40px;font-family:var(--bx-monospaced-font);white-space:pre;font-size:13px;margin:0 4px}.bx-number-stepper > div button{flex-shrink:0;border:none;width:24px;height:24px;margin:0;line-height:24px;background-color:var(--bx-default-button-color);color:#fff;border-radius:4px;font-weight:bold;font-size:14px;font-family:var(--bx-monospaced-font)}@media (hover:hover){.bx-number-stepper > div button:hover{background-color:var(--bx-default-button-hover-color)}}.bx-number-stepper > div button:active{background-color:var(--bx-default-button-hover-color)}.bx-number-stepper > div button:disabled + span{font-family:var(--bx-title-font)}.bx-number-stepper input[type=range]{display:block;margin:8px 0 2px auto;min-width:180px;width:100%;color:#959595 !important}.bx-number-stepper input[type=range]:disabled,.bx-number-stepper button:disabled{display:none}.bx-number-stepper[data-disabled=true] input[type=range],.bx-number-stepper[disabled=true] input[type=range],.bx-number-stepper[data-disabled=true] button,.bx-number-stepper[disabled=true] button{display:none}.bx-dual-number-stepper > span{display:block;font-family:var(--bx-monospaced-font);font-size:13px;white-space:pre;margin:0 4px;text-align:center}.bx-dual-number-stepper > div input[type=range]{display:block;width:100%;min-width:180px;background:transparent;color:#959595 !important;appearance:none;padding:8px 0}.bx-dual-number-stepper > div input[type=range]::-webkit-slider-runnable-track{background:linear-gradient(90deg,#fff var(--from),var(--bx-primary-button-color) var(--from) var(--to),#fff var(--to) 100%);height:8px;border-radius:2px}.bx-dual-number-stepper > div input[type=range]::-moz-range-track{background:linear-gradient(90deg,#fff var(--from),var(--bx-primary-button-color) var(--from) var(--to),#fff var(--to) 100%);height:8px;border-radius:2px}.bx-dual-number-stepper > div input[type=range]::-webkit-slider-thumb{margin-top:-4px;appearance:none;width:4px;height:16px;background:#00b85f;border:none;border-radius:2px}.bx-dual-number-stepper > div input[type=range]::-moz-range-thumb{margin-top:-4px;appearance:none;width:4px;height:16px;background:#00b85f;border:none;border-radius:2px}.bx-dual-number-stepper > div input[type=range]:hover::-webkit-slider-runnable-track,.bx-dual-number-stepper > div input[type=range].bx-dual-number-stepper > div input[type=range]:active::-webkit-slider-runnable-track,.bx-dual-number-stepper > div input[type=range]:focus::-webkit-slider-runnable-track{background:linear-gradient(90deg,#fff var(--from),#006635 var(--from) var(--to),#fff var(--to) 100%)}.bx-dual-number-stepper > div input[type=range]:hover::-moz-range-track,.bx-dual-number-stepper > div input[type=range].bx-dual-number-stepper > div input[type=range]:active::-moz-range-track,.bx-dual-number-stepper > div input[type=range]:focus::-moz-range-track{background:linear-gradient(90deg,#fff var(--from),#006635 var(--from) var(--to),#fff var(--to) 100%)}.bx-dual-number-stepper > div input[type=range]:hover::-webkit-slider-thumb,.bx-dual-number-stepper > div input[type=range].bx-dual-number-stepper > div input[type=range]:active::-webkit-slider-thumb,.bx-dual-number-stepper > div input[type=range]:focus::-webkit-slider-thumb{background:#fb3232}.bx-dual-number-stepper > div input[type=range]:hover::-moz-range-thumb,.bx-dual-number-stepper > div input[type=range].bx-dual-number-stepper > div input[type=range]:active::-moz-range-thumb,.bx-dual-number-stepper > div input[type=range]:focus::-moz-range-thumb{background:#fb3232}.bx-dual-number-stepper[data-disabled=true] input[type=range],.bx-dual-number-stepper[disabled=true] input[type=range]{display:none}#bx-game-bar{z-index:var(--bx-game-bar-z-index);position:fixed;bottom:0;width:40px;height:90px;overflow:visible;cursor:pointer}#bx-game-bar > svg{display:none;pointer-events:none;position:absolute;height:28px;margin-top:16px}@media (hover:hover){#bx-game-bar:hover > svg{display:block}}#bx-game-bar .bx-game-bar-container{opacity:0;position:absolute;display:flex;overflow:hidden;background:rgba(26,27,30,0.91);box-shadow:0 0 6px #1c1c1c;transition:opacity .1s ease-in}#bx-game-bar .bx-game-bar-container.bx-show{opacity:.9}#bx-game-bar .bx-game-bar-container.bx-show + svg{display:none !important}#bx-game-bar .bx-game-bar-container.bx-hide{opacity:0;pointer-events:none}#bx-game-bar .bx-game-bar-container button{width:60px;height:60px;border-radius:0}#bx-game-bar .bx-game-bar-container button svg{width:28px;height:28px;transition:transform .08s ease 0s}#bx-game-bar .bx-game-bar-container button:hover{border-radius:0}#bx-game-bar .bx-game-bar-container button:active svg{transform:scale(.75)}#bx-game-bar .bx-game-bar-container button.bx-activated{background-color:#fff}#bx-game-bar .bx-game-bar-container button.bx-activated svg{filter:invert(1)}#bx-game-bar .bx-game-bar-container div[data-activated] button{display:none}#bx-game-bar .bx-game-bar-container div[data-activated=\'false\'] button:first-of-type{display:block}#bx-game-bar .bx-game-bar-container div[data-activated=\'true\'] button:last-of-type{display:block}#bx-game-bar[data-position="bottom-left"]{left:0;direction:ltr}#bx-game-bar[data-position="bottom-left"] .bx-game-bar-container{border-radius:0 10px 10px 0}#bx-game-bar[data-position="bottom-right"]{right:0;direction:rtl}#bx-game-bar[data-position="bottom-right"] .bx-game-bar-container{direction:ltr;border-radius:10px 0 0 10px}.bx-badges{margin-left:0;user-select:none;-webkit-user-select:none}.bx-badge{border:none;display:inline-block;line-height:24px;color:#fff;font-family:var(--bx-title-font-semibold);font-size:14px;font-weight:400;margin:0 8px 8px 0;box-shadow:0 0 6px #000;border-radius:4px}.bx-badge-name{background-color:#2d3036;border-radius:4px 0 0 4px}.bx-badge-name svg{width:16px;height:16px}.bx-badge-value{background-color:#808080;border-radius:0 4px 4px 0}.bx-badge-name,.bx-badge-value{display:inline-block;padding:0 8px;line-height:30px;vertical-align:bottom}.bx-badge-battery[data-charging=true] span:first-of-type::after{content:\' ⚡️\'}div[class^=StreamMenu-module__container] .bx-badges{position:absolute;max-width:500px}#gamepass-dialog-root .bx-badges{position:fixed;top:60px;left:460px;max-width:500px}@media (min-width:568px) and (max-height:480px){#gamepass-dialog-root .bx-badges{position:unset;top:unset;left:unset;margin:8px 0}}.bx-stats-bar{display:flex;flex-direction:row;gap:8px;user-select:none;-webkit-user-select:none;position:fixed;top:0;background-color:#000;color:#fff;font-family:var(--bx-monospaced-font);font-size:.9rem;padding-left:8px;z-index:var(--bx-stats-bar-z-index);text-wrap:nowrap}.bx-stats-bar[data-stats*="[time]"] > .bx-stat-time,.bx-stats-bar[data-stats*="[play]"] > .bx-stat-play,.bx-stats-bar[data-stats*="[batt]"] > .bx-stat-batt,.bx-stats-bar[data-stats*="[fps]"] > .bx-stat-fps,.bx-stats-bar[data-stats*="[ping]"] > .bx-stat-ping,.bx-stats-bar[data-stats*="[jit]"] > .bx-stat-jit,.bx-stats-bar[data-stats*="[btr]"] > .bx-stat-btr,.bx-stats-bar[data-stats*="[dt]"] > .bx-stat-dt,.bx-stats-bar[data-stats*="[pl]"] > .bx-stat-pl,.bx-stats-bar[data-stats*="[fl]"] > .bx-stat-fl,.bx-stats-bar[data-stats*="[dl]"] > .bx-stat-dl,.bx-stats-bar[data-stats*="[ul]"] > .bx-stat-ul{display:inline-flex;align-items:baseline}.bx-stats-bar[data-stats$="[time]"] > .bx-stat-time,.bx-stats-bar[data-stats$="[play]"] > .bx-stat-play,.bx-stats-bar[data-stats$="[batt]"] > .bx-stat-batt,.bx-stats-bar[data-stats$="[fps]"] > .bx-stat-fps,.bx-stats-bar[data-stats$="[ping]"] > .bx-stat-ping,.bx-stats-bar[data-stats$="[jit]"] > .bx-stat-jit,.bx-stats-bar[data-stats$="[btr]"] > .bx-stat-btr,.bx-stats-bar[data-stats$="[dt]"] > .bx-stat-dt,.bx-stats-bar[data-stats$="[pl]"] > .bx-stat-pl,.bx-stats-bar[data-stats$="[fl]"] > .bx-stat-fl,.bx-stats-bar[data-stats$="[dl]"] > .bx-stat-dl,.bx-stats-bar[data-stats$="[ul]"] > .bx-stat-ul{border-right:none}.bx-stats-bar::before{display:none;content:\'👀\';vertical-align:middle;margin-right:8px}.bx-stats-bar[data-display=glancing]::before{display:inline-block}.bx-stats-bar[data-position=top-left]{left:0;border-radius:0 0 4px 0}.bx-stats-bar[data-position=top-right]{right:0;border-radius:0 0 0 4px}.bx-stats-bar[data-position=top-center]{transform:translate(-50%,0);left:50%;border-radius:0 0 4px 4px}.bx-stats-bar[data-shadow=true]{background:none;filter:drop-shadow(1px 0 0 rgba(0,0,0,0.941)) drop-shadow(-1px 0 0 rgba(0,0,0,0.941)) drop-shadow(0 1px 0 rgba(0,0,0,0.941)) drop-shadow(0 -1px 0 rgba(0,0,0,0.941))}.bx-stats-bar > div{display:none;border-right:1px solid #fff;padding-right:8px}.bx-stats-bar label{margin:0 8px 0 0;font-family:var(--bx-title-font);font-size:70%;font-weight:bold;vertical-align:middle;cursor:help}.bx-stats-bar span{display:inline-block;text-align:right;vertical-align:middle;white-space:pre}.bx-stats-bar span[data-grade=good]{color:#6bffff}.bx-stats-bar span[data-grade=ok]{color:#fff16b}.bx-stats-bar span[data-grade=bad]{color:#ff5f5f}.bx-mkb-settings{display:flex;flex-direction:column;flex:1;padding-bottom:10px;overflow:hidden}.bx-mkb-pointer-lock-msg{user-select:none;-webkit-user-select:none;position:fixed;left:50%;bottom:40px;transform:translateX(-50%);margin:auto;background:#151515;z-index:var(--bx-mkb-pointer-lock-msg-z-index);color:#fff;font-weight:400;font-family:"Segoe UI",Arial,Helvetica,sans-serif;font-size:1.3rem;padding:12px;border-radius:8px;align-items:center;box-shadow:0 0 6px #000;min-width:300px;opacity:.9;display:flex;flex-direction:column;gap:10px}.bx-mkb-pointer-lock-msg:hover{opacity:1}.bx-mkb-pointer-lock-msg > p{margin:0;width:100%;font-size:22px;margin-bottom:4px;font-weight:bold;text-align:left}.bx-mkb-pointer-lock-msg > div{width:100%;display:flex;flex-direction:row;gap:10px}.bx-mkb-pointer-lock-msg > div button:first-of-type{flex-shrink:1}.bx-mkb-pointer-lock-msg > div button:last-of-type{flex-grow:1}.bx-mkb-key-row{display:flex;margin-bottom:10px;align-items:center;gap:20px}.bx-mkb-key-row label{margin-bottom:0;font-family:var(--bx-promptfont-font);font-size:32px;text-align:center}.bx-mkb-settings.bx-editing .bx-mkb-key-row button{background:#393939;border-radius:4px;border:none}.bx-mkb-settings.bx-editing .bx-mkb-key-row button:hover{background:#333;cursor:pointer}.bx-mkb-action-buttons > div{text-align:right;display:none}.bx-mkb-action-buttons button{margin-left:8px}.bx-mkb-settings:not(.bx-editing) .bx-mkb-action-buttons > div:first-child{display:block}.bx-mkb-settings.bx-editing .bx-mkb-action-buttons > div:last-child{display:block}.bx-mkb-note{display:block;margin:0 0 10px;font-size:12px;text-align:center}button.bx-binding-button{flex:1;min-height:38px;border:none;border-radius:4px;font-size:14px;color:#fff;display:flex;align-items:center;align-self:center;padding:0 6px}button.bx-binding-button:disabled{background:#131416;padding:0 8px}button.bx-binding-button:not(:disabled){border:2px solid transparent;border-top:none;border-bottom:4px solid #252525;background:#3b3b3b;cursor:pointer}button.bx-binding-button:not(:disabled):hover,button.bx-binding-button:not(:disabled).bx-focusable:focus{background:#20b217;border-bottom-color:#186c13}button.bx-binding-button:not(:disabled):active{background:#16900f;border-bottom:3px solid #0c4e08;border-left-width:2px;border-right-width:2px}button.bx-binding-button:not(:disabled).bx-focusable:focus::after{top:-6px;left:-8px;right:-8px;bottom:-10px}.bx-settings-row .bx-binding-button-wrapper button.bx-binding-button{min-width:60px}.bx-controller-customizations-container .bx-btn-detect{display:block;margin-bottom:20px}.bx-controller-customizations-container .bx-btn-detect.bx-monospaced{background:none;font-weight:bold;font-size:12px}.bx-controller-customizations-container .bx-buttons-grid{display:grid;grid-template-columns:auto auto;column-gap:20px;row-gap:10px;margin-bottom:20px}.bx-controller-key-row{display:flex;align-items:stretch}.bx-controller-key-row > label{margin-bottom:0;font-family:var(--bx-promptfont-font);font-size:32px;text-align:center;min-width:50px;flex-shrink:0;display:flex;align-self:center}.bx-controller-key-row > label::after{content:\'❯\';margin:0 12px;font-size:16px;align-self:center}.bx-controller-key-row .bx-select{width:100% !important}.bx-controller-key-row .bx-select > div{min-width:50px}.bx-controller-key-row .bx-select label{font-family:var(--bx-promptfont-font),var(--bx-normal-font);font-size:32px;text-align:center;margin-bottom:6px;height:40px;line-height:40px}.bx-controller-key-row:hover > label{color:#ffe64b}.bx-controller-key-row:hover > label::after{color:#fff}.bx-controller-customization-summary{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:10px}.bx-controller-customization-summary span{font-family:var(--bx-promptfont);font-size:24px;border-radius:6px;background:#131313;color:#fff;display:inline-block;padding:2px;text-align:center}.bx-product-details-icons{padding:8px;border-radius:4px}.bx-product-details-icons svg{margin-right:8px}.bx-product-details-buttons{display:flex;gap:10px;flex-direction:row}.bx-product-details-buttons button{max-width:max-content;margin:10px 0 0 0;display:flex}@media (min-width:568px) and (max-height:480px){.bx-product-details-buttons{flex-direction:column}.bx-product-details-buttons button{margin:8px 0 0 10px}}', PREF_HIDE_SECTIONS = getGlobalPref("ui.hideSections"), selectorToHide = [];if (PREF_HIDE_SECTIONS.includes("news")) selectorToHide.push("#BodyContent > div[class*=CarouselRow-module]");if (getGlobalPref("block.features").includes("byog")) selectorToHide.push("#BodyContent > div[class*=ByogRow-module__container___]");if (PREF_HIDE_SECTIONS.includes("all-games")) selectorToHide.push("#BodyContent div[class*=AllGamesRow-module__gridContainer]"), selectorToHide.push("#BodyContent div[class*=AllGamesRow-module__rowHeader]");if (PREF_HIDE_SECTIONS.includes("most-popular")) selectorToHide.push('#BodyContent div[class*=HomePage-module__bottomSpacing]:has(a[href="/play/gallery/popular"])');if (PREF_HIDE_SECTIONS.includes("touch")) selectorToHide.push('#BodyContent div[class*=HomePage-module__bottomSpacing]:has(a[href="/play/gallery/touch"])');if (PREF_HIDE_SECTIONS.includes("recently-added")) selectorToHide.push('#BodyContent div[class*=HomePage-module__bottomSpacing]:has(a[href="/play/gallery/recently-added"])');if (PREF_HIDE_SECTIONS.includes("genres")) selectorToHide.push("#BodyContent div[class*=HomePage-module__genresRow]");if (containsAll(PREF_HIDE_SECTIONS, ["recently-added", "leaving-soon", "genres", "all-games"])) selectorToHide.push("#BodyContent div[class*=GamePassPromoSection-module__container]");if (getGlobalPref("block.features").includes("friends")) selectorToHide.push("#gamepass-dialog-root div[class^=AchievementsPreview-module__container] + button[class*=HomeLandingPage-module__button]");if (selectorToHide) css += selectorToHide.join(",") + "{ display: none; }";if (getGlobalPref("ui.theme") === "dark-oled") css += 'body[data-theme=dark]{--gds-containerSolidAppBackground:#000 !important}div[class*="ProductDetailPage-module__backgroundImageGradient"]:after{background:radial-gradient(ellipse 100% 100% at 50% 0,rgba(21,21,23,0.549) 0,rgba(26,27,30,0.651) 32%,#000 100%) !important}';if (getGlobalPref("ui.reduceAnimations")) css += "div[class*=GameCard-module__gameTitleInnerWrapper],div[class*=GameCard-module__card],div[class*=ScrollArrows-module]{transition:none !important}";if (getGlobalPref("ui.systemMenu.hideHandle")) css += "div[class*=Grip-module__container]{visibility:hidden}@media (hover:hover){button[class*=GripHandle-module__container]:hover div[class*=Grip-module__container]{visibility:visible}}button[class*=GripHandle-module__container][aria-expanded=true] div[class*=Grip-module__container]{visibility:visible}button[class*=GripHandle-module__container][aria-expanded=false]{background-color:transparent !important}div[class*=StreamHUD-module__buttonsContainer]{padding:0 !important}";if (css += "div[class*=StreamMenu-module__menu]{min-width:100vw !important}", getGlobalPref("ui.streamMenu.simplify")) css += "div[class*=Menu-module__scrollable]{--bxStreamMenuItemSize:80px;--streamMenuItemSize:calc(var(--bxStreamMenuItemSize) + 40px) !important}.bx-badges{top:calc(var(--streamMenuItemSize) - 20px)}body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) - 10px) !important}button[class*=MenuItem-module__container]{min-width:auto !important;min-height:auto !important;width:var(--bxStreamMenuItemSize) !important;height:var(--bxStreamMenuItemSize) !important}div[class*=MenuItem-module__label]{display:none !important}svg[class*=MenuItem-module__icon]{width:36px;height:100% !important;padding:0 !important;margin:0 !important}";else css += "body[data-media-type=tv] .bx-badges{top:calc(var(--streamMenuItemSize) + 30px)}body:not([data-media-type=tv]) .bx-badges{top:calc(var(--streamMenuItemSize) + 20px)}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]{min-width:auto !important;width:100px !important}body:not([data-media-type=tv]) button[class*=MenuItem-module__container]:nth-child(n+2){margin-left:10px !important}body:not([data-media-type=tv]) div[class*=MenuItem-module__label]{margin-left:8px !important;margin-right:8px !important}";if (getGlobalPref("ui.hideScrollbar")) css += "html{scrollbar-width:none}body::-webkit-scrollbar{display:none}";let $style = CE("style", !1, css);document.documentElement.appendChild($style);}
function preloadFonts() {let $link = CE("link", {rel: "preload",href: "https://redphx.github.io/better-xcloud/fonts/promptfont.otf",as: "font",type: "font/otf",crossorigin: ""});document.querySelector("head")?.appendChild($link);}
class MouseCursorHider {static instance;static getInstance() {if (typeof MouseCursorHider.instance === "undefined") if (!getGlobalPref("mkb.enabled") && getGlobalPref("mkb.cursor.hideIdle")) MouseCursorHider.instance = new MouseCursorHider;else MouseCursorHider.instance = null;return MouseCursorHider.instance;}timeoutId;isCursorVisible = !0;show() {document.body && (document.body.style.cursor = "unset"), this.isCursorVisible = !0;}hide() {document.body && (document.body.style.cursor = "none"), this.timeoutId = null, this.isCursorVisible = !1;}onMouseMove = (e) => {!this.isCursorVisible && this.show(), this.timeoutId && clearTimeout(this.timeoutId), this.timeoutId = window.setTimeout(this.hide, 3000);};start() {this.show(), document.addEventListener("mousemove", this.onMouseMove);}stop() {this.timeoutId && clearTimeout(this.timeoutId), this.timeoutId = null, document.removeEventListener("mousemove", this.onMouseMove), this.show();}}
function patchHistoryMethod(type) {let orig = window.history[type];return function(...args) {return BxEvent.dispatch(window, BxEvent.POPSTATE, {arguments: args}), orig.apply(this, arguments);};}
diff --git a/src/enums/pref-keys.ts b/src/enums/pref-keys.ts
index 9f5018b..79eb7ac 100755
--- a/src/enums/pref-keys.ts
+++ b/src/enums/pref-keys.ts
@@ -1,5 +1,5 @@
import type { BaseSettingsStorage } from "@/utils/settings-storages/base-settings-storage";
-import type { BlockFeature, CodecProfile, DeviceVibrationMode, GameBarPosition, LoadingScreenRocket, NativeMkbMode, StreamPlayerType, StreamResolution, StreamStat, StreamStatPosition, StreamVideoProcessing, TouchControllerMode, TouchControllerStyleCustom, TouchControllerStyleStandard, UiLayout, UiSection, VideoPosition, VideoPowerPreference, VideoRatio } from "./pref-values"
+import type { BlockFeature, CodecProfile, DeviceVibrationMode, GameBarPosition, LoadingScreenRocket, NativeMkbMode, StreamPlayerType, StreamResolution, StreamStat, StreamStatPosition, StreamVideoProcessing, TouchControllerMode, TouchControllerStyleCustom, TouchControllerStyleStandard, UiLayout, UiSection, UiTheme, VideoPosition, VideoPowerPreference, VideoRatio } from "./pref-values"
export const enum StorageKey {
GLOBAL = 'BetterXcloud',
@@ -74,6 +74,7 @@ export const enum GlobalPref {
UI_HIDE_SYSTEM_MENU_ICON = 'ui.systemMenu.hideHandle',
UI_REDUCE_ANIMATIONS = 'ui.reduceAnimations',
UI_IMAGE_QUALITY = 'ui.imageQuality',
+ UI_THEME = 'ui.theme',
AUDIO_MIC_ON_PLAYING = 'audio.mic.onPlaying',
AUDIO_VOLUME_CONTROL_ENABLED = 'audio.volume.booster.enabled',
@@ -126,6 +127,7 @@ export type GlobalPrefTypeMap = {
[GlobalPref.UI_SCROLLBAR_HIDE]: boolean;
[GlobalPref.UI_SIMPLIFY_STREAM_MENU]: boolean;
[GlobalPref.UI_SKIP_SPLASH_VIDEO]: boolean;
+ [GlobalPref.UI_THEME]: UiTheme;
[GlobalPref.VERSION_CURRENT]: string;
[GlobalPref.VERSION_LAST_CHECK]: number;
[GlobalPref.VERSION_LATEST]: string;
@@ -258,6 +260,7 @@ export const ALL_PREFS: {
GlobalPref.UI_SCROLLBAR_HIDE,
GlobalPref.UI_SIMPLIFY_STREAM_MENU,
GlobalPref.UI_SKIP_SPLASH_VIDEO,
+ GlobalPref.UI_THEME,
GlobalPref.VERSION_CURRENT,
GlobalPref.VERSION_LAST_CHECK,
GlobalPref.VERSION_LATEST,
diff --git a/src/enums/pref-values.ts b/src/enums/pref-values.ts
index fa20309..0fc775f 100755
--- a/src/enums/pref-values.ts
+++ b/src/enums/pref-values.ts
@@ -134,3 +134,8 @@ export const enum BlockFeature {
NOTIFICATIONS_INVITES = 'notifications-invites',
NOTIFICATIONS_ACHIEVEMENTS = 'notifications-achievements',
}
+
+export const enum UiTheme {
+ DEFAULT = 'default',
+ DARK_OLED = 'dark-oled',
+}
diff --git a/src/modules/ui/dialog/settings-dialog.ts b/src/modules/ui/dialog/settings-dialog.ts
index 4fa3bfc..c8db482 100755
--- a/src/modules/ui/dialog/settings-dialog.ts
+++ b/src/modules/ui/dialog/settings-dialog.ts
@@ -272,6 +272,7 @@ export class SettingsDialog extends NavigationDialog {
label: t('ui'),
items: [
GlobalPref.UI_LAYOUT,
+ GlobalPref.UI_THEME,
GlobalPref.UI_IMAGE_QUALITY,
GlobalPref.UI_GAME_CARD_SHOW_WAIT_TIME,
GlobalPref.UI_CONTROLLER_SHOW_STATUS,
diff --git a/src/utils/css.ts b/src/utils/css.ts
index 6feeb86..8a4e6cc 100755
--- a/src/utils/css.ts
+++ b/src/utils/css.ts
@@ -1,6 +1,6 @@
import { CE } from "@utils/html";
import { compressCss, isLiteVersion, renderStylus } from "@macros/build" with { type: "macro" };
-import { BlockFeature, UiSection } from "@/enums/pref-values";
+import { BlockFeature, UiSection, UiTheme } from "@/enums/pref-values";
import { GlobalPref } from "@/enums/pref-keys";
import { getGlobalPref } from "./pref-utils";
import { containsAll } from "./utils";
@@ -69,6 +69,19 @@ export function addCss() {
css += selectorToHide.join(',') + '{ display: none; }';
}
+ // Change site's background
+ if (getGlobalPref(GlobalPref.UI_THEME) === UiTheme.DARK_OLED) {
+ css += compressCss(`
+body[data-theme=dark] {
+ --gds-containerSolidAppBackground: #000 !important;
+}
+
+div[class*="ProductDetailPage-module__backgroundImageGradient"]:after {
+ background: radial-gradient(ellipse 100% 100% at 50% 0, #1515178c 0, #1a1b1ea6 32%, #000000 100%) !important;
+}
+`);
+ }
+
// Reduce animations
if (getGlobalPref(GlobalPref.UI_REDUCE_ANIMATIONS)) {
css += compressCss(`
diff --git a/src/utils/settings-storages/global-settings-storage.ts b/src/utils/settings-storages/global-settings-storage.ts
index 2622367..8639ffd 100755
--- a/src/utils/settings-storages/global-settings-storage.ts
+++ b/src/utils/settings-storages/global-settings-storage.ts
@@ -8,7 +8,7 @@ import { CE } from "../html";
import { t, SUPPORTED_LANGUAGES } from "../translation";
import { UserAgent } from "../user-agent";
import { BaseSettingsStorage } from "./base-settings-storage";
-import { CodecProfile, StreamResolution, TouchControllerMode, TouchControllerStyleStandard, TouchControllerStyleCustom, GameBarPosition, NativeMkbMode, UiLayout, UiSection, BlockFeature } from "@/enums/pref-values";
+import { CodecProfile, StreamResolution, TouchControllerMode, TouchControllerStyleStandard, TouchControllerStyleCustom, GameBarPosition, NativeMkbMode, UiLayout, UiSection, BlockFeature, UiTheme } from "@/enums/pref-values";
import { GhPagesUtils } from "../gh-pages";
import { BxEventBus } from "../bx-event-bus";
import { BxIcon } from "../bx-icon";
@@ -210,6 +210,14 @@ export class GlobalSettingsStorage extends BaseSettingsStorage {
},
},
},
+ [GlobalPref.UI_THEME]: {
+ label: t('theme'),
+ default: UiTheme.DEFAULT,
+ options: {
+ [UiTheme.DEFAULT]: t('default'),
+ [UiTheme.DARK_OLED]: t('oled'),
+ },
+ },
[GlobalPref.STREAM_COMBINE_SOURCES]: {
requiredVariants: 'full',
diff --git a/src/utils/translation.ts b/src/utils/translation.ts
index 3dc4631..b1aa597 100755
--- a/src/utils/translation.ts
+++ b/src/utils/translation.ts
@@ -31,6 +31,8 @@ const Texts = {
"section-recently-added": "Recently added",
"section-leaving-soon": "Leaving soon",
"section-genres": "Genres",
+ "oled": "OLED",
+ "theme": "Theme",
"achievements": "Achievements",
"activate": "Activate",
"activated": "Activated",