export const PLAYER_STYLES = /* css */ ` :host { display: block; position: relative; overflow: hidden; background: #000; contain: layout style; } .hfp-container { position: absolute; inset: 0; overflow: hidden; pointer-events: none; } .hfp-iframe { position: absolute; top: 50%; left: 50%; border: none; pointer-events: none; } .hfp-poster { position: absolute; inset: 0; object-fit: contain; z-index: 1; pointer-events: none; } .hfp-shader-loader { position: absolute; inset: 0; z-index: 20; display: grid; place-items: center; visibility: hidden; opacity: 0; pointer-events: none; background: #030504; color: #f4f7fb; cursor: default; user-select: none; -webkit-user-select: none; transition: opacity 420ms ease-out, visibility 420ms ease-out; } .hfp-shader-loader.hfp-visible, .hfp-shader-loader.hfp-hiding { visibility: visible; } .hfp-shader-loader.hfp-visible { opacity: 1; pointer-events: auto; } .hfp-shader-loader.hfp-hiding { opacity: 0; pointer-events: none; } .hfp-shader-loader-panel { display: grid; grid-template-rows: 86px 40px 26px 12px 44px; justify-items: center; align-items: center; gap: 8px; width: min(620px, 82%); text-align: center; font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } .hfp-shader-loader-mark { width: 86px; height: 86px; display: grid; place-items: center; overflow: visible; } .hfp-shader-loader-mark svg { display: block; overflow: visible; filter: drop-shadow(0 0 5px rgba(79, 219, 94, 0.16)); pointer-events: none; } .hfp-shader-loader-title { width: 100%; height: 40px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 26px; line-height: 40px; font-weight: 700; letter-spacing: 0; } .hfp-shader-loader-title-text { color: transparent; background: linear-gradient( 90deg, rgba(244, 247, 251, 0.84) 0%, #ffffff 42%, #80efe4 52%, #ffffff 62%, rgba(244, 247, 251, 0.84) 100% ); background-size: 220% 100%; -webkit-background-clip: text; background-clip: text; animation: hfp-shader-loader-sheen 1.9s linear infinite; } .hfp-shader-loader-detail { width: 100%; height: 26px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: rgba(244, 247, 251, 0.62); font-size: 15px; line-height: 26px; font-weight: 500; } .hfp-shader-loader-track { width: min(360px, 100%); height: 8px; overflow: hidden; border-radius: 999px; background: rgba(255, 255, 255, 0.1); } .hfp-shader-loader-fill { width: 100%; height: 100%; border-radius: inherit; background: linear-gradient(90deg, #06e3fa, #4fdb5e); transform: scaleX(0); transform-origin: left center; transition: transform 160ms ease; } .hfp-shader-loader-progress { width: min(420px, 100%); height: 44px; display: grid; grid-template-rows: repeat(2, 22px); color: rgba(244, 247, 251, 0.48); font: 600 13px/22px "IBM Plex Mono", "SF Mono", "Fira Code", "Courier New", monospace; font-variant-numeric: tabular-nums; } .hfp-shader-loader-row { display: grid; grid-template-columns: minmax(0, 1fr) 74px; align-items: center; column-gap: 20px; width: 100%; white-space: nowrap; } .hfp-shader-loader-label { min-width: 0; overflow: hidden; text-align: left; text-overflow: ellipsis; } .hfp-shader-loader-value { text-align: right; } @keyframes hfp-shader-loader-sheen { from { background-position: 140% 0; } to { background-position: -140% 0; } } /* ── Theming via CSS custom properties ── * * Override from outside the shadow DOM: * hyperframes-player { * --hfp-controls-bg: linear-gradient(transparent, rgba(0,0,0,0.9)); * --hfp-accent: #ff6b6b; * --hfp-font: "Inter", sans-serif; * } */ .hfp-controls { position: absolute; bottom: 0; left: 0; right: 0; display: flex; align-items: center; gap: var(--hfp-controls-gap, 12px); padding: var(--hfp-controls-padding, 8px 16px); background: var(--hfp-controls-bg, linear-gradient(transparent, rgba(0, 0, 0, 0.7))); color: var(--hfp-color, #fff); font-family: var(--hfp-font, system-ui, -apple-system, sans-serif); font-size: var(--hfp-font-size, 13px); z-index: 10; pointer-events: auto; opacity: 1; transition: opacity 0.3s ease; user-select: none; } .hfp-controls.hfp-hidden { opacity: 0; pointer-events: none; } .hfp-play-btn { background: none; border: none; color: var(--hfp-color, #fff); cursor: pointer; padding: 8px; display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; flex-shrink: 0; z-index: 10; } .hfp-play-btn:hover { opacity: 0.8; } .hfp-play-btn svg, .hfp-play-btn svg * { pointer-events: none; } .hfp-scrubber { flex: 1; min-width: 0; height: var(--hfp-scrubber-height, 4px); background: var(--hfp-scrubber-bg, rgba(255, 255, 255, 0.3)); border-radius: var(--hfp-scrubber-radius, 2px); cursor: pointer; position: relative; overflow: hidden; } .hfp-scrubber:hover { height: var(--hfp-scrubber-height-hover, 6px); } .hfp-progress { position: absolute; top: 0; left: 0; height: 100%; background: var(--hfp-accent, #fff); pointer-events: none; } .hfp-time { flex-shrink: 0; font-variant-numeric: tabular-nums; opacity: 0.9; } .hfp-speed-wrap { position: relative; flex-shrink: 0; } .hfp-speed-btn { background: var(--hfp-speed-btn-bg, rgba(255, 255, 255, 0.15)); border: none; border-radius: var(--hfp-speed-btn-radius, 4px); color: var(--hfp-color, #fff); cursor: pointer; font-family: var(--hfp-font, system-ui, -apple-system, sans-serif); font-size: 12px; font-variant-numeric: tabular-nums; font-weight: 600; padding: 4px 8px; min-width: 40px; text-align: center; transition: background 0.15s ease; } .hfp-speed-btn:hover { background: var(--hfp-speed-btn-bg-hover, rgba(255, 255, 255, 0.3)); } .hfp-speed-menu { position: absolute; bottom: calc(100% + 8px); right: 0; background: var(--hfp-menu-bg, rgba(20, 20, 20, 0.95)); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--hfp-menu-border, rgba(255, 255, 255, 0.1)); border-radius: var(--hfp-menu-radius, 8px); padding: 4px; display: flex; flex-direction: column; gap: 2px; min-width: 80px; opacity: 0; visibility: hidden; transform: translateY(4px); transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s; box-shadow: var(--hfp-menu-shadow, 0 8px 24px rgba(0, 0, 0, 0.4)); } .hfp-speed-menu.hfp-open { opacity: 1; visibility: visible; transform: translateY(0); } .hfp-speed-option { background: none; border: none; border-radius: 4px; color: var(--hfp-menu-color, rgba(255, 255, 255, 0.7)); cursor: pointer; font-family: var(--hfp-font, system-ui, -apple-system, sans-serif); font-size: 13px; font-variant-numeric: tabular-nums; padding: 6px 12px; text-align: left; transition: background 0.1s ease, color 0.1s ease; white-space: nowrap; } .hfp-speed-option:hover { background: var(--hfp-menu-hover-bg, rgba(255, 255, 255, 0.1)); color: var(--hfp-color, #fff); } .hfp-speed-option.hfp-active { color: var(--hfp-accent, #fff); font-weight: 600; } .hfp-volume-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; gap: 0; } .hfp-mute-btn { background: none; border: none; color: var(--hfp-color, #fff); cursor: pointer; padding: 4px; display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; flex-shrink: 0; } .hfp-mute-btn:hover { opacity: 0.8; } .hfp-mute-btn svg, .hfp-mute-btn svg * { pointer-events: none; } .hfp-volume-slider-wrap { width: 0; overflow: hidden; transition: width 0.2s ease; display: flex; align-items: center; } .hfp-volume-wrap:hover .hfp-volume-slider-wrap { width: 64px; } .hfp-volume-slider { width: 56px; height: var(--hfp-scrubber-height, 4px); background: var(--hfp-scrubber-bg, rgba(255, 255, 255, 0.3)); border-radius: var(--hfp-scrubber-radius, 2px); cursor: pointer; position: relative; overflow: hidden; margin-left: 4px; margin-right: 4px; } .hfp-volume-fill { position: absolute; top: 0; left: 0; height: 100%; background: var(--hfp-accent, #fff); pointer-events: none; } `; export const PLAY_ICON = ``; export const PAUSE_ICON = ``; export const VOLUME_HIGH_ICON = ``; export const VOLUME_LOW_ICON = ``; export const VOLUME_MUTED_ICON = ``; /** * Process-wide cache for the constructed PLAYER_STYLES sheet. Lazy so the * module stays SSR-safe (CSSStyleSheet is window-scoped) and so a single * sheet can be shared across every shadow root via `adoptedStyleSheets` — * the studio thumbnail grid renders dozens of players, and avoiding N * duplicate `