stormcloud-video-player 0.2.14 → 0.2.16

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/lib/index.cjs CHANGED
@@ -917,7 +917,7 @@ function createHlsAdPlayer(contentVideo, options) {
917
917
  const xmlDoc = parser.parseFromString(xmlString, "text/xml");
918
918
  const parserError = xmlDoc.querySelector("parsererror");
919
919
  if (parserError) {
920
- console.error("[HlsAdPlayer] XML parsing error:", parserError.textContent);
920
+ console.error("[HlsAdPlayer] XML parsing error (malformed VAST XML):", parserError.textContent);
921
921
  return null;
922
922
  }
923
923
  const adElement = xmlDoc.querySelector("Ad");
@@ -927,28 +927,45 @@ function createHlsAdPlayer(contentVideo, options) {
927
927
  }
928
928
  const adId = adElement.getAttribute("id") || "unknown";
929
929
  const title = ((_a = xmlDoc.querySelector("AdTitle")) == null ? void 0 : _a.textContent) || "Ad";
930
+ const isNoAdAvailable = adId === "empty" || title.toLowerCase().includes("no ad available") || title.toLowerCase() === "no ad available";
930
931
  const durationText = ((_b = xmlDoc.querySelector("Duration")) == null ? void 0 : _b.textContent) || "00:00:30";
931
932
  const durationParts = durationText.split(":");
932
933
  const duration = parseInt(durationParts[0] || "0", 10) * 3600 + parseInt(durationParts[1] || "0", 10) * 60 + parseInt(durationParts[2] || "0", 10);
933
934
  const mediaFileElements = xmlDoc.querySelectorAll("MediaFile");
934
935
  const mediaFiles = [];
935
- mediaFileElements.forEach((mf) => {
936
+ console.log(`[HlsAdPlayer] Found ${mediaFileElements.length} MediaFile element(s) in VAST XML`);
937
+ mediaFileElements.forEach((mf, index) => {
936
938
  var _a2;
937
939
  const type = mf.getAttribute("type") || "";
940
+ const url = ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "";
941
+ const width = mf.getAttribute("width") || "";
942
+ const height = mf.getAttribute("height") || "";
943
+ console.log(`[HlsAdPlayer] MediaFile ${index}: type="${type}", url="${url}", width="${width}", height="${height}"`);
938
944
  if (type === "application/x-mpegURL" || type.includes("m3u8")) {
945
+ if (!url) {
946
+ console.warn(`[HlsAdPlayer] MediaFile ${index} has HLS type but empty URL`);
947
+ return;
948
+ }
939
949
  const bitrateAttr = mf.getAttribute("bitrate");
940
950
  const bitrateValue = bitrateAttr ? parseInt(bitrateAttr, 10) : void 0;
941
951
  mediaFiles.push({
942
- url: ((_a2 = mf.textContent) == null ? void 0 : _a2.trim()) || "",
952
+ url,
943
953
  type,
944
- width: parseInt(mf.getAttribute("width") || "1920", 10),
945
- height: parseInt(mf.getAttribute("height") || "1080", 10),
954
+ width: parseInt(width || "1920", 10),
955
+ height: parseInt(height || "1080", 10),
946
956
  bitrate: bitrateValue && bitrateValue > 0 ? bitrateValue : void 0
947
957
  });
958
+ console.log(`[HlsAdPlayer] Added HLS MediaFile: ${url}`);
959
+ } else {
960
+ console.log(`[HlsAdPlayer] MediaFile ${index} ignored (type="${type}" is not HLS)`);
948
961
  }
949
962
  });
950
963
  if (mediaFiles.length === 0) {
951
- console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
964
+ if (isNoAdAvailable) {
965
+ console.warn("[HlsAdPlayer] No ads available (VAST response indicates no ads)");
966
+ } else {
967
+ console.warn("[HlsAdPlayer] No HLS media files found in VAST XML");
968
+ }
952
969
  return null;
953
970
  }
954
971
  const trackingUrls = {
@@ -1136,9 +1153,11 @@ function createHlsAdPlayer(contentVideo, options) {
1136
1153
  }
1137
1154
  const vastXml = await response.text();
1138
1155
  console.log("[HlsAdPlayer] VAST XML received");
1156
+ console.log("[HlsAdPlayer] VAST XML content (first 2000 chars):", vastXml.substring(0, 2e3));
1139
1157
  const ad = parseVastXml(vastXml);
1140
1158
  if (!ad) {
1141
- throw new Error("Failed to parse VAST XML or no ads available");
1159
+ console.warn("[HlsAdPlayer] No ads available from VAST response");
1160
+ return Promise.resolve();
1142
1161
  }
1143
1162
  currentAd = ad;
1144
1163
  console.log(`[HlsAdPlayer] Ad parsed: ${ad.title}, duration: ${ad.duration}s`);
@@ -1153,7 +1172,7 @@ function createHlsAdPlayer(contentVideo, options) {
1153
1172
  },
1154
1173
  async play() {
1155
1174
  if (!currentAd) {
1156
- console.warn("[HlsAdPlayer] Cannot play: No ad loaded");
1175
+ console.warn("[HlsAdPlayer] Cannot play: No ad loaded (no ads available)");
1157
1176
  return Promise.reject(new Error("No ad loaded"));
1158
1177
  }
1159
1178
  console.log("[HlsAdPlayer] Starting ad playback");
@@ -1784,6 +1803,8 @@ var StormcloudVideoPlayer = class {
1784
1803
  this.totalAdsInBreak = 0;
1785
1804
  this.showAds = false;
1786
1805
  this.isLiveStream = false;
1806
+ this.nativeHlsMode = false;
1807
+ this.videoSrcProtection = null;
1787
1808
  initializePolyfills();
1788
1809
  const browserOverrides = getBrowserConfigOverrides();
1789
1810
  this.config = { ...config, ...browserOverrides };
@@ -1804,7 +1825,9 @@ var StormcloudVideoPlayer = class {
1804
1825
  }
1805
1826
  if (adPlayerType === "hls") {
1806
1827
  if (this.config.debugAdTiming) {
1807
- console.log("[StormcloudVideoPlayer] Creating HLS ad player (AdStorm mode)");
1828
+ console.log(
1829
+ "[StormcloudVideoPlayer] Creating HLS ad player (AdStorm mode)"
1830
+ );
1808
1831
  }
1809
1832
  return createHlsAdPlayer(this.video, {
1810
1833
  continueLiveStreamDuringAds,
@@ -1813,7 +1836,9 @@ var StormcloudVideoPlayer = class {
1813
1836
  });
1814
1837
  } else {
1815
1838
  if (this.config.debugAdTiming) {
1816
- console.log("[StormcloudVideoPlayer] Creating Google IMA ad player (Default mode)");
1839
+ console.log(
1840
+ "[StormcloudVideoPlayer] Creating Google IMA ad player (Default mode)"
1841
+ );
1817
1842
  }
1818
1843
  return createImaController(this.video, {
1819
1844
  continueLiveStreamDuringAds
@@ -1837,11 +1862,13 @@ var StormcloudVideoPlayer = class {
1837
1862
  }
1838
1863
  this.initializeTracking();
1839
1864
  if (this.shouldUseNativeHls()) {
1865
+ this.nativeHlsMode = true;
1866
+ this.videoSrcProtection = this.config.src;
1840
1867
  this.video.src = this.config.src;
1841
1868
  this.isLiveStream = (_a = this.config.lowLatencyMode) != null ? _a : false;
1842
1869
  if (this.config.debugAdTiming) {
1843
1870
  console.log(
1844
- "[StormcloudVideoPlayer] allowNativeHls: true - VOD mode detected:",
1871
+ "[StormcloudVideoPlayer] Using native HLS playback - VOD mode:",
1845
1872
  {
1846
1873
  isLive: this.isLiveStream,
1847
1874
  allowNativeHls: this.config.allowNativeHls,
@@ -1989,7 +2016,9 @@ var StormcloudVideoPlayer = class {
1989
2016
  this.ima.initialize();
1990
2017
  this.ima.on("all_ads_completed", () => {
1991
2018
  if (this.config.debugAdTiming) {
1992
- console.log("[StormcloudVideoPlayer] IMA all_ads_completed event received");
2019
+ console.log(
2020
+ "[StormcloudVideoPlayer] IMA all_ads_completed event received"
2021
+ );
1993
2022
  }
1994
2023
  });
1995
2024
  this.ima.on("ad_error", () => {
@@ -2054,13 +2083,31 @@ var StormcloudVideoPlayer = class {
2054
2083
  this.video.addEventListener("timeupdate", () => {
2055
2084
  this.onTimeUpdate(this.video.currentTime);
2056
2085
  });
2086
+ this.video.addEventListener("emptied", () => {
2087
+ if (this.nativeHlsMode && this.videoSrcProtection && !this.ima.isAdPlaying()) {
2088
+ if (this.config.debugAdTiming) {
2089
+ console.log(
2090
+ "[StormcloudVideoPlayer] Video src was cleared, restoring:",
2091
+ this.videoSrcProtection
2092
+ );
2093
+ }
2094
+ const currentTime = this.video.currentTime;
2095
+ const wasPaused = this.video.paused;
2096
+ this.video.src = this.videoSrcProtection;
2097
+ this.video.currentTime = currentTime;
2098
+ if (!wasPaused) {
2099
+ this.video.play().catch(() => {
2100
+ });
2101
+ }
2102
+ }
2103
+ });
2057
2104
  }
2058
2105
  shouldUseNativeHls() {
2059
2106
  const streamType = this.getStreamType();
2060
2107
  if (streamType === "other") {
2061
2108
  return true;
2062
2109
  }
2063
- const canNative = this.video.canPlayType("application/vnd.apple.mpegURL");
2110
+ const canNative = this.video.canPlayType("application/vnd.apple.mpegurl");
2064
2111
  return !!(this.config.allowNativeHls && canNative);
2065
2112
  }
2066
2113
  onId3Tag(tag) {
@@ -2487,10 +2534,7 @@ var StormcloudVideoPlayer = class {
2487
2534
  var _a, _b, _c;
2488
2535
  const vastMode = this.config.vastMode || "default";
2489
2536
  if (this.config.debugAdTiming) {
2490
- console.log(
2491
- "[StormcloudVideoPlayer] VAST mode:",
2492
- vastMode
2493
- );
2537
+ console.log("[StormcloudVideoPlayer] VAST mode:", vastMode);
2494
2538
  }
2495
2539
  if (vastMode === "adstorm") {
2496
2540
  if (!this.config.licenseKey) {
@@ -2505,7 +2549,7 @@ var StormcloudVideoPlayer = class {
2505
2549
  this.apiVastTagUrl = vastEndpoint;
2506
2550
  if (this.config.debugAdTiming) {
2507
2551
  console.log(
2508
- "[StormcloudVideoPlayer] Using AdStorm VAST endpoint:",
2552
+ "[StormcloudVideoPlayer] Using AdStorm VAST endpoint (adstorm mode):",
2509
2553
  vastEndpoint
2510
2554
  );
2511
2555
  }
@@ -2608,10 +2652,7 @@ var StormcloudVideoPlayer = class {
2608
2652
  this.currentAdIndex = 0;
2609
2653
  this.totalAdsInBreak = 1;
2610
2654
  if (this.config.debugAdTiming) {
2611
- console.log(
2612
- "[StormcloudVideoPlayer] Using VAST endpoint:",
2613
- vastTagUrl
2614
- );
2655
+ console.log("[StormcloudVideoPlayer] Using VAST endpoint:", vastTagUrl);
2615
2656
  }
2616
2657
  } else if (tags && tags.length > 0) {
2617
2658
  vastTagUrl = tags[0];
@@ -2761,12 +2802,26 @@ var StormcloudVideoPlayer = class {
2761
2802
  this.startAdFailsafeTimer();
2762
2803
  try {
2763
2804
  await this.ima.requestAds(vastTagUrl);
2764
- if (this.config.debugAdTiming) {
2765
- console.log("[StormcloudVideoPlayer] Ad request successful, starting playback");
2766
- }
2767
- await this.ima.play();
2768
- if (this.config.debugAdTiming) {
2769
- console.log("[StormcloudVideoPlayer] Ad playback started successfully");
2805
+ try {
2806
+ if (this.config.debugAdTiming) {
2807
+ console.log(
2808
+ "[StormcloudVideoPlayer] Ad request completed, attempting playback"
2809
+ );
2810
+ }
2811
+ await this.ima.play();
2812
+ if (this.config.debugAdTiming) {
2813
+ console.log(
2814
+ "[StormcloudVideoPlayer] Ad playback started successfully"
2815
+ );
2816
+ }
2817
+ } catch (playError) {
2818
+ if (this.config.debugAdTiming) {
2819
+ console.log(
2820
+ "[StormcloudVideoPlayer] No ads available, skipping playback"
2821
+ );
2822
+ }
2823
+ this.handleAdFailure();
2824
+ return;
2770
2825
  }
2771
2826
  } catch (error) {
2772
2827
  if (this.config.debugAdTiming) {
@@ -2819,7 +2874,9 @@ var StormcloudVideoPlayer = class {
2819
2874
  });
2820
2875
  } else {
2821
2876
  if (this.config.debugAdTiming) {
2822
- console.log("[StormcloudVideoPlayer] Video is already playing, no resume needed");
2877
+ console.log(
2878
+ "[StormcloudVideoPlayer] Video is already playing, no resume needed"
2879
+ );
2823
2880
  }
2824
2881
  }
2825
2882
  }
@@ -2838,7 +2895,11 @@ var StormcloudVideoPlayer = class {
2838
2895
  if (this.config.debugAdTiming) {
2839
2896
  console.warn(
2840
2897
  "[StormcloudVideoPlayer] Failsafe timer triggered - forcing video resume",
2841
- { paused: this.video.paused, showAds: this.showAds, adPlaying: this.ima.isAdPlaying() }
2898
+ {
2899
+ paused: this.video.paused,
2900
+ showAds: this.showAds,
2901
+ adPlaying: this.ima.isAdPlaying()
2902
+ }
2842
2903
  );
2843
2904
  }
2844
2905
  this.handleAdFailure();
@@ -2983,7 +3044,8 @@ var CRITICAL_PROPS = [
2983
3044
  "allowNativeHls",
2984
3045
  "licenseKey",
2985
3046
  "lowLatencyMode",
2986
- "driftToleranceMs"
3047
+ "driftToleranceMs",
3048
+ "vastMode"
2987
3049
  ];
2988
3050
  var StormcloudVideoPlayerComponent = import_react.default.memo(
2989
3051
  (props) => {
@@ -3011,6 +3073,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3011
3073
  poster,
3012
3074
  children,
3013
3075
  licenseKey,
3076
+ vastMode,
3077
+ vastTagUrl,
3078
+ adPlayerType,
3014
3079
  ...restVideoAttrs
3015
3080
  } = props;
3016
3081
  const videoRef = (0, import_react.useRef)(null);
@@ -3030,6 +3095,19 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3030
3095
  const [isBuffering, setIsBuffering] = import_react.default.useState(false);
3031
3096
  const [showCenterPlay, setShowCenterPlay] = import_react.default.useState(false);
3032
3097
  const [showLicenseWarning, setShowLicenseWarning] = import_react.default.useState(false);
3098
+ const [viewportWidth, setViewportWidth] = import_react.default.useState(
3099
+ typeof window !== "undefined" ? window.innerWidth : 1920
3100
+ );
3101
+ const [isPortrait, setIsPortrait] = import_react.default.useState(
3102
+ typeof window !== "undefined" ? window.innerHeight > window.innerWidth : false
3103
+ );
3104
+ const getResponsiveScale = () => {
3105
+ if (viewportWidth < 480) return 0.7;
3106
+ if (viewportWidth < 768) return 0.8;
3107
+ if (viewportWidth < 1024) return 0.9;
3108
+ return 1;
3109
+ };
3110
+ const responsiveScale = getResponsiveScale();
3033
3111
  const formatTime = (seconds) => {
3034
3112
  if (!isFinite(seconds)) return "0:00:00";
3035
3113
  const hours = Math.floor(seconds / 3600);
@@ -3038,10 +3116,20 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3038
3116
  return `${hours}:${minutes.toString().padStart(2, "0")}:${remainingSeconds.toString().padStart(2, "0")}`;
3039
3117
  };
3040
3118
  const handlePlayPause = () => {
3119
+ var _a;
3041
3120
  if (videoRef.current) {
3042
3121
  if (videoRef.current.paused) {
3043
- videoRef.current.play();
3044
- setShowCenterPlay(false);
3122
+ const hasValidSource = videoRef.current.src || videoRef.current.currentSrc && videoRef.current.currentSrc !== "" || videoRef.current.readyState >= 1;
3123
+ if (hasValidSource) {
3124
+ (_a = videoRef.current.play()) == null ? void 0 : _a.catch((error) => {
3125
+ console.error("[StormcloudVideoPlayer] Failed to play:", error);
3126
+ });
3127
+ setShowCenterPlay(false);
3128
+ } else {
3129
+ console.warn(
3130
+ "[StormcloudVideoPlayer] Cannot play: video has no valid source"
3131
+ );
3132
+ }
3045
3133
  } else {
3046
3134
  videoRef.current.pause();
3047
3135
  setShowCenterPlay(true);
@@ -3049,9 +3137,19 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3049
3137
  }
3050
3138
  };
3051
3139
  const handleCenterPlayClick = () => {
3140
+ var _a;
3052
3141
  if (videoRef.current && videoRef.current.paused) {
3053
- videoRef.current.play();
3054
- setShowCenterPlay(false);
3142
+ const hasValidSource = videoRef.current.src || videoRef.current.currentSrc && videoRef.current.currentSrc !== "" || videoRef.current.readyState >= 1;
3143
+ if (hasValidSource) {
3144
+ (_a = videoRef.current.play()) == null ? void 0 : _a.catch((error) => {
3145
+ console.error("[StormcloudVideoPlayer] Failed to play:", error);
3146
+ });
3147
+ setShowCenterPlay(false);
3148
+ } else {
3149
+ console.warn(
3150
+ "[StormcloudVideoPlayer] Cannot play: video has no valid source"
3151
+ );
3152
+ }
3055
3153
  }
3056
3154
  };
3057
3155
  const handleTimelineSeek = (e) => {
@@ -3082,7 +3180,14 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3082
3180
  const shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
3083
3181
  const criticalPropsKey = (0, import_react.useMemo)(() => {
3084
3182
  return CRITICAL_PROPS.map((prop) => `${prop}:${props[prop]}`).join("|");
3085
- }, [src, allowNativeHls, licenseKey, lowLatencyMode, driftToleranceMs]);
3183
+ }, [
3184
+ src,
3185
+ allowNativeHls,
3186
+ licenseKey,
3187
+ lowLatencyMode,
3188
+ driftToleranceMs,
3189
+ vastMode
3190
+ ]);
3086
3191
  (0, import_react.useEffect)(() => {
3087
3192
  if (typeof window === "undefined") return;
3088
3193
  const el = videoRef.current;
@@ -3123,6 +3228,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3123
3228
  cfg.onFullscreenToggle = onFullscreenToggle;
3124
3229
  if (onControlClick !== void 0) cfg.onControlClick = onControlClick;
3125
3230
  if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
3231
+ if (vastMode !== void 0) cfg.vastMode = vastMode;
3232
+ if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
3233
+ if (adPlayerType !== void 0) cfg.adPlayerType = adPlayerType;
3126
3234
  const player = new StormcloudVideoPlayer(cfg);
3127
3235
  playerRef.current = player;
3128
3236
  player.load().then(() => {
@@ -3183,6 +3291,8 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3183
3291
  playerRef.current.resize();
3184
3292
  }
3185
3293
  }
3294
+ setViewportWidth(window.innerWidth);
3295
+ setIsPortrait(window.innerHeight > window.innerWidth);
3186
3296
  };
3187
3297
  window.addEventListener("resize", handleResize);
3188
3298
  return () => window.removeEventListener("resize", handleResize);
@@ -3499,14 +3609,14 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3499
3609
  },
3500
3610
  onMouseEnter: (e) => {
3501
3611
  const target = e.currentTarget;
3502
- target.style.transform = "translate(-50%, -50%) scale(1.1)";
3612
+ target.style.transform = "translate(-50%, -50%)";
3503
3613
  target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.95) 0%, rgba(40, 40, 40, 0.9) 100%)";
3504
3614
  target.style.boxShadow = "0 16px 48px rgba(0, 0, 0, 0.9), inset 0 2px 0 rgba(255, 255, 255, 0.4)";
3505
3615
  target.style.borderColor = "rgba(255, 255, 255, 0.9)";
3506
3616
  },
3507
3617
  onMouseLeave: (e) => {
3508
3618
  const target = e.currentTarget;
3509
- target.style.transform = "translate(-50%, -50%) scale(1)";
3619
+ target.style.transform = "translate(-50%, -50%)";
3510
3620
  target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.9) 0%, rgba(20, 20, 20, 0.8) 100%)";
3511
3621
  target.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.8), inset 0 2px 0 rgba(255, 255, 255, 0.3)";
3512
3622
  target.style.borderColor = "rgba(255, 255, 255, 0.8)";
@@ -3596,7 +3706,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3596
3706
  display: "flex",
3597
3707
  alignItems: "center",
3598
3708
  justifyContent: "space-between",
3599
- color: "white"
3709
+ color: "white",
3710
+ flexWrap: viewportWidth < 768 ? "wrap" : "nowrap",
3711
+ gap: `${8 * responsiveScale}px`
3600
3712
  },
3601
3713
  children: [
3602
3714
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
@@ -3605,7 +3717,8 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3605
3717
  style: {
3606
3718
  display: "flex",
3607
3719
  alignItems: "center",
3608
- gap: "12px"
3720
+ gap: `${12 * responsiveScale}px`,
3721
+ flexWrap: viewportWidth < 480 ? "wrap" : "nowrap"
3609
3722
  },
3610
3723
  children: [
3611
3724
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -3613,44 +3726,42 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3613
3726
  {
3614
3727
  onClick: handlePlayPause,
3615
3728
  style: {
3616
- background: "linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.05) 100%)",
3617
- backdropFilter: "blur(10px)",
3618
- border: "1px solid rgba(255, 255, 255, 0.2)",
3729
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.65) 100%)",
3730
+ backdropFilter: "blur(12px)",
3731
+ border: `${2 * responsiveScale}px solid rgba(255, 255, 255, 0.3)`,
3619
3732
  color: "#ffffff",
3620
3733
  cursor: "pointer",
3621
- padding: "12px",
3622
- borderRadius: "12px",
3734
+ padding: `${10 * responsiveScale}px`,
3735
+ borderRadius: `${16 * responsiveScale}px`,
3623
3736
  display: "flex",
3624
3737
  alignItems: "center",
3625
3738
  justifyContent: "center",
3626
3739
  transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
3627
- boxShadow: "0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2)",
3628
- minWidth: "48px",
3629
- minHeight: "48px"
3740
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.3)",
3741
+ minWidth: `${48 * responsiveScale}px`,
3742
+ minHeight: `${48 * responsiveScale}px`
3630
3743
  },
3631
3744
  onMouseEnter: (e) => {
3632
3745
  const target = e.target;
3633
- target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.25) 0%, rgba(255, 255, 255, 0.1) 100%)";
3634
- target.style.transform = "translateY(-2px) scale(1.05)";
3635
- target.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.3)";
3746
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.75) 100%)";
3747
+ target.style.boxShadow = "0 12px 48px rgba(0, 0, 0, 0.6), 0 6px 24px rgba(0, 0, 0, 0.4), inset 0 2px 0 rgba(255, 255, 255, 0.4)";
3636
3748
  },
3637
3749
  onMouseLeave: (e) => {
3638
3750
  const target = e.target;
3639
- target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.05) 100%)";
3640
- target.style.transform = "translateY(0) scale(1)";
3641
- target.style.boxShadow = "0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.2)";
3751
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.65) 100%)";
3752
+ target.style.boxShadow = "0 8px 32px rgba(0, 0, 0, 0.4), 0 4px 16px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.3)";
3642
3753
  },
3643
3754
  title: isPlaying ? "Pause" : "Play",
3644
3755
  children: isPlaying ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3645
3756
  import_fa.FaPause,
3646
3757
  {
3647
- size: 20,
3758
+ size: Math.max(16, 20 * responsiveScale),
3648
3759
  style: { filter: "drop-shadow(0 0 0 transparent)" }
3649
3760
  }
3650
3761
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3651
3762
  import_fa.FaPlay,
3652
3763
  {
3653
- size: 20,
3764
+ size: Math.max(16, 20 * responsiveScale),
3654
3765
  style: { filter: "drop-shadow(0 0 0 transparent)" }
3655
3766
  }
3656
3767
  )
@@ -3673,45 +3784,44 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3673
3784
  "button",
3674
3785
  {
3675
3786
  onClick: () => {
3787
+ if (playerRef.current) {
3788
+ playerRef.current.toggleMute();
3789
+ }
3676
3790
  if (onVolumeToggle) {
3677
3791
  onVolumeToggle();
3678
- } else if (playerRef.current) {
3679
- playerRef.current.toggleMute();
3680
3792
  }
3681
3793
  },
3682
3794
  style: {
3683
- background: "linear-gradient(135deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.04) 100%)",
3684
- backdropFilter: "blur(8px)",
3685
- border: "1px solid rgba(255, 255, 255, 0.15)",
3686
- color: isMuted ? "#ff6b6b" : "#ffffff",
3795
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.6) 100%)",
3796
+ backdropFilter: "blur(10px)",
3797
+ border: `${2 * responsiveScale}px solid rgba(255, 255, 255, 0.3)`,
3798
+ color: "#ffffff",
3687
3799
  cursor: "pointer",
3688
- padding: "10px",
3689
- borderRadius: "10px",
3800
+ padding: `${8 * responsiveScale}px`,
3801
+ borderRadius: `${16 * responsiveScale}px`,
3690
3802
  display: "flex",
3691
3803
  alignItems: "center",
3692
3804
  justifyContent: "center",
3693
3805
  transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
3694
- boxShadow: "0 6px 24px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.1)",
3695
- minWidth: "40px",
3696
- minHeight: "40px"
3806
+ boxShadow: "0 6px 28px rgba(0, 0, 0, 0.4), 0 3px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.25)",
3807
+ minWidth: `${44 * responsiveScale}px`,
3808
+ minHeight: `${44 * responsiveScale}px`
3697
3809
  },
3698
3810
  onMouseEnter: (e) => {
3699
3811
  const target = e.target;
3700
- target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.08) 100%)";
3701
- target.style.transform = "translateY(-1px) scale(1.03)";
3702
- target.style.boxShadow = "0 8px 28px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.2)";
3812
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.7) 100%)";
3813
+ target.style.boxShadow = "0 10px 36px rgba(0, 0, 0, 0.6), 0 5px 16px rgba(0, 0, 0, 0.4), inset 0 2px 0 rgba(255, 255, 255, 0.35)";
3703
3814
  },
3704
3815
  onMouseLeave: (e) => {
3705
3816
  const target = e.target;
3706
- target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.04) 100%)";
3707
- target.style.transform = "translateY(0) scale(1)";
3708
- target.style.boxShadow = "0 6px 24px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.1)";
3817
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.6) 100%)";
3818
+ target.style.boxShadow = "0 6px 28px rgba(0, 0, 0, 0.4), 0 3px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.25)";
3709
3819
  },
3710
3820
  title: isMuted ? "Unmute" : "Mute",
3711
3821
  children: isMuted || volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3712
3822
  import_fa.FaVolumeMute,
3713
3823
  {
3714
- size: 16,
3824
+ size: Math.max(14, 16 * responsiveScale),
3715
3825
  style: {
3716
3826
  filter: "drop-shadow(0 0 0 transparent)"
3717
3827
  }
@@ -3719,7 +3829,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3719
3829
  ) : volume < 0.5 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3720
3830
  import_fa.FaVolumeDown,
3721
3831
  {
3722
- size: 16,
3832
+ size: Math.max(14, 16 * responsiveScale),
3723
3833
  style: {
3724
3834
  filter: "drop-shadow(0 0 0 transparent)"
3725
3835
  }
@@ -3727,7 +3837,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3727
3837
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3728
3838
  import_fa.FaVolumeUp,
3729
3839
  {
3730
- size: 16,
3840
+ size: Math.max(14, 16 * responsiveScale),
3731
3841
  style: {
3732
3842
  filter: "drop-shadow(0 0 0 transparent)"
3733
3843
  }
@@ -3778,13 +3888,11 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3778
3888
  },
3779
3889
  onMouseEnter: (e) => {
3780
3890
  setShowVolumeSlider(true);
3781
- e.currentTarget.style.transform = "translateX(-50%) translateY(-2px) scale(1.02)";
3782
3891
  e.currentTarget.style.boxShadow = "0 16px 48px rgba(0, 0, 0, 0.6), 0 6px 16px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 0 24px rgba(59, 130, 246, 0.3)";
3783
3892
  e.currentTarget.style.borderColor = "rgba(59, 130, 246, 0.4)";
3784
3893
  },
3785
3894
  onMouseLeave: (e) => {
3786
3895
  setShowVolumeSlider(false);
3787
- e.currentTarget.style.transform = "translateX(-50%)";
3788
3896
  e.currentTarget.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.15)";
3789
3897
  e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.15)";
3790
3898
  },
@@ -3799,10 +3907,8 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3799
3907
  transition: "transform 0.2s ease-in-out"
3800
3908
  },
3801
3909
  onMouseEnter: (e) => {
3802
- e.currentTarget.style.transform = "scaleX(1.2)";
3803
3910
  },
3804
3911
  onMouseLeave: (e) => {
3805
- e.currentTarget.style.transform = "scaleX(1)";
3806
3912
  },
3807
3913
  onMouseDown: (e) => {
3808
3914
  e.preventDefault();
@@ -3815,11 +3921,23 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3815
3921
  handleVolumeChange(percentage2);
3816
3922
  };
3817
3923
  const handleMouseUp = () => {
3818
- document.removeEventListener("mousemove", handleMouseMove);
3819
- document.removeEventListener("mouseup", handleMouseUp);
3924
+ document.removeEventListener(
3925
+ "mousemove",
3926
+ handleMouseMove
3927
+ );
3928
+ document.removeEventListener(
3929
+ "mouseup",
3930
+ handleMouseUp
3931
+ );
3820
3932
  };
3821
- document.addEventListener("mousemove", handleMouseMove);
3822
- document.addEventListener("mouseup", handleMouseUp);
3933
+ document.addEventListener(
3934
+ "mousemove",
3935
+ handleMouseMove
3936
+ );
3937
+ document.addEventListener(
3938
+ "mouseup",
3939
+ handleMouseUp
3940
+ );
3823
3941
  const rect = sliderElement.getBoundingClientRect();
3824
3942
  const y = e.clientY - rect.top;
3825
3943
  const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
@@ -3881,20 +3999,16 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3881
3999
  cursor: "grab"
3882
4000
  },
3883
4001
  onMouseEnter: (e) => {
3884
- e.currentTarget.style.transform = "translateX(-50%) scale(1.3)";
3885
4002
  e.currentTarget.style.boxShadow = "0 3px 10px rgba(0, 0, 0, 0.4), 0 0 0 3px rgba(59, 130, 246, 0.5), 0 0 20px rgba(59, 130, 246, 0.6)";
3886
4003
  e.currentTarget.style.cursor = "grab";
3887
4004
  },
3888
4005
  onMouseLeave: (e) => {
3889
- e.currentTarget.style.transform = "translateX(-50%) scale(1)";
3890
4006
  e.currentTarget.style.boxShadow = "0 2px 6px rgba(0, 0, 0, 0.3), 0 0 0 2px rgba(59, 130, 246, 0.3), 0 0 12px rgba(59, 130, 246, 0.4)";
3891
4007
  },
3892
4008
  onMouseDown: (e) => {
3893
- e.currentTarget.style.transform = "translateX(-50%) scale(1.4)";
3894
4009
  e.currentTarget.style.cursor = "grabbing";
3895
4010
  },
3896
4011
  onMouseUp: (e) => {
3897
- e.currentTarget.style.transform = "translateX(-50%) scale(1.3)";
3898
4012
  e.currentTarget.style.cursor = "grab";
3899
4013
  }
3900
4014
  }
@@ -3912,9 +4026,10 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3912
4026
  "div",
3913
4027
  {
3914
4028
  style: {
3915
- fontSize: "14px",
4029
+ fontSize: `${14 * responsiveScale}px`,
3916
4030
  fontFamily: "monospace",
3917
- color: "rgba(255, 255, 255, 0.9)"
4031
+ color: "rgba(255, 255, 255, 0.9)",
4032
+ display: viewportWidth < 480 ? "none" : "block"
3918
4033
  },
3919
4034
  children: [
3920
4035
  formatTime(currentTime),
@@ -3932,105 +4047,113 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3932
4047
  style: {
3933
4048
  display: "flex",
3934
4049
  alignItems: "center",
3935
- gap: "12px"
4050
+ gap: `${12 * responsiveScale}px`
3936
4051
  },
3937
4052
  children: [
3938
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative" }, children: [
3939
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
3940
- "button",
3941
- {
3942
- onClick: () => setShowSpeedMenu(!showSpeedMenu),
3943
- style: {
3944
- background: "linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.03) 100%)",
3945
- backdropFilter: "blur(8px)",
3946
- border: "1px solid rgba(255, 255, 255, 0.12)",
3947
- color: "#ffffff",
3948
- cursor: "pointer",
3949
- padding: "8px 14px",
3950
- borderRadius: "8px",
3951
- fontSize: "13px",
3952
- fontFamily: "monospace",
3953
- fontWeight: "600",
3954
- transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
3955
- boxShadow: "0 4px 16px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08)",
3956
- minWidth: "50px"
3957
- },
3958
- onMouseEnter: (e) => {
3959
- const target = e.target;
3960
- target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0.06) 100%)";
3961
- target.style.transform = "translateY(-1px) scale(1.02)";
3962
- target.style.boxShadow = "0 6px 20px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.15)";
3963
- },
3964
- onMouseLeave: (e) => {
3965
- const target = e.target;
3966
- target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.03) 100%)";
3967
- target.style.transform = "translateY(0) scale(1)";
3968
- target.style.boxShadow = "0 4px 16px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.08)";
3969
- },
3970
- title: "Playback Speed",
3971
- children: [
3972
- playbackRate,
3973
- "x"
3974
- ]
3975
- }
3976
- ),
3977
- showSpeedMenu && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3978
- "div",
3979
- {
3980
- style: {
3981
- position: "absolute",
3982
- bottom: "100%",
3983
- right: 0,
3984
- marginBottom: "12px",
3985
- background: "linear-gradient(135deg, rgba(0, 0, 0, 0.9) 0%, rgba(20, 20, 20, 0.95) 100%)",
3986
- backdropFilter: "blur(20px)",
3987
- borderRadius: "12px",
3988
- border: "1px solid rgba(255, 255, 255, 0.1)",
3989
- overflow: "hidden",
3990
- minWidth: "90px",
3991
- boxShadow: "0 16px 48px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.1)"
3992
- },
3993
- children: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2].map(
3994
- (speed) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
3995
- "button",
3996
- {
3997
- onClick: () => handlePlaybackRateChange(speed),
3998
- style: {
3999
- display: "block",
4000
- width: "100%",
4001
- padding: "10px 16px",
4002
- background: playbackRate === speed ? "linear-gradient(135deg, rgba(99, 102, 241, 0.8) 0%, rgba(139, 92, 246, 0.6) 100%)" : "transparent",
4003
- border: "none",
4004
- color: "white",
4005
- cursor: "pointer",
4006
- fontSize: "13px",
4007
- fontFamily: "monospace",
4008
- fontWeight: "600",
4009
- textAlign: "center",
4010
- transition: "all 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
4011
- borderBottom: speed !== 2 ? "1px solid rgba(255, 255, 255, 0.05)" : "none"
4012
- },
4013
- onMouseEnter: (e) => {
4014
- if (playbackRate !== speed) {
4015
- e.target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.05) 100%)";
4016
- }
4017
- },
4018
- onMouseLeave: (e) => {
4019
- if (playbackRate !== speed) {
4020
- e.target.style.background = "transparent";
4021
- }
4022
- },
4023
- children: [
4024
- speed,
4025
- "x"
4026
- ]
4053
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
4054
+ "div",
4055
+ {
4056
+ style: {
4057
+ position: "relative",
4058
+ display: viewportWidth < 600 ? "none" : "block"
4059
+ },
4060
+ children: [
4061
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
4062
+ "button",
4063
+ {
4064
+ onClick: () => setShowSpeedMenu(!showSpeedMenu),
4065
+ style: {
4066
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.6) 100%)",
4067
+ backdropFilter: "blur(10px)",
4068
+ border: `${2 * responsiveScale}px solid rgba(255, 255, 255, 0.3)`,
4069
+ color: "#ffffff",
4070
+ cursor: "pointer",
4071
+ padding: `${8 * responsiveScale}px ${14 * responsiveScale}px`,
4072
+ borderRadius: `${14 * responsiveScale}px`,
4073
+ fontSize: `${14 * responsiveScale}px`,
4074
+ fontFamily: "monospace",
4075
+ fontWeight: "700",
4076
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
4077
+ boxShadow: "0 6px 24px rgba(0, 0, 0, 0.4), 0 3px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.25)",
4078
+ minWidth: `${56 * responsiveScale}px`,
4079
+ minHeight: `${40 * responsiveScale}px`
4027
4080
  },
4028
- speed
4029
- )
4081
+ onMouseEnter: (e) => {
4082
+ const target = e.target;
4083
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.7) 100%)";
4084
+ target.style.boxShadow = "0 10px 32px rgba(0, 0, 0, 0.6), 0 5px 16px rgba(0, 0, 0, 0.4), inset 0 2px 0 rgba(255, 255, 255, 0.35)";
4085
+ },
4086
+ onMouseLeave: (e) => {
4087
+ const target = e.target;
4088
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.6) 100%)";
4089
+ target.style.boxShadow = "0 6px 24px rgba(0, 0, 0, 0.4), 0 3px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.25)";
4090
+ },
4091
+ title: "Playback Speed",
4092
+ children: [
4093
+ playbackRate,
4094
+ "x"
4095
+ ]
4096
+ }
4097
+ ),
4098
+ showSpeedMenu && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4099
+ "div",
4100
+ {
4101
+ style: {
4102
+ position: "absolute",
4103
+ bottom: "100%",
4104
+ right: 0,
4105
+ marginBottom: "12px",
4106
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.9) 0%, rgba(20, 20, 20, 0.95) 100%)",
4107
+ backdropFilter: "blur(20px)",
4108
+ borderRadius: "12px",
4109
+ border: "1px solid rgba(255, 255, 255, 0.1)",
4110
+ overflow: "hidden",
4111
+ minWidth: "90px",
4112
+ boxShadow: "0 16px 48px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.1)"
4113
+ },
4114
+ children: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2].map(
4115
+ (speed) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
4116
+ "button",
4117
+ {
4118
+ onClick: () => handlePlaybackRateChange(speed),
4119
+ style: {
4120
+ display: "block",
4121
+ width: "100%",
4122
+ padding: "10px 16px",
4123
+ background: playbackRate === speed ? "linear-gradient(135deg, rgba(99, 102, 241, 0.8) 0%, rgba(139, 92, 246, 0.6) 100%)" : "transparent",
4124
+ border: "none",
4125
+ color: "white",
4126
+ cursor: "pointer",
4127
+ fontSize: "13px",
4128
+ fontFamily: "monospace",
4129
+ fontWeight: "600",
4130
+ textAlign: "center",
4131
+ transition: "all 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
4132
+ borderBottom: speed !== 2 ? "1px solid rgba(255, 255, 255, 0.05)" : "none"
4133
+ },
4134
+ onMouseEnter: (e) => {
4135
+ if (playbackRate !== speed) {
4136
+ e.target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0.05) 100%)";
4137
+ }
4138
+ },
4139
+ onMouseLeave: (e) => {
4140
+ if (playbackRate !== speed) {
4141
+ e.target.style.background = "transparent";
4142
+ }
4143
+ },
4144
+ children: [
4145
+ speed,
4146
+ "x"
4147
+ ]
4148
+ },
4149
+ speed
4150
+ )
4151
+ )
4152
+ }
4030
4153
  )
4031
- }
4032
- )
4033
- ] }),
4154
+ ]
4155
+ }
4156
+ ),
4034
4157
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4035
4158
  "button",
4036
4159
  {
@@ -4044,44 +4167,42 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4044
4167
  }
4045
4168
  },
4046
4169
  style: {
4047
- background: "linear-gradient(135deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.04) 100%)",
4048
- backdropFilter: "blur(8px)",
4049
- border: "1px solid rgba(255, 255, 255, 0.15)",
4170
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.6) 100%)",
4171
+ backdropFilter: "blur(10px)",
4172
+ border: `${2 * responsiveScale}px solid rgba(255, 255, 255, 0.3)`,
4050
4173
  color: "#ffffff",
4051
4174
  cursor: "pointer",
4052
- padding: "10px",
4053
- borderRadius: "10px",
4175
+ padding: `${8 * responsiveScale}px`,
4176
+ borderRadius: `${16 * responsiveScale}px`,
4054
4177
  display: "flex",
4055
4178
  alignItems: "center",
4056
4179
  justifyContent: "center",
4057
4180
  transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
4058
- boxShadow: "0 6px 24px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.1)",
4059
- minWidth: "40px",
4060
- minHeight: "40px"
4181
+ boxShadow: "0 6px 28px rgba(0, 0, 0, 0.4), 0 3px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.25)",
4182
+ minWidth: `${44 * responsiveScale}px`,
4183
+ minHeight: `${44 * responsiveScale}px`
4061
4184
  },
4062
4185
  onMouseEnter: (e) => {
4063
4186
  const target = e.target;
4064
- target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.08) 100%)";
4065
- target.style.transform = "translateY(-1px) scale(1.03)";
4066
- target.style.boxShadow = "0 8px 28px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.2)";
4187
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0.7) 100%)";
4188
+ target.style.boxShadow = "0 10px 36px rgba(0, 0, 0, 0.6), 0 5px 16px rgba(0, 0, 0, 0.4), inset 0 2px 0 rgba(255, 255, 255, 0.35)";
4067
4189
  },
4068
4190
  onMouseLeave: (e) => {
4069
4191
  const target = e.target;
4070
- target.style.background = "linear-gradient(135deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.04) 100%)";
4071
- target.style.transform = "translateY(0) scale(1)";
4072
- target.style.boxShadow = "0 6px 24px rgba(0, 0, 0, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.1)";
4192
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0.6) 100%)";
4193
+ target.style.boxShadow = "0 6px 28px rgba(0, 0, 0, 0.4), 0 3px 12px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.25)";
4073
4194
  },
4074
4195
  title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
4075
4196
  children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4076
4197
  import_fa.FaCompress,
4077
4198
  {
4078
- size: 16,
4199
+ size: Math.max(14, 16 * responsiveScale),
4079
4200
  style: { filter: "drop-shadow(0 0 0 transparent)" }
4080
4201
  }
4081
4202
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4082
4203
  import_fa.FaExpand,
4083
4204
  {
4084
- size: 16,
4205
+ size: Math.max(14, 16 * responsiveScale),
4085
4206
  style: { filter: "drop-shadow(0 0 0 transparent)" }
4086
4207
  }
4087
4208
  )
@@ -4100,10 +4221,12 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4100
4221
  {
4101
4222
  style: {
4102
4223
  position: "absolute",
4103
- bottom: "10px",
4104
- right: "10px",
4224
+ bottom: `${10 * responsiveScale}px`,
4225
+ right: `${10 * responsiveScale}px`,
4226
+ transform: "none",
4105
4227
  display: "flex",
4106
- gap: "8px",
4228
+ flexDirection: isPortrait ? "column" : "row",
4229
+ gap: `${10 * responsiveScale}px`,
4107
4230
  zIndex: 10
4108
4231
  },
4109
4232
  children: [
@@ -4124,45 +4247,44 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4124
4247
  "button",
4125
4248
  {
4126
4249
  onClick: () => {
4250
+ if (playerRef.current) {
4251
+ playerRef.current.toggleMute();
4252
+ }
4127
4253
  if (onVolumeToggle) {
4128
4254
  onVolumeToggle();
4129
- } else if (playerRef.current) {
4130
- playerRef.current.toggleMute();
4131
4255
  }
4132
4256
  },
4133
4257
  onMouseEnter: (e) => {
4134
4258
  const target = e.currentTarget;
4135
- target.style.transform = "translateY(-3px) scale(1.08)";
4136
- target.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.8), 0 0 0 2px rgba(255, 255, 255, 0.8), inset 0 2px 0 rgba(255, 255, 255, 0.3)";
4137
- target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.9) 0%, rgba(40, 40, 40, 0.85) 100%)";
4259
+ target.style.boxShadow = "0 14px 48px rgba(0, 0, 0, 0.7), 0 0 0 3px rgba(255, 255, 255, 0.8), inset 0 2px 0 rgba(255, 255, 255, 0.4)";
4260
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.75) 100%)";
4138
4261
  },
4139
4262
  onMouseLeave: (e) => {
4140
4263
  const target = e.currentTarget;
4141
- target.style.transform = "translateY(0) scale(1)";
4142
- target.style.boxShadow = "0 8px 32px rgba(0, 0, 0, 0.7), 0 0 0 2px rgba(255, 255, 255, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2)";
4143
- target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.85) 0%, rgba(30, 30, 30, 0.8) 100%)";
4264
+ target.style.boxShadow = "0 10px 36px rgba(0, 0, 0, 0.6), 0 0 0 2px rgba(255, 255, 255, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.3)";
4265
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.65) 100%)";
4144
4266
  },
4145
4267
  style: {
4146
- background: "linear-gradient(135deg, rgba(0, 0, 0, 0.85) 0%, rgba(30, 30, 30, 0.8) 100%)",
4147
- color: isMuted ? "#ff6b6b" : "#ffffff",
4268
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.65) 100%)",
4269
+ color: "#ffffff",
4148
4270
  border: "none",
4149
- borderRadius: "16px",
4150
- padding: "10px",
4271
+ borderRadius: `${18 * responsiveScale}px`,
4272
+ padding: `${8 * responsiveScale}px`,
4151
4273
  cursor: "pointer",
4152
4274
  display: "flex",
4153
4275
  alignItems: "center",
4154
4276
  justifyContent: "center",
4155
4277
  backdropFilter: "blur(20px)",
4156
- boxShadow: "0 8px 32px rgba(0, 0, 0, 0.7), 0 0 0 2px rgba(255, 255, 255, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2)",
4278
+ boxShadow: "0 10px 36px rgba(0, 0, 0, 0.6), 0 0 0 2px rgba(255, 255, 255, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.3)",
4157
4279
  transition: "all 0.4s cubic-bezier(0.4, 0, 0.2, 1)",
4158
- minWidth: "44px",
4159
- minHeight: "44px"
4280
+ minWidth: `${46 * responsiveScale}px`,
4281
+ minHeight: `${46 * responsiveScale}px`
4160
4282
  },
4161
4283
  title: isMuted ? "Unmute" : "Mute",
4162
4284
  children: isMuted || volume === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4163
4285
  import_fa.FaVolumeMute,
4164
4286
  {
4165
- size: 16,
4287
+ size: Math.max(14, 16 * responsiveScale),
4166
4288
  style: {
4167
4289
  filter: "drop-shadow(0 2px 4px rgba(0, 0, 0, 0.8))",
4168
4290
  color: "#ffffff"
@@ -4171,7 +4293,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4171
4293
  ) : volume < 0.5 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4172
4294
  import_fa.FaVolumeDown,
4173
4295
  {
4174
- size: 16,
4296
+ size: Math.max(14, 16 * responsiveScale),
4175
4297
  style: {
4176
4298
  filter: "drop-shadow(0 2px 4px rgba(0, 0, 0, 0.8))",
4177
4299
  color: "#ffffff"
@@ -4180,7 +4302,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4180
4302
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4181
4303
  import_fa.FaVolumeUp,
4182
4304
  {
4183
- size: 16,
4305
+ size: Math.max(14, 16 * responsiveScale),
4184
4306
  style: {
4185
4307
  filter: "drop-shadow(0 2px 4px rgba(0, 0, 0, 0.8))",
4186
4308
  color: "#ffffff"
@@ -4232,13 +4354,11 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4232
4354
  },
4233
4355
  onMouseEnter: (e) => {
4234
4356
  setShowVolumeSlider(true);
4235
- e.currentTarget.style.transform = "translateX(-50%) translateY(-2px) scale(1.02)";
4236
4357
  e.currentTarget.style.boxShadow = "0 16px 48px rgba(0, 0, 0, 0.9), 0 6px 16px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 0 24px rgba(96, 165, 250, 0.4)";
4237
4358
  e.currentTarget.style.borderColor = "rgba(96, 165, 250, 0.8)";
4238
4359
  },
4239
4360
  onMouseLeave: (e) => {
4240
4361
  setShowVolumeSlider(false);
4241
- e.currentTarget.style.transform = "translateX(-50%)";
4242
4362
  e.currentTarget.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.85), 0 4px 12px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.35)";
4243
4363
  e.currentTarget.style.borderColor = "rgba(255, 255, 255, 0.7)";
4244
4364
  },
@@ -4252,12 +4372,6 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4252
4372
  cursor: "pointer",
4253
4373
  transition: "transform 0.2s ease-in-out"
4254
4374
  },
4255
- onMouseEnter: (e) => {
4256
- e.currentTarget.style.transform = "scaleX(1.2)";
4257
- },
4258
- onMouseLeave: (e) => {
4259
- e.currentTarget.style.transform = "scaleX(1)";
4260
- },
4261
4375
  onMouseDown: (e) => {
4262
4376
  e.preventDefault();
4263
4377
  const sliderElement = e.currentTarget;
@@ -4269,11 +4383,23 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4269
4383
  handleVolumeChange(percentage2);
4270
4384
  };
4271
4385
  const handleMouseUp = () => {
4272
- document.removeEventListener("mousemove", handleMouseMove);
4273
- document.removeEventListener("mouseup", handleMouseUp);
4386
+ document.removeEventListener(
4387
+ "mousemove",
4388
+ handleMouseMove
4389
+ );
4390
+ document.removeEventListener(
4391
+ "mouseup",
4392
+ handleMouseUp
4393
+ );
4274
4394
  };
4275
- document.addEventListener("mousemove", handleMouseMove);
4276
- document.addEventListener("mouseup", handleMouseUp);
4395
+ document.addEventListener(
4396
+ "mousemove",
4397
+ handleMouseMove
4398
+ );
4399
+ document.addEventListener(
4400
+ "mouseup",
4401
+ handleMouseUp
4402
+ );
4277
4403
  const rect = sliderElement.getBoundingClientRect();
4278
4404
  const y = e.clientY - rect.top;
4279
4405
  const percentage = 1 - Math.max(0, Math.min(1, y / rect.height));
@@ -4337,20 +4463,16 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4337
4463
  cursor: "grab"
4338
4464
  },
4339
4465
  onMouseEnter: (e) => {
4340
- e.currentTarget.style.transform = "translateX(-50%) scale(1.35)";
4341
4466
  e.currentTarget.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.6), 0 0 0 3px rgba(96, 165, 250, 0.6), 0 0 24px rgba(96, 165, 250, 0.7)";
4342
4467
  e.currentTarget.style.cursor = "grab";
4343
4468
  },
4344
4469
  onMouseLeave: (e) => {
4345
- e.currentTarget.style.transform = "translateX(-50%) scale(1)";
4346
4470
  e.currentTarget.style.boxShadow = "0 3px 8px rgba(0, 0, 0, 0.5), 0 0 0 2px rgba(96, 165, 250, 0.4), 0 0 16px rgba(96, 165, 250, 0.5)";
4347
4471
  },
4348
4472
  onMouseDown: (e) => {
4349
- e.currentTarget.style.transform = "translateX(-50%) scale(1.45)";
4350
4473
  e.currentTarget.style.cursor = "grabbing";
4351
4474
  },
4352
4475
  onMouseUp: (e) => {
4353
- e.currentTarget.style.transform = "translateX(-50%) scale(1.35)";
4354
4476
  e.currentTarget.style.cursor = "grab";
4355
4477
  }
4356
4478
  }
@@ -4378,37 +4500,35 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4378
4500
  },
4379
4501
  onMouseEnter: (e) => {
4380
4502
  const target = e.currentTarget;
4381
- target.style.transform = "translateY(-3px) scale(1.08)";
4382
- target.style.boxShadow = "0 12px 40px rgba(0, 0, 0, 0.8), 0 0 0 2px rgba(255, 255, 255, 0.8), inset 0 2px 0 rgba(255, 255, 255, 0.3)";
4383
- target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.9) 0%, rgba(40, 40, 40, 0.85) 100%)";
4503
+ target.style.boxShadow = "0 14px 48px rgba(0, 0, 0, 0.7), 0 0 0 3px rgba(255, 255, 255, 0.8), inset 0 2px 0 rgba(255, 255, 255, 0.4)";
4504
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.85) 0%, rgba(0, 0, 0, 0.75) 100%)";
4384
4505
  },
4385
4506
  onMouseLeave: (e) => {
4386
4507
  const target = e.currentTarget;
4387
- target.style.transform = "translateY(0) scale(1)";
4388
- target.style.boxShadow = "0 8px 32px rgba(0, 0, 0, 0.7), 0 0 0 2px rgba(255, 255, 255, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2)";
4389
- target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.85) 0%, rgba(30, 30, 30, 0.8) 100%)";
4508
+ target.style.boxShadow = "0 10px 36px rgba(0, 0, 0, 0.6), 0 0 0 2px rgba(255, 255, 255, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.3)";
4509
+ target.style.background = "linear-gradient(135deg, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.65) 100%)";
4390
4510
  },
4391
4511
  style: {
4392
- background: "linear-gradient(135deg, rgba(0, 0, 0, 0.85) 0%, rgba(30, 30, 30, 0.8) 100%)",
4512
+ background: "linear-gradient(135deg, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0.65) 100%)",
4393
4513
  color: "#ffffff",
4394
4514
  border: "none",
4395
- borderRadius: "16px",
4396
- padding: "10px",
4515
+ borderRadius: `${18 * responsiveScale}px`,
4516
+ padding: `${8 * responsiveScale}px`,
4397
4517
  cursor: "pointer",
4398
4518
  display: "flex",
4399
4519
  alignItems: "center",
4400
4520
  justifyContent: "center",
4401
4521
  backdropFilter: "blur(20px)",
4402
- boxShadow: "0 8px 32px rgba(0, 0, 0, 0.7), 0 0 0 2px rgba(255, 255, 255, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2)",
4522
+ boxShadow: "0 10px 36px rgba(0, 0, 0, 0.6), 0 0 0 2px rgba(255, 255, 255, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.3)",
4403
4523
  transition: "all 0.4s cubic-bezier(0.4, 0, 0.2, 1)",
4404
- minWidth: "44px",
4405
- minHeight: "44px"
4524
+ minWidth: `${46 * responsiveScale}px`,
4525
+ minHeight: `${46 * responsiveScale}px`
4406
4526
  },
4407
4527
  title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
4408
4528
  children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4409
4529
  import_fa.FaCompress,
4410
4530
  {
4411
- size: 16,
4531
+ size: Math.max(14, 16 * responsiveScale),
4412
4532
  style: {
4413
4533
  filter: "drop-shadow(0 2px 4px rgba(0, 0, 0, 0.8))",
4414
4534
  color: "#ffffff"
@@ -4417,7 +4537,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
4417
4537
  ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4418
4538
  import_fa.FaExpand,
4419
4539
  {
4420
- size: 16,
4540
+ size: Math.max(14, 16 * responsiveScale),
4421
4541
  style: {
4422
4542
  filter: "drop-shadow(0 2px 4px rgba(0, 0, 0, 0.8))",
4423
4543
  color: "#ffffff"
@@ -4707,10 +4827,20 @@ var HlsPlayer = class extends import_react3.Component {
4707
4827
  }
4708
4828
  };
4709
4829
  this.play = () => {
4710
- var _a, _b;
4830
+ var _a, _b, _c;
4711
4831
  if (this.props.videoElement) {
4712
- this.props.videoElement.play();
4713
- (_b = (_a = this.props).onPlay) == null ? void 0 : _b.call(_a);
4832
+ const video = this.props.videoElement;
4833
+ const hasValidSource = video.src || video.currentSrc && video.currentSrc !== "" || video.readyState >= 1;
4834
+ if (hasValidSource) {
4835
+ (_a = video.play()) == null ? void 0 : _a.catch((error) => {
4836
+ var _a2, _b2;
4837
+ console.error("[HlsPlayer] Failed to play:", error);
4838
+ (_b2 = (_a2 = this.props).onError) == null ? void 0 : _b2.call(_a2, error);
4839
+ });
4840
+ (_c = (_b = this.props).onPlay) == null ? void 0 : _c.call(_b);
4841
+ } else {
4842
+ console.warn("[HlsPlayer] Cannot play: video has no valid source");
4843
+ }
4714
4844
  }
4715
4845
  };
4716
4846
  this.pause = () => {
@@ -4879,8 +5009,19 @@ var FilePlayer = class extends import_react4.Component {
4879
5009
  };
4880
5010
  };
4881
5011
  this.play = () => {
5012
+ var _a;
4882
5013
  if (this.props.videoElement) {
4883
- this.props.videoElement.play();
5014
+ const video = this.props.videoElement;
5015
+ const hasValidSource = video.src || video.currentSrc && video.currentSrc !== "" || video.readyState >= 1;
5016
+ if (hasValidSource) {
5017
+ (_a = video.play()) == null ? void 0 : _a.catch((error) => {
5018
+ var _a2, _b;
5019
+ console.error("[FilePlayer] Failed to play:", error);
5020
+ (_b = (_a2 = this.props).onError) == null ? void 0 : _b.call(_a2, error);
5021
+ });
5022
+ } else {
5023
+ console.warn("[FilePlayer] Cannot play: video has no valid source");
5024
+ }
4884
5025
  }
4885
5026
  };
4886
5027
  this.pause = () => {