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
@@ -143,13 +143,13 @@
143
143
 
144
144
  /* Z-Index Layering System */
145
145
  --vidply-z-base: 1; /* Video, base elements */
146
- --vidply-z-overlay: 2; /* Play overlay, video wrapper on mobile */
147
- --vidply-z-transcript: 5; /* Transcript window */
148
- --vidply-z-playlist: 15; /* Playlist panel in fullscreen */
149
- --vidply-z-menu: 20; /* Menus in normal mode */
150
146
  --vidply-z-controls: 30; /* Control bar */
151
- --vidply-z-menu-high: 100; /* Volume menu */
147
+ --vidply-z-menu: 20; /* Menus in normal mode */
152
148
  --vidply-z-menu-fullscreen: 1000; /* Menus in fullscreen mode */
149
+ --vidply-z-menu-high: 100; /* Volume menu */
150
+ --vidply-z-overlay: 2; /* Play overlay, video wrapper on mobile */
151
+ --vidply-z-playlist: 15; /* Playlist panel in fullscreen */
152
+ --vidply-z-transcript: 5; /* Transcript window */
153
153
  }
154
154
 
155
155
  /* Utility Classes */
@@ -420,7 +420,7 @@
420
420
  }
421
421
 
422
422
  /* Mobile: Ensure player contains all elements properly */
423
- @media (width < 48rem) {
423
+ @media (width <= 48rem), (width < 48rem) {
424
424
  .vidply-player {
425
425
  isolation: isolate; /* Create stacking context */
426
426
  overflow: visible; /* Allow menus to overflow but within bounds */
@@ -436,7 +436,6 @@
436
436
  /* Responsive container */
437
437
 
438
438
  .vidply-player.vidply-audio {
439
- aspect-ratio: auto;
440
439
  background: linear-gradient(135deg, var(--vidply-primary-20) 0%, rgb(var(--vidply-primary-dark-rgb), 0.2) 100%);
441
440
  height: auto;
442
441
  }
@@ -455,11 +454,14 @@
455
454
  }
456
455
 
457
456
  /* Mobile: Video element order and sizing */
458
- @media (width < 48rem) {
457
+ @media (width <= 48rem), (width < 48rem) {
459
458
  .vidply-player video,
460
459
  .vidply-player audio {
461
460
  flex: 0 0 auto; /* Don't grow or shrink */
462
- height: auto;
461
+
462
+ /* Player sets inline `height: 100%` on the media element.
463
+ On mobile we need `auto` to prevent wrapper height collapse / overlap. */
464
+ height: auto !important;
463
465
  order: 1; /* Before controls */
464
466
  }
465
467
 
@@ -494,6 +496,16 @@
494
496
  z-index: 1; /* Base video layer */
495
497
  }
496
498
 
499
+ /* Ensure the video wrapper establishes an intrinsic height in ALL non-fullscreen modes.
500
+ Controls are appended inside `.vidply-video-wrapper` and are positioned `absolute` by default.
501
+ If the wrapper has no intrinsic height,
502
+ the wrapper can collapse and the controls will overlap the content that follows (like `.vidply-track-info`).
503
+
504
+ We keep fullscreen behavior untouched (fullscreen rules already size the wrapper explicitly). */
505
+ .vidply-player.vidply-video:not(.vidply-fullscreen, :fullscreen) .vidply-video-wrapper {
506
+ height: auto;
507
+ }
508
+
497
509
  /* Allow controls and menus to overflow in fullscreen landscape mode */
498
510
  @media (orientation: landscape) {
499
511
  .vidply-player.vidply-fullscreen .vidply-video-wrapper,
@@ -514,17 +526,19 @@
514
526
  }
515
527
 
516
528
  /* Audio content in video player - uses 16:3 aspect ratio for a banner-like appearance */
529
+
517
530
  /* When audio files are played in a video element, we use CSS poster overlay for better control */
518
531
  .vidply-player.vidply-video.vidply-audio-content .vidply-video-wrapper {
519
- aspect-ratio: 16 / 3 !important;
520
532
  height: auto !important;
521
- min-height: 0 !important;
533
+
534
+ /* We still need a visible box for the poster banner */
535
+ min-height: 7.5rem !important;
522
536
  overflow: hidden;
523
537
  }
524
538
 
525
539
  .vidply-player.vidply-video.vidply-audio-content .vidply-video-wrapper.vidply-forced-poster {
526
- background-size: cover;
527
540
  background-position: center;
541
+ background-size: cover;
528
542
  }
529
543
 
530
544
  /* Hide the video element completely when playing audio - let the wrapper show the poster */
@@ -532,40 +546,48 @@
532
546
  display: none !important;
533
547
  }
534
548
 
535
- /* YouTube and Vimeo iframe containers - ensure 16:9 aspect ratio */
536
- .vidply-video-wrapper > div[id^="youtube-player-"],
549
+ /* YouTube and Vimeo iframe containers - keep classic 16:9 framing */
550
+ .vidply-video-wrapper > iframe[id^="youtube-player-"],
537
551
  .vidply-video-wrapper > div[id^="vimeo-player-"] {
538
- width: 100% !important;
539
552
  aspect-ratio: 16 / 9;
540
- max-height: 100%;
553
+ height: auto;
554
+ max-height: none !important; /* override renderer inline maxHeight=100% */
555
+ position: relative; /* ensure absolutely-positioned iframes size against this box */
556
+ width: 100% !important;
541
557
  }
542
558
 
543
559
  .vidply-video-wrapper > div[id^="youtube-player-"] iframe,
544
560
  .vidply-video-wrapper > div[id^="vimeo-player-"] iframe {
561
+ aspect-ratio: 16 / 9;
562
+
563
+ /* Some providers inject height:100% which can ignore the intended 16:9 sizing.
564
+ Force the iframe itself to be 16:9 and let height be derived. */
565
+ display: block;
566
+ height: auto !important;
567
+ position: relative;
545
568
  width: 100% !important;
546
- height: 100% !important;
547
569
  }
548
570
 
549
- /* SoundCloud iframe - uses 16:3 aspect ratio for single track audio banner appearance */
571
+ /* SoundCloud iframe - stable height */
550
572
  .vidply-video-wrapper > iframe.vidply-soundcloud-iframe {
573
+ height: clamp(6rem, 18vh, 12rem);
551
574
  width: 100% !important;
552
- aspect-ratio: 16 / 3;
553
- max-height: 100%;
554
575
  }
555
576
 
556
- /* SoundCloud playlist - uses 16:9 aspect ratio to show track list */
577
+ /* SoundCloud playlist - taller variant to show track list */
557
578
  .vidply-video-wrapper > iframe.vidply-soundcloud-iframe.vidply-soundcloud-playlist {
558
- aspect-ratio: 16 / 9;
579
+ height: clamp(12.5rem, 45vh, 28rem);
559
580
  }
560
581
 
561
582
  /* Hide VidPly controls when external renderer (YouTube, Vimeo, SoundCloud) is active */
583
+
562
584
  /* These services have their own native controls */
563
585
  .vidply-player.vidply-external-controls .vidply-controls {
564
586
  display: none !important;
565
587
  }
566
588
 
567
589
  /* Mobile: Simplify video wrapper but keep captions contained */
568
- @media (width < 48rem) {
590
+ @media (width <= 48rem), (width < 48rem) {
569
591
  .vidply-video-wrapper {
570
592
  display: block;
571
593
  height: auto;
@@ -583,30 +605,31 @@
583
605
  /* Ensure video doesn't collapse */
584
606
  .vidply-player video {
585
607
  display: block;
608
+ height: auto !important;
586
609
  position: relative;
587
- width: 100%;
610
+ width: 100%;
588
611
  }
589
612
 
590
613
  /* Override mobile rules in fullscreen mode - critical for iOS */
591
614
  .vidply-player.vidply-fullscreen .vidply-video-wrapper,
592
615
  .vidply-player:fullscreen .vidply-video-wrapper {
616
+ bottom: 0 !important;
593
617
  display: flex !important;
594
618
  height: 100% !important;
619
+ left: 0 !important;
595
620
  min-height: 0 !important;
596
621
  position: absolute !important;
597
- top: 0 !important;
598
- left: 0 !important;
599
622
  right: 0 !important;
600
- bottom: 0 !important;
623
+ top: 0 !important;
601
624
  }
602
625
 
603
626
  .vidply-player.vidply-fullscreen video,
604
627
  .vidply-player:fullscreen video {
628
+ height: 100% !important;
629
+ left: 0 !important;
605
630
  position: absolute !important;
606
631
  top: 0 !important;
607
- left: 0 !important;
608
632
  width: 100% !important;
609
- height: 100% !important;
610
633
  }
611
634
  }
612
635
 
@@ -622,6 +645,8 @@
622
645
 
623
646
  /* Centered Play Button Overlay */
624
647
  .vidply-play-overlay {
648
+ border: 0.125rem solid var(--vidply-primary);
649
+ border-radius: 50%;
625
650
  cursor: pointer;
626
651
  filter: drop-shadow(0 0.5rem 2rem rgb(0 0 0 / 30%));
627
652
  left: 50%;
@@ -630,8 +655,6 @@
630
655
  transform: translate(-50%, -50%);
631
656
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
632
657
  z-index: var(--vidply-z-overlay);
633
- border: 0.125rem solid var(--vidply-primary);
634
- border-radius: 50%;
635
658
  }
636
659
 
637
660
  .vidply-play-overlay:hover {
@@ -683,7 +706,7 @@
683
706
  }
684
707
 
685
708
  /* Mobile: Controls underneath video (but not in landscape fullscreen) */
686
- @media (width < 48rem) {
709
+ @media (width <= 48rem), (width < 48rem) {
687
710
  .vidply-controls {
688
711
  background: var(--vidply-black-90);
689
712
  border-top: 0.0625rem solid var(--vidply-border-light);
@@ -793,22 +816,22 @@
793
816
  color: var(--vidply-white);
794
817
  display: none;
795
818
  font-size: 0.75rem;
819
+ overflow: hidden;
796
820
  padding: 0;
797
821
  pointer-events: none;
798
822
  position: absolute;
799
823
  transform: translateX(-50%);
800
824
  white-space: nowrap;
801
- overflow: hidden;
802
825
  }
803
826
 
804
827
  .vidply-progress-preview {
805
- background-size: cover;
806
828
  background-position: center;
829
+ background-size: cover;
807
830
  border-radius: 0.25rem 0.25rem 0 0;
808
831
  display: none;
809
832
  height: 5rem;
810
- width: 8.888888889rem; /* 160px at 18px base */
811
833
  min-width: 8.888888889rem;
834
+ width: 8.888888889rem; /* 160px at 18px base */
812
835
  }
813
836
 
814
837
  .vidply-progress-tooltip-time {
@@ -1078,7 +1101,7 @@
1078
1101
  }
1079
1102
 
1080
1103
  /* Mobile: Don't use backdrop, menus position above buttons */
1081
- @media (width < 48rem) {
1104
+ @media (width <= 48rem), (width < 48rem) {
1082
1105
  .vidply-menu-backdrop {
1083
1106
  display: none !important;
1084
1107
  }
@@ -1117,6 +1140,11 @@
1117
1140
  }
1118
1141
 
1119
1142
  /* Menu positioned below button */
1143
+ .vidply-menu.vidply-menu-below {
1144
+ bottom: auto;
1145
+ top: calc(100% + 0.5rem);
1146
+ }
1147
+
1120
1148
  .vidply-menu.vidply-menu-below::after {
1121
1149
  border-bottom: 0.375rem solid var(--vidply-bg-menu);
1122
1150
  border-top: none;
@@ -1240,10 +1268,10 @@
1240
1268
  left: auto !important;
1241
1269
  max-width: calc(100vw - 1.25rem);
1242
1270
  right: 0 !important;
1243
- z-index: 1000; /* Ensure menu appears above all player elements including playlist */
1271
+ transform: none !important;
1244
1272
 
1245
1273
  /* Ensure menu stays within viewport */
1246
- transform: none !important;
1274
+ z-index: 1000; /* Ensure menu appears above all player elements including playlist */
1247
1275
  }
1248
1276
 
1249
1277
  /* Overflow menu items with icons */
@@ -1476,7 +1504,7 @@
1476
1504
  }
1477
1505
 
1478
1506
  /* Mobile: Caption positioning handled by JavaScript */
1479
- @media (width < 48rem) {
1507
+ @media (width <= 48rem), (width < 48rem) {
1480
1508
  .vidply-captions {
1481
1509
  /* Bottom position set dynamically by JS based on control height */
1482
1510
  left: 50%;
@@ -1699,15 +1727,15 @@
1699
1727
  background: #000;
1700
1728
  bottom: 0;
1701
1729
  left: 0;
1730
+ margin: 0 !important;
1731
+ padding: 0 !important;
1702
1732
  position: fixed !important;
1703
1733
  right: 0;
1704
- top: 0;
1705
- z-index: 999999;
1706
1734
 
1707
1735
  /* Critical iOS fixes */
1736
+ top: 0;
1708
1737
  transform: translate3d(0, 0, 0);
1709
- margin: 0 !important;
1710
- padding: 0 !important;
1738
+ z-index: 999999;
1711
1739
  }
1712
1740
 
1713
1741
  /* Fix controls in fullscreen LANDSCAPE mode - overlay them on video */
@@ -1880,44 +1908,44 @@
1880
1908
 
1881
1909
  .vidply-player.vidply-fullscreen,
1882
1910
  .vidply-player:fullscreen {
1883
- height: 100vh !important;
1884
- width: 100vw !important;
1885
1911
  display: flex !important;
1886
1912
  flex-direction: column !important;
1913
+ height: 100vh !important;
1914
+ width: 100vw !important;
1887
1915
  }
1888
1916
 
1889
1917
  /* Make video wrapper fill entire screen - positioned absolutely */
1890
1918
  .vidply-player.vidply-fullscreen .vidply-video-wrapper,
1891
1919
  .vidply-player:fullscreen .vidply-video-wrapper {
1892
- position: absolute !important;
1893
- top: 0 !important;
1920
+ align-items: center !important;
1921
+ bottom: 0 !important;
1922
+ display: flex !important;
1923
+ height: 100% !important;
1924
+ justify-content: center !important;
1894
1925
  left: 0 !important;
1926
+ position: absolute !important;
1895
1927
  right: 0 !important;
1896
- bottom: 0 !important;
1928
+ top: 0 !important;
1897
1929
  width: 100% !important;
1898
- height: 100% !important;
1899
1930
  z-index: 1 !important;
1900
- display: flex !important;
1901
- align-items: center !important;
1902
- justify-content: center !important;
1903
1931
  }
1904
1932
 
1905
1933
  .vidply-player.vidply-fullscreen video,
1906
1934
  .vidply-player:fullscreen video {
1907
- position: relative !important;
1908
- width: 100% !important;
1909
1935
  height: 100% !important;
1910
- object-fit: contain !important;
1911
- max-width: 100% !important;
1912
1936
  max-height: 100% !important;
1937
+ max-width: 100% !important;
1938
+ object-fit: contain !important;
1939
+ position: relative !important;
1940
+ width: 100% !important;
1913
1941
  }
1914
1942
 
1915
1943
  .vidply-player.vidply-fullscreen .vidply-controls,
1916
1944
  .vidply-player:fullscreen .vidply-controls {
1917
1945
  /* Position controls at the bottom */
1918
- position: absolute !important;
1919
1946
  bottom: 0 !important;
1920
1947
  left: 0 !important;
1948
+ position: absolute !important;
1921
1949
  right: 0 !important;
1922
1950
  z-index: 30 !important; /* Above playlist */
1923
1951
  }
@@ -1925,12 +1953,12 @@
1925
1953
  /* Force playlist to truly overlay - above video, below controls */
1926
1954
  .vidply-player.vidply-fullscreen .vidply-playlist-panel,
1927
1955
  .vidply-player:fullscreen .vidply-playlist-panel {
1928
- position: absolute !important; /* Absolute relative to player */
1929
1956
  bottom: 5rem !important; /* Above controls (typical control height is ~5rem) */
1930
1957
  left: 0 !important;
1958
+ margin: 0 !important;
1959
+ position: absolute !important; /* Absolute relative to player */
1931
1960
  right: 0 !important;
1932
1961
  z-index: 15 !important; /* Above video (z-index:1), below controls (z-index:30) */
1933
- margin: 0 !important;
1934
1962
  }
1935
1963
  }
1936
1964
 
@@ -2016,7 +2044,7 @@
2016
2044
  }
2017
2045
 
2018
2046
  /* Responsive Breakpoints */
2019
- @media (width < 48rem) {
2047
+ @media (width <= 48rem), (width < 48rem) {
2020
2048
  .vidply-controls {
2021
2049
  padding: 1rem 0.75rem 0.75rem;
2022
2050
  }
@@ -2138,7 +2166,7 @@
2138
2166
  }
2139
2167
 
2140
2168
  /* Landscape mobile optimization */
2141
- @media (width <= 56rem) and (orientation: landscape) {
2169
+ @media (width <= 56rem) and (orientation: landscape), (width <= 56rem) and (orientation: landscape) {
2142
2170
  .vidply-menu {
2143
2171
  max-height: 50vh;
2144
2172
  }
@@ -2156,11 +2184,11 @@
2156
2184
  .vidply-player:fullscreen .vidply-playlist-panel {
2157
2185
  bottom: 4.375rem; /* Directly above controls */
2158
2186
  max-height: 30vh; /* Less height in landscape */
2159
- padding: 0.625rem 0;
2160
- overflow-y: hidden;
2187
+ -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
2161
2188
  overflow-x: auto;
2189
+ overflow-y: hidden;
2190
+ padding: 0.625rem 0;
2162
2191
  touch-action: pan-x; /* Allow horizontal scrolling on touch devices */
2163
- -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
2164
2192
  }
2165
2193
 
2166
2194
  /* Landscape playlist list - horizontal row */
@@ -2175,10 +2203,10 @@
2175
2203
  /* Landscape items - smaller vertical cards */
2176
2204
  .vidply-player.vidply-fullscreen .vidply-playlist-item,
2177
2205
  .vidply-player:fullscreen .vidply-playlist-item {
2178
- width: 11.25rem;
2179
- min-width: 11.25rem;
2180
- max-width: 11.25rem;
2181
2206
  flex-shrink: 0;
2207
+ max-width: 11.25rem;
2208
+ min-width: 11.25rem;
2209
+ width: 11.25rem;
2182
2210
  }
2183
2211
 
2184
2212
  .vidply-player.vidply-fullscreen .vidply-playlist-item-button,
@@ -2190,9 +2218,9 @@
2190
2218
 
2191
2219
  .vidply-player.vidply-fullscreen .vidply-playlist-thumbnail,
2192
2220
  .vidply-player:fullscreen .vidply-playlist-thumbnail {
2221
+ border-radius: 0.5rem 0.5rem 0 0;
2193
2222
  height: 6.25rem;
2194
2223
  width: 100%;
2195
- border-radius: 0.5rem 0.5rem 0 0;
2196
2224
  }
2197
2225
 
2198
2226
  .vidply-player.vidply-fullscreen .vidply-playlist-item-info,
@@ -2202,14 +2230,14 @@
2202
2230
 
2203
2231
  .vidply-player.vidply-fullscreen .vidply-playlist-header,
2204
2232
  .vidply-player:fullscreen .vidply-playlist-header {
2205
- padding: 0 0.625rem 0.5rem;
2206
- font-size: 0.6875rem;
2207
2233
  flex-shrink: 0;
2234
+ font-size: 0.6875rem;
2235
+ padding: 0 0.625rem 0.5rem;
2208
2236
  }
2209
2237
  }
2210
2238
 
2211
2239
  /* Extra small screens */
2212
- @media (width <= 30rem) {
2240
+ @media (width <= 30rem), (width <= 30rem) {
2213
2241
  .vidply-speed-text {
2214
2242
  display: none;
2215
2243
  }
@@ -2255,12 +2283,12 @@
2255
2283
 
2256
2284
  /* Track Artwork - Displays album art/poster above audio player */
2257
2285
  .vidply-track-artwork {
2258
- aspect-ratio: 16 / 3;
2259
2286
  background-color: var(--vidply-black);
2260
2287
  background-position: center;
2261
2288
  background-repeat: no-repeat;
2262
2289
  background-size: cover;
2263
2290
  border-bottom: 0.0625rem solid var(--vidply-border-light);
2291
+ height: clamp(7.5rem, 22vh, 12rem);
2264
2292
  order: 1; /* Before video-wrapper */
2265
2293
  overflow: hidden;
2266
2294
  position: relative;
@@ -2323,15 +2351,15 @@
2323
2351
  }
2324
2352
 
2325
2353
  .vidply-track-description {
2354
+ -webkit-box-orient: vertical;
2326
2355
  color: var(--vidply-white-60);
2356
+ display: -webkit-box;
2327
2357
  font-size: 0.8125rem;
2358
+ -webkit-line-clamp: 2;
2328
2359
  line-height: 1.4;
2329
2360
  margin-top: 0.5rem;
2330
2361
  max-height: 3.5em;
2331
2362
  overflow: hidden;
2332
- display: -webkit-box;
2333
- -webkit-line-clamp: 2;
2334
- -webkit-box-orient: vertical;
2335
2363
  }
2336
2364
 
2337
2365
  /* Playlist Panel */
@@ -2339,7 +2367,6 @@
2339
2367
  background: var(--vidply-bg-playlist);
2340
2368
  border-top: 0.0625rem solid var(--vidply-border-light);
2341
2369
  max-height: 25rem;
2342
- transform: translate3d(0, 0, 0);
2343
2370
  order: 3; /* After track info */
2344
2371
  -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
2345
2372
  overflow-y: auto;
@@ -2349,11 +2376,77 @@
2349
2376
  z-index: var(--vidply-z-base); /* Below menus but part of player stacking context */
2350
2377
  }
2351
2378
 
2379
+ /* iOS Safari fix: Ensure playlist panel doesn't cause overflow issues */
2380
+ @supports (-webkit-touch-callout: none) {
2381
+ /* Remove transform in normal mode that creates stacking context issues on iOS */
2382
+
2383
+ /* The transform was only for hardware acceleration, but causes layout issues */
2384
+
2385
+ /* Fullscreen mode overrides with its own transform, so this is safe */
2386
+ .vidply-playlist-panel {
2387
+ transform: none;
2388
+
2389
+ /* Ensure it's properly positioned in flex layout */
2390
+ flex-shrink: 0;
2391
+
2392
+ /* Remove z-index in normal mode to prevent overlaying content below */
2393
+ z-index: auto;
2394
+
2395
+ /* Ensure it participates in normal document flow */
2396
+ position: relative;
2397
+
2398
+ /* Explicitly set display to ensure it's in flow */
2399
+ display: block;
2400
+ }
2401
+
2402
+ /* Ensure player container properly contains playlist on iOS */
2403
+ .vidply-player.vidply-has-playlist {
2404
+ /* Remove contain: layout to allow container to expand with playlist */
2405
+
2406
+ /* Keep style containment for performance, but allow layout to flow */
2407
+ contain: style;
2408
+
2409
+ /* Don't use isolation as it creates stacking context that causes overlay issues */
2410
+
2411
+ /* Override mobile isolation rule for playlists */
2412
+ isolation: auto;
2413
+
2414
+ /* Ensure container expands to contain all children */
2415
+ min-height: 0;
2416
+
2417
+ /* Ensure height is calculated based on content - override any fixed heights */
2418
+ height: auto !important;
2419
+
2420
+ /* Ensure overflow doesn't clip the playlist */
2421
+ overflow: visible;
2422
+ }
2423
+
2424
+ /* Override mobile isolation for playlists on iOS */
2425
+ @media (width <= 48rem), (width < 48rem) {
2426
+ .vidply-player.vidply-has-playlist {
2427
+ isolation: auto;
2428
+ }
2429
+ }
2430
+
2431
+ /* Ensure playlist panel doesn't overflow container on iOS */
2432
+ .vidply-player.vidply-has-playlist .vidply-playlist-panel {
2433
+ /* Prevent overflow that causes content below to be overlapped */
2434
+ max-width: 100%;
2435
+ width: 100%;
2436
+
2437
+ /* Ensure it's part of the flex layout flow */
2438
+ flex-basis: auto;
2439
+
2440
+ /* Explicitly ensure it's in normal flow */
2441
+ float: none;
2442
+ }
2443
+ }
2444
+
2352
2445
  /* Fullscreen Playlist Panel - YouTube-style overlay above controls */
2353
2446
  .vidply-player.vidply-fullscreen .vidply-playlist-panel,
2354
2447
  .vidply-player:fullscreen .vidply-playlist-panel {
2355
- background: linear-gradient(to top, rgb(0 0 0 / 95%) 0%, rgb(0 0 0 / 90%) 100%);
2356
2448
  backdrop-filter: blur(0.625rem);
2449
+ background: linear-gradient(to top, rgb(0 0 0 / 95%) 0%, rgb(0 0 0 / 90%) 100%);
2357
2450
  border: none;
2358
2451
  border-top: 0.0625rem solid var(--vidply-border);
2359
2452
  bottom: 5rem; /* Directly above controls */
@@ -2395,11 +2488,11 @@
2395
2488
  display: flex;
2396
2489
  flex-direction: row;
2397
2490
  gap: 0.75rem;
2398
- padding: 0.5rem 1rem;
2491
+ -webkit-overflow-scrolling: touch;
2399
2492
  overflow-x: auto;
2400
2493
  overflow-y: hidden;
2494
+ padding: 0.5rem 1rem;
2401
2495
  scroll-snap-type: x mandatory;
2402
- -webkit-overflow-scrolling: touch;
2403
2496
  }
2404
2497
 
2405
2498
  /* Fullscreen playlist header - more subtle */
@@ -2415,28 +2508,28 @@
2415
2508
  .vidply-player.vidply-fullscreen .vidply-playlist-item,
2416
2509
  .vidply-player:fullscreen .vidply-playlist-item {
2417
2510
  flex: 0 0 auto;
2418
- min-width: 17.5rem;
2419
2511
  max-width: 20rem;
2512
+ min-width: 17.5rem;
2420
2513
  scroll-snap-align: start;
2421
2514
  }
2422
2515
 
2423
2516
  .vidply-player.vidply-fullscreen .vidply-playlist-item-button,
2424
2517
  .vidply-player:fullscreen .vidply-playlist-item-button {
2425
- flex-direction: column;
2426
2518
  align-items: stretch;
2427
- gap: 0.5rem;
2428
- padding: 0;
2429
2519
  background: var(--vidply-black-40);
2430
2520
  border-radius: 0.5rem;
2521
+ flex-direction: column;
2522
+ gap: 0.5rem;
2431
2523
  overflow: hidden;
2524
+ padding: 0;
2432
2525
  transition: all 0.2s ease;
2433
2526
  }
2434
2527
 
2435
2528
  .vidply-player.vidply-fullscreen .vidply-playlist-item-button:hover,
2436
2529
  .vidply-player:fullscreen .vidply-playlist-item-button:hover {
2437
2530
  background: var(--vidply-white-10);
2438
- transform: translateY(-0.25rem);
2439
2531
  box-shadow: 0 0.5rem 1.5rem var(--vidply-black-60);
2532
+ transform: translateY(-0.25rem);
2440
2533
  }
2441
2534
 
2442
2535
  /* Fullscreen thumbnail container - takes full width of card */
@@ -2448,9 +2541,9 @@
2448
2541
 
2449
2542
  .vidply-player.vidply-fullscreen .vidply-playlist-thumbnail,
2450
2543
  .vidply-player:fullscreen .vidply-playlist-thumbnail {
2451
- width: 100%;
2452
- height: 10rem;
2453
2544
  border-radius: 0;
2545
+ height: 10rem;
2546
+ width: 100%;
2454
2547
  }
2455
2548
 
2456
2549
  /* Larger duration badge in fullscreen for better visibility */
@@ -2475,15 +2568,15 @@
2475
2568
 
2476
2569
  .vidply-player.vidply-fullscreen .vidply-playlist-item-title,
2477
2570
  .vidply-player:fullscreen .vidply-playlist-item-title {
2571
+ -webkit-box-orient: vertical;
2572
+ display: -webkit-box;
2478
2573
  font-size: 0.875rem;
2479
2574
  font-weight: 600;
2575
+ -webkit-line-clamp: 2;
2480
2576
  margin-bottom: 0.25rem;
2481
- white-space: normal;
2482
2577
  overflow: hidden;
2483
2578
  text-overflow: ellipsis;
2484
- display: -webkit-box;
2485
- -webkit-line-clamp: 2;
2486
- -webkit-box-orient: vertical;
2579
+ white-space: normal;
2487
2580
  }
2488
2581
 
2489
2582
  .vidply-player.vidply-fullscreen .vidply-playlist-item-artist,
@@ -2551,8 +2644,8 @@
2551
2644
  /* Active item styling in fullscreen */
2552
2645
  .vidply-player.vidply-fullscreen .vidply-playlist-item-active .vidply-playlist-item-button,
2553
2646
  .vidply-player:fullscreen .vidply-playlist-item-active .vidply-playlist-item-button {
2554
- border: 0.125rem solid var(--vidply-primary-light);
2555
2647
  background: var(--vidply-primary-15);
2648
+ border: 0.125rem solid var(--vidply-primary-light);
2556
2649
  }
2557
2650
 
2558
2651
  .vidply-player.vidply-fullscreen .vidply-playlist-item-active .vidply-playlist-item-title,
@@ -3615,6 +3708,9 @@
3615
3708
  min-height: 6.25rem;
3616
3709
  overflow: visible; /* Allow menu to overflow */
3617
3710
  position: absolute;
3711
+
3712
+ /* Mobile/touch: make the entire overlay a reliable drag surface (touch-action doesn't inherit) */
3713
+ touch-action: none;
3618
3714
  transition: opacity 0.3s ease;
3619
3715
  width: 17.5rem;
3620
3716
  z-index: 3;
@@ -3644,6 +3740,12 @@
3644
3740
  user-select: none;
3645
3741
  }
3646
3742
 
3743
+ /* iOS/Android: `touch-action` does NOT inherit.
3744
+ Ensure touching any child inside the header still counts as a drag gesture area. */
3745
+ .vidply-sign-language-header * {
3746
+ touch-action: none;
3747
+ }
3748
+
3647
3749
  .vidply-sign-language-header:focus,
3648
3750
  .vidply-sign-language-header:focus-visible {
3649
3751
  box-shadow: 0 0 0 0.25rem rgb(91 144 255 / 35%);
@@ -3801,6 +3903,13 @@
3801
3903
  flex: 1;
3802
3904
  }
3803
3905
 
3906
+ /* Mobile: drag is always available via touch, so hide the keyboard drag mode toggle */
3907
+ @media (width <= 48rem), (width < 48rem) {
3908
+ .vidply-sign-language-settings-item[data-setting="keyboard-drag"] {
3909
+ display: none !important;
3910
+ }
3911
+ }
3912
+
3804
3913
  .vidply-sign-language-header h3 {
3805
3914
  color: var(--vidply-white);
3806
3915
  font-size: var(--vidply-font-lg);
@@ -3861,6 +3970,7 @@
3861
3970
  /* Sign Language Resize Handles */
3862
3971
  .vidply-sign-resize-handle {
3863
3972
  position: absolute;
3973
+ touch-action: none;
3864
3974
  z-index: 10;
3865
3975
  }
3866
3976
 
@@ -4019,7 +4129,7 @@
4019
4129
  }
4020
4130
 
4021
4131
  /* Responsive Sign Language Video */
4022
- @media (width < 48rem) {
4132
+ @media (width <= 48rem), (width < 48rem) {
4023
4133
  .vidply-sign-language-wrapper {
4024
4134
  min-width: 7.5rem;
4025
4135
  width: 35%;
@@ -4032,7 +4142,7 @@
4032
4142
  }
4033
4143
 
4034
4144
  /* Responsive Adjustments */
4035
- @media (width < 48rem) {
4145
+ @media (width <= 48rem), (width < 48rem) {
4036
4146
  .vidply-playlist-thumbnail {
4037
4147
  height: 2.125rem;
4038
4148
  width: 3.75rem;
@@ -4044,7 +4154,7 @@
4044
4154
  }
4045
4155
 
4046
4156
  .vidply-track-artwork {
4047
- aspect-ratio: 16 / 3;
4157
+ height: clamp(6.5rem, 20vh, 10rem);
4048
4158
  }
4049
4159
 
4050
4160
  .vidply-track-info {
@@ -4060,12 +4170,12 @@
4060
4170
  .vidply-player:fullscreen .vidply-playlist-panel {
4061
4171
  bottom: 6.25rem; /* Directly above controls with extra space */
4062
4172
  max-height: 35vh; /* Compact height */
4063
- padding: 0.75rem 0; /* Vertical padding only */
4064
- overflow-y: hidden; /* No vertical scrolling */
4173
+ -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
4065
4174
  overflow-x: auto; /* Horizontal scrolling */
4175
+ overflow-y: hidden; /* No vertical scrolling */
4176
+ padding: 0.75rem 0; /* Vertical padding only */
4066
4177
  position: absolute !important; /* Force absolute over video */
4067
4178
  touch-action: pan-x; /* Allow horizontal scrolling on touch devices */
4068
- -webkit-overflow-scrolling: touch; /* iOS momentum scrolling */
4069
4179
  }
4070
4180
 
4071
4181
  /* Mobile playlist list - horizontal row, no wrapping */
@@ -4074,8 +4184,8 @@
4074
4184
  flex-direction: row; /* Items side by side */
4075
4185
  flex-wrap: nowrap; /* Never wrap */
4076
4186
  gap: 0.5rem;
4077
- padding: 0 0.75rem;
4078
4187
  -webkit-overflow-scrolling: touch;
4188
+ padding: 0 0.75rem;
4079
4189
  scroll-behavior: smooth;
4080
4190
  touch-action: pan-x; /* Ensure horizontal swipe gestures work */
4081
4191
  }
@@ -4083,11 +4193,11 @@
4083
4193
  /* Mobile playlist items - only show thumbnails */
4084
4194
  .vidply-player.vidply-fullscreen .vidply-playlist-item,
4085
4195
  .vidply-player:fullscreen .vidply-playlist-item {
4086
- width: 7.5rem; /* Smaller width for thumbnail-only */
4087
- min-width: 7.5rem;
4088
- max-width: 7.5rem;
4089
4196
  flex-shrink: 0; /* Don't shrink */
4197
+ max-width: 7.5rem;
4198
+ min-width: 7.5rem;
4090
4199
  scroll-snap-align: start;
4200
+ width: 7.5rem; /* Smaller width for thumbnail-only */
4091
4201
  }
4092
4202
 
4093
4203
  .vidply-player.vidply-fullscreen .vidply-playlist-item-button,
@@ -4099,10 +4209,10 @@
4099
4209
 
4100
4210
  .vidply-player.vidply-fullscreen .vidply-playlist-thumbnail,
4101
4211
  .vidply-player:fullscreen .vidply-playlist-thumbnail {
4212
+ border-radius: 0.5rem; /* Fully rounded for thumbnail-only */
4213
+ flex-shrink: 0;
4102
4214
  height: 5.625rem; /* Square-ish thumbnail */
4103
4215
  width: 100%; /* Full width of card */
4104
- flex-shrink: 0;
4105
- border-radius: 0.5rem; /* Fully rounded for thumbnail-only */
4106
4216
  }
4107
4217
 
4108
4218
  /* Hide text info on mobile - show only thumbnails */
@@ -4114,13 +4224,13 @@
4114
4224
  /* If no thumbnail, show only text */
4115
4225
  .vidply-player.vidply-fullscreen .vidply-playlist-item:not(:has(.vidply-playlist-thumbnail)) .vidply-playlist-item-info,
4116
4226
  .vidply-player:fullscreen .vidply-playlist-item:not(:has(.vidply-playlist-thumbnail)) .vidply-playlist-item-info {
4227
+ align-items: center;
4117
4228
  display: flex;
4118
4229
  flex-direction: column;
4119
- padding: 0.5rem;
4230
+ height: 5.625rem;
4120
4231
  justify-content: center;
4121
- align-items: center;
4232
+ padding: 0.5rem;
4122
4233
  text-align: center;
4123
- height: 5.625rem;
4124
4234
  }
4125
4235
 
4126
4236
  .vidply-player.vidply-fullscreen .vidply-playlist-item:not(:has(.vidply-playlist-thumbnail)) .vidply-playlist-item-title,
@@ -4136,9 +4246,9 @@
4136
4246
 
4137
4247
  .vidply-player.vidply-fullscreen .vidply-playlist-header,
4138
4248
  .vidply-player:fullscreen .vidply-playlist-header {
4139
- padding: 0 0.75rem 0.5rem;
4140
- font-size: 0.6875rem;
4141
4249
  flex-shrink: 0;
4250
+ font-size: 0.6875rem;
4251
+ padding: 0 0.75rem 0.5rem;
4142
4252
  }
4143
4253
 
4144
4254
  /* Mobile transcript underneath video and controls */