vidply 1.0.34 → 1.0.35

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.
Files changed (42) hide show
  1. package/dist/dev/{vidply.SoundCloudRenderer-RIA3QKP3.js → vidply.SoundCloudRenderer-HCMKXHSX.js} +1 -3
  2. package/dist/dev/vidply.SoundCloudRenderer-HCMKXHSX.js.map +7 -0
  3. package/dist/dev/{vidply.TranscriptManager-T3BVTZHZ.js → vidply.TranscriptManager-EIIN5YOF.js} +2 -2
  4. package/dist/dev/{vidply.VimeoRenderer-DY2FG7LZ.js → vidply.VimeoRenderer-SLEBCZTT.js} +1 -2
  5. package/dist/dev/vidply.VimeoRenderer-SLEBCZTT.js.map +7 -0
  6. package/dist/dev/{vidply.YouTubeRenderer-EVXXE34A.js → vidply.YouTubeRenderer-E6F4UGVF.js} +1 -2
  7. package/dist/dev/vidply.YouTubeRenderer-E6F4UGVF.js.map +7 -0
  8. package/dist/dev/{vidply.chunk-74NJTDQI.js → vidply.chunk-AXXU22HR.js} +87 -10
  9. package/dist/dev/{vidply.chunk-74NJTDQI.js.map → vidply.chunk-AXXU22HR.js.map} +2 -2
  10. package/dist/dev/vidply.esm.js +32 -50
  11. package/dist/dev/vidply.esm.js.map +2 -2
  12. package/dist/legacy/vidply.js +119 -58
  13. package/dist/legacy/vidply.js.map +3 -3
  14. package/dist/legacy/vidply.min.js +1 -1
  15. package/dist/legacy/vidply.min.meta.json +18 -18
  16. package/dist/prod/vidply.SoundCloudRenderer-D2FNOEG6.min.js +6 -0
  17. package/dist/prod/{vidply.TranscriptManager-GPAOXEK4.min.js → vidply.TranscriptManager-VXCTCJ7X.min.js} +1 -1
  18. package/dist/prod/vidply.VimeoRenderer-QELFZVDU.min.js +6 -0
  19. package/dist/prod/vidply.YouTubeRenderer-ZL6YUHTF.min.js +6 -0
  20. package/dist/prod/{vidply.chunk-OM7DNW5P.min.js → vidply.chunk-Z6BHMOGK.min.js} +1 -1
  21. package/dist/prod/vidply.esm.min.js +3 -3
  22. package/dist/vidply.css +218 -108
  23. package/dist/vidply.esm.min.meta.json +33 -33
  24. package/dist/vidply.min.css +1 -1
  25. package/package.json +3 -3
  26. package/src/controls/ControlBar.js +3 -0
  27. package/src/controls/KeyboardManager.js +19 -0
  28. package/src/core/Player.js +1 -64
  29. package/src/core/SignLanguageManager.js +18 -4
  30. package/src/index.js +3 -1
  31. package/src/renderers/SoundCloudRenderer.js +0 -2
  32. package/src/renderers/VimeoRenderer.js +0 -1
  33. package/src/renderers/YouTubeRenderer.js +0 -1
  34. package/src/styles/vidply.css +218 -108
  35. package/src/utils/DraggableResizable.js +123 -12
  36. package/dist/dev/vidply.SoundCloudRenderer-RIA3QKP3.js.map +0 -7
  37. package/dist/dev/vidply.VimeoRenderer-DY2FG7LZ.js.map +0 -7
  38. package/dist/dev/vidply.YouTubeRenderer-EVXXE34A.js.map +0 -7
  39. package/dist/prod/vidply.SoundCloudRenderer-BFV5SSIU.min.js +0 -6
  40. package/dist/prod/vidply.VimeoRenderer-UQWHQ4LC.min.js +0 -6
  41. package/dist/prod/vidply.YouTubeRenderer-K7A57ICA.min.js +0 -6
  42. /package/dist/dev/{vidply.TranscriptManager-T3BVTZHZ.js.map → vidply.TranscriptManager-EIIN5YOF.js.map} +0 -0
package/dist/vidply.css CHANGED
@@ -149,13 +149,13 @@
149
149
 
150
150
  /* Z-Index Layering System */
151
151
  --vidply-z-base: 1; /* Video, base elements */
152
- --vidply-z-overlay: 2; /* Play overlay, video wrapper on mobile */
153
- --vidply-z-transcript: 5; /* Transcript window */
154
- --vidply-z-playlist: 15; /* Playlist panel in fullscreen */
155
- --vidply-z-menu: 20; /* Menus in normal mode */
156
152
  --vidply-z-controls: 30; /* Control bar */
157
- --vidply-z-menu-high: 100; /* Volume menu */
153
+ --vidply-z-menu: 20; /* Menus in normal mode */
158
154
  --vidply-z-menu-fullscreen: 1000; /* Menus in fullscreen mode */
155
+ --vidply-z-menu-high: 100; /* Volume menu */
156
+ --vidply-z-overlay: 2; /* Play overlay, video wrapper on mobile */
157
+ --vidply-z-playlist: 15; /* Playlist panel in fullscreen */
158
+ --vidply-z-transcript: 5; /* Transcript window */
159
159
  }
160
160
 
161
161
  /* Utility Classes */
@@ -426,7 +426,7 @@
426
426
  }
427
427
 
428
428
  /* Mobile: Ensure player contains all elements properly */
429
- @media (width < 48rem) {
429
+ @media (width <= 48rem), (width < 48rem) {
430
430
  .vidply-player {
431
431
  isolation: isolate; /* Create stacking context */
432
432
  overflow: visible; /* Allow menus to overflow but within bounds */
@@ -442,7 +442,6 @@
442
442
  /* Responsive container */
443
443
 
444
444
  .vidply-player.vidply-audio {
445
- aspect-ratio: auto;
446
445
  background: linear-gradient(135deg, var(--vidply-primary-20) 0%, rgb(var(--vidply-primary-dark-rgb), 0.2) 100%);
447
446
  height: auto;
448
447
  }
@@ -461,11 +460,14 @@
461
460
  }
462
461
 
463
462
  /* Mobile: Video element order and sizing */
464
- @media (width < 48rem) {
463
+ @media (width <= 48rem), (width < 48rem) {
465
464
  .vidply-player video,
466
465
  .vidply-player audio {
467
466
  flex: 0 0 auto; /* Don't grow or shrink */
468
- height: auto;
467
+
468
+ /* Player sets inline `height: 100%` on the media element.
469
+ On mobile we need `auto` to prevent wrapper height collapse / overlap. */
470
+ height: auto !important;
469
471
  order: 1; /* Before controls */
470
472
  }
471
473
 
@@ -500,6 +502,16 @@
500
502
  z-index: 1; /* Base video layer */
501
503
  }
502
504
 
505
+ /* Ensure the video wrapper establishes an intrinsic height in ALL non-fullscreen modes.
506
+ Controls are appended inside `.vidply-video-wrapper` and are positioned `absolute` by default.
507
+ If the wrapper has no intrinsic height,
508
+ the wrapper can collapse and the controls will overlap the content that follows (like `.vidply-track-info`).
509
+
510
+ We keep fullscreen behavior untouched (fullscreen rules already size the wrapper explicitly). */
511
+ .vidply-player.vidply-video:not(.vidply-fullscreen, :fullscreen) .vidply-video-wrapper {
512
+ height: auto;
513
+ }
514
+
503
515
  /* Allow controls and menus to overflow in fullscreen landscape mode */
504
516
  @media (orientation: landscape) {
505
517
  .vidply-player.vidply-fullscreen .vidply-video-wrapper,
@@ -520,17 +532,19 @@
520
532
  }
521
533
 
522
534
  /* Audio content in video player - uses 16:3 aspect ratio for a banner-like appearance */
535
+
523
536
  /* When audio files are played in a video element, we use CSS poster overlay for better control */
524
537
  .vidply-player.vidply-video.vidply-audio-content .vidply-video-wrapper {
525
- aspect-ratio: 16 / 3 !important;
526
538
  height: auto !important;
527
- min-height: 0 !important;
539
+
540
+ /* We still need a visible box for the poster banner */
541
+ min-height: 7.5rem !important;
528
542
  overflow: hidden;
529
543
  }
530
544
 
531
545
  .vidply-player.vidply-video.vidply-audio-content .vidply-video-wrapper.vidply-forced-poster {
532
- background-size: cover;
533
546
  background-position: center;
547
+ background-size: cover;
534
548
  }
535
549
 
536
550
  /* Hide the video element completely when playing audio - let the wrapper show the poster */
@@ -538,40 +552,48 @@
538
552
  display: none !important;
539
553
  }
540
554
 
541
- /* YouTube and Vimeo iframe containers - ensure 16:9 aspect ratio */
542
- .vidply-video-wrapper > div[id^="youtube-player-"],
555
+ /* YouTube and Vimeo iframe containers - keep classic 16:9 framing */
556
+ .vidply-video-wrapper > iframe[id^="youtube-player-"],
543
557
  .vidply-video-wrapper > div[id^="vimeo-player-"] {
544
- width: 100% !important;
545
558
  aspect-ratio: 16 / 9;
546
- max-height: 100%;
559
+ height: auto;
560
+ max-height: none !important; /* override renderer inline maxHeight=100% */
561
+ position: relative; /* ensure absolutely-positioned iframes size against this box */
562
+ width: 100% !important;
547
563
  }
548
564
 
549
565
  .vidply-video-wrapper > div[id^="youtube-player-"] iframe,
550
566
  .vidply-video-wrapper > div[id^="vimeo-player-"] iframe {
567
+ aspect-ratio: 16 / 9;
568
+
569
+ /* Some providers inject height:100% which can ignore the intended 16:9 sizing.
570
+ Force the iframe itself to be 16:9 and let height be derived. */
571
+ display: block;
572
+ height: auto !important;
573
+ position: relative;
551
574
  width: 100% !important;
552
- height: 100% !important;
553
575
  }
554
576
 
555
- /* SoundCloud iframe - uses 16:3 aspect ratio for single track audio banner appearance */
577
+ /* SoundCloud iframe - stable height */
556
578
  .vidply-video-wrapper > iframe.vidply-soundcloud-iframe {
579
+ height: clamp(6rem, 18vh, 12rem);
557
580
  width: 100% !important;
558
- aspect-ratio: 16 / 3;
559
- max-height: 100%;
560
581
  }
561
582
 
562
- /* SoundCloud playlist - uses 16:9 aspect ratio to show track list */
583
+ /* SoundCloud playlist - taller variant to show track list */
563
584
  .vidply-video-wrapper > iframe.vidply-soundcloud-iframe.vidply-soundcloud-playlist {
564
- aspect-ratio: 16 / 9;
585
+ height: clamp(12.5rem, 45vh, 28rem);
565
586
  }
566
587
 
567
588
  /* Hide VidPly controls when external renderer (YouTube, Vimeo, SoundCloud) is active */
589
+
568
590
  /* These services have their own native controls */
569
591
  .vidply-player.vidply-external-controls .vidply-controls {
570
592
  display: none !important;
571
593
  }
572
594
 
573
595
  /* Mobile: Simplify video wrapper but keep captions contained */
574
- @media (width < 48rem) {
596
+ @media (width <= 48rem), (width < 48rem) {
575
597
  .vidply-video-wrapper {
576
598
  display: block;
577
599
  height: auto;
@@ -589,30 +611,31 @@
589
611
  /* Ensure video doesn't collapse */
590
612
  .vidply-player video {
591
613
  display: block;
614
+ height: auto !important;
592
615
  position: relative;
593
- width: 100%;
616
+ width: 100%;
594
617
  }
595
618
 
596
619
  /* Override mobile rules in fullscreen mode - critical for iOS */
597
620
  .vidply-player.vidply-fullscreen .vidply-video-wrapper,
598
621
  .vidply-player:fullscreen .vidply-video-wrapper {
622
+ bottom: 0 !important;
599
623
  display: flex !important;
600
624
  height: 100% !important;
625
+ left: 0 !important;
601
626
  min-height: 0 !important;
602
627
  position: absolute !important;
603
- top: 0 !important;
604
- left: 0 !important;
605
628
  right: 0 !important;
606
- bottom: 0 !important;
629
+ top: 0 !important;
607
630
  }
608
631
 
609
632
  .vidply-player.vidply-fullscreen video,
610
633
  .vidply-player:fullscreen video {
634
+ height: 100% !important;
635
+ left: 0 !important;
611
636
  position: absolute !important;
612
637
  top: 0 !important;
613
- left: 0 !important;
614
638
  width: 100% !important;
615
- height: 100% !important;
616
639
  }
617
640
  }
618
641
 
@@ -628,6 +651,8 @@
628
651
 
629
652
  /* Centered Play Button Overlay */
630
653
  .vidply-play-overlay {
654
+ border: 0.125rem solid var(--vidply-primary);
655
+ border-radius: 50%;
631
656
  cursor: pointer;
632
657
  filter: drop-shadow(0 0.5rem 2rem rgb(0 0 0 / 30%));
633
658
  left: 50%;
@@ -636,8 +661,6 @@
636
661
  transform: translate(-50%, -50%);
637
662
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
638
663
  z-index: var(--vidply-z-overlay);
639
- border: 0.125rem solid var(--vidply-primary);
640
- border-radius: 50%;
641
664
  }
642
665
 
643
666
  .vidply-play-overlay:hover {
@@ -689,7 +712,7 @@
689
712
  }
690
713
 
691
714
  /* Mobile: Controls underneath video (but not in landscape fullscreen) */
692
- @media (width < 48rem) {
715
+ @media (width <= 48rem), (width < 48rem) {
693
716
  .vidply-controls {
694
717
  background: var(--vidply-black-90);
695
718
  border-top: 0.0625rem solid var(--vidply-border-light);
@@ -799,22 +822,22 @@
799
822
  color: var(--vidply-white);
800
823
  display: none;
801
824
  font-size: 0.75rem;
825
+ overflow: hidden;
802
826
  padding: 0;
803
827
  pointer-events: none;
804
828
  position: absolute;
805
829
  transform: translateX(-50%);
806
830
  white-space: nowrap;
807
- overflow: hidden;
808
831
  }
809
832
 
810
833
  .vidply-progress-preview {
811
- background-size: cover;
812
834
  background-position: center;
835
+ background-size: cover;
813
836
  border-radius: 0.25rem 0.25rem 0 0;
814
837
  display: none;
815
838
  height: 5rem;
816
- width: 8.888888889rem; /* 160px at 18px base */
817
839
  min-width: 8.888888889rem;
840
+ width: 8.888888889rem; /* 160px at 18px base */
818
841
  }
819
842
 
820
843
  .vidply-progress-tooltip-time {
@@ -1084,7 +1107,7 @@
1084
1107
  }
1085
1108
 
1086
1109
  /* Mobile: Don't use backdrop, menus position above buttons */
1087
- @media (width < 48rem) {
1110
+ @media (width <= 48rem), (width < 48rem) {
1088
1111
  .vidply-menu-backdrop {
1089
1112
  display: none !important;
1090
1113
  }
@@ -1123,6 +1146,11 @@
1123
1146
  }
1124
1147
 
1125
1148
  /* Menu positioned below button */
1149
+ .vidply-menu.vidply-menu-below {
1150
+ bottom: auto;
1151
+ top: calc(100% + 0.5rem);
1152
+ }
1153
+
1126
1154
  .vidply-menu.vidply-menu-below::after {
1127
1155
  border-bottom: 0.375rem solid var(--vidply-bg-menu);
1128
1156
  border-top: none;
@@ -1246,10 +1274,10 @@
1246
1274
  left: auto !important;
1247
1275
  max-width: calc(100vw - 1.25rem);
1248
1276
  right: 0 !important;
1249
- z-index: 1000; /* Ensure menu appears above all player elements including playlist */
1277
+ transform: none !important;
1250
1278
 
1251
1279
  /* Ensure menu stays within viewport */
1252
- transform: none !important;
1280
+ z-index: 1000; /* Ensure menu appears above all player elements including playlist */
1253
1281
  }
1254
1282
 
1255
1283
  /* Overflow menu items with icons */
@@ -1482,7 +1510,7 @@
1482
1510
  }
1483
1511
 
1484
1512
  /* Mobile: Caption positioning handled by JavaScript */
1485
- @media (width < 48rem) {
1513
+ @media (width <= 48rem), (width < 48rem) {
1486
1514
  .vidply-captions {
1487
1515
  /* Bottom position set dynamically by JS based on control height */
1488
1516
  left: 50%;
@@ -1705,15 +1733,15 @@
1705
1733
  background: #000;
1706
1734
  bottom: 0;
1707
1735
  left: 0;
1736
+ margin: 0 !important;
1737
+ padding: 0 !important;
1708
1738
  position: fixed !important;
1709
1739
  right: 0;
1710
- top: 0;
1711
- z-index: 999999;
1712
1740
 
1713
1741
  /* Critical iOS fixes */
1742
+ top: 0;
1714
1743
  transform: translate3d(0, 0, 0);
1715
- margin: 0 !important;
1716
- padding: 0 !important;
1744
+ z-index: 999999;
1717
1745
  }
1718
1746
 
1719
1747
  /* Fix controls in fullscreen LANDSCAPE mode - overlay them on video */
@@ -1886,44 +1914,44 @@
1886
1914
 
1887
1915
  .vidply-player.vidply-fullscreen,
1888
1916
  .vidply-player:fullscreen {
1889
- height: 100vh !important;
1890
- width: 100vw !important;
1891
1917
  display: flex !important;
1892
1918
  flex-direction: column !important;
1919
+ height: 100vh !important;
1920
+ width: 100vw !important;
1893
1921
  }
1894
1922
 
1895
1923
  /* Make video wrapper fill entire screen - positioned absolutely */
1896
1924
  .vidply-player.vidply-fullscreen .vidply-video-wrapper,
1897
1925
  .vidply-player:fullscreen .vidply-video-wrapper {
1898
- position: absolute !important;
1899
- top: 0 !important;
1926
+ align-items: center !important;
1927
+ bottom: 0 !important;
1928
+ display: flex !important;
1929
+ height: 100% !important;
1930
+ justify-content: center !important;
1900
1931
  left: 0 !important;
1932
+ position: absolute !important;
1901
1933
  right: 0 !important;
1902
- bottom: 0 !important;
1934
+ top: 0 !important;
1903
1935
  width: 100% !important;
1904
- height: 100% !important;
1905
1936
  z-index: 1 !important;
1906
- display: flex !important;
1907
- align-items: center !important;
1908
- justify-content: center !important;
1909
1937
  }
1910
1938
 
1911
1939
  .vidply-player.vidply-fullscreen video,
1912
1940
  .vidply-player:fullscreen video {
1913
- position: relative !important;
1914
- width: 100% !important;
1915
1941
  height: 100% !important;
1916
- object-fit: contain !important;
1917
- max-width: 100% !important;
1918
1942
  max-height: 100% !important;
1943
+ max-width: 100% !important;
1944
+ object-fit: contain !important;
1945
+ position: relative !important;
1946
+ width: 100% !important;
1919
1947
  }
1920
1948
 
1921
1949
  .vidply-player.vidply-fullscreen .vidply-controls,
1922
1950
  .vidply-player:fullscreen .vidply-controls {
1923
1951
  /* Position controls at the bottom */
1924
- position: absolute !important;
1925
1952
  bottom: 0 !important;
1926
1953
  left: 0 !important;
1954
+ position: absolute !important;
1927
1955
  right: 0 !important;
1928
1956
  z-index: 30 !important; /* Above playlist */
1929
1957
  }
@@ -1931,12 +1959,12 @@
1931
1959
  /* Force playlist to truly overlay - above video, below controls */
1932
1960
  .vidply-player.vidply-fullscreen .vidply-playlist-panel,
1933
1961
  .vidply-player:fullscreen .vidply-playlist-panel {
1934
- position: absolute !important; /* Absolute relative to player */
1935
1962
  bottom: 5rem !important; /* Above controls (typical control height is ~5rem) */
1936
1963
  left: 0 !important;
1964
+ margin: 0 !important;
1965
+ position: absolute !important; /* Absolute relative to player */
1937
1966
  right: 0 !important;
1938
1967
  z-index: 15 !important; /* Above video (z-index:1), below controls (z-index:30) */
1939
- margin: 0 !important;
1940
1968
  }
1941
1969
  }
1942
1970
 
@@ -2022,7 +2050,7 @@
2022
2050
  }
2023
2051
 
2024
2052
  /* Responsive Breakpoints */
2025
- @media (width < 48rem) {
2053
+ @media (width <= 48rem), (width < 48rem) {
2026
2054
  .vidply-controls {
2027
2055
  padding: 1rem 0.75rem 0.75rem;
2028
2056
  }
@@ -2144,7 +2172,7 @@
2144
2172
  }
2145
2173
 
2146
2174
  /* Landscape mobile optimization */
2147
- @media (width <= 56rem) and (orientation: landscape) {
2175
+ @media (width <= 56rem) and (orientation: landscape), (width <= 56rem) and (orientation: landscape) {
2148
2176
  .vidply-menu {
2149
2177
  max-height: 50vh;
2150
2178
  }
@@ -2162,11 +2190,11 @@
2162
2190
  .vidply-player:fullscreen .vidply-playlist-panel {
2163
2191
  bottom: 4.375rem; /* Directly above controls */
2164
2192
  max-height: 30vh; /* Less height in landscape */
2165
- padding: 0.625rem 0;
2166
- overflow-y: hidden;
2193
+ -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
2167
2194
  overflow-x: auto;
2195
+ overflow-y: hidden;
2196
+ padding: 0.625rem 0;
2168
2197
  touch-action: pan-x; /* Allow horizontal scrolling on touch devices */
2169
- -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
2170
2198
  }
2171
2199
 
2172
2200
  /* Landscape playlist list - horizontal row */
@@ -2181,10 +2209,10 @@
2181
2209
  /* Landscape items - smaller vertical cards */
2182
2210
  .vidply-player.vidply-fullscreen .vidply-playlist-item,
2183
2211
  .vidply-player:fullscreen .vidply-playlist-item {
2184
- width: 11.25rem;
2185
- min-width: 11.25rem;
2186
- max-width: 11.25rem;
2187
2212
  flex-shrink: 0;
2213
+ max-width: 11.25rem;
2214
+ min-width: 11.25rem;
2215
+ width: 11.25rem;
2188
2216
  }
2189
2217
 
2190
2218
  .vidply-player.vidply-fullscreen .vidply-playlist-item-button,
@@ -2196,9 +2224,9 @@
2196
2224
 
2197
2225
  .vidply-player.vidply-fullscreen .vidply-playlist-thumbnail,
2198
2226
  .vidply-player:fullscreen .vidply-playlist-thumbnail {
2227
+ border-radius: 0.5rem 0.5rem 0 0;
2199
2228
  height: 6.25rem;
2200
2229
  width: 100%;
2201
- border-radius: 0.5rem 0.5rem 0 0;
2202
2230
  }
2203
2231
 
2204
2232
  .vidply-player.vidply-fullscreen .vidply-playlist-item-info,
@@ -2208,14 +2236,14 @@
2208
2236
 
2209
2237
  .vidply-player.vidply-fullscreen .vidply-playlist-header,
2210
2238
  .vidply-player:fullscreen .vidply-playlist-header {
2211
- padding: 0 0.625rem 0.5rem;
2212
- font-size: 0.6875rem;
2213
2239
  flex-shrink: 0;
2240
+ font-size: 0.6875rem;
2241
+ padding: 0 0.625rem 0.5rem;
2214
2242
  }
2215
2243
  }
2216
2244
 
2217
2245
  /* Extra small screens */
2218
- @media (width <= 30rem) {
2246
+ @media (width <= 30rem), (width <= 30rem) {
2219
2247
  .vidply-speed-text {
2220
2248
  display: none;
2221
2249
  }
@@ -2261,12 +2289,12 @@
2261
2289
 
2262
2290
  /* Track Artwork - Displays album art/poster above audio player */
2263
2291
  .vidply-track-artwork {
2264
- aspect-ratio: 16 / 3;
2265
2292
  background-color: var(--vidply-black);
2266
2293
  background-position: center;
2267
2294
  background-repeat: no-repeat;
2268
2295
  background-size: cover;
2269
2296
  border-bottom: 0.0625rem solid var(--vidply-border-light);
2297
+ height: clamp(7.5rem, 22vh, 12rem);
2270
2298
  order: 1; /* Before video-wrapper */
2271
2299
  overflow: hidden;
2272
2300
  position: relative;
@@ -2329,15 +2357,15 @@
2329
2357
  }
2330
2358
 
2331
2359
  .vidply-track-description {
2360
+ -webkit-box-orient: vertical;
2332
2361
  color: var(--vidply-white-60);
2362
+ display: -webkit-box;
2333
2363
  font-size: 0.8125rem;
2364
+ -webkit-line-clamp: 2;
2334
2365
  line-height: 1.4;
2335
2366
  margin-top: 0.5rem;
2336
2367
  max-height: 3.5em;
2337
2368
  overflow: hidden;
2338
- display: -webkit-box;
2339
- -webkit-line-clamp: 2;
2340
- -webkit-box-orient: vertical;
2341
2369
  }
2342
2370
 
2343
2371
  /* Playlist Panel */
@@ -2345,7 +2373,6 @@
2345
2373
  background: var(--vidply-bg-playlist);
2346
2374
  border-top: 0.0625rem solid var(--vidply-border-light);
2347
2375
  max-height: 25rem;
2348
- transform: translate3d(0, 0, 0);
2349
2376
  order: 3; /* After track info */
2350
2377
  -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
2351
2378
  overflow-y: auto;
@@ -2355,11 +2382,77 @@
2355
2382
  z-index: var(--vidply-z-base); /* Below menus but part of player stacking context */
2356
2383
  }
2357
2384
 
2385
+ /* iOS Safari fix: Ensure playlist panel doesn't cause overflow issues */
2386
+ @supports (-webkit-touch-callout: none) {
2387
+ /* Remove transform in normal mode that creates stacking context issues on iOS */
2388
+
2389
+ /* The transform was only for hardware acceleration, but causes layout issues */
2390
+
2391
+ /* Fullscreen mode overrides with its own transform, so this is safe */
2392
+ .vidply-playlist-panel {
2393
+ transform: none;
2394
+
2395
+ /* Ensure it's properly positioned in flex layout */
2396
+ flex-shrink: 0;
2397
+
2398
+ /* Remove z-index in normal mode to prevent overlaying content below */
2399
+ z-index: auto;
2400
+
2401
+ /* Ensure it participates in normal document flow */
2402
+ position: relative;
2403
+
2404
+ /* Explicitly set display to ensure it's in flow */
2405
+ display: block;
2406
+ }
2407
+
2408
+ /* Ensure player container properly contains playlist on iOS */
2409
+ .vidply-player.vidply-has-playlist {
2410
+ /* Remove contain: layout to allow container to expand with playlist */
2411
+
2412
+ /* Keep style containment for performance, but allow layout to flow */
2413
+ contain: style;
2414
+
2415
+ /* Don't use isolation as it creates stacking context that causes overlay issues */
2416
+
2417
+ /* Override mobile isolation rule for playlists */
2418
+ isolation: auto;
2419
+
2420
+ /* Ensure container expands to contain all children */
2421
+ min-height: 0;
2422
+
2423
+ /* Ensure height is calculated based on content - override any fixed heights */
2424
+ height: auto !important;
2425
+
2426
+ /* Ensure overflow doesn't clip the playlist */
2427
+ overflow: visible;
2428
+ }
2429
+
2430
+ /* Override mobile isolation for playlists on iOS */
2431
+ @media (width <= 48rem), (width < 48rem) {
2432
+ .vidply-player.vidply-has-playlist {
2433
+ isolation: auto;
2434
+ }
2435
+ }
2436
+
2437
+ /* Ensure playlist panel doesn't overflow container on iOS */
2438
+ .vidply-player.vidply-has-playlist .vidply-playlist-panel {
2439
+ /* Prevent overflow that causes content below to be overlapped */
2440
+ max-width: 100%;
2441
+ width: 100%;
2442
+
2443
+ /* Ensure it's part of the flex layout flow */
2444
+ flex-basis: auto;
2445
+
2446
+ /* Explicitly ensure it's in normal flow */
2447
+ float: none;
2448
+ }
2449
+ }
2450
+
2358
2451
  /* Fullscreen Playlist Panel - YouTube-style overlay above controls */
2359
2452
  .vidply-player.vidply-fullscreen .vidply-playlist-panel,
2360
2453
  .vidply-player:fullscreen .vidply-playlist-panel {
2361
- background: linear-gradient(to top, rgb(0 0 0 / 95%) 0%, rgb(0 0 0 / 90%) 100%);
2362
2454
  backdrop-filter: blur(0.625rem);
2455
+ background: linear-gradient(to top, rgb(0 0 0 / 95%) 0%, rgb(0 0 0 / 90%) 100%);
2363
2456
  border: none;
2364
2457
  border-top: 0.0625rem solid var(--vidply-border);
2365
2458
  bottom: 5rem; /* Directly above controls */
@@ -2401,11 +2494,11 @@
2401
2494
  display: flex;
2402
2495
  flex-direction: row;
2403
2496
  gap: 0.75rem;
2404
- padding: 0.5rem 1rem;
2497
+ -webkit-overflow-scrolling: touch;
2405
2498
  overflow-x: auto;
2406
2499
  overflow-y: hidden;
2500
+ padding: 0.5rem 1rem;
2407
2501
  scroll-snap-type: x mandatory;
2408
- -webkit-overflow-scrolling: touch;
2409
2502
  }
2410
2503
 
2411
2504
  /* Fullscreen playlist header - more subtle */
@@ -2421,28 +2514,28 @@
2421
2514
  .vidply-player.vidply-fullscreen .vidply-playlist-item,
2422
2515
  .vidply-player:fullscreen .vidply-playlist-item {
2423
2516
  flex: 0 0 auto;
2424
- min-width: 17.5rem;
2425
2517
  max-width: 20rem;
2518
+ min-width: 17.5rem;
2426
2519
  scroll-snap-align: start;
2427
2520
  }
2428
2521
 
2429
2522
  .vidply-player.vidply-fullscreen .vidply-playlist-item-button,
2430
2523
  .vidply-player:fullscreen .vidply-playlist-item-button {
2431
- flex-direction: column;
2432
2524
  align-items: stretch;
2433
- gap: 0.5rem;
2434
- padding: 0;
2435
2525
  background: var(--vidply-black-40);
2436
2526
  border-radius: 0.5rem;
2527
+ flex-direction: column;
2528
+ gap: 0.5rem;
2437
2529
  overflow: hidden;
2530
+ padding: 0;
2438
2531
  transition: all 0.2s ease;
2439
2532
  }
2440
2533
 
2441
2534
  .vidply-player.vidply-fullscreen .vidply-playlist-item-button:hover,
2442
2535
  .vidply-player:fullscreen .vidply-playlist-item-button:hover {
2443
2536
  background: var(--vidply-white-10);
2444
- transform: translateY(-0.25rem);
2445
2537
  box-shadow: 0 0.5rem 1.5rem var(--vidply-black-60);
2538
+ transform: translateY(-0.25rem);
2446
2539
  }
2447
2540
 
2448
2541
  /* Fullscreen thumbnail container - takes full width of card */
@@ -2454,9 +2547,9 @@
2454
2547
 
2455
2548
  .vidply-player.vidply-fullscreen .vidply-playlist-thumbnail,
2456
2549
  .vidply-player:fullscreen .vidply-playlist-thumbnail {
2457
- width: 100%;
2458
- height: 10rem;
2459
2550
  border-radius: 0;
2551
+ height: 10rem;
2552
+ width: 100%;
2460
2553
  }
2461
2554
 
2462
2555
  /* Larger duration badge in fullscreen for better visibility */
@@ -2481,15 +2574,15 @@
2481
2574
 
2482
2575
  .vidply-player.vidply-fullscreen .vidply-playlist-item-title,
2483
2576
  .vidply-player:fullscreen .vidply-playlist-item-title {
2577
+ -webkit-box-orient: vertical;
2578
+ display: -webkit-box;
2484
2579
  font-size: 0.875rem;
2485
2580
  font-weight: 600;
2581
+ -webkit-line-clamp: 2;
2486
2582
  margin-bottom: 0.25rem;
2487
- white-space: normal;
2488
2583
  overflow: hidden;
2489
2584
  text-overflow: ellipsis;
2490
- display: -webkit-box;
2491
- -webkit-line-clamp: 2;
2492
- -webkit-box-orient: vertical;
2585
+ white-space: normal;
2493
2586
  }
2494
2587
 
2495
2588
  .vidply-player.vidply-fullscreen .vidply-playlist-item-artist,
@@ -2557,8 +2650,8 @@
2557
2650
  /* Active item styling in fullscreen */
2558
2651
  .vidply-player.vidply-fullscreen .vidply-playlist-item-active .vidply-playlist-item-button,
2559
2652
  .vidply-player:fullscreen .vidply-playlist-item-active .vidply-playlist-item-button {
2560
- border: 0.125rem solid var(--vidply-primary-light);
2561
2653
  background: var(--vidply-primary-15);
2654
+ border: 0.125rem solid var(--vidply-primary-light);
2562
2655
  }
2563
2656
 
2564
2657
  .vidply-player.vidply-fullscreen .vidply-playlist-item-active .vidply-playlist-item-title,
@@ -3621,6 +3714,9 @@
3621
3714
  min-height: 6.25rem;
3622
3715
  overflow: visible; /* Allow menu to overflow */
3623
3716
  position: absolute;
3717
+
3718
+ /* Mobile/touch: make the entire overlay a reliable drag surface (touch-action doesn't inherit) */
3719
+ touch-action: none;
3624
3720
  transition: opacity 0.3s ease;
3625
3721
  width: 17.5rem;
3626
3722
  z-index: 3;
@@ -3650,6 +3746,12 @@
3650
3746
  user-select: none;
3651
3747
  }
3652
3748
 
3749
+ /* iOS/Android: `touch-action` does NOT inherit.
3750
+ Ensure touching any child inside the header still counts as a drag gesture area. */
3751
+ .vidply-sign-language-header * {
3752
+ touch-action: none;
3753
+ }
3754
+
3653
3755
  .vidply-sign-language-header:focus,
3654
3756
  .vidply-sign-language-header:focus-visible {
3655
3757
  box-shadow: 0 0 0 0.25rem rgb(91 144 255 / 35%);
@@ -3807,6 +3909,13 @@
3807
3909
  flex: 1;
3808
3910
  }
3809
3911
 
3912
+ /* Mobile: drag is always available via touch, so hide the keyboard drag mode toggle */
3913
+ @media (width <= 48rem), (width < 48rem) {
3914
+ .vidply-sign-language-settings-item[data-setting="keyboard-drag"] {
3915
+ display: none !important;
3916
+ }
3917
+ }
3918
+
3810
3919
  .vidply-sign-language-header h3 {
3811
3920
  color: var(--vidply-white);
3812
3921
  font-size: var(--vidply-font-lg);
@@ -3867,6 +3976,7 @@
3867
3976
  /* Sign Language Resize Handles */
3868
3977
  .vidply-sign-resize-handle {
3869
3978
  position: absolute;
3979
+ touch-action: none;
3870
3980
  z-index: 10;
3871
3981
  }
3872
3982
 
@@ -4025,7 +4135,7 @@
4025
4135
  }
4026
4136
 
4027
4137
  /* Responsive Sign Language Video */
4028
- @media (width < 48rem) {
4138
+ @media (width <= 48rem), (width < 48rem) {
4029
4139
  .vidply-sign-language-wrapper {
4030
4140
  min-width: 7.5rem;
4031
4141
  width: 35%;
@@ -4038,7 +4148,7 @@
4038
4148
  }
4039
4149
 
4040
4150
  /* Responsive Adjustments */
4041
- @media (width < 48rem) {
4151
+ @media (width <= 48rem), (width < 48rem) {
4042
4152
  .vidply-playlist-thumbnail {
4043
4153
  height: 2.125rem;
4044
4154
  width: 3.75rem;
@@ -4050,7 +4160,7 @@
4050
4160
  }
4051
4161
 
4052
4162
  .vidply-track-artwork {
4053
- aspect-ratio: 16 / 3;
4163
+ height: clamp(6.5rem, 20vh, 10rem);
4054
4164
  }
4055
4165
 
4056
4166
  .vidply-track-info {
@@ -4066,12 +4176,12 @@
4066
4176
  .vidply-player:fullscreen .vidply-playlist-panel {
4067
4177
  bottom: 6.25rem; /* Directly above controls with extra space */
4068
4178
  max-height: 35vh; /* Compact height */
4069
- padding: 0.75rem 0; /* Vertical padding only */
4070
- overflow-y: hidden; /* No vertical scrolling */
4179
+ -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
4071
4180
  overflow-x: auto; /* Horizontal scrolling */
4181
+ overflow-y: hidden; /* No vertical scrolling */
4182
+ padding: 0.75rem 0; /* Vertical padding only */
4072
4183
  position: absolute !important; /* Force absolute over video */
4073
4184
  touch-action: pan-x; /* Allow horizontal scrolling on touch devices */
4074
- -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
4075
4185
  }
4076
4186
 
4077
4187
  /* Mobile playlist list - horizontal row, no wrapping */
@@ -4080,8 +4190,8 @@
4080
4190
  flex-direction: row; /* Items side by side */
4081
4191
  flex-wrap: nowrap; /* Never wrap */
4082
4192
  gap: 0.5rem;
4083
- padding: 0 0.75rem;
4084
4193
  -webkit-overflow-scrolling: touch;
4194
+ padding: 0 0.75rem;
4085
4195
  scroll-behavior: smooth;
4086
4196
  touch-action: pan-x; /* Ensure horizontal swipe gestures work */
4087
4197
  }
@@ -4089,11 +4199,11 @@
4089
4199
  /* Mobile playlist items - only show thumbnails */
4090
4200
  .vidply-player.vidply-fullscreen .vidply-playlist-item,
4091
4201
  .vidply-player:fullscreen .vidply-playlist-item {
4092
- width: 7.5rem; /* Smaller width for thumbnail-only */
4093
- min-width: 7.5rem;
4094
- max-width: 7.5rem;
4095
4202
  flex-shrink: 0; /* Don't shrink */
4203
+ max-width: 7.5rem;
4204
+ min-width: 7.5rem;
4096
4205
  scroll-snap-align: start;
4206
+ width: 7.5rem; /* Smaller width for thumbnail-only */
4097
4207
  }
4098
4208
 
4099
4209
  .vidply-player.vidply-fullscreen .vidply-playlist-item-button,
@@ -4105,10 +4215,10 @@
4105
4215
 
4106
4216
  .vidply-player.vidply-fullscreen .vidply-playlist-thumbnail,
4107
4217
  .vidply-player:fullscreen .vidply-playlist-thumbnail {
4218
+ border-radius: 0.5rem; /* Fully rounded for thumbnail-only */
4219
+ flex-shrink: 0;
4108
4220
  height: 5.625rem; /* Square-ish thumbnail */
4109
4221
  width: 100%; /* Full width of card */
4110
- flex-shrink: 0;
4111
- border-radius: 0.5rem; /* Fully rounded for thumbnail-only */
4112
4222
  }
4113
4223
 
4114
4224
  /* Hide text info on mobile - show only thumbnails */
@@ -4120,13 +4230,13 @@
4120
4230
  /* If no thumbnail, show only text */
4121
4231
  .vidply-player.vidply-fullscreen .vidply-playlist-item:not(:has(.vidply-playlist-thumbnail)) .vidply-playlist-item-info,
4122
4232
  .vidply-player:fullscreen .vidply-playlist-item:not(:has(.vidply-playlist-thumbnail)) .vidply-playlist-item-info {
4233
+ align-items: center;
4123
4234
  display: flex;
4124
4235
  flex-direction: column;
4125
- padding: 0.5rem;
4236
+ height: 5.625rem;
4126
4237
  justify-content: center;
4127
- align-items: center;
4238
+ padding: 0.5rem;
4128
4239
  text-align: center;
4129
- height: 5.625rem;
4130
4240
  }
4131
4241
 
4132
4242
  .vidply-player.vidply-fullscreen .vidply-playlist-item:not(:has(.vidply-playlist-thumbnail)) .vidply-playlist-item-title,
@@ -4142,9 +4252,9 @@
4142
4252
 
4143
4253
  .vidply-player.vidply-fullscreen .vidply-playlist-header,
4144
4254
  .vidply-player:fullscreen .vidply-playlist-header {
4145
- padding: 0 0.75rem 0.5rem;
4146
- font-size: 0.6875rem;
4147
4255
  flex-shrink: 0;
4256
+ font-size: 0.6875rem;
4257
+ padding: 0 0.75rem 0.5rem;
4148
4258
  }
4149
4259
 
4150
4260
  /* Mobile transcript underneath video and controls */