saltfish 0.3.68 → 0.3.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/services/PlaylistOrchestrator.d.ts.map +1 -1
- package/dist/core/services/StateMachineActionHandler.d.ts.map +1 -1
- package/dist/player.js +2 -2
- package/dist/player.min.js +2 -2
- package/dist/saltfish-playlist-player.es.js +24 -28
- package/dist/saltfish-playlist-player.umd.js +1 -1
- package/package.json +1 -1
|
@@ -2856,11 +2856,14 @@ class PlaylistOrchestrator {
|
|
|
2856
2856
|
if (this.userManagementService) {
|
|
2857
2857
|
await this.userManagementService.recordABTestAttempt(playlistId);
|
|
2858
2858
|
}
|
|
2859
|
-
if (true) {
|
|
2859
|
+
if ((options == null ? void 0 : options._startedFromShareLink) !== true) {
|
|
2860
2860
|
if (!this.managers.abTestManager.isPlaylistAvailable(playlistId)) {
|
|
2861
2861
|
log(`[PlaylistOrchestrator.startPlaylist] Playlist ${playlistId} not available due to A/B test assignment`);
|
|
2862
2862
|
return;
|
|
2863
2863
|
}
|
|
2864
|
+
} else if (false) ;
|
|
2865
|
+
else if ((options == null ? void 0 : options._startedFromShareLink) === true) {
|
|
2866
|
+
log(`[PlaylistOrchestrator.startPlaylist] Share link - skipping A/B test check for playlist ${playlistId}`);
|
|
2864
2867
|
}
|
|
2865
2868
|
const validator = new PlaylistValidator();
|
|
2866
2869
|
const validationResult = await validator.validatePlaylistStart({
|
|
@@ -3311,7 +3314,6 @@ class StateMachineActionHandler {
|
|
|
3311
3314
|
}
|
|
3312
3315
|
// Private action handler methods
|
|
3313
3316
|
async handleStartVideoPlayback(context) {
|
|
3314
|
-
var _a, _b, _c;
|
|
3315
3317
|
if (!context.currentStep) {
|
|
3316
3318
|
return;
|
|
3317
3319
|
}
|
|
@@ -3324,18 +3326,12 @@ class StateMachineActionHandler {
|
|
|
3324
3326
|
}
|
|
3325
3327
|
}
|
|
3326
3328
|
this.managers.uiManager.updatePosition();
|
|
3327
|
-
const store = getSaltfishStore();
|
|
3328
|
-
const isFirstStep = store.manifest && store.currentStepId === ((_a = store.manifest.steps[0]) == null ? void 0 : _a.id);
|
|
3329
|
-
if (isFirstStep && ((_b = store.manifest) == null ? void 0 : _b.idleMode) && ((_c = store.manifest) == null ? void 0 : _c.compactFirstStep)) {
|
|
3330
|
-
const playerElement = this.managers.uiManager.getPlayerElement();
|
|
3331
|
-
playerElement == null ? void 0 : playerElement.classList.add("sf-player--compact");
|
|
3332
|
-
}
|
|
3333
3329
|
this.managers.uiManager.showPlayer();
|
|
3334
3330
|
const videoUrl = this.getVideoUrl(currentStep);
|
|
3335
3331
|
const isAudioFallback = this.isUsingAudioFallback(currentStep);
|
|
3336
3332
|
if (isAudioFallback) {
|
|
3337
|
-
const
|
|
3338
|
-
const manifest =
|
|
3333
|
+
const store = getSaltfishStore();
|
|
3334
|
+
const manifest = store.manifest;
|
|
3339
3335
|
const posterUrl = currentStep.gifUrl;
|
|
3340
3336
|
const avatarThumbnailUrl = manifest == null ? void 0 : manifest.avatarThumbnailUrl;
|
|
3341
3337
|
this.managers.videoManager.showAudioFallbackOverlay(posterUrl, avatarThumbnailUrl);
|
|
@@ -3357,8 +3353,8 @@ class StateMachineActionHandler {
|
|
|
3357
3353
|
this.managers.transitionManager.setupTransitions(currentStep, false, true);
|
|
3358
3354
|
}
|
|
3359
3355
|
this.managers.videoManager.setCompletionPolicy(completionPolicy, () => {
|
|
3360
|
-
var
|
|
3361
|
-
const
|
|
3356
|
+
var _a;
|
|
3357
|
+
const store = getSaltfishStore();
|
|
3362
3358
|
if (!hasSpecialTransitions) {
|
|
3363
3359
|
const timeoutTransition = currentStep.transitions.find((t) => t.type === "timeout");
|
|
3364
3360
|
const hasNonZeroTimeout = timeoutTransition && timeoutTransition.timeout && timeoutTransition.timeout > 0;
|
|
@@ -3370,33 +3366,33 @@ class StateMachineActionHandler {
|
|
|
3370
3366
|
this.managers.transitionManager.setupTransitions(currentStep, true);
|
|
3371
3367
|
}
|
|
3372
3368
|
const hasValidNextSteps = currentStep.transitions.some((transition) => {
|
|
3373
|
-
return
|
|
3369
|
+
return store.manifest.steps.some((s) => s.id === transition.nextStep);
|
|
3374
3370
|
});
|
|
3375
3371
|
if (!hasValidNextSteps) {
|
|
3376
3372
|
log("StateMachineActionHandler: No valid next steps found, completing playlist");
|
|
3377
|
-
|
|
3373
|
+
store.sendStateMachineEvent({
|
|
3378
3374
|
type: "COMPLETE_PLAYLIST"
|
|
3379
3375
|
});
|
|
3380
3376
|
}
|
|
3381
3377
|
} else {
|
|
3382
3378
|
const timeoutTransition = currentStep.transitions.find((t) => t.type === "timeout");
|
|
3383
|
-
const hasStepTransitionButtons = (
|
|
3379
|
+
const hasStepTransitionButtons = (_a = currentStep.buttons) == null ? void 0 : _a.some(
|
|
3384
3380
|
(button) => button.action.type === "goto" || button.action.type === "next"
|
|
3385
3381
|
);
|
|
3386
3382
|
if (timeoutTransition && !hasStepTransitionButtons) {
|
|
3387
3383
|
const timeout = timeoutTransition.timeout || 0;
|
|
3388
3384
|
log(`StateMachineActionHandler: Video ended, setting up timeout transition to ${timeoutTransition.nextStep} with ${timeout}ms delay`);
|
|
3389
3385
|
setTimeout(() => {
|
|
3390
|
-
var
|
|
3386
|
+
var _a2;
|
|
3391
3387
|
const currentStore = getSaltfishStore();
|
|
3392
3388
|
if (currentStore.currentStepId === currentStep.id && (currentStore.currentState === "waitingForInteraction" || currentStore.currentState === "playing")) {
|
|
3393
3389
|
log(`StateMachineActionHandler: Timeout expired (${timeout}ms), transitioning to ${timeoutTransition.nextStep}`);
|
|
3394
|
-
(
|
|
3390
|
+
(_a2 = currentStore.goToStep) == null ? void 0 : _a2.call(currentStore, timeoutTransition.nextStep);
|
|
3395
3391
|
} else {
|
|
3396
3392
|
log(`StateMachineActionHandler: Timeout cancelled - step changed or state is ${currentStore.currentState}`);
|
|
3397
3393
|
}
|
|
3398
3394
|
}, timeout);
|
|
3399
|
-
|
|
3395
|
+
store.sendStateMachineEvent({
|
|
3400
3396
|
type: "VIDEO_FINISHED_WAIT",
|
|
3401
3397
|
step: currentStep
|
|
3402
3398
|
});
|
|
@@ -3406,7 +3402,7 @@ class StateMachineActionHandler {
|
|
|
3406
3402
|
} else {
|
|
3407
3403
|
log("StateMachineActionHandler: Video ended, waiting for user interaction");
|
|
3408
3404
|
}
|
|
3409
|
-
|
|
3405
|
+
store.sendStateMachineEvent({
|
|
3410
3406
|
type: "VIDEO_FINISHED_WAIT",
|
|
3411
3407
|
step: currentStep
|
|
3412
3408
|
});
|
|
@@ -3415,10 +3411,10 @@ class StateMachineActionHandler {
|
|
|
3415
3411
|
});
|
|
3416
3412
|
log("StateMachineActionHandler: Starting async video load");
|
|
3417
3413
|
const loadTranscriptForStep = () => {
|
|
3418
|
-
var
|
|
3419
|
-
const
|
|
3420
|
-
const captionsEnabled = ((
|
|
3421
|
-
const language = (
|
|
3414
|
+
var _a, _b;
|
|
3415
|
+
const store = getSaltfishStore();
|
|
3416
|
+
const captionsEnabled = ((_a = store.manifest) == null ? void 0 : _a.captions) ?? true;
|
|
3417
|
+
const language = (_b = store.userData) == null ? void 0 : _b.language;
|
|
3422
3418
|
let transcript = currentStep.transcript;
|
|
3423
3419
|
if (language && currentStep.translations && currentStep.translations[language]) {
|
|
3424
3420
|
const translatedTranscript = currentStep.translations[language].transcript;
|
|
@@ -3463,18 +3459,18 @@ class StateMachineActionHandler {
|
|
|
3463
3459
|
this.managers.videoManager.preloadNextVideo(nextVideoUrl);
|
|
3464
3460
|
}
|
|
3465
3461
|
}).catch((error2) => {
|
|
3466
|
-
var
|
|
3462
|
+
var _a;
|
|
3467
3463
|
log(`StateMachineActionHandler: Error loading video: ${error2}`);
|
|
3468
3464
|
this.managers.uiManager.showError(
|
|
3469
3465
|
error2 instanceof Error ? error2 : new Error(`Failed to load video: ${error2}`),
|
|
3470
3466
|
"video"
|
|
3471
3467
|
);
|
|
3472
|
-
const
|
|
3468
|
+
const store = getSaltfishStore();
|
|
3473
3469
|
const errorObj = error2 instanceof Error ? error2 : new Error(`Failed to load video: ${error2}`);
|
|
3474
3470
|
const enrichedError = error2;
|
|
3475
3471
|
this.managers.eventManager.trigger("error", {
|
|
3476
3472
|
timestamp: Date.now(),
|
|
3477
|
-
playlistId: ((
|
|
3473
|
+
playlistId: ((_a = store.manifest) == null ? void 0 : _a.id) || void 0,
|
|
3478
3474
|
stepId: currentStep.id,
|
|
3479
3475
|
error: errorObj,
|
|
3480
3476
|
errorType: "video",
|
|
@@ -4226,7 +4222,7 @@ __publicField(_ManagerOrchestrator, "prevState", {
|
|
|
4226
4222
|
let ManagerOrchestrator = _ManagerOrchestrator;
|
|
4227
4223
|
const baseResetCss = "/* \n * CSS Reset for the Saltfish playlist Player\n * Minimal reset for the Shadow DOM to ensure consistent rendering\n */\n\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n box-sizing: border-box;\n}\n\n:host *,\n:host *::before,\n:host *::after {\n box-sizing: inherit;\n margin: 0;\n padding: 0;\n}\n\nbutton {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n outline: none;\n padding: 0;\n}\n\n/* Utility classes for CSP-compliant styling */\n.sf-hidden {\n display: none !important;\n} ";
|
|
4228
4224
|
const baseVariablesCss = "/* \n * Variables for the Saltfish playlist Player\n * Defines all design tokens used throughout the application\n */\n\n:host {\n /* Colors */\n --sf-primary-color: #4a9bff;\n --sf-secondary-color: #6ccfff;\n --sf-background-color: #1e1e1e;\n --sf-text-color: #ffffff;\n --sf-button-bg: rgba(0, 0, 0, 0.5);\n --sf-button-hover-bg: rgba(0, 0, 0, 0.7);\n --sf-overlay-gradient: linear-gradient(180deg, rgba(0, 0, 0, 0.7) 0%, transparent 30%, transparent 70%, rgba(0, 0, 0, 0.7) 100%);\n --sf-progress-gradient: linear-gradient(90deg, var(--sf-primary-color), var(--sf-secondary-color));\n --sf-error-color: #ff4d4d;\n --sf-error-bg: rgba(255, 77, 77, 0.1);\n \n /* Spacing */\n --sf-spacing-xs: 4px;\n --sf-spacing-sm: 8px;\n --sf-spacing-md: 12px;\n --sf-spacing-lg: 16px;\n --sf-spacing-xl: 24px;\n \n /* Sizes */\n --sf-player-width: 240px;\n --sf-player-height: 336px;\n --sf-player-min-width: 80px;\n --sf-player-min-height: 80px;\n --sf-player-compact-width: 120px;\n --sf-player-compact-height: 120px;\n --sf-control-button-size: 24px;\n --sf-play-button-size: 60px;\n --sf-play-button-compact-size: 44px;\n --sf-minimize-button-size: 34px;\n --sf-mute-button-size: 32px;\n --sf-cc-button-size: 32px;\n --sf-cursor-size: 32px;\n \n /* Border radius */\n --sf-border-radius-sm: 4px;\n --sf-border-radius-md: 8px;\n --sf-border-radius-lg: 16px;\n --sf-border-radius-circle: 50%;\n \n /* Transitions */\n --sf-transition-fast: 0.1s ease;\n --sf-transition-normal: 0.2s ease;\n --sf-transition-slow: 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n \n /* Shadows */\n --sf-shadow-small: 0 2px 5px rgba(0, 0, 0, 0.2);\n --sf-shadow-medium: 0 4px 8px rgba(0, 0, 0, 0.15);\n --sf-shadow-large: 0 10px 25px rgba(0, 0, 0, 0.2);\n \n /* Z-index layering */\n --sf-z-index-base: 1;\n --sf-z-index-overlay: 2;\n --sf-z-index-controls: 10;\n --sf-z-index-cursor: 9999;\n --sf-z-index-player: 2147483648;\n \n /* Font sizes */\n --sf-font-size-sm: 14px;\n --sf-font-size-md: 16px;\n --sf-font-size-lg: 18px;\n --sf-font-size-xl: 24px;\n} \n\n/* Mobile device responsive adjustments - make player smaller for mobile screens */\n@media (max-width: 768px) {\n :host {\n /* Reduce player size on mobile for better space utilization */\n --sf-player-width: 180px; /* 25% smaller than desktop (240px -> 180px) */\n --sf-player-height: 252px; /* 25% smaller than desktop (336px -> 252px) */\n --sf-player-min-width: 60px; /* Smaller when minimized (80px -> 60px) */\n --sf-player-min-height: 60px; /* Smaller when minimized (80px -> 60px) */\n --sf-player-compact-width: 90px; /* Smaller compact mode for mobile (120px -> 90px) */\n --sf-player-compact-height: 90px; /* Smaller compact mode for mobile (120px -> 90px) */\n\n /* Keep controls touch-friendly despite smaller player size */\n --sf-play-button-size: 44px; /* Smaller but still touch-friendly (60px -> 44px) */\n --sf-play-button-compact-size: 36px; /* Touch-friendly compact play button */\n --sf-control-button-size: 28px; /* Keep larger for touch targets (24px -> 28px) */\n --sf-mute-button-size: 26px; /* Smaller for mobile (32px -> 26px) */\n --sf-cc-button-size: 26px; /* Smaller for mobile (32px -> 26px) */\n --sf-minimize-button-size: 26px; /* Match other mobile button sizes */\n }\n}\n\n/* Touch device specific adjustments (tablets and larger touch devices, excluding mobile) */\n@media (pointer: coarse) and (min-width: 769px) {\n :host {\n /* Ensure touch-friendly sizes even on larger touch devices */\n --sf-control-button-size: 28px;\n --sf-mute-button-size: 38px;\n --sf-cc-button-size: 38px;\n --sf-minimize-button-size: 38px; /* Match other touch device button sizes */\n }\n} ";
|
|
4229
|
-
const componentsPlayerCss = "/* \n * Player component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main player container */\n.sf-player {\n border-radius: var(--sf-border-radius-md);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15), 0 5px 15px rgba(0, 0, 0, 0.08);\n position: relative;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n opacity: 0;\n /* Only transition opacity initially - prevents size flicker on load */\n transition: opacity 0.3s ease-in-out;\n}\n\n/* Player visible state - show with fade in and enable size transitions */\n.sf-player--visible {\n opacity: 1;\n /* Enable size transitions only after player is visible to prevent initial flicker */\n transition: opacity 0.3s ease-in-out,\n width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n height 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n border-radius 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Gradient overlay now moved to video container - see _video.css */\n\n/* Full-size player state */\n.sf-player:not(.sf-player--minimized) {\n width: var(--sf-player-width);\n height: var(--sf-player-height);\n}\n\n/* Autoplay fallback state - ensure play button is visible */\n.sf-player--waiting-for-user-interaction .sf-controls-container__play-button {\n display: flex !important;\n opacity: 1 !important;\n visibility: visible !important;\n}\n\n/* Also show the center play button in autoplay fallback state */\n.sf-player--waiting-for-user-interaction .sf-player__center-play-button {\n display: flex !important;\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 20) !important; /* Higher z-index to appear above overlay */\n}\n\n/* Make the autoplay fallback state more prominent to indicate need for interaction */\n.sf-player--waiting-for-user-interaction::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n}\n\n/* Player state: minimized */\n.sf-player--minimized {\n /* Equal width and height are essential for maintaining a perfect circle when using border-radius: 50% */\n width: var(--sf-player-min-width);\n height: var(--sf-player-min-height);\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.20), 0 5px 15px rgba(0, 0, 0, 0.12);\n cursor: pointer;\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-min-width) !important;\n max-height: var(--sf-player-min-height) !important;\n min-width: var(--sf-player-min-width) !important;\n min-height: var(--sf-player-min-height) !important;\n}\n\n/* Player state: compact (first step, small rounded) */\n.sf-player--compact {\n width: var(--sf-player-compact-width) !important;\n height: var(--sf-player-compact-height) !important;\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.20), 0 5px 15px rgba(0, 0, 0, 0.12);\n cursor: pointer; /* Whole bubble is clickable */\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-compact-width) !important;\n max-height: var(--sf-player-compact-height) !important;\n min-width: var(--sf-player-compact-width) !important;\n min-height: var(--sf-player-compact-height) !important;\n}\n\n/* Hide center play button in compact mode - the whole bubble is clickable */\n.sf-player--compact .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Hide elements in compact mode */\n.sf-player--compact .sf-player__logo,\n.sf-player--compact .sf-player__minimize-button {\n display: none;\n}\n\n/* Hide gradient overlay when in compact mode - see _video.css */\n.sf-player--compact .sf-video-container::after {\n display: none;\n}\n\n/* Hide controls when minimized */\n.sf-player--minimized .sf-controls-container {\n display: none;\n}\n\n/* Hide controls when in compact mode */\n.sf-player--compact .sf-controls-container {\n display: none;\n}\n\n/* Only show the minimize button when hovering on minimized player */\n.sf-player--minimized .sf-player__minimize-button {\n opacity: 0;\n}\n\n.sf-player--minimized:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Player root element */\n#sf-player-root {\n position: fixed;\n z-index: var(--sf-z-index-player);\n}\n\n/* Fixed positioning classes */\n.sf-player-root--bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.sf-player-root--bottom-right {\n bottom: 20px;\n right: 20px;\n}\n\n/* Player error message */\n.sf-player__error {\n padding: var(--sf-spacing-md);\n color: var(--sf-error-color);\n background-color: var(--sf-error-bg);\n border-radius: var(--sf-border-radius-md);\n margin: var(--sf-spacing-sm);\n font-size: var(--sf-font-size-sm);\n border-left: 4px solid var(--sf-error-color);\n}\n\n/* Minimize button */\n.sf-player__minimize-button {\n position: absolute;\n top: 8px;\n right: 4px;\n width: var(--sf-minimize-button-size);\n height: var(--sf-minimize-button-size);\n background: none !important;\n border-radius: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-sm) + 4px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Minimize button background circle */\n.sf-player__minimize-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n/* Minimize button hover state */\n.sf-player__minimize-button:hover {\n transform: scale(1.1);\n}\n\n/* Show minimize button on player hover */\n.sf-player:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Mobile and touch device overrides for minimize button visibility */\n/* Ensure minimize button is always visible on touch devices, even when minimized */\n@media (pointer: coarse) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n}\n\n/* Ensure minimize button is always visible on mobile screens under 768px */\n@media (max-width: 768px) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n}\n\n/* Player title */\n.sf-player__title {\n position: absolute;\n top: var(--sf-spacing-md);\n left: var(--sf-spacing-md);\n color: var(--sf-text-color);\n font-size: var(--sf-font-size-md);\n font-weight: 600;\n z-index: var(--sf-z-index-controls);\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\n max-width: 70%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Centered play/pause button overlay */\n.sf-player__center-play-button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: none; /* Hidden by default */\n justify-content: center;\n align-items: center;\n z-index: calc(var(--sf-z-index-controls) + 10); /* Ensure higher z-index than other elements */\n color: white;\n border: none;\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal), opacity var(--sf-transition-normal);\n backdrop-filter: blur(1px);\n -webkit-backdrop-filter: blur(1px);\n pointer-events: auto; /* Enable pointer events to capture clicks */\n}\n\n/* Icon visibility control - use opacity for smooth transitions */\n.sf-player__center-play-button__pause-icon,\n.sf-player__center-play-button__play-icon {\n position: absolute;\n transition: opacity var(--sf-transition-normal);\n}\n\n.sf-player__center-play-button__pause-icon {\n opacity: 0;\n}\n\n.sf-player__center-play-button__play-icon {\n opacity: 1;\n}\n\n/* When playing, make button hoverable but invisible (desktop only) */\n@media (hover: hover) and (pointer: fine) {\n .sf-player--playing .sf-player__center-play-button {\n display: flex;\n opacity: 0;\n pointer-events: auto;\n }\n\n /* Show pause icon on hover when playing */\n .sf-player--playing .sf-player__center-play-button:hover {\n opacity: 1;\n }\n\n .sf-player--playing .sf-player__center-play-button:hover .sf-player__center-play-button__play-icon {\n opacity: 0;\n transition: none; /* Instant switch when hovering during playback */\n }\n\n .sf-player--playing .sf-player__center-play-button:hover .sf-player__center-play-button__pause-icon {\n opacity: 1;\n transition: none; /* Instant switch when hovering during playback */\n }\n\n /* Delay icon switch when not hovering during playback so pause icon stays visible during fade-out */\n .sf-player--playing .sf-player__center-play-button .sf-player__center-play-button__play-icon,\n .sf-player--playing .sf-player__center-play-button .sf-player__center-play-button__pause-icon {\n transition: opacity 0s 0.2s; /* Instant transition but delayed by button fade duration */\n }\n}\n\n/* Replay icon hidden by default */\n.sf-player__center-play-button__replay-icon {\n opacity: 0;\n position: absolute;\n transition: opacity var(--sf-transition-normal);\n}\n\n/* Show replay icon when video completed or waiting for interaction */\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__replay-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__replay-icon {\n opacity: 1;\n transition: none;\n}\n\n/* Hide play/pause icons when showing replay */\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__play-icon,\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__pause-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__play-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__pause-icon {\n opacity: 0;\n transition: none;\n}\n\n/* Center play button visible state */\n.sf-player__center-play-button--visible {\n display: flex !important;\n}\n\n/* Center play button prominent state (for autoplay blocked, idle mode) */\n.sf-player__center-play-button--prominent {\n opacity: 1 !important;\n pointer-events: auto !important;\n}\n\n/* Center play button hover state */\n.sf-player__center-play-button:hover {\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n/* Hide center play button in minimized state */\n.sf-player--minimized .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Center play button with dynamic positioning when buttons are present */\n/* Positions button centered between top of player and top of first button */\n.sf-player__center-play-button--with-buttons {\n /* Available space above buttons = playerHeight - bottomSpacing - buttonContainerHeight */\n /* Center point = availableSpace / 2 */\n top: calc((var(--sf-player-height) - var(--sf-spacing-xl) - var(--sf-button-container-height, 0px)) / 2) !important;\n transform: translate(-50%, -50%) !important;\n}\n\n/* Maintain scale on hover for buttons with dynamic positioning */\n.sf-player__center-play-button--with-buttons:hover {\n transform: translate(-50%, -50%) scale(1.1) !important;\n}\n\n/* Exit button for minimized mode */\n.sf-player__exit-button {\n position: absolute;\n top: -22px; /* Position it above the player */\n right: 0;\n width: 22px;\n height: 22px;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: var(--sf-font-size-md);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.sf-player__exit-button svg {\n width: 18px;\n height: 18px;\n}\n\n/* Exit button hover state */\n.sf-player__exit-button:hover {\n transform: scale(1.1);\n background-color: rgba(0, 0, 0, 0.7);\n}\n\n/* Show exit button on minimized player hover */\n.sf-player--minimized:hover .sf-player__exit-button {\n opacity: 1;\n}\n\n/* Saltfish logo */\n.sf-player__logo {\n position: absolute;\n bottom: var(--sf-spacing-xs);\n left: 0;\n right: 0;\n height: 18px;\n z-index: var(--sf-z-index-controls);\n opacity: 0.7;\n transition: opacity var(--sf-transition-normal);\n cursor: pointer;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.sf-player__logo svg {\n width: 55px;\n height: 20px;\n}\n\n/* Logo hover state */\n.sf-player:hover .sf-player__logo {\n opacity: 0.9;\n}\n\n/* Hide logo when minimized */\n.sf-player--minimized .sf-player__logo {\n display: none;\n} ";
|
|
4225
|
+
const componentsPlayerCss = "/* \n * Player component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main player container */\n.sf-player {\n border-radius: var(--sf-border-radius-md);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15), 0 5px 15px rgba(0, 0, 0, 0.08);\n position: relative;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n opacity: 0;\n /* Smooth transitions for size changes and opacity */\n transition: opacity 0.3s ease-in-out,\n width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n height 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n border-radius 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Player visible state - show with fade in */\n.sf-player--visible {\n opacity: 1;\n}\n\n/* Gradient overlay now moved to video container - see _video.css */\n\n/* Full-size player state */\n.sf-player:not(.sf-player--minimized) {\n width: var(--sf-player-width);\n height: var(--sf-player-height);\n}\n\n/* Autoplay fallback state - ensure play button is visible */\n.sf-player--waiting-for-user-interaction .sf-controls-container__play-button {\n display: flex !important;\n opacity: 1 !important;\n visibility: visible !important;\n}\n\n/* Also show the center play button in autoplay fallback state */\n.sf-player--waiting-for-user-interaction .sf-player__center-play-button {\n display: flex !important;\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 20) !important; /* Higher z-index to appear above overlay */\n}\n\n/* Make the autoplay fallback state more prominent to indicate need for interaction */\n.sf-player--waiting-for-user-interaction::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n}\n\n/* Player state: minimized */\n.sf-player--minimized {\n /* Equal width and height are essential for maintaining a perfect circle when using border-radius: 50% */\n width: var(--sf-player-min-width);\n height: var(--sf-player-min-height);\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.20), 0 5px 15px rgba(0, 0, 0, 0.12);\n cursor: pointer;\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-min-width) !important;\n max-height: var(--sf-player-min-height) !important;\n min-width: var(--sf-player-min-width) !important;\n min-height: var(--sf-player-min-height) !important;\n}\n\n/* Player state: compact (first step, small rounded) */\n.sf-player--compact {\n width: var(--sf-player-compact-width) !important;\n height: var(--sf-player-compact-height) !important;\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.20), 0 5px 15px rgba(0, 0, 0, 0.12);\n cursor: pointer; /* Whole bubble is clickable */\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-compact-width) !important;\n max-height: var(--sf-player-compact-height) !important;\n min-width: var(--sf-player-compact-width) !important;\n min-height: var(--sf-player-compact-height) !important;\n}\n\n/* Hide center play button in compact mode - the whole bubble is clickable */\n.sf-player--compact .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Hide elements in compact mode */\n.sf-player--compact .sf-player__logo,\n.sf-player--compact .sf-player__minimize-button {\n display: none;\n}\n\n/* Hide gradient overlay when in compact mode - see _video.css */\n.sf-player--compact .sf-video-container::after {\n display: none;\n}\n\n/* Hide controls when minimized */\n.sf-player--minimized .sf-controls-container {\n display: none;\n}\n\n/* Hide controls when in compact mode */\n.sf-player--compact .sf-controls-container {\n display: none;\n}\n\n/* Only show the minimize button when hovering on minimized player */\n.sf-player--minimized .sf-player__minimize-button {\n opacity: 0;\n}\n\n.sf-player--minimized:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Player root element */\n#sf-player-root {\n position: fixed;\n z-index: var(--sf-z-index-player);\n}\n\n/* Fixed positioning classes */\n.sf-player-root--bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.sf-player-root--bottom-right {\n bottom: 20px;\n right: 20px;\n}\n\n/* Player error message */\n.sf-player__error {\n padding: var(--sf-spacing-md);\n color: var(--sf-error-color);\n background-color: var(--sf-error-bg);\n border-radius: var(--sf-border-radius-md);\n margin: var(--sf-spacing-sm);\n font-size: var(--sf-font-size-sm);\n border-left: 4px solid var(--sf-error-color);\n}\n\n/* Minimize button */\n.sf-player__minimize-button {\n position: absolute;\n top: 8px;\n right: 4px;\n width: var(--sf-minimize-button-size);\n height: var(--sf-minimize-button-size);\n background: none !important;\n border-radius: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-sm) + 4px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Minimize button background circle */\n.sf-player__minimize-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n/* Minimize button hover state */\n.sf-player__minimize-button:hover {\n transform: scale(1.1);\n}\n\n/* Show minimize button on player hover */\n.sf-player:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Mobile and touch device overrides for minimize button visibility */\n/* Ensure minimize button is always visible on touch devices, even when minimized */\n@media (pointer: coarse) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n}\n\n/* Ensure minimize button is always visible on mobile screens under 768px */\n@media (max-width: 768px) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n}\n\n/* Player title */\n.sf-player__title {\n position: absolute;\n top: var(--sf-spacing-md);\n left: var(--sf-spacing-md);\n color: var(--sf-text-color);\n font-size: var(--sf-font-size-md);\n font-weight: 600;\n z-index: var(--sf-z-index-controls);\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\n max-width: 70%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Centered play/pause button overlay */\n.sf-player__center-play-button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: none; /* Hidden by default */\n justify-content: center;\n align-items: center;\n z-index: calc(var(--sf-z-index-controls) + 10); /* Ensure higher z-index than other elements */\n color: white;\n border: none;\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal), opacity var(--sf-transition-normal);\n backdrop-filter: blur(1px);\n -webkit-backdrop-filter: blur(1px);\n pointer-events: auto; /* Enable pointer events to capture clicks */\n}\n\n/* Icon visibility control - use opacity for smooth transitions */\n.sf-player__center-play-button__pause-icon,\n.sf-player__center-play-button__play-icon {\n position: absolute;\n transition: opacity var(--sf-transition-normal);\n}\n\n.sf-player__center-play-button__pause-icon {\n opacity: 0;\n}\n\n.sf-player__center-play-button__play-icon {\n opacity: 1;\n}\n\n/* When playing, make button hoverable but invisible (desktop only) */\n@media (hover: hover) and (pointer: fine) {\n .sf-player--playing .sf-player__center-play-button {\n display: flex;\n opacity: 0;\n pointer-events: auto;\n }\n\n /* Show pause icon on hover when playing */\n .sf-player--playing .sf-player__center-play-button:hover {\n opacity: 1;\n }\n\n .sf-player--playing .sf-player__center-play-button:hover .sf-player__center-play-button__play-icon {\n opacity: 0;\n transition: none; /* Instant switch when hovering during playback */\n }\n\n .sf-player--playing .sf-player__center-play-button:hover .sf-player__center-play-button__pause-icon {\n opacity: 1;\n transition: none; /* Instant switch when hovering during playback */\n }\n\n /* Delay icon switch when not hovering during playback so pause icon stays visible during fade-out */\n .sf-player--playing .sf-player__center-play-button .sf-player__center-play-button__play-icon,\n .sf-player--playing .sf-player__center-play-button .sf-player__center-play-button__pause-icon {\n transition: opacity 0s 0.2s; /* Instant transition but delayed by button fade duration */\n }\n}\n\n/* Replay icon hidden by default */\n.sf-player__center-play-button__replay-icon {\n opacity: 0;\n position: absolute;\n transition: opacity var(--sf-transition-normal);\n}\n\n/* Show replay icon when video completed or waiting for interaction */\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__replay-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__replay-icon {\n opacity: 1;\n transition: none;\n}\n\n/* Hide play/pause icons when showing replay */\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__play-icon,\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__pause-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__play-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__pause-icon {\n opacity: 0;\n transition: none;\n}\n\n/* Center play button visible state */\n.sf-player__center-play-button--visible {\n display: flex !important;\n}\n\n/* Center play button prominent state (for autoplay blocked, idle mode) */\n.sf-player__center-play-button--prominent {\n opacity: 1 !important;\n pointer-events: auto !important;\n}\n\n/* Center play button hover state */\n.sf-player__center-play-button:hover {\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n/* Hide center play button in minimized state */\n.sf-player--minimized .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Center play button with dynamic positioning when buttons are present */\n/* Positions button centered between top of player and top of first button */\n.sf-player__center-play-button--with-buttons {\n /* Available space above buttons = playerHeight - bottomSpacing - buttonContainerHeight */\n /* Center point = availableSpace / 2 */\n top: calc((var(--sf-player-height) - var(--sf-spacing-xl) - var(--sf-button-container-height, 0px)) / 2) !important;\n transform: translate(-50%, -50%) !important;\n}\n\n/* Maintain scale on hover for buttons with dynamic positioning */\n.sf-player__center-play-button--with-buttons:hover {\n transform: translate(-50%, -50%) scale(1.1) !important;\n}\n\n/* Exit button for minimized mode */\n.sf-player__exit-button {\n position: absolute;\n top: -22px; /* Position it above the player */\n right: 0;\n width: 22px;\n height: 22px;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: var(--sf-font-size-md);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.sf-player__exit-button svg {\n width: 18px;\n height: 18px;\n}\n\n/* Exit button hover state */\n.sf-player__exit-button:hover {\n transform: scale(1.1);\n background-color: rgba(0, 0, 0, 0.7);\n}\n\n/* Show exit button on minimized player hover */\n.sf-player--minimized:hover .sf-player__exit-button {\n opacity: 1;\n}\n\n/* Saltfish logo */\n.sf-player__logo {\n position: absolute;\n bottom: var(--sf-spacing-xs);\n left: 0;\n right: 0;\n height: 18px;\n z-index: var(--sf-z-index-controls);\n opacity: 0.7;\n transition: opacity var(--sf-transition-normal);\n cursor: pointer;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.sf-player__logo svg {\n width: 55px;\n height: 20px;\n}\n\n/* Logo hover state */\n.sf-player:hover .sf-player__logo {\n opacity: 0.9;\n}\n\n/* Hide logo when minimized */\n.sf-player--minimized .sf-player__logo {\n display: none;\n} ";
|
|
4230
4226
|
const componentsVideoCss = "/* \n * Video component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Video container */\n.sf-video-container {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: var(--sf-border-radius-md);\n overflow: hidden;\n pointer-events: auto; /* Ensure clicks on video container are captured */\n background-color: #000; /* Fallback background for audio-only mode */\n /* Force clean border-radius clipping */\n isolation: isolate;\n transform: translateZ(0);\n -webkit-mask-image: -webkit-radial-gradient(white, black);\n /* Ensure video container and its children (including captions) sit above the gradient overlay */\n z-index: 3;\n /* Smooth transition for border-radius changes */\n transition: border-radius var(--sf-transition-slow);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-lg) var(--sf-border-radius-lg);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-lg) var(--sf-border-radius-lg);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Audio fallback poster image */\n.sf-video-container--audio-fallback {\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n background-image: var(--sf-audio-poster-url, none);\n}\n\n/* Audio fallback overlay */\n.sf-audio-fallback-overlay {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.6);\n z-index: 2;\n pointer-events: none;\n}\n\n/* Avatar mode overlay - no background, just container */\n.sf-audio-fallback-overlay--avatar {\n background: none;\n}\n\n.sf-audio-fallback-overlay__icon {\n width: 60px;\n height: 60px;\n margin-bottom: 16px;\n color: white;\n opacity: 0.9;\n}\n\n.sf-audio-fallback-overlay__text {\n color: white;\n font-size: 14px;\n text-align: center;\n padding: 0 20px;\n text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);\n opacity: 0.9;\n}\n\n.sf-audio-fallback-overlay__avatar {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n z-index: 1;\n}\n\n/* Semi-transparent overlay on top of avatar */\n.sf-audio-fallback-overlay__dim {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.3);\n z-index: 2;\n}\n\n/* Soundbar-only mode overlay - dark background for soundbar visibility */\n.sf-audio-fallback-overlay--soundbar-only {\n background: rgba(0, 0, 0, 0.85);\n}\n\n/* Audio visualization soundbar container */\n.sf-audio-soundbar {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 120px;\n width: auto;\n max-width: 300px;\n z-index: 3;\n position: relative;\n padding: 0 20px;\n}\n\n/* Individual soundbar frequency bar */\n.sf-audio-soundbar__bar {\n flex: 1;\n min-width: 8px;\n max-width: 20px;\n height: 10%; /* Default minimum height */\n background-color: hsla(180, 70%, 60%, 0.3);\n border-radius: 4px;\n transition: height 0.05s ease-out, background-color 0.1s ease-out;\n transform-origin: center;\n will-change: height, background-color;\n}\n\n/* Video element */\n.sf-video-container__video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n /* Ensure video is visible on mobile */\n display: block;\n /* Add explicit positioning to ensure video is visible */\n position: relative;\n z-index: 1;\n /* Remove any border-radius - let container's overflow: hidden do the clipping */\n border-radius: 0;\n /* Force GPU acceleration for cleaner clipping with scale effect */\n transform: scale(1.04) translateZ(0);\n backface-visibility: hidden;\n transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Video blur effect (for end-of-video transitions) */\n.sf-video-container__video--blurred {\n filter: blur(3px);\n transform: scale(1.04) translateZ(0);\n transition: filter 0.3s ease-out, transform 0.3s ease-out;\n}\n\n\n\n/* Mobile-specific video styles */\n@media (max-width: 768px) {\n\n .sf-video-container__video {\n /* Force video dimensions on mobile */\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n /* Prevent video from being hidden */\n opacity: 1 !important;\n visibility: visible !important;\n position: relative !important;\n }\n \n /* Make controls more touch-friendly on mobile */\n .sf-video-container__controls {\n height: 5px; /* Thicker on mobile for easier touch */\n }\n \n /* Adjust pseudo-element for mobile touch target */\n .sf-video-container__controls::before {\n height: 14px; /* Larger touch target on mobile */\n }\n \n .sf-video-container__mute-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-mute-button-size) !important;\n min-height: var(--sf-mute-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n \n .sf-video-container__cc-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-cc-button-size) !important;\n min-height: var(--sf-cc-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n}\n\n/* Touch device specific styles */\n@media (pointer: coarse) {\n .sf-video-container__controls:hover {\n height: 5px; /* Keep consistent height on touch devices */\n }\n \n /* Maintain consistent clickable area on touch devices */\n .sf-video-container__controls::before,\n .sf-video-container__controls:hover::before {\n height: 14px; /* Consistent touch target */\n }\n \n .sf-video-container__mute-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container__cc-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n }\n}\n\n/* Video in minimized state */\n.sf-player--minimized .sf-video-container {\n border-radius: var(--sf-border-radius-circle);\n cursor: pointer;\n z-index: var(--sf-z-index-base);\n width: 100%;\n height: 100%;\n /* Ensure clean clipping in circular state */\n isolation: isolate;\n transform: translateZ(0);\n}\n\n/* Hide gradient overlay when minimized */\n.sf-player--minimized .sf-video-container::after {\n display: none;\n}\n\n.sf-player--minimized .sf-video-container__video {\n border-radius: 0; /* Let container handle clipping */\n object-fit: cover;\n width: 100%;\n height: 100%;\n transform: scale(1.2) translateZ(0);\n}\n\n/* Hide progress bar in minimized state */\n.sf-player--minimized .sf-video-container__controls {\n display: none !important;\n}\n\n/* Also hide mute button in minimized state */\n.sf-player--minimized .sf-video-container__mute-button {\n display: none !important;\n}\n\n/* Also hide CC button in minimized state */\n.sf-player--minimized .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Progress bar container */\n.sf-video-container__controls {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n width: 100%;\n height: 4px;\n background-color: rgba(255, 255, 255, 0.3);\n z-index: var(--sf-z-index-controls);\n /* Match the container's top border-radius for seamless integration */\n border-radius: var(--sf-border-radius-md) var(--sf-border-radius-md) 0 0;\n cursor: pointer;\n /* Ensure pixel-perfect alignment and edge-to-edge coverage */\n transform: translateZ(0);\n backface-visibility: hidden;\n /* Smooth transition for height change on hover */\n transition: height 0.15s ease-in-out, background-color 0.15s ease-in-out;\n /* Ensure it covers the full width */\n margin: 0;\n box-sizing: border-box;\n}\n\n/* Invisible pseudo-element to extend clickable area downward */\n.sf-video-container__controls::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 10px; /* Visual height (4px) + extended clickable area (6px) */\n cursor: pointer;\n}\n\n/* Show slightly thicker progress bar on hover for better UX */\n.sf-video-container__controls:hover {\n height: 6px;\n background-color: rgba(255, 255, 255, 0.35);\n}\n\n/* Extend pseudo-element when progress bar grows on hover */\n.sf-video-container__controls:hover::before {\n height: 12px; /* Visual height (6px) + extended clickable area (6px) */\n}\n\n/* Progress indicator */\n.sf-video-container__progress {\n height: 100%;\n background: linear-gradient(90deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.85) 100%);\n width: 0%;\n transition: width 0.1s linear;\n /* Only apply top-left border-radius to maintain seamless look */\n border-radius: var(--sf-border-radius-md) 0 0 0;\n cursor: pointer;\n transform-origin: left;\n /* Ensure smooth rendering */\n will-change: width;\n}\n\n/* Mute button */\n.sf-video-container__mute-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px);\n right: 4px;\n width: var(--sf-mute-button-size);\n height: var(--sf-mute-button-size);\n background: none !important;\n border-radius: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Mute button background circle */\n.sf-video-container__mute-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n/* Mute button hover state */\n.sf-video-container__mute-button:hover {\n transform: scale(1.1);\n}\n\n/* Show mute button on container hover */\n.sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n}\n\n/* CC button */\n.sf-video-container__cc-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px + var(--sf-mute-button-size) + 6px);\n right: 4px;\n width: var(--sf-cc-button-size);\n height: var(--sf-cc-button-size);\n background: none !important;\n border-radius: 0;\n padding: 0; /* Remove default button padding */\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* CC button background circle */\n.sf-video-container__cc-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n.sf-video-container__cc-button svg {\n display: block;\n margin: auto;\n width: 60%;\n height: 60%;\n}\n\n/* CC button hover state */\n.sf-video-container__cc-button:hover {\n transform: scale(1.1);\n}\n\n/* Compact mode styling - circular border-radius for video container */\n.sf-player--compact .sf-video-container {\n border-radius: var(--sf-border-radius-circle);\n}\n\n/* Hide gradient overlay in compact mode (already handled in _player.css but kept for clarity) */\n.sf-player--compact .sf-video-container::after {\n display: none;\n}\n\n/* Hide mute and cc buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-video-container__mute-button,\n.sf-player--autoplayBlocked .sf-video-container__cc-button,\n.sf-player--idleMode .sf-video-container__mute-button,\n.sf-player--idleMode .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Show mute and cc buttons on hover in playing/paused states */\n.sf-player--playing .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--playing .sf-video-container:hover .sf-video-container__cc-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__cc-button {\n opacity: 1;\n} ";
|
|
4231
4227
|
const componentsControlsCss = "/* \n * Controls component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main controls container */\n.sf-controls-container {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: transparent;\n z-index: var(--sf-z-index-controls);\n pointer-events: auto;\n}\n\n/* Play button */\n.sf-controls-container__play-button {\n background-color: rgba(0, 0, 0, 0.6);\n border: none;\n color: var(--sf-text-color);\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n justify-content: center;\n align-items: center;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal);\n padding-left: 4px; /* Optical centering for play icon */\n}\n\n/* Button hover state */\n.sf-controls-container__play-button:hover {\n background-color: rgba(0, 0, 0, 0.4);\n transform: scale(1.1);\n}\n\n/* Button container for interactive buttons */\n.sf-controls-container__buttons {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: var(--sf-spacing-md);\n}\n\n/* Interactive button */\n.sf-controls-container__interactive-button {\n background-color: rgba(255, 255, 255, 0.2);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n border: none;\n border-radius: var(--sf-border-radius-md);\n padding: var(--sf-spacing-xs) var(--sf-spacing-md);\n font-size: var(--sf-font-size-sm);\n cursor: pointer;\n transition: background-color var(--sf-transition-normal), transform var(--sf-transition-fast);\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n}\n\n.sf-controls-container__interactive-button:hover {\n background-color: rgba(255, 255, 255, 0.3);\n transform: translateY(-2px);\n}\n\n/* \n * Choice buttons container and buttons - positioned inside player\n */\n\n/* Choice buttons container - positioned inside the player at the bottom */\n.sf-choice-buttons-container {\n position: absolute;\n bottom: var(--sf-spacing-xl);\n left: 50%;\n transform: translateX(-50%);\n width: calc(100% - var(--sf-spacing-lg));\n max-width: calc(100% - var(--sf-spacing-lg));\n z-index: calc(var(--sf-z-index-controls) + 1);\n gap: var(--sf-spacing-sm);\n pointer-events: auto;\n align-items: center;\n display: flex;\n flex-direction: column;\n /* Ensure container is fully transparent */\n background: transparent;\n border: none;\n outline: none;\n}\n\n/* Choice buttons container with scrolling for 5+ buttons */\n.sf-choice-buttons-container--scrollable {\n max-height: 176px; /* Show ~4 buttons with gaps (4 * 36px button + 4 * 8px gap) */\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: thin; /* Show thin scrollbar in Firefox */\n scrollbar-color: rgba(255, 255, 255, 0.2) transparent; /* More transparent Firefox scrollbar */\n scroll-behavior: smooth;\n /* Important: Use block display for scrollable container */\n display: block !important;\n}\n\n/* Style webkit scrollbar to be visible but subtle */\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar {\n width: 4px;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2); /* More transparent */\n border-radius: 2px;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.4); /* Still subtle on hover */\n}\n\n/* Removed fade gradient to keep container fully transparent */\n\n/* Choice button styles - solid rounded buttons matching the image */\n.sf-choice-button {\n width: 100%;\n max-width: none;\n background: rgba(0, 0, 0, 4);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n border: none;\n border-radius: 24px; /* More rounded for pill shape */\n padding: var(--sf-spacing-md) var(--sf-spacing-md);\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s ease;\n text-align: center;\n outline: none;\n font-family: inherit;\n margin-bottom: 0;\n position: relative;\n overflow: hidden;\n opacity: 0; /* Start hidden for animation */\n pointer-events: none;\n /* Animation will be triggered by JavaScript when video reaches 90% */\n}\n\n/* Add margin between buttons in scrollable container */\n.sf-choice-buttons-container--scrollable .sf-choice-button {\n margin-bottom: var(--sf-spacing-sm);\n}\n\n/* Remove margin from last button */\n.sf-choice-buttons-container--scrollable .sf-choice-button:last-child {\n margin-bottom: 0;\n}\n\n/* Hover state for buttons */\n.sf-choice-button:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.8);\n}\n\n/* Active state for all buttons */\n.sf-choice-button:active {\n transform: translateY(0) scale(0.98);\n transition: all 0.1s ease;\n}\n\n/* Remove specific action type styling - use consistent dark buttons */\n.sf-choice-button--goto,\n.sf-choice-button--url,\n.sf-choice-button--next,\n.sf-choice-button--dom,\n.sf-choice-button--function {\n background: rgba(0, 0, 0, 0.4);\n border: none;\n}\n\n.sf-choice-button--goto:hover,\n.sf-choice-button--url:hover,\n.sf-choice-button--next:hover,\n.sf-choice-button--dom:hover,\n.sf-choice-button--function:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n}\n\n/* Hide choice buttons in minimized state */\n.sf-player--minimized .sf-choice-buttons-container {\n display: none !important;\n}\n\n/* Hide choice buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-choice-buttons-container,\n.sf-player--idleMode .sf-choice-buttons-container {\n display: none !important;\n}\n\n/* Smaller mobile screens - maintain same layout but with tighter spacing */\n@media (max-width: 480px) {\n .sf-choice-buttons-container {\n bottom: var(--sf-spacing-sm);\n width: calc(100% - var(--sf-spacing-md));\n max-width: calc(100% - var(--sf-spacing-md));\n gap: calc(var(--sf-spacing-xs) + 2px);\n }\n \n .sf-choice-button {\n padding: var(--sf-spacing-sm) var(--sf-spacing-sm);\n font-size: 11px;\n border-radius: 20px;\n }\n}\n\n/* Touch device specific adjustments */\n@media (pointer: coarse) {\n .sf-choice-buttons-container {\n gap: var(--sf-spacing-sm);\n }\n \n .sf-choice-button {\n min-height: 44px; /* Apple's recommended minimum touch target size */\n padding: var(--sf-spacing-md) var(--sf-spacing-md);\n }\n}\n\n/* Button fade-in animation */\n@keyframes buttonFadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Animation class that will be added by JavaScript at 90% video progress */\n.sf-choice-button.sf-show-button {\n animation: buttonFadeIn 0.3s ease-out forwards;\n pointer-events: auto;\n}\n\n/* Staggered animation delays for multiple buttons when shown */\n.sf-choice-button.sf-show-button:nth-child(1) {\n animation-delay: 0s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(2) {\n animation-delay: 0.15s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(3) {\n animation-delay: 0.3s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(4) {\n animation-delay: 0.45s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(5) {\n animation-delay: 0.6s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(6) {\n animation-delay: 0.75s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(7) {\n animation-delay: 0.9s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(8) {\n animation-delay: 1.05s;\n}\n\n/* Scroll indicator arrow */\n.sf-scroll-indicator {\n position: absolute;\n bottom: calc(var(--sf-spacing-xl) - 25px);\n left: 50%;\n transform: translateX(-50%);\n color: rgba(255, 255, 255, 0.6);\n font-size: 20px;\n pointer-events: none;\n z-index: calc(var(--sf-z-index-controls) + 2);\n transition: opacity 0.3s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0; /* Start hidden */\n}\n\n/* Show scroll indicator with animation - appears after buttons */\n.sf-scroll-indicator.sf-show-scroll-indicator {\n animation: scrollIndicatorFadeIn 0.4s ease-out 1.2s forwards, bounceArrow 1.5s ease-in-out 1.6s infinite;\n}\n\n/* Hide arrow when scrolled to bottom */\n.sf-scroll-indicator--hidden {\n opacity: 0;\n}\n\n/* Fade in animation for scroll indicator */\n@keyframes scrollIndicatorFadeIn {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n\n/* Bounce animation for the arrow */\n@keyframes bounceArrow {\n 0%, 100% {\n transform: translateX(-50%) translateY(0);\n }\n 50% {\n transform: translateX(-50%) translateY(5px);\n }\n}\n\n/* Hide scroll indicator in minimized state */\n.sf-player--minimized .sf-scroll-indicator {\n display: none !important;\n}\n\n/* Hide scroll indicator in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-scroll-indicator,\n.sf-player--idleMode .sf-scroll-indicator {\n display: none !important;\n} ";
|
|
4232
4228
|
const componentsTranscriptCss = "/* \n * Transcript component styles for the Saltfish Playlist Player\n * Following BEM naming convention\n */\n\n/* Transcript container */\n.sf-transcript {\n position: absolute;\n bottom: 40px; /* Above the progress bar */\n left: 0;\n right: 0;\n max-height: 200px;\n background: transparent;\n margin: 0 var(--sf-spacing-md);\n overflow: hidden;\n z-index: var(--sf-z-index-controls);\n opacity: 0;\n transform: translateY(20px);\n transition: all 0.3s ease-out;\n pointer-events: none;\n}\n\n/* Visible state */\n.sf-transcript--visible {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n/* Transcript content */\n.sf-transcript__content {\n max-height: 180px;\n overflow: visible;\n padding: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n text-align: center;\n}\n\n/* Webkit scrollbar styling */\n.sf-transcript__content::-webkit-scrollbar {\n width: 4px;\n}\n\n.sf-transcript__content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.sf-transcript__content::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 2px;\n}\n\n.sf-transcript__content::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.5);\n}\n\n/* Word-by-word display container - progressive reveal style */\n.sf-transcript__word-container {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 0.04em; /* Much tighter gap to compensate for inverse scaling effect */\n min-height: 60px;\n padding: 0 var(--sf-spacing-md);\n flex-wrap: nowrap;\n overflow: hidden;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n text-align: center;\n transition: opacity 0.15s ease-in-out; /* Smooth fade during window transitions */\n}\n\n/* Individual word styling - base state (hidden by default) */\n.sf-transcript__word {\n color: rgba(255, 255, 255, 0.65);\n font-size: 20px; /* Increased from 18px to compensate for 0.893 scale (20 * 0.893 ≈ 18px) */\n font-weight: 500; /* Set to 500 from start to prevent pixel shift on activation */\n line-height: 1.3;\n white-space: nowrap;\n text-align: center;\n opacity: 0;\n transform: scale(0.893) translateY(0); /* Scaled down - active word will be normal size (1/1.12 ≈ 0.893) */\n transition: opacity 0.2s ease, color 0.2s ease, text-shadow 0.2s ease, transform 0.2s ease;\n padding-left: 0.12em; /* Consistent padding */\n padding-right: 0.12em;\n}\n\n/* Visible state - word has appeared */\n.sf-transcript__word--visible {\n opacity: 0.8;\n transform: scale(0.893) translateY(0); /* Keep scaled down */\n}\n\n/* Active word (currently speaking) - highlighted at normal size (inverse scale approach) */\n.sf-transcript__word--active {\n color: rgba(255, 255, 255, 1) !important;\n opacity: 1 !important;\n transform: scale(1) translateY(0); /* Normal size - appears 12% larger relative to scaled-down neighbors */\n text-shadow: 0 0 20px rgba(255, 255, 255, 0.3);\n /* font-weight removed - already 500 from base to prevent pixel shift */\n}\n\n/* Legacy segment styling (kept for compatibility) */\n.sf-transcript__segment {\n color: rgba(255, 255, 255);\n font-size: var(--sf-font-size-sm);\n line-height: 1.4;\n padding: var(--sf-spacing-xs) 0;\n cursor: pointer;\n transition: all 0.2s ease;\n padding-left: var(--sf-spacing-xs);\n padding-right: var(--sf-spacing-xs);\n}\n\n/* CC button styling removed - now handled via icon toggling */\n\n/* Mobile responsive styles */\n@media (max-width: 768px) {\n .sf-transcript {\n bottom: 35px; /* Positioned lower on mobile for better visibility */\n margin: 0 var(--sf-spacing-sm);\n max-height: 150px; /* Smaller on mobile */\n }\n\n .sf-transcript__content {\n max-height: 130px;\n padding: var(--sf-spacing-sm);\n }\n\n .sf-transcript__word-container {\n min-height: 50px;\n padding: 0 var(--sf-spacing-sm);\n gap: 0.2em; /* Tighter gap for mobile */\n }\n \n .sf-transcript__word {\n font-size: var(--sf-font-size-md);\n /* font-weight already 500 from base styles */\n }\n \n .sf-transcript__segment {\n font-size: var(--sf-font-size-xs);\n padding: var(--sf-spacing-xs) var(--sf-spacing-sm);\n }\n}\n\n/* Touch device optimizations */\n@media (pointer: coarse) {\n .sf-transcript__segment {\n padding: var(--sf-spacing-sm) var(--sf-spacing-xs);\n min-height: 44px; /* Larger touch target */\n display: flex;\n align-items: center;\n }\n}\n\n/* Hide transcript in minimized state */\n.sf-player--minimized .sf-transcript {\n display: none !important;\n}\n\n/* Hide transcript in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-transcript,\n.sf-player--idleMode .sf-transcript {\n display: none !important;\n}\n\n/* Animation for transcript appearance */\n@keyframes transcriptFadeIn {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes transcriptFadeOut {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(20px);\n }\n}";
|
|
@@ -12573,7 +12569,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
|
|
|
12573
12569
|
__proto__: null,
|
|
12574
12570
|
SaltfishPlayer
|
|
12575
12571
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
12576
|
-
const version = "0.3.
|
|
12572
|
+
const version = "0.3.70";
|
|
12577
12573
|
const packageJson = {
|
|
12578
12574
|
version
|
|
12579
12575
|
};
|