YouTube Embed Enhancer

Enhances YouTube Embeds with custom volume controls, hotkeys, and some optimizations.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         YouTube Embed Enhancer
// @namespace    https://github.com/jmpatag
// @version      2.4.0
// @description  Enhances YouTube Embeds with custom volume controls, hotkeys, and some optimizations.
// @author       jmpatag
// @license      GPL-3.0
// @match        *://www.youtube.com/embed/*
// @match        *://www.youtube-nocookie.com/embed/*
// @run-at       document-idle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addValueChangeListener
// @grant        GM_xmlhttpRequest
// @connect      holodex.net
// @grant        unsafeWindow
// ==/UserScript==

(() => {
  "use strict";

  const isControlsDisabled = new URLSearchParams(window.location.search).get("controls") === "0";
  const isPlayButtonMissing = !document.querySelector(".ytp-play-button");

  if (!isControlsDisabled && !isPlayButtonMissing) {
    console.log('YTEE: Normal controls detected, enhancing anyway.');
  }

  document.head.appendChild(
    Object.assign(document.createElement("style"), {
      textContent: `
:root {
  /* Styles */
  --ytee-ew: 800px;

  /* Sizing */
  --ytee-btn-size: clamp(25.5px, calc(var(--ytee-ew) * 0.04), 37.5px);
  --ytee-icon-size: clamp(15px, calc(var(--ytee-ew) * 0.0225), 21px);
  --ytee-font-size: clamp(11px,  calc(var(--ytee-ew) * 0.0175), 15px);
  --ytee-gap: clamp(2.5px,  calc(var(--ytee-ew) * 0.00375), 5px);

  --ytee-bg-dark: rgba(15, 15, 15, 0.75);
  --ytee-bg-medium: rgba(25, 25, 25, 0.65);
  --ytee-btn-bg: rgba(255,255,255,0.08);
  --ytee-btn-border: rgba(255,255,255,0.13);
  --ytee-btn-hover: rgba(255,255,255,0.19);
  --ytee-text: rgba(255,255,255,0.92);

  --ytee-stats-color: #ffd700;
  --ytee-stats-bg: rgba(255,215,0,0.14);
  --ytee-stats-border: rgba(255,215,0,0.55);

  --ytee-speed-color: #7ddeff;
  --ytee-speed-bg: rgba(119,221,255,0.12);
  --ytee-speed-border: rgba(119,221,255,0.55);

  --ytee-rec-bg: rgba(255,68,68,0.15);
  --ytee-rec-border: rgba(255,68,68,0.65);

  --ytee-anim-fast: 0.08s cubic-bezier(0.4,0,0.2,1);
  --ytee-anim-normal: 0.15s cubic-bezier(0.4,0,0.2,1);
  --ytee-anim-slow: 0.25s cubic-bezier(0.4,0,0.2,1);
  --ytee-radius: 5px;
}

[data-ytee-high-contrast="1"] {
  --ytee-btn-bg: rgba(10, 10, 10, 0.82) !important;
  --ytee-btn-border: rgba(255, 255, 255, 0.28) !important;
  --ytee-btn-hover: rgba(30, 30, 30, 0.95) !important;
  --ytee-text: #ffffff !important;
}

player-fullscreen-action-menu { display: none !important; }

/* Overlays */
#custom-vol-overlay,
#custom-speed-overlay {
  position: fixed;
  top: clamp(60px,10vh,140px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--ytee-bg-dark);
  color: var(--ytee-text);
  padding: clamp(5px,calc(var(--ytee-ew) * 0.008),10px) clamp(10px,calc(var(--ytee-ew) * 0.016),20px);
  border-radius: 6px;
  font-size: clamp(13px,calc(var(--ytee-ew) * 0.018),20px);
  font-family: sans-serif;
  font-weight: bold;
  z-index: 9999;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--ytee-anim-slow);
  will-change: opacity;
}
#custom-vol-overlay.show,
#custom-speed-overlay.show { opacity: 1; transition: opacity var(--ytee-anim-fast); }
#custom-speed-overlay { top: clamp(95px,16vh,190px); }

#custom-clip-overlay {
  position: fixed;
  top: clamp(125px,22vh,240px);
  left: 50%;
  transform: translateX(-50%);
  background: rgba(180,0,0,0.78);
  color: white;
  padding: clamp(4px,calc(var(--ytee-ew) * 0.005),7px) clamp(10px,calc(var(--ytee-ew) * 0.014),18px);
  border-radius: 6px;
  font-size: clamp(11px,calc(var(--ytee-ew) * 0.014),16px);
  font-family: monospace;
  font-weight: bold;
  z-index: 9999;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--ytee-anim-slow);
  will-change: opacity;
}
#custom-clip-overlay.show { opacity: 1; transition: opacity var(--ytee-anim-fast); }

#custom-mini-stats {
  position: fixed;
  bottom: 45px;
  left: 10px;
  background: rgba(10, 10, 10, 0.7);
  backdrop-filter: blur(4px);
  color: rgba(255, 255, 255, 0.6);
  padding: 4px 10px;
  border-radius: 6px;
  font-family: ui-monospace, 'Cascadia Code', monospace;
  font-size: 10.5px;
  z-index: 9999;
  border: 1px solid rgba(255, 255, 255, 0.08);
  opacity: 0;
  pointer-events: none;
  cursor: grab;
  transition: opacity var(--ytee-anim-slow), transform var(--ytee-anim-fast);
  white-space: nowrap;
  display: flex;
  gap: 12px;
}
#custom-mini-stats.show { opacity: 1; pointer-events: auto; }
#custom-mini-stats:active { cursor: grabbing; transform: scale(1.02); }
#custom-mini-stats span { color: var(--ytee-speed-color); font-weight: bold; }
#custom-mini-stats b { color: rgba(255, 255, 255, 0.3); font-weight: normal; margin-right: 4px; }

/* Mute button */
#custom-mute-btn {
  position: fixed;
  bottom: clamp(6px,1vh,18px);
  left: clamp(6px,calc(var(--ytee-ew) * 0.008),14px);
  width: var(--ytee-btn-size);
  height: var(--ytee-btn-size);
  z-index: 9999;
  cursor: pointer;
  border: none;
  background-color: transparent;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></svg>');
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--ytee-anim-slow), transform var(--ytee-anim-fast);
  will-change: opacity;
}
#custom-mute-btn.show { opacity: 1; pointer-events: auto; }
#custom-mute-btn.show:hover { transform: scale(1.1); }
#custom-mute-btn.muted {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>');
  opacity: 0.5 !important;
}
#custom-mute-btn.show.muted { opacity: 0.5; }

/* Volume slider */
#custom-vol-slider {
  position: fixed;
  bottom: calc(clamp(6px,1vh,18px) + var(--ytee-btn-size)/2 - 6px);
  left: calc(clamp(6px,calc(var(--ytee-ew) * 0.008),14px) + var(--ytee-btn-size) + clamp(3px,calc(var(--ytee-ew) * 0.004),7px));
  z-index: 9999;
  width: clamp(52px,calc(var(--ytee-ew) * 0.072),90px);
  height: 12px;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  background: transparent !important;
  border: none !important;
  padding: 0 !important;
  margin: 0 !important;
  outline: none;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--ytee-anim-slow), width var(--ytee-anim-normal);
  will-change: opacity;
}
#custom-vol-slider.show { opacity: 0.75; pointer-events: auto; }
#custom-vol-slider.show:hover { opacity: 1; width: clamp(68px,calc(var(--ytee-ew) * 0.092),110px); }
#custom-vol-slider::-webkit-slider-runnable-track { -webkit-appearance: none; height: 3px; border-radius: 2px; background: rgba(255,255,255,0.35); border: none; }
#custom-vol-slider::-moz-range-track { height: 3px; border-radius: 2px; background: rgba(255,255,255,0.35); border: none; }
#custom-vol-slider::-webkit-slider-thumb {
  width: clamp(10px,calc(var(--ytee-ew) * 0.013),14px); height: clamp(10px,calc(var(--ytee-ew) * 0.013),14px);
  margin-top: calc(-1*(clamp(10px,calc(var(--ytee-ew) * 0.013),14px)/2 - 1.5px));
  appearance: none; border-radius: 50%; background: white;
  box-shadow: 0 1px 3px rgba(0,0,0,0.5);
}
#custom-vol-slider::-moz-range-thumb {
  width: clamp(10px,calc(var(--ytee-ew) * 0.013),14px); height: clamp(10px,calc(var(--ytee-ew) * 0.013),14px);
  border-radius: 50%; background: white; border: none;
  box-shadow: 0 1px 3px rgba(0,0,0,0.5);
}

/* Button group */
#custom-btn-group {
  position: fixed;
  bottom: clamp(6px,1vh,18px);
  right: clamp(6px,calc(var(--ytee-ew) * 0.008),14px);
  display: flex;
  align-items: center;
  gap: var(--ytee-gap);
  z-index: 9999;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--ytee-anim-slow);
  will-change: opacity;
}
#custom-btn-group.show { opacity: 1; pointer-events: auto; }
#custom-btn-group.collapsed .ytee-collapsible { display: none !important; }
#custom-btn-group.collapsed { gap: 4px; }

/* Shared button base */
.ytee-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  cursor: pointer;
  color: var(--ytee-text);
  background: var(--ytee-btn-bg) !important;
  border: 1px solid var(--ytee-btn-border) !important;
  border-radius: var(--ytee-radius) !important;
  font-size: var(--ytee-font-size);
  font-family: ui-monospace, 'Cascadia Code', monospace;
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1;
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
  opacity: 0;
  pointer-events: none;
  position: relative;
  overflow: visible;
  white-space: nowrap;
  transition: opacity var(--ytee-anim-slow), background var(--ytee-anim-fast), transform var(--ytee-anim-fast);
  width: var(--ytee-btn-size);
  height: var(--ytee-btn-size);
  padding: 0;
}
#custom-btn-group.show .ytee-btn, #custom-toggle-btn, #custom-settings-btn { opacity: 1; pointer-events: auto; }
.ytee-btn:hover { background: var(--ytee-btn-hover) !important; transform: scale(1.08); z-index: 10; }

/* Speed keeps auto width for the rate text */
#custom-speed-btn { width: auto; min-width: var(--ytee-btn-size); padding: 0 clamp(3px,calc(var(--ytee-ew) * 0.004),7px); }

/* SVG icons inside each button */
.ytee-btn .ytee-icon { display: flex; }

/* Label spans — hidden in icon mode */
.ytee-btn .ytee-label { display: none; }

/* Tooltips — shown in icon mode only */
.ytee-btn::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 7.5px);
  right: 0;
  background: rgba(10,10,10,0.92);
  color: rgba(255,255,255,0.92);
  font-size: 12.5px;
  font-family: system-ui, sans-serif;
  font-weight: 500;
  white-space: nowrap;
  padding: 3.75px 10px;
  border-radius: 5px;
  border: 1.25px solid rgba(255,255,255,0.1);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s;
  letter-spacing: 0;
}
.ytee-btn:hover::after { opacity: 1; }

/* Label mode */
[data-ytee-labels="1"] .ytee-btn { width: auto; padding: 0 clamp(6px,calc(var(--ytee-ew) * 0.009),13px); }
[data-ytee-labels="1"] .ytee-btn .ytee-label { display: inline; }
[data-ytee-labels="1"] .ytee-btn .ytee-icon { display: flex; }

/* State colors */
#custom-stats-btn.active {
  color: var(--ytee-stats-color) !important;
  background: var(--ytee-stats-bg) !important;
  border-color: var(--ytee-stats-border) !important;
}
#custom-stats-btn.active svg { fill: var(--ytee-stats-color); }

#custom-stats-btn.nerds-active {
  color: #7ddeff !important;
  background: rgba(119,221,255,0.12) !important;
  border-color: rgba(119,221,255,0.55) !important;
}
#custom-stats-btn.nerds-active svg { fill: #7ddeff; }

/* When both are active, prioritize Mini Stats background but keep blue icon/text for Nerds (or vice-versa) */
#custom-stats-btn.active.nerds-active {
  background: var(--ytee-stats-bg) !important;
  border-color: #7ddeff !important;
  color: #7ddeff !important;
}
#custom-stats-btn.active.nerds-active svg { fill: #7ddeff; }

#custom-speed-btn.modified {
  color: var(--ytee-speed-color) !important;
  background: var(--ytee-speed-bg) !important;
  border-color: var(--ytee-speed-border) !important;
}
#custom-speed-btn.modified svg { fill: var(--ytee-speed-color); }

@keyframes ytee-rec-pulse {
  0%,100% { box-shadow: 0 0 0 0 rgba(255,60,60,0.7); }
  50%      { box-shadow: 0 0 0 5px rgba(255,60,60,0); }
}
#custom-clip-btn.recording {
  color: #ff4444 !important;
  background: var(--ytee-rec-bg) !important;
  border-color: var(--ytee-rec-border) !important;
  animation: ytee-rec-pulse 1.1s ease-in-out infinite;
}
#custom-clip-btn.recording svg { fill: #ff4444; }

/* Feedback States */
@keyframes ytee-btn-bounce {
  0%, 100% { transform: scale(1); }
  40%      { transform: scale(1.25); }
  60%      { transform: scale(0.95); }
}
.ytee-btn.success {
  color: #2ecc71 !important;
  background: rgba(46, 204, 113, 0.2) !important;
  border-color: rgba(46, 204, 113, 0.6) !important;
  animation: ytee-btn-bounce 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
  z-index: 20;
}
.ytee-btn.success svg { fill: #2ecc71; }

.ytee-btn.error {
  color: #ff4444 !important;
  background: rgba(255, 68, 68, 0.2) !important;
  border-color: rgba(255, 68, 68, 0.6) !important;
  animation: ytee-btn-bounce 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
  z-index: 20;
}
.ytee-btn.error svg { fill: #ff4444; }

/* Settings Modal */
@keyframes ytee-modal-in {
  from { opacity:0; transform: scale(0.96) translateY(8px); }
  to   { opacity:1; transform: scale(1) translateY(0); }
}
#custom-settings-modal {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.78);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  z-index: 10000; display: none;
  align-items: center; justify-content: center;
}
#custom-settings-modal.show { display: flex; }
#custom-settings-content {
  background: linear-gradient(160deg,rgba(22,22,28,0.97) 0%,rgba(14,14,18,0.97) 100%);
  border: 1px solid rgba(255,255,255,0.1);
  border-radius: 14px;
  padding: 16px 18px 14px;
  width: min(480px,96vw);
  max-height: 90vh;
  overflow-y: auto; overflow-x: hidden;
  color: white;
  font-family: system-ui,-apple-system,sans-serif;
  box-shadow: 0 24px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04) inset;
  animation: ytee-modal-in 0.2s cubic-bezier(0.34,1.56,0.64,1) both;
  scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.15) transparent;
}
#custom-settings-content::-webkit-scrollbar { width: 4px; }
#custom-settings-content::-webkit-scrollbar-thumb { background:rgba(255,255,255,0.15); border-radius:99px; }
#custom-settings-content h2 { margin:0 0 2px; font-size:15px; font-weight:700; letter-spacing:-0.01em; color:rgba(255,255,255,0.95); }
#ytee-settings-subtitle { font-size:11px; color:rgba(255,255,255,0.35); margin:0 0 12px; letter-spacing:0.01em; }
#custom-settings-content h3.setting-section-title {
  display:flex; align-items:center; gap:8px;
  margin:14px 0 2px; font-size:10px; font-weight:700;
  color:rgba(255,255,255,0.38); text-transform:uppercase; letter-spacing:0.15em;
}
#custom-settings-content h3.setting-section-title::before {
  content:''; display:block; width:3px; height:14px; border-radius:99px; flex-shrink:0;
  background:linear-gradient(to bottom,rgba(119,221,255,0.9),rgba(119,221,255,0.2));
}
#custom-settings-content h3.setting-section-title::after { content:''; flex:1; height:1px; background:rgba(255,255,255,0.06); }
#custom-settings-content .setting-item {
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:7px 10px; margin:2px 0; border-radius:8px; border:1px solid transparent;
  transition: background 0.15s, border-color 0.15s;
}
#custom-settings-content .setting-item:hover { background:rgba(255,255,255,0.04); border-color:rgba(255,255,255,0.07); }
#custom-settings-content .setting-item label:not(.ytee-toggle-track) {
  flex:1; font-size:13.5px; font-weight:500; color:rgba(255,255,255,0.85); cursor:pointer; user-select:none;
}
.ytee-toggle-wrap { position:relative; width:38px; height:22px; flex:0 0 38px; flex-shrink:0; }
.ytee-toggle-wrap input[type="checkbox"] { opacity:0; width:0; height:0; position:absolute; }
.ytee-toggle-track {
  position:absolute; inset:0; border-radius:99px;
  background:rgba(255,255,255,0.12); border:1px solid rgba(255,255,255,0.12);
  transition: background 0.2s, border-color 0.2s; cursor:pointer;
}
.ytee-toggle-thumb {
  position:absolute; top:3px; left:3px; width:14px; height:14px; border-radius:50%;
  background:rgba(255,255,255,0.5);
  transition: transform 0.2s cubic-bezier(0.34,1.56,0.64,1), background 0.2s;
  pointer-events:none;
}
.ytee-toggle-wrap input:checked ~ .ytee-toggle-track { background:rgba(119,221,255,0.25); border-color:rgba(119,221,255,0.6); }
.ytee-toggle-wrap input:checked ~ .ytee-toggle-track .ytee-toggle-thumb { transform:translateX(16px); background:#7ddeff; }
#custom-settings-content .hk-input {
  width:108px; padding:7px 11px;
  background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.1);
  border-radius:8px; color:rgba(255,255,255,0.9);
  font-size:12px; font-family:ui-monospace,'Cascadia Code',monospace;
  font-weight:600; letter-spacing:0.04em; text-transform:lowercase;
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s; flex-shrink:0;
}
#custom-settings-content .hk-input:focus { outline:none; background:rgba(119,221,255,0.06); border-color:rgba(119,221,255,0.5); box-shadow:0 0 0 3px rgba(119,221,255,0.1); }
#custom-settings-content input[type="range"] { -webkit-appearance:none; appearance:none; height:4px; border-radius:99px; background:rgba(255,255,255,0.12); outline:none; cursor:pointer; flex-shrink:0; }
#custom-settings-content input[type="range"]::-webkit-slider-thumb { -webkit-appearance:none; width:16px; height:16px; border-radius:50%; background:#fff; box-shadow:0 1px 4px rgba(0,0,0,0.4); transition:transform 0.12s,box-shadow 0.12s; }
#custom-settings-content input[type="range"]:hover::-webkit-slider-thumb { transform:scale(1.15); box-shadow:0 2px 8px rgba(0,0,0,0.5); }
#custom-settings-content input[type="range"]::-moz-range-thumb { width:16px; height:16px; border-radius:50%; background:#fff; border:none; box-shadow:0 1px 4px rgba(0,0,0,0.4); }
#custom-settings-content input[type="range"]::-moz-range-track { height:4px; border-radius:99px; background:rgba(255,255,255,0.12); }
.ytee-slider-value { font-size:12px; font-weight:700; font-family:ui-monospace,monospace; color:rgba(255,255,255,0.5); min-width:40px; text-align:right; flex-shrink:0; }
.setting-note { display:block; font-size:11px; color:rgba(255,255,255,0.3); margin:4px 14px 12px; line-height:1.4; font-style:italic; }
#custom-settings-buttons { display:flex; align-items:center; justify-content:flex-end; gap:8px; margin-top:14px; padding-top:10px; border-top:1px solid rgba(255,255,255,0.07); }
#custom-settings-restore { margin-right:auto; padding:8px 14px; background:transparent; border:1px solid rgba(255,80,80,0.3); border-radius:9px; color:rgba(255,110,110,0.8); cursor:pointer; font-size:12.5px; font-weight:600; transition:background 0.15s,border-color 0.15s,color 0.15s; }
#custom-settings-restore:hover { background:rgba(255,60,60,0.1); border-color:rgba(255,80,80,0.6); color:#ff8080; }
#custom-settings-cancel { padding:8px 16px; background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.1); border-radius:9px; color:rgba(255,255,255,0.6); cursor:pointer; font-size:13px; font-weight:600; transition:background 0.15s,color 0.15s; }
#custom-settings-cancel:hover { background:rgba(255,255,255,0.1); color:rgba(255,255,255,0.9); }
#custom-settings-save { padding:8px 20px; background:rgba(119,221,255,0.15); border:1px solid rgba(119,221,255,0.45); border-radius:9px; color:#7ddeff; cursor:pointer; font-size:13px; font-weight:700; letter-spacing:0.01em; transition:background 0.15s,border-color 0.15s,box-shadow 0.15s; }
#custom-settings-save:hover { background:rgba(119,221,255,0.25); border-color:rgba(119,221,255,0.7); box-shadow:0 0 14px rgba(119,221,255,0.15); }
.ytee-quality-select {
  padding:7px 11px; background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.1);
  border-radius:8px; color:rgba(255,255,255,0.9); font-size:12px;
  font-family:ui-monospace,'Cascadia Code',monospace; font-weight:600; letter-spacing:0.04em;
  cursor:pointer; flex-shrink:0; transition:border-color 0.15s,box-shadow 0.15s,background 0.15s;
  appearance:none; -webkit-appearance:none;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6'><path d='M0 0l5 6 5-6z' fill='rgba(255,255,255,0.4)'/></svg>");
  background-repeat:no-repeat; background-position:right 10px center; padding-right:28px;
}
.ytee-quality-select:focus { outline:none; background-color:rgba(119,221,255,0.06); border-color:rgba(119,221,255,0.5); box-shadow:0 0 0 3px rgba(119,221,255,0.1); }
.ytee-quality-select option { background:#1a1a22; color:white; }
.ytee-quality-note { display:block; font-size:11px; color:rgba(255,255,255,0.3); margin:4px 14px 12px; line-height:1.4; font-style:italic; }

/* Info Button and Box */
.ytee-info-btn {
  display: flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.12);
  color: rgba(255,255,255,0.4); cursor: pointer; transition: all 0.15s;
  flex-shrink: 0;
}
.ytee-info-btn:hover { background: rgba(119,221,255,0.12); border-color: rgba(119,221,255,0.35); color: #7ddeff; }
.ytee-info-box {
  margin: 4px 10px 14px; padding: 12px 14px;
  background: rgba(15, 15, 20, 0.45); border: 1px solid rgba(255,255,255,0.06);
  border-radius: 10px; font-size: 11.5px; line-height: 1.6; color: rgba(255,255,255,0.55);
  display: none; animation: ytee-modal-in 0.2s ease-out;
}
.ytee-info-box.show { display: block; }
.ytee-info-box strong { color: rgba(119,221,255,0.9); font-weight: 700; margin-right: 4px; font-family: ui-monospace, monospace; }
.ytee-info-box p { margin: 0 0 10px; }
.ytee-info-box p:last-child { margin-bottom: 4px; }
.ytee-info-link { display: inline-block; color: #7ddeff; text-decoration: none; font-size: 10px; opacity: 0.5; transition: opacity 0.2s; margin-top: 4px; }
.ytee-info-link:hover { opacity: 0.9; text-decoration: underline; }

#ytee-settings-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 2px;
}
`
    })
  );

  const SVG_NS = 'http://www.w3.org/2000/svg';
  const mkSvgEl = (...pathDefs) => {
    const svg = document.createElementNS(SVG_NS, 'svg');
    svg.setAttribute('viewBox', '0 0 24 24');
    svg.setAttribute('fill', 'currentColor');
    svg.style.cssText = 'width:var(--ytee-icon-size,13px);height:var(--ytee-icon-size,13px);flex-shrink:0;';
    pathDefs.forEach(def => {
      const el = document.createElementNS(SVG_NS, def.tag || 'path');
      Object.entries(def.attrs).forEach(([k, v]) => el.setAttribute(k, v));
      svg.appendChild(el);
    });
    return svg;
  };

  const ICON_DEFS = {
    wl: () => mkSvgEl({ tag: 'path', attrs: { d: 'M17 3H7c-1.1 0-2 .9-2 2v16l7-3 7 3V5c0-1.1-.9-2-2-2z' } }),
    url: () => mkSvgEl({ tag: 'path', attrs: { d: 'M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z' } }),
    screenshot: () => mkSvgEl({ tag: 'path', attrs: { d: 'M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z' } }),
    clip: () => mkSvgEl({ tag: 'circle', attrs: { cx: '12', cy: '12', r: '7' } }),
    pip: () => mkSvgEl(
      { tag: 'path', attrs: { d: 'M19 7H5c-1.1 0-2 .9-2 2v6c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm-9 5v-1.5l4 2-4 2V12z' } },
      { tag: 'path', attrs: { d: 'M23 5h-2v14h2V5zM1 5v14h2V5H1z' } }
    ),
    stats: () => mkSvgEl({ tag: 'path', attrs: { d: 'M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 3c1.93 0 3.5 1.57 3.5 3.5S13.93 13 12 13s-3.5-1.57-3.5-3.5S10.07 6 12 6zm7 13H5v-.23c0-.62.28-1.2.76-1.58C7.47 15.82 9.64 15 12 15s4.53.82 6.24 2.19c.48.38.76.97.76 1.58V19z' } }),
    settings: () => mkSvgEl({ tag: 'path', attrs: { d: 'M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z' } }),
    speed: () => mkSvgEl({ tag: 'path', attrs: { d: 'M10 8v8l6-4-6-4zm6.5-4.5l-1.5 1.5C16.78 6.76 18 9.24 18 12s-1.22 5.24-3 6.99l1.5 1.5C18.77 18.12 20 15.2 20 12s-1.23-6.12-3.5-8.5zM7.5 5.5L6 4C3.23 6.38 2 9.3 2 12s1.23 5.62 4 8l1.5-1.5C5.22 16.76 4 14.29 4 12s1.22-5.24 3.5-6.5z' } }),
    hide: () => mkSvgEl({ tag: 'path', attrs: { d: 'M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z' } }),
    expand: () => mkSvgEl({ tag: 'path', attrs: { d: 'M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z' } }),
    info: () => mkSvgEl({ tag: 'path', attrs: { d: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z' } }),
  };

  const mkBtn = (id, iconKey, labelText, tipText, titleText, isCollapsible = true) => {
    const btn = document.createElement('button');
    btn.id = id;
    btn.className = 'ytee-btn' + (isCollapsible ? ' ytee-collapsible' : '');
    btn.title = titleText || labelText;
    btn.dataset.tip = tipText || labelText;
    btn.dataset.defaultLabel = labelText;
    btn.dataset.defaultTip = tipText || labelText;
    btn.setAttribute('aria-label', labelText);

    const iconSpan = document.createElement('span');
    iconSpan.className = 'ytee-icon';
    iconSpan.appendChild(ICON_DEFS[iconKey]());

    const labelSpan = document.createElement('span');
    labelSpan.className = 'ytee-label';
    labelSpan.textContent = labelText;

    btn.appendChild(iconSpan);
    btn.appendChild(labelSpan);
    return btn;
  };

  const waitForVideo = (callback, timeoutMs = 15000) => {
    const existing = document.querySelector("video");
    if (existing) { callback(existing); return; }
    const observer = new MutationObserver(() => {
      const v = document.querySelector("video");
      if (v) { observer.disconnect(); clearTimeout(timer); callback(v); }
    });
    const timer = setTimeout(() => { observer.disconnect(); console.warn('YTEE: video element never appeared'); }, timeoutMs);
    observer.observe(document.documentElement, { childList: true, subtree: true });
  };

  // Settings
  const defaultSettings = {
    buttons: { wl: true, url: true, screenshot: true, clip: true, pip: true, speed: true, stats: true, vol: true },
    hotkeys: {
      toggleMute: 'm',
      toggleStats: 'shift+s',
      increaseSpeed: '.',
      decreaseSpeed: ',',
      increaseSpeedFine: 'shift+.',
      decreaseSpeedFine: 'shift+,',
      volumeUp: 'arrowup',
      volumeDown: 'arrowdown',
    },
    volumeBoostLevel: 1,
    enableVolumeBoost: true,
    enableScrollVolume: true,
    clipDuration: 5,
    clipDurationCtrl: 300,
    preferredQuality: 'auto',
    compactMode: false,
    isCollapsed: false,
    highContrastUI: false,
    playbackSpeed: 1,
    volumeCache: {},
    miniStatsCache: {},
    miniStatsPos: null,
  };

  const loadStoredSettings = () => {
    try {
      if (typeof GM_getValue === 'function') {
        const v = GM_getValue('ytee-settings', null);
        if (v) return typeof v === 'string' ? JSON.parse(v) : v;
      }
    } catch (e) { console.warn('GM_getValue failed', e); }
    try { const r = localStorage.getItem('ytee-settings'); if (r) return JSON.parse(r); } catch (e) { }
    return null;
  };

  const saveStoredSettings = (s) => {
    try { if (typeof GM_setValue === 'function') GM_setValue('ytee-settings', JSON.stringify(s)); } catch (e) { }
    try { localStorage.setItem('ytee-settings', JSON.stringify(s)); } catch (e) { }
  };

  let currentSettings = loadStoredSettings() || defaultSettings;

  const normalizeSettings = (s) => {
    if (!s || typeof s !== 'object') return JSON.parse(JSON.stringify(defaultSettings));
    const rs = {
      buttons: Object.assign({}, defaultSettings.buttons, s.buttons),
      hotkeys: Object.assign({}, defaultSettings.hotkeys, s.hotkeys),
      volumeBoostLevel: typeof s.volumeBoostLevel === 'number' ? s.volumeBoostLevel
        : s.volumeBoost === true ? 1.5 : defaultSettings.volumeBoostLevel,
      enableVolumeBoost: typeof s.enableVolumeBoost === 'boolean' ? s.enableVolumeBoost : defaultSettings.enableVolumeBoost,
      enableScrollVolume: typeof s.enableScrollVolume === 'boolean' ? s.enableScrollVolume : defaultSettings.enableScrollVolume,
      clipDuration: typeof s.clipDuration === 'number' ? Math.min(300, Math.max(1, s.clipDuration)) : defaultSettings.clipDuration,
      clipDurationCtrl: typeof s.clipDurationCtrl === 'number' ? Math.min(300, Math.max(1, s.clipDurationCtrl)) : defaultSettings.clipDurationCtrl,
      preferredQuality: typeof s.preferredQuality === 'string' ? s.preferredQuality : defaultSettings.preferredQuality,
      compactMode: typeof s.compactMode === 'boolean' ? s.compactMode : (typeof s.labelMode === 'boolean' ? !s.labelMode : defaultSettings.compactMode),
      isCollapsed: typeof s.isCollapsed === 'boolean' ? s.isCollapsed : defaultSettings.isCollapsed,
      highContrastUI: typeof s.highContrastUI === 'boolean' ? s.highContrastUI : defaultSettings.highContrastUI,
      playbackSpeed: typeof s.playbackSpeed === 'number' ? Math.min(16, Math.max(0.1, s.playbackSpeed)) : defaultSettings.playbackSpeed,
      volumeCache: typeof s.volumeCache === 'object' ? s.volumeCache : defaultSettings.volumeCache,
      miniStatsCache: typeof s.miniStatsCache === 'object' ? s.miniStatsCache : defaultSettings.miniStatsCache,
      miniStatsPos: s.miniStatsPos || defaultSettings.miniStatsPos,
    };
    // memory remembers 10
    ['volumeCache', 'miniStatsCache'].forEach(cacheKey => {
      const keys = Object.keys(rs[cacheKey]);
      if (keys.length > 10) {
        keys.slice(0, keys.length - 10).forEach(k => delete rs[cacheKey][k]);
      }
    });
    return rs;
  };

  const applyUIStates = (settings) => {
    document.documentElement.dataset.yteeLabels = settings.compactMode ? '0' : '1';
    document.documentElement.dataset.yteeHighContrast = settings.highContrastUI ? '1' : '0';
    const group = document.getElementById('custom-btn-group');
    if (group) {
      group.classList.toggle('collapsed', !!settings.isCollapsed);
      const tBtn = document.getElementById('custom-toggle-btn');
      if (tBtn) {
        const iconSpan = tBtn.querySelector('.ytee-icon');
        if (iconSpan) {
          while (iconSpan.firstChild) iconSpan.removeChild(iconSpan.firstChild);
          iconSpan.appendChild(ICON_DEFS[settings.isCollapsed ? 'expand' : 'hide']());
        }
        setBtnLabel(tBtn, '', settings.isCollapsed ? 'Expand UI' : 'Collapse UI');
      }
    }
  };

  currentSettings = normalizeSettings(currentSettings);
  applyUIStates(currentSettings);

  const getVideoAuthor = (player) => {
    if (player && typeof player.getVideoData === 'function') {
      const data = player.getVideoData();
      if (data?.author) return data.author.replace(/[<>:"/\\|?*\x00-\x1F]/g, '').trim();
    }
    return 'YouTube';
  };

  const formatTimestamp = (currentTime) => {
    const timeMs = Math.floor(currentTime * 1000);
    const mins = Math.floor(timeMs / 60000).toString().padStart(2, '0');
    const secs = Math.floor((timeMs % 60000) / 1000).toString().padStart(2, '0');
    const ms = (timeMs % 1000).toString().padStart(3, '0');
    return `${mins}-${secs}-${ms}`;
  };

  const getVideoId = (p) => {
    if (p && typeof p.getVideoData === 'function') {
      const id = p.getVideoData()?.video_id;
      if (id) return id;
    }
    return window.location.pathname.split('/').pop().split('?')[0].split('#')[0];
  };

  const setBtnLabel = (btn, text, tipText) => {
    const label = btn.querySelector('.ytee-label');
    if (label) label.textContent = (text !== undefined && text !== null) ? text : btn.dataset.defaultLabel;
    btn.dataset.tip = (tipText !== undefined && tipText !== null) ? tipText : btn.dataset.defaultTip;
  };

  const flashBtnState = (btn, state, duration = 1500) => {
    btn.classList.add(state);
    setTimeout(() => btn.classList.remove(state), duration);
  };

  // Main
  waitForVideo((video) => {
    let targetVolume = video.volume;
    let targetMuted = video.muted;

    const uw = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;

    let cachedPlayer = null;
    const getPlayer = () => {
      if (cachedPlayer) return cachedPlayer;
      cachedPlayer = uw.document.getElementById("movie_player") || uw.document.querySelector(".html5-video-player");
      return cachedPlayer;
    };

    const QUALITY_LABELS = {
      auto: 'Auto (YouTube decides)', hd2160: '4K (2160p)', hd1440: '1440p',
      hd1080: '1080p', hd720: '720p', large: '480p', medium: '360p', small: '240p', tiny: '144p',
    };
    const QUALITY_ORDER = ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny'];

    const applyQuality = () => {
      const pref = currentSettings.preferredQuality;
      if (!pref || pref === 'auto') return;
      const p = getPlayer();
      if (!p) return;
      try {
        if (typeof p.setPlaybackQualityRange === 'function') p.setPlaybackQualityRange(pref, pref);
        if (typeof p.setPlaybackQuality === 'function') p.setPlaybackQuality(pref);
      } catch (e) { console.warn('YTEE: applyQuality failed', e); }
    };

    let lastHolodexStatus = 'unknown';

    const hookPlayerEvents = () => {
      const p = getPlayer();
      if (!p || typeof p.addEventListener !== 'function') return;
      p.addEventListener('onStateChange', (state) => {
        if (state === 1 || state === 3) applyQuality();
        if (state === 1) sessionStorage.setItem('ytee-reload-count', '0');
      });
    };

    let qualityHookAttempts = 0;
    const tryHookQuality = () => {
      const p = getPlayer();
      if (p && typeof p.addEventListener === 'function') { hookPlayerEvents(); applyQuality(); }
      else if (qualityHookAttempts < 20) { qualityHookAttempts++; setTimeout(tryHookQuality, 500); }
    };
    tryHookQuality();

    let scriptChangeDepth = 0;
    let audioContext = null, gainNode = null, mediaSource = null, virtualMuted = video.muted, audioSetupFailed = false;
    let activeStream = null, rafPending = 0;
    let volTimeout, speedTimeout, controlsTimeout, clipRafId = null;

    const getBoostLevel = () => currentSettings.enableVolumeBoost ? Math.max(1, Number(currentSettings.volumeBoostLevel) || 1) : 1;

    // Volume
    const setupWebAudio = () => {
      if (gainNode || audioSetupFailed || !(window.AudioContext || window.webkitAudioContext)) return;
      try {
        const AudioCtor = window.AudioContext || window.webkitAudioContext;
        audioContext = new AudioCtor();
        mediaSource = audioContext.createMediaElementSource(video);
        gainNode = audioContext.createGain();
        mediaSource.connect(gainNode);
        gainNode.connect(audioContext.destination);
        video.volume = 1;
        if (audioContext.state === 'suspended') audioContext.resume().catch(e => console.warn('AudioContext resume failed', e));
      } catch (e) {
        console.warn('Web Audio setup failed', e);
        audioContext = null; gainNode = null; mediaSource = null; audioSetupFailed = true;
      }
    };

    const setGain = (linearVolume) => {
      if (!gainNode || !audioContext) return;
      if (audioContext.state === 'suspended') audioContext.resume().catch(e => console.warn('AudioContext resume failed', e));
      gainNode.gain.setTargetAtTime(linearVolume * getBoostLevel(), audioContext.currentTime, 0.01);
    };

    const applyAudioState = (volume, muted) => {
      scriptChangeDepth++;
      try {
        targetVolume = Math.min(1, Math.max(0, volume));
        targetMuted = muted;
        virtualMuted = muted;
        if (currentSettings.enableVolumeBoost && !gainNode && getBoostLevel() > 1) setupWebAudio();
        if (currentSettings.enableVolumeBoost && gainNode) {
          setGain(targetMuted ? 0 : targetVolume);
        } else {
          const p = getPlayer();
          if (targetMuted) { if (p && typeof p.mute === 'function') p.mute(); else video.muted = true; }
          else {
            if (p && typeof p.unMute === 'function') p.unMute(); else video.muted = false;
            if (p && typeof p.setVolume === 'function') p.setVolume(Math.round(targetVolume * 100)); else video.volume = targetVolume;
          }
        }
      } finally { scriptChangeDepth--; }
    };

    const applyVolume = (newVol) => {
      const clamped = Math.min(1, Math.max(0, Math.round(newVol * 100) / 100));
      applyAudioState(clamped, clamped === 0);
      vol.value = clamped;
      showVolumePercent(clamped === 0 ? 0 : clamped);

      const vid = getVideoId(getPlayer());
      if (vid) {
        currentSettings.volumeCache[vid] = clamped;
        saveStoredSettings(currentSettings);
      }
    };

    const toggleMute = () => {
      const newMuted = !targetMuted;
      applyAudioState(targetVolume, newMuted);
      muteBtn.classList.toggle("muted", newMuted);
      showVolumePercent(newMuted ? 0 : targetVolume);
    };

    // Overlays
    const volPct = Object.assign(document.createElement("div"), { id: "custom-vol-overlay" });
    const showVolumePercent = (volume) => {
      const text = Math.round(volume * 100) + "%";
      if (volPct.textContent !== text) volPct.textContent = text;
      volPct.classList.add("show");
      clearTimeout(volTimeout);
      volTimeout = setTimeout(() => volPct.classList.remove("show"), 1500);
    };

    const speedOverlay = Object.assign(document.createElement("div"), { id: "custom-speed-overlay" });
    const showSpeedOverlay = (rate) => {
      const text = rate + "x";
      if (speedOverlay.textContent !== text) speedOverlay.textContent = text;
      speedOverlay.classList.add("show");
      clearTimeout(speedTimeout);
      speedTimeout = setTimeout(() => speedOverlay.classList.remove("show"), 1500);
    };

    // Mute button
    const muteBtn = Object.assign(document.createElement("button"), { id: "custom-mute-btn" });
    muteBtn.addEventListener("click", toggleMute);

    // Volume slider
    const vol = Object.assign(document.createElement("input"), {
      id: "custom-vol-slider", type: "range", min: 0, max: 1, step: 0.01, value: video.volume,
    });
    vol.addEventListener("input", () => applyVolume(Number(vol.value)));

    video.addEventListener("volumechange", () => {
      if (scriptChangeDepth > 0) return;
      if (gainNode) { muteBtn.classList.toggle("muted", video.muted); return; }
      targetMuted = video.muted;
      targetVolume = video.muted ? targetVolume : video.volume;
      muteBtn.classList.toggle("muted", targetMuted);
      const displayVol = targetMuted ? 0 : targetVolume;
      if (Number(vol.value) !== displayVol) vol.value = displayVol;
    });

    let isHoveringSpeedBtn = false;
    let pendingWheelDelta = 0, wheelRafId = 0;
    window.addEventListener("wheel", (e) => {
      if (isSettingsOpen) {
        if (settingsContent.contains(e.target)) return;
        e.stopImmediatePropagation(); e.preventDefault(); return;
      }

      const shouldHandleSpeed = isHoveringSpeedBtn;
      const shouldHandleVolume = currentSettings.enableScrollVolume && !isHoveringSpeedBtn;

      if (!shouldHandleSpeed && !shouldHandleVolume) return;

      e.preventDefault();
      pendingWheelDelta += e.deltaY;
      if (wheelRafId) return;
      wheelRafId = requestAnimationFrame(() => {
        const delta = pendingWheelDelta;
        pendingWheelDelta = 0;
        wheelRafId = 0;
        if (shouldHandleSpeed) {
          applySpeed(targetSpeed + (delta > 0 ? -SPEED_STEP : SPEED_STEP));
        } else if (shouldHandleVolume) {
          applyVolume(targetVolume + (delta > 0 ? -0.05 : 0.05));
        }
      });
    }, { passive: false });

    // Stats
    let isStatsOpen = false, isMiniStatsOpen = false, miniStatsTimer = null;
    const miniStats = Object.assign(document.createElement("div"), { id: "custom-mini-stats" });
    const statsBtn = mkBtn('custom-stats-btn', 'stats', 'Stats', 'Stats (Ctrl = Mini)', 'Stats for Nerds (Shift+S)');

    // Dragging
    let isDragging = false, startX, startY, startL, startT;
    miniStats.addEventListener('mousedown', (e) => {
      if (e.button !== 0) return;
      isDragging = true;
      startX = e.clientX; startY = e.clientY;
      const rect = miniStats.getBoundingClientRect();
      startL = rect.left; startT = rect.top;
      miniStats.style.transition = 'none';
      e.preventDefault();
    });
    window.addEventListener('mousemove', (e) => {
      if (!isDragging) return;
      const x = startL + (e.clientX - startX);
      const y = startT + (e.clientY - startY);
      miniStats.style.left = x + 'px';
      miniStats.style.top = y + 'px';
      miniStats.style.bottom = 'auto';
    });
    window.addEventListener('mouseup', () => {
      if (!isDragging) return;
      isDragging = false;
      miniStats.style.transition = '';
      const rect = miniStats.getBoundingClientRect();
      const pL = rect.left / window.innerWidth;
      const pT = rect.top / window.innerHeight;
      currentSettings.miniStatsPos = { pL, pT };
      saveStoredSettings(currentSettings);
    });
    const applyMiniStatsPos = () => {
      if (!currentSettings.miniStatsPos || isDragging) return;
      const { pL, pT } = currentSettings.miniStatsPos;
      const w = window.innerWidth, h = window.innerHeight;
      const rect = miniStats.getBoundingClientRect();
      const x = Math.max(0, Math.min(w - rect.width, pL * w));
      const y = Math.max(0, Math.min(h - rect.height, pT * h));
      Object.assign(miniStats.style, { left: x + 'px', top: y + 'px', bottom: 'auto' });
    };
    applyMiniStatsPos();

    const miniStatsParts = {}, miniStatsWrappers = {};
    (() => {
      const mkPart = (key, label) => {
        const wrap = document.createElement('div');
        const b = document.createElement('b'); b.textContent = label;
        const s = document.createElement('span'); s.textContent = '-';
        wrap.append(b, s);
        miniStats.appendChild(wrap);
        miniStatsParts[key] = s;
        miniStatsWrappers[key] = wrap;
      };
      mkPart('bandwidth', 'Speed');
      mkPart('buffer', 'Buffer');
      mkPart('latency', 'Latency');
      mkPart('dropped', 'Drop');
      mkPart('views', 'Watching');
    })();

    let lastWatcherTime = 0;
    const formatViewers = (n) => {
      if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
      if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
      return String(n);
    };

    const fetchViewers = (videoId) => {
      const url = `https://holodex.net/api/v2/videos/${videoId}?include=live_info`;
      return new Promise((resolve) => {
        if (typeof GM_xmlhttpRequest === 'undefined') return resolve({ v: '-', live: false });

        GM_xmlhttpRequest({
          method: 'GET', url: url, anonymous: true,
          headers: { "Referer": "https://holodex.net/", "Origin": "https://holodex.net" },
          onload: (r) => {
            if (r.status === 200) {
              try {
                const json = JSON.parse(r.responseText);
                lastHolodexStatus = json.status || 'unknown';
                const v = json.live_viewers;
                resolve({ v: v && v > 0 ? formatViewers(v) : '-', live: lastHolodexStatus === 'live' });
              } catch (e) { resolve({ v: '-', live: false }); }
            } else { resolve({ v: '-', live: false }); }
          },
          onerror: () => resolve({ v: '-', live: false }),
          timeout: 8000
        });
      });
    };

    const updateMiniStats = () => {
      if (!isMiniStatsOpen) return;
      try {
        const p = getPlayer();
        if (!p) return;
        const stats = typeof p.getStatsForNerds === 'function' ? p.getStatsForNerds() : null;

        let buffer = null;
        if (stats?.buffer_health_seconds) {
          buffer = parseFloat(stats.buffer_health_seconds).toFixed(2);
        } else if (video.buffered.length > 0) {
          buffer = (video.buffered.end(video.buffered.length - 1) - video.currentTime).toFixed(2);
        }

        let latency = null;
        if (stats?.live_latency_secs) {
          latency = parseFloat(stats.live_latency_secs);
        }
        if (latency == null || latency > 1000) {
          const isLive = p.getVideoData?.().isLive;
          if (isLive) {
            const seekable = video.seekable;
            if (seekable?.length > 0) {
              const edge = seekable.end(seekable.length - 1);
              if (edge - video.currentTime < 1000) latency = Math.max(0, edge - video.currentTime);
            }
            if (latency == null || latency > 1000) {
              const dur = p.getDuration?.();
              if (dur > 0 && dur - video.currentTime < 1000) latency = Math.max(0, dur - video.currentTime);
            }
          }
        }

        // Dropped frames
        const dropped = video.getVideoPlaybackQuality()?.droppedVideoFrames ?? 0;

        const formattedLatency = latency != null ? latency.toFixed(2) : 'N/A';
        const dCount = Number(dropped);
        let dColor = '';
        if (dCount > 0 && dCount <= 100) dColor = '#3498db';
        else if (dCount > 100 && dCount <= 250) dColor = '#f1c40f';
        else if (dCount > 250 && dCount <= 350) dColor = '#e67e22';
        else if (dCount > 350) dColor = '#e74c3c';

        let bandwidth = 'N/A';
        if (stats?.bandwidth_kbps) {
          const kbps = parseFloat(stats.bandwidth_kbps);
          if (!isNaN(kbps)) {
            bandwidth = kbps >= 1000
              ? (kbps / 1000).toFixed(1) + ' Mbps'
              : Math.round(kbps) + ' Kbps';
          }
        }
        miniStatsParts.bandwidth.textContent = bandwidth;

        miniStatsParts.buffer.textContent = buffer != null ? buffer + 's' : 'N/A';
        miniStatsParts.latency.textContent = formattedLatency !== 'N/A' ? formattedLatency + 's' : 'N/A';
        miniStatsParts.dropped.textContent = dropped;
        miniStatsParts.dropped.style.color = dColor;

        const now = Date.now();
        const viewsText = miniStatsParts.views.textContent.trim();
        const isInitial = viewsText === '-' || viewsText === '';
        if (now - lastWatcherTime >= (isInitial ? 5000 : 90000)) {
          lastWatcherTime = now;
          const videoId = getVideoId(p);
          if (videoId && videoId.length > 5) {
            fetchViewers(videoId).then(res => {
              if (res.v && res.v !== '-') miniStatsParts.views.textContent = res.v;
              if (miniStatsWrappers.views) {
                miniStatsWrappers.views.style.display = (lastHolodexStatus === 'past') ? 'none' : '';
              }
            });
          }
        }
      } finally {
        if (isMiniStatsOpen) miniStatsTimer = setTimeout(updateMiniStats, 2000);
      }
    };

    const toggleMiniStats = () => {
      isMiniStatsOpen = !isMiniStatsOpen;
      miniStats.classList.toggle("show", isMiniStatsOpen);
      statsBtn.classList.toggle("active", isMiniStatsOpen);
      clearTimeout(miniStatsTimer);
      if (isMiniStatsOpen) updateMiniStats();

      const vid = getVideoId(getPlayer());
      if (vid) {
        currentSettings.miniStatsCache[vid] = isMiniStatsOpen;
        saveStoredSettings(currentSettings);
      }
    };

    const toggleStats = (e) => {
      if (e && e.ctrlKey) { toggleMiniStats(); return; }
      const p = getPlayer();
      if (!p) return;
      if (isStatsOpen && p.hideVideoInfo) { p.hideVideoInfo(); isStatsOpen = false; }
      else if (p.showVideoInfo) { p.showVideoInfo(); isStatsOpen = true; }
      statsBtn.classList.toggle("nerds-active", isStatsOpen);
    };
    statsBtn.addEventListener("click", toggleStats);

    // Speed
    const SPEED_MIN = 0.1, SPEED_MAX = 16, SPEED_STEP = 0.05, SPEED_STEP_FINE = 0.01, SPEED_DEFAULT = 1;
    let targetSpeed = Math.round((video.playbackRate || SPEED_DEFAULT) * 100) / 100;

    const speedBtn = mkBtn('custom-speed-btn', 'speed', targetSpeed + 'x', 'Speed', 'Playback Speed');

    const updateSpeedBtnText = (rate) => {
      setBtnLabel(speedBtn, rate + 'x', `Speed: ${rate}x`);
    };

    const applySpeed = (rate) => {
      targetSpeed = Math.round(Math.min(SPEED_MAX, Math.max(SPEED_MIN, rate)) * 100) / 100;
      if (video.playbackRate !== targetSpeed) video.playbackRate = targetSpeed;
      updateSpeedBtnText(targetSpeed);
      speedBtn.classList.toggle("modified", targetSpeed !== 1);
      showSpeedOverlay(targetSpeed);
      const speedInput = document.getElementById('ytee-precise-speed');
      if (speedInput && parseFloat(speedInput.value) !== targetSpeed) speedInput.value = targetSpeed;
    };

    speedBtn.addEventListener("click", (e) => {
      const step = e.shiftKey ? SPEED_STEP_FINE : SPEED_STEP;
      const next = targetSpeed + step;
      applySpeed(next > SPEED_MAX ? SPEED_MIN : next);
    });
    speedBtn.addEventListener("contextmenu", (e) => { e.preventDefault(); applySpeed(SPEED_DEFAULT); });
    speedBtn.addEventListener("mouseenter", () => { isHoveringSpeedBtn = true; });
    speedBtn.addEventListener("mouseleave", () => { isHoveringSpeedBtn = false; });

    // Snap
    const screenshotBtn = mkBtn('custom-screenshot-btn', 'screenshot', 'Snap', 'Take Screenshot (Ctrl = Save)');
    screenshotBtn.addEventListener("click", (e) => {
      const canvas = document.createElement("canvas");
      canvas.width = video.videoWidth; canvas.height = video.videoHeight;
      canvas.getContext("2d", { alpha: false }).drawImage(video, 0, 0);
      const author = getVideoAuthor(getPlayer());
      const timestamp = formatTimestamp(video.currentTime);
      canvas.toBlob((blob) => {
        if (!blob) return;
        if (e.ctrlKey) {
          const objUrl = URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.href = objUrl; a.download = `${author}_${timestamp}.png`; a.click();
          URL.revokeObjectURL(objUrl);
        }
        if (navigator.clipboard) {
          if (typeof ClipboardItem !== "undefined") {
            navigator.clipboard.write([new ClipboardItem({ "image/png": blob })])
              .then(() => {
                setBtnLabel(screenshotBtn, e.ctrlKey ? '✓ Saved!' : '✓ Copied!');
                flashBtnState(screenshotBtn, 'success');
                setTimeout(() => setBtnLabel(screenshotBtn), 1500);
              })
              .catch(() => {
                setBtnLabel(screenshotBtn, '✗ Error');
                flashBtnState(screenshotBtn, 'error');
                setTimeout(() => setBtnLabel(screenshotBtn), 1500);
              });
          } else {
            if (!e.ctrlKey) { setBtnLabel(screenshotBtn, '✗ N/A'); setTimeout(() => setBtnLabel(screenshotBtn, 'Snap'), 1500); }
          }
        }
      }, "image/png");
    });

    // Clip
    const clipOverlay = Object.assign(document.createElement('div'), { id: 'custom-clip-overlay' });
    const clipBtn = mkBtn('custom-clip-btn', 'clip', 'Clip', 'Record Clip (Ctrl = Long)');
    let clipRecorder = null;

    const stopClip = (cancelled) => {
      if (!clipRecorder) return;
      if (clipRecorder.state !== 'inactive') clipRecorder.stop();
      clipRecorder = null;
      if (activeStream) { activeStream.getTracks().forEach(t => t.stop()); activeStream = null; }
      cancelAnimationFrame(clipRafId); clipRafId = null;
      clipBtn.classList.remove('recording');
      setBtnLabel(clipBtn, cancelled ? '✗ Cancelled' : 'Processing…');
      clipOverlay.classList.remove('show');
      if (cancelled) setTimeout(() => setBtnLabel(clipBtn), 1500);
    };

    const startClip = (durationSec) => {
      if (clipRecorder) { stopClip(true); return; }
      if (!video.captureStream) { setBtnLabel(clipBtn, '✗ N/A'); setTimeout(() => setBtnLabel(clipBtn), 2000); return; }

      const mimeType = MediaRecorder.isTypeSupported('video/webm; codecs=vp9,opus')
        ? 'video/webm; codecs=vp9,opus'
        : MediaRecorder.isTypeSupported('video/webm; codecs=vp8,opus')
          ? 'video/webm; codecs=vp8,opus' : 'video/webm';

      // Clip Recording Setup
      const width = video.videoWidth || 1920;
      const height = video.videoHeight || 1080;
      const px = width * height;
      const isVP9 = mimeType.includes('vp9');

      let fps = 30;
      const p = getPlayer();
      if (p && typeof p.getStatsForNerdsData === 'function') {
        const s = p.getStatsForNerdsData();
        if (s && s.resolution) {
          const m = s.resolution.match(/@(\d+)/);
          if (m) fps = parseInt(m[1]);
        }
      }

      const BPP_MAP = [
        [426 * 240, 0.250, 0.350],
        [640 * 360, 0.200, 0.300],
        [854 * 480, 0.170, 0.250],
        [1280 * 720, 0.140, 0.200],
        [1920 * 1080, 0.110, 0.160],
        [2560 * 1440, 0.080, 0.120],
        [3840 * 2160, 0.060, 0.090],
      ];

      const [, vp9bpp, vp8bpp] = BPP_MAP.find(([maxPx]) => px <= maxPx) ?? BPP_MAP.at(-1);
      const videoBitsPerSecond = Math.round(width * height * fps * (isVP9 ? vp9bpp : vp8bpp));

      try {
        activeStream = video.captureStream();
      } catch (e) {
        console.warn('YTEE: captureStream failed', e);
        setBtnLabel(clipBtn, '✗ Error'); setTimeout(() => setBtnLabel(clipBtn), 2000); return;
      }

      const chunks = [];
      let recorder;
      try {
        recorder = new MediaRecorder(activeStream, {
          mimeType,
          videoBitsPerSecond,
          audioBitsPerSecond: 192_000
        });
      } catch (e) {
        console.warn('YTEE: MediaRecorder init failed', e);
        activeStream.getTracks().forEach(t => t.stop()); activeStream = null;
        setBtnLabel(clipBtn, '✗ Error'); setTimeout(() => setBtnLabel(clipBtn), 2000); return;
      }

      recorder.ondataavailable = (ev) => { if (ev.data && ev.data.size > 0) chunks.push(ev.data); };
      recorder.onstop = () => {
        if (chunks.length === 0) { setBtnLabel(clipBtn, '✗ Empty'); setTimeout(() => setBtnLabel(clipBtn), 1500); return; }
        const blob = new Blob(chunks, { type: mimeType });
        const author = getVideoAuthor(getPlayer());
        const timestamp = formatTimestamp(video.currentTime);
        const objUrl = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = objUrl; a.download = `${author}_${timestamp}.webm`; a.click();
        URL.revokeObjectURL(objUrl);
        setBtnLabel(clipBtn, '✓ Saved!');
        setTimeout(() => setBtnLabel(clipBtn), 2000);
      };
      recorder.onerror = (ev) => {
        console.warn('YTEE: MediaRecorder error', ev);
        stopClip(true); setBtnLabel(clipBtn, '✗ Error'); setTimeout(() => setBtnLabel(clipBtn), 2000);
      };

      clipRecorder = recorder;
      recorder.start(200);
      clipBtn.classList.add('recording');
      setBtnLabel(clipBtn, 'Stop');

      const endTime = performance.now() + durationSec * 1000;
      const tick = () => {
        const remaining = endTime - performance.now();
        if (remaining <= 0) { stopClip(false); return; }
        const text = `REC ${(remaining / 1000).toFixed(1)}s`;
        if (clipOverlay.textContent !== text) clipOverlay.textContent = text;
        clipOverlay.classList.add('show');
        clipRafId = requestAnimationFrame(tick);
      };
      clipRafId = requestAnimationFrame(tick);
    };

    clipBtn.addEventListener('click', (e) => {
      if (clipRecorder) { stopClip(true); return; }
      const dur = e.ctrlKey ? (Number(currentSettings.clipDurationCtrl) || 300) : (Number(currentSettings.clipDuration) || 5);
      startClip(dur);
    });
    clipBtn.addEventListener('contextmenu', (e) => { e.preventDefault(); stopClip(true); });

    // PiP
    const pipSupported = document.pictureInPictureEnabled && typeof video.requestPictureInPicture === "function";
    const pipBtn = mkBtn('custom-pip-btn', 'pip', 'PiP', 'Picture-in-Picture');
    if (pipSupported) {
      pipBtn.addEventListener("click", async () => {
        try {
          if (document.pictureInPictureElement) await document.exitPictureInPicture();
          else await video.requestPictureInPicture();
        } catch (err) { console.error("PiP failed:", err); }
      });
    } else {
      pipBtn.style.display = "none";
    }

    // URL
    const urlBtn = mkBtn('custom-url-btn', 'url', 'URL', 'Copy URL (Ctrl+Click = with timestamp)');
    urlBtn.addEventListener("click", async (e) => {
      try {
        const videoId = getVideoId(getPlayer());
        let url = `https://youtu.be/${videoId}`;
        if (e.ctrlKey) url += `?t=${Math.floor(video.currentTime)}`;
        if (navigator.clipboard) {
          await navigator.clipboard.writeText(url);
          setBtnLabel(urlBtn, '✓ Copied!');
          flashBtnState(urlBtn, 'success');
          setTimeout(() => setBtnLabel(urlBtn), 1500);
        }
      } catch (err) { console.error("Copy URL failed:", err); flashBtnState(urlBtn, 'error'); }
    });

    // Watch Later
    const wlBtn = mkBtn('custom-wl-btn', 'wl', 'WL', 'Watch Later');
    let cachedApiKey = null, cachedContext = null;
    const INNERTUBE_CACHE_TTL = 24 * 60 * 60 * 1000;
    try {
      if (typeof GM_getValue === 'function') {
        const stored = GM_getValue('ytee-innertube', null);
        if (stored) {
          const parsed = JSON.parse(stored);
          const age = Date.now() - (parsed.savedAt || 0);
          if (age < INNERTUBE_CACHE_TTL && parsed.apiKey && parsed.context) { cachedApiKey = parsed.apiKey; cachedContext = parsed.context; }
        }
      }
    } catch (e) { console.warn('InnerTube cache read failed', e); }

    const sha1 = async (str) => {
      const buf = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(str));
      return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, "0")).join("");
    };
    const getSapisid = () => { const m = document.cookie.match(/(?:^|;\s*)(?:__Secure-3PAPISID|SAPISID)=([^;]+)/); return m ? m[1] : null; };

    const getInnertubeConfig = async (videoId) => {
      if (cachedApiKey && cachedContext) return { apiKey: cachedApiKey, context: cachedContext };
      const localYtcfg = uw.ytcfg || (uw.yt && uw.yt.config_);
      if (localYtcfg && localYtcfg.get) {
        const key = localYtcfg.get("INNERTUBE_API_KEY"), ctx = localYtcfg.get("INNERTUBE_CONTEXT");
        if (key && ctx) {
          cachedApiKey = key; cachedContext = ctx;
          try { if (typeof GM_setValue === 'function') GM_setValue('ytee-innertube', JSON.stringify({ apiKey: key, context: ctx, savedAt: Date.now() })); } catch (e) { }
          return { apiKey: key, context: ctx };
        }
      }
      return new Promise((resolve, reject) => {
        if (typeof GM_xmlhttpRequest === "undefined") return reject(new Error("GM_xmlhttpRequest unavailable"));
        GM_xmlhttpRequest({
          method: "GET", url: `https://www.youtube.com/watch?v=${videoId}`,
          headers: { "Accept-Language": navigator.language || "en-US,en;q=0.9" },
          onload: (res) => {
            const m = res.responseText.match(/ytcfg\.set\s*\(({[\s\S]+?})\s*\)\s*;/);
            if (!m) return reject(new Error("ytcfg block not found"));
            try {
              const cfg = JSON.parse(m[1]);
              if (!cfg.INNERTUBE_API_KEY) return reject(new Error("INNERTUBE_API_KEY missing"));
              cachedApiKey = cfg.INNERTUBE_API_KEY; cachedContext = cfg.INNERTUBE_CONTEXT;
              try { if (typeof GM_setValue === 'function') GM_setValue('ytee-innertube', JSON.stringify({ apiKey: cachedApiKey, context: cachedContext, savedAt: Date.now() })); } catch (e) { }
              resolve({ apiKey: cachedApiKey, context: cachedContext });
            } catch (e) { reject(e); }
          },
          onerror: () => reject(new Error("Network error")),
        });
      });
    };

    const clearInnertubeCache = () => {
      cachedApiKey = null; cachedContext = null;
      try { if (typeof GM_setValue === 'function') GM_setValue('ytee-innertube', null); } catch (e) { }
    };

    wlBtn.addEventListener("click", async () => {
      try {
        setBtnLabel(wlBtn, '…');
        const videoId = getVideoId(getPlayer());
        if (!videoId || videoId.length < 5) { setBtnLabel(wlBtn, '✗ Err'); setTimeout(() => setBtnLabel(wlBtn), 1500); return; }
        const sapisid = getSapisid();
        if (!sapisid) { setBtnLabel(wlBtn, '✗ Login'); setTimeout(() => setBtnLabel(wlBtn), 1500); return; }
        const attemptRequest = async () => {
          const { apiKey, context } = await getInnertubeConfig(videoId);
          const ts = Math.floor(Date.now() / 1000);
          const hashStr = await sha1(`${ts} ${sapisid} https://www.youtube.com`);
          const sapisidHash = `${ts}_${hashStr}`;
          const payload = { context, playlistId: "WL", actions: [{ addedVideoId: videoId, action: "ACTION_ADD_VIDEO" }] };
          return new Promise((resolve, reject) => {
            if (typeof GM_xmlhttpRequest !== "undefined") {
              GM_xmlhttpRequest({
                method: "POST",
                url: `https://www.youtube.com/youtubei/v1/browse/edit_playlist?key=${apiKey}&prettyPrint=false`,
                headers: { "Content-Type": "application/json", "X-Origin": "https://www.youtube.com", "X-Goog-AuthUser": "0", "Authorization": `SAPISIDHASH ${sapisidHash}` },
                data: JSON.stringify(payload),
                onload: (res) => resolve(res.status),
                onerror: () => reject(new Error("Network error")),
              });
            } else { reject(new Error("GM_xmlhttpRequest required")); }
          });
        };
        let status = await attemptRequest();
        if (status === 401 || status === 403) { clearInnertubeCache(); status = await attemptRequest(); }
        if (status === 200) { setBtnLabel(wlBtn, '✓ Saved'); flashBtnState(wlBtn, 'success'); } else { throw new Error(`HTTP ${status}`); }
        setTimeout(() => setBtnLabel(wlBtn), 1500);
      } catch (err) { console.error("Watch Later failed:", err); setBtnLabel(wlBtn, '✗ Err'); flashBtnState(wlBtn, 'error'); setTimeout(() => setBtnLabel(wlBtn), 1500); }
    });

    const toggleBtn = mkBtn('custom-toggle-btn', currentSettings.isCollapsed ? 'expand' : 'hide', '', 'Collapse UI', null, false);
    toggleBtn.addEventListener('click', () => {
      currentSettings.isCollapsed = !currentSettings.isCollapsed;
      saveStoredSettings(currentSettings);
      applyUIStates(currentSettings);
    });

    // Settings Modal
    const settingsBtn = mkBtn('custom-settings-btn', 'settings', 'Settings', 'Settings Menu', null, false);
    const settingsModal = document.createElement("div");
    settingsModal.id = "custom-settings-modal";
    let isSettingsOpen = false;
    const settingsContent = document.createElement("div");
    settingsContent.id = "custom-settings-content";
    const settingsHeader = Object.assign(document.createElement("div"), { id: "ytee-settings-header" });
    const settingsTitle = Object.assign(document.createElement("h2"), { textContent: "YouTube Embed Enhancer" });
    const infoBtn = Object.assign(document.createElement('div'), { className: 'ytee-info-btn', title: 'What do these stats mean?' });
    infoBtn.appendChild(ICON_DEFS.info());
    settingsHeader.append(settingsTitle, infoBtn);

    const infoBox = Object.assign(document.createElement('div'), { className: 'ytee-info-box' });
    const mkInfoRow = (title, text) => {
      const p = document.createElement('p');
      const s = document.createElement('strong'); s.textContent = title;
      p.append(s, document.createTextNode(' ' + text));
      return p;
    };
    infoBox.append(
      mkInfoRow('Speed', 'How fast your internet is. Higher = smoother high-quality video.'),
      mkInfoRow('Buffer', "Pre-loaded video 'cushion'. If this hits 0, the video will pause to load."),
      mkInfoRow('Latency', 'Your delay from live. Lower = closer to real-time.'),
      mkInfoRow('Drop', 'If this rises, your PC is struggling and the video will look laggy or stutter.'),
      Object.assign(document.createElement('a'), {
        href: 'https://github.com/jmpatag/YouTube-Embed-Enhancer',
        target: '_blank',
        className: 'ytee-info-link',
        textContent: 'Source: YouTube Embed Enhancer (GitHub)'
      })
    );
    infoBtn.addEventListener('click', () => infoBox.classList.toggle('show'));

    const settingsSubtitle = Object.assign(document.createElement("p"), { id: "ytee-settings-subtitle", textContent: "Customize your embed experience" });
    const settingsItems = Object.assign(document.createElement("div"), { id: "custom-settings-items" });
    const settingsButtons = Object.assign(document.createElement("div"), { id: "custom-settings-buttons" });
    const restoreBtn = Object.assign(document.createElement("button"), { id: "custom-settings-restore", textContent: "Restore defaults" });
    const cancelBtn = Object.assign(document.createElement("button"), { id: "custom-settings-cancel", textContent: "Cancel" });
    const saveBtn = Object.assign(document.createElement("button"), { id: "custom-settings-save", textContent: "Save" });
    settingsButtons.append(restoreBtn, cancelBtn, saveBtn);
    settingsContent.append(settingsHeader, settingsSubtitle, infoBox, settingsItems, settingsButtons);
    settingsModal.appendChild(settingsContent);
    document.body.appendChild(settingsModal);

    const mkToggleRow = (id, labelText, checked) => {
      const div = Object.assign(document.createElement('div'), { className: 'setting-item' });
      const wrap = Object.assign(document.createElement('div'), { className: 'ytee-toggle-wrap' });
      const cb = Object.assign(document.createElement('input'), { type: 'checkbox', id, checked });
      const track = Object.assign(document.createElement('label'), { className: 'ytee-toggle-track', htmlFor: id });
      track.appendChild(Object.assign(document.createElement('span'), { className: 'ytee-toggle-thumb' }));
      wrap.append(cb, track);
      const label = Object.assign(document.createElement('label'), { htmlFor: id, textContent: labelText });
      div.append(label, wrap);
      return div;
    };

    const showSettingsModal = () => {
      const items = settingsItems;
      while (items.firstChild) items.removeChild(items.firstChild);

      // Playback
      const sectionQ = Object.assign(document.createElement('h3'), { className: 'setting-section-title', textContent: 'Playback' });
      items.appendChild(sectionQ);
      const qualityDiv = Object.assign(document.createElement('div'), { className: 'setting-item' });
      const qualityLabel = Object.assign(document.createElement('label'), { htmlFor: 'preferred-quality', textContent: 'Preferred quality' });
      const qualitySelect = Object.assign(document.createElement('select'), { id: 'preferred-quality', className: 'ytee-quality-select' });
      const p = getPlayer();
      let availableLevels = [];
      if (p && typeof p.getAvailableQualityLevels === 'function') availableLevels = p.getAvailableQualityLevels().filter(q => q !== 'auto' && q !== 'unknown');
      if (availableLevels.length === 0) availableLevels = QUALITY_ORDER.slice();
      qualitySelect.appendChild(Object.assign(document.createElement('option'), { value: 'auto', textContent: QUALITY_LABELS['auto'] }));
      availableLevels.forEach(level => qualitySelect.appendChild(Object.assign(document.createElement('option'), { value: level, textContent: QUALITY_LABELS[level] || level })));
      qualitySelect.value = currentSettings.preferredQuality || 'auto';
      if (!qualitySelect.value) qualitySelect.value = 'auto';
      qualityDiv.append(qualityLabel, qualitySelect);
      items.appendChild(qualityDiv);
      items.appendChild(Object.assign(document.createElement('div'), { className: 'ytee-quality-note', textContent: 'Applies to all embeds instantly. Falls back to closest available level.' }));

      // Volume
      const sectionVol = Object.assign(document.createElement('h3'), { className: 'setting-section-title', textContent: 'Volume' });
      items.appendChild(sectionVol);
      items.appendChild(mkToggleRow('ytee-enable-scroll-volume', 'Enable scroll wheel volume', currentSettings.enableScrollVolume));
      const boostToggleRow = mkToggleRow('ytee-enable-volume-boost', 'Enable volume boost', currentSettings.enableVolumeBoost);
      items.appendChild(boostToggleRow);
      const boostToggleInput = boostToggleRow.querySelector('input');

      const volBoostDiv = Object.assign(document.createElement('div'), { className: 'setting-item' });
      const volBoostLabel = Object.assign(document.createElement('label'), { htmlFor: 'volume-boost-level', textContent: 'Boost level' });
      const volBoostInput = Object.assign(document.createElement('input'), { type: 'range', id: 'volume-boost-level', min: '1.0', max: '3.0', step: '0.1', value: currentSettings.volumeBoostLevel });
      volBoostInput.style.width = '140px';
      const volBoostValue = Object.assign(document.createElement('span'), { className: 'ytee-slider-value', textContent: `${Number(currentSettings.volumeBoostLevel).toFixed(1)}x` });
      volBoostInput.addEventListener('input', () => { volBoostValue.textContent = `${Number(volBoostInput.value).toFixed(1)}x`; });

      const updateBoostState = () => {
        const enabled = boostToggleInput.checked;
        volBoostInput.disabled = !enabled;
        volBoostDiv.style.opacity = enabled ? '1' : '0.4';
        volBoostDiv.style.filter = enabled ? '' : 'grayscale(1)';
        volBoostDiv.style.pointerEvents = enabled ? 'auto' : 'none';
      };
      boostToggleInput.addEventListener('change', updateBoostState);

      volBoostDiv.append(volBoostLabel, volBoostInput, volBoostValue);
      items.appendChild(volBoostDiv);
      updateBoostState();


      // Clip Recording
      const sectionClip = Object.assign(document.createElement('h3'), { className: 'setting-section-title', textContent: 'Clip Recording' });
      items.appendChild(sectionClip);

      const clipDurDiv = Object.assign(document.createElement('div'), { className: 'setting-item' });
      const clipDurLabel = Object.assign(document.createElement('label'), { htmlFor: 'clip-duration', textContent: 'Duration (seconds)' });
      const clipDurInput = Object.assign(document.createElement('input'), { type: 'number', id: 'clip-duration', min: '1', max: '300', step: '1', value: currentSettings.clipDuration, className: 'hk-input' });
      clipDurInput.style.width = '80px';
      clipDurDiv.append(clipDurLabel, clipDurInput);
      items.appendChild(clipDurDiv);

      const clipCtrlDiv = Object.assign(document.createElement('div'), { className: 'setting-item' });
      const clipCtrlLabel = Object.assign(document.createElement('label'), { htmlFor: 'clip-duration-ctrl', textContent: 'Ctrl+Click duration (seconds)' });
      const clipCtrlInput = Object.assign(document.createElement('input'), { type: 'number', id: 'clip-duration-ctrl', min: '1', max: '300', step: '1', value: currentSettings.clipDurationCtrl, className: 'hk-input' });
      clipCtrlInput.style.width = '80px';
      clipCtrlDiv.append(clipCtrlLabel, clipCtrlInput);
      items.appendChild(clipCtrlDiv);
      items.appendChild(Object.assign(document.createElement('div'), { className: 'setting-note', textContent: 'Higher resolutions require more system resources.' }));

      // Hotkeys
      const hotkeyNames = {
        toggleMute: 'Toggle Mute', toggleStats: 'Toggle Stats',
        increaseSpeed: 'Increase Speed', decreaseSpeed: 'Decrease Speed',
        increaseSpeedFine: 'Increase Speed (fine)', decreaseSpeedFine: 'Decrease Speed (fine)',
        volumeUp: 'Volume Up', volumeDown: 'Volume Down',
      };
      const sectionHK = Object.assign(document.createElement('h3'), { className: 'setting-section-title', textContent: 'Hotkeys' });
      items.appendChild(sectionHK);
      Object.keys(hotkeyNames).forEach(key => {
        const div = Object.assign(document.createElement('div'), { className: 'setting-item' });
        const input = Object.assign(document.createElement('input'), { type: 'text', id: `hk-${key}`, value: currentSettings.hotkeys[key], className: 'hk-input' });
        input.addEventListener('blur', () => { input.value = sanitizeHotkeyInput(input.value); });
        const label = Object.assign(document.createElement('label'), { htmlFor: `hk-${key}`, textContent: hotkeyNames[key] });
        div.append(label, input);
        items.appendChild(div);
      });

      // Appearance
      const sectionUI = Object.assign(document.createElement('h3'), { className: 'setting-section-title', textContent: 'Appearance' });
      items.appendChild(sectionUI);
      items.appendChild(mkToggleRow('ytee-compact-mode', 'Compact icon mode (hides text labels)', currentSettings.compactMode));
      items.appendChild(Object.assign(document.createElement('div'), { className: 'setting-note', textContent: 'Compact mode saves space in multi-stream layouts by hiding text labels.' }));
      items.appendChild(mkToggleRow('ytee-high-contrast', 'High Contrast Mode', currentSettings.highContrastUI));
      items.appendChild(Object.assign(document.createElement('div'), { className: 'setting-note', textContent: 'Uses solid backgrounds for buttons.' }));

      const buttonNames = {
        vol: 'Volume Controls', wl: 'Watch Later', url: 'Copy URL', screenshot: 'Screenshot',
        clip: 'Clip', pip: 'Picture-in-Picture (Firefox unsupported)',
        speed: 'Playback Speed', stats: 'Stats for Nerds',
      };
      Object.keys(buttonNames).forEach(key => items.appendChild(mkToggleRow(`btn-${key}`, buttonNames[key], currentSettings.buttons[key])));

      settingsModal.classList.add('show');
      isSettingsOpen = true;
    };

    const hideSettingsModal = () => { settingsModal.classList.remove('show'); isSettingsOpen = false; };

    settingsBtn.addEventListener('click', showSettingsModal);
    cancelBtn.addEventListener('click', hideSettingsModal);

    restoreBtn.addEventListener('click', () => {
      currentSettings = JSON.parse(JSON.stringify(defaultSettings));
      applyUIStates(currentSettings);
      if (settingsModal.classList.contains('show')) showSettingsModal();
      restoreBtn.textContent = 'Restored!'; restoreBtn.disabled = true;
      setTimeout(() => { restoreBtn.textContent = 'Restore defaults'; restoreBtn.disabled = false; }, 1000);
    });

    saveBtn.addEventListener('click', () => {
      const newSettings = { buttons: {}, hotkeys: {} };
      Object.keys(defaultSettings.buttons).forEach(key => {
        const el = document.getElementById(`btn-${key}`);
        if (el) newSettings.buttons[key] = el.checked;
      });
      Object.keys(defaultSettings.hotkeys).forEach(key => {
        const el = document.getElementById(`hk-${key}`);
        if (el) newSettings.hotkeys[key] = sanitizeHotkeyInput(el.value);
      });
      newSettings.volumeBoostLevel = Number(document.getElementById('volume-boost-level').value) || 1;
      newSettings.enableVolumeBoost = document.getElementById('ytee-enable-volume-boost').checked;
      newSettings.enableScrollVolume = document.getElementById('ytee-enable-scroll-volume').checked;
      newSettings.clipDuration = Math.min(300, Math.max(1, Number(document.getElementById('clip-duration').value) || 5));
      newSettings.clipDurationCtrl = Math.min(300, Math.max(1, Number(document.getElementById('clip-duration-ctrl').value) || 300));
      newSettings.preferredQuality = document.getElementById('preferred-quality').value || 'auto';
      newSettings.compactMode = document.getElementById('ytee-compact-mode').checked;
      newSettings.highContrastUI = document.getElementById('ytee-high-contrast').checked;
      newSettings.volumeCache = currentSettings.volumeCache || {};
      newSettings.isCollapsed = currentSettings.isCollapsed;
      currentSettings = newSettings;
      saveStoredSettings(currentSettings);
      buildHotkeyMap();
      applyVolume(targetVolume);
      applyQuality();
      applyUIStates(currentSettings);
      updateButtonVisibility();
      saveBtn.textContent = 'Saved'; saveBtn.disabled = true;
      setTimeout(() => { hideSettingsModal(); saveBtn.textContent = 'Save'; saveBtn.disabled = false; }, 350);
    });

    const updateButtonVisibility = () => {
      const buttonMap = { wl: wlBtn, url: urlBtn, screenshot: screenshotBtn, clip: clipBtn, pip: pipBtn, speed: speedBtn, stats: statsBtn };
      let anyCollapsibleVisible = false;
      Object.keys(buttonMap).forEach(key => {
        const isVisible = key === 'pip'
          ? currentSettings.buttons[key] && pipSupported
          : currentSettings.buttons[key];
        buttonMap[key].style.display = isVisible ? '' : 'none';
        if (isVisible) anyCollapsibleVisible = true;
      });
      const volDisplay = currentSettings.buttons.vol ? '' : 'none';
      if (muteBtn) muteBtn.style.display = volDisplay;
      if (vol) vol.style.display = volDisplay;

      if (toggleBtn) toggleBtn.style.display = anyCollapsibleVisible ? '' : 'none';
    };

    // Hotkeys
    const SHIFTED_SYMBOL_MAP = {
      '!': '1', '@': '2', '#': '3', '$': '4', '%': '5', '^': '6', '&': '7', '*': '8', '(': '9', ')': '0',
      '~': '`', '_': '-', '+': '=', '{': '[', '}': ']', '|': '\\', ':': ';', '"': "'", '<': ',', '>': '.', '?': '/'
    };

    const sanitizeHotkeyInput = (value) => {
      if (!value || typeof value !== 'string') return '';
      let cleaned = value.trim().toLowerCase().replace(/\s*\+\s*/g, '+');
      const parts = cleaned.split('+').filter(Boolean);
      let modifiers = []; let key = '';

      parts.forEach(part => {
        if (['shift', 'ctrl', 'alt'].includes(part)) {
          if (!modifiers.includes(part)) modifiers.push(part);
        } else if (!key) key = part;
      });

      if (SHIFTED_SYMBOL_MAP[key]) {
        key = SHIFTED_SYMBOL_MAP[key];
        if (!modifiers.includes('shift')) modifiers.push('shift');
      }

      if (!key) return '';
      return [...modifiers.sort(), key].join('+');
    };

    const normalizeHotkey = (hk) => {
      const sanitized = sanitizeHotkeyInput(hk);
      if (!sanitized) return { key: '', modifiers: { shift: false, ctrl: false, alt: false } };
      const parts = sanitized.split('+');
      const key = parts.pop();
      const modifiers = {
        shift: parts.includes('shift'),
        ctrl: parts.includes('ctrl'),
        alt: parts.includes('alt')
      };
      return { key, modifiers };
    };

    const getHotkeyCombos = ({ key, modifiers }) => {
      const mods = (modifiers.ctrl ? 'ctrl+' : '') + (modifiers.alt ? 'alt+' : '') + (modifiers.shift ? 'shift+' : '');
      const combos = [mods + key];
      if (modifiers.shift) {
        const shiftedKey = Object.keys(SHIFTED_SYMBOL_MAP).find(k => SHIFTED_SYMBOL_MAP[k] === key);
        if (shiftedKey) {
          const baseMods = (modifiers.ctrl ? 'ctrl+' : '') + (modifiers.alt ? 'alt+' : '');
          combos.push(baseMods + shiftedKey);
        }
      }
      return combos;
    };

    const hotkeyMap = {};
    const buildHotkeyMap = () => {
      Object.keys(hotkeyMap).forEach(k => delete hotkeyMap[k]);
      Object.keys(currentSettings.hotkeys).forEach(action => {
        getHotkeyCombos(normalizeHotkey(currentSettings.hotkeys[action])).forEach(combo => {
          hotkeyMap[combo] = action;
        });
      });
    };
    buildHotkeyMap();

    window.addEventListener("keydown", (e) => {
      if (isSettingsOpen) {
        if (e.key === "Escape") { hideSettingsModal(); e.preventDefault(); e.stopImmediatePropagation(); }
        return;
      }
      const isShiftedSym = e.shiftKey && (e.key in SHIFTED_SYMBOL_MAP);
      const combo = [
        e.altKey ? 'alt+' : '',
        e.ctrlKey ? 'ctrl+' : '',
        e.shiftKey && !isShiftedSym ? 'shift+' : '',
        e.key.toLowerCase()
      ].join('');

      const action = hotkeyMap[combo];
      if (action) {
        e.stopImmediatePropagation(); e.preventDefault();
        switch (action) {
          case 'toggleMute': toggleMute(); break;
          case 'toggleStats': toggleStats(); break;
          case 'increaseSpeed': applySpeed(targetSpeed + SPEED_STEP); break;
          case 'decreaseSpeed': applySpeed(targetSpeed - SPEED_STEP); break;
          case 'increaseSpeedFine': applySpeed(targetSpeed + SPEED_STEP_FINE); break;
          case 'decreaseSpeedFine': applySpeed(targetSpeed - SPEED_STEP_FINE); break;
          case 'volumeUp': applyVolume(targetVolume + 0.05); break;
          case 'volumeDown': applyVolume(targetVolume - 0.05); break;
        }
        showControls();
      }
    }, true);


    const btnGroup = document.createElement("div");
    btnGroup.id = "custom-btn-group";
    btnGroup.append(toggleBtn, wlBtn, urlBtn, screenshotBtn, clipBtn, pipBtn, speedBtn, statsBtn, settingsBtn);
    updateButtonVisibility();

    let isHoveringBtnGroup = false;
    btnGroup.addEventListener("mouseenter", () => { isHoveringBtnGroup = true; });
    btnGroup.addEventListener("mouseleave", () => { isHoveringBtnGroup = false; });

    const ALL_CONTROLS = [muteBtn, vol, btnGroup];
    let controlsVisible = false, lastInteractionTime = 0;

    const checkHideControls = () => {
      if (Date.now() - lastInteractionTime >= 2000 && !isHoveringBtnGroup) {
        controlsVisible = false;
        ALL_CONTROLS.forEach(el => el.classList.remove("show"));
      } else {
        controlsTimeout = setTimeout(checkHideControls, 2000);
      }
    };

    const showControls = () => {
      lastInteractionTime = Date.now();
      if (!controlsVisible) {
        controlsVisible = true;
        ALL_CONTROLS.forEach(el => el.classList.add("show"));
        clearTimeout(controlsTimeout);
        controlsTimeout = setTimeout(checkHideControls, 2000);
      }
    };

    window.addEventListener("mousemove", () => {
      if (rafPending) return;
      rafPending = requestAnimationFrame(() => { showControls(); rafPending = 0; });
    });


    // memory 2
    const initialVid = getVideoId(getPlayer());
    if (initialVid) {
      if (currentSettings.volumeCache[initialVid] !== undefined) {
        applyVolume(currentSettings.volumeCache[initialVid]);
      }
      if (currentSettings.miniStatsCache[initialVid]) {
        toggleMiniStats();
      }
    }

    applySpeed(targetSpeed);
    showControls();

    window.addEventListener("dblclick", (e) => {
      if (isSettingsOpen) return;
      if (e.target.closest("#custom-btn-group, #custom-mute-btn, #custom-vol-slider")) return;
      if (!document.fullscreenElement) document.documentElement.requestFullscreen().catch(() => { });
      else if (document.exitFullscreen) document.exitFullscreen();
    });

    const initUI = () => {
      document.body.prepend(volPct, speedOverlay, clipOverlay, miniStats, vol, muteBtn, btnGroup);
    };
    initUI();

    // Cleanup
    const updateEmbedWidth = () => {
      const w = document.documentElement.clientWidth || window.innerWidth;
      document.documentElement.style.setProperty('--ytee-ew', w + 'px');
      if (typeof applyMiniStatsPos === 'function') applyMiniStatsPos();
    };
    updateEmbedWidth();
    const resizeObs = new ResizeObserver(updateEmbedWidth);
    resizeObs.observe(document.documentElement);

    if (typeof GM_addValueChangeListener === 'function') {
      GM_addValueChangeListener('ytee-settings', (name, oldVal, newVal, remote) => {
        if (remote) {
          try {
            currentSettings = normalizeSettings(typeof newVal === 'string' ? JSON.parse(newVal) : newVal);
            updateButtonVisibility();
            buildHotkeyMap();
            applyQuality();
            applyUIStates(currentSettings);
          } catch (e) { console.warn('Failed to sync settings', e); }
        }
      });
    }

    const cleanup = () => {
      clearTimeout(volTimeout); clearTimeout(speedTimeout); clearTimeout(controlsTimeout); clearTimeout(miniStatsTimer);
      if (clipRafId) cancelAnimationFrame(clipRafId);
      if (rafPending) cancelAnimationFrame(rafPending);
      if (wheelRafId) cancelAnimationFrame(wheelRafId);
      rafPending = 0; clipRafId = null; wheelRafId = 0;
      if (clipRecorder) { try { if (clipRecorder.state !== 'inactive') clipRecorder.stop(); } catch (e) { } clipRecorder = null; }
      if (activeStream) { activeStream.getTracks().forEach(t => t.stop()); activeStream = null; }
      if (audioContext) { audioContext.close().catch(() => { }); audioContext = null; gainNode = null; mediaSource = null; }
      cachedPlayer = null;
      resizeObs.disconnect();
    };
    window.addEventListener('pagehide', cleanup);

  });
})();