@oddin-gg/havik-player 2.16.0 → 2.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -860,7 +860,8 @@ function qe(e, t) {
860
860
  }
861
861
  //#endregion
862
862
  //#region src/core/engine/native.ts
863
- function Je(e) {
863
+ var Je = 2e3, Ye = 3;
864
+ function Xe(e) {
864
865
  try {
865
866
  let t = new TextDecoder("utf-8").decode(new Uint8Array(e));
866
867
  return /^skd:\/\/[0-9a-fA-F-]{36}:([0-9a-fA-F]{32})$/.exec(t)?.[1];
@@ -876,7 +877,7 @@ function G() {
876
877
  let e = "WebKitMediaKeys" in window || typeof HTMLMediaElement < "u" && "webkitSetMediaKeys" in HTMLMediaElement.prototype, t = typeof navigator < "u" && /Apple/i.test(navigator.vendor ?? "");
877
878
  return e || t;
878
879
  }
879
- function Ye() {
880
+ function Ze() {
880
881
  if (typeof navigator > "u" || !G()) return !1;
881
882
  let e = navigator.userAgent ?? "";
882
883
  return /iPhone|iPad|iPod/.test(e) ? !0 : /Macintosh/.test(e) && typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1;
@@ -890,6 +891,9 @@ var K = class {
890
891
  fairplayLicenseUrl;
891
892
  keySession = null;
892
893
  fairplayArmed = !1;
894
+ onVisibility = null;
895
+ onPageShow = null;
896
+ hiddenSince = null;
893
897
  fairplayKeyIV;
894
898
  loadStarted;
895
899
  preloadTouched = !1;
@@ -901,7 +905,7 @@ var K = class {
901
905
  }
902
906
  async load() {
903
907
  let { video: e, descriptor: t, emit: r } = this.deps;
904
- if (this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
908
+ if (this.watchRefocus(), this.loadStarted || (this.preloadTouched = !0, this.savedPreload = e.getAttribute("preload"), e.preload = "none"), t.drmEnabled) {
905
909
  if (!t.drm?.fairplay) {
906
910
  r({
907
911
  type: "error",
@@ -917,7 +921,7 @@ var K = class {
917
921
  type: "error",
918
922
  error: new n("INTERNAL", 0, "native HLS playback error"),
919
923
  fatal: !0
920
- }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Xe(t.manifestUrl, t.analytics?.sid), e.load();
924
+ }), this.onLoaded && e.addEventListener("loadedmetadata", this.onLoaded, { once: !0 }), e.addEventListener("error", this.onError), e.src = Qe(t.manifestUrl, t.analytics?.sid), e.load();
921
925
  }
922
926
  startLoad() {
923
927
  this.loadStarted || (this.loadStarted = !0, this.restorePreload());
@@ -939,7 +943,7 @@ var K = class {
939
943
  });
940
944
  this.onEncrypted = (n) => {
941
945
  let i = n;
942
- i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Je(i.initData), (async () => {
946
+ i.initData && !this.fairplayArmed && (this.fairplayArmed = !0, this.fairplayKeyIV = Xe(i.initData), (async () => {
943
947
  try {
944
948
  let n = await (await navigator.requestMediaKeySystemAccess("com.apple.fps", [{
945
949
  initDataTypes: [i.initDataType],
@@ -1053,7 +1057,31 @@ var K = class {
1053
1057
  this.deps.video.pause();
1054
1058
  } catch {}
1055
1059
  }
1060
+ watchRefocus() {
1061
+ this.deps.snapToLiveOnRefocus === !1 || typeof document > "u" || this.onVisibility || (this.onVisibility = () => {
1062
+ let e = typeof performance < "u" ? performance.now() : Date.now();
1063
+ if (document.visibilityState === "hidden") {
1064
+ this.hiddenSince = e;
1065
+ return;
1066
+ }
1067
+ let t = this.hiddenSince;
1068
+ this.hiddenSince = null, t != null && e - t >= Je && this.snapToLive();
1069
+ }, this.onPageShow = (e) => {
1070
+ e.persisted && this.snapToLive();
1071
+ }, document.addEventListener("visibilitychange", this.onVisibility), typeof window < "u" && window.addEventListener("pageshow", this.onPageShow));
1072
+ }
1073
+ snapToLive() {
1074
+ let e = this.deps.video;
1075
+ if (e.duration !== Infinity || e.seekable.length === 0) return;
1076
+ let t = e.seekable.start(e.seekable.length - 1), n = e.seekable.end(e.seekable.length - 1);
1077
+ if (!Number.isFinite(n)) return;
1078
+ let r = Math.max(t, n - Ye);
1079
+ try {
1080
+ e.currentTime = r;
1081
+ } catch {}
1082
+ }
1056
1083
  destroy() {
1084
+ this.onVisibility && typeof document < "u" && (document.removeEventListener("visibilitychange", this.onVisibility), this.onVisibility = null), this.onPageShow && typeof window < "u" && (window.removeEventListener("pageshow", this.onPageShow), this.onPageShow = null);
1057
1085
  let { video: e } = this.deps;
1058
1086
  this.onLoaded && e.removeEventListener("loadedmetadata", this.onLoaded), this.onError && e.removeEventListener("error", this.onError), this.onEncrypted && e.removeEventListener("encrypted", this.onEncrypted), this.keySession?.close().catch(() => {}), this.keySession = null, this.fairplayArmed = !1, this.fairplayKeyIV = void 0;
1059
1087
  try {
@@ -1065,13 +1093,13 @@ var K = class {
1065
1093
  } catch {}
1066
1094
  }
1067
1095
  };
1068
- function Xe(e, t) {
1096
+ function Qe(e, t) {
1069
1097
  return t ? `${e}${e.includes("?") ? "&" : "?"}CMCD=${encodeURIComponent(`sid="${t}"`)}` : e;
1070
1098
  }
1071
1099
  //#endregion
1072
1100
  //#region src/core/engine/prefetch.ts
1073
- var Ze = 15e3, Qe = 5e3, $e = 6;
1074
- function et(e) {
1101
+ var $e = 15e3, et = 5e3, tt = 6;
1102
+ function nt(e) {
1075
1103
  try {
1076
1104
  let t = new URL(e);
1077
1105
  return t.searchParams.delete("CMCD"), t.toString();
@@ -1079,7 +1107,7 @@ function et(e) {
1079
1107
  return e;
1080
1108
  }
1081
1109
  }
1082
- var tt = class {
1110
+ var rt = class {
1083
1111
  cmcd;
1084
1112
  entries = /* @__PURE__ */ new Map();
1085
1113
  keyed = /* @__PURE__ */ new Set();
@@ -1102,10 +1130,10 @@ var tt = class {
1102
1130
  }
1103
1131
  prefetch(e, t, n) {
1104
1132
  if (!this.isActive(t)) return;
1105
- let r = et(e);
1133
+ let r = nt(e);
1106
1134
  if (this.entries.has(r)) return;
1107
1135
  let i = this.perTrack.get(t) ?? 0;
1108
- if (i >= $e) return;
1136
+ if (i >= tt) return;
1109
1137
  this.perTrack.set(t, i + 1);
1110
1138
  let a = new AbortController(), o = {
1111
1139
  started: performance.now(),
@@ -1119,10 +1147,10 @@ var tt = class {
1119
1147
  signal: a.signal
1120
1148
  }).then(async (e) => (o.first = performance.now(), e.ok ? e.arrayBuffer() : null)).catch(() => null), this.entries.set(r, o), this.stats.started += 1, setTimeout(() => {
1121
1149
  this.entries.get(r) === o && (this.entries.delete(r), a.abort(), this.stats.expired += 1);
1122
- }, Ze);
1150
+ }, $e);
1123
1151
  }
1124
1152
  take(e) {
1125
- let t = et(e), n = this.entries.get(t);
1153
+ let t = nt(e), n = this.entries.get(t);
1126
1154
  return n && this.entries.delete(t), n;
1127
1155
  }
1128
1156
  destroy() {
@@ -1142,13 +1170,13 @@ var tt = class {
1142
1170
  }
1143
1171
  }
1144
1172
  };
1145
- function nt(t) {
1173
+ function it(t) {
1146
1174
  let n = e.DefaultConfig?.loader;
1147
1175
  if (typeof n != "function") return;
1148
1176
  class r extends n {
1149
1177
  served = !1;
1150
1178
  cancelled = !1;
1151
- stats = rt();
1179
+ stats = at();
1152
1180
  load(e, n, r) {
1153
1181
  let i = e.rangeEnd ? void 0 : t.take(e.url);
1154
1182
  if (!i) {
@@ -1156,7 +1184,7 @@ function nt(t) {
1156
1184
  return;
1157
1185
  }
1158
1186
  this.served = !0;
1159
- let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || Qe, s = setTimeout(() => {
1187
+ let a = performance.now(), o = n?.loadPolicy?.maxTimeToFirstByteMs || et, s = setTimeout(() => {
1160
1188
  !this.cancelled && this.served && (i.abort.abort(), t.stats.failed += 1, this.served = !1, super.load(e, n, r));
1161
1189
  }, o);
1162
1190
  i.bytes.then((o) => {
@@ -1183,7 +1211,7 @@ function nt(t) {
1183
1211
  }
1184
1212
  return r;
1185
1213
  }
1186
- function rt() {
1214
+ function at() {
1187
1215
  return {
1188
1216
  aborted: !1,
1189
1217
  loaded: 0,
@@ -1207,10 +1235,10 @@ function rt() {
1207
1235
  }
1208
1236
  };
1209
1237
  }
1210
- function it(e) {
1238
+ function ot(e) {
1211
1239
  return e === "audio" ? "audio" : "main";
1212
1240
  }
1213
- function at(e, t) {
1241
+ function st(e, t) {
1214
1242
  let n = [];
1215
1243
  t.initSegment?.url && !t.initSegment.data && n.push({
1216
1244
  url: t.initSegment.url,
@@ -1229,24 +1257,24 @@ function at(e, t) {
1229
1257
  }
1230
1258
  //#endregion
1231
1259
  //#region src/core/engine/hls.ts
1232
- function ot() {
1260
+ function ct() {
1233
1261
  return e.isSupported();
1234
1262
  }
1235
- var st = 3, ct = 5, lt = 3, ut = 3e4, dt = 12e3, ft = 3e3, pt = 6e3, mt = .5, ht = 3, gt = .5, _t = 1.1, vt = .25, yt = 5e3, bt = 4e3, xt = 2, St = 5, Ct = 2, wt = 2, Tt = 4, Et = 4, Dt = 2e3, Ot = 3e4, kt = .2, At = 30, jt = 2, Mt = 2, Nt = 9, Pt = .5, Ft = 64;
1236
- function It(e) {
1263
+ var lt = 3, ut = 5, dt = 3, ft = 3e4, pt = 12e3, mt = 3e3, ht = 6e3, gt = .5, _t = 3, vt = .5, yt = 1.1, bt = .25, xt = 5e3, St = 4e3, Ct = 2, wt = 5, Tt = 2, Et = 2, Dt = 4, Ot = 4, kt = 2e3, At = 3e4, jt = .2, Mt = 30, Nt = 2, Pt = 2, Ft = 9, It = .5, Lt = 64;
1264
+ function Rt(e) {
1237
1265
  if (e.liveSyncDurationCount != null || e.liveMaxLatencyDurationCount != null) {
1238
1266
  delete e.liveSyncDuration, delete e.liveMaxLatencyDuration;
1239
1267
  return;
1240
1268
  }
1241
- e.liveSyncDuration ??= Mt;
1242
- let t = Math.max(12, e.liveSyncDuration + Nt);
1243
- (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), Lt(e, e.liveSyncDuration);
1269
+ e.liveSyncDuration ??= Pt;
1270
+ let t = Math.max(12, e.liveSyncDuration + Ft);
1271
+ (e.liveMaxLatencyDuration == null || e.liveMaxLatencyDuration <= e.liveSyncDuration) && (e.liveMaxLatencyDuration = t), zt(e, e.liveSyncDuration);
1244
1272
  }
1245
- function Lt(e, t) {
1273
+ function zt(e, t) {
1246
1274
  let n = (e, t, n) => Math.min(n, Math.max(t, e));
1247
1275
  e.maxStarvationDelay ??= n(t / 2, .5, 4), e.maxLoadingDelay ??= n(t, 1, 4), e.abrEwmaFastLive ??= n(t / 2, 1, 3);
1248
1276
  }
1249
- var Rt = class {
1277
+ var Bt = class {
1250
1278
  name = "hls";
1251
1279
  hls = null;
1252
1280
  deps;
@@ -1359,7 +1387,7 @@ var Rt = class {
1359
1387
  }
1360
1388
  this.loadSuspended = !0;
1361
1389
  }
1362
- }, yt));
1390
+ }, xt));
1363
1391
  }
1364
1392
  resumeLoading() {
1365
1393
  if (this.pauseSuspendTimer &&= (clearTimeout(this.pauseSuspendTimer), null), this.resetChaseWindow(), this.resetFrameDropWindow(), this.loadSuspended && (this.loadSuspended = !1, !this.stopped && this.hls)) {
@@ -1391,7 +1419,7 @@ var Rt = class {
1391
1419
  let t = e.liveSyncPosition;
1392
1420
  if (typeof t != "number" || !Number.isFinite(t)) return;
1393
1421
  let { video: n } = this.deps;
1394
- n.currentTime <= t + Pt || (n.currentTime = t);
1422
+ n.currentTime <= t + It || (n.currentTime = t);
1395
1423
  }
1396
1424
  startHls() {
1397
1425
  let { video: t, descriptor: n, credential: r, deviceId: i, userId: a, lowLatency: o, debug: s, hlsConfig: c, emit: l } = this.deps;
@@ -1432,20 +1460,20 @@ var Rt = class {
1432
1460
  ...c
1433
1461
  };
1434
1462
  if (this.prefetch?.destroy(), this.prefetch = null, u && this.deps.mediaDuringKey !== !1 && !d.fLoader) {
1435
- let e = new tt({
1463
+ let e = new rt({
1436
1464
  sessionId: n.analytics?.sid,
1437
1465
  contentId: n.matchUrn
1438
- }), t = nt(e);
1466
+ }), t = it(e);
1439
1467
  t && (this.prefetch = e, d.fLoader = t);
1440
1468
  }
1441
- It(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1469
+ Rt(d), this.catchUpRate = typeof d.maxLiveSyncPlaybackRate == "number" ? d.maxLiveSyncPlaybackRate : 1, this.catchUpEngaged = !1, this.catchUpRate > 1 && (d.maxLiveSyncPlaybackRate = 1), this.sizeCapManaged = d.capLevelToPlayerSize !== !0, this.fpsCapManaged = !(c && "capLevelOnFPSDrop" in c), this.loadStarted = d.autoStartLoad !== !1;
1442
1470
  let f = new e(d);
1443
1471
  if (this.hls = f, f.on(e.Events.MANIFEST_PARSED, () => {
1444
1472
  this.mediaRecoveries = 0, this.networkRecoveries = 0, u && !this.deps.hlsConfig?.requestMediaKeySystemAccessFunc && this.dropLevelsWidevineCannotPlay(f), this.measureLadder(f), this.applySizeCap(), this.loadSuspended = !1, t.paused && this.schedulePauseSuspend(), l({ type: "ready" });
1445
1473
  }), f.on(e.Events.FRAG_BUFFERED, (e, t) => {
1446
1474
  t?.frag?.type === "main" && (this.kickKind !== "dead" && this.clearKick(), (this.mediaRecoveries > 0 || this.networkRecoveries > 0 || this.licenseRecoveries > 0 || this.starvationKicks > 0 || this.starvationRebuilds > 0) && !this.recoveryResetTimer && (this.recoveryResetTimer = setTimeout(() => {
1447
1475
  this.mediaRecoveries = 0, this.networkRecoveries = 0, this.licenseRecoveries = 0, this.starvationKicks = 0, this.starvationRebuilds = 0, this.recoveryResetTimer = null;
1448
- }, ut)));
1476
+ }, ft)));
1449
1477
  }), f.on(e.Events.FRAG_LOADING, (e, t) => {
1450
1478
  t?.frag?.type === "main" && (this.lastFragLoadingMs = Date.now());
1451
1479
  }), f.on(e.Events.FRAG_LOADED, (e, t) => {
@@ -1453,7 +1481,7 @@ var Rt = class {
1453
1481
  let n = t?.frag?.stats, r = n?.loaded;
1454
1482
  typeof r == "number" && (this.bytesLoaded += r), !this.reportedFirstBytes && typeof r == "number" && r > 0 && (this.reportedFirstBytes = !0, l({ type: "firstBytes" }));
1455
1483
  let i = n?.loading;
1456
- i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Ft && this.requestTimesMs.shift());
1484
+ i && i.end > 0 && i.start > 0 && (this.requestCount += 1, this.requestTimesMs.push(Math.max(0, Math.round(i.end - i.start))), this.requestTimesMs.length > Lt && this.requestTimesMs.shift());
1457
1485
  let a = t?.frag?.url;
1458
1486
  if (a) {
1459
1487
  let e = H(a);
@@ -1470,15 +1498,15 @@ var Rt = class {
1470
1498
  }), f.on(e.Events.LEVEL_LOADED, (e, t) => this.trackEnd(t)), this.prefetch) {
1471
1499
  let t = this.prefetch;
1472
1500
  f.on(e.Events.KEY_LOADING, (e, n) => {
1473
- let r = n?.frag, i = it(r?.type);
1474
- if (r && t.isActive(i)) for (let e of at(f, r)) t.prefetch(e.url, i, e.kind);
1475
- }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(it(n?.frag?.type)));
1501
+ let r = n?.frag, i = ot(r?.type);
1502
+ if (r && t.isActive(i)) for (let e of st(f, r)) t.prefetch(e.url, i, e.kind);
1503
+ }), f.on(e.Events.KEY_LOADED, (e, n) => t.keyUsable(ot(n?.frag?.type)));
1476
1504
  }
1477
1505
  f.on(e.Events.KEY_LOADED, () => {
1478
1506
  u && !this.reportedDrmReady && (this.reportedDrmReady = !0, l({ type: "drmReady" }));
1479
1507
  }), this.endWatchdog && clearInterval(this.endWatchdog), this.endWatchdog = setInterval(() => {
1480
1508
  this.checkEndStale(), this.checkStarvation(), this.updateCatchUpBand(), this.checkFutileChase(), this.checkFrameDrops();
1481
- }, ft), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1509
+ }, mt), f.on(e.Events.LEVEL_SWITCHED, (e, t) => {
1482
1510
  this.renditionSwitches += 1;
1483
1511
  let n = this.lastLevelIndex >= 0 ? f.levels[this.lastLevelIndex] : void 0, r = f.levels[t.level];
1484
1512
  n && r && r.bitrate !== n.bitrate && (r.bitrate > n.bitrate ? this.upshifts += 1 : this.downshifts += 1), this.lastLevelIndex = t.level, l({
@@ -1542,7 +1570,7 @@ var Rt = class {
1542
1570
  return;
1543
1571
  }
1544
1572
  this.capTimer && clearTimeout(this.capTimer);
1545
- let t = e > this.sizeCapLevel ? Dt : Ot;
1573
+ let t = e > this.sizeCapLevel ? kt : At;
1546
1574
  this.capTimer = setTimeout(() => {
1547
1575
  this.capTimer = null, this.computeSizeCapTarget() === e ? this.applySizeCap() : this.onMediaResize();
1548
1576
  }, t);
@@ -1663,7 +1691,7 @@ var Rt = class {
1663
1691
  return;
1664
1692
  }
1665
1693
  let e = Date.now() - this.lastAdvanceMs;
1666
- !this.chaseSuspended && e > pt && this.suspendChasing(), e > dt && this.emitEnded("stalled");
1694
+ !this.chaseSuspended && e > ht && this.suspendChasing(), e > pt && this.emitEnded("stalled");
1667
1695
  }
1668
1696
  resetStarvationWindow() {
1669
1697
  this.starvedTicks = 0, this.deadTicks = 0, this.mainFragsSinceTick = 0, this.recentMainFrags = [];
@@ -1678,7 +1706,7 @@ var Rt = class {
1678
1706
  this.resetStarvationWindow();
1679
1707
  return;
1680
1708
  }
1681
- let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < pt, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > bt, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = U(t), c = o - s, l = c !== this.starvedFrames;
1709
+ let n = Date.now(), r = this.lastAdvanceMs !== 0 && n - this.lastAdvanceMs < ht, i = this.lastFragLoadingMs !== 0 && n - this.lastFragLoadingMs > St, a = t.readyState < HTMLMediaElement.HAVE_FUTURE_DATA && !t.paused, { totalFrames: o, dropped: s } = U(t), c = o - s, l = c !== this.starvedFrames;
1682
1710
  if (this.starvedFrames = c, !a || l) {
1683
1711
  (t.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA || l) && this.clearKick(), this.resetStarvationWindow();
1684
1712
  return;
@@ -1687,12 +1715,12 @@ var Rt = class {
1687
1715
  this.resetStarvationWindow();
1688
1716
  return;
1689
1717
  }
1690
- if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > Tt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= Ct && (this.clearKick(), this.starvationRebuilds < wt)) {
1718
+ if (this.kickPending && (this.kickKind === "dead" || i) && (this.kickTicks += 1), this.starvedTicks = i ? this.starvedTicks + 1 : 0, this.deadTicks += 1, this.recentMainFrags.push(this.mainFragsSinceTick), this.mainFragsSinceTick = 0, this.recentMainFrags.length > Dt && this.recentMainFrags.shift(), this.clearRecoveryReset(), this.kickPending && this.kickTicks >= Tt && (this.clearKick(), this.starvationRebuilds < Et)) {
1691
1719
  this.starvationRebuilds += 1, this.resetStarvationWindow(), this.clearRecoveryReset(), console.warn("havik-player: restarting the load did not resume video (the wedge is in hls.js state that only a rebuild clears) — rebuilding the player"), this.rebuildInstance("starvation rebuild");
1692
1720
  return;
1693
1721
  }
1694
- let u = i && this.starvedTicks >= xt, d = !i && this.deadTicks >= Tt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Et;
1695
- if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= St))) {
1722
+ let u = i && this.starvedTicks >= Ct, d = !i && this.deadTicks >= Dt && this.recentMainFrags.reduce((e, t) => e + t, 0) >= Ot;
1723
+ if ((u || d) && (this.resetStarvationWindow(), !(this.starvationKicks >= wt))) {
1696
1724
  this.starvationKicks += 1, this.kickPending = !0, this.kickTicks = 0, this.kickKind = d ? "dead" : "quiet", this.clearRecoveryReset(), console.warn(d ? "havik-player: video starved while hls.js keeps loading media it never plays (dead pipeline at the live edge) — restarting the load" : "havik-player: video starved while the live playlist advances (wedged hls.js fragment pipeline) — restarting the load");
1697
1725
  try {
1698
1726
  e.stopLoad(), e.startLoad(-1);
@@ -1707,7 +1735,7 @@ var Rt = class {
1707
1735
  let t = e.latency, n = e.targetLatency;
1708
1736
  if (typeof t != "number" || typeof n != "number" || !Number.isFinite(t)) return;
1709
1737
  let r = t - n;
1710
- !this.catchUpEngaged && r > mt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= mt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1738
+ !this.catchUpEngaged && r > gt ? this.catchUpEngaged = !0 : this.catchUpEngaged && r <= gt && this.deps.video.playbackRate === 1 && (this.catchUpEngaged = !1);
1711
1739
  let i = this.catchUpEngaged ? this.catchUpRate : 1;
1712
1740
  e.config.maxLiveSyncPlaybackRate !== i && (e.config.maxLiveSyncPlaybackRate = i);
1713
1741
  }
@@ -1729,15 +1757,15 @@ var Rt = class {
1729
1757
  return;
1730
1758
  }
1731
1759
  let { totalFrames: n, dropped: r } = U(t), i = this.fpsLastFrames < 0, a = n - this.fpsLastFrames, o = r - this.fpsLastDropped;
1732
- if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < At || o < 0) {
1760
+ if (this.fpsLastFrames = n, this.fpsLastDropped = r, i || a < Mt || o < 0) {
1733
1761
  this.fpsBadTicks = 0;
1734
1762
  return;
1735
1763
  }
1736
- if (o <= kt * a) {
1764
+ if (o <= jt * a) {
1737
1765
  this.fpsBadTicks = 0;
1738
1766
  return;
1739
1767
  }
1740
- if (this.fpsBadTicks += 1, this.fpsBadTicks < jt) return;
1768
+ if (this.fpsBadTicks += 1, this.fpsBadTicks < Nt) return;
1741
1769
  this.fpsBadTicks = 0;
1742
1770
  let s = e.levels, c = s[e.currentLevel];
1743
1771
  if (!c) return;
@@ -1754,20 +1782,20 @@ var Rt = class {
1754
1782
  return;
1755
1783
  }
1756
1784
  let n = e.latency, r = t.playbackRate, i = e.config.maxLiveSyncPlaybackRate;
1757
- if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(_t, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1785
+ if (!(!t.paused && typeof i == "number" && i > 1 && r >= Math.min(yt, i) && r <= i && typeof n == "number" && Number.isFinite(n))) {
1758
1786
  this.resetChaseWindow();
1759
1787
  return;
1760
1788
  }
1761
- if (this.chaseLatency < 0 || this.chaseLatency - n >= gt) {
1789
+ if (this.chaseLatency < 0 || this.chaseLatency - n >= vt) {
1762
1790
  this.chaseLatency = n, this.chaseTicks = 0;
1763
1791
  return;
1764
1792
  }
1765
- if (this.chaseTicks += 1, this.chaseTicks < ht) return;
1793
+ if (this.chaseTicks += 1, this.chaseTicks < _t) return;
1766
1794
  this.resetChaseWindow();
1767
1795
  let a = typeof e.config.liveMaxLatencyDuration == "number" ? e.config.liveMaxLatencyDuration : e.maxLatency;
1768
1796
  if (!(a > 1)) return;
1769
1797
  let o = typeof e.targetLatency == "number" ? e.targetLatency : 0, s = Math.min(n, a - 1);
1770
- s < o + vt || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
1798
+ s < o + bt || (console.warn(`havik-player: catch-up at ${r}x not gaining on the live edge (latency ${n.toFixed(1)}s); holding at ${s.toFixed(1)}s`), this.liveRetargets += 1, e.targetLatency = s);
1771
1799
  }
1772
1800
  suspendChasing() {
1773
1801
  let e = this.hls;
@@ -1812,7 +1840,7 @@ var Rt = class {
1812
1840
  scheduleLicenseRetry(t) {
1813
1841
  if (t.details !== e.ErrorDetails.KEY_SYSTEM_LICENSE_REQUEST_FAILED && t.details !== e.ErrorDetails.KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED) return !1;
1814
1842
  let n = t.response?.code ?? 0;
1815
- if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= lt) return !1;
1843
+ if (!(n === 0 || n === 408 || n === 429 || n >= 500) || this.licenseRecoveries >= dt) return !1;
1816
1844
  this.licenseRecoveries += 1;
1817
1845
  let r = Math.min(8e3, 500 * 2 ** (this.licenseRecoveries - 1));
1818
1846
  return this.licenseRetryTimer = setTimeout(() => {
@@ -1844,7 +1872,7 @@ var Rt = class {
1844
1872
  return;
1845
1873
  }
1846
1874
  if (t.type === e.ErrorTypes.NETWORK_ERROR) {
1847
- if (this.networkRecoveries < ct) {
1875
+ if (this.networkRecoveries < ut) {
1848
1876
  this.networkRecoveries += 1;
1849
1877
  let e = Math.min(8e3, 1e3 * 2 ** (this.networkRecoveries - 1));
1850
1878
  this.networkRetryTimer = setTimeout(() => {
@@ -1861,7 +1889,7 @@ var Rt = class {
1861
1889
  return;
1862
1890
  }
1863
1891
  if (t.type === e.ErrorTypes.MEDIA_ERROR) {
1864
- if (this.mediaRecoveries < st) {
1892
+ if (this.mediaRecoveries < lt) {
1865
1893
  this.mediaRecoveries += 1, n.recoverMediaError();
1866
1894
  return;
1867
1895
  }
@@ -1885,19 +1913,19 @@ var Rt = class {
1885
1913
  let r = e.response?.code ?? 0, a = e.details ?? e.type, o = e.reason ?? e.error?.message ?? "";
1886
1914
  return new n(t === "DRM" ? i(r) : r === 401 ? "UNAUTHORIZED" : r === 403 ? "FORBIDDEN" : "INTERNAL", r, `${t} error: ${a}${o ? ` (${o})` : ""}`);
1887
1915
  }
1888
- }, zt = 15e3, Bt = 6e5, Vt = 3e5, Ht = 100, q = 1, Ut = 1e3, Wt = 3e4, Gt = 1e3, Kt = {
1916
+ }, Vt = 15e3, Ht = 6e5, Ut = 3e5, Wt = 100, q = 1, Gt = 1e3, Kt = 3e4, qt = 1e3, Jt = {
1889
1917
  inline: "PRESENTATION_INLINE",
1890
1918
  fullscreen: "PRESENTATION_FULLSCREEN",
1891
1919
  pip: "PRESENTATION_PIP"
1892
- }, qt = {
1920
+ }, Yt = {
1893
1921
  widevine: "KEY_SYSTEM_WIDEVINE",
1894
1922
  fairplay: "KEY_SYSTEM_FAIRPLAY",
1895
1923
  none: "KEY_SYSTEM_NONE"
1896
1924
  };
1897
- function Jt(e, t) {
1925
+ function Xt(e, t) {
1898
1926
  return e.length === 0 ? 0 : e[Math.min(e.length, Math.max(1, Math.ceil(t / 100 * e.length))) - 1] ?? 0;
1899
1927
  }
1900
- var Yt = /* @__PURE__ */ new Set([
1928
+ var Zt = /* @__PURE__ */ new Set([
1901
1929
  "INVALID_URN",
1902
1930
  "NOT_FOUND",
1903
1931
  "GONE",
@@ -1917,7 +1945,7 @@ var Yt = /* @__PURE__ */ new Set([
1917
1945
  ended: "PLAYER_STATE_ENDED",
1918
1946
  error: "PLAYER_STATE_ERROR"
1919
1947
  };
1920
- function Xt(e) {
1948
+ function Qt(e) {
1921
1949
  try {
1922
1950
  let t = new URL(e), [n, ...r] = t.hostname.split(".");
1923
1951
  return !n || r.length === 0 || n !== "feed" && !n.startsWith("feed-") ? void 0 : (t.hostname = [n.replace(/^feed/, "beacons"), ...r].join("."), t.pathname = "", t.search = "", t.origin);
@@ -1925,8 +1953,8 @@ function Xt(e) {
1925
1953
  return;
1926
1954
  }
1927
1955
  }
1928
- var Zt = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), Qt = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), $t = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
1929
- function en(e) {
1956
+ var $t = (e, t) => e.replace(/\/$/, "").toLowerCase() === t.replace(/\/$/, "").toLowerCase(), en = /* @__PURE__ */ new Set(), Y = /* @__PURE__ */ new Set(), X = /* @__PURE__ */ new Set(), tn = (e) => `this page's Content-Security-Policy blocks QoE beacons. Add ${e} to connect-src; until then none are sent.`;
1957
+ function nn(e) {
1930
1958
  if (e.disposition !== "enforce" || e.effectiveDirective !== "connect-src") return;
1931
1959
  let t;
1932
1960
  try {
@@ -1935,19 +1963,19 @@ function en(e) {
1935
1963
  } catch {
1936
1964
  return;
1937
1965
  }
1938
- if (Qt.has(t) && !Y.has(t)) {
1939
- Y.add(t), g($t(new URL(t).origin));
1966
+ if (en.has(t) && !Y.has(t)) {
1967
+ Y.add(t), g(tn(new URL(t).origin));
1940
1968
  for (let e of X) e.noteCspBlocked();
1941
1969
  }
1942
1970
  }
1943
- function tn(e, t) {
1971
+ function rn(e, t) {
1944
1972
  return g(t, e), { disabledReason: t };
1945
1973
  }
1946
- function nn(e, t, n) {
1947
- if (n) return t && !Zt(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
1974
+ function an(e, t, n) {
1975
+ if (n) return t && !$t(t, n) && g(`analytics.endpoint "${t}" ignored; the server named "${n}".`), { endpoint: n };
1948
1976
  if (t) return { endpoint: t };
1949
- if (t !== void 0) return tn("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
1950
- let r = Xt(e);
1977
+ if (t !== void 0) return rn("empty-endpoint", "analytics is disabled: no QoE beacons will be sent. analytics.endpoint was supplied but empty. Pass a real beacons origin, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, or omit the option to derive it from baseUrl (or analytics: false to opt out).");
1978
+ let r = Qt(e);
1951
1979
  if (r) return { endpoint: r };
1952
1980
  let i;
1953
1981
  try {
@@ -1955,9 +1983,9 @@ function nn(e, t, n) {
1955
1983
  } catch {
1956
1984
  i = e;
1957
1985
  }
1958
- return tn(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
1986
+ return rn(i, `analytics is disabled: no QoE beacons will be sent. The beacons endpoint cannot be derived from the baseUrl host "${i}" — the convention is feed[-dev].<domain> → beacons[-dev].<domain>. Pass an explicit endpoint, analytics: { endpoint: 'https://beacons[-dev].<domain>' }, to createPlayer (or analytics: false to opt out deliberately).`);
1959
1987
  }
1960
- var rn = class {
1988
+ var on = class {
1961
1989
  opts;
1962
1990
  url;
1963
1991
  cspKey;
@@ -2039,8 +2067,8 @@ var rn = class {
2039
2067
  constructor(e) {
2040
2068
  this.opts = {
2041
2069
  ...e,
2042
- heartbeatMs: e.heartbeatMs ?? zt,
2043
- idleMs: e.idleMs ?? Bt
2070
+ heartbeatMs: e.heartbeatMs ?? Vt,
2071
+ idleMs: e.idleMs ?? Ht
2044
2072
  }, this.url = `${e.endpoint.replace(/\/$/, "")}/v1/beacons`;
2045
2073
  try {
2046
2074
  let e = new URL(this.url);
@@ -2057,11 +2085,11 @@ var rn = class {
2057
2085
  sdkVersion: this.opts.sdkVersion,
2058
2086
  ...this.opts.environment
2059
2087
  };
2060
- this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Ut), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && Qt.add(this.cspKey), document.addEventListener("securitypolicyviolation", en), X.add(this), this.noteCspBlocked(), this.onVisibility());
2088
+ this.pendingStart = e, this.enqueue({ sessionStart: e }), this.firstFlushTimer = setTimeout(() => this.flush(), Gt), this.lastTickMs = this.now(), this.timer = setInterval(() => this.heartbeat(), this.opts.heartbeatMs), typeof window < "u" && window.addEventListener("pagehide", this.onPagehide), typeof document < "u" && (document.addEventListener("visibilitychange", this.onVisibility), document.addEventListener("freeze", this.onFreeze), document.addEventListener("resume", this.onResume), this.cspKey && en.add(this.cspKey), document.addEventListener("securitypolicyviolation", nn), X.add(this), this.noteCspBlocked(), this.onVisibility());
2061
2089
  }
2062
2090
  checkSuspension(e) {
2063
2091
  if (this.endedFlag || !this.opts.idleMs) return !1;
2064
- let t = Math.max(this.opts.idleMs, Vt);
2092
+ let t = Math.max(this.opts.idleMs, Ut);
2065
2093
  return this.lastTickMs > 0 && e - this.lastTickMs >= t ? (this.endIdle(this.lastTickMs), !0) : (this.lastTickMs = e, !1);
2066
2094
  }
2067
2095
  syncIdle(e) {
@@ -2084,12 +2112,12 @@ var rn = class {
2084
2112
  let a = {
2085
2113
  fromState: J[e] ?? "PLAYER_STATE_UNSPECIFIED",
2086
2114
  toState: J[t] ?? "PLAYER_STATE_UNSPECIFIED",
2087
- presentation: Kt[this.presentation]
2115
+ presentation: Jt[this.presentation]
2088
2116
  }, o = this.causeOf(e, t, i);
2089
2117
  o && (a.cause = o), n > 0 && (a.positionMs = Math.round(n)), r && (a.renditionHeight = r), this.enqueue({ stateChange: a });
2090
2118
  }
2091
2119
  seekInduced(e) {
2092
- return this.lastSeekMs >= 0 && e - this.lastSeekMs < Gt;
2120
+ return this.lastSeekMs >= 0 && e - this.lastSeekMs < qt;
2093
2121
  }
2094
2122
  causeOf(e, t, n) {
2095
2123
  if (t === "error") return "TRANSITION_CAUSE_ERROR";
@@ -2163,7 +2191,7 @@ var rn = class {
2163
2191
  let r = n ?? "";
2164
2192
  if (r !== "") return /^fragLoad/i.test(r) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /^(manifest|level|audioTrack|subtitleTrack)/i.test(r) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(r) ? "ERROR_STAGE_DRM" : /parsing|append|buffer|remux|decrypt|media/i.test(r) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
2165
2193
  if (e === "DRM_CLIENT") return "ERROR_STAGE_DRM";
2166
- if (Yt.has(e)) return "ERROR_STAGE_RESOLVE";
2194
+ if (Zt.has(e)) return "ERROR_STAGE_RESOLVE";
2167
2195
  let i = t ?? "";
2168
2196
  return /frag|segment/i.test(i) ? this.sawFirstBytes ? "ERROR_STAGE_SEGMENT" : "ERROR_STAGE_FIRST_SEGMENT" : /manifest|level|playlist/i.test(i) ? "ERROR_STAGE_MANIFEST" : /key|licen[cs]e/i.test(i) ? "ERROR_STAGE_DRM" : /buffer|decode|media|append/i.test(i) ? "ERROR_STAGE_DECODE" : "ERROR_STAGE_OTHER";
2169
2197
  }
@@ -2210,14 +2238,14 @@ var rn = class {
2210
2238
  if (this.lastRequestCount = g, _ > 0) {
2211
2239
  o.requestCountDelta = _;
2212
2240
  let e = t.requestTimesMs ?? [], n = e.slice(Math.max(0, e.length - _)).sort((e, t) => e - t);
2213
- n.length > 0 && (o.requestTimeP50Ms = Jt(n, 50), o.requestTimeP95Ms = Jt(n, 95));
2241
+ n.length > 0 && (o.requestTimeP50Ms = Xt(n, 50), o.requestTimeP95Ms = Xt(n, 95));
2214
2242
  }
2215
2243
  typeof t.latencySeconds == "number" && typeof t.targetLatencySeconds == "number" && (o.driftMs = Math.round((t.latencySeconds - t.targetLatencySeconds) * 1e3)), typeof t.playbackRate == "number" && t.playbackRate > 0 && (o.playbackRate = t.playbackRate), t.qualityPinned === !0 && (o.qualityPinned = !0), t.cdnHost && (o.cdnHost = t.cdnHost), this.maybeEmitMediaInfo(t), this.enqueue({ heartbeat: o }), this.flush(), s > 0 && this.noteFirstBytes();
2216
2244
  }
2217
2245
  maybeEmitMediaInfo(e) {
2218
2246
  if (!(e.videoCodec ?? e.keySystem ?? e.ladderHeights)) return;
2219
2247
  let t = {};
2220
- e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = qt[e.keySystem]), e.drmSecurityLevel && (t.drmSecurityLevel = e.drmSecurityLevel), e.ladderHeights?.length && (t.ladderHeights = e.ladderHeights), e.ladderTopBitrateKbps && (t.ladderTopBitrateKbps = e.ladderTopBitrateKbps), e.lowLatency && (t.lowLatency = !0);
2248
+ e.videoCodec && (t.videoCodec = e.videoCodec), e.audioCodec && (t.audioCodec = e.audioCodec), e.keySystem && (t.keySystem = Yt[e.keySystem]), e.drmSecurityLevel && (t.drmSecurityLevel = e.drmSecurityLevel), e.ladderHeights?.length && (t.ladderHeights = e.ladderHeights), e.ladderTopBitrateKbps && (t.ladderTopBitrateKbps = e.ladderTopBitrateKbps), e.lowLatency && (t.lowLatency = !0);
2221
2249
  let n = JSON.stringify(t);
2222
2250
  n !== this.mediaInfoSignature && (this.mediaInfoSignature = n, this.enqueue({ mediaInfo: t }));
2223
2251
  }
@@ -2237,7 +2265,7 @@ var rn = class {
2237
2265
  let c = r?.positionMs ?? 0;
2238
2266
  c > 0 && (i.exitPositionMs = Math.round(c)), this.activeTotalMs > 0 && (i.activeWatchTimeMs = Math.round(this.activeTotalMs)), this.mutedTotalMs > 0 && (i.mutedTimeMs = Math.round(this.mutedTotalMs));
2239
2267
  let l = e !== "END_REASON_ENDED";
2240
- l && this.lastStallMs > 0 && n - this.lastStallMs <= Wt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Wt && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2268
+ l && this.lastStallMs > 0 && n - this.lastStallMs <= Kt && (i.abandonAfterStallMs = Math.max(q, Math.round(n - this.lastStallMs))), l && this.lastErrorMs > 0 && n - this.lastErrorMs <= Kt && (i.abandonAfterErrorMs = Math.max(q, Math.round(n - this.lastErrorMs))), this.fullscreenTotalMs > 0 && (i.fullscreenTimeMs = Math.round(this.fullscreenTotalMs)), this.pipTotalMs > 0 && (i.pipTimeMs = Math.round(this.pipTotalMs)), this.volumeChanges > 0 && (i.volumeChanges = this.volumeChanges), this.muteChanges > 0 && (i.muteChanges = this.muteChanges);
2241
2269
  let u = r?.decodedFrames ?? this.lastDecoded;
2242
2270
  u > 0 && (i.decodedFramesTotal = u), e === "END_REASON_STOPPED" && this.startupTimeMs === 0 && this.lastErrorStage === null && (e = "END_REASON_ABORTED", i.reason = e), this.startupTimeMs === 0 && e !== "END_REASON_ABORTED" && (i.failedStage = this.lastErrorStage ?? (this.manifestLoadMs === 0 ? "ERROR_STAGE_MANIFEST" : this.firstFragLoadMs === 0 ? "ERROR_STAGE_FIRST_SEGMENT" : "ERROR_STAGE_OTHER")), this.pending.push(this.wrap({ sessionEnd: i })), this.flush(e === "END_REASON_PAGEHIDE");
2243
2271
  }
@@ -2257,13 +2285,13 @@ var rn = class {
2257
2285
  };
2258
2286
  }
2259
2287
  noteCspBlocked() {
2260
- this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.($t(new URL(this.url).origin)));
2288
+ this.cspBlockedNoted || this.endedFlag || !this.cspBlocked() || (this.cspBlockedNoted = !0, this.opts.onBlocked?.(tn(new URL(this.url).origin)));
2261
2289
  }
2262
2290
  cspBlocked() {
2263
2291
  return !!this.cspKey && Y.has(this.cspKey);
2264
2292
  }
2265
2293
  enqueue(e) {
2266
- if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Ht;) {
2294
+ if (!this.cspBlocked()) for (this.pending.push(this.wrap(e)); this.pending.length > Wt;) {
2267
2295
  let e = this.pending.findIndex((e) => e.heartbeat || e.stateChange);
2268
2296
  this.pending.splice(e >= 0 ? e : 0, 1);
2269
2297
  }
@@ -2290,7 +2318,7 @@ var rn = class {
2290
2318
  };
2291
2319
  //#endregion
2292
2320
  //#region src/core/environment.ts
2293
- function an() {
2321
+ function sn() {
2294
2322
  if (typeof window > "u") return { integration: "INTEGRATION_KIND_SDK" };
2295
2323
  let e;
2296
2324
  try {
@@ -2315,14 +2343,14 @@ function an() {
2315
2343
  integration: "INTEGRATION_KIND_IFRAME"
2316
2344
  };
2317
2345
  }
2318
- function on() {
2346
+ function cn() {
2319
2347
  if (typeof navigator > "u") return "DEVICE_CLASS_OTHER";
2320
2348
  let e = navigator.userAgentData, t = e?.platform ?? "";
2321
2349
  if (/tv|tizen|webos/i.test(t)) return "DEVICE_CLASS_TV";
2322
2350
  let n = typeof screen < "u" ? Math.min(screen.width, screen.height) : 0;
2323
2351
  return e?.mobile ?? (typeof navigator.maxTouchPoints == "number" && navigator.maxTouchPoints > 1 && n > 0 && n < 900) ? n >= 600 ? "DEVICE_CLASS_TABLET" : "DEVICE_CLASS_PHONE" : e || n >= 900 || /mac|win|linux|chrome os/i.test(t) ? "DEVICE_CLASS_DESKTOP" : "DEVICE_CLASS_OTHER";
2324
2352
  }
2325
- function sn() {
2353
+ function ln() {
2326
2354
  let e = typeof navigator < "u" ? navigator.connection : void 0;
2327
2355
  if (!e) return { connectionType: "CONNECTION_TYPE_UNKNOWN" };
2328
2356
  let t = {
@@ -2341,17 +2369,17 @@ function sn() {
2341
2369
  }
2342
2370
  return typeof e.downlink == "number" && e.downlink > 0 && (i.downlinkKbps = Math.round(e.downlink * 1e3)), typeof e.rtt == "number" && e.rtt > 0 && (i.rttMs = Math.round(e.rtt)), e.saveData && (i.saveData = !0), i;
2343
2371
  }
2344
- function cn(e) {
2345
- let t = an(), n = {
2346
- deviceClass: on(),
2372
+ function un(e) {
2373
+ let t = sn(), n = {
2374
+ deviceClass: cn(),
2347
2375
  integration: t.integration,
2348
- ...sn()
2376
+ ...ln()
2349
2377
  };
2350
2378
  t.host && (n.host = t.host), typeof screen < "u" && screen.width > 0 && (n.screenWidth = screen.width, n.screenHeight = screen.height), typeof window < "u" && window.devicePixelRatio > 0 && (n.devicePixelRatio = Math.round(window.devicePixelRatio * 100) / 100);
2351
2379
  let r = e.getBoundingClientRect?.();
2352
2380
  return r && r.width > 0 && (n.viewportWidth = Math.round(r.width), n.viewportHeight = Math.round(r.height)), n;
2353
2381
  }
2354
- async function ln() {
2382
+ async function dn() {
2355
2383
  let e = typeof navigator < "u" ? navigator.userAgentData : void 0;
2356
2384
  if (!e?.getHighEntropyValues) return {};
2357
2385
  try {
@@ -2363,7 +2391,7 @@ async function ln() {
2363
2391
  }
2364
2392
  //#endregion
2365
2393
  //#region src/core/version.ts
2366
- var un = "2.16.0", dn = {
2394
+ var fn = "2.16.1", pn = {
2367
2395
  accent: "#E1B600",
2368
2396
  accentText: "#1B1C23",
2369
2397
  background: "#0e0f13",
@@ -2374,7 +2402,7 @@ var un = "2.16.0", dn = {
2374
2402
  border: "rgba(255, 255, 255, 0.1)",
2375
2403
  radius: "8px",
2376
2404
  fontFamily: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif"
2377
- }, fn = {
2405
+ }, mn = {
2378
2406
  accent: "--havik-accent",
2379
2407
  accentText: "--havik-accent-text",
2380
2408
  background: "--havik-bg",
@@ -2386,26 +2414,26 @@ var un = "2.16.0", dn = {
2386
2414
  radius: "--havik-radius",
2387
2415
  fontFamily: "--havik-font"
2388
2416
  };
2389
- function pn(e, t) {
2417
+ function hn(e, t) {
2390
2418
  let n = {
2391
- ...dn,
2419
+ ...pn,
2392
2420
  ...t
2393
2421
  };
2394
- for (let t of Object.keys(fn)) e.style.setProperty(fn[t], n[t]);
2422
+ for (let t of Object.keys(mn)) e.style.setProperty(mn[t], n[t]);
2395
2423
  n.logoUrl && e.style.setProperty("--havik-logo", `url("${n.logoUrl}")`);
2396
2424
  }
2397
2425
  //#endregion
2398
2426
  //#region src/ui/styles.ts
2399
- var mn = "havik-player-styles", hn = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
2400
- function gn(e = document, t) {
2401
- let n = e.querySelector(`style#${mn}`);
2427
+ var gn = "havik-player-styles", _n = "\n.havik-player{position:relative;display:block;width:100%;background:var(--havik-bg,#0e0f13);\n color:var(--havik-text,#fff);font-family:var(--havik-font,system-ui,sans-serif);\n overflow:hidden;line-height:1.4;-webkit-tap-highlight-color:transparent}\n.havik-player video{display:block;width:100%;height:auto;aspect-ratio:16/9;\n object-fit:contain;background:#000;outline:none}\n.havik-player:focus{outline:none}\n.havik-player *{box-sizing:border-box}\n\n.havik-player:fullscreen,.havik-player:-webkit-full-screen{display:flex;align-items:center;\n justify-content:center;width:100vw;height:100vh;aspect-ratio:auto}\n.havik-player:fullscreen video,.havik-player:-webkit-full-screen video{width:100%;height:100%;\n aspect-ratio:auto;object-fit:contain}\n\n.havik-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;cursor:pointer;\n touch-action:manipulation}\n.havik-gradient{position:absolute;left:0;right:0;bottom:0;height:120px;pointer-events:none;\n background:linear-gradient(to top,rgba(0,0,0,.78),transparent);\n opacity:1;transition:opacity .25s}\n.havik-player.havik-hide .havik-gradient,\n.havik-player.havik-hide .havik-bar{opacity:0;pointer-events:none}\n.havik-player.havik-hide{cursor:none}\n\n.havik-center{width:74px;height:74px;border-radius:50%;border:0;cursor:pointer;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);\n display:flex;align-items:center;justify-content:center;\n box-shadow:0 6px 24px rgba(0,0,0,.45);transition:transform .15s,opacity .15s}\n.havik-center:hover{transform:scale(1.06)}\n.havik-center svg{width:38px;height:38px;margin-left:2px}\n.havik-center.havik-gone{opacity:0;pointer-events:none;transform:scale(.8)}\n\n/* Absolutely centred, NOT a flex sibling of .havik-center: the hidden center\n button (.havik-gone) still occupies its 74px in the row, which pushed an\n in-flow spinner 37px right of centre. */\n.havik-spinner{position:absolute;inset:0;margin:auto;width:56px;height:56px;border-radius:50%;\n border:4px solid rgba(255,255,255,.2);border-top-color:var(--havik-accent,#E1B600);\n animation:havik-spin .8s linear infinite}\n@keyframes havik-spin{to{transform:rotate(360deg)}}\n\n/* Status card — branded full-bleed overlay for the stopped/pre-play states\n (ended / fatal error / pre-play / armed-waiting). */\n.havik-status{position:absolute;inset:0;display:flex;flex-direction:column;gap:16px;\n align-items:center;justify-content:center;background:rgba(14,15,19,.82);text-align:center;padding:24px}\n.havik-status__logo{width:128px;height:46px;background:var(--havik-logo) center/contain no-repeat;opacity:.95}\n.havik-status__msg{color:var(--havik-text,#fff);font-size:15px;font-weight:600;max-width:480px}\n.havik-status__btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;\n padding:10px 18px;border-radius:var(--havik-radius,8px);font-weight:700;font-size:14px;\n background:var(--havik-accent,#E1B600);color:var(--havik-accent-text,#1B1C23);transition:transform .15s}\n.havik-status__btn:hover{transform:scale(1.04)}\n.havik-status__btn svg{width:18px;height:18px}\n/* Pre-play: lighter scrim so the poster shows through, and a round play CTA. */\n.havik-status--preplay{background:rgba(14,15,19,.4)}\n.havik-status--preplay .havik-status__btn--play{width:74px;height:74px;border-radius:50%;padding:0;\n justify-content:center;box-shadow:0 6px 24px rgba(0,0,0,.45)}\n.havik-status--preplay .havik-status__btn--play svg{width:38px;height:38px;margin-left:3px}\n\n.havik-watermark{position:absolute;top:12px;right:14px;height:22px;opacity:.85;pointer-events:none;\n content:'';background:var(--havik-logo) center/contain no-repeat;width:90px}\n/* A status card carries its own logo — the corner watermark would duplicate it. */\n.havik-player.havik-has-status .havik-watermark{display:none}\n\n.havik-bar{position:absolute;left:0;right:0;bottom:0;padding:0 12px 8px;\n opacity:1;transition:opacity .25s;z-index:2}\n.havik-seek{position:relative;height:16px;display:flex;align-items:center;cursor:pointer;margin-bottom:2px}\n.havik-seek__track{position:relative;width:100%;height:4px;border-radius:3px;background:rgba(255,255,255,.25)}\n.havik-seek__buffered{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:rgba(255,255,255,.4)}\n.havik-seek__played{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-seek__thumb{position:absolute;top:50%;width:13px;height:13px;border-radius:50%;\n background:var(--havik-accent,#E1B600);transform:translate(-50%,-50%) scale(0);transition:transform .1s}\n.havik-seek:hover .havik-seek__thumb{transform:translate(-50%,-50%) scale(1)}\n\n.havik-controls{display:flex;align-items:center;gap:6px;height:40px}\n.havik-spacer{flex:1}\n.havik-btn{display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;border-radius:var(--havik-radius,8px);\n padding:0;transition:background .12s,color .12s}\n.havik-btn:hover{background:rgba(255,255,255,.12)}\n.havik-btn:focus-visible{outline:2px solid var(--havik-accent,#E1B600);outline-offset:1px}\n.havik-btn svg{width:22px;height:22px}\n\n/* The volume level is filled in accent up to the thumb, like the seek bar's\n played span — a native range input paints no \"elapsed\" side, which left the\n level readable only from the dot's position. --havik-vol (0..1) is set by\n syncVolume(); the track width and thumb size live here as variables because\n the WebKit fill has to compute the thumb centre from both. */\n.havik-vol{display:flex;align-items:center}\n.havik-vol__slider{--havik-vol-w:70px;--havik-vol-thumb:12px;--havik-vol:1;\n --havik-vol-pos:calc(var(--havik-vol-thumb) / 2 + var(--havik-vol) * (var(--havik-vol-w) - var(--havik-vol-thumb)));\n width:0;opacity:0;transition:width .18s,opacity .18s;height:4px;cursor:pointer;\n appearance:none;-webkit-appearance:none;background:transparent;border-radius:3px;margin:0 4px}\n.havik-vol:hover .havik-vol__slider,.havik-vol:focus-within .havik-vol__slider{width:var(--havik-vol-w);opacity:1}\n/* WebKit/Blink have no progress pseudo-element: paint the fill as a hard-stop\n gradient that ends at the thumb centre. */\n.havik-vol__slider::-webkit-slider-runnable-track{height:4px;border-radius:3px;\n background:linear-gradient(to right,var(--havik-accent,#E1B600) var(--havik-vol-pos),\n rgba(255,255,255,.3) var(--havik-vol-pos))}\n/* Firefox fills natively, and tracks the thumb exactly. */\n.havik-vol__slider::-moz-range-track{height:4px;border-radius:3px;background:rgba(255,255,255,.3)}\n.havik-vol__slider::-moz-range-progress{height:4px;border-radius:3px;background:var(--havik-accent,#E1B600)}\n.havik-vol__slider::-webkit-slider-thumb{-webkit-appearance:none;width:var(--havik-vol-thumb);\n height:var(--havik-vol-thumb);border-radius:50%;background:var(--havik-accent,#E1B600);\n margin-top:calc((4px - var(--havik-vol-thumb)) / 2)}\n.havik-vol__slider::-moz-range-thumb{width:var(--havik-vol-thumb);height:var(--havik-vol-thumb);\n border:0;border-radius:50%;background:var(--havik-accent,#E1B600)}\n\n.havik-time{font-size:12px;color:var(--havik-text-muted,#9aa0ad);\n font-variant-numeric:tabular-nums;padding:0 6px;white-space:nowrap}\n.havik-live{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;\n letter-spacing:.4px;padding:0 8px;color:var(--havik-text,#fff)}\n.havik-live svg{width:9px;height:9px;color:var(--havik-text-muted,#9aa0ad)}\n.havik-live.is-live svg{color:var(--havik-accent,#E1B600)}\n.havik-live__go{margin-left:2px;border:0;cursor:pointer;background:transparent;color:var(--havik-text-muted,#9aa0ad);\n font:inherit;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;padding:2px 6px;border-radius:6px}\n.havik-live.is-live .havik-live__go{display:none}\n.havik-live__go:hover{color:var(--havik-accent,#E1B600)}\n\n.havik-menu{position:absolute;bottom:54px;right:12px;min-width:170px;max-height:230px;overflow:auto;\n background:var(--havik-surface,#1B1C23);border:1px solid var(--havik-border,rgba(255,255,255,.1));\n border-radius:var(--havik-radius,8px);box-shadow:0 10px 30px rgba(0,0,0,.5);padding:6px;z-index:3}\n.havik-menu[hidden]{display:none}\n.havik-menu__title{font-size:11px;text-transform:uppercase;letter-spacing:.6px;\n color:var(--havik-text-muted,#9aa0ad);padding:6px 8px 4px}\n.havik-menu__item{display:flex;align-items:center;justify-content:space-between;gap:10px;width:100%;\n border:0;background:transparent;color:var(--havik-text,#fff);cursor:pointer;font:inherit;font-size:13px;\n text-align:left;padding:7px 8px;border-radius:6px}\n.havik-menu__item:hover{background:var(--havik-surface-muted,#2a2c36)}\n.havik-menu__item[aria-checked=\"true\"]{color:var(--havik-accent,#E1B600);font-weight:600}\n.havik-menu__item[aria-checked=\"true\"]::after{content:'✓'}\n", Z = /* @__PURE__ */ new WeakMap();
2428
+ function vn(e = document, t) {
2429
+ let n = e.querySelector(`style#${gn}`);
2402
2430
  if (n && (!t || Z.get(n) === t)) return;
2403
2431
  let r = e.createElement("style");
2404
- r.id = mn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = hn, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2432
+ r.id = gn, t && (r.nonce = t, r.setAttribute("nonce", t)), r.textContent = _n, Z.set(r, t), n ? n.replaceWith(r) : e.head.appendChild(r);
2405
2433
  }
2406
2434
  //#endregion
2407
2435
  //#region src/ui/icons.ts
2408
- var _n = {
2436
+ var yn = {
2409
2437
  play: "<path d=\"M8 5v14l11-7z\"/>",
2410
2438
  pause: "<path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"/>",
2411
2439
  volumeHigh: "<path d=\"M3 10v4h4l5 5V5L7 10H3zm13.5 2a4.5 4.5 0 0 0-2.5-4v8a4.5 4.5 0 0 0 2.5-4zm-2.5-9v2.06A7 7 0 0 1 14 19v2a9 9 0 0 0 0-18z\"/>",
@@ -2419,20 +2447,20 @@ var _n = {
2419
2447
  retry: "<path d=\"M17.65 6.35A8 8 0 1 0 19.73 13h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z\"/>"
2420
2448
  };
2421
2449
  function Q(e) {
2422
- return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${_n[e]}</svg>`;
2450
+ return `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor">${yn[e]}</svg>`;
2423
2451
  }
2424
2452
  //#endregion
2425
2453
  //#region src/ui/controls.ts
2426
- var vn = 3e3, yn = 250, bn = /* @__PURE__ */ new Set([
2454
+ var bn = 3e3, xn = 250, Sn = /* @__PURE__ */ new Set([
2427
2455
  "GONE",
2428
2456
  "NOT_FOUND",
2429
2457
  "INVALID_URN",
2430
2458
  "UNAUTHORIZED"
2431
2459
  ]);
2432
- function xn(e) {
2433
- return new Sn(e);
2460
+ function Cn(e) {
2461
+ return new wn(e);
2434
2462
  }
2435
- var Sn = class {
2463
+ var wn = class {
2436
2464
  root;
2437
2465
  video;
2438
2466
  player;
@@ -2478,7 +2506,7 @@ var Sn = class {
2478
2506
  scrubbing = !1;
2479
2507
  offFns = [];
2480
2508
  constructor(e) {
2481
- this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? vn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, gn(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2509
+ this.root = e.root, this.video = e.video, this.player = e.player, this.doc = e.root.ownerDocument ?? document, this.autoHideMs = e.autoHideMs ?? bn, this.logoUrl = e.logoUrl, this.statusOverlays = e.statusOverlays !== !1, this.endedMessage = e.endedMessage ?? "This stream has ended", this.interruptedMessage = e.interruptedMessage ?? "Reconnecting — please stand by", this.errorMessage = e.errorMessage, vn(this.doc, e.cspNonce), this.root.classList.add("havik-player"), this.root.hasAttribute("tabindex") || (this.root.tabIndex = 0), this.root.setAttribute("role", "region"), this.root.setAttribute("aria-label", "Video player");
2482
2510
  let t = (e, t, n) => {
2483
2511
  let r = this.doc.createElement(e);
2484
2512
  if (r.className = t, n) for (let [e, t] of Object.entries(n)) r.setAttribute(e, t);
@@ -2564,7 +2592,7 @@ var Sn = class {
2564
2592
  let t = this.surfaceWasHidden;
2565
2593
  this.tapTimer = setTimeout(() => {
2566
2594
  this.tapTimer = void 0, this.toggleBar(t);
2567
- }, yn);
2595
+ }, xn);
2568
2596
  }
2569
2597
  toggleBar(e) {
2570
2598
  e ? this.poke() : this.hideIfIdle();
@@ -2599,7 +2627,7 @@ var Sn = class {
2599
2627
  e.type = "button", e.className = "havik-status__btn havik-status__btn--play", e.setAttribute("aria-label", "Play"), e.innerHTML = Q("play"), e.addEventListener("click", () => void this.player.play()), n.append(e);
2600
2628
  } else {
2601
2629
  let r = this.doc.createElement("div");
2602
- if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !bn.has(this.lastError.code)) {
2630
+ if (r.className = "havik-status__msg", r.textContent = t ?? "", n.append(r), e === "error" && this.lastError && !Sn.has(this.lastError.code)) {
2603
2631
  let e = this.doc.createElement("button");
2604
2632
  e.type = "button", e.className = "havik-status__btn", e.innerHTML = `${Q("retry")}<span>Retry</span>`, e.addEventListener("click", () => void this.player.retry()), n.append(e);
2605
2633
  }
@@ -2640,7 +2668,7 @@ var Sn = class {
2640
2668
  let n = r.end(r.length - 1), i = Math.min(1, Math.max(0, (n - e.start) / t));
2641
2669
  this.seekBuffered.style.width = `${(i * 100).toFixed(2)}%`;
2642
2670
  }
2643
- !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Cn(this.video.currentTime)} / ${Cn(this.video.duration)}`);
2671
+ !this.player.getStats().isLive && Number.isFinite(this.video.duration) && (this.time.textContent = `${Tn(this.video.currentTime)} / ${Tn(this.video.duration)}`);
2644
2672
  }
2645
2673
  syncLive() {
2646
2674
  let e = this.player.getStats(), t = e.isLive !== !1;
@@ -2690,17 +2718,17 @@ var Sn = class {
2690
2718
  renderQualityMenu() {
2691
2719
  let e = this.player.getQualityLevels(), t = this.player.getCurrentQuality(), n = this.doc.createElement("div");
2692
2720
  n.className = "havik-menu__title", n.textContent = "Quality", this.menu.replaceChildren(n, this.menuItem("Auto", t === -1, () => this.player.setQuality("auto")));
2693
- for (let n of e) this.menu.append(this.menuItem(wn(n), t === n.index, () => this.player.setQuality(n.index)));
2721
+ for (let n of e) this.menu.append(this.menuItem(En(n), t === n.index, () => this.player.setQuality(n.index)));
2694
2722
  }
2695
2723
  renderAudioMenu() {
2696
2724
  let e = this.player.getAudioTracks(), t = this.doc.createElement("div");
2697
2725
  t.className = "havik-menu__title", t.textContent = "Audio", this.menu.replaceChildren(t);
2698
- for (let t of e) this.menu.append(this.menuItem(Tn(t), t.default, () => this.player.setAudioTrack(t.id)));
2726
+ for (let t of e) this.menu.append(this.menuItem(Dn(t), t.default, () => this.player.setAudioTrack(t.id)));
2699
2727
  }
2700
2728
  renderCcMenu() {
2701
2729
  let e = this.player.getTextTracks(), t = this.doc.createElement("div");
2702
2730
  t.className = "havik-menu__title", t.textContent = "Subtitles", this.menu.replaceChildren(t, this.menuItem("Off", !1, () => this.player.setTextTrack(-1)));
2703
- for (let t of e) this.menu.append(this.menuItem(En(t), !1, () => this.player.setTextTrack(t.id)));
2731
+ for (let t of e) this.menu.append(this.menuItem(On(t), !1, () => this.player.setTextTrack(t.id)));
2704
2732
  }
2705
2733
  onTracksChanged() {
2706
2734
  this.openMenu && this.renderMenu(this.openMenu);
@@ -2801,41 +2829,41 @@ var Sn = class {
2801
2829
  this.root.classList.remove("havik-player", "havik-hide", "havik-has-status");
2802
2830
  }
2803
2831
  };
2804
- function Cn(e) {
2832
+ function Tn(e) {
2805
2833
  (!Number.isFinite(e) || e < 0) && (e = 0);
2806
2834
  let t = Math.floor(e % 60), n = Math.floor(e / 60 % 60), r = Math.floor(e / 3600), i = r > 0 ? String(n).padStart(2, "0") : String(n), a = String(t).padStart(2, "0");
2807
2835
  return r > 0 ? `${r}:${i}:${a}` : `${i}:${a}`;
2808
2836
  }
2809
- function wn(e) {
2837
+ function En(e) {
2810
2838
  return e.height ? `${e.height}p` : `${Math.round(e.bitrate / 1e3)} kbps`;
2811
2839
  }
2812
- function Tn(e) {
2840
+ function Dn(e) {
2813
2841
  return e.name || e.lang || `Track ${e.id}`;
2814
2842
  }
2815
- function En(e) {
2843
+ function On(e) {
2816
2844
  return e.name || e.lang || `Track ${e.id}`;
2817
2845
  }
2818
2846
  //#endregion
2819
2847
  //#region src/managed/index.ts
2820
- var Dn = 6e3, On = 45e3, kn = 2e3, An = 3, jn = 2e3, Mn = 48e4;
2821
- function Nn(e) {
2848
+ var kn = 6e3, An = 45e3, jn = 2e3, Mn = 3, Nn = 2e3, Pn = 48e4;
2849
+ function Fn(e) {
2822
2850
  if (e.env !== void 0 && e.baseUrl !== void 0) throw new n("INTERNAL", 0, `createPlayer: pass env OR baseUrl, not both (got env=${JSON.stringify(e.env)} and baseUrl=${JSON.stringify(e.baseUrl)})`);
2823
2851
  if (e.env !== void 0) return B(e.env);
2824
2852
  if (!e.baseUrl) throw new n("INTERNAL", 0, "createPlayer: env or baseUrl is required (env: 'integration' | 'production')");
2825
2853
  return e.baseUrl;
2826
2854
  }
2827
- async function Pn(e) {
2855
+ async function In(e) {
2828
2856
  if (!e.video || typeof e.video.play != "function") throw new n("INTERNAL", 0, "createPlayer: opts.video must be an HTMLVideoElement");
2829
- let t = Nn(e);
2857
+ let t = Fn(e);
2830
2858
  if (!e.matchUrn) throw new n("INVALID_URN", 0, "createPlayer: matchUrn is required");
2831
2859
  if (!e.credential) throw new n("INTERNAL", 0, "createPlayer: credential is required");
2832
- let r = new Fn({
2860
+ let r = new Ln({
2833
2861
  ...e,
2834
2862
  baseUrl: t
2835
2863
  });
2836
2864
  return await r.start(), r;
2837
2865
  }
2838
- var Fn = class {
2866
+ var Ln = class {
2839
2867
  opts;
2840
2868
  abort = new AbortController();
2841
2869
  listeners = {};
@@ -2923,7 +2951,7 @@ var Fn = class {
2923
2951
  setTimeout(() => {
2924
2952
  a || this.destroyed || e !== this.loadGen || this.emit("waiting", {
2925
2953
  phase: i ? "unavailable" : "tooEarly",
2926
- retryInMs: On,
2954
+ retryInMs: An,
2927
2955
  attempt: 1,
2928
2956
  elapsedMs: 0,
2929
2957
  ...!i && f !== void 0 && f > Date.now() ? { ttkMs: f - Date.now() } : {}
@@ -2962,13 +2990,13 @@ var Fn = class {
2962
2990
  !a && !p() && h();
2963
2991
  }, e);
2964
2992
  };
2965
- _(Dn), this.armingSub = E({
2993
+ _(kn), this.armingSub = E({
2966
2994
  eventsBaseUrl: t,
2967
2995
  matchUrn: this.opts.matchUrn,
2968
2996
  credential: this.opts.credential,
2969
- onAlive: () => _(On),
2997
+ onAlive: () => _(An),
2970
2998
  onState: (e) => {
2971
- a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * kn);
2999
+ a || p() || (e.state === "live" || e.state === "gone") && setTimeout(g, Math.random() * jn);
2972
3000
  },
2973
3001
  onError: () => h()
2974
3002
  });
@@ -3013,19 +3041,19 @@ var Fn = class {
3013
3041
  if (this.analyticsSession?.noteDestroyed(), this.analyticsSession = null, this.detachMediaListeners?.(), this.opts.analytics === !1) return;
3014
3042
  let i = e.analytics?.sid;
3015
3043
  if (!i) return;
3016
- let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = nn(this.opts.baseUrl, a, e.analytics?.endpoint);
3044
+ let a = typeof this.opts.analytics == "object" ? this.opts.analytics.endpoint : void 0, { endpoint: o, disabledReason: s } = an(this.opts.baseUrl, a, e.analytics?.endpoint);
3017
3045
  if (!o) {
3018
3046
  s && setTimeout(() => {
3019
3047
  this.destroyed || r !== this.loadGen || this.emit("warning", new n("INTERNAL", 0, s));
3020
3048
  }, 0);
3021
3049
  return;
3022
3050
  }
3023
- let c = this.opts.video, l = new rn({
3051
+ let c = this.opts.video, l = new on({
3024
3052
  endpoint: o,
3025
3053
  sid: i,
3026
3054
  player: t.name === "native" ? "PLAYER_SAFARI_NATIVE" : "PLAYER_HLSJS",
3027
- sdkVersion: un,
3028
- environment: cn(c),
3055
+ sdkVersion: fn,
3056
+ environment: un(c),
3029
3057
  idleMs: typeof this.opts.analytics == "object" ? this.opts.analytics.idleMs : void 0,
3030
3058
  onIdle: () => this.onAnalyticsIdle(t),
3031
3059
  onBlocked: (e) => setTimeout(() => {
@@ -3046,7 +3074,7 @@ var Fn = class {
3046
3074
  let u = () => l.noteSeek(), d = () => l.noteVolume(c.muted, c.volume);
3047
3075
  c.addEventListener("seeking", u), c.addEventListener("volumechange", d), this.detachMediaListeners = () => {
3048
3076
  c.removeEventListener("seeking", u), c.removeEventListener("volumechange", d);
3049
- }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), ln().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3077
+ }, l.start(), l.seedVolume(c.muted, c.volume), l.notePresentation(this.currentPresentation()), dn().then((e) => l.noteEnvironment(e)), this.opts.autoplay === !1 && l.noteAutoplay("AUTOPLAY_RESULT_NOT_ATTEMPTED");
3050
3078
  }
3051
3079
  currentPresentation() {
3052
3080
  let e = this.opts.video;
@@ -3072,9 +3100,9 @@ var Fn = class {
3072
3100
  emit: (e) => this.onEngineEvent(e)
3073
3101
  }, o = this.opts.engine ?? "auto";
3074
3102
  if (o === "native") return new K(a);
3075
- if (o === "hls") return new Rt(a);
3076
- if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G() || !e.drmEnabled && Ye() && W(this.opts.video)) return new K(a);
3077
- if (ot()) return new Rt(a);
3103
+ if (o === "hls") return new Bt(a);
3104
+ if (e.drmEnabled && e.drm?.fairplay?.licenseUrl && e.drm.fairplay.certificateUrl && W(this.opts.video) && G() || !e.drmEnabled && Ze() && W(this.opts.video)) return new K(a);
3105
+ if (ct()) return new Bt(a);
3078
3106
  if (W(this.opts.video)) return new K(a);
3079
3107
  throw new n("INTERNAL", 0, "no supported HLS playback engine in this browser");
3080
3108
  }
@@ -3127,7 +3155,7 @@ var Fn = class {
3127
3155
  r = 0, i = !1;
3128
3156
  },
3129
3157
  onError: () => {
3130
- this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= An && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
3158
+ this.destroyed || e !== this.loadGen || i || this.endedHandled || (r += 1, r >= Mn && (i = !0, this.emit("warning", new n("NETWORK", 0, `live-state events unreachable at ${t} after ${r} attempts — end-of-stream detection degraded to the HLS staleness watchdog. Check the events host, the api-key's allowed origins, and CSP connect-src.`))));
3131
3159
  }
3132
3160
  });
3133
3161
  }
@@ -3149,7 +3177,7 @@ var Fn = class {
3149
3177
  scheduleRejoin(e) {
3150
3178
  this.rejoinEnabled() && !this.rejoinTimer && (this.rejoinTimer = setTimeout(() => {
3151
3179
  this.rejoinTimer = null, !(this.destroyed || e !== this.loadGen || this._state !== "ended") && this.rejoin();
3152
- }, Math.random() * kn));
3180
+ }, Math.random() * jn));
3153
3181
  }
3154
3182
  cancelRejoin() {
3155
3183
  this.rejoinTimer &&= (clearTimeout(this.rejoinTimer), null);
@@ -3173,7 +3201,7 @@ var Fn = class {
3173
3201
  }
3174
3202
  t.controls = !1;
3175
3203
  let n = (t.ownerDocument ?? document).createElement("div"), r = t.parentNode;
3176
- r && r.insertBefore(n, t), n.appendChild(t), pn(n, this.opts.theme), this.container = n, this.controlBar = xn({
3204
+ r && r.insertBefore(n, t), n.appendChild(t), hn(n, this.opts.theme), this.container = n, this.controlBar = Cn({
3177
3205
  root: n,
3178
3206
  video: t,
3179
3207
  player: this,
@@ -3204,7 +3232,7 @@ var Fn = class {
3204
3232
  }
3205
3233
  startStats() {
3206
3234
  this.stopStats();
3207
- let e = Math.max(500, this.opts.statsIntervalMs ?? jn);
3235
+ let e = Math.max(500, this.opts.statsIntervalMs ?? Nn);
3208
3236
  this.statsTimer = setInterval(() => {
3209
3237
  if (!this.engine) return;
3210
3238
  let e = this.engine.getStats();
@@ -3216,7 +3244,7 @@ var Fn = class {
3216
3244
  }
3217
3245
  scheduleLicenseRefresh() {
3218
3246
  this.stopRefresh();
3219
- let e = this.opts.licenseRefreshMs ?? Mn;
3247
+ let e = this.opts.licenseRefreshMs ?? Pn;
3220
3248
  e && this._descriptor?.drmEnabled && (this.refreshTimer = setInterval(() => void this.refreshLicense(), e));
3221
3249
  }
3222
3250
  stopRefresh() {
@@ -3371,7 +3399,7 @@ function $(e) {
3371
3399
  }
3372
3400
  //#endregion
3373
3401
  //#region src/embed/host.ts
3374
- function In(e) {
3402
+ function Rn(e) {
3375
3403
  if (!e.container || typeof e.container.appendChild != "function") throw Error("mountEmbed: opts.container must be a DOM element");
3376
3404
  if (!e.src) throw Error("mountEmbed: opts.src is required");
3377
3405
  if (!e.baseUrl || !e.matchUrn) throw Error("mountEmbed: opts.baseUrl and opts.matchUrn are required");
@@ -3430,15 +3458,15 @@ function In(e) {
3430
3458
  }
3431
3459
  //#endregion
3432
3460
  //#region src/embed/page.ts
3433
- var Ln = /^[A-Za-z0-9:_.-]{1,128}$/;
3434
- function Rn(e) {
3461
+ var zn = /^[A-Za-z0-9:_.-]{1,128}$/;
3462
+ function Bn(e) {
3435
3463
  if (typeof e == "boolean") return e;
3436
3464
  if (typeof e == "object" && e) {
3437
3465
  let t = e.endpoint;
3438
3466
  return typeof t == "string" ? { endpoint: t } : {};
3439
3467
  }
3440
3468
  }
3441
- function zn() {
3469
+ function Vn() {
3442
3470
  let e = window.HAVIK_EMBED_CONFIG;
3443
3471
  if (e) return {
3444
3472
  baseUrl: e.baseUrl ?? "",
@@ -3448,7 +3476,7 @@ function zn() {
3448
3476
  autoplay: e.autoplay ?? !0,
3449
3477
  muted: e.muted ?? !0,
3450
3478
  waitForLive: e.waitForLive ?? !0,
3451
- analytics: Rn(e.analytics)
3479
+ analytics: Bn(e.analytics)
3452
3480
  };
3453
3481
  let t = new URLSearchParams(location.search);
3454
3482
  return {
@@ -3461,9 +3489,9 @@ function zn() {
3461
3489
  waitForLive: !0
3462
3490
  };
3463
3491
  }
3464
- async function Bn() {
3465
- let e = zn();
3466
- Hn();
3492
+ async function Hn() {
3493
+ let e = Vn();
3494
+ Wn();
3467
3495
  let t = document.createElement("video");
3468
3496
  t.setAttribute("playsinline", ""), t.muted = e.muted ?? !0, t.style.cssText = "width:100%;height:100%;object-fit:contain;background:#000;aspect-ratio:auto", document.body.appendChild(t);
3469
3497
  let r = e.parentOrigin && e.parentOrigin !== "null" ? e.parentOrigin : null;
@@ -3518,12 +3546,12 @@ async function Bn() {
3518
3546
  code: e.code,
3519
3547
  message: e.message
3520
3548
  })), e.on("autoplayblocked", () => {
3521
- i({ type: "oddin:autoplayblocked" }), Vn(t, e);
3549
+ i({ type: "oddin:autoplayblocked" }), Un(t, e);
3522
3550
  });
3523
3551
  }, s = async (r) => {
3524
3552
  a?.destroy(), a = null;
3525
3553
  try {
3526
- let n = await Pn({
3554
+ let n = await In({
3527
3555
  video: t,
3528
3556
  baseUrl: e.baseUrl,
3529
3557
  matchUrn: r,
@@ -3585,7 +3613,7 @@ async function Bn() {
3585
3613
  a?.retry();
3586
3614
  break;
3587
3615
  case "oddin:load":
3588
- typeof e.matchUrn == "string" && Ln.test(e.matchUrn) && s(e.matchUrn);
3616
+ typeof e.matchUrn == "string" && zn.test(e.matchUrn) && s(e.matchUrn);
3589
3617
  break;
3590
3618
  case "oddin:destroy": c();
3591
3619
  }
@@ -3597,18 +3625,18 @@ async function Bn() {
3597
3625
  protocol: 1
3598
3626
  });
3599
3627
  }
3600
- function Vn(e, t) {
3628
+ function Un(e, t) {
3601
3629
  if (document.getElementById("havik-tap")) return;
3602
3630
  let n = document.createElement("button");
3603
3631
  n.id = "havik-tap", n.textContent = "▶ Tap to play", n.style.cssText = "position:fixed;inset:0;width:100%;height:100%;border:0;background:rgba(0,0,0,.55);color:#fff;font:600 18px system-ui,sans-serif;cursor:pointer;z-index:9", n.addEventListener("click", () => {
3604
3632
  n.remove(), t.play();
3605
3633
  }), document.body.appendChild(n);
3606
3634
  }
3607
- function Hn() {
3635
+ function Wn() {
3608
3636
  let e = document.createElement("style");
3609
3637
  e.textContent = "html,body{margin:0;height:100%;background:#000;overflow:hidden}body{display:flex}", document.head.appendChild(e);
3610
3638
  }
3611
3639
  //#endregion
3612
- export { dn as ODDIN_THEME, n as PlaybackError, pn as applyTheme, B as baseUrlForEnv, Bn as bootEmbed, we as clearDeviceId, Pn as createPlayer, D as deriveEventsBaseUrl, Ve as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ge as fetchCatalog, ve as fetchTournament, be as flattenMatches, A as getDeviceId, Ue as isLowLatencyManifest, $ as isOddinMessage, Ee as licenseRequestHeaders, In as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, Se as watchStatus };
3640
+ export { pn as ODDIN_THEME, n as PlaybackError, hn as applyTheme, B as baseUrlForEnv, Hn as bootEmbed, we as clearDeviceId, In as createPlayer, D as deriveEventsBaseUrl, Ve as detectDrmSupport, w as enterVideoFullscreen, T as exitVideoFullscreen, ge as fetchCatalog, ve as fetchTournament, be as flattenMatches, A as getDeviceId, Ue as isLowLatencyManifest, $ as isOddinMessage, Ee as licenseRequestHeaders, Rn as mountEmbed, v as pollToLive, b as resolveStream, E as subscribeLiveState, C as videoFullscreenActive, Se as watchStatus };
3613
3641
 
3614
3642
  //# sourceMappingURL=index.js.map