soulsync/webui/static/video/video-side.css
BoulderBadgeDad 80d504f94d Discover: meaningful filter colors + drop the asymmetric edge-fade
Colors now carry meaning instead of cycling by position:
- segments (Movies/TV, sort) → the app accent (they're modes, not categories)
- genre chips → a thematic colour per genre (Horror red, Comedy gold, Sci-Fi
  cyan, Romance pink, …) via a name→colour map; unmapped fall back to neutral
- provider chips → each service's brand colour (Netflix red, Disney+ blue, Max
  purple, Hulu green, …)
- era chips → a single warm amber; 'All/Any …' reset chips → neutral grey

Edge-fade: removed the mask-image from .vdsc-rail and .vdsc-chips. On short
filter rows only the left fade landed (dimming the first chip) while the right
fell on empty space — reading as a one-sided fade over everything.
2026-06-16 15:26:12 -07:00

2398 lines
145 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SoulSync — Video side shell styling.
*
* Loaded AFTER style.css so these rules win where specificity ties. Everything
* keys off body[data-side="music|video"] (set by video-side.js). The music side
* is the default and is never affected — these rules only do something once the
* body flips to data-side="video".
*/
/* ── The Music ↔ Video header toggle (animated sliding pill) ────────────── */
.side-toggle {
position: relative;
display: flex;
margin-top: 12px;
padding: 4px;
background: rgba(0, 0, 0, 0.28);
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 11px;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.35);
isolation: isolate;
}
/* The thumb that slides under the active side. Positioned over the left half by
default; slides to the right half when body[data-side="video"]. */
.side-toggle-thumb {
position: absolute;
z-index: 0;
top: 4px;
bottom: 4px;
left: 4px;
width: calc(50% - 4px);
border-radius: 8px;
background: linear-gradient(135deg,
rgb(var(--accent-rgb, 88 101 242)),
rgba(var(--accent-rgb, 88 101 242), 0.82));
box-shadow: 0 3px 10px rgba(var(--accent-rgb, 88 101 242), 0.35);
transition: transform 0.28s cubic-bezier(0.34, 1.3, 0.5, 1);
}
body[data-side="video"] .side-toggle-thumb {
transform: translateX(100%);
}
.side-toggle-btn {
position: relative;
z-index: 1;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 7px 6px;
font-size: 11.5px;
font-weight: 600;
letter-spacing: 0.02em;
color: var(--text-secondary, #9aa0aa);
background: transparent;
border: none;
border-radius: 8px;
cursor: pointer;
transition: color 0.2s ease;
}
.side-toggle-btn .side-toggle-icon {
width: 14px;
height: 14px;
flex: none;
opacity: 0.85;
transition: opacity 0.2s ease;
}
.side-toggle-btn:not(.active):hover {
color: var(--text-primary, #e8e8ea);
}
.side-toggle-btn.active {
color: #fff;
}
.side-toggle-btn.active .side-toggle-icon {
opacity: 1;
}
/* ── Nav swap: music nav vs video nav ──────────────────────────────────── */
/* The video nav reuses .sidebar-nav layout (same class) — only visibility
differs. Hidden by default (music side); shown when data-side="video". */
.video-nav {
display: none;
}
body[data-side="video"] nav.sidebar-nav:not(.video-nav) {
display: none;
}
body[data-side="video"] .video-nav {
display: flex;
}
/* ── Page visibility per side ──────────────────────────────────────────── */
/* Music pages hidden on the video side; video pages hidden on the music side.
The music router still controls .page.active among music pages; we just hide
the whole set while the video side is showing. */
body[data-side="music"] .page.video-page {
display: none !important;
}
body[data-side="video"] .page:not(.video-page) {
display: none !important;
}
body[data-side="video"] .page.video-page {
display: block;
}
/* ── Service status: not needed on the video side (for now) ─────────────── */
body[data-side="video"] .status-section {
display: none;
}
/* ── Shared pages: show the REAL music page on the video side ───────────── */
/* For now Settings is shown identically (no hiding of music-only bits yet).
The id selector + extra attribute outrank the blanket music-page hide rule. */
body[data-side="video"][data-video-page="video-settings"] #settings-page {
display: block !important;
}
body[data-side="video"][data-video-page="video-settings"] #video-page-host {
display: none !important;
}
/* Video-only additions inside the shared settings page (e.g. the Movies/TV
library mapping) — hidden on the music side. */
body[data-side="music"] [data-video-only] {
display: none !important;
}
/* Conversely, the music-library picker is irrelevant on the video side — hide
it there (the Movies/TV mapping is its replacement). */
body[data-side="video"] #plex-library-selector-container,
body[data-side="video"] #jellyfin-library-selector-container,
body[data-side="video"] #navidrome-folder-selector-container {
display: none !important;
}
/* Music-only settings sections (e.g. the music API services) are hidden on the
video side; their video counterparts carry data-video-only. */
body[data-side="video"] [data-music-only] {
display: none !important;
}
/* The whole Library tab is music-specific today (file-org templates, music
paths, post-processing, conversion, stats) — hide it all on the video side.
Future video library settings just need data-video-only to stay visible. */
body[data-side="video"] [data-stg="library"]:not([data-video-only]) {
display: none !important;
}
/* The video side has its OWN server section (Video Source above) and reuses the
shared Plex/Jellyfin credentials — so hide music's Server Connections group
entirely on the video side. Video never configures or selects the MUSIC server. */
body[data-side="video"] .settings-group[data-stg="connections"]:not([data-video-only]) {
display: none !important;
}
/* ── Dashboard header: match music, minus the sweep animation ──────────── */
/* The header reuses music's .dashboard-header markup/CSS for an identical look;
we only mute the ambient sweep on the video side (equiv may return later,
driven by meta sources). Scoped to data-side="video" so music is untouched. */
body[data-side="video"] .dashboard-header-sweep {
display: none;
}
/* ── Dashboard enrichment-worker buttons (isolated; music untouched) ────── */
.video-enrich-container { position: relative; }
/* Mirrors music's .musicbrainz-button accent treatment, driven by --ve-accent. */
.video-enrich-button {
position: relative;
width: 46px;
height: 46px;
border-radius: 50%;
border: 1.5px solid rgba(var(--ve-accent, 88, 101, 242), 0.25);
background: rgba(18, 18, 22, 0.85);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 4px 16px rgba(var(--ve-accent, 88, 101, 242), 0.2),
0 2px 8px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.video-enrich-button:hover {
transform: scale(1.05);
border-color: rgba(var(--ve-accent, 88, 101, 242), 0.4);
box-shadow: 0 6px 20px rgba(var(--ve-accent, 88, 101, 242), 0.3),
0 3px 12px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.video-enrich-button.active,
.video-enrich-button.complete {
border-color: rgba(var(--ve-accent, 88, 101, 242), 0.5);
box-shadow: 0 6px 24px rgba(var(--ve-accent, 88, 101, 242), 0.4),
0 3px 12px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
/* Paused → amber accent, identical to music's .musicbrainz-button.paused. */
.video-enrich-button.paused {
background: linear-gradient(135deg, rgba(255, 193, 7, 0.12) 0%, rgba(255, 152, 0, 0.18) 100%);
border-color: rgba(255, 193, 7, 0.35);
box-shadow: 0 4px 16px rgba(255, 193, 7, 0.2),
0 2px 8px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
.video-enrich-button.paused:hover {
border-color: rgba(255, 193, 7, 0.5);
box-shadow: 0 6px 20px rgba(255, 193, 7, 0.3), 0 3px 12px rgba(0, 0, 0, 0.2);
}
.video-enrich-button.disabled { opacity: 0.4; cursor: default; }
.video-enrich-logo {
width: 24px;
height: 24px;
object-fit: contain;
opacity: 0.85;
position: relative;
z-index: 1;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
transition: opacity 0.3s ease;
}
.video-enrich-button:hover .video-enrich-logo { opacity: 1; }
/* The TVDB brand mark is dark — invert it so it reads on the dark UI. */
.video-enrich-button[data-video-enrich="tvdb"] .video-enrich-logo {
filter: invert(1) drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
}
.video-enrich-spinner {
position: absolute;
width: 46px;
height: 46px;
border: 3px solid transparent;
border-top-color: rgba(var(--ve-accent, 88, 101, 242), 0.8);
border-right-color: rgba(var(--ve-accent, 88, 101, 242), 0.5);
border-radius: 50%;
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.video-enrich-button.active .video-enrich-spinner { opacity: 1; animation: video-enrich-spin 1.2s linear infinite; }
@keyframes video-enrich-spin { to { transform: rotate(360deg); } }
/* Tint the reused .tooltip-content with the service accent (music's default is
MusicBrainz purple; each service overrides — so we do the same per video svc). */
.video-enrich-tooltip .tooltip-content {
border-color: rgba(var(--ve-accent, 88, 101, 242), 0.3);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5),
0 6px 20px rgba(var(--ve-accent, 88, 101, 242), 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.video-enrich-tooltip .tooltip-header { color: rgba(var(--ve-accent, 88, 101, 242), 0.95); }
.video-enrich-tooltip .tooltip-content::before { border-bottom-color: rgba(var(--ve-accent, 88, 101, 242), 0.3); }
.video-enrich-tooltip [data-video-enrich-status] { color: rgb(var(--ve-accent, 88, 101, 242)); font-weight: 600; }
/* Paused status text goes amber too, matching music. */
.video-enrich-button.paused ~ .video-enrich-tooltip [data-video-enrich-status] { color: #ffc107; }
/* Positioning wrapper only — the content reuses music's shared .tooltip-content
/ .tooltip-header / .tooltip-body styling, so it looks identical to the music
enrichment tooltips. */
.video-enrich-tooltip {
position: absolute;
left: 50%;
top: calc(100% + 12px);
transform: translateX(-50%) translateY(-5px);
z-index: 5000;
opacity: 0;
visibility: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
pointer-events: none;
}
.video-enrich-container:hover .video-enrich-tooltip {
opacity: 1;
visibility: visible;
transform: translateX(-50%) translateY(0);
}
/* The Manage Workers button reuses music's .em-manage-btn* classes verbatim
(see index.html), so it needs no styling of its own here — identical by reuse. */
/* Service logo in the settings API-config frame headers (TMDB/TVDB). */
.video-svc-logo { width: 18px; height: 18px; object-fit: contain; margin-right: 2px; }
.video-svc-logo--tvdb { filter: invert(1); }
/* ── Video Manage-Workers modal: only the bits not covered by music's global
.em-* classes, ALL scoped to #vem-overlay so music is never affected. ───── */
#vem-overlay .vem-logo { width: 22px; height: 22px; object-fit: contain; }
#vem-overlay .vem-logo--tvdb { filter: invert(1); }
#vem-overlay .vem-icon {
width: 34px;
height: 34px;
border-radius: 9px;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.12);
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 800;
color: #fff;
flex-shrink: 0;
}
#vem-overlay .em-panel-header { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 6px; }
#vem-overlay .em-ph-main { display: flex; align-items: center; gap: 8px; font-size: 16px; }
#vem-overlay .em-ph-status { color: var(--text-secondary, #9aa0aa); font-size: 13px; }
#vem-overlay .em-ph-current { color: var(--text-secondary, #9aa0aa); font-size: 12px; opacity: 0.85; }
#vem-overlay .em-pause-btn {
margin-left: auto;
padding: 7px 16px;
border-radius: 9px;
border: 1px solid rgba(255, 255, 255, 0.12);
background: rgba(255, 255, 255, 0.06);
color: var(--text-primary, #e8e8ea);
font-size: 13px;
font-weight: 600;
cursor: pointer;
}
#vem-overlay .em-pause-btn:disabled { opacity: 0.45; cursor: default; }
#vem-overlay .em-unmatched-controls { display: flex; align-items: center; justify-content: space-between; margin: 14px 0 8px; }
#vem-overlay .em-section-sub { color: var(--text-secondary, #9aa0aa); font-size: 13px; }
#vem-overlay .em-retry-all-btn {
padding: 6px 14px;
border-radius: 8px;
border: 1px solid rgba(var(--accent-rgb, 88 101 242), 0.4);
background: rgba(var(--accent-rgb, 88 101 242), 0.12);
color: rgb(var(--accent-light-rgb, var(--accent-rgb, 88 101 242)));
font-size: 12px;
font-weight: 600;
cursor: pointer;
}
#vem-overlay .em-item {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 10px;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.05);
margin-bottom: 6px;
}
#vem-overlay .em-item-img {
width: 38px;
height: 56px;
object-fit: cover;
border-radius: 6px;
background: rgba(255, 255, 255, 0.06);
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
flex-shrink: 0;
}
#vem-overlay .em-item-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
#vem-overlay .em-item-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#vem-overlay .em-item-sub { font-size: 12px; color: var(--text-secondary, #9aa0aa); }
#vem-overlay .em-item-retry {
padding: 5px 12px;
border-radius: 7px;
border: 1px solid rgba(255, 255, 255, 0.12);
background: transparent;
color: var(--text-secondary, #9aa0aa);
font-size: 12px;
cursor: pointer;
}
#vem-overlay .em-item-retry:hover { color: #fff; border-color: rgba(255, 255, 255, 0.25); }
#vem-overlay .em-empty { padding: 30px; text-align: center; color: var(--text-secondary, #9aa0aa); }
#vem-overlay .em-pager { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 12px; }
#vem-overlay .em-pg {
width: 30px;
height: 30px;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.12);
background: rgba(255, 255, 255, 0.05);
color: var(--text-primary, #e8e8ea);
cursor: pointer;
}
#vem-overlay .em-pg:disabled { opacity: 0.4; cursor: default; }
#vem-overlay .em-pg-info { font-size: 13px; color: var(--text-secondary, #9aa0aa); }
/* ── Subpages: one built video page shown at a time ────────────────────── */
/* Each real page is a .video-subpage inside #video-page-host; the controller
toggles the [hidden] attribute. Be explicit so no reused .dash-* rule can
resurrect a hidden page. */
.video-subpage[hidden],
.video-placeholder-slot[hidden] {
display: none !important;
}
/* ── Placeholder content (for pages not built yet) ─────────────────────── */
.video-placeholder-slot {
padding: 48px 40px;
}
.video-placeholder-slot .header-title {
font-size: 22px;
font-weight: 700;
}
.video-placeholder-note {
margin-top: 10px;
color: var(--text-secondary, #9aa0aa);
font-size: 14px;
}
/* Empty-state line inside reused dashboard cards (e.g. Recent Downloads). */
.video-empty-note {
margin: 0;
padding: 8px 2px;
color: var(--text-secondary, #9aa0aa);
font-size: 14px;
}
/* ── Library page ──────────────────────────────────────────────────────── */
/* The grid/cards/search/alphabet all reuse the music library CSS verbatim.
The only video-specific bit is the Movies/Shows tab pill. */
.video-library-tabs {
display: flex;
gap: 6px;
padding: 4px;
margin: 0 auto 4px;
width: max-content;
background: rgba(0, 0, 0, 0.25);
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 12px;
}
.video-lib-tab {
padding: 8px 22px;
font-size: 13px;
font-weight: 600;
color: var(--text-secondary, #9aa0aa);
background: transparent;
border: none;
border-radius: 9px;
cursor: pointer;
transition: background 0.15s ease, color 0.15s ease;
}
.video-lib-tab:hover { color: var(--text-primary, #e8e8ea); }
.video-lib-tab.active {
color: #fff;
background: rgb(var(--accent-rgb, 88 101 242));
}
.video-library-filters {
display: flex;
gap: 10px;
justify-content: center;
margin: 4px 0;
}
/* Resolution chip on a poster card (top-left, above the gradient overlay). */
.library-artist-card .video-card-badge {
position: absolute;
top: 8px;
left: 8px;
z-index: 3;
padding: 2px 7px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.02em;
color: #fff;
background: rgba(0, 0, 0, 0.7);
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 5px;
backdrop-filter: blur(4px);
}
/* ════════════════════════════════════════════════════════════════════════════
Video detail page — NETFLIX style (isolated .vd-*; NOT the music layout).
--vd-accent-rgb is sampled from the poster at load for a per-show glow.
════════════════════════════════════════════════════════════════════════════ */
/* Break out of the host .page's 40px/90px padding so the billboard is truly
edge-to-edge (Netflix full-bleed) — no bare gaps around it. */
.vd-page { --vd-accent-rgb: var(--accent-rgb, 88, 101, 242); position: relative; margin: -40px -40px -90px; }
/* Sticky so it stays reachable on these long detail pages (negative bottom margin
pulls the billboard up under it, keeping the full-bleed overlay look). */
.vd-back {
position: sticky; top: 14px; z-index: 8; width: max-content;
margin: 0 0 -42px 22px;
display: inline-flex; align-items: center; gap: 7px;
padding: 8px 15px; border-radius: 999px;
background: rgba(0,0,0,0.55); border: 1px solid rgba(255,255,255,0.14);
color: #fff; font-size: 13px; font-weight: 600; cursor: pointer;
backdrop-filter: blur(10px); transition: background 0.2s ease, transform 0.2s ease;
}
.vd-back:hover { background: rgba(0,0,0,0.8); transform: translateX(-2px); }
.vd-back [data-vd-back-label] {
display: inline-block; max-width: 230px; overflow: hidden; text-overflow: ellipsis;
white-space: nowrap; vertical-align: bottom;
}
/* ── Billboard ─────────────────────────────────────────────────────────────── */
.vd-billboard { position: relative; width: 100%; min-height: 76vh; display: flex; align-items: flex-end; overflow: hidden; }
.vd-bb-bg {
position: absolute; inset: 0; background-size: cover; background-position: center 18%;
z-index: 0; transform: scale(1.02); animation: vdKenburns 24s ease-out forwards;
}
.vd-bb-bg--poster { background-position: center 28%; }
.vd-bb-bg--empty { background: radial-gradient(120% 90% at 70% 0%, rgba(var(--vd-accent-rgb), 0.4), #0b0b0f 65%); }
@keyframes vdKenburns { to { transform: scale(1.1); } }
.vd-bb-fade {
position: absolute; inset: 0; z-index: 1; pointer-events: none;
background:
linear-gradient(0deg, var(--bg-primary, #0b0b0f) 2%, rgba(11,11,15,0.55) 32%, rgba(11,11,15,0.1) 62%, rgba(11,11,15,0.45) 100%),
linear-gradient(90deg, rgba(11,11,15,0.92) 0%, rgba(11,11,15,0.55) 38%, transparent 72%);
}
.vd-bb-content {
position: relative; z-index: 2; max-width: 720px; padding: 0 0 52px 56px;
animation: vdRise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
@keyframes vdRise { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }
.vd-title {
font-size: clamp(2.6em, 5vw, 4.4em); line-height: 0.98; font-weight: 900; margin: 0 0 18px;
color: #fff; letter-spacing: -0.02em; text-shadow: 0 4px 30px rgba(0,0,0,0.7);
}
.vd-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-bottom: 16px;
font-size: 14px; font-weight: 600; color: rgba(255,255,255,0.82); }
.vd-meta > span { position: relative; }
.vd-meta > span + span::before { content: ''; position: absolute; left: -8px; top: 50%; width: 3px; height: 3px;
border-radius: 50%; background: rgba(255,255,255,0.4); transform: translateY(-50%); }
.vd-match { color: #4ade80 !important; font-weight: 800; }
.vd-score { color: #fbbf24 !important; font-weight: 800; }
.vd-tagline { font-size: 16px; font-style: italic; color: rgba(255,255,255,0.7); margin: -8px 0 14px;
text-shadow: 0 2px 12px rgba(0,0,0,0.6); }
.vd-genres { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.vd-genre { padding: 5px 13px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
color: rgba(255,255,255,0.85); background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.14);
backdrop-filter: blur(6px); }
.vd-meta-rating { padding: 1px 7px; border: 1px solid rgba(255,255,255,0.35); border-radius: 4px; font-size: 12px; }
.vd-status { color: rgb(var(--vd-accent-rgb)); }
.vd-overview { font-size: 16px; line-height: 1.6; color: rgba(255,255,255,0.86); margin: 0 0 22px; max-width: 640px;
text-shadow: 0 2px 12px rgba(0,0,0,0.6);
display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
/* Action buttons + source links reuse the music artist-detail classes verbatim
(.library-artist-watchlist-btn / .discog-download-btn / .artist-hero-badge);
only the billboard-specific bits live here. */
.vd-actions { margin-bottom: 16px; }
.vd-links { margin-bottom: 16px; }
.vd-links .artist-hero-badge[title="TVDB"] img { filter: invert(1); }
.vd-loading { padding: 50px 0; text-align: center; color: rgba(255,255,255,0.55); }
/* ── Episodes ──────────────────────────────────────────────────────────────── */
.vd-body { padding: 30px 56px 70px; }
.vd-ep-toolbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
.vd-ep-heading { font-size: 22px; font-weight: 800; color: #fff; margin: 0; }
.vd-toolbar-right { display: flex; align-items: center; gap: 12px; }
.vd-missing-toggle {
padding: 8px 14px; border-radius: 8px; cursor: pointer; font-size: 12.5px; font-weight: 700;
background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.14); color: rgba(255,255,255,0.8);
transition: all 0.2s ease;
}
.vd-missing-toggle:hover { background: rgba(255,255,255,0.1); }
.vd-missing-toggle--on { background: rgba(var(--vd-accent-rgb), 0.22); border-color: rgba(var(--vd-accent-rgb), 0.6); color: #fff; }
/* view toggle (rail / timeline / pills / dropdown) */
.vd-view-toggle { display: inline-flex; gap: 2px; padding: 3px; border-radius: 9px;
background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); }
.vd-vt-btn { width: 34px; height: 30px; border: 0; border-radius: 6px; background: transparent; cursor: pointer;
color: rgba(255,255,255,0.55); font-size: 14px; transition: all 0.18s ease; }
.vd-vt-btn:hover { background: rgba(255,255,255,0.08); color: #fff; }
.vd-vt-btn--active { background: rgba(var(--vd-accent-rgb), 0.85); color: #fff; box-shadow: 0 2px 10px rgba(var(--vd-accent-rgb), 0.4); }
.vd-season-nav { margin-bottom: 26px; }
.vd-season-nav:empty { margin: 0; }
/* — rail — */
.vd-rail { display: flex; gap: 14px; overflow-x: auto; padding: 6px 2px 14px; scroll-snap-type: x proximity; }
.vd-rail::-webkit-scrollbar { height: 8px; }
.vd-rail::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.15); border-radius: 4px; }
.vd-rcard { flex: 0 0 150px; width: 150px; text-align: left; padding: 0; cursor: pointer; scroll-snap-align: start;
border-radius: 12px; overflow: hidden; background: rgba(18,18,22,1); border: 1px solid rgba(255,255,255,0.07);
box-shadow: 0 4px 16px rgba(0,0,0,0.3); transition: transform 0.3s cubic-bezier(0.4,0,0.2,1), box-shadow 0.3s ease, border-color 0.3s ease; }
.vd-rcard:hover { transform: translateY(-5px); border-color: rgba(var(--vd-accent-rgb), 0.3);
box-shadow: 0 12px 36px rgba(0,0,0,0.5), 0 0 22px rgba(var(--vd-accent-rgb), 0.16); }
.vd-rcard--active { border-color: rgba(var(--vd-accent-rgb), 0.7); box-shadow: 0 12px 36px rgba(0,0,0,0.5), 0 0 26px rgba(var(--vd-accent-rgb), 0.32); }
.vd-rcard-art { position: relative; aspect-ratio: 2/3; overflow: hidden;
background: linear-gradient(135deg, rgba(var(--vd-accent-rgb), 0.2), rgba(var(--vd-accent-rgb), 0.05)); }
.vd-rcard-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.vd-rcard-fb { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 36px; opacity: 0.32; }
.vd-rcard-grad { position: absolute; inset: 0; background: linear-gradient(180deg, transparent 50%, rgba(10,10,14,0.85)); }
.vd-rcard-pct { position: absolute; top: 7px; right: 7px; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 800;
color: #fff; background: rgba(0,0,0,0.55); backdrop-filter: blur(4px); }
.vd-rcard-info { padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 5px; }
.vd-rcard-name { font-size: 13.5px; font-weight: 700; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vd-rcard-sub { font-size: 11.5px; color: rgba(255,255,255,0.55); }
.vd-rcard-bar { height: 5px; border-radius: 999px; background: rgba(255,255,255,0.1); overflow: hidden; }
.vd-rcard-bar > span { display: block; height: 100%; border-radius: 999px;
background: linear-gradient(90deg, rgb(var(--vd-accent-rgb)), rgba(var(--vd-accent-rgb), 0.5)); }
/* — timeline — */
.vd-timeline { display: flex; gap: 6px; align-items: stretch; }
.vd-tseg { position: relative; min-width: 84px; height: 76px; padding: 0; cursor: pointer; overflow: hidden;
border-radius: 10px; border: 1px solid rgba(255,255,255,0.1); background: rgba(255,255,255,0.04);
transition: all 0.25s ease; }
.vd-tseg:hover { border-color: rgba(var(--vd-accent-rgb), 0.45); transform: translateY(-2px); }
.vd-tseg--active { border-color: rgba(var(--vd-accent-rgb), 0.75); box-shadow: 0 6px 22px rgba(var(--vd-accent-rgb), 0.28); }
.vd-tseg-fill { position: absolute; left: 0; bottom: 0; top: 0; border-radius: 9px 0 0 9px;
background: linear-gradient(180deg, rgba(var(--vd-accent-rgb), 0.45), rgba(var(--vd-accent-rgb), 0.18)); }
.vd-tseg-label { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 3px; padding: 12px 14px; height: 100%; justify-content: center; }
.vd-tseg-name { font-size: 14px; font-weight: 700; color: #fff; white-space: nowrap; }
.vd-tseg-meta { font-size: 12px; color: rgba(255,255,255,0.7); }
/* — pills — */
.vd-pills { display: flex; flex-wrap: wrap; gap: 9px; }
.vd-pill-btn { display: inline-flex; align-items: center; gap: 9px; padding: 9px 16px; border-radius: 999px; cursor: pointer;
background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.14); color: rgba(255,255,255,0.82);
font-size: 13.5px; font-weight: 700; transition: all 0.2s ease; }
.vd-pill-btn:hover { background: rgba(255,255,255,0.1); border-color: rgba(var(--vd-accent-rgb), 0.4); }
.vd-pill-btn--active { background: rgba(var(--vd-accent-rgb), 0.9); border-color: transparent; color: #fff;
box-shadow: 0 4px 16px rgba(var(--vd-accent-rgb), 0.4); }
.vd-pill-meta { font-size: 11.5px; opacity: 0.8; }
.vd-pill-btn--active .vd-pill-meta { opacity: 0.95; }
.vd-ep-empty { padding: 40px 0; text-align: center; color: rgba(255,255,255,0.5); }
/* season dropdown */
.vd-season-select { position: relative; display: inline-block; }
.vd-ss-btn {
display: inline-flex; align-items: center; gap: 12px; padding: 10px 16px; min-width: 150px;
justify-content: space-between; border-radius: 8px; cursor: pointer;
background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.16);
color: #fff; font-size: 14px; font-weight: 700; transition: all 0.2s ease;
}
.vd-ss-btn:hover { background: rgba(255,255,255,0.1); border-color: rgba(var(--vd-accent-rgb), 0.5); }
.vd-ss-caret { font-size: 11px; opacity: 0.7; }
.vd-ss-menu {
position: absolute; top: calc(100% + 8px); right: 0; min-width: 220px; z-index: 20;
background: rgba(20,20,26,0.98); border: 1px solid rgba(255,255,255,0.12); border-radius: 10px;
box-shadow: 0 16px 44px rgba(0,0,0,0.6); padding: 6px; overflow: hidden;
opacity: 0; transform: translateY(-8px) scale(0.98); pointer-events: none;
transition: opacity 0.2s ease, transform 0.2s ease;
}
.vd-ss-menu--open { opacity: 1; transform: none; pointer-events: auto; }
.vd-ss-opt {
width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 14px;
padding: 10px 13px; border-radius: 7px; cursor: pointer; background: transparent; border: 0;
color: rgba(255,255,255,0.85); font-size: 14px; font-weight: 600; text-align: left; transition: background 0.15s ease;
}
.vd-ss-opt:hover { background: rgba(255,255,255,0.07); }
.vd-ss-opt--active { color: #fff; background: rgba(var(--vd-accent-rgb), 0.2); }
.vd-ss-opt-meta { font-size: 12px; color: rgba(255,255,255,0.5); }
/* episode rows */
.vd-episodes { border-top: 1px solid rgba(255,255,255,0.08); }
.vd-ep-anim .vd-ep { animation: vdEpIn 0.4s cubic-bezier(0.2,0.7,0.2,1) both; }
.vd-ep-anim .vd-ep:nth-child(2) { animation-delay: 0.03s; }
.vd-ep-anim .vd-ep:nth-child(3) { animation-delay: 0.06s; }
.vd-ep-anim .vd-ep:nth-child(4) { animation-delay: 0.09s; }
.vd-ep-anim .vd-ep:nth-child(n+5) { animation-delay: 0.12s; }
@keyframes vdEpIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.vd-ep {
display: grid; grid-template-columns: 48px 150px 1fr auto auto; align-items: center; gap: 20px;
padding: 18px 14px; border-bottom: 1px solid rgba(255,255,255,0.06);
transition: background 0.2s ease; cursor: pointer;
}
.vd-ep-chev { color: rgba(255,255,255,0.35); font-size: 16px; transition: transform 0.25s ease, color 0.2s ease; }
.vd-ep:hover .vd-ep-chev { color: rgba(255,255,255,0.7); }
.vd-ep--open .vd-ep-chev { transform: rotate(180deg); color: rgb(var(--vd-accent-rgb)); }
.vd-ep:hover { background: rgba(255,255,255,0.04); }
.vd-ep-index { font-size: 22px; font-weight: 800; color: rgba(255,255,255,0.4); text-align: center; }
.vd-ep:hover .vd-ep-index { color: rgb(var(--vd-accent-rgb)); }
.vd-ep-thumb {
position: relative; width: 150px; aspect-ratio: 16 / 9; border-radius: 8px; overflow: hidden;
background: linear-gradient(135deg, rgba(var(--vd-accent-rgb), 0.28), rgba(0,0,0,0.5));
display: flex; align-items: center; justify-content: center;
box-shadow: 0 4px 14px rgba(0,0,0,0.4);
}
.vd-ep-still { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.vd-ep-thumb-ic { position: relative; z-index: 1; font-size: 20px; color: #fff; opacity: 0; transform: scale(0.7);
transition: all 0.25s ease; text-shadow: 0 2px 10px rgba(0,0,0,0.7); }
.vd-ep:hover .vd-ep-thumb-ic { opacity: 1; transform: scale(1); }
.vd-ep:hover .vd-ep-still { filter: brightness(0.7); transition: filter 0.25s ease; }
.vd-ep-info { min-width: 0; }
.vd-ep-top { display: flex; align-items: baseline; gap: 12px; margin-bottom: 5px; }
.vd-ep-title { font-size: 15.5px; font-weight: 700; color: #fff; }
.vd-ep-rt { font-size: 12.5px; color: rgba(255,255,255,0.5); white-space: nowrap; }
.vd-ep-desc { margin: 0; font-size: 13.5px; line-height: 1.5; color: rgba(255,255,255,0.62);
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.vd-ep-badge { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.6px;
padding: 5px 12px; border-radius: 999px; white-space: nowrap; }
.vd-ep--owned .vd-ep-badge { color: #4ade80; background: rgba(74,222,128,0.12); border: 1px solid rgba(74,222,128,0.32); }
.vd-ep--missing .vd-ep-badge { color: rgba(255,255,255,0.5); background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.12); }
.vd-ep--missing .vd-ep-index, .vd-ep--missing .vd-ep-title { opacity: 0.7; }
@media (max-width: 820px) {
.vd-bb-content { padding-left: 24px; }
.vd-body { padding: 24px 22px 60px; }
.vd-ep { grid-template-columns: 36px 1fr auto; }
.vd-ep-thumb { display: none; }
}
.video-card--clickable { cursor: pointer; }
/* ── Manage-Workers modal: live status + glow (scoped to #vem-overlay; the
music modal's shared .em-* styles are never touched). ───────────────────── */
#vem-overlay .em-dot--running { animation: vemDotPulse 1.5s ease-in-out infinite; }
@keyframes vemDotPulse {
0%, 100% { box-shadow: 0 0 8px #1db954; }
50% { box-shadow: 0 0 16px 3px #1db954; }
}
/* The selected worker's rail row carries a live accent glow. */
#vem-overlay .em-worker-row.active {
box-shadow: inset 0 0 0 1px rgba(var(--row-accent), 0.45),
0 0 22px rgba(var(--row-accent), 0.20);
}
/* "Now processing" chip pulses in the worker's accent — clear live signal. */
#vem-overlay .em-ph-current {
color: rgb(var(--em-accent-rgb));
text-shadow: 0 0 12px rgba(var(--em-accent-rgb), 0.55);
animation: vemNowPulse 1.8s ease-in-out infinite;
}
@keyframes vemNowPulse { 0%, 100% { opacity: 0.78; } 50% { opacity: 1; } }
/* Active "Process first" / kind selection glow in the worker accent. */
#vem-overlay .em-global-tabs button.active,
#vem-overlay .em-card--current {
box-shadow: 0 0 18px rgba(var(--em-accent-rgb), 0.28);
}
/* ── Cast & crew section (detail page) ───────────────────────────────────── */
.vd-cast-section { margin-top: 46px; }
.vd-section-h { font-size: 22px; font-weight: 800; color: #fff; margin: 0 0 16px; }
.vd-crew { display: flex; flex-wrap: wrap; gap: 8px 24px; margin-bottom: 24px;
color: rgba(255, 255, 255, 0.72); font-size: 14px; }
.vd-crew-job { color: rgba(255, 255, 255, 0.45); font-weight: 600; }
.vd-cast { display: flex; gap: 18px; overflow-x: auto; padding-bottom: 12px; scroll-snap-type: x proximity; }
.vd-cast::-webkit-scrollbar { height: 8px; }
.vd-cast::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 4px; }
.vd-cast-card { flex: 0 0 116px; width: 116px; scroll-snap-align: start; text-align: center; }
.vd-cast-photo {
width: 116px; height: 116px; border-radius: 50%; object-fit: cover; display: block; margin: 0 auto 10px;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45); border: 2px solid rgba(255, 255, 255, 0.08);
transition: transform 0.25s ease, border-color 0.25s ease;
}
.vd-cast-photo--ph {
display: flex; align-items: center; justify-content: center; font-size: 40px; font-weight: 800;
color: rgba(255, 255, 255, 0.55);
background: linear-gradient(135deg, rgba(var(--vd-accent-rgb), 0.32), rgba(var(--vd-accent-rgb), 0.1));
}
.vd-cast-card:hover .vd-cast-photo { transform: translateY(-3px); border-color: rgba(var(--vd-accent-rgb), 0.6); }
.vd-cast-name { display: block; font-size: 13.5px; font-weight: 700; color: #fff; line-height: 1.3;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vd-cast-char { display: block; font-size: 12px; color: rgba(255, 255, 255, 0.55); line-height: 1.3;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* ── Movie detail: details strip ─────────────────────────────────────────── */
.vd-details { margin-bottom: 8px; }
.vd-detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px 28px; max-width: 760px; }
.vd-detail-row { display: flex; flex-direction: column; gap: 3px; }
.vd-detail-k { font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px; color: rgba(255, 255, 255, 0.45); }
.vd-detail-v { font-size: 14.5px; font-weight: 600; color: #fff; }
/* ── Clearlogo title (replaces the text title when available) ─────────────── */
.vd-logo {
display: block; max-width: min(440px, 60%); max-height: 150px; width: auto; height: auto;
margin: 0 0 16px; object-fit: contain; object-position: left bottom;
filter: drop-shadow(0 4px 24px rgba(0, 0, 0, 0.7));
animation: vdRise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
/* Keep the title for screen readers, but hide it visually when the logo shows. */
.vd-title--logo {
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* ── Detail extras: trailer button, providers, More Like This, trailer modal ── */
.vd-trailer-btn {
display: inline-flex; align-items: center; gap: 8px; padding: 7px 18px; border-radius: 8px;
font-size: 12.5px; font-weight: 800; letter-spacing: 0.02em; cursor: pointer;
color: #fff; background: rgb(var(--vd-accent-rgb)); border: 1px solid transparent;
box-shadow: 0 6px 18px rgba(var(--vd-accent-rgb), 0.4); transition: all 0.2s ease;
}
.vd-trailer-btn:hover { transform: translateY(-1px); filter: brightness(1.08);
box-shadow: 0 8px 22px rgba(var(--vd-accent-rgb), 0.55); }
.vd-trailer-ic { font-size: 12px; }
.vd-providers-section, .vd-similar-section, .vd-collection-section { margin-top: 40px; }
.vd-sim-year { display: block; font-size: 11px; color: rgba(255, 255, 255, 0.45); margin-top: 2px; }
.vd-providers { display: flex; flex-wrap: wrap; gap: 14px; }
.vd-prov { display: flex; flex-direction: column; align-items: center; gap: 7px; width: 78px; text-align: center; }
.vd-prov img, .vd-prov-ph {
width: 56px; height: 56px; border-radius: 14px; object-fit: cover;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4); border: 1px solid rgba(255, 255, 255, 0.1);
}
.vd-prov-ph { display: flex; align-items: center; justify-content: center; font-size: 24px; font-weight: 800;
color: #fff; background: linear-gradient(135deg, rgba(var(--vd-accent-rgb), 0.4), rgba(var(--vd-accent-rgb), 0.1)); }
.vd-prov-name { font-size: 11.5px; color: rgba(255, 255, 255, 0.7); line-height: 1.25;
overflow: hidden; text-overflow: ellipsis; }
/* Clickable provider / server tiles (anchors). */
a.vd-prov { text-decoration: none; color: inherit; cursor: pointer; transition: transform 0.2s ease; }
a.vd-prov:hover { transform: translateY(-4px); }
a.vd-prov:hover .vd-prov-name { color: #fff; }
a.vd-prov:hover img, a.vd-prov:hover .vd-prov-ph { border-color: rgba(var(--vd-accent-rgb), 0.6); }
/* "Play on your server" tile — leads the row, glows green like the owned ribbon. */
.vd-prov--server .vd-prov-play {
background: linear-gradient(135deg, #22c55e, #15803d); color: #fff; font-size: 22px;
box-shadow: 0 6px 18px rgba(34, 197, 94, 0.45); border-color: rgba(255, 255, 255, 0.2);
}
/* The actual Plex/Jellyfin logo on a dark tile with a green "you own it" glow. */
.vd-prov--server .vd-prov-server-logo {
background: rgba(10, 12, 16, 0.9); padding: 11px;
box-shadow: 0 6px 18px rgba(34, 197, 94, 0.42); border-color: rgba(34, 197, 94, 0.55);
}
.vd-prov-server-logo img {
width: 100%; height: 100%; object-fit: contain;
border: 0; border-radius: 0; box-shadow: none;
}
.vd-prov--server .vd-prov-name { color: #6ee7a0; font-weight: 700; }
/* streaming providers are informational badges (no per-provider link exists) */
.vd-prov--badge { cursor: default; }
/* the single real "where to watch" link (JustWatch/TMDB aggregate page) */
.vd-prov--more .vd-prov-more-ic {
display: flex; align-items: center; justify-content: center; font-size: 24px; font-weight: 800;
color: rgb(var(--vd-accent-rgb)); background: rgba(var(--vd-accent-rgb), 0.16);
border-color: rgba(var(--vd-accent-rgb), 0.4);
}
.vd-prov--more .vd-prov-name { color: rgb(var(--vd-accent-rgb)); font-weight: 700; }
.vd-similar { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 12px; scroll-snap-type: x proximity; }
.vd-similar::-webkit-scrollbar { height: 8px; }
.vd-similar::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 4px; }
.vd-sim-card { flex: 0 0 130px; width: 130px; scroll-snap-align: start; text-decoration: none; color: inherit;
transition: transform 0.25s ease; }
.vd-sim-card:hover { transform: translateY(-4px); }
.vd-sim-poster { width: 130px; aspect-ratio: 2/3; border-radius: 10px; object-fit: cover; display: block; margin-bottom: 8px;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45); border: 1px solid rgba(255, 255, 255, 0.08); }
.vd-sim-poster--ph { display: flex; align-items: center; justify-content: center; font-size: 34px;
background: linear-gradient(135deg, rgba(var(--vd-accent-rgb), 0.28), rgba(0, 0, 0, 0.5)); }
.vd-sim-title { display: block; font-size: 12.5px; font-weight: 600; color: rgba(255, 255, 255, 0.85); line-height: 1.3;
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.vd-trailer-overlay {
position: fixed; inset: 0; z-index: 9000; display: none; align-items: center; justify-content: center;
background: rgba(0, 0, 0, 0.85); backdrop-filter: blur(6px);
}
.vd-trailer-overlay--open { display: flex; animation: vdFade 0.2s ease both; }
@keyframes vdFade { from { opacity: 0; } to { opacity: 1; } }
.vd-trailer-box { position: relative; width: min(1100px, 92vw); aspect-ratio: 16/9;
border-radius: 12px; overflow: hidden; box-shadow: 0 24px 80px rgba(0, 0, 0, 0.7); }
.vd-trailer-box iframe { width: 100%; height: 100%; border: 0; display: block; }
.vd-trailer-close {
position: absolute; top: -44px; right: 0; width: 36px; height: 36px; border-radius: 50%;
background: rgba(255, 255, 255, 0.12); border: 1px solid rgba(255, 255, 255, 0.2); color: #fff;
font-size: 22px; line-height: 1; cursor: pointer; transition: background 0.2s ease;
}
.vd-trailer-close:hover { background: rgba(255, 255, 255, 0.25); }
/* ── Rating badges (IMDb / Rotten Tomatoes / Metacritic, via OMDb) ────────── */
.vd-ratings { display: flex; flex-wrap: wrap; gap: 10px; margin: -4px 0 16px; }
.vd-rt {
display: inline-flex; align-items: center; gap: 7px; padding: 5px 12px; border-radius: 8px;
font-size: 14px; font-weight: 800; color: #fff; background: rgba(0, 0, 0, 0.4);
border: 1px solid rgba(255, 255, 255, 0.12); backdrop-filter: blur(6px);
}
.vd-rt-tag { font-size: 11px; font-weight: 900; padding: 1px 5px; border-radius: 4px; letter-spacing: 0.02em; }
.vd-rt-ic { font-size: 15px; line-height: 1; }
.vd-rt--imdb .vd-rt-tag { background: #f5c518; color: #000; }
.vd-rt--rt { }
.vd-rt--mc .vd-rt-tag { background: #fff; color: #000; }
.vd-rt--mc-good .vd-rt-tag { background: #6c3; color: #000; }
.vd-rt--mc-mid .vd-rt-tag { background: #fc3; color: #000; }
.vd-rt--mc-bad .vd-rt-tag { background: #f00; color: #fff; }
/* ── OMDb worker uses a ★ glyph (no clean brand logo) ─────────────────────── */
.video-enrich-glyph {
position: relative; z-index: 1; font-size: 22px; line-height: 1;
color: rgb(var(--ve-accent, 245, 197, 24));
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.4)); transition: transform 0.3s ease;
}
.video-enrich-button:hover .video-enrich-glyph { transform: scale(1.1); }
#vem-overlay .vem-glyph { font-size: 20px; line-height: 1; }
/* ══════════════════════════════════════════════════════════════════════════
In-app SEARCH + PERSON pages — cinematic, Netflix-grade (isolated, video).
Shares the detail page's language: --vd-accent-rgb glow, full-bleed feel,
poster cards with hover lift + gradient overlay, rise/fade entrances.
════════════════════════════════════════════════════════════════════════ */
/* ── shared poster/portrait card (search results + filmography) ───────────── */
.vsr-grid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
gap: 22px 20px;
}
.vsr-card {
position: relative; display: flex; flex-direction: column; text-decoration: none;
color: inherit; cursor: pointer; border-radius: 14px;
animation: vsr-pop 0.45s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
@keyframes vsr-pop { from { opacity: 0; transform: translateY(14px) scale(0.97); } to { opacity: 1; transform: none; } }
.vsr-poster {
position: relative; aspect-ratio: 2 / 3; border-radius: 14px; overflow: hidden;
background: linear-gradient(145deg, rgba(var(--vd-accent-rgb), 0.22), rgba(8, 8, 12, 0.9));
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
border: 1px solid rgba(255, 255, 255, 0.06);
transition: transform 0.32s cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 0.32s ease, border-color 0.32s ease;
}
.vsr-poster img { width: 100%; height: 100%; object-fit: cover; display: block;
transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1); }
.vsr-poster .library-artist-image-fallback,
.vsr-poster-ph {
width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
font-size: 46px; color: rgba(255, 255, 255, 0.4);
}
.vsr-card:hover .vsr-poster {
transform: translateY(-8px);
border-color: rgba(var(--vd-accent-rgb), 0.55);
box-shadow: 0 20px 46px rgba(0, 0, 0, 0.6), 0 0 30px rgba(var(--vd-accent-rgb), 0.32);
}
.vsr-card:hover .vsr-poster img { transform: scale(1.08); }
/* gradient + hover affordance */
.vsr-poster::after {
content: ''; position: absolute; inset: 0; pointer-events: none; opacity: 0;
background: linear-gradient(0deg, rgba(0, 0, 0, 0.55) 0%, transparent 45%);
transition: opacity 0.3s ease;
}
.vsr-card:hover .vsr-poster::after { opacity: 1; }
/* hover affordance = "view details" (an info badge), NOT a play button */
.vsr-peek {
position: absolute; left: 50%; top: 50%; z-index: 3;
width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
background: rgba(var(--vd-accent-rgb), 0.92); color: #fff;
font-family: Georgia, 'Times New Roman', serif; font-style: italic; font-weight: 700; font-size: 22px;
transform: translate(-50%, -50%) scale(0.5); opacity: 0;
box-shadow: 0 6px 20px rgba(var(--vd-accent-rgb), 0.5);
transition: transform 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.4), opacity 0.25s ease;
}
.vsr-card:hover .vsr-peek { transform: translate(-50%, -50%) scale(1); opacity: 1; }
/* ribbon + rating chips */
.vsr-ribbon {
position: absolute; top: 10px; left: 10px; z-index: 2;
font-size: 10px; font-weight: 800; letter-spacing: 0.5px; text-transform: uppercase;
padding: 4px 9px; border-radius: 7px; color: #fff;
backdrop-filter: blur(8px); box-shadow: 0 3px 12px rgba(0, 0, 0, 0.5);
}
.vsr-ribbon--owned { background: rgba(34, 197, 94, 0.95); }
.vsr-ribbon--preview { background: rgba(255, 255, 255, 0.16); border: 1px solid rgba(255, 255, 255, 0.28); }
.vsr-rating {
position: absolute; top: 10px; right: 10px; z-index: 2;
display: inline-flex; align-items: center; gap: 3px;
font-size: 11.5px; font-weight: 800; color: #fde68a;
padding: 3px 8px; border-radius: 7px; background: rgba(0, 0, 0, 0.62); backdrop-filter: blur(6px);
}
.vsr-info { padding: 11px 4px 0; min-width: 0; }
.vsr-info--center { text-align: center; }
.vsr-name {
display: block; font-size: 14px; font-weight: 700; color: #fff; line-height: 1.3;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
transition: color 0.2s ease;
}
.vsr-card:hover .vsr-name { color: rgb(var(--vd-accent-rgb)); }
.vsr-sub { display: block; font-size: 12px; color: rgba(255, 255, 255, 0.5); margin-top: 3px;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* people = circular portrait card */
.vsr-card--person .vsr-poster {
aspect-ratio: 1 / 1; border-radius: 50%;
background: linear-gradient(145deg, rgba(var(--vd-accent-rgb), 0.3), rgba(8, 8, 12, 0.9));
}
.vsr-card--person:hover .vsr-poster { border-radius: 50%; }
.vsr-card--person .vsr-poster::after { border-radius: 50%; }
/* ── SEARCH page ──────────────────────────────────────────────────────────── */
.vsr-page { --vd-accent-rgb: var(--accent-rgb, 88, 101, 242); position: relative; margin: -40px -40px 0; }
.vsr-hero {
position: relative; overflow: hidden;
padding: 48px 56px 30px; text-align: center;
}
.vsr-hero-glow {
position: absolute; inset: -40% 0 auto 0; height: 360px; z-index: 0; pointer-events: none;
background: radial-gradient(60% 100% at 50% 0%, rgba(var(--vd-accent-rgb), 0.28), transparent 70%);
animation: vsr-glow 7s ease-in-out infinite alternate;
}
@keyframes vsr-glow { from { opacity: 0.65; } to { opacity: 1; } }
.vsr-hero-title {
position: relative; z-index: 1; margin: 0 0 8px;
font-size: clamp(2em, 4vw, 3em); font-weight: 900; letter-spacing: -0.02em; color: #fff;
text-shadow: 0 4px 30px rgba(0, 0, 0, 0.6);
}
.vsr-hero-sub { position: relative; z-index: 1; margin: 0 0 26px; font-size: 14.5px; color: rgba(255, 255, 255, 0.6); }
.vsr-searchbar {
position: relative; z-index: 1; display: flex; align-items: center; gap: 12px;
max-width: 660px; margin: 0 auto; padding: 0 20px; height: 58px;
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 16px; backdrop-filter: blur(14px);
box-shadow: 0 10px 34px rgba(0, 0, 0, 0.4); transition: border-color 0.25s ease, box-shadow 0.25s ease;
}
.vsr-searchbar:focus-within {
border-color: rgba(var(--vd-accent-rgb), 0.65);
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5), 0 0 0 4px rgba(var(--vd-accent-rgb), 0.18);
}
.vsr-search-ic { font-size: 19px; opacity: 0.7; }
.vsr-input {
flex: 1; min-width: 0; height: 100%; border: 0; background: transparent; outline: none;
color: #fff; font-size: 17px; font-weight: 500;
}
.vsr-input::placeholder { color: rgba(255, 255, 255, 0.4); }
.vsr-body { padding: 6px 56px 70px; }
.vsr-results { display: flex; flex-direction: column; gap: 40px; }
.vsr-group { animation: vsr-fade 0.4s ease both; }
@keyframes vsr-fade { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.vsr-group-title {
display: flex; align-items: center; gap: 11px; margin: 0 0 18px;
font-size: 20px; font-weight: 800; color: #fff; letter-spacing: -0.01em;
}
.vsr-group-ic { font-size: 19px; }
.vsr-group-count {
font-size: 12px; font-weight: 700; color: rgba(255, 255, 255, 0.6);
background: rgba(var(--vd-accent-rgb), 0.18); border: 1px solid rgba(var(--vd-accent-rgb), 0.3);
border-radius: 999px; padding: 2px 10px;
}
.vsr-state { padding: 70px 20px; text-align: center; }
.vsr-state-ic {
font-size: 56px; margin-bottom: 16px; display: inline-block;
filter: drop-shadow(0 6px 18px rgba(var(--vd-accent-rgb), 0.4));
animation: vsr-float 4s ease-in-out infinite;
}
@keyframes vsr-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
.vsr-state-title { font-size: 21px; font-weight: 800; color: #fff; margin-bottom: 8px; }
.vsr-state-sub { font-size: 14px; color: rgba(255, 255, 255, 0.55); max-width: 460px; margin: 0 auto; line-height: 1.6; }
.vsr-loading { padding: 60px 0; text-align: center; color: rgba(255, 255, 255, 0.6); }
/* ══════════════════════════════════════════════════════════════════════════
PERSON page — cinematic bio + filmography
════════════════════════════════════════════════════════════════════════ */
.vp-page {
--vd-accent-rgb: var(--accent-rgb, 88, 101, 242);
position: relative; margin: -40px -40px -90px; min-height: 80vh;
}
/* Cinematic hero: a blurred-portrait wash + an accent colour mesh, capped by a
vignette and a fade into the page. Layers are static (painted once) so the
hero stays cheap. */
.vp-ambient {
position: absolute; inset: 0 0 auto 0; height: 560px; z-index: 0; overflow: hidden;
-webkit-mask-image: linear-gradient(180deg, #000 62%, transparent);
mask-image: linear-gradient(180deg, #000 62%, transparent);
}
.vp-ambient::before {
content: ''; position: absolute; inset: -80px; background-size: cover; background-position: center 18%;
background-image: var(--vp-bg, none); filter: blur(54px) saturate(1.35); transform: scale(1.2);
opacity: 0.5;
}
.vp-ambient::after {
content: ''; position: absolute; inset: 0;
background:
radial-gradient(80% 90% at 16% -10%, rgba(var(--vd-accent-rgb), 0.42), transparent 60%),
radial-gradient(70% 80% at 100% 0%, rgba(var(--vd-accent-rgb), 0.2), transparent 65%),
radial-gradient(120% 80% at 50% 120%, rgba(0, 0, 0, 0.5), transparent 60%),
linear-gradient(180deg, rgba(11,11,15,0.25) 0%, rgba(11,11,15,0.62) 58%, var(--bg-primary, #0b0b0f) 100%);
}
.vp-page[data-has-bg="0"] .vp-ambient::before {
background-image: radial-gradient(80% 120% at 30% 0%, rgba(var(--vd-accent-rgb), 0.55), transparent 70%);
filter: none; opacity: 0.8;
}
.vp-page .vd-back { z-index: 6; }
.vp-hero {
position: relative; z-index: 2; display: flex; gap: 40px; align-items: flex-end;
padding: 150px 56px 34px; animation: vdRise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
@keyframes vdRise { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }
/* Portrait: a frame with a slowly-rotating accent gradient ring (GPU transform —
cheap) + a gentle float. */
.vp-photo-wrap {
position: relative; flex: 0 0 auto; width: 200px; height: 200px;
animation: vp-float 7s ease-in-out infinite;
}
@keyframes vp-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
.vp-photo-ring {
position: absolute; inset: -7px; border-radius: 50%; z-index: 0;
background: conic-gradient(from 0deg,
rgba(var(--vd-accent-rgb), 0.95), rgba(var(--vd-accent-rgb), 0.04) 38%,
rgba(var(--vd-accent-rgb), 0.55) 72%, rgba(var(--vd-accent-rgb), 0.95));
-webkit-mask: radial-gradient(closest-side, transparent calc(100% - 9px), #000 calc(100% - 8px));
mask: radial-gradient(closest-side, transparent calc(100% - 9px), #000 calc(100% - 8px));
animation: vp-spin 18s linear infinite; will-change: transform; opacity: 0.9;
}
@keyframes vp-spin { to { transform: rotate(360deg); } }
.vp-photo-frame {
position: absolute; inset: 0; border-radius: 50%; overflow: hidden; z-index: 1;
background: linear-gradient(145deg, rgba(var(--vd-accent-rgb), 0.42), rgba(8, 8, 12, 0.92));
display: flex; align-items: center; justify-content: center;
box-shadow: 0 22px 56px rgba(0, 0, 0, 0.62), 0 0 60px rgba(var(--vd-accent-rgb), 0.32),
inset 0 0 0 2px rgba(255, 255, 255, 0.07);
}
.vp-photo { width: 100%; height: 100%; object-fit: cover; }
.vp-photo-ph { font-size: 80px; opacity: 0.55; }
.vp-hero-info { flex: 1; min-width: 0; padding-bottom: 10px; }
.vp-role {
display: inline-block; margin-bottom: 12px; font-size: 12px; font-weight: 800;
letter-spacing: 1.4px; text-transform: uppercase; color: rgb(var(--vd-accent-rgb));
padding: 5px 13px; border-radius: 999px;
background: rgba(var(--vd-accent-rgb), 0.14); border: 1px solid rgba(var(--vd-accent-rgb), 0.34);
text-shadow: 0 0 18px rgba(var(--vd-accent-rgb), 0.5);
}
.vp-name {
margin: 0 0 14px; font-size: clamp(2.4em, 5vw, 3.8em); font-weight: 900;
line-height: 0.98; letter-spacing: -0.025em;
background: linear-gradient(180deg, #fff 55%, rgba(255, 255, 255, 0.72));
-webkit-background-clip: text; background-clip: text; color: transparent;
filter: drop-shadow(0 6px 30px rgba(0, 0, 0, 0.6));
}
.vp-meta { display: flex; flex-wrap: wrap; gap: 9px; }
.vp-meta span {
font-size: 12.5px; font-weight: 600; color: rgba(255, 255, 255, 0.82);
padding: 5px 12px; border-radius: 999px;
background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.14); backdrop-filter: blur(6px);
}
@media (prefers-reduced-motion: reduce) {
.vp-photo-wrap { animation: none; }
.vp-photo-ring { animation: none; }
}
.vp-body { position: relative; z-index: 2; padding: 16px 56px 60px; }
.vp-bio {
font-size: 15px; line-height: 1.7; color: rgba(255, 255, 255, 0.8);
max-width: 920px; margin: 0 0 6px; white-space: pre-line;
display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden;
}
.vp-bio.vp-bio--open { -webkit-line-clamp: 99; }
.vp-bio-more {
background: none; border: 0; color: rgb(var(--vd-accent-rgb)); font-weight: 700; font-size: 13.5px;
cursor: pointer; padding: 4px 0; margin: 0 0 30px; display: inline-block;
}
.vp-bio-more[hidden] { display: none; }
/* Known For — a horizontal hero rail of the person's best-known titles */
.vp-known-section { position: relative; z-index: 2; margin-bottom: 38px; }
.vp-known-title { margin: 0 0 16px; }
.vp-known-rail {
display: flex; gap: 18px; overflow-x: auto; padding: 4px 2px 14px; scroll-snap-type: x proximity;
}
.vp-known-rail::-webkit-scrollbar { height: 8px; }
.vp-known-rail::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 4px; }
.vp-known-rail .vsr-card { flex: 0 0 152px; width: 152px; scroll-snap-align: start; }
/* Long filmography grids can be hundreds of cards — let the browser skip
rendering the off-screen ones (cheap scrolling) and don't replay the entrance
animation as cards recycle in and out of view. */
.vp-credits-section .vsr-grid > .vsr-card {
content-visibility: auto;
contain-intrinsic-size: auto 300px;
animation: none;
}
.vp-credits-section { position: relative; z-index: 2; }
.vp-credits-head {
display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 14px; margin-bottom: 16px;
}
.vp-credits-title { font-size: 22px; font-weight: 800; color: #fff; margin: 0; }
.vp-credit-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin-bottom: 20px; }
.vp-credit-tabs { display: flex; gap: 8px; }
/* The ownership group sits after a faint divider so it reads as a second axis. */
.vp-own-tabs { position: relative; padding-left: 14px; }
.vp-own-tabs::before {
content: ''; position: absolute; left: 0; top: 14%; height: 72%; width: 1px;
background: rgba(255, 255, 255, 0.16);
}
/* "In Library" filter glows green (matches the owned ribbon) when active. */
.vp-own-tabs [data-vp-own="owned"].vp-tab--active {
background: rgba(34, 197, 94, 0.92); box-shadow: 0 4px 16px rgba(34, 197, 94, 0.4);
}
.vp-credits-empty {
padding: 44px 20px; text-align: center; font-size: 14px; color: rgba(255, 255, 255, 0.55);
}
.vp-dept-tabs [data-vp-dept].vp-tab--active {
background: rgba(var(--vd-accent-rgb, 99, 102, 241), 0.92); border-color: transparent; color: #fff;
}
.vp-dept-tabs:empty { display: none; }
.vp-sort {
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.14);
color: rgba(255, 255, 255, 0.85); border-radius: 9px; padding: 8px 12px; font-size: 13px;
font-weight: 600; cursor: pointer; outline: none;
}
.vp-sort:hover { background: rgba(255, 255, 255, 0.1); }
.vp-sort option { background: #16161c; color: #fff; }
.vp-tab {
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.7); border-radius: 999px; padding: 7px 16px; cursor: pointer;
font-size: 13px; font-weight: 700; display: inline-flex; align-items: center; gap: 7px;
transition: all 0.18s ease;
}
.vp-tab:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.vp-tab--active {
background: rgba(var(--vd-accent-rgb), 0.92); border-color: transparent; color: #fff;
box-shadow: 0 4px 16px rgba(var(--vd-accent-rgb), 0.4);
}
.vp-tab-count { font-size: 11px; opacity: 0.85; }
/* cast card on the detail page becomes a real link → person */
.vd-cast-card--link { cursor: pointer; text-decoration: none; }
.vd-cast-card--link:hover .vd-cast-name { color: rgb(var(--vd-accent-rgb)); }
.vd-status--preview {
color: #fff !important;
background: rgba(255, 255, 255, 0.16); border: 1px solid rgba(255, 255, 255, 0.3);
padding: 2px 10px; border-radius: 999px; font-size: 12px; font-weight: 700;
}
@media (max-width: 720px) {
.vsr-page, .vp-page { margin-left: -20px; margin-right: -20px; }
.vsr-hero { padding: 34px 22px 22px; }
.vsr-body, .vp-body { padding-left: 22px; padding-right: 22px; }
.vp-hero { flex-direction: column; align-items: center; text-align: center; padding: 104px 22px 24px; }
.vp-meta { justify-content: center; }
.vsr-grid { grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: 16px 14px; }
.vp-photo-wrap { width: 150px; height: 150px; }
}
/* ── billboard: Play CTA, crew line, next-episode, season overview ────────── */
/* Matches .vd-trailer-btn exactly (consistent with the other hero buttons) —
just green to read as "owned / play". */
.vd-play-btn {
display: inline-flex; align-items: center; gap: 7px; padding: 7px 18px; border-radius: 8px;
font-size: 12.5px; font-weight: 800; letter-spacing: 0.02em; cursor: pointer; text-decoration: none;
color: #fff; border: 1px solid transparent;
/* deeper green so the light Plex/Jellyfin wordmark reads clearly on it */
background: linear-gradient(135deg, #1fae54, #15803d);
box-shadow: 0 6px 18px rgba(34, 197, 94, 0.4); transition: all 0.2s ease;
}
.vd-play-btn:hover { transform: translateY(-1px); filter: brightness(1.1);
box-shadow: 0 8px 22px rgba(34, 197, 94, 0.55); }
.vd-play-logo { height: 15px; width: auto; position: relative; top: 0.5px; }
.vd-play-ic { font-size: 12px; }
.vd-crew-line { font-size: 14px; color: rgba(255, 255, 255, 0.84); margin: 2px 0 14px;
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6); }
.vd-crew-line-k { color: rgba(255, 255, 255, 0.5); font-weight: 600; margin-right: 4px; }
.vd-next-ep {
display: inline-flex; align-items: center; flex-wrap: wrap; gap: 10px; margin: 2px 0 14px;
font-size: 13.5px; color: rgba(255, 255, 255, 0.9); text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6);
}
.vd-next-ep-badge {
font-size: 11.5px; font-weight: 800; letter-spacing: 0.5px; text-transform: uppercase;
color: rgb(var(--vd-accent-rgb)); padding: 4px 11px; border-radius: 999px;
background: rgba(var(--vd-accent-rgb), 0.16); border: 1px solid rgba(var(--vd-accent-rgb), 0.36);
}
.vd-next-ep-code { font-weight: 800; }
.vd-next-ep-name { color: rgba(255, 255, 255, 0.72); font-style: italic; }
.vd-next-ep-when { color: rgba(255, 255, 255, 0.6); }
.vd-season-overview {
font-size: 14px; line-height: 1.6; color: rgba(255, 255, 255, 0.7);
max-width: 880px; margin: -8px 0 22px;
}
/* ── detail skeleton loader (shimmer billboard while data loads) ──────────── */
.vd-skel {
position: absolute; top: 0; left: 0; right: 0; height: 76vh; min-height: 470px; z-index: 5; overflow: hidden;
background: radial-gradient(120% 90% at 70% 0%, rgba(var(--vd-accent-rgb, 88, 101, 242), 0.18), var(--bg-primary, #0b0b0f) 60%);
}
.vd-skel-content { position: absolute; left: 56px; bottom: 60px; width: min(60%, 600px); }
.skel-shine {
border-radius: 8px;
background: linear-gradient(100deg, rgba(255,255,255,0.05) 30%, rgba(255,255,255,0.14) 50%, rgba(255,255,255,0.05) 70%);
background-size: 200% 100%; animation: vd-skel-shine 1.4s ease-in-out infinite;
}
@keyframes vd-skel-shine { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.vd-skel-logo { height: 54px; width: 320px; max-width: 80%; margin-bottom: 22px; }
.vd-skel-meta { height: 16px; width: 280px; max-width: 70%; margin-bottom: 22px; }
.vd-skel-text { height: 13px; width: 100%; margin-bottom: 10px; }
.vd-skel-text.short { width: 70%; margin-bottom: 26px; }
.vd-skel-btns { display: flex; gap: 12px; }
.vd-skel-btns span { height: 44px; width: 130px; border-radius: 10px; display: block; }
@media (max-width: 720px) {
.vd-skel-content { left: 22px; right: 22px; width: auto; bottom: 60px; }
}
@media (prefers-reduced-motion: reduce) { .skel-shine { animation: none; } }
/* clickable crew / director names → person page */
.vd-person-link { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; transition: color 0.18s ease, border-color 0.18s ease; }
.vd-person-link:hover { color: rgb(var(--vd-accent-rgb)); border-bottom-color: rgba(var(--vd-accent-rgb), 0.5); }
/* "fetching full episode list" banner (shown while the TMDB cascade runs) */
.vd-ep-syncing {
display: flex; align-items: center; gap: 11px; margin: 0 0 18px; padding: 12px 16px;
border-radius: 10px; font-size: 13.5px; color: rgba(255, 255, 255, 0.78);
background: rgba(var(--vd-accent-rgb), 0.1); border: 1px solid rgba(var(--vd-accent-rgb), 0.26);
}
.vd-ep-syncing-spin {
flex: 0 0 auto; width: 16px; height: 16px; border-radius: 50%;
border: 2px solid rgba(var(--vd-accent-rgb), 0.3); border-top-color: rgb(var(--vd-accent-rgb));
animation: vd-ep-spin 0.8s linear infinite;
}
@keyframes vd-ep-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .vd-ep-syncing-spin { animation: none; } }
/* A class with an explicit `display` (e.g. .vd-ep-syncing/.vd-next-ep) otherwise
beats the UA [hidden]{display:none}, so toggling el.hidden wouldn't hide it.
Guarantee hidden always hides on the video detail/search/person pages. */
.vd-page [hidden], .vp-page [hidden], .vsr-page [hidden] { display: none !important; }
/* ══════════════════════════════════════════════════════════════════════════
Detail extras: Details/keywords, Videos, Photos gallery + lightbox, full cast
════════════════════════════════════════════════════════════════════════ */
.vd-section-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 16px; }
.vd-section-head .vd-section-h { margin: 0; }
.vd-viewall {
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.14);
color: rgba(255, 255, 255, 0.8); border-radius: 999px; padding: 6px 14px; font-size: 12.5px;
font-weight: 700; cursor: pointer; transition: all 0.18s ease;
}
.vd-viewall:hover { background: rgba(var(--vd-accent-rgb), 0.2); border-color: rgba(var(--vd-accent-rgb), 0.5); color: #fff; }
.vd-facts-section, .vd-videos-section, .vd-gallery-section { margin-top: 44px; }
.vd-keywords { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.vd-kw {
padding: 5px 12px; border-radius: 999px; font-size: 12px; color: rgba(255, 255, 255, 0.7);
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.12);
}
/* videos rail */
.vd-videos { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 12px; scroll-snap-type: x proximity; }
.vd-videos::-webkit-scrollbar, .vd-gallery::-webkit-scrollbar { height: 8px; }
.vd-videos::-webkit-scrollbar-thumb, .vd-gallery::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 4px; }
.vd-video-card { flex: 0 0 240px; width: 240px; scroll-snap-align: start; background: none; border: 0; padding: 0; cursor: pointer; text-align: left; }
.vd-video-thumb {
position: relative; display: block; aspect-ratio: 16 / 9; border-radius: 10px; overflow: hidden; background: #000;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4); transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.vd-video-thumb img { width: 100%; height: 100%; object-fit: cover; }
.vd-video-play {
position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
font-size: 30px; color: #fff; background: rgba(0, 0, 0, 0.25); text-shadow: 0 2px 12px rgba(0, 0, 0, 0.7);
}
.vd-video-card:hover .vd-video-thumb { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(0, 0, 0, 0.55); }
.vd-video-name { display: block; margin-top: 9px; font-size: 13px; font-weight: 600; color: #fff;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vd-video-type { display: block; font-size: 11.5px; color: rgba(255, 255, 255, 0.5); }
/* photos rail */
.vd-gallery { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 12px; scroll-snap-type: x proximity; }
.vd-shot {
flex: 0 0 280px; width: 280px; aspect-ratio: 16 / 9; scroll-snap-align: start; padding: 0; border: 0; cursor: pointer;
border-radius: 10px; overflow: hidden; background: #000; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.vd-shot img { width: 100%; height: 100%; object-fit: cover; }
.vd-shot:hover { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(0, 0, 0, 0.55); }
/* lightbox + full-cast modal share the accent fallback (they live on <body>) */
.vd-lightbox, .vd-cast-modal { --vd-accent-rgb: var(--accent-rgb, 88, 101, 242); }
.vd-lightbox {
position: fixed; inset: 0; z-index: 1000; display: none; align-items: center; justify-content: center;
background: rgba(0, 0, 0, 0.92); backdrop-filter: blur(6px);
}
.vd-lightbox--open { display: flex; animation: vd-fade 0.2s ease; }
@keyframes vd-fade { from { opacity: 0; } to { opacity: 1; } }
.vd-lb-img { max-width: 92vw; max-height: 88vh; border-radius: 8px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.7); }
.vd-lb-close { position: absolute; top: 20px; right: 24px; width: 42px; height: 42px; border-radius: 50%; border: 0; cursor: pointer;
background: rgba(255, 255, 255, 0.12); color: #fff; font-size: 24px; }
.vd-lb-close:hover { background: rgba(255, 255, 255, 0.22); }
.vd-lb-nav { position: absolute; top: 50%; transform: translateY(-50%); width: 52px; height: 52px; border-radius: 50%; border: 0; cursor: pointer;
background: rgba(255, 255, 255, 0.1); color: #fff; font-size: 30px; line-height: 1; }
.vd-lb-nav:hover { background: rgba(255, 255, 255, 0.22); }
.vd-lb-prev { left: 24px; }
.vd-lb-next { right: 24px; }
.vd-lb-count { position: absolute; bottom: 22px; left: 50%; transform: translateX(-50%); font-size: 13px; color: rgba(255, 255, 255, 0.7); }
.vd-cast-modal {
position: fixed; inset: 0; z-index: 1000; display: none; align-items: center; justify-content: center;
background: rgba(0, 0, 0, 0.75); backdrop-filter: blur(6px); padding: 30px;
}
.vd-cast-modal--open { display: flex; animation: vd-fade 0.2s ease; }
.vd-cm-box {
background: #16161c; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px;
width: min(960px, 96vw); max-height: 86vh; overflow: hidden; display: flex; flex-direction: column;
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
}
.vd-cm-head { display: flex; align-items: center; justify-content: space-between; padding: 18px 22px; border-bottom: 1px solid rgba(255, 255, 255, 0.08); }
.vd-cm-head h3 { margin: 0; font-size: 18px; font-weight: 800; color: #fff; }
.vd-cm-close { width: 36px; height: 36px; border-radius: 50%; border: 0; cursor: pointer; background: rgba(255, 255, 255, 0.08); color: #fff; font-size: 22px; }
.vd-cm-close:hover { background: rgba(255, 255, 255, 0.18); }
.vd-cm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 18px; padding: 22px; overflow-y: auto; }
.vd-cm-card { text-decoration: none; text-align: center; color: inherit; cursor: pointer; }
.vd-cm-photo {
width: 84px; height: 84px; border-radius: 50%; object-fit: cover; display: block; margin: 0 auto 9px;
border: 2px solid rgba(255, 255, 255, 0.08); transition: transform 0.2s ease, border-color 0.2s ease;
}
.vd-cm-photo--ph { display: flex; align-items: center; justify-content: center; font-size: 30px; font-weight: 800;
color: rgba(255, 255, 255, 0.5); background: linear-gradient(135deg, rgba(var(--vd-accent-rgb), 0.32), rgba(var(--vd-accent-rgb), 0.1)); }
.vd-cm-card:hover .vd-cm-photo { transform: translateY(-3px); border-color: rgba(var(--vd-accent-rgb), 0.6); }
.vd-cm-name { display: block; font-size: 13px; font-weight: 700; color: #fff; line-height: 1.3; }
.vd-cm-char { display: block; font-size: 12px; color: rgba(255, 255, 255, 0.55); line-height: 1.3; }
.vd-cm-eps { display: block; font-size: 11px; color: rgb(var(--vd-accent-rgb)); margin-top: 2px; font-weight: 600; }
/* ── person: photos rail + also-known-as ─────────────────────────────────── */
.vp-aka { font-size: 13.5px; color: rgba(255, 255, 255, 0.6); margin: 0 0 18px; font-style: italic; }
.vp-photos-section { position: relative; z-index: 2; margin-bottom: 38px; }
.vp-photos { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 12px; scroll-snap-type: x proximity; }
.vp-photos::-webkit-scrollbar { height: 8px; }
.vp-photos::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); border-radius: 4px; }
.vp-photo-thumb {
flex: 0 0 120px; width: 120px; aspect-ratio: 2 / 3; scroll-snap-align: start; padding: 0; border: 0; cursor: pointer;
border-radius: 10px; overflow: hidden; background: #000; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.vp-photo-thumb img { width: 100%; height: 100%; object-fit: cover; }
.vp-photo-thumb:hover { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(0, 0, 0, 0.55); }
/* ── featured review ─────────────────────────────────────────────────────── */
.vd-review-section { margin-top: 44px; }
.vd-review {
max-width: 880px; padding: 20px 22px; border-radius: 14px;
background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.08);
}
.vd-review-head { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.vd-review-author { font-size: 15px; font-weight: 800; color: #fff; }
.vd-review-rating { font-size: 13px; font-weight: 800; color: #fbbf24; }
.vd-review-date { font-size: 12.5px; color: rgba(255, 255, 255, 0.45); }
.vd-review-body {
margin: 0; font-size: 14.5px; line-height: 1.7; color: rgba(255, 255, 255, 0.8); white-space: pre-line;
display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
}
.vd-review-body--open { -webkit-line-clamp: 999; }
.vd-review-more {
background: none; border: 0; color: rgb(var(--vd-accent-rgb)); font-weight: 700; font-size: 13.5px;
cursor: pointer; padding: 8px 0 0;
}
/* ── billboard autoplay trailer ──────────────────────────────────────────── */
.vd-bb-trailer { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: #000; opacity: 0; }
.vd-bb-trailer iframe {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
width: 100vw; height: 56.25vw; min-height: 100%; min-width: 177.78vh; border: 0; pointer-events: none;
}
/* Reveal — only once the trailer is actually PLAYING (gated in video-detail.js).
The trailer wipes in left→right behind a soft feathered edge while it
crossfades, so the backdrop appears to roll away from the left AND fade —
"both a rollover and a fade." @property animates the mask gradient smoothly;
browsers without it still get the opacity crossfade. */
@property --vd-wipe { syntax: '<percentage>'; inherits: false; initial-value: 0%; }
.vd-billboard--trailer .vd-bb-trailer {
-webkit-mask-image: linear-gradient(100deg, #000 var(--vd-wipe), transparent calc(var(--vd-wipe) + 16%));
mask-image: linear-gradient(100deg, #000 var(--vd-wipe), transparent calc(var(--vd-wipe) + 16%));
animation: vdTrailerWipeIn 1.15s cubic-bezier(0.62, 0.04, 0.18, 1) forwards;
}
@keyframes vdTrailerWipeIn { from { --vd-wipe: -16%; opacity: 0; } to { --vd-wipe: 116%; opacity: 1; } }
.vd-billboard--trailer .vd-bb-bg { animation: vdBgFadeOut 1.15s ease forwards; }
@keyframes vdBgFadeOut { from { opacity: 1; } to { opacity: 0; } }
/* Restore — when the trailer ends, fade the original backdrop back in and the
trailer out, then it's torn down. */
.vd-billboard--restoring .vd-bb-bg { animation: vdBgFadeIn 0.9s ease forwards; }
@keyframes vdBgFadeIn { from { opacity: 0; } to { opacity: 1; } }
.vd-billboard--restoring .vd-bb-trailer { animation: vdTrailerFadeOut 0.7s ease forwards; }
@keyframes vdTrailerFadeOut { from { opacity: 1; } to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
.vd-billboard--trailer .vd-bb-trailer { -webkit-mask-image: none; mask-image: none; animation: vd-fade 0.4s ease forwards; }
.vd-billboard--trailer .vd-bb-bg { animation: vdBgFadeOut 0.4s ease forwards; }
}
.vd-bb-tctrls { position: absolute; bottom: 20px; right: 24px; z-index: 4; display: flex; gap: 8px; }
.vd-bb-tbtn {
width: 38px; height: 38px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.25); cursor: pointer;
background: rgba(0, 0, 0, 0.5); color: #fff; font-size: 15px; backdrop-filter: blur(8px); transition: all 0.2s ease;
}
.vd-bb-tbtn:hover { background: rgba(0, 0, 0, 0.78); transform: translateY(-1px); }
/* settings: detail-pages preference toggle */
.vid-pref-row { display: flex; align-items: center; gap: 10px; cursor: pointer; font-size: 14px; color: var(--text-primary, #fff); }
.vid-pref-row input { width: 16px; height: 16px; cursor: pointer; accent-color: #38bdf8; }
/* ── owned media: multiple versions/editions ─────────────────────────────── */
.vd-versions { margin-top: 18px; }
.vd-versions-h { font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px; color: rgba(255, 255, 255, 0.45); margin-bottom: 8px; }
.vd-version {
display: inline-block; margin: 0 8px 8px 0; padding: 7px 13px; border-radius: 8px;
font-size: 13px; font-weight: 600; color: rgba(255, 255, 255, 0.85);
background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1);
}
/* ── episode expand (guest stars + bigger still) ─────────────────────────── */
.vd-ep-extra {
display: flex; gap: 22px; padding: 6px 14px 24px 82px;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
animation: vsr-fade 0.3s ease;
}
.vd-ep-extra-still { width: 240px; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 10px; flex: 0 0 auto;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4); }
.vd-ep-extra-body { flex: 1; min-width: 0; }
.vd-ep-extra-ov { margin: 0 0 16px; font-size: 14px; line-height: 1.6; color: rgba(255, 255, 255, 0.8); }
.vd-ep-extra-empty { color: rgba(255, 255, 255, 0.45); font-size: 13.5px; padding: 4px 0; }
.vd-ep-extra-gh { font-size: 11px; text-transform: uppercase; letter-spacing: 0.6px; color: rgba(255, 255, 255, 0.45); margin-bottom: 12px; }
.vd-ep-guests { display: flex; flex-wrap: wrap; gap: 16px; }
.vd-guest { width: 92px; text-align: center; text-decoration: none; color: inherit; }
a.vd-guest { cursor: pointer; transition: transform 0.18s ease; }
a.vd-guest:hover { transform: translateY(-3px); }
a.vd-guest:hover .vd-guest-name { color: rgb(var(--vd-accent-rgb)); }
.vd-guest-photo {
width: 64px; height: 64px; border-radius: 50%; object-fit: cover; display: block; margin: 0 auto 7px;
border: 2px solid rgba(255, 255, 255, 0.08);
}
.vd-guest-photo--ph { display: flex; align-items: center; justify-content: center; font-size: 24px; font-weight: 800;
color: rgba(255, 255, 255, 0.5); background: linear-gradient(135deg, rgba(var(--vd-accent-rgb), 0.3), rgba(var(--vd-accent-rgb), 0.08)); }
.vd-guest-name { display: block; font-size: 12px; font-weight: 700; color: #fff; line-height: 1.25; }
.vd-guest-char { display: block; font-size: 11px; color: rgba(255, 255, 255, 0.5); line-height: 1.25; }
@media (max-width: 720px) {
.vd-ep-extra { flex-direction: column; padding-left: 14px; }
.vd-ep-extra-still { width: 100%; }
}
.vid-pref-row--select { justify-content: space-between; cursor: default; }
.vid-pref-row--select select {
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.14);
color: var(--text-primary, #fff); border-radius: 8px; padding: 7px 10px; font-size: 13px; cursor: pointer;
}
.vid-pref-row--select select option { background: #16161c; color: #fff; }
/* Server Connection mirrors the music server picker (.server-toggle-container /
.server-config-container) — no video-specific styling needed beyond those
shared classes. */
/* library: no-server gate banner */
.video-noserver {
margin: 0 0 18px; padding: 16px 18px; border-radius: 12px; font-size: 14px; line-height: 1.6;
color: rgba(255, 255, 255, 0.85);
background: rgba(245, 158, 11, 0.1); border: 1px solid rgba(245, 158, 11, 0.32);
}
.video-noserver.hidden { display: none; }
/* Navidrome + SoulSync Standalone are music-only — don't offer them as server
options on the VIDEO side (scoped to body[data-side="video"], so the music side
is untouched). The "Video Source" panel governs which video server is used. */
body[data-side="video"] #navidrome-toggle,
body[data-side="video"] #soulsync-toggle { display: none; }
/* ── Calendar — the Week Grid (every episode, air times, breathing cells) ──── */
.vcal-page { --vcal-accent: var(--accent-rgb, 88, 101, 242); color: var(--text-primary, #fff); padding: 0 0 70px; }
.vcal-head { position: relative; padding: 30px 40px 18px; overflow: hidden; }
.vcal-head-glow {
position: absolute; top: -190px; left: 50%; transform: translateX(-50%);
width: 860px; height: 390px; pointer-events: none; z-index: 0;
background: radial-gradient(56% 70% at 50% 0%, rgba(var(--vcal-accent), 0.26), transparent 70%); filter: blur(10px);
}
.vcal-title { position: relative; z-index: 1; font-size: 36px; font-weight: 800; letter-spacing: -0.025em; margin: 0; }
.vcal-sub { position: relative; z-index: 1; margin: 7px 0 0; color: rgba(255, 255, 255, 0.55); font-size: 14px; font-weight: 600; }
.vcal-body { padding: 4px 40px 0; }
.vcal-loading { padding: 90px 0; text-align: center; }
.vcal-grid { border-radius: 20px; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.07);
background: linear-gradient(180deg, #0d0d12, #0a0a0e); box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45); }
.vcal-grid.hidden { display: none; }
/* EPG guide — a frozen time-rail (rows = time-of-day) × 7 day columns with a
frozen header row, so the whole week reads on ONE shared time axis. */
.vcal-cols { display: grid; grid-template-columns: 84px repeat(7, minmax(150px, 1fr)); align-items: stretch; }
/* sticky top-left corner */
.vcal-guide-corner { position: sticky; top: 0; left: 0; z-index: 6;
background: linear-gradient(180deg, rgba(15, 15, 20, 0.97), rgba(13, 13, 18, 0.88));
backdrop-filter: blur(12px); border-bottom: 1px solid rgba(255, 255, 255, 0.07); }
/* day header — sticky top */
.vcal-dayhead { position: sticky; top: 0; z-index: 4; padding: 15px 14px 13px;
background: linear-gradient(180deg, rgba(15, 15, 20, 0.96), rgba(13, 13, 18, 0.85));
backdrop-filter: blur(12px); border-bottom: 1px solid rgba(255, 255, 255, 0.07);
border-left: 1px solid rgba(255, 255, 255, 0.05); }
.vcal-dayhead-wd { display: block; font-size: 14px; font-weight: 800; letter-spacing: -0.01em; color: #fff; }
.vcal-dayhead-date { display: block; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
color: rgba(255, 255, 255, 0.4); margin-top: 2px; }
.vcal-dayhead-n { position: absolute; top: 14px; right: 13px; font-size: 11px; font-weight: 800; color: rgba(255, 255, 255, 0.6);
background: rgba(255, 255, 255, 0.08); padding: 3px 9px; border-radius: 999px; }
.vcal-dayhead--today { background: linear-gradient(180deg, rgba(var(--vcal-accent), 0.24), rgba(13, 13, 18, 0.86));
border-bottom-color: rgba(var(--vcal-accent), 0.55);
box-shadow: 0 1px 0 rgba(var(--vcal-accent), 0.55), 0 12px 28px -14px rgba(var(--vcal-accent), 0.6); }
.vcal-dayhead--today .vcal-dayhead-wd { color: hsl(232, 100%, 84%); }
.vcal-dayhead--today .vcal-dayhead-n { background: rgba(var(--vcal-accent), 0.9); color: #fff; }
/* time rail — sticky left, labels the band */
.vcal-rail { position: sticky; left: 0; z-index: 2; display: flex; flex-direction: column; gap: 2px;
padding: 17px 12px; border-top: 1px solid rgba(255, 255, 255, 0.05);
background: linear-gradient(90deg, rgba(255, 255, 255, 0.025), rgba(255, 255, 255, 0.004)); }
.vcal-rail-label { font-size: 12.5px; font-weight: 800; letter-spacing: -0.01em; color: rgba(255, 255, 255, 0.8); }
.vcal-rail small { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: rgba(255, 255, 255, 0.3); }
.vcal-rail--prime .vcal-rail-label { color: hsl(44, 100%, 72%); }
.vcal-rail--prime small { color: hsla(44, 90%, 60%, 0.6); }
/* one day×band cell */
.vcal-slot { display: flex; flex-direction: column; gap: 15px; padding: 17px 13px; min-width: 0;
border-top: 1px solid rgba(255, 255, 255, 0.05); border-left: 1px solid rgba(255, 255, 255, 0.05); }
.vcal-slot--today { background: linear-gradient(180deg, rgba(var(--vcal-accent), 0.07), rgba(var(--vcal-accent), 0.015)); }
.vcal-slot--empty { align-items: center; justify-content: center; padding: 0; }
.vcal-slot-dot { width: 4px; height: 4px; border-radius: 50%; background: rgba(255, 255, 255, 0.07); }
/* live "now" intersection — today column × current time-of-day band */
.vcal-slot--now { box-shadow: inset 3px 0 0 rgba(var(--vcal-accent), 0.95), inset 0 0 34px -12px rgba(var(--vcal-accent), 0.5);
background: linear-gradient(180deg, rgba(var(--vcal-accent), 0.12), rgba(var(--vcal-accent), 0.03)); }
/* staggered entrance — only on a fresh load/week-change (class added by JS),
keyed off the per-card --i (cycles every 24). Filter re-renders don't get it. */
.vcal-cols.vcal-animate-in .vcal-card { animation: vcalCardIn 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) both;
animation-delay: calc(var(--i, 0) * 0.022s); }
@keyframes vcalCardIn { from { opacity: 0; transform: translateY(10px) scale(0.985); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .vcal-cols.vcal-animate-in .vcal-card { animation: none; } }
/* week-change crossfade */
.vcal-grid { transition: opacity 0.22s ease; }
.vcal-grid.vcal-fading { opacity: 0.32; }
/* keyboard focus — mirrors hover + a clear ring (cards are real <a>s) */
.vcal-cell:focus-visible { outline: none; --ty: -6px; --sc: 1.04; z-index: 3; }
.vcal-cell:focus-visible .vcal-card { border-color: hsla(var(--vcal-show), 80%, 64%, 0.85);
box-shadow: 0 0 0 2px hsla(var(--vcal-show), 82%, 62%, 0.9), 0 18px 40px rgba(0, 0, 0, 0.5); }
/* Episode cell — one clean card (art + info), breathing colour halo behind it */
.vcal-cell { --vcal-show: var(--vcal-h, 230); position: relative; display: block; text-decoration: none; color: inherit;
transform: perspective(760px) translateY(var(--ty, 0px)) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--sc, 1));
transition: transform 0.16s ease; }
/* Calm by default; the colour only comes alive on hover. */
.vcal-glow { position: absolute; inset: -11px; z-index: 0; border-radius: 22px; pointer-events: none;
background: radial-gradient(closest-side, hsla(var(--vcal-show), 90%, 55%, 0.6), transparent 76%);
opacity: 0.06; animation: vcalBreathe 7s ease-in-out infinite; animation-delay: calc(var(--i) * -0.5s);
transition: opacity 0.25s ease; }
@keyframes vcalBreathe { 0%, 100% { opacity: 0.04; } 50% { opacity: 0.13; } }
.vcal-card { position: relative; z-index: 1; display: block; border-radius: 14px; overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.08); background: #14141a;
transition: border-color 0.2s ease, box-shadow 0.2s ease; }
.vcal-art { position: relative; display: block; aspect-ratio: 16 / 9; overflow: hidden;
background: linear-gradient(135deg, hsl(var(--vcal-show), 42%, 22%), #0a0a0e 90%); }
/* skeleton shimmer shown until the image fades in */
.vcal-art::before { content: ''; position: absolute; inset: 0; z-index: 0;
background: linear-gradient(100deg, transparent 16%, rgba(255, 255, 255, 0.05) 38%,
rgba(255, 255, 255, 0.10) 50%, rgba(255, 255, 255, 0.05) 62%, transparent 84%);
background-size: 220% 100%; animation: vcalShimmer 1.5s ease-in-out infinite; }
.vcal-cell-img { position: relative; z-index: 1; width: 100%; height: 100%; object-fit: cover; display: block;
opacity: 0; transition: opacity 0.5s ease; }
.vcal-cell-img.vcal-loaded { opacity: 1; }
@keyframes vcalShimmer { 0% { background-position: 200% 0; } 100% { background-position: -130% 0; } }
@media (prefers-reduced-motion: reduce) { .vcal-art::before { animation: none; } .vcal-cell-img { transition: none; } }
.vcal-art-scrim { position: absolute; inset: 0; z-index: 2; background: linear-gradient(0deg, rgba(0, 0, 0, 0.45), transparent 55%); }
.vcal-flag { position: absolute; top: 8px; right: 8px; z-index: 3; width: 22px; height: 22px; border-radius: 50%;
display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 900;
background: rgba(108, 211, 145, 0.94); color: #07130c; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5); }
.vcal-info { display: block; padding: 9px 11px 11px; }
.vcal-time { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 800; letter-spacing: 0.01em;
color: hsl(var(--vcal-show), 85%, 80%); }
.vcal-time-dot { width: 6px; height: 6px; border-radius: 50%; background: hsl(var(--vcal-show), 85%, 62%);
box-shadow: 0 0 8px hsl(var(--vcal-show), 85%, 60%); }
.vcal-time--none { color: rgba(255, 255, 255, 0.32); font-weight: 700; }
.vcal-show { display: block; font-size: 13.5px; font-weight: 800; line-height: 1.25; margin-top: 5px;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vcal-meta { display: block; font-size: 11.5px; color: rgba(255, 255, 255, 0.5); margin-top: 2px;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vcal-se { font-weight: 800; color: rgba(255, 255, 255, 0.72); }
.vcal-ep { margin-left: 6px; }
.vcal-cell:hover { --ty: -6px; --sc: 1.04; z-index: 3; }
.vcal-cell:hover .vcal-glow { opacity: 0.6 !important; animation-play-state: paused; }
.vcal-cell:hover .vcal-card { border-color: hsla(var(--vcal-show), 78%, 62%, 0.7);
box-shadow: 0 22px 46px rgba(0, 0, 0, 0.55), 0 0 30px hsla(var(--vcal-show), 78%, 55%, 0.34); }
@media (prefers-reduced-motion: reduce) {
.vcal-glow { animation: none; opacity: 0.08; }
.vcal-cell { transform: none; } .vcal-cell:hover { --ty: 0px; --sc: 1; }
}
/* Empty state */
.vcal-state { text-align: center; padding: 90px 20px; color: rgba(255, 255, 255, 0.6); }
.vcal-state-ic { font-size: 48px; opacity: 0.55; }
.vcal-state-title { font-size: 20px; font-weight: 800; color: #fff; margin-top: 12px; }
.vcal-state-sub { font-size: 14px; margin-top: 6px; }
@media (max-width: 900px) { .vcal-head, .vcal-body { padding-left: 18px; padding-right: 18px; } .vcal-cols { overflow-x: auto; } }
/* ── Calendar — episode modal ─────────────────────────────────────────────── */
.vcm-overlay { position: fixed; inset: 0; z-index: 9000; display: flex; align-items: center; justify-content: center;
padding: 24px; background: rgba(5, 5, 8, 0.72); backdrop-filter: blur(9px); opacity: 0; transition: opacity 0.2s ease; }
.vcm-overlay.vcm-open { opacity: 1; }
.vcm-modal { --vcm-h: 230; position: relative; width: min(700px, 100%); max-height: 90vh; overflow-y: auto;
border-radius: 22px; background: #101015; border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 50px 130px rgba(0, 0, 0, 0.72); transform: translateY(16px) scale(0.985);
transition: transform 0.26s cubic-bezier(0.2, 0.7, 0.2, 1); }
.vcm-overlay.vcm-open .vcm-modal { transform: none; }
.vcm-modal::-webkit-scrollbar { width: 9px; }
.vcm-modal::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.14); border-radius: 5px; }
.vcm-close { position: absolute; top: 14px; right: 14px; z-index: 3; width: 36px; height: 36px; border-radius: 50%;
border: 1px solid rgba(255, 255, 255, 0.18); background: rgba(0, 0, 0, 0.45); color: #fff; font-size: 22px; cursor: pointer;
backdrop-filter: blur(6px); display: flex; align-items: center; justify-content: center; line-height: 1; transition: all 0.15s ease; }
.vcm-close:hover { background: rgba(0, 0, 0, 0.72); border-color: rgba(255, 255, 255, 0.4); }
.vcm-hero { position: relative; min-height: 210px; border-radius: 22px 22px 0 0; overflow: hidden; display: flex; align-items: flex-end; }
.vcm-hero-bg { position: absolute; inset: 0; background-size: cover; background-position: center 28%; transform: scale(1.05); }
.vcm-hero-scrim { position: absolute; inset: 0;
background: linear-gradient(0deg, #101015 3%, rgba(16, 16, 21, 0.45) 52%, rgba(16, 16, 21, 0.15)),
radial-gradient(130% 110% at 0% 100%, hsla(var(--vcm-h), 72%, 45%, 0.38), transparent 60%); }
.vcm-hero-content { position: relative; z-index: 1; padding: 24px 26px 18px; width: 100%; }
.vcm-eyebrow { font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: hsl(var(--vcm-h), 82%, 80%); }
.vcm-eyebrow:empty { display: none; }
.vcm-show { font-size: 27px; font-weight: 800; letter-spacing: -0.02em; margin: 6px 0 0; line-height: 1.1; }
.vcm-genres { display: flex; gap: 7px; margin-top: 11px; flex-wrap: wrap; }
.vcm-genre { font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 999px; background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.82); }
.vcm-body { padding: 20px 26px; }
.vcm-ep { display: grid; grid-template-columns: 176px 1fr; gap: 20px; }
.vcm-ep-still { position: relative; aspect-ratio: 16 / 9; border-radius: 12px; overflow: hidden;
background: linear-gradient(135deg, hsl(var(--vcm-h), 48%, 28%), #0b0b0f); }
.vcm-ep-still img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 1;
opacity: 0; transition: opacity 0.45s ease; }
.vcm-ep-still img.vcm-loaded { opacity: 1; }
.vcm-ep-fb { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 24px; color: rgba(255, 255, 255, 0.3); }
.vcm-ep-main { min-width: 0; }
.vcm-ep-se { font-size: 12px; font-weight: 800; color: hsl(var(--vcm-h), 82%, 78%); letter-spacing: 0.03em; }
.vcm-ep-title { font-size: 20px; font-weight: 800; margin: 3px 0 0; line-height: 1.2; }
.vcm-when { font-size: 13px; color: rgba(255, 255, 255, 0.62); margin-top: 8px; font-weight: 600; }
.vcm-tags { display: flex; gap: 8px; margin-top: 13px; flex-wrap: wrap; align-items: center; }
.vcm-badge { font-size: 11px; font-weight: 800; padding: 4px 11px; border-radius: 999px; }
.vcm-badge--have { background: rgba(108, 211, 145, 0.16); color: #6cd391; }
.vcm-badge--miss { background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.55); }
.vcm-tag { font-size: 11.5px; font-weight: 700; color: rgba(255, 255, 255, 0.62); }
.vcm-tag--star { color: rgba(245, 197, 24, 0.95); }
.vcm-ep-ov { font-size: 13.5px; line-height: 1.6; color: rgba(255, 255, 255, 0.8); margin: 15px 0 0; }
.vcm-ep-ov--none { color: rgba(255, 255, 255, 0.35); font-style: italic; }
.vcm-about { margin-top: 22px; padding-top: 18px; border-top: 1px solid rgba(255, 255, 255, 0.07); }
.vcm-about-h { font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: rgba(255, 255, 255, 0.5); margin: 0 0 8px; }
.vcm-about-ov { font-size: 13.5px; line-height: 1.6; color: rgba(255, 255, 255, 0.72); margin: 0; }
.vcm-actions { display: flex; justify-content: flex-end; gap: 10px; padding: 4px 26px 24px; }
.vcm-btn { font-size: 13px; font-weight: 800; padding: 11px 18px; border-radius: 12px; cursor: pointer; border: 1px solid transparent; transition: all 0.15s ease; }
.vcm-btn--ghost { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.12); color: rgba(255, 255, 255, 0.82); }
.vcm-btn--ghost:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.vcm-btn--primary { background: hsl(var(--vcm-h), 68%, 52%); color: #fff; box-shadow: 0 8px 24px hsla(var(--vcm-h), 70%, 45%, 0.4); }
.vcm-btn--primary:hover { filter: brightness(1.08); transform: translateY(-1px); }
@media (max-width: 560px) {
.vcm-ep { grid-template-columns: 1fr; }
.vcm-ep-still { max-width: 240px; }
.vcm-actions { flex-direction: column-reverse; }
.vcm-btn { width: 100%; }
}
/* ── Calendar — featured "next up" billboard ──────────────────────────────── */
.vcal-hero-wrap { padding: 4px 40px 8px; perspective: 1400px; }
.vcal-hero-wrap:empty { display: none; }
.vcal-bb { --vcal-h: 230; position: relative; display: flex; align-items: flex-end; min-height: 306px;
border-radius: 22px; overflow: hidden; cursor: pointer; border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 34px 90px rgba(0, 0, 0, 0.55);
transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) scale(var(--sc, 1));
transition: transform 0.18s ease, box-shadow 0.3s ease; will-change: transform; }
.vcal-bb:hover { --sc: 1.012; box-shadow: 0 44px 110px rgba(0, 0, 0, 0.62), 0 0 60px hsla(var(--vcal-h), 72%, 50%, 0.22); }
.vcal-bb-bg { position: absolute; inset: 0; background-size: cover; background-position: center 22%; transform: scale(1.08); }
.vcal-bb-scrim { position: absolute; inset: 0;
background: linear-gradient(90deg, rgba(8, 8, 12, 0.94) 0%, rgba(8, 8, 12, 0.62) 42%, transparent 78%),
linear-gradient(0deg, rgba(8, 8, 12, 0.82), transparent 58%),
radial-gradient(120% 130% at 0% 100%, hsla(var(--vcal-h), 72%, 45%, 0.42), transparent 58%); }
.vcal-bb-content { position: relative; z-index: 1; padding: 34px 42px 34px; max-width: 640px; }
.vcal-bb-eyebrow { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 800;
letter-spacing: 0.09em; text-transform: uppercase; color: hsl(var(--vcal-h), 88%, 80%); }
.vcal-bb-dot { width: 7px; height: 7px; border-radius: 50%; background: hsl(var(--vcal-h), 88%, 62%);
box-shadow: 0 0 12px hsl(var(--vcal-h), 88%, 60%); animation: vcalPulse 2s ease-in-out infinite; }
@keyframes vcalPulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.45; transform: scale(0.6); } }
.vcal-bb-title { font-size: 42px; font-weight: 900; letter-spacing: -0.03em; line-height: 1.02; margin: 11px 0 0;
text-shadow: 0 2px 20px rgba(0, 0, 0, 0.6); }
.vcal-bb-sub { font-size: 15px; color: rgba(255, 255, 255, 0.82); margin-top: 9px; font-weight: 600; }
.vcal-bb-se { font-weight: 800; color: #fff; }
.vcal-bb-actions { display: flex; align-items: center; gap: 14px; margin-top: 22px; }
.vcal-bb-btn { display: inline-flex; align-items: center; font-size: 13.5px; font-weight: 800; padding: 12px 22px;
border-radius: 12px; background: #fff; color: #0a0a0e; box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
transition: transform 0.15s ease; }
.vcal-bb:hover .vcal-bb-btn { transform: translateY(-2px); }
.vcal-bb-badge { font-size: 12px; font-weight: 800; padding: 6px 13px; border-radius: 999px;
background: rgba(108, 211, 145, 0.18); color: #6cd391; }
@media (prefers-reduced-motion: reduce) { .vcal-bb { transform: none; } .vcal-bb-dot { animation: none; } }
@media (max-width: 900px) {
.vcal-hero-wrap { padding-left: 18px; padding-right: 18px; }
.vcal-bb-title { font-size: 30px; } .vcal-bb { min-height: 240px; }
}
/* ── Calendar — header controls (week nav + filter) ───────────────────────── */
.vcal-head-row { position: relative; z-index: 1; display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.vcal-controls { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.vcal-nav { display: inline-flex; align-items: center; gap: 2px; padding: 4px; border-radius: 12px;
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.08); }
.vcal-nav-btn { width: 34px; height: 32px; border: 0; background: transparent; color: rgba(255, 255, 255, 0.75);
font-size: 20px; font-weight: 700; cursor: pointer; border-radius: 8px; line-height: 1; transition: all 0.15s ease; }
.vcal-nav-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
.vcal-nav-today { border: 0; background: transparent; color: rgba(255, 255, 255, 0.82); font-size: 12.5px; font-weight: 800;
padding: 7px 12px; border-radius: 8px; cursor: pointer; transition: all 0.15s ease; }
.vcal-nav-today:hover:not(:disabled) { background: rgba(255, 255, 255, 0.1); color: #fff; }
.vcal-nav-today:disabled { opacity: 0.34; cursor: default; }
.vcal-filter { display: inline-flex; gap: 3px; padding: 4px; border-radius: 12px;
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.08); }
.vcal-filter-btn { border: 0; background: transparent; color: rgba(255, 255, 255, 0.7); font-size: 12.5px; font-weight: 700;
padding: 7px 14px; border-radius: 8px; cursor: pointer; transition: all 0.15s ease; }
.vcal-filter-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }
.vcal-filter-btn--on { color: #fff; background: rgba(var(--vcal-accent), 0.9); box-shadow: 0 4px 14px rgba(var(--vcal-accent), 0.32); }
@media (max-width: 720px) { .vcal-head-row { flex-direction: column; align-items: stretch; } .vcal-controls { justify-content: space-between; } }
/* ══════════════════════════════════════════════════════════════════════════
Watchlist — shared "add to watchlist" button (.vwl-btn) + the Watchlist page
(.vwlp-*). The button is the video mirror of the music ya-watchlist-btn.
══════════════════════════════════════════════════════════════════════════ */
/* Shared eye button — overlaid top-right on a show poster / person photo. */
.vwl-btn {
position: absolute; top: 8px; right: 8px; z-index: 4;
width: 30px; height: 30px; border-radius: 9px;
display: flex; align-items: center; justify-content: center;
background: rgba(0, 0, 0, 0.55); backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.14); color: rgba(255, 255, 255, 0.82);
cursor: pointer; opacity: 0; transform: translateY(-2px);
transition: opacity 0.18s ease, transform 0.18s ease, background 0.18s ease,
color 0.18s ease, border-color 0.18s ease; }
.vwl-btn:hover { background: rgba(0, 0, 0, 0.78); color: #fff; border-color: rgba(255, 255, 255, 0.3); }
.vwl-btn.active { opacity: 1; transform: none;
color: rgb(var(--accent-rgb, 88 101 242));
background: rgba(var(--accent-rgb, 88 101 242), 0.18);
border-color: rgba(var(--accent-rgb, 88 101 242), 0.55); }
.vwl-btn:disabled { opacity: 0.5; cursor: default; }
/* hover-reveal on the cards that host it (always shown once active / on touch) */
.library-artist-card:hover .vwl-btn, .vwlp-card:hover .vwl-btn,
.vd-cast-card:hover .vwl-btn, .vsr-card:hover .vwl-btn, .vd-sim-card:hover .vwl-btn {
opacity: 1; transform: none; }
@media (hover: none) { .vwl-btn { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .vwl-btn { transition: opacity 0.18s ease; transform: none; } }
/* ── Watchlist page ───────────────────────────────────────────────────────── */
.vwlp-page { color: var(--text-primary, #fff); padding: 0 0 70px; }
.vwlp-head { position: relative; padding: 30px 40px 0; overflow: hidden; }
.vwlp-head-glow { position: absolute; top: -190px; left: 50%; transform: translateX(-50%);
width: 860px; height: 390px; pointer-events: none; z-index: 0;
background: radial-gradient(56% 70% at 50% 0%, rgba(var(--accent-rgb, 88 101 242), 0.22), transparent 70%); filter: blur(10px); }
.vwlp-head-row { position: relative; z-index: 1; display: flex; align-items: flex-end;
justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.vwlp-title { font-size: 36px; font-weight: 800; letter-spacing: -0.025em; margin: 0; }
.vwlp-sub { margin: 7px 0 0; color: rgba(255, 255, 255, 0.55); font-size: 14px; font-weight: 600; }
.vwlp-tabs { display: inline-flex; gap: 3px; padding: 4px; border-radius: 13px;
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.08); }
.vwlp-tab { border: 0; background: transparent; color: rgba(255, 255, 255, 0.7);
font-size: 13px; font-weight: 800; padding: 8px 16px; border-radius: 9px; cursor: pointer;
display: inline-flex; align-items: center; gap: 8px; transition: all 0.15s ease; }
.vwlp-tab:hover { color: #fff; background: rgba(255, 255, 255, 0.07); }
.vwlp-tab--on { color: #fff; background: rgba(var(--accent-rgb, 88 101 242), 0.9);
box-shadow: 0 4px 14px rgba(var(--accent-rgb, 88 101 242), 0.32); }
.vwlp-tab-n { font-size: 11px; font-weight: 800; min-width: 20px; text-align: center;
padding: 1px 7px; border-radius: 999px; background: rgba(0, 0, 0, 0.25); color: inherit; }
.vwlp-tab--on .vwlp-tab-n { background: rgba(0, 0, 0, 0.28); }
.vwlp-body { padding: 26px 40px 0; }
.vwlp-loading { padding: 80px 0; text-align: center; }
.vwlp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(158px, 1fr)); gap: 22px 20px; }
.vwlp-grid.hidden { display: none; }
.vwlp-card { position: relative; display: block; text-decoration: none; color: inherit;
transition: transform 0.16s ease; }
.vwlp-card:hover { transform: translateY(-5px); }
.vwlp-card-art { position: relative; aspect-ratio: 2 / 3; border-radius: 14px; overflow: hidden;
background: linear-gradient(140deg, #1a1a22, #0c0c10); border: 1px solid rgba(255, 255, 255, 0.07);
box-shadow: 0 14px 34px rgba(0, 0, 0, 0.4); transition: border-color 0.18s ease, box-shadow 0.18s ease; }
.vwlp-card:hover .vwlp-card-art { border-color: rgba(var(--accent-rgb, 88 101 242), 0.5);
box-shadow: 0 22px 50px rgba(0, 0, 0, 0.55), 0 0 24px rgba(var(--accent-rgb, 88 101 242), 0.22); }
.vwlp-card--person .vwlp-card-art { border-radius: 16px; }
.vwlp-card-img { width: 100%; height: 100%; object-fit: cover; display: block;
opacity: 0; transition: opacity 0.45s ease; }
.vwlp-card-img.vwlp-loaded { opacity: 1; }
.vwlp-card-ph { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
font-size: 40px; opacity: 0.5; }
.vwlp-card-scrim { position: absolute; inset: 0; pointer-events: none;
background: linear-gradient(0deg, rgba(0, 0, 0, 0.4), transparent 42%); }
.vwlp-card-info { padding: 9px 4px 0; }
.vwlp-card-title { display: block; font-size: 13.5px; font-weight: 700; line-height: 1.3;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vwlp-state { text-align: center; padding: 90px 20px; color: rgba(255, 255, 255, 0.6); }
.vwlp-state.hidden { display: none; }
.vwlp-state-ic { font-size: 46px; opacity: 0.5; }
.vwlp-state-title { font-size: 20px; font-weight: 800; color: #fff; margin-top: 12px; }
.vwlp-state-sub { font-size: 14px; margin-top: 6px; max-width: 420px; margin-left: auto; margin-right: auto; }
@media (max-width: 900px) {
.vwlp-head, .vwlp-body { padding-left: 18px; padding-right: 18px; }
.vwlp-grid { grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: 18px 14px; }
}
/* Ensure the show poster box is a positioning context for its .vwl-btn
(scoped to VIDEO cards so the shared music .library-artist-image is untouched). */
.video-card--clickable .library-artist-image { position: relative; }
/* ── Watchlist page — search toolbar + pagination ─────────────────────────── */
.vwlp-toolbar { padding: 18px 40px 0; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.vwlp-search { position: relative; flex: 1; max-width: 420px; min-width: 220px; }
.vwlp-search-ic { position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
color: rgba(255, 255, 255, 0.4); pointer-events: none; }
.vwlp-search-input { width: 100%; padding: 11px 14px 11px 38px; border-radius: 12px;
background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1);
color: #fff; font-size: 14px; font-weight: 500; outline: none; transition: border-color 0.15s ease, background 0.15s ease; }
.vwlp-search-input::placeholder { color: rgba(255, 255, 255, 0.35); }
.vwlp-search-input:focus { border-color: rgba(var(--accent-rgb, 88 101 242), 0.6);
background: rgba(255, 255, 255, 0.07); }
.vwlp-pagination { display: flex; align-items: center; justify-content: center; gap: 16px; padding: 30px 0 4px; }
.vwlp-pagination.hidden { display: none; }
.vwlp-page-btn { padding: 9px 16px; border-radius: 10px; font-size: 13px; font-weight: 700;
background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.85); cursor: pointer; transition: all 0.15s ease; }
.vwlp-page-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.12); color: #fff; }
.vwlp-page-btn:disabled { opacity: 0.35; cursor: default; }
.vwlp-page-info { font-size: 13px; font-weight: 700; color: rgba(255, 255, 255, 0.6); min-width: 110px; text-align: center; }
@media (max-width: 900px) { .vwlp-toolbar { padding-left: 18px; padding-right: 18px; } }
/* ══════════════════════════════════════════════════════════════════════════
"Get" button (.vget-btn) + detail/download modal (.vgm-*) — the terminal-
content counterpart to the watchlist eye (movies + ended shows).
══════════════════════════════════════════════════════════════════════════ */
.vget-btn {
position: absolute; top: 8px; right: 8px; z-index: 4;
width: 30px; height: 30px; border-radius: 9px;
display: flex; align-items: center; justify-content: center;
background: rgba(0, 0, 0, 0.55); backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.16); color: rgba(255, 255, 255, 0.88);
cursor: pointer; opacity: 0; transform: translateY(-2px);
transition: opacity 0.18s ease, transform 0.18s ease, background 0.18s ease, border-color 0.18s ease; }
.vget-btn:hover { background: rgba(var(--accent-rgb, 88 101 242), 0.92); color: #fff;
border-color: rgba(var(--accent-rgb, 88 101 242), 0.92); }
.library-artist-card:hover .vget-btn, .vwlp-card:hover .vget-btn,
.vsr-card:hover .vget-btn, .vd-sim-card:hover .vget-btn { opacity: 1; transform: none; }
@media (hover: none) { .vget-btn { opacity: 1; transform: none; } }
/* modal */
.vgm-overlay { position: fixed; inset: 0; z-index: 9100; display: flex; align-items: center; justify-content: center;
padding: 24px; background: rgba(5, 5, 8, 0.72); backdrop-filter: blur(9px); opacity: 0; transition: opacity 0.2s ease; }
.vgm-overlay.vgm-open { opacity: 1; }
.vgm-modal { position: relative; width: min(680px, 100%); max-height: 90vh; overflow-y: auto;
border-radius: 22px; background: #101015; border: 1px solid rgba(255, 255, 255, 0.08);
box-shadow: 0 50px 130px rgba(0, 0, 0, 0.72); transform: translateY(16px) scale(0.985);
transition: transform 0.26s cubic-bezier(0.2, 0.7, 0.2, 1); }
.vgm-overlay.vgm-open .vgm-modal { transform: none; }
.vgm-modal::-webkit-scrollbar { width: 9px; }
.vgm-modal::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.14); border-radius: 5px; }
.vgm-close { position: absolute; top: 14px; right: 14px; z-index: 3; width: 36px; height: 36px; border-radius: 50%;
border: 1px solid rgba(255, 255, 255, 0.18); background: rgba(0, 0, 0, 0.45); color: #fff; font-size: 22px;
cursor: pointer; backdrop-filter: blur(6px); display: flex; align-items: center; justify-content: center;
line-height: 1; transition: all 0.15s ease; }
.vgm-close:hover { background: rgba(0, 0, 0, 0.72); border-color: rgba(255, 255, 255, 0.4); }
.vgm-hero { position: relative; min-height: 260px; border-radius: 22px 22px 0 0; overflow: hidden;
display: flex; align-items: flex-end; background-size: cover; background-position: center 22%; background-color: #16161d; }
.vgm-hero-scrim { position: absolute; inset: 0;
background: linear-gradient(0deg, #101015 4%, rgba(16, 16, 21, 0.5) 52%, rgba(16, 16, 21, 0.1)),
radial-gradient(130% 110% at 0% 100%, rgba(var(--accent-rgb, 88 101 242), 0.32), transparent 60%); }
.vgm-hero-content { position: relative; z-index: 1; padding: 26px 28px 20px; width: 100%; }
.vgm-eyebrow { font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em;
color: rgba(255, 255, 255, 0.6); }
.vgm-eyebrow:empty { display: none; }
.vgm-title { font-size: 30px; font-weight: 900; letter-spacing: -0.025em; line-height: 1.05; margin: 8px 0 0;
text-shadow: 0 2px 18px rgba(0, 0, 0, 0.55); }
.vgm-meta { display: flex; gap: 16px; margin-top: 11px; flex-wrap: wrap; }
.vgm-meta-item { font-size: 13px; font-weight: 700; color: rgba(255, 255, 255, 0.78); }
.vgm-genres { display: flex; gap: 7px; margin-top: 12px; flex-wrap: wrap; }
.vgm-genres:empty { display: none; }
.vgm-genre { font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 999px;
background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.82); }
.vgm-body { padding: 20px 28px 4px; }
.vgm-overview { font-size: 14px; line-height: 1.65; color: rgba(255, 255, 255, 0.82); margin: 0; }
.vgm-overview--none { color: rgba(255, 255, 255, 0.4); font-style: italic; }
.vgm-actions { display: flex; justify-content: flex-end; gap: 10px; padding: 20px 28px 26px; }
.vgm-btn { font-size: 13px; font-weight: 800; padding: 11px 20px; border-radius: 12px; cursor: pointer;
border: 1px solid transparent; transition: all 0.15s ease; }
.vgm-btn--ghost { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.12); color: rgba(255, 255, 255, 0.82); }
.vgm-btn--ghost:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.vgm-btn--primary { background: rgb(var(--accent-rgb, 88 101 242)); color: #fff;
box-shadow: 0 8px 24px rgba(var(--accent-rgb, 88 101 242), 0.4); }
.vgm-btn--primary:hover { filter: brightness(1.08); transform: translateY(-1px); }
@media (max-width: 560px) { .vgm-actions { flex-direction: column-reverse; } .vgm-btn { width: 100%; } }
/* ── Get-modal: poster + ratings + owned-note + next-up ───────────────────── */
/* Poster floats over the hero bottom-left; content shifts right to clear it. */
.vgm-poster { position: absolute; left: 28px; bottom: 18px; z-index: 2; width: 104px; aspect-ratio: 2 / 3;
object-fit: cover; border-radius: 10px; background: #16161d;
border: 1px solid rgba(255, 255, 255, 0.16);
box-shadow: 0 14px 34px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(0, 0, 0, 0.4); }
.vgm-poster[hidden] { display: none; }
.vgm-hero.vgm-has-poster .vgm-hero-content { padding-left: 152px; }
@media (max-width: 560px) { .vgm-poster { width: 78px; left: 20px; }
.vgm-hero.vgm-has-poster .vgm-hero-content { padding-left: 112px; } }
/* Ratings strip — branded source chips (IMDb / RT / Metacritic). */
.vgm-ratings { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.vgm-ratings[hidden] { display: none; }
.vgm-rating { display: inline-flex; align-items: baseline; gap: 6px; padding: 5px 11px; border-radius: 9px;
background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.09); }
.vgm-rating-src { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em;
color: rgba(255, 255, 255, 0.5); }
.vgm-rating-val { font-size: 14px; font-weight: 900; color: #fff; letter-spacing: -0.01em; }
.vgm-rating--imdb { background: rgba(245, 197, 24, 0.1); border-color: rgba(245, 197, 24, 0.32); }
.vgm-rating--imdb .vgm-rating-src { color: #f5c518; }
.vgm-rating--rt { background: rgba(250, 50, 11, 0.1); border-color: rgba(250, 50, 11, 0.3); }
.vgm-rating--rt .vgm-rating-src { color: #ff6446; }
.vgm-rating--mc { background: rgba(108, 211, 145, 0.1); border-color: rgba(108, 211, 145, 0.3); }
.vgm-rating--mc .vgm-rating-src { color: #6cd391; }
/* Owned-movie note — "in your library" with the best version's quality. */
.vgm-owned { display: flex; align-items: center; gap: 9px; margin-top: 16px; padding: 12px 14px; border-radius: 12px;
background: rgba(108, 211, 145, 0.08); border: 1px solid rgba(108, 211, 145, 0.26); }
.vgm-owned[hidden] { display: none; }
.vgm-owned-ic { font-size: 14px; font-weight: 900; color: #6cd391; flex-shrink: 0; }
.vgm-owned-txt { font-size: 13px; color: rgba(255, 255, 255, 0.7); }
.vgm-owned-txt strong { color: #8fe7af; font-weight: 800; }
/* Next-episode line — the soonest upcoming episode for an airing show. */
.vgm-next { display: flex; align-items: center; gap: 11px; margin-top: 16px; padding: 12px 14px; border-radius: 12px;
background: rgba(var(--accent-rgb, 88 101 242), 0.09); border: 1px solid rgba(var(--accent-rgb, 88 101 242), 0.26); }
.vgm-next[hidden] { display: none; }
.vgm-next-ic { font-size: 11px; color: rgb(var(--accent-rgb, 88 101 242)); flex-shrink: 0; }
.vgm-next-txt { font-size: 13px; color: rgba(255, 255, 255, 0.78); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vgm-next-txt strong { color: #fff; font-weight: 800; }
.vgm-next-date { margin-left: auto; flex-shrink: 0; font-size: 12px; font-weight: 800; color: #c4cbff; }
/* Watchlist card richness — status pill + episode-count meta + sort select */
.vwlp-pill { position: absolute; top: 8px; left: 8px; z-index: 3;
font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em;
padding: 3px 8px; border-radius: 7px; backdrop-filter: blur(6px);
background: rgba(0, 0, 0, 0.55); color: rgba(255, 255, 255, 0.9); border: 1px solid rgba(255, 255, 255, 0.12); }
.vwlp-pill--airing { background: rgba(108, 211, 145, 0.22); color: #8fe7af; border-color: rgba(108, 211, 145, 0.4); }
.vwlp-pill--soon { background: rgba(var(--accent-rgb, 88 101 242), 0.24); color: #c4cbff; border-color: rgba(var(--accent-rgb, 88 101 242), 0.45); }
.vwlp-pill--ended { background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.6); }
.vwlp-card-meta { display: block; font-size: 11.5px; font-weight: 600; color: rgba(255, 255, 255, 0.45); margin-top: 3px; }
.vwlp-sort { padding: 11px 14px; border-radius: 12px; background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1); color: #fff; font-size: 13px; font-weight: 600;
cursor: pointer; outline: none; transition: border-color 0.15s ease; }
.vwlp-sort:focus { border-color: rgba(var(--accent-rgb, 88 101 242), 0.6); }
.vwlp-sort option { background: #16161d; color: #fff; }
/* The eye/get button anchors to these card roots (other surfaces). Position is
additive (no flow change); buttons are absolute top-right within them. */
.vsr-card, .vd-sim-card, .vd-cast-card { position: relative; }
.vd-cast-card:hover .vget-btn { opacity: 1; transform: none; }
/* Card control GROUP (eye + get can co-exist on an airing show). The wrapper is
positioned top-right; the buttons inside flow statically in a little row. */
.vcard-ctrls { position: absolute; top: 8px; right: 8px; z-index: 4; display: flex; gap: 6px; }
.vcard-ctrls .vwl-btn, .vcard-ctrls .vget-btn { position: static; top: auto; right: auto; }
/* ── Get-modal: season/episode selector + smarter footer ──────────────────── */
.vgm-eps { margin-top: 20px; padding-top: 18px; border-top: 1px solid rgba(255, 255, 255, 0.08); }
.vgm-eps[hidden] { display: none; }
.vgm-eps-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.vgm-eps-h { font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: rgba(255, 255, 255, 0.55); }
.vgm-eps-toggle { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 700;
color: rgba(255, 255, 255, 0.6); cursor: pointer; user-select: none; }
.vgm-eps-toggle input { accent-color: rgb(var(--accent-rgb, 88 101 242)); width: 15px; height: 15px; cursor: pointer; }
.vgm-eps-list { display: flex; flex-direction: column; gap: 8px; }
.vgm-season { border: 1px solid rgba(255, 255, 255, 0.07); border-radius: 12px; background: rgba(255, 255, 255, 0.02); overflow: hidden; }
.vgm-season-head { display: flex; align-items: center; gap: 11px; padding: 12px 14px; cursor: pointer; transition: background 0.15s ease; }
.vgm-season-head:hover { background: rgba(255, 255, 255, 0.04); }
.vgm-season-check { display: inline-flex; align-items: center; }
.vgm-season-check input { accent-color: rgb(var(--accent-rgb, 88 101 242)); width: 17px; height: 17px; cursor: pointer; }
.vgm-season-check--lock { color: rgba(108, 211, 145, 0.85); font-size: 14px; font-weight: 900; width: 17px; justify-content: center; }
.vgm-season-name { font-size: 14px; font-weight: 800; color: #fff; }
.vgm-season-meta { font-size: 12px; font-weight: 600; color: rgba(255, 255, 255, 0.45); margin-left: auto; }
.vgm-season-chev { color: rgba(255, 255, 255, 0.4); transition: transform 0.2s ease; font-size: 13px; }
.vgm-season--open .vgm-season-chev { transform: rotate(180deg); }
.vgm-season-eps { display: none; padding: 2px 6px 8px; }
.vgm-season--open .vgm-season-eps { display: block; }
.vgm-season-loading { padding: 14px 12px; font-size: 12.5px; font-weight: 600; color: rgba(255, 255, 255, 0.4); text-align: center; }
.vgm-ep { display: flex; align-items: center; gap: 11px; padding: 8px 10px; border-radius: 9px; cursor: pointer; transition: background 0.12s ease; }
.vgm-ep:hover { background: rgba(255, 255, 255, 0.04); }
.vgm-eps--missing-only .vgm-ep--owned { display: none; }
.vgm-ep-ctrl { width: 18px; display: inline-flex; justify-content: center; flex-shrink: 0; }
.vgm-ep-cb { accent-color: rgb(var(--accent-rgb, 88 101 242)); width: 16px; height: 16px; cursor: pointer; }
.vgm-ep-lock { font-size: 13px; }
.vgm-ep--owned .vgm-ep-lock { color: rgba(108, 211, 145, 0.8); }
.vgm-ep--upcoming .vgm-ep-lock { color: rgba(255, 255, 255, 0.3); }
.vgm-ep-num { font-size: 11.5px; font-weight: 800; color: rgba(255, 255, 255, 0.4); min-width: 30px; flex-shrink: 0; }
.vgm-ep-title { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; color: rgba(255, 255, 255, 0.9); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vgm-ep--owned .vgm-ep-title, .vgm-ep--upcoming .vgm-ep-title { color: rgba(255, 255, 255, 0.45); }
.vgm-ep-date { font-size: 11.5px; font-weight: 600; color: rgba(255, 255, 255, 0.35); margin-left: 8px; flex-shrink: 0; }
.vgm-ep-badge { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em; padding: 2px 8px; border-radius: 6px; margin-left: 8px; flex-shrink: 0; }
.vgm-ep-badge--owned { background: rgba(108, 211, 145, 0.16); color: #6cd391; }
.vgm-ep-badge--missing { background: rgba(var(--accent-rgb, 88 101 242), 0.18); color: #c4cbff; }
.vgm-ep-badge--soon { background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.5); }
/* footer */
.vgm-sel-count { margin-right: auto; font-size: 13px; font-weight: 700; color: rgba(255, 255, 255, 0.55); }
.vgm-btn--text { background: transparent; border-color: transparent; color: rgba(255, 255, 255, 0.6); padding: 11px 8px; }
.vgm-btn--text:hover { color: #fff; }
.vgm-btn:disabled { opacity: 0.4; cursor: default; transform: none !important; filter: none !important; }
/* "Add to watchlist" offer in the show get-modal (airing + not-yet-followed) */
.vgm-follow { margin-top: 14px; }
.vgm-follow[hidden] { display: none; }
.vgm-follow-row { display: flex; align-items: center; gap: 11px; padding: 13px 14px; border-radius: 12px; cursor: pointer;
background: rgba(var(--accent-rgb, 88 101 242), 0.1); border: 1px solid rgba(var(--accent-rgb, 88 101 242), 0.28); }
.vgm-follow-row:hover { background: rgba(var(--accent-rgb, 88 101 242), 0.14); }
.vgm-follow-row input { accent-color: rgb(var(--accent-rgb, 88 101 242)); width: 17px; height: 17px; cursor: pointer; flex-shrink: 0; }
.vgm-follow-txt { font-size: 13px; color: rgba(255, 255, 255, 0.82); }
.vgm-follow-txt strong { color: #fff; font-weight: 800; }
/* Fully-owned seasons hide while "Missing only" is on (turn it off to re-download). */
.vgm-eps--missing-only .vgm-season--owned { display: none; }
.vgm-eps-allowned { display: none; padding: 22px 14px; text-align: center; font-size: 13.5px; font-weight: 600; color: rgba(108, 211, 145, 0.85); }
.vgm-eps--missing-only .vgm-eps-allowned { display: block; }
/* ══════════════════════════════════════════════════════════════════════════
Get-modal — premium vibe pass: per-title hue glows + motion (--vgm-h set by JS)
══════════════════════════════════════════════════════════════════════════ */
.vgm-overlay { background: rgba(4, 4, 7, 0.78); }
.vgm-modal {
box-shadow: 0 60px 140px rgba(0, 0, 0, 0.75),
0 0 90px hsla(var(--vgm-h, 230), 75%, 55%, 0.20),
inset 0 1px 0 rgba(255, 255, 255, 0.06);
transform: translateY(22px) scale(0.96);
transition: transform 0.42s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease;
}
.vgm-overlay.vgm-open .vgm-modal { transform: none; }
/* hero — slow Ken Burns drift, hue-tinted scrim, and a drifting light sweep */
.vgm-hero { animation: vgmKen 22s ease-in-out infinite alternate; }
@keyframes vgmKen { from { background-position: center 18%; } to { background-position: center 34%; } }
.vgm-hero-scrim {
background: linear-gradient(0deg, #101015 3%, rgba(16, 16, 21, 0.55) 50%, rgba(16, 16, 21, 0.05)),
radial-gradient(140% 120% at 0% 100%, hsla(var(--vgm-h, 230), 78%, 48%, 0.42), transparent 60%),
radial-gradient(120% 100% at 100% 0%, hsla(var(--vgm-h, 230), 80%, 62%, 0.18), transparent 55%);
}
.vgm-hero::after {
content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
background: linear-gradient(115deg, transparent 34%, hsla(var(--vgm-h, 230), 92%, 78%, 0.07) 49%, transparent 60%);
background-size: 250% 100%; animation: vgmSheen 9s ease-in-out infinite;
}
@keyframes vgmSheen { 0% { background-position: 170% 0; } 55%, 100% { background-position: -70% 0; } }
/* staggered content rise on open */
.vgm-overlay.vgm-open .vgm-hero-content > * { animation: vgmRise 0.55s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
.vgm-hero-content > *:nth-child(1) { animation-delay: 0.05s; }
.vgm-hero-content > *:nth-child(2) { animation-delay: 0.11s; }
.vgm-hero-content > *:nth-child(3) { animation-delay: 0.17s; }
.vgm-hero-content > *:nth-child(4) { animation-delay: 0.23s; }
@keyframes vgmRise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.vgm-title { text-shadow: 0 2px 24px rgba(0, 0, 0, 0.65), 0 0 42px hsla(var(--vgm-h, 230), 80%, 55%, 0.28); }
/* poster — hue-aware halo + its own rise (it sits outside hero-content) */
.vgm-poster { box-shadow: 0 14px 34px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(0, 0, 0, 0.4),
0 0 28px -6px hsla(var(--vgm-h, 230), 80%, 58%, 0.5); }
.vgm-overlay.vgm-open .vgm-poster { animation: vgmRise 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) 0.12s both; }
/* primary CTA — hue-aware gradient + glow + lift */
.vgm-btn--primary {
background: linear-gradient(135deg, hsl(var(--vgm-h, 230), 70%, 58%), hsl(var(--vgm-h, 230), 72%, 47%));
box-shadow: 0 10px 30px hsla(var(--vgm-h, 230), 70%, 45%, 0.45);
}
.vgm-btn--primary:hover:not(:disabled) { transform: translateY(-2px); filter: brightness(1.07);
box-shadow: 0 16px 42px hsla(var(--vgm-h, 230), 75%, 50%, 0.6); }
.vgm-btn--primary:active:not(:disabled) { transform: translateY(0); }
/* close button spins on hover */
.vgm-close { transition: transform 0.25s ease, background 0.2s ease, border-color 0.2s ease; }
.vgm-close:hover { transform: rotate(90deg); }
/* episode rows — accent edge slides in on hover */
.vgm-ep { position: relative; transition: background 0.14s ease, padding-left 0.14s ease; }
.vgm-ep:hover { padding-left: 14px; }
.vgm-ep::before { content: ''; position: absolute; left: 0; top: 8px; bottom: 8px; width: 2px; border-radius: 2px;
background: hsl(var(--vgm-h, 230), 82%, 62%); opacity: 0; transition: opacity 0.14s ease; }
.vgm-ep:hover::before { opacity: 0.75; }
/* the watchlist offer — gentle breathing glow so it invites the tick */
.vgm-follow-row { animation: vgmFollowPulse 3.6s ease-in-out infinite; }
@keyframes vgmFollowPulse {
0%, 100% { box-shadow: 0 0 0 1px rgba(var(--accent-rgb, 88 101 242), 0.28), 0 0 16px -7px rgba(var(--accent-rgb, 88 101 242), 0.45); }
50% { box-shadow: 0 0 0 1px rgba(var(--accent-rgb, 88 101 242), 0.55), 0 0 28px -4px rgba(var(--accent-rgb, 88 101 242), 0.65); }
}
@media (prefers-reduced-motion: reduce) {
.vgm-hero, .vgm-hero::after, .vgm-follow-row, .vgm-overlay.vgm-open .vgm-poster,
.vgm-overlay.vgm-open .vgm-hero-content > * { animation: none; }
.vgm-modal { transition: opacity 0.2s ease; }
}
/* ══════════════════════════════════════════════════════════════════════════
Discover page — trending hero slideshow + lazy genre/decade rails (.vdsc-*)
══════════════════════════════════════════════════════════════════════════ */
.vdsc-page { padding: 0 0 60px; }
/* ── hero slideshow ───────────────────────────────────────────────────────── */
.vdsc-hero { position: relative; height: 420px; border-radius: 20px; overflow: hidden;
margin: 4px 0 26px; background: #0d0d12; isolation: isolate; }
.vdsc-hero.hidden { display: none; }
.vdsc-slides { position: absolute; inset: 0; }
.vdsc-slide { position: absolute; inset: 0; background-size: cover; background-position: center 18%;
opacity: 0; transition: opacity 1.1s ease; transform: scale(1.06); }
.vdsc-slide--on { opacity: 1; animation: vdscKen 12s ease-out forwards; }
@keyframes vdscKen { from { transform: scale(1.12); } to { transform: scale(1.0); } }
.vdsc-slide-scrim { position: absolute; inset: 0;
background: linear-gradient(90deg, #0b0b10 6%, rgba(11, 11, 16, 0.72) 38%, rgba(11, 11, 16, 0.15) 70%, transparent),
linear-gradient(0deg, #0b0b10 2%, transparent 42%),
radial-gradient(120% 130% at 0% 100%, hsla(var(--vgm-h, 230), 80%, 50%, 0.34), transparent 58%); }
.vdsc-hero-body { position: absolute; left: 40px; bottom: 34px; z-index: 2; max-width: 560px;
animation: vdscRise 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
@keyframes vdscRise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
.vdsc-hero-eyebrow { font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.07em;
color: hsl(var(--vgm-h, 230), 85%, 78%); margin-bottom: 8px; }
.vdsc-hero-title { font-size: 38px; font-weight: 900; letter-spacing: -0.03em; line-height: 1.04; margin: 0;
color: #fff; text-shadow: 0 3px 26px rgba(0, 0, 0, 0.7), 0 0 46px hsla(var(--vgm-h, 230), 80%, 55%, 0.3); }
.vdsc-hero-pills { display: flex; flex-wrap: wrap; gap: 8px; margin: 13px 0 0; }
.vdsc-hero-pill { font-size: 12px; font-weight: 700; padding: 4px 11px; border-radius: 999px;
background: rgba(255, 255, 255, 0.12); color: rgba(255, 255, 255, 0.9); backdrop-filter: blur(4px); }
.vdsc-hero-ov { font-size: 14px; line-height: 1.6; color: rgba(255, 255, 255, 0.82); margin: 14px 0 0;
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.vdsc-hero-cta { margin-top: 18px;
background: linear-gradient(135deg, hsl(var(--vgm-h, 230), 70%, 58%), hsl(var(--vgm-h, 230), 72%, 47%)) !important;
box-shadow: 0 12px 32px hsla(var(--vgm-h, 230), 70%, 45%, 0.5) !important; }
.vdsc-hero-cta:hover { transform: translateY(-2px); filter: brightness(1.07); }
.vdsc-dots { position: absolute; right: 26px; bottom: 26px; z-index: 3; display: flex; gap: 8px; }
.vdsc-dot { width: 9px; height: 9px; border-radius: 50%; border: none; cursor: pointer; padding: 0;
background: rgba(255, 255, 255, 0.32); transition: all 0.2s ease; }
.vdsc-dot--on { background: hsl(var(--vgm-h, 230), 85%, 65%); width: 26px; border-radius: 5px; }
/* ── Browse button (shared by the Browse panel + grid header) ─────────────── */
.vdsc-btn { padding: 10px 18px; border-radius: 10px; font-size: 13px; font-weight: 800; cursor: pointer;
border: 1px solid transparent; background: rgb(var(--accent-rgb, 88 101 242)); color: #fff;
box-shadow: 0 8px 22px rgba(var(--accent-rgb, 88 101 242), 0.34); transition: all 0.15s ease; }
.vdsc-btn:hover { filter: brightness(1.08); transform: translateY(-1px); }
.vdsc-btn--ghost { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.12);
color: rgba(255, 255, 255, 0.82); box-shadow: none; }
.vdsc-btn--ghost:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
/* ── shelves (lazy rails) ─────────────────────────────────────────────────── */
.vdsc-shelves.hidden, .vdsc-grid-wrap.hidden { display: none; }
.vdsc-shelf { margin: 0 0 30px; }
.vdsc-shelf-head { display: flex; align-items: center; justify-content: space-between; margin: 0 0 13px; }
.vdsc-shelf-title { font-size: 19px; font-weight: 800; letter-spacing: -0.01em; color: #fff; margin: 0; }
.vdsc-shelf-nav { display: flex; gap: 7px; }
.vdsc-arrow { width: 32px; height: 32px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, 0.12);
background: rgba(255, 255, 255, 0.05); color: rgba(255, 255, 255, 0.8); font-size: 18px; line-height: 1;
cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.15s ease; }
.vdsc-arrow:hover { background: rgba(var(--accent-rgb, 88 101 242), 0.85); border-color: transparent; color: #fff; }
.vdsc-rail { display: flex; gap: 16px; overflow-x: auto; overflow-y: hidden; padding: 6px 2px 12px;
scroll-snap-type: x proximity; scrollbar-width: thin; }
.vdsc-rail::-webkit-scrollbar { height: 8px; }
.vdsc-rail::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.14); border-radius: 4px; }
.vdsc-rail::-webkit-scrollbar-track { background: transparent; }
.vdsc-rail .vsr-card { flex: 0 0 162px; width: 162px; scroll-snap-align: start; }
/* skeleton shimmer while a rail loads */
.vdsc-skel { display: flex; gap: 16px; }
.vdsc-skel-card { flex: 0 0 162px; height: 280px; border-radius: 12px;
background: linear-gradient(100deg, rgba(255, 255, 255, 0.04) 30%, rgba(255, 255, 255, 0.09) 50%, rgba(255, 255, 255, 0.04) 70%);
background-size: 220% 100%; animation: vdscShimmer 1.4s ease-in-out infinite; }
@keyframes vdscShimmer { from { background-position: 180% 0; } to { background-position: -80% 0; } }
/* ── filter grid ──────────────────────────────────────────────────────────── */
.vdsc-grid { margin-top: 4px; }
.vdsc-more-wrap { display: flex; justify-content: center; margin-top: 26px; }
.vdsc-more { padding: 12px 30px; }
.vdsc-more.hidden { display: none; }
@media (max-width: 720px) {
.vdsc-hero { height: 340px; }
.vdsc-hero-body { left: 22px; bottom: 22px; right: 22px; }
.vdsc-hero-title { font-size: 27px; }
.vdsc-rail .vsr-card, .vdsc-skel-card { flex-basis: 132px; width: 132px; }
}
@media (prefers-reduced-motion: reduce) {
.vdsc-slide, .vdsc-slide--on { animation: none; transition: opacity 0.4s ease; transform: none; }
.vdsc-hero-body { animation: none; }
.vdsc-skel-card { animation: none; }
}
/* ── Discover v2: ambient glow + see-all + grid head + hide-owned + polish ─── */
.vdsc-page { position: relative; }
.vdsc-hero, .vdsc-browse, .vdsc-shelves, .vdsc-grid-wrap { position: relative; z-index: 1; }
/* a faint page-top color bleed that follows the current hero slide's hue */
.vdsc-amb { position: absolute; top: -40px; left: 50%; transform: translateX(-50%); z-index: 0;
width: 130%; height: 580px; pointer-events: none; opacity: 0.5; transition: opacity 0.7s ease;
background: radial-gradient(58% 80% at 50% 0%, hsla(var(--vdsc-amb, 230), 82%, 55%, 0.22), transparent 70%); }
/* "See all" → opens the rail as a paged grid */
.vdsc-seeall { font-size: 12.5px; font-weight: 700; color: rgba(255, 255, 255, 0.5); background: none;
border: none; cursor: pointer; padding: 4px 9px; border-radius: 8px; margin-right: 4px;
transition: color 0.15s ease, background 0.15s ease; }
.vdsc-seeall:hover { color: #fff; background: rgba(255, 255, 255, 0.07); }
/* grid (category) header — back button + title */
.vdsc-grid-head { display: flex; align-items: center; gap: 16px; margin: 2px 0 22px; }
.vdsc-grid-title { font-size: 23px; font-weight: 800; letter-spacing: -0.01em; color: #fff; margin: 0; }
/* hide-owned toggle (sits at the far right of the filter bar) */
.vdsc-toggle { display: inline-flex; align-items: center; gap: 7px; margin-left: auto;
font-size: 13px; font-weight: 600; color: rgba(255, 255, 255, 0.7); cursor: pointer; user-select: none; }
.vdsc-toggle input { accent-color: rgb(var(--accent-rgb, 88 101 242)); width: 16px; height: 16px; cursor: pointer; }
.vdsc-hide-owned .vsr-card--owned { display: none; }
/* rails: a gentle fade-in when filled + per-title hue on hover */
.vdsc-shelf--in .vdsc-rail { animation: vdscFade 0.45s ease both; }
@keyframes vdscFade { from { opacity: 0.35; } to { opacity: 1; } }
.vdsc-rail .vsr-card, .vdsc-grid .vsr-card { transition: transform 0.2s ease, box-shadow 0.2s ease; }
.vdsc-rail .vsr-card:hover, .vdsc-grid .vsr-card:hover {
box-shadow: 0 14px 36px rgba(0, 0, 0, 0.5), 0 0 26px -6px hsla(var(--vgm-h, 230), 80%, 58%, 0.5); }
@media (prefers-reduced-motion: reduce) {
.vdsc-shelf--in .vdsc-rail { animation: none; }
.vdsc-amb { transition: none; }
}
/* ── Discover Browse panel — segmented controls + genre/era chips ──────────── */
.vdsc-browse { position: relative; z-index: 1; margin: 6px 0 28px; padding: 16px 18px 18px;
border-radius: 16px; border: 1px solid rgba(255, 255, 255, 0.08);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02));
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 18px 50px -30px rgba(var(--accent-rgb, 88 101 242), 0.5); }
.vdsc-browse-top { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
/* segments are now just a row of the same buttons (no sliding pill) */
.vdsc-seg { display: inline-flex; gap: 6px; }
.vdsc-seg::before { display: none; }
/* chip rows (genres, providers, eras) — horizontally scrollable */
.vdsc-chips { display: flex; gap: 8px; overflow-x: auto; padding: 4px 1px 7px; margin-top: 13px;
scrollbar-width: thin; }
.vdsc-chips::-webkit-scrollbar { height: 6px; }
.vdsc-chips::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.13); border-radius: 3px; }
.vdsc-chips--era { margin-top: 0; }
/* Filter buttons (chips + segment buttons) — rounded-rect, each tinted from a
vibey palette (mirrors the music album-detail action buttons); active = filled. */
.vdsc-chip, .vdsc-seg-btn { flex: 0 0 auto; padding: 8px 15px; border-radius: 9px; cursor: pointer;
white-space: nowrap; font-size: 12.5px; font-weight: 700; letter-spacing: -0.01em;
color: rgba(var(--c, 200, 205, 230), 0.64);
background: rgba(var(--c, 200, 205, 230), 0.07);
border: 1px solid rgba(var(--c, 200, 205, 230), 0.18);
transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease, box-shadow 0.2s ease, transform 0.18s cubic-bezier(0.34, 1.4, 0.5, 1); }
.vdsc-chip:hover, .vdsc-seg-btn:hover { color: rgba(var(--c, 200, 205, 230), 0.96);
background: rgba(var(--c, 200, 205, 230), 0.14); border-color: rgba(var(--c, 200, 205, 230), 0.4); transform: translateY(-1px); }
.vdsc-chip--on, .vdsc-seg-btn--on { color: #fff; border-color: transparent; transform: translateY(-1px);
background: linear-gradient(135deg, rgba(var(--c, 120, 130, 240), 0.96), rgba(var(--c, 120, 130, 240), 0.6));
box-shadow: 0 9px 22px -9px rgba(var(--c, 120, 130, 240), 0.9),
0 0 0 1px rgba(var(--c, 120, 130, 240), 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.25); }
/* Colours carry meaning, not position:
- segments (Movies/TV, sort) → the app accent (they're modes, not categories)
- genre chips → a thematic colour per genre (set inline by JS)
- provider chips → the service's brand colour (set inline in markup)
- era chips → a single warm amber; reset chips ('All/Any …') → neutral
so each --c is provided where it's meaningful and falls back to neutral here. */
.vdsc-seg-btn { --c: var(--accent-rgb, 29, 185, 84); }
.vdsc-chip--reset { --c: 148, 163, 184; } /* All genres / Any service / Any era */
.vdsc-chips--era .vdsc-chip { --c: 245, 158, 11; }
.vdsc-chips--era .vdsc-chip--reset { --c: 148, 163, 184; }
.vdsc-browse-bottom { display: flex; align-items: center; gap: 16px; margin-top: 12px; }
.vdsc-browse-bottom .vdsc-chips { flex: 1; min-width: 0; margin-top: 0; }
.vdsc-browse-go { flex: 0 0 auto; padding: 11px 22px;
box-shadow: 0 10px 26px -8px rgba(var(--accent-rgb, 88 101 242), 0.7); }
.vdsc-browse-go:hover { filter: brightness(1.08); transform: translateY(-1px); }
.vdsc-browse .vdsc-toggle { margin-left: auto; }
@media (max-width: 720px) {
.vdsc-browse-bottom { flex-direction: column; align-items: stretch; }
.vdsc-browse-go { width: 100%; }
}
/* no-TMDB empty state */
.vdsc-empty { text-align: center; padding: 86px 24px; }
.vdsc-empty.hidden { display: none; }
.vdsc-empty-ic { font-size: 46px; margin-bottom: 14px; opacity: 0.85; }
.vdsc-empty-title { font-size: 21px; font-weight: 800; color: #fff; margin-bottom: 9px; }
.vdsc-empty-sub { font-size: 14px; line-height: 1.6; color: rgba(255, 255, 255, 0.58); max-width: 440px; margin: 0 auto; }
.vdsc-empty-sub strong { color: rgba(255, 255, 255, 0.82); font-weight: 700; }
@media (prefers-reduced-motion: reduce) {
.vdsc-seg::before { transition: none; }
.vdsc-chip, .vdsc-chip:hover, .vdsc-chip--on { transition: color 0.15s ease, background 0.15s ease; transform: none; }
}
/* ── hero actions: View CTA + Trailer button ──────────────────────────────── */
.vdsc-hero-actions { display: flex; align-items: center; gap: 12px; margin-top: 18px; flex-wrap: wrap; }
.vdsc-hero-actions .vdsc-hero-cta { margin-top: 0; }
.vdsc-hero-trailer { display: inline-flex; align-items: center; gap: 8px; padding: 11px 19px; border-radius: 12px;
font-size: 13px; font-weight: 800; cursor: pointer; color: #fff; backdrop-filter: blur(6px);
background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.22);
transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease; }
.vdsc-hero-trailer:hover { background: rgba(255, 255, 255, 0.18); border-color: rgba(255, 255, 255, 0.42); transform: translateY(-1px); }
.vdsc-tr-ic { font-size: 10px; }
/* "More like…" rails get a gradient title as a personalized cue */
.vdsc-shelf--ml .vdsc-shelf-title { color: #fff;
background: linear-gradient(90deg, #fff 35%, hsl(265 85% 78%) 100%);
-webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
/* ── trailer lightbox (in-app YouTube embed) ──────────────────────────────── */
.vdsc-tr-overlay { position: fixed; inset: 0; z-index: 9200; display: flex; align-items: center; justify-content: center;
padding: 24px; background: rgba(3, 3, 6, 0.86); backdrop-filter: blur(10px); opacity: 0; transition: opacity 0.2s ease; }
.vdsc-tr-overlay.vdsc-tr-open { opacity: 1; }
.vdsc-tr-box { position: relative; width: min(960px, 100%); }
.vdsc-tr-close { position: absolute; top: -46px; right: 0; width: 38px; height: 38px; border-radius: 50%;
border: 1px solid rgba(255, 255, 255, 0.2); background: rgba(0, 0, 0, 0.5); color: #fff; font-size: 22px; line-height: 1;
cursor: pointer; display: flex; align-items: center; justify-content: center;
transition: background 0.15s ease, transform 0.25s ease; }
.vdsc-tr-close:hover { background: rgba(0, 0, 0, 0.82); transform: rotate(90deg); }
.vdsc-tr-frame { position: relative; aspect-ratio: 16 / 9; border-radius: 14px; overflow: hidden; background: #000;
box-shadow: 0 40px 120px rgba(0, 0, 0, 0.7); display: flex; align-items: center; justify-content: center;
transform: scale(0.97); transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1); }
.vdsc-tr-open .vdsc-tr-frame { transform: none; }
.vdsc-tr-frame iframe { width: 100%; height: 100%; border: 0; }
.vdsc-tr-none { color: rgba(255, 255, 255, 0.6); font-size: 15px; font-weight: 600; }
.vdsc-tr-title { margin-top: 14px; text-align: center; font-size: 15px; font-weight: 700; color: rgba(255, 255, 255, 0.85); }
@media (prefers-reduced-motion: reduce) { .vdsc-tr-frame { transition: none; } }
/* infinite-scroll sentinel (invisible trigger near the grid bottom) */
.vdsc-sentinel { height: 1px; width: 100%; }
/* keyboard focus rings (a11y) */
.vdsc-chip:focus-visible, .vdsc-seg-btn:focus-visible, .vdsc-arrow:focus-visible, .vdsc-seeall:focus-visible,
.vdsc-btn:focus-visible, .vdsc-hero-trailer:focus-visible, .vdsc-dot:focus-visible, .vdsc-toggle:focus-within,
.vdsc-page .vsr-card:focus-visible {
outline: 2px solid rgba(var(--accent-rgb, 88 101 242), 0.9); outline-offset: 2px; }