summaryrefslogtreecommitdiff
path: root/js/videojs/src/css
diff options
context:
space:
mode:
authorLester Caine <lester@lsces.co.uk>2026-05-15 11:33:30 +0100
committerLester Caine <lester@lsces.co.uk>2026-05-15 11:33:30 +0100
commit8bf31bcde496852f35a00b847bb50ba05f5386c9 (patch)
tree97e8f59e767207d673c3a3381b4e69fa6040a966 /js/videojs/src/css
parentdcb7dd852a63d0a84056d3b84e2f05f0b5967900 (diff)
downloadthemes-8bf31bcde496852f35a00b847bb50ba05f5386c9.tar.gz
themes-8bf31bcde496852f35a00b847bb50ba05f5386c9.tar.bz2
themes-8bf31bcde496852f35a00b847bb50ba05f5386c9.zip
Add videojs package to javascript library
Diffstat (limited to 'js/videojs/src/css')
-rw-r--r--js/videojs/src/css/_icons.scss29
-rw-r--r--js/videojs/src/css/_print.scss5
-rw-r--r--js/videojs/src/css/_private-variables.scss22
-rw-r--r--js/videojs/src/css/_utilities.scss81
-rw-r--r--js/videojs/src/css/_variables.scss1
-rw-r--r--js/videojs/src/css/components/_adaptive.scss71
-rw-r--r--js/videojs/src/css/components/_audio.scss19
-rw-r--r--js/videojs/src/css/components/_big-play.scss62
-rw-r--r--js/videojs/src/css/components/_button.scss27
-rw-r--r--js/videojs/src/css/components/_captions-settings.scss121
-rw-r--r--js/videojs/src/css/components/_captions.scss7
-rw-r--r--js/videojs/src/css/components/_chapters.scss7
-rw-r--r--js/videojs/src/css/components/_close-button.scss12
-rw-r--r--js/videojs/src/css/components/_control-bar.scss63
-rw-r--r--js/videojs/src/css/components/_control-spacer.scss3
-rw-r--r--js/videojs/src/css/components/_control.scss45
-rw-r--r--js/videojs/src/css/components/_descriptions.scss7
-rw-r--r--js/videojs/src/css/components/_error.scss4
-rw-r--r--js/videojs/src/css/components/_fullscreen.scss18
-rw-r--r--js/videojs/src/css/components/_layout.scss211
-rw-r--r--js/videojs/src/css/components/_live.scss66
-rw-r--r--js/videojs/src/css/components/_loading.scss100
-rw-r--r--js/videojs/src/css/components/_modal-dialog.scss21
-rw-r--r--js/videojs/src/css/components/_picture-in-picture.scss18
-rw-r--r--js/videojs/src/css/components/_play-pause.scss13
-rw-r--r--js/videojs/src/css/components/_playback-rate.scss21
-rw-r--r--js/videojs/src/css/components/_poster.scss32
-rw-r--r--js/videojs/src/css/components/_progress.scss192
-rw-r--r--js/videojs/src/css/components/_skip-buttons.scss40
-rw-r--r--js/videojs/src/css/components/_slider.scss25
-rw-r--r--js/videojs/src/css/components/_subs-caps.scss36
-rw-r--r--js/videojs/src/css/components/_subtitles.scss3
-rw-r--r--js/videojs/src/css/components/_text-track.scss57
-rw-r--r--js/videojs/src/css/components/_time.scss25
-rw-r--r--js/videojs/src/css/components/_title-bar.scss46
-rw-r--r--js/videojs/src/css/components/_transient-button.scss48
-rw-r--r--js/videojs/src/css/components/_volume.scss268
-rw-r--r--js/videojs/src/css/components/menu/_menu-inline.scss48
-rw-r--r--js/videojs/src/css/components/menu/_menu-popup.scss49
-rw-r--r--js/videojs/src/css/components/menu/_menu.scss80
-rw-r--r--js/videojs/src/css/utilities/_linear-gradient.scss93
-rw-r--r--js/videojs/src/css/video-js.scss68
-rw-r--r--js/videojs/src/css/vjs-cdn.scss3
-rw-r--r--js/videojs/src/css/vjs.scss1
44 files changed, 2168 insertions, 0 deletions
diff --git a/js/videojs/src/css/_icons.scss b/js/videojs/src/css/_icons.scss
new file mode 100644
index 0000000..fc0f974
--- /dev/null
+++ b/js/videojs/src/css/_icons.scss
@@ -0,0 +1,29 @@
+// CSS styles for SVG icons used throughout video.js.
+//
+// The goal is to replace all icons from the font family pulled from videojs/font entirely.
+// This project currently uses fonts. We want to replace this with SVGs from
+// images/icons.svg. This will ensure consitency between versions, as well as simplified
+// and straight-forward customization.
+
+// Default styling for all SVG icons
+.vjs-svg-icon {
+ display: inline-block;
+ background-repeat: no-repeat;
+ background-position: center;
+
+ fill: currentColor;
+ height: 1.8em;
+ width: 1.8em;
+
+ // Overwrite any font content
+ &:before {
+ content: none !important;
+ }
+}
+
+// SVG shadow on hover and focus
+.vjs-svg-icon:hover,
+.vjs-control:focus .vjs-svg-icon {
+ -webkit-filter: drop-shadow(0 0 0.25em #fff);
+ filter: drop-shadow(0 0 0.25em #fff);
+}
diff --git a/js/videojs/src/css/_print.scss b/js/videojs/src/css/_print.scss
new file mode 100644
index 0000000..7a10c4e
--- /dev/null
+++ b/js/videojs/src/css/_print.scss
@@ -0,0 +1,5 @@
+@media print {
+ .video-js > *:not(.vjs-tech):not(.vjs-poster) {
+ visibility:hidden;
+ }
+}
diff --git a/js/videojs/src/css/_private-variables.scss b/js/videojs/src/css/_private-variables.scss
new file mode 100644
index 0000000..46d7e55
--- /dev/null
+++ b/js/videojs/src/css/_private-variables.scss
@@ -0,0 +1,22 @@
+@use "sass:color";
+
+// Text, icons, hover states
+$primary-foreground-color: #fff !default;
+
+// Control backgrounds (control bar, big play, menus)
+$primary-background-color: #2B333F !default;
+$primary-background-transparency: 0.7 !default;
+
+// Hover states, slider backgrounds
+$secondary-background-color: color.adjust($primary-background-color, $lightness: 33%, $space: hsl) !default;
+$secondary-background-transparency: 0.5 !default;
+
+// Avoiding helvetica: issue #376
+$text-font-family: Arial, Helvetica, sans-serif !default;
+
+// Using the '--' naming for component-specific styles
+$big-play-button--border-size: 0.06666em !default;
+$big-play-button--width: 3em !default;
+$big-play-button--line-height: 1.5em !default;
+$big-play-button--height: $big-play-button--line-height + ($big-play-button--border-size * 2) !default;
+$big-play-button--transparency: 0.8 !default;
diff --git a/js/videojs/src/css/_utilities.scss b/js/videojs/src/css/_utilities.scss
new file mode 100644
index 0000000..7dd1cce
--- /dev/null
+++ b/js/videojs/src/css/_utilities.scss
@@ -0,0 +1,81 @@
+@import "utilities/linear-gradient";
+
+@mixin background-color-with-alpha($color, $alpha) {
+ background-color: $color;
+ background-color: rgba($color, $alpha);
+}
+
+@mixin transform($transform) {
+ transform: $transform;
+}
+
+@mixin transition($string: $transition--default) {
+ transition: $string;
+}
+
+@mixin hide-visually {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+@mixin border-radius($radius) {
+ border-radius: $radius;
+}
+
+@mixin animation($string: spin 1s infinite linear) {
+ animation: $string;
+}
+
+@mixin display-flex($alignment: '', $justification: '') {
+ display: flex;
+
+ @if $alignment != '' {
+ align-items: $alignment;
+ }
+
+ @if $justification != '' {
+ justify-content: $justification;
+ }
+}
+
+@mixin flex($value) {
+ flex: $value;
+}
+
+// https://developer.mozilla.org/en-US/docs/Web/CSS/user-select
+// https://stackoverflow.com/questions/826782/how-to-disable-text-selection-highlighting-using-css (version: January, 2017)
+@mixin user-select($string: none) {
+ /* iOS Safari */
+ -webkit-touch-callout: $string;
+ /* Safari, and Chrome 53 */
+ -webkit-user-select: $string;
+ /* Non-prefixed version, currently supported by Chrome and Opera */
+ user-select: $string;
+}
+
+// https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow
+@mixin box-shadow ($string: 0 0 1em rgba(0, 0, 0, 0.25)) {
+ box-shadow: $string;
+}
+
+@mixin order($value) {
+ order: $value;
+}
+
+%fill-parent {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+%icon-default {
+ @extend %fill-parent;
+ text-align: center;
+}
diff --git a/js/videojs/src/css/_variables.scss b/js/videojs/src/css/_variables.scss
new file mode 100644
index 0000000..0ed69c2
--- /dev/null
+++ b/js/videojs/src/css/_variables.scss
@@ -0,0 +1 @@
+$icon-font-path: 'font' !default;
diff --git a/js/videojs/src/css/components/_adaptive.scss b/js/videojs/src/css/components/_adaptive.scss
new file mode 100644
index 0000000..8977438
--- /dev/null
+++ b/js/videojs/src/css/components/_adaptive.scss
@@ -0,0 +1,71 @@
+// When the player is "medium" and higher, display everything by default.
+//
+// When the player is "small", display only:
+// - Play button
+// - Volume Mute button
+// - Progress bar
+// - Track buttons
+// - Native PiP button
+// - Fullscreen button
+//
+// When the player is "x-small", display only:
+// - Play button
+// - Volume Mute button
+// - Spacer
+// - Track buttons
+// - Native PiP button
+// - Fullscreen button
+//
+// When the player is "tiny", display only:
+// - Play button
+// - Volume Mute button
+// - Track buttons
+// - Native PiP button
+// - Fullscreen Button
+//
+.video-js {
+
+ &.vjs-layout-small,
+ &.vjs-layout-x-small,
+ &.vjs-layout-tiny {
+ .vjs-current-time,
+ .vjs-time-divider,
+ .vjs-duration,
+ .vjs-remaining-time,
+ .vjs-playback-rate,
+ .vjs-volume-control {
+ display: none;
+ }
+
+ // Reset the size of the volume panel to the default so we don't see a big
+ // empty space to the right of the mute button.
+ .vjs-volume-panel.vjs-volume-panel-horizontal {
+ &:hover,
+ &:active,
+ &.vjs-slider-active,
+ &.vjs-hover {
+ width: auto;
+ width: initial;
+ }
+ }
+ }
+
+ // At x-small and tiny, the progress control is too narrow to be useful.
+ &.vjs-layout-x-small,
+ &.vjs-layout-tiny {
+
+ .vjs-progress-control {
+ display: none;
+ }
+ }
+
+ // At x-small, the buttons alone leave a large gap on the right. Fill it with
+ // the spacer element.
+ &.vjs-layout-x-small {
+
+ .vjs-custom-control-spacer {
+ @include flex(auto);
+ display: block;
+ }
+ }
+}
diff --git a/js/videojs/src/css/components/_audio.scss b/js/videojs/src/css/components/_audio.scss
new file mode 100644
index 0000000..3f7d703
--- /dev/null
+++ b/js/videojs/src/css/components/_audio.scss
@@ -0,0 +1,19 @@
+.video-js .vjs-audio-button .vjs-icon-placeholder {
+ @extend .vjs-icon-audio;
+}
+
+.video-js .vjs-audio-button + .vjs-menu .vjs-descriptions-menu-item .vjs-menu-item-text .vjs-icon-placeholder,
+.video-js .vjs-audio-button + .vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder {
+ vertical-align: middle;
+ display: inline-block;
+ margin-bottom: -0.1em;
+}
+
+// Mark a main-desc-menu-item (main + description) or description item with a trailing Audio Description icon
+.video-js .vjs-audio-button + .vjs-menu .vjs-descriptions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before,
+.video-js .vjs-audio-button + .vjs-menu .vjs-main-desc-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before {
+ font-family: VideoJS;
+ content: " \f12e";
+ font-size: 1.5em;
+ line-height: inherit;
+}
diff --git a/js/videojs/src/css/components/_big-play.scss b/js/videojs/src/css/components/_big-play.scss
new file mode 100644
index 0000000..7af937a
--- /dev/null
+++ b/js/videojs/src/css/components/_big-play.scss
@@ -0,0 +1,62 @@
+@use "sass:math";
+
+.video-js .vjs-big-play-button {
+ font-size: 3em;
+ line-height: $big-play-button--line-height;
+ height: $big-play-button--height;
+ width: $big-play-button--width; // Firefox bug: For some reason without width the icon wouldn't show up. Switched to using width and removed padding.
+ display: block;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ padding: 0;
+ margin-top: -(math.div($big-play-button--height, 2));
+ margin-left: -(math.div($big-play-button--width, 2));
+ cursor: pointer;
+ opacity: 1;
+ border: $big-play-button--border-size solid $primary-foreground-color;
+
+ // Need a slightly gray bg so it can be seen on black backgrounds
+ @include background-color-with-alpha($primary-background-color, $primary-background-transparency);
+ @include border-radius(0.3em);
+ @include transition(all 0.4s);
+
+ // Since the big play button doesn't inherit from vjs-control, we need to specify a bit more than
+ // other buttons for the icon.
+ & .vjs-icon-placeholder:before {
+ @extend .vjs-icon-play;
+
+ @extend %icon-default;
+ }
+}
+
+.vjs-big-play-button .vjs-svg-icon {
+ width: 1em;
+ height: 1em;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ line-height: 1;
+ transform: translate(-50%, -50%);
+}
+
+.video-js:hover .vjs-big-play-button,
+.video-js .vjs-big-play-button:focus {
+ border-color: $primary-foreground-color;
+
+ @include background-color-with-alpha($secondary-background-color, $secondary-background-transparency);
+ @include transition(all 0s);
+}
+
+// Hide if controls are disabled, the video is playing, or native controls are used.
+.vjs-controls-disabled .vjs-big-play-button,
+.vjs-has-started .vjs-big-play-button,
+.vjs-using-native-controls .vjs-big-play-button,
+.vjs-error .vjs-big-play-button {
+ display: none;
+}
+
+// Show big play button if video is paused and .vjs-show-big-play-button-on-pause is set on video element
+.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause:not(.vjs-seeking, .vjs-scrubbing, .vjs-error) .vjs-big-play-button {
+ display: block;
+}
diff --git a/js/videojs/src/css/components/_button.scss b/js/videojs/src/css/components/_button.scss
new file mode 100644
index 0000000..e14a921
--- /dev/null
+++ b/js/videojs/src/css/components/_button.scss
@@ -0,0 +1,27 @@
+.video-js button {
+ background: none;
+ border: none;
+ color: inherit;
+ display: inline-block;
+
+ font-size: inherit; // IE in general. WTF.
+ line-height: inherit;
+ text-transform: none;
+ text-decoration: none;
+ transition: none;
+
+ // Chrome < 83
+ -webkit-appearance: none;
+ appearance: none;
+}
+
+// Replacement for focus in case spatial navigation is enabled
+.video-js.vjs-spatial-navigation-enabled .vjs-button:focus {
+ outline: 0.0625em solid rgba($primary-foreground-color, 1);
+ box-shadow: none;
+}
+
+.vjs-control .vjs-button {
+ width: 100%;
+ height: 100%;
+}
diff --git a/js/videojs/src/css/components/_captions-settings.scss b/js/videojs/src/css/components/_captions-settings.scss
new file mode 100644
index 0000000..29c7bfd
--- /dev/null
+++ b/js/videojs/src/css/components/_captions-settings.scss
@@ -0,0 +1,121 @@
+.vjs-modal-dialog.vjs-text-track-settings {
+ background-color: $primary-background-color;
+ background-color: rgba($primary-background-color, 0.75);
+ color: $primary-foreground-color;
+ height: 70%;
+
+ // When Spatial Navigation is enabled
+ .vjs-spatial-navigation-enabled & {
+ height: 80%;
+ }
+}
+
+// Hide if an error occurs
+.vjs-error .vjs-text-track-settings {
+ display: none;
+}
+
+// Layout divs
+.vjs-text-track-settings .vjs-modal-dialog-content {
+ display: table;
+}
+
+.vjs-text-track-settings .vjs-track-settings-colors,
+.vjs-text-track-settings .vjs-track-settings-font,
+.vjs-text-track-settings .vjs-track-settings-controls {
+ display: table-cell;
+}
+
+.vjs-text-track-settings .vjs-track-settings-controls {
+ text-align: right;
+ vertical-align: bottom;
+}
+
+// code that will only run if CSS Grid is supported by the browser
+@supports (display: grid) {
+ .vjs-text-track-settings .vjs-modal-dialog-content {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: 1fr;
+ // Flex and Grid for Firefox, IE, and Edge remove the bottom padding/margin in a container as size decreases
+ // so we add bottom padding/margin to the last item in the grid instead of here
+ // see https://stackoverflow.com/a/23754080
+ padding: 20px 24px 0px 24px;
+ }
+
+ // see the comment for padding above
+ .vjs-track-settings-controls .vjs-default-button {
+ margin-bottom: 20px;
+ }
+
+ .vjs-text-track-settings .vjs-track-settings-controls {
+ // make this take up both columns
+ grid-column: 1 / -1;
+ }
+
+ // 1 column for small players
+ .vjs-layout-small .vjs-text-track-settings .vjs-modal-dialog-content ,
+ .vjs-layout-x-small .vjs-text-track-settings .vjs-modal-dialog-content,
+ .vjs-layout-tiny .vjs-text-track-settings .vjs-modal-dialog-content {
+ grid-template-columns: 1fr;
+ }
+
+}
+
+// Form elements
+.vjs-text-track-settings select {
+ font-size: inherit;
+}
+
+.vjs-track-setting > select {
+ margin-right: 1em;
+ margin-bottom: 0.5em;
+}
+
+.vjs-text-track-settings fieldset {
+ margin: 10px;
+ border: none;
+}
+
+.vjs-text-track-settings fieldset span {
+ display: inline-block;
+ padding: 0 .6em .8em;
+}
+
+// style the second select for text colors
+.vjs-text-track-settings fieldset span > select {
+ max-width: 7.3em;
+}
+
+.vjs-text-track-settings legend {
+ color: $primary-foreground-color;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+.vjs-text-track-settings .vjs-label {
+ margin: 0 .5em .5em 0;
+}
+
+.vjs-track-settings-controls button:focus,
+.vjs-track-settings-controls button:active {
+ outline-style: solid;
+ outline-width: medium;
+ background-image: linear-gradient(0deg, $primary-foreground-color 88%, $secondary-background-color 100%);
+}
+
+.vjs-track-settings-controls button:hover {
+ color: rgba(#2B333F, 0.75);
+}
+
+.vjs-track-settings-controls button {
+ background-color: $primary-foreground-color;
+ background-image: linear-gradient(-180deg, $primary-foreground-color 88%, $secondary-background-color 100%);
+ color: #2B333F;
+ cursor: pointer;
+ border-radius: 2px;
+}
+
+.vjs-track-settings-controls .vjs-default-button {
+ margin-right: 1em;
+}
diff --git a/js/videojs/src/css/components/_captions.scss b/js/videojs/src/css/components/_captions.scss
new file mode 100644
index 0000000..8cffef9
--- /dev/null
+++ b/js/videojs/src/css/components/_captions.scss
@@ -0,0 +1,7 @@
+.video-js .vjs-captions-button .vjs-icon-placeholder {
+ @extend .vjs-icon-captions;
+}
+
+.video-js.vjs-audio-only-mode .vjs-captions-button {
+ display: none;
+}
diff --git a/js/videojs/src/css/components/_chapters.scss b/js/videojs/src/css/components/_chapters.scss
new file mode 100644
index 0000000..7eab3e8
--- /dev/null
+++ b/js/videojs/src/css/components/_chapters.scss
@@ -0,0 +1,7 @@
+.video-js .vjs-chapters-button .vjs-icon-placeholder {
+ @extend .vjs-icon-chapters;
+}
+
+.vjs-chapters-button .vjs-menu ul {
+ width: 24em;
+}
diff --git a/js/videojs/src/css/components/_close-button.scss b/js/videojs/src/css/components/_close-button.scss
new file mode 100644
index 0000000..07193e7
--- /dev/null
+++ b/js/videojs/src/css/components/_close-button.scss
@@ -0,0 +1,12 @@
+.video-js .vjs-control.vjs-close-button {
+ cursor: pointer;
+ height: 3em;
+ position: absolute;
+ right: 0;
+ top: 0.5em;
+ z-index: 2;
+
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-cancel;
+ }
+}
diff --git a/js/videojs/src/css/components/_control-bar.scss b/js/videojs/src/css/components/_control-bar.scss
new file mode 100644
index 0000000..3679539
--- /dev/null
+++ b/js/videojs/src/css/components/_control-bar.scss
@@ -0,0 +1,63 @@
+.video-js .vjs-control-bar {
+ display: none;
+ width: 100%;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 3.0em;
+
+ @include background-color-with-alpha($primary-background-color, $primary-background-transparency);
+}
+
+.video-js.vjs-spatial-navigation-enabled .vjs-control-bar {
+ gap: 1px;
+}
+
+// Locks the display only if:
+// - controls are not disabled
+// - native controls are not used
+// - there is no error
+.video-js:not(.vjs-controls-disabled, .vjs-using-native-controls, .vjs-error) .vjs-control-bar.vjs-lock-showing {
+ display: flex !important;
+}
+
+// Video has started playing or we are in audioOnlyMode
+.vjs-has-started .vjs-control-bar,
+.vjs-audio-only-mode .vjs-control-bar {
+ @include display-flex;
+ visibility: visible;
+ opacity: 1;
+
+ $trans: visibility 0.1s, opacity 0.1s; // Var needed because of comma
+ @include transition($trans);
+}
+
+// Video has started playing AND user is inactive
+.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
+ // Remain visible for screen reader and keyboard users
+ visibility: visible;
+ opacity: 0;
+ // prevent a click/tap from interacting with vjs-lock-showing menu's
+ // or other controls while we are inactive/hidden
+ pointer-events: none;
+
+ $trans: visibility 1.0s, opacity 1.0s;
+ @include transition($trans);
+
+}
+
+.vjs-controls-disabled .vjs-control-bar,
+.vjs-using-native-controls .vjs-control-bar,
+.vjs-error .vjs-control-bar {
+ // !important is ok in this context.
+ display: none !important;
+}
+
+// Don't hide the control bar if it's audio or in audioOnlyMode
+.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar,
+.vjs-audio-only-mode.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
+ opacity: 1;
+ visibility: visible;
+ pointer-events: auto;
+}
diff --git a/js/videojs/src/css/components/_control-spacer.scss b/js/videojs/src/css/components/_control-spacer.scss
new file mode 100644
index 0000000..010751b
--- /dev/null
+++ b/js/videojs/src/css/components/_control-spacer.scss
@@ -0,0 +1,3 @@
+.video-js .vjs-custom-control-spacer {
+ display: none;
+}
diff --git a/js/videojs/src/css/components/_control.scss b/js/videojs/src/css/components/_control.scss
new file mode 100644
index 0000000..6dd7b6b
--- /dev/null
+++ b/js/videojs/src/css/components/_control.scss
@@ -0,0 +1,45 @@
+// vjs-control might be better named vjs-button now.
+// It's used on both real buttons (play button)
+// and div buttons (menu buttons)
+.video-js .vjs-control {
+ position: relative;
+ text-align: center;
+ margin: 0;
+ padding: 0;
+ height: 100%;
+ width: 4em;
+ @include flex(none);
+}
+
+.video-js .vjs-control.vjs-visible-text {
+ width: auto;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+.vjs-button > .vjs-icon-placeholder:before {
+ font-size: 1.8em;
+ line-height: 1.67;
+
+ @extend %icon-default;
+}
+
+.vjs-button > .vjs-icon-placeholder {
+ display: block;
+}
+
+.vjs-button > .vjs-svg-icon {
+ display: inline-block;
+}
+
+// Replacement for focus outline
+.video-js .vjs-control:focus:before,
+.video-js .vjs-control:hover:before,
+.video-js .vjs-control:focus {
+ text-shadow: 0em 0em 1em rgba($primary-foreground-color, 1);
+}
+
+// Hide control text visually, but have it available for screenreaders
+.video-js *:not(.vjs-visible-text) > .vjs-control-text {
+ @include hide-visually;
+}
diff --git a/js/videojs/src/css/components/_descriptions.scss b/js/videojs/src/css/components/_descriptions.scss
new file mode 100644
index 0000000..9cf8d95
--- /dev/null
+++ b/js/videojs/src/css/components/_descriptions.scss
@@ -0,0 +1,7 @@
+.video-js .vjs-descriptions-button .vjs-icon-placeholder {
+ @extend .vjs-icon-audio-description;
+}
+
+.video-js.vjs-audio-only-mode .vjs-descriptions-button {
+ display: none;
+}
diff --git a/js/videojs/src/css/components/_error.scss b/js/videojs/src/css/components/_error.scss
new file mode 100644
index 0000000..118e262
--- /dev/null
+++ b/js/videojs/src/css/components/_error.scss
@@ -0,0 +1,4 @@
+.vjs-error .vjs-error-display .vjs-modal-dialog-content {
+ font-size: 1.4em;
+ text-align: center;
+}
diff --git a/js/videojs/src/css/components/_fullscreen.scss b/js/videojs/src/css/components/_fullscreen.scss
new file mode 100644
index 0000000..f682341
--- /dev/null
+++ b/js/videojs/src/css/components/_fullscreen.scss
@@ -0,0 +1,18 @@
+.video-js .vjs-fullscreen-control {
+ cursor: pointer;
+ @include flex(none);
+
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-fullscreen-enter;
+ }
+}
+
+.video-js.vjs-audio-only-mode .vjs-fullscreen-control,
+.vjs-pip-window .vjs-fullscreen-control {
+ display: none;
+}
+
+// Switch to the exit icon when the player is in fullscreen
+.video-js.vjs-fullscreen .vjs-fullscreen-control .vjs-icon-placeholder {
+ @extend .vjs-icon-fullscreen-exit;
+}
diff --git a/js/videojs/src/css/components/_layout.scss b/js/videojs/src/css/components/_layout.scss
new file mode 100644
index 0000000..fdf9d25
--- /dev/null
+++ b/js/videojs/src/css/components/_layout.scss
@@ -0,0 +1,211 @@
+@use "sass:math";
+
+.video-js {
+ display: inline-block;
+ // Make video.js videos align top when next to video elements
+ vertical-align: top;
+ box-sizing: border-box;
+
+ color: $primary-foreground-color;
+ background-color: #000;
+ position: relative;
+ padding: 0;
+ // Start with 10px for base font size so other dimensions can be em based and
+ // easily calculable.
+ font-size: 10px;
+ line-height: 1;
+
+ // Provide some basic defaults for fonts
+ font-weight: normal;
+ font-style: normal;
+ // Avoiding helvetica: issue #376
+ font-family: $text-font-family;
+
+ // reset word-break inside the player div
+ word-break: initial;
+
+ // Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
+ // checking fullScreenEnabled.
+ &:-moz-full-screen { position: absolute; }
+
+ &:-webkit-full-screen {
+ width: 100% !important;
+ height: 100% !important;
+ }
+}
+
+.video-js[tabindex="-1"] {
+ outline: none;
+}
+
+// All elements inherit border-box sizing
+.video-js *,
+.video-js *:before,
+.video-js *:after {
+ box-sizing: inherit;
+}
+
+// List style reset
+.video-js ul {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ list-style-position: outside;
+
+ // Important to specify each
+ margin-left: 0;
+ margin-right: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+// Fill the width of the containing element and use padding to create the
+// desired aspect ratio. Default to 16x9 unless another ratio is given.
+@mixin apply-aspect-ratio($width, $height) {
+ padding-top: 100% * math.div($height, $width);
+}
+
+// Not including a default AR in vjs-fluid because it would override
+// the user set AR injected into the header.
+.video-js.vjs-fluid,
+.video-js.vjs-16-9,
+.video-js.vjs-4-3,
+.video-js.vjs-9-16,
+.video-js.vjs-1-1 {
+ width: 100%;
+ max-width: 100%;
+}
+
+.video-js.vjs-fluid:not(.vjs-audio-only-mode),
+.video-js.vjs-16-9:not(.vjs-audio-only-mode),
+.video-js.vjs-4-3:not(.vjs-audio-only-mode),
+.video-js.vjs-9-16:not(.vjs-audio-only-mode),
+.video-js.vjs-1-1:not(.vjs-audio-only-mode) {
+ height: 0;
+}
+
+.video-js.vjs-16-9:not(.vjs-audio-only-mode) {
+ @include apply-aspect-ratio(16, 9);
+}
+
+.video-js.vjs-4-3:not(.vjs-audio-only-mode) {
+ @include apply-aspect-ratio(4, 3);
+}
+
+.video-js.vjs-9-16:not(.vjs-audio-only-mode) {
+ @include apply-aspect-ratio(9, 16);
+}
+
+.video-js.vjs-1-1:not(.vjs-audio-only-mode) {
+ @include apply-aspect-ratio(1, 1);
+}
+
+.video-js.vjs-fill:not(.vjs-audio-only-mode) {
+ width: 100%;
+ height: 100%;
+}
+
+// Playback technology elements expand to the width/height of the containing div
+// <video> or <object>
+.video-js .vjs-tech {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.video-js.vjs-audio-only-mode .vjs-tech {
+ display: none;
+}
+
+// Fullscreen and Document Picture-in-Picture Styles
+body.vjs-full-window,
+body.vjs-pip-window {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+}
+.vjs-full-window .video-js.vjs-fullscreen,
+body.vjs-pip-window .video-js {
+ position: fixed;
+ overflow: hidden;
+ z-index: 1000;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ right: 0;
+}
+.video-js.vjs-fullscreen:not(.vjs-ios-native-fs),
+body.vjs-pip-window .video-js {
+ width: 100% !important;
+ height: 100% !important;
+ // Undo any aspect ratio padding for fluid layouts
+ padding-top: 0 !important;
+ // Older Safari (<= 15.6) needs display: block in fullscreen.
+ display: block;
+}
+
+.video-js.vjs-fullscreen.vjs-user-inactive {
+ cursor: none;
+}
+
+.vjs-pip-container .vjs-pip-text {
+ position: absolute;
+ bottom: 10%;
+ font-size: 2em;
+ background-color: rgba(0, 0, 0, .7);
+ padding: .5em;
+ text-align: center;
+ width: 100%
+}
+
+.vjs-layout-tiny.vjs-pip-container .vjs-pip-text,
+.vjs-layout-x-small.vjs-pip-container .vjs-pip-text,
+.vjs-layout-small.vjs-pip-container .vjs-pip-text {
+ bottom: 0;
+ font-size: 1.4em;
+}
+
+
+// Hide disabled or unsupported controls.
+.vjs-hidden { display: none !important; }
+
+.vjs-disabled {
+ opacity: 0.5;
+ cursor: default;
+}
+
+// Visually hidden offscreen, but accessible to screen readers.
+.video-js .vjs-offscreen {
+ height: 1px;
+ left: -9999px;
+ position: absolute;
+ top: 0;
+ width: 1px;
+}
+
+.vjs-lock-showing {
+ display: block !important;
+ opacity: 1 !important;
+ visibility: visible !important;
+}
+
+// This optional paragraph inside the video tag can provide a message to users
+// about what's required to play video when JavaScript is disabled
+.vjs-no-js {
+ padding: 20px;
+ color: #fff;
+ background-color: #000;
+ font-size: 18px;
+ font-family: $text-font-family;
+ text-align: center;
+ width: 300px;
+ height: 150px;
+ margin: 0px auto;
+}
+
+.vjs-no-js a,
+.vjs-no-js a:visited {
+ color: #66A8CC;
+}
diff --git a/js/videojs/src/css/components/_live.scss b/js/videojs/src/css/components/_live.scss
new file mode 100644
index 0000000..a0a5d46
--- /dev/null
+++ b/js/videojs/src/css/components/_live.scss
@@ -0,0 +1,66 @@
+// css for the old live ui, assumes that the progress bar is hidden
+.video-js .vjs-live-control {
+ @include display-flex(flex-start);
+ @include flex(auto);
+ font-size: 1em;
+ line-height: 3em;
+}
+
+// hide the LiveDisplay when not live or when
+// the new liveui is in use
+.video-js:not(.vjs-live) .vjs-live-control,
+.video-js.vjs-liveui .vjs-live-control {
+ display: none;
+}
+
+// css for the new live ui below
+.video-js .vjs-seek-to-live-control {
+ align-items: center;
+ cursor: pointer;
+ @include flex(none);
+ display: inline-flex;
+ height: 100%;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ font-size: 1em;
+ line-height: 3em;
+ width: auto;
+ min-width: 4em;
+}
+
+// hide the SeekToLive button when not live and
+// when the liveui is not in use
+.video-js.vjs-live:not(.vjs-liveui) .vjs-seek-to-live-control,
+.video-js:not(.vjs-live) .vjs-seek-to-live-control {
+ display: none;
+}
+
+// only show as a pointer when we will seek to live edge
+.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge {
+ cursor: auto;
+}
+
+.vjs-seek-to-live-control .vjs-icon-placeholder {
+ margin-right: 0.5em;
+ @extend .vjs-icon-circle;
+ color: #888;
+}
+
+.vjs-svg-icons-enabled .vjs-seek-to-live-control {
+ line-height: 0;
+}
+
+.vjs-seek-to-live-control .vjs-svg-icon {
+ width: 1em;
+ height: 1em;
+ pointer-events: none;
+ fill: #888888;
+}
+
+// make the live circle red when at the live edge
+.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-icon-placeholder {
+ color: red;
+}
+.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-svg-icon {
+ fill: red;
+}
diff --git a/js/videojs/src/css/components/_loading.scss b/js/videojs/src/css/components/_loading.scss
new file mode 100644
index 0000000..e9b82bf
--- /dev/null
+++ b/js/videojs/src/css/components/_loading.scss
@@ -0,0 +1,100 @@
+.vjs-loading-spinner {
+ display: none;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ opacity: 0.85;
+
+ // Need to fix centered page layouts
+ text-align: left;
+
+ border: .6em solid rgba($primary-background-color, $primary-background-transparency);
+ // border: 6px solid rgba(43, 51, 63, 0.5);
+
+ box-sizing: border-box;
+ background-clip: padding-box;
+ width: 5em;
+ height: 5em;
+ border-radius: 50%;
+ visibility: hidden;
+}
+
+.vjs-seeking .vjs-loading-spinner,
+.vjs-waiting .vjs-loading-spinner {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ // add a delay before actual show the spinner
+ animation: vjs-spinner-show 0s linear 0.3s forwards;
+}
+
+// Hide if an error occurs
+.vjs-error .vjs-loading-spinner {
+ display: none;
+}
+
+.vjs-loading-spinner:before,
+.vjs-loading-spinner:after {
+ content: "";
+ position: absolute;
+ box-sizing: inherit;
+ width: inherit;
+ height: inherit;
+ border-radius: inherit;
+ // Keep 100% opacity so they don't show through each other
+ opacity: 1;
+ border: inherit;
+ border-color: transparent;
+ border-top-color: white;
+}
+
+// only animate when showing because it can be processor heavy
+.vjs-seeking .vjs-loading-spinner:before,
+.vjs-seeking .vjs-loading-spinner:after,
+.vjs-waiting .vjs-loading-spinner:before,
+.vjs-waiting .vjs-loading-spinner:after {
+ animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite;
+}
+
+.vjs-seeking .vjs-loading-spinner:before,
+.vjs-waiting .vjs-loading-spinner:before {
+ border-top-color: rgb(255,255,255);
+}
+
+.vjs-seeking .vjs-loading-spinner:after,
+.vjs-waiting .vjs-loading-spinner:after {
+ border-top-color: rgb(255,255,255);
+ animation-delay: 0.44s;
+}
+
+@keyframes vjs-spinner-show {
+ to {
+ visibility: visible;
+ }
+}
+
+@keyframes vjs-spinner-spin {
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+@keyframes vjs-spinner-fade {
+ 0% {
+ border-top-color: $secondary-background-color;
+ }
+ 20% {
+ border-top-color: $secondary-background-color;
+ }
+ 35% {
+ border-top-color: white;
+ }
+ 60% {
+ border-top-color: $secondary-background-color;
+ }
+ 100% {
+ border-top-color: $secondary-background-color;
+ }
+}
diff --git a/js/videojs/src/css/components/_modal-dialog.scss b/js/videojs/src/css/components/_modal-dialog.scss
new file mode 100644
index 0000000..0c88c5b
--- /dev/null
+++ b/js/videojs/src/css/components/_modal-dialog.scss
@@ -0,0 +1,21 @@
+.video-js .vjs-modal-dialog {
+ @extend %fill-parent;
+ @include linear-gradient(180deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0));
+
+ // This allows scrolling of content if need be.
+ overflow: auto;
+}
+
+// Reset box-sizing inside the modal dialog.
+.video-js .vjs-modal-dialog > * {
+ box-sizing: border-box;
+}
+
+.vjs-modal-dialog .vjs-modal-dialog-content {
+ @extend %fill-parent;
+
+ font-size: 1.2em; // 12px
+ line-height: 1.5; // 18px
+ padding: 20px 24px;
+ z-index: 1;
+}
diff --git a/js/videojs/src/css/components/_picture-in-picture.scss b/js/videojs/src/css/components/_picture-in-picture.scss
new file mode 100644
index 0000000..5992407
--- /dev/null
+++ b/js/videojs/src/css/components/_picture-in-picture.scss
@@ -0,0 +1,18 @@
+.video-js .vjs-picture-in-picture-control {
+ cursor: pointer;
+ @include flex(none);
+
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-picture-in-picture-enter;
+ }
+}
+
+.video-js.vjs-audio-only-mode .vjs-picture-in-picture-control,
+.vjs-pip-window .vjs-picture-in-picture-control {
+ display: none;
+}
+
+// Switch to the exit icon when the player is in Picture-in-Picture
+.video-js.vjs-picture-in-picture .vjs-picture-in-picture-control .vjs-icon-placeholder {
+ @extend .vjs-icon-picture-in-picture-exit;
+}
diff --git a/js/videojs/src/css/components/_play-pause.scss b/js/videojs/src/css/components/_play-pause.scss
new file mode 100644
index 0000000..b9615fd
--- /dev/null
+++ b/js/videojs/src/css/components/_play-pause.scss
@@ -0,0 +1,13 @@
+.video-js .vjs-play-control {
+ cursor: pointer;
+}
+.video-js .vjs-play-control .vjs-icon-placeholder {
+ @include flex(none);
+ @extend .vjs-icon-play;
+}
+.video-js .vjs-play-control.vjs-playing .vjs-icon-placeholder {
+ @extend .vjs-icon-pause;
+}
+.video-js .vjs-play-control.vjs-ended .vjs-icon-placeholder {
+ @extend .vjs-icon-replay;
+}
diff --git a/js/videojs/src/css/components/_playback-rate.scss b/js/videojs/src/css/components/_playback-rate.scss
new file mode 100644
index 0000000..e13a517
--- /dev/null
+++ b/js/videojs/src/css/components/_playback-rate.scss
@@ -0,0 +1,21 @@
+// TODO: I feel like this should be a generic menu. Research later.
+.vjs-playback-rate > .vjs-menu-button,
+.vjs-playback-rate .vjs-playback-rate-value {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.vjs-playback-rate .vjs-playback-rate-value {
+ pointer-events: none;
+ font-size: 1.5em;
+ line-height: 2;
+ text-align: center;
+}
+
+.vjs-playback-rate .vjs-menu {
+ width: 4em;
+ left: 0em;
+}
diff --git a/js/videojs/src/css/components/_poster.scss b/js/videojs/src/css/components/_poster.scss
new file mode 100644
index 0000000..d1f1d22
--- /dev/null
+++ b/js/videojs/src/css/components/_poster.scss
@@ -0,0 +1,32 @@
+.vjs-poster {
+ display: inline-block;
+ vertical-align: middle;
+ cursor: pointer;
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: 100%;
+}
+
+// Hide the poster after the video has started playing and when native controls are used
+.vjs-has-started .vjs-poster,
+.vjs-using-native-controls .vjs-poster {
+ display: none;
+}
+
+// Don't hide the poster if we're playing audio or when audio-poster-mode is true
+.vjs-audio.vjs-has-started .vjs-poster,
+.vjs-has-started.vjs-audio-poster-mode .vjs-poster,
+.vjs-pip-container.vjs-has-started .vjs-poster {
+ display: block;
+}
+
+.vjs-poster img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+}
diff --git a/js/videojs/src/css/components/_progress.scss b/js/videojs/src/css/components/_progress.scss
new file mode 100644
index 0000000..5334c65
--- /dev/null
+++ b/js/videojs/src/css/components/_progress.scss
@@ -0,0 +1,192 @@
+// .vjs-progress-control / ProgressControl
+//
+// This is the container for all progress bar-related components/elements.
+.video-js .vjs-progress-control {
+ cursor: pointer;
+ @include flex(auto);
+ @include display-flex(center);
+ min-width: 4em;
+ touch-action: none;
+}
+
+.video-js .vjs-progress-control.disabled {
+ cursor: default;
+}
+
+.vjs-live .vjs-progress-control {
+ display: none;
+}
+
+.vjs-liveui .vjs-progress-control {
+ @include display-flex(center);
+}
+
+// .vjs-progress-holder / SeekBar
+//
+// Box containing play and load progress bars. It also acts as seek scrubber.
+.video-js .vjs-progress-holder {
+ @include flex(auto);
+ @include transition(all 0.2s);
+ height: 0.3em;
+}
+
+.video-js .vjs-progress-control .vjs-progress-holder {
+
+ // This is one of the rare cases where we are using a pixel dimension. The
+ // reason is that the progress holder font-size changes on hover. With the
+ // default em-based margins, this means it gets narrower and causes issues
+ // with mouseover behaviors/math.
+ margin: 0 10px;
+}
+
+// This increases the size of the progress holder so there is an increased
+// hit area for clicks/touches.
+.video-js .vjs-progress-control:hover .vjs-progress-holder,
+.video-js.vjs-scrubbing.vjs-touch-enabled .vjs-progress-control .vjs-progress-holder {
+ font-size: 1.666666666666666666em;
+}
+
+.video-js .vjs-progress-control:hover .vjs-progress-holder.disabled {
+ font-size: 1em;
+}
+
+// .vjs-play-progress / PlayProgressBar and .vjs-load-progress / LoadProgressBar
+//
+// These are bars that appear within the progress control to communicate the
+// amount of media that has played back and the amount of media that has
+// loaded, respectively.
+.video-js .vjs-progress-holder .vjs-play-progress,
+.video-js .vjs-progress-holder .vjs-load-progress,
+.video-js .vjs-progress-holder .vjs-load-progress div {
+ position: absolute;
+ display: block;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ // updated by javascript during playback
+ width: 0;
+}
+
+.video-js .vjs-play-progress {
+ background-color: $primary-foreground-color;
+ @extend .vjs-icon-circle;
+
+ // Progress handle
+ &:before {
+ font-size: 0.9em;
+ position: absolute;
+ right: -0.5em;
+ line-height: .35em;
+ z-index: 1;
+ }
+}
+
+// Remove content from play-progress when using SVGs.
+.vjs-svg-icons-enabled .vjs-play-progress {
+ &:before {
+ content: none !important;
+ }
+}
+
+.vjs-play-progress .vjs-svg-icon {
+ position: absolute;
+ top: -0.35em;
+ right: -0.4em;
+ width: 0.9em;
+ height: 0.9em;
+ pointer-events: none;
+ line-height: 0.15em;
+ z-index: 1;
+}
+
+.video-js .vjs-load-progress {
+ background: rgba($secondary-background-color, $secondary-background-transparency);
+}
+
+// There are child elements of the load progress bar that represent the
+// specific time ranges that have been buffered.
+.video-js .vjs-load-progress div {
+ background: rgba($secondary-background-color, 0.75);
+}
+
+// .vjs-time-tooltip
+//
+// These elements are displayed above the progress bar.
+//
+// By default, they are hidden and only shown when hovering over the progress
+// control.
+.video-js .vjs-time-tooltip {
+ @include background-color-with-alpha(#fff, 0.8);
+ @include border-radius(0.3em);
+ color: #000;
+
+ // By floating the tooltips to the right, their right edge becomes aligned
+ // with the right edge of their parent element. However, in order to have them
+ // centered, they must be pulled further to the right via positioning (e.g.
+ // `right: -10px;`. This part is left to JavaScript.
+ float: right;
+ font-family: $text-font-family;
+
+ // The font-size should translate to a consistent 10px for time tooltips in
+ // all states. This is tricky because the .vjs-progress-holder element
+ // changes its font-size when the .vjs-progress-control is hovered.
+ font-size: 1em;
+ padding: 6px 8px 8px 8px;
+ pointer-events: none;
+ position: absolute;
+ top: -3.4em;
+ visibility: hidden;
+ z-index: 1;
+}
+
+.video-js .vjs-progress-holder:focus .vjs-time-tooltip {
+ display: none;
+}
+
+.video-js .vjs-progress-control:hover .vjs-time-tooltip,
+.video-js .vjs-progress-control:hover .vjs-progress-holder:focus .vjs-time-tooltip,
+.video-js.vjs-scrubbing.vjs-touch-enabled .vjs-progress-control .vjs-time-tooltip {
+ display: block;
+
+ // Ensure that we maintain a font-size of ~10px.
+ font-size: 0.6em;
+ visibility: visible;
+}
+
+.video-js .vjs-progress-control.disabled:hover .vjs-time-tooltip {
+ font-size: 1em;
+}
+
+// .vjs-mouse-display / MouseTimeDisplay
+//
+// This element tracks the mouse position along the progress control and
+// includes a tooltip, which displays the time at that point in the media.
+.video-js .vjs-progress-control .vjs-mouse-display {
+ display: none;
+ position: absolute;
+ width: 1px;
+ height: 100%;
+ background-color: #000;
+ z-index: 1;
+}
+
+.video-js .vjs-progress-control:hover .vjs-mouse-display {
+ display: block;
+}
+
+.video-js.vjs-scrubbing.vjs-touch-enabled .vjs-progress-control .vjs-mouse-display {
+ display: block;
+}
+
+.video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display,
+.video-js.vjs-touch-enabled:not(.vjs-scrubbing) .vjs-progress-control .vjs-mouse-display {
+ visibility: hidden;
+ opacity: 0;
+ $trans: visibility 1.0s, opacity 1.0s;
+ @include transition($trans);
+}
+
+.vjs-mouse-display .vjs-time-tooltip {
+ color: #fff;
+ @include background-color-with-alpha(#000, 0.8);
+}
diff --git a/js/videojs/src/css/components/_skip-buttons.scss b/js/videojs/src/css/components/_skip-buttons.scss
new file mode 100644
index 0000000..135e895
--- /dev/null
+++ b/js/videojs/src/css/components/_skip-buttons.scss
@@ -0,0 +1,40 @@
+.video-js .vjs-skip-forward-5 {
+ cursor: pointer;
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-forward-5;
+ }
+}
+
+.video-js .vjs-skip-forward-10 {
+ cursor: pointer;
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-forward-10;
+ }
+}
+.video-js .vjs-skip-forward-30 {
+ cursor: pointer;
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-forward-30;
+ }
+}
+
+.video-js .vjs-skip-backward-5 {
+ cursor: pointer;
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-replay-5;
+ }
+}
+
+.video-js .vjs-skip-backward-10 {
+ cursor: pointer;
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-replay-10;
+ }
+}
+
+.video-js .vjs-skip-backward-30 {
+ cursor: pointer;
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-replay-30;
+ }
+}
diff --git a/js/videojs/src/css/components/_slider.scss b/js/videojs/src/css/components/_slider.scss
new file mode 100644
index 0000000..2843fd3
--- /dev/null
+++ b/js/videojs/src/css/components/_slider.scss
@@ -0,0 +1,25 @@
+.video-js .vjs-slider {
+ position: relative;
+ cursor: pointer;
+ padding: 0;
+ margin: 0 0.45em 0 0.45em;
+
+ @include user-select(none);
+
+ @include background-color-with-alpha($secondary-background-color, $secondary-background-transparency);
+ }
+
+.video-js .vjs-slider.disabled {
+ cursor: default;
+}
+
+.video-js .vjs-slider:focus {
+ text-shadow: 0em 0em 1em rgba($primary-foreground-color, 1);
+
+ @include box-shadow(0 0 1em $primary-foreground-color);
+}
+
+// Replacement for focus in case spatial navigation is enabled
+.video-js.vjs-spatial-navigation-enabled .vjs-slider:focus {
+ outline: 0.0625em solid rgba($primary-foreground-color, 1);
+}
diff --git a/js/videojs/src/css/components/_subs-caps.scss b/js/videojs/src/css/components/_subs-caps.scss
new file mode 100644
index 0000000..e22a59d
--- /dev/null
+++ b/js/videojs/src/css/components/_subs-caps.scss
@@ -0,0 +1,36 @@
+// North America uses 'CC' icon
+.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder,
+.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder {
+ @extend .vjs-icon-captions;
+}
+
+// ROW uses 'subtitles'
+// Double selector because @extend puts these rules above the captions icon
+.video-js .vjs-subs-caps-button .vjs-icon-placeholder,
+.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder,
+.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder,
+.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder,
+.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder {
+ @extend .vjs-icon-subtitles;
+}
+
+.vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-svg-icon {
+ width: 1.5em;
+ height: 1.5em;
+}
+
+.video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder {
+ vertical-align: middle;
+ display: inline-block;
+ margin-bottom: -0.1em;
+}
+.video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text .vjs-icon-placeholder:before {
+ font-family: VideoJS;
+ content: "\f10c";
+ font-size: 1.5em;
+ line-height: inherit;
+}
+
+.video-js.vjs-audio-only-mode .vjs-subs-caps-button {
+ display: none;
+}
diff --git a/js/videojs/src/css/components/_subtitles.scss b/js/videojs/src/css/components/_subtitles.scss
new file mode 100644
index 0000000..fb5da83
--- /dev/null
+++ b/js/videojs/src/css/components/_subtitles.scss
@@ -0,0 +1,3 @@
+.video-js .vjs-subtitles-button .vjs-icon-placeholder {
+ @extend .vjs-icon-subtitles;
+}
diff --git a/js/videojs/src/css/components/_text-track.scss b/js/videojs/src/css/components/_text-track.scss
new file mode 100644
index 0000000..5b58f3c
--- /dev/null
+++ b/js/videojs/src/css/components/_text-track.scss
@@ -0,0 +1,57 @@
+// Emulated tracks
+.vjs-text-track-display {
+ position: absolute;
+ bottom: 3em;
+ left: 0;
+ right: 0;
+ top: 0;
+ pointer-events: none;
+}
+
+// Hide if an error occurs
+.vjs-error .vjs-text-track-display {
+ display: none;
+}
+
+// Move captions down when controls aren't being shown
+.video-js.vjs-controls-disabled .vjs-text-track-display,
+.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display {
+ bottom: 1em;
+}
+
+// Individual tracks
+.video-js .vjs-text-track {
+ font-size: 1.4em;
+ text-align: center;
+ margin-bottom: 0.1em;
+}
+
+.vjs-subtitles { color: #fff; } // Subtitles are white
+.vjs-captions { color: #fc6; } // Captions are yellow
+.vjs-tt-cue { display: block; }
+
+// Native tracks
+video::-webkit-media-text-track-display {
+ @include transform(translateY(-3em));
+}
+
+// Move captions down when controls aren't being shown
+.video-js.vjs-controls-disabled video::-webkit-media-text-track-display,
+.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display {
+ @include transform(translateY(-1.5em));
+}
+
+// force cues to be center aligned
+.video-js.vjs-force-center-align-cues .vjs-text-track-cue {
+ text-align: center !important;
+ width: 80% !important;
+}
+
+@supports not (inset: 10px) {
+ .video-js .vjs-text-track-display > div {
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ }
+}
diff --git a/js/videojs/src/css/components/_time.scss b/js/videojs/src/css/components/_time.scss
new file mode 100644
index 0000000..cec3411
--- /dev/null
+++ b/js/videojs/src/css/components/_time.scss
@@ -0,0 +1,25 @@
+.video-js .vjs-time-control {
+ @include flex(none);
+ font-size: 1em;
+ line-height: 3em;
+ min-width: 2em;
+ width: auto;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+.vjs-live .vjs-time-control,
+.vjs-live .vjs-time-divider,
+.video-js .vjs-current-time,
+.video-js .vjs-duration {
+ display: none;
+}
+
+.vjs-time-divider {
+ display: none;
+ line-height: 3em;
+}
+
+.vjs-normalise-time-controls:not(.vjs-live) .vjs-time-control {
+ display: flex;
+}
diff --git a/js/videojs/src/css/components/_title-bar.scss b/js/videojs/src/css/components/_title-bar.scss
new file mode 100644
index 0000000..19b5b6b
--- /dev/null
+++ b/js/videojs/src/css/components/_title-bar.scss
@@ -0,0 +1,46 @@
+.vjs-title-bar {
+
+ // At a base inherited font-size of 10px, the title bar overall height should
+ // be 96px with the area of text occupying the first 48px and the rest being
+ // padding. This leaves plenty of room for the gradient to fade to
+ // transparent while maintaining an WCAG AA-compliant contrast ratio (tested
+ // using the TPGi Color Contrast Analyzer application) even on top of a solid
+ // white background.
+ @include linear-gradient(
+ 180deg,
+ rgba(0, 0, 0, 0.9) 0%,
+ rgba(0, 0, 0, 0.7) 60%,
+ rgba(0, 0, 0, 0) 100%
+ );
+ font-size: 1.2em; // 12px
+ line-height: 1.5; // 18px
+ @include transition(opacity 0.1s);
+ padding: 0.666em 1.333em 4em; // 8px 16px 48px
+ pointer-events: none;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+
+// Hide if an error occurs
+.vjs-error .vjs-title-bar {
+ display: none;
+}
+
+.vjs-title-bar-title,
+.vjs-title-bar-description {
+ margin: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.vjs-title-bar-title {
+ font-weight: bold;
+ margin-bottom: 0.333em; // 4px
+}
+
+.vjs-playing.vjs-user-inactive .vjs-title-bar {
+ opacity: 0;
+ @include transition(opacity 1s);
+}
diff --git a/js/videojs/src/css/components/_transient-button.scss b/js/videojs/src/css/components/_transient-button.scss
new file mode 100644
index 0000000..ddc866f
--- /dev/null
+++ b/js/videojs/src/css/components/_transient-button.scss
@@ -0,0 +1,48 @@
+.video-js .vjs-transient-button {
+ position: absolute;
+ height: 3em;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(50, 50, 50, 0.5);
+ cursor: pointer;
+ opacity: 1;
+ transition: opacity 1s;
+}
+
+.video-js:not(.vjs-has-started) .vjs-transient-button {
+ display: none;
+}
+
+.video-js.not-hover .vjs-transient-button:not(.force-display),
+.video-js.vjs-user-inactive .vjs-transient-button:not(.force-display) {
+ opacity: 0;
+}
+
+.video-js .vjs-transient-button span {
+ padding: 0 0.5em;
+}
+
+.video-js .vjs-transient-button.vjs-left {
+ left: 1em;
+}
+
+.video-js .vjs-transient-button.vjs-right {
+ right: 1em;
+}
+
+.video-js .vjs-transient-button.vjs-top {
+ top: 1em;
+}
+
+.video-js .vjs-transient-button.vjs-near-top {
+ top: 4em;
+}
+
+.video-js .vjs-transient-button.vjs-bottom {
+ bottom: 4em;
+}
+
+.video-js .vjs-transient-button:hover {
+ background-color: rgba(50, 50, 50, 0.9);
+}
diff --git a/js/videojs/src/css/components/_volume.scss b/js/videojs/src/css/components/_volume.scss
new file mode 100644
index 0000000..f355a93
--- /dev/null
+++ b/js/videojs/src/css/components/_volume.scss
@@ -0,0 +1,268 @@
+.video-js .vjs-mute-control {
+ cursor: pointer;
+ @include flex(none);
+
+ & .vjs-icon-placeholder {
+ @extend .vjs-icon-volume-high;
+ }
+}
+
+.video-js .vjs-mute-control.vjs-vol-0 .vjs-icon-placeholder {
+ @extend .vjs-icon-volume-mute;
+}
+.video-js .vjs-mute-control.vjs-vol-1 .vjs-icon-placeholder {
+ @extend .vjs-icon-volume-low;
+}
+.video-js .vjs-mute-control.vjs-vol-2 .vjs-icon-placeholder {
+ @extend .vjs-icon-volume-mid;
+}
+
+.video-js .vjs-volume-control {
+ cursor: pointer;
+ margin-right: 1em;
+ @include display-flex;
+}
+.video-js .vjs-volume-control.vjs-volume-horizontal {
+ width: 5em;
+}
+
+.video-js .vjs-volume-panel .vjs-volume-control {
+ visibility: visible;
+ opacity: 0;
+ width: 1px;
+ height: 1px;
+ margin-left: -1px;
+}
+
+.video-js .vjs-volume-panel {
+ @include transition(width 1s);
+
+ &.vjs-hover .vjs-volume-control,
+ &:active .vjs-volume-control,
+ &:focus .vjs-volume-control,
+ & .vjs-volume-control:active,
+ &.vjs-hover .vjs-mute-control ~ .vjs-volume-control,
+ & .vjs-volume-control.vjs-slider-active {
+ visibility: visible;
+ opacity: 1;
+ position: relative;
+ $transition-property: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s;
+ @include transition($transition-property);
+
+ &.vjs-volume-horizontal {
+ width: 5em;
+ height: 3em;
+ margin-right: 0;
+ }
+
+ &.vjs-volume-vertical {
+ left: -3.5em;
+ @include transition(left 0s);
+ }
+ }
+
+ &.vjs-volume-panel-horizontal {
+ &.vjs-hover,
+ &:active,
+ &.vjs-slider-active {
+ width: 10em;
+
+ @include transition(width 0.1s);
+ }
+ &.vjs-mute-toggle-only {
+ width: 4em;
+ }
+ }
+}
+
+.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical {
+ height: 8em;
+ width: 3em;
+ left: -3000em;
+
+ $transition-property: visibility 1s, opacity 1s, height 1s 1s, width 1s 1s, left 1s 1s, top 1s 1s;
+ @include transition($transition-property)
+}
+
+.video-js .vjs-volume-panel .vjs-volume-control.vjs-volume-horizontal {
+ $transition-property: visibility 1s, opacity 1s, height 1s 1s, width 1s, left 1s 1s, top 1s 1s;
+ @include transition($transition-property)
+}
+
+.video-js .vjs-volume-panel {
+ @include display-flex;
+}
+
+.video-js .vjs-volume-bar {
+ margin: 1.35em 0.45em;
+}
+
+.vjs-volume-bar.vjs-slider-horizontal {
+ width: 5em;
+ height: 0.3em;
+}
+
+.vjs-volume-bar.vjs-slider-vertical {
+ width: 0.3em;
+ height: 5em;
+ margin: 1.35em auto;
+}
+
+.video-js .vjs-volume-level {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+
+ background-color: $primary-foreground-color;
+
+ @extend .vjs-icon-circle;
+
+ // Volume handle
+ &:before {
+ position: absolute;
+ font-size: 0.9em; // Doing this to match the handle on play progress.
+ z-index: 1;
+ }
+}
+
+.vjs-slider-vertical .vjs-volume-level {
+ width: 0.3em;
+
+ // Volume handle
+ &:before {
+ top: -0.5em;
+ left: -0.3em;
+ z-index: 1;
+ }
+}
+// Remove content from volume-level when using SVGs.
+.vjs-svg-icons-enabled .vjs-volume-level {
+ &:before {
+ content: none;
+ }
+}
+
+.vjs-volume-level .vjs-svg-icon {
+ position: absolute;
+ width: 0.9em;
+ height: 0.9em;
+ pointer-events: none;
+ z-index: 1;
+}
+
+.vjs-slider-horizontal .vjs-volume-level {
+ height: 0.3em;
+
+ // Volume handle
+ &:before {
+ line-height: .35em;
+ right: -0.5em;
+ }
+}
+
+// Update placement of circle icon when using SVG icons
+.vjs-slider-horizontal .vjs-volume-level .vjs-svg-icon {
+ right: -0.3em;
+ transform: translateY(-50%);
+}
+.vjs-slider-vertical .vjs-volume-level .vjs-svg-icon {
+ top: -0.55em;
+ transform: translateX(-50%);
+}
+
+.video-js .vjs-volume-panel.vjs-volume-panel-vertical {
+ width: 4em;
+}
+
+// Assumes volume starts at 1.0.
+.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level {
+ height: 100%;
+}
+
+.vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level {
+ width: 100%;
+}
+
+.video-js .vjs-volume-vertical {
+ width: 3em;
+ height: 8em;
+ bottom: 8em;
+
+ @include background-color-with-alpha($primary-background-color, $primary-background-transparency);
+}
+
+.video-js .vjs-volume-horizontal .vjs-menu {
+ left: -2em;
+}
+
+// .vjs-volume-tooltip
+//
+// These elements are displayed above the volume bar.
+//
+// By default, they are hidden and only shown when hovering over the volume
+// control.
+.video-js .vjs-volume-tooltip {
+ @include background-color-with-alpha(#fff, 0.8);
+ @include border-radius(0.3em);
+ color: #000;
+ float: right;
+ font-family: $text-font-family;
+ font-size: 1em;
+ padding: 6px 8px 8px 8px;
+ pointer-events: none;
+ position: absolute;
+ top: -3.4em;
+ visibility: hidden;
+ z-index: 1;
+}
+
+.video-js .vjs-volume-control:hover .vjs-volume-tooltip,
+.video-js .vjs-volume-control:hover .vjs-progress-holder:focus .vjs-volume-tooltip {
+ display: block;
+ font-size: 1em;
+ visibility: visible;
+}
+
+.video-js .vjs-volume-vertical:hover .vjs-volume-tooltip,
+.video-js .vjs-volume-vertical:hover .vjs-progress-holder:focus .vjs-volume-tooltip {
+ left: 1em;
+ top: -12px;
+}
+
+.video-js .vjs-volume-control.disabled:hover .vjs-volume-tooltip {
+ font-size: 1em;
+}
+
+// .vjs-mouse-display / MouseVolumeLevelDisplay
+//
+// This element tracks the mouse position along the volume control and
+// includes a tooltip, which displays the volume level.
+.video-js .vjs-volume-control .vjs-mouse-display {
+ display: none;
+ position: absolute;
+ width: 100%;
+ height: 1px;
+ background-color: #000;
+ z-index: 1;
+}
+
+.video-js .vjs-volume-horizontal .vjs-mouse-display {
+ width: 1px;
+ height: 100%;
+}
+
+.video-js .vjs-volume-control:hover .vjs-mouse-display {
+ display: block;
+}
+
+.video-js.vjs-user-inactive .vjs-volume-control .vjs-mouse-display {
+ visibility: hidden;
+ opacity: 0;
+ $trans: visibility 1.0s, opacity 1.0s;
+ @include transition($trans);
+}
+
+.vjs-mouse-display .vjs-volume-tooltip {
+ color: #fff;
+ @include background-color-with-alpha(#000, 0.8);
+}
diff --git a/js/videojs/src/css/components/menu/_menu-inline.scss b/js/videojs/src/css/components/menu/_menu-inline.scss
new file mode 100644
index 0000000..4ed1f5c
--- /dev/null
+++ b/js/videojs/src/css/components/menu/_menu-inline.scss
@@ -0,0 +1,48 @@
+.video-js .vjs-menu-button-inline {
+ @include transition(all 0.4s);
+ overflow: hidden;
+}
+
+.video-js .vjs-menu-button-inline:before {
+ // Icon pseudoelement has a different base font size (1.8em), so we need to
+ // account for that in the width. 4em (standard button width) divided by 1.8
+ // to get the same button width as normal.
+ width: 2.222222222em;
+}
+
+// Hover state
+.video-js .vjs-menu-button-inline:hover,
+.video-js .vjs-menu-button-inline:focus,
+.video-js .vjs-menu-button-inline.vjs-slider-active {
+ // This width is currently specific to the inline volume bar.
+ width: 12em;
+}
+
+.vjs-menu-button-inline .vjs-menu {
+ opacity: 0;
+ height: 100%;
+ width: auto;
+
+ position: absolute;
+ left: 4em;
+ top: 0;
+
+ padding: 0;
+ margin: 0;
+
+ @include transition(all 0.4s);
+}
+
+.vjs-menu-button-inline:hover .vjs-menu,
+.vjs-menu-button-inline:focus .vjs-menu,
+.vjs-menu-button-inline.vjs-slider-active .vjs-menu {
+ display: block;
+ opacity: 1;
+}
+
+.vjs-menu-button-inline .vjs-menu-content {
+ width: auto;
+ height: 100%;
+ margin: 0;
+ overflow: hidden;
+}
diff --git a/js/videojs/src/css/components/menu/_menu-popup.scss b/js/videojs/src/css/components/menu/_menu-popup.scss
new file mode 100644
index 0000000..550c761
--- /dev/null
+++ b/js/videojs/src/css/components/menu/_menu-popup.scss
@@ -0,0 +1,49 @@
+.vjs-menu-button-popup .vjs-menu {
+ display: none;
+ position: absolute;
+ bottom: 0;
+ width: 10em;
+ left: -3em; // (Width of vjs-menu - width of button) / 2
+ height: 0em;
+ margin-bottom: 1.5em;
+ border-top-color: rgba($primary-background-color, $primary-background-transparency); // Same as ul background
+}
+
+.vjs-pip-window .vjs-menu-button-popup .vjs-menu {
+ left: unset;
+ right: 1em; // Extra offset for last menu button in pip window, as fullscreen button not present
+}
+
+// Button Pop-up Menu
+.vjs-menu-button-popup .vjs-menu .vjs-menu-content {
+ @include background-color-with-alpha($primary-background-color, $primary-background-transparency);
+
+ position: absolute;
+ width: 100%;
+ bottom: 1.5em; // Same bottom as vjs-menu border-top
+ max-height: 15em;
+}
+
+.vjs-layout-tiny .vjs-menu-button-popup .vjs-menu .vjs-menu-content,
+.vjs-layout-x-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content {
+ max-height: 5em;
+}
+
+.vjs-layout-small .vjs-menu-button-popup .vjs-menu .vjs-menu-content {
+ max-height: 10em;
+}
+
+.vjs-layout-medium .vjs-menu-button-popup .vjs-menu .vjs-menu-content {
+ max-height: 14em;
+}
+
+.vjs-layout-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content,
+.vjs-layout-x-large .vjs-menu-button-popup .vjs-menu .vjs-menu-content,
+.vjs-layout-huge .vjs-menu-button-popup .vjs-menu .vjs-menu-content {
+ max-height: 25em;
+}
+
+.vjs-workinghover .vjs-menu-button-popup.vjs-hover .vjs-menu,
+.vjs-menu-button-popup .vjs-menu.vjs-lock-showing {
+ display: block;
+}
diff --git a/js/videojs/src/css/components/menu/_menu.scss b/js/videojs/src/css/components/menu/_menu.scss
new file mode 100644
index 0000000..be53c3a
--- /dev/null
+++ b/js/videojs/src/css/components/menu/_menu.scss
@@ -0,0 +1,80 @@
+.vjs-menu-button {
+ cursor: pointer;
+}
+
+// Change cursor back to default if the menu button is disabled
+.vjs-menu-button.vjs-disabled {
+ cursor: default;
+}
+
+// prevent menus from opening while disabled
+.vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu {
+ display: none;
+}
+
+.vjs-menu .vjs-menu-content {
+ display: block;
+ padding: 0;
+ margin: 0;
+ font-family: $text-font-family;
+
+ // This allows scrolling of content if need be.
+ overflow: auto;
+}
+
+// Reset box-sizing inside the menu.
+.vjs-menu .vjs-menu-content > * {
+ box-sizing: border-box;
+}
+
+// prevent menus from opening while scrubbing
+.vjs-scrubbing .vjs-control.vjs-menu-button:hover .vjs-menu {
+ display: none;
+}
+
+.vjs-menu li {
+ display: flex;
+ justify-content: center;
+ list-style: none;
+ margin: 0;
+ padding: 0.2em 0;
+ line-height: 1.4em;
+ font-size: 1.2em;
+ text-align: center;
+ text-transform: lowercase;
+}
+
+.vjs-menu li.vjs-menu-item:focus,
+.vjs-menu li.vjs-menu-item:hover,
+.js-focus-visible .vjs-menu li.vjs-menu-item:hover {
+ @include background-color-with-alpha($secondary-background-color, $secondary-background-transparency);
+}
+
+.vjs-menu li.vjs-selected,
+.vjs-menu li.vjs-selected:focus,
+.vjs-menu li.vjs-selected:hover,
+.js-focus-visible .vjs-menu li.vjs-selected:hover {
+ background-color: $primary-foreground-color;
+ color: $primary-background-color;
+
+ // Change the SVG color when an item is selected
+ .vjs-svg-icon {
+ fill: #000000;
+ }
+}
+
+.video-js .vjs-menu *:not(.vjs-selected):focus:not(:focus-visible),
+.js-focus-visible .vjs-menu *:not(.vjs-selected):focus:not(.focus-visible) {
+ background: none;
+}
+
+.vjs-menu li.vjs-menu-title {
+ text-align: center;
+ text-transform: uppercase;
+ font-size: 1em;
+ line-height: 2em;
+ padding: 0;
+ margin: 0 0 0.3em 0;
+ font-weight: bold;
+ cursor: default;
+}
diff --git a/js/videojs/src/css/utilities/_linear-gradient.scss b/js/videojs/src/css/utilities/_linear-gradient.scss
new file mode 100644
index 0000000..5adc2eb
--- /dev/null
+++ b/js/videojs/src/css/utilities/_linear-gradient.scss
@@ -0,0 +1,93 @@
+@use "sass:math";
+
+// These functions and mixins taken from:
+//
+// "Building a linear-gradient Mixin in Sass" by Hugo Giraudel
+// http://www.sitepoint.com/building-linear-gradient-mixin-sass/
+// http://sassmeister.com/gist/b58f6e2cc3160007c880
+//
+
+/// Convert angle
+/// @author Chris Eppstein
+/// @param {Number} $value - Value to convert
+/// @param {String} $unit - Unit to convert to
+/// @return {Number} Converted angle
+@function convert-angle($value, $unit) {
+ $convertable-units: deg grad turn rad;
+ $conversion-factors: 1 math.div(10grad, 9deg) math.div(1turn, 360deg) math.div(3.1415926rad, 180deg);
+ @if index($convertable-units, unit($value)) and index($convertable-units, $unit) {
+ @return math.div($value, nth($conversion-factors, index($convertable-units, unit($value))))
+ * nth($conversion-factors, index($convertable-units, $unit));
+ }
+
+ @warn "Cannot convert `#{unit($value)}` to `#{$unit}`.";
+}
+
+/// Test if `$value` is an angle
+/// @param {*} $value - Value to test
+/// @return {Bool}
+@function is-direction($value) {
+ $is-direction: index((
+ 'to top',
+ 'to top right',
+ 'to right top',
+ 'to right',
+ 'to bottom right',
+ 'to right bottom',
+ 'to bottom',
+ 'to bottom left',
+ 'to left bottom',
+ 'to left',
+ 'to left top',
+ 'to top left'
+ ), $value);
+ $is-angle: type-of($value) == 'number' and index('deg' 'grad' 'turn' 'rad', unit($value));
+
+ @return $is-direction or $is-angle;
+}
+
+/// Convert a direction to legacy syntax
+/// @param {Keyword | Angle} $value - Value to convert
+/// @require {function} is-direction
+/// @require {function} convert-angle
+@function legacy-direction($value) {
+ @if is-direction($value) == false {
+ @warn "Cannot convert `#{$value}` to legacy syntax because it doesn't seem to be an angle or a direction";
+ }
+
+ $conversion-map: (
+ 'to top' : 'bottom',
+ 'to top right' : 'bottom left',
+ 'to right top' : 'left bottom',
+ 'to right' : 'left',
+ 'to bottom right' : 'top left',
+ 'to right bottom' : 'left top',
+ 'to bottom' : 'top',
+ 'to bottom left' : 'top right',
+ 'to left bottom' : 'right top',
+ 'to left' : 'right',
+ 'to left top' : 'right bottom',
+ 'to top left' : 'bottom right'
+ );
+
+ @if map-has-key($conversion-map, $value) {
+ @return map-get($conversion-map, $value);
+ }
+
+ @return 90deg - convert-angle($value, 'deg');
+}
+
+/// Mixin printing a linear-gradient
+/// as well as a plain color fallback
+/// @access public
+/// @param {String | List | Angle} $direction - Linear gradient direction
+/// @param {Arglist} $color-stops - List of color-stops composing the gradient
+@mixin linear-gradient($direction, $color-stops...) {
+ @if is-direction($direction) == false {
+ $color-stops: ($direction, $color-stops);
+ $direction: 180deg;
+ }
+
+ background: nth(nth($color-stops, 1), 1);
+ background: linear-gradient($direction, $color-stops);
+}
diff --git a/js/videojs/src/css/video-js.scss b/js/videojs/src/css/video-js.scss
new file mode 100644
index 0000000..fcb8388
--- /dev/null
+++ b/js/videojs/src/css/video-js.scss
@@ -0,0 +1,68 @@
+@import "icons";
+@import "variables";
+@import "private-variables";
+@import "utilities";
+
+@import "videojs-font/scss/icons";
+
+@import "components/layout";
+@import "components/big-play";
+@import "components/button";
+@import "components/close-button";
+@import "components/modal-dialog";
+
+@import "components/menu/menu";
+@import "components/menu/menu-popup";
+@import "components/menu/menu-inline";
+
+@import "components/control-bar";
+@import "components/control";
+@import "components/control-spacer";
+
+@import "components/progress";
+@import "components/slider";
+
+@import "components/volume";
+
+@import "components/poster";
+@import "components/live";
+@import "components/time";
+@import "components/play-pause";
+@import "components/text-track";
+@import "components/picture-in-picture";
+@import "components/fullscreen";
+@import "components/playback-rate";
+@import "components/error";
+@import "components/loading";
+@import "components/captions";
+@import "components/chapters";
+@import "components/descriptions";
+@import "components/subtitles";
+@import "components/subs-caps";
+@import "components/audio";
+@import "components/adaptive";
+@import "components/captions-settings";
+@import "components/title-bar";
+@import "components/skip-buttons";
+@import "components/transient-button";
+
+@import "print";
+
+.vjs-resize-manager {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border: none;
+ z-index: -1000;
+}
+
+// The rule is needed for :focus-visible polyfill
+.js-focus-visible .video-js *:focus:not(.focus-visible) {
+ outline: none;
+}
+
+.video-js *:focus:not(:focus-visible) {
+ outline: none;
+}
diff --git a/js/videojs/src/css/vjs-cdn.scss b/js/videojs/src/css/vjs-cdn.scss
new file mode 100644
index 0000000..abf75b6
--- /dev/null
+++ b/js/videojs/src/css/vjs-cdn.scss
@@ -0,0 +1,3 @@
+$icon-font-path: '//vjs.zencdn.net/font/1.5.1';
+
+@import 'video-js';
diff --git a/js/videojs/src/css/vjs.scss b/js/videojs/src/css/vjs.scss
new file mode 100644
index 0000000..d80517f
--- /dev/null
+++ b/js/videojs/src/css/vjs.scss
@@ -0,0 +1 @@
+@import "video-js";