.playerWrap { /* Fixed + inset so it fills the actual viewport regardless of .mainContent's own padding (which used to add to 100vh and push the whole page taller than the screen, causing an outer scrollbar). Also covers the sidebar while playing, like most video players' theater mode - "Quitter" is how you get back to it. */ position: fixed; inset: 0; z-index: 20; background: #000; } .playerWrap video { width: 100%; height: 100%; object-fit: contain; } /* Two stacked rows, both part of the same top gradient overlay: the action bar (title/members/next/settings/leave) and, below it, the presence avatars - see .presenceOverlay in styles/presence.css. Stacking them in normal flow inside one column means the avatar row always ends up right after the action bar regardless of how tall that bar is (it wraps to two lines on narrow screens), instead of guessing a fixed pixel offset for a second absolutely-positioned block. */ .topOverlay { position: absolute; top: 0; left: 0; right: 0; display: flex; flex-direction: column; gap: 10px; padding: 12px 16px; background: linear-gradient(to bottom, rgba(0,0,0,.7), transparent); z-index: 5; } .actionBar { display: flex; align-items: center; gap: 16px; color: white; font-size: 13px; flex-wrap: wrap; } .actionBar .itemTitle { font-weight: 600; } .actionBar .members { color: var(--muted); flex: 1; } /* Settings: a small gear icon in the action bar, not a permanently-visible block of dropdowns - opens a compact popup on click. */ .settingsWrap { position: relative; } .iconBtn { background: none; padding: 4px 8px; font-size: 16px; line-height: 1; border-radius: 6px; } .iconBtn:hover { background: rgba(255, 255, 255, .12); } .settingsPanel { position: absolute; top: 100%; right: 0; margin-top: 6px; display: flex; flex-direction: column; gap: 10px; background: var(--bg-header); padding: 12px; border-radius: 10px; font-size: 12px; min-width: 180px; box-shadow: 0 8px 24px rgba(0, 0, 0, .4); z-index: 5; } .settingsPanel label { color: var(--muted); margin-bottom: 0; display: flex; flex-direction: column; gap: 4px; } .settingsPanel select { background: var(--panel); color: var(--text); border: 1px solid #3a3a3a; border-radius: 6px; padding: 4px 6px; font-size: 12px; } .loadingNotice { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: var(--muted); font-size: 14px; margin: 0; } .playerError { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 360px; text-align: center; background: rgba(0, 0, 0, .75); padding: 20px; border-radius: 10px; } .playerError p { color: var(--danger); font-size: 14px; margin: 0 0 10px; } .followerNotice { /* margin:0 overrides the

's default UA margin - for an absolutely positioned box, "bottom" places the MARGIN edge, so the default ~1em bottom margin was quietly pushing the pill 13px higher than its declared bottom:24px ever suggested. Harmless on its own, but it made .pauseRequestBanner's bottom offset above it read as barely any gap at all once that one was measured against this element's real position. */ position: absolute; bottom: 24px; left: 50%; transform: translateX(-50%); margin: 0; background: rgba(0,0,0,.6); padding: 8px 16px; border-radius: 20px; font-size: 13px; color: var(--muted); } /* Only the viewer's own avatar gets this, and only while not host - see renderMembers() in Player.ts. The host has direct controls, so their own circle is presence-only. */ .avatarClickable { cursor: pointer; transition: opacity .15s, transform .15s; } .avatarClickable:hover { opacity: 1; transform: scale(1.08); } /* Shown to EVERY member (including the host and the requester themselves) on the matching person's circle while their "pauseRequested" is active - see onPauseRequested() in Player.ts. Orange border + a small pause-icon badge, not just a generic pulse, so it reads unambiguously even to someone glancing at the video rather than the banner text. */ .avatarPauseRequested { opacity: 1; border-color: #ff9800; } .avatarPauseBadge { position: absolute; bottom: -4px; right: -4px; width: 16px; height: 16px; border-radius: 50%; background: #ff9800; border: 1px solid rgba(0, 0, 0, .5); display: none; align-items: center; justify-content: center; } .avatarPauseRequested .avatarPauseBadge { display: flex; } .pauseRequestBanner { /* Bottom-anchored, clear of the presence row now living up in .topOverlay - stacked above .followerNotice (bottom: 24px) rather than on top of it, since a non-host sees both at once. */ position: absolute; bottom: 72px; left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, .75); color: white; padding: 8px 16px; border-radius: 20px; font-size: 13px; z-index: 6; }