/* OpenStudio — composed-stage visuals for the guest "program" mirror.
   These rules mirror the host studio's inline stage CSS (studio.html, `.o3 .*`),
   scoped here to `.stagebox` so the guest renders the program identically.
   Keep in sync with studio.html if the host stage look changes. */

.stagebox { position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; container-type: size; }
/* Letterbox to a strict --arn ratio (set by renderProgram) — largest box fitting both the
   box's width (100cqw) and its height at that ratio (100cqh*arn). Mirror of studio.html. */
.stagebox .stage { position: relative; border-radius: 14px; overflow: hidden; aspect-ratio: 16/9; width: min(100cqw, calc(100cqh * var(--arn, 1.7778))); height: auto; max-width: 100%; max-height: 100%; background: #000; display: grid; gap: var(--tilegap, 6px); padding: var(--tilegap, 6px); }

.stagebox .feed { position: relative; border-radius: var(--tilerad, 10px); overflow: hidden; display: flex; align-items: center; justify-content: center; min-width: 0; }
.stagebox .feed .fi { font-weight: 500; color: rgba(255,255,255,.82); letter-spacing: .5px; }
.stagebox .feed .avimg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* camera-off tile: centred medallion (initials or photo) over a per-style backdrop.
   Shared with studio.js/studio.html — keep the .ph-* looks in sync. */
.stagebox .phdisc { position: relative; z-index: 1; height: 46%; aspect-ratio: 1; max-width: 64%; border-radius: 50%; display: flex; align-items: center; justify-content: center; overflow: hidden; container-type: size; }
.stagebox .phdisc .phimg { width: 100%; height: 100%; object-fit: cover; }
.stagebox .phblur { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: blur(18px) saturate(1.25) brightness(.5); transform: scale(1.18); }
/* Initials scale with the medallion (cqmin of .phdisc) so they stay large and legible
   as tiles shrink with more guests on stage. */
.stagebox .phini { font-weight: 600; letter-spacing: .5px; line-height: 1; color: rgba(255,255,255,.9); font-size: 52cqmin; }
.stagebox .phini.dark { color: rgba(12,14,18,.92); text-shadow: none; }
.stagebox .feed.ph-themed { background: radial-gradient(120% 120% at 50% 32%, rgba(var(--lime-rgb),.14), #0B0C0E 68%); }
.stagebox .ph-themed .phdisc { background: rgba(var(--lime-rgb),.07); box-shadow: 0 0 0 2px rgba(var(--lime-rgb),.5), inset 0 0 0 1px rgba(var(--lime-rgb),.25), 0 10px 34px rgba(0,0,0,.5); backdrop-filter: blur(3px); }
.stagebox .ph-themed .phini { color: var(--lime); }
.stagebox .ph-color .phdisc { background: rgba(255,255,255,.12); box-shadow: inset 0 0 0 1px rgba(255,255,255,.18), 0 8px 24px rgba(0,0,0,.38); }
.stagebox .feed.ph-aurora { background: linear-gradient(125deg, #4b2e83, #1f6f8b, #2f8f6b, #7a3d8f); background-size: 300% 300%; animation: phaurora 17s ease infinite; }
.stagebox .ph-aurora .phdisc { background: rgba(255,255,255,.15); box-shadow: inset 0 0 0 1px rgba(255,255,255,.32), 0 10px 30px rgba(0,0,0,.4); backdrop-filter: blur(8px); }
.stagebox .feed.ph-mono { background: radial-gradient(125% 135% at 50% 16%, #20242c, #0a0b0d 72%); }
.stagebox .ph-mono .phdisc { background: radial-gradient(circle at 50% 34%, #2b313c, #12151b); box-shadow: 0 0 44px 6px rgba(var(--lime-rgb),.12), 0 12px 30px rgba(0,0,0,.6); }
.stagebox .ph-mono .phini { text-shadow: 0 0 18px rgba(var(--lime-rgb),.4); }
@keyframes phaurora { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
@media (prefers-reduced-motion: reduce) { .stagebox .feed.ph-aurora { animation: none; } }
/* active speaker: a soft lime aura that gently breathes */
/* Speaking ring/glow drawn as an overlay ABOVE the camera video + avatar image so
   it's never hidden; sits under the name plate/badges (lifted to z-index 2/3). It
   lives on every .feed so its opacity can fade IN when speaking starts and OUT when
   it stops; spkpulse animates the glow while active.
   The two fades are deliberately lopsided. IN is fast (.12s): it's part of how late the
   ring *feels*, and anything slower reads as lag on top of detection. OUT is slow (.85s)
   and starts almost immediately (OSSpeak holds only 150ms), which is what makes a pause
   between words merely DIM the ring — ~250ms of silence takes it to about 90% before the
   voice returns and snaps it back — while a real stop still reads as letting go at once.
   A short hold + long fade does that; a long hold + short fade can't (it sits at full
   brightness, then drops).
   The pulse lives here on the base, not on .spk, and is only PAUSED when idle. On .spk it
   would restart from 0% at every toggle — invisible when toggles were rare, a visible jump
   in the glow now that they're routine. Pausing keeps the animation's phase, so it picks up
   where it left off, and a paused animation costs nothing on the other 19 tiles.
   Keep in sync with studio.html. */
.stagebox .feed::after { content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: 1; box-shadow: inset 0 0 0 2.5px var(--lime), inset 0 0 18px 2px rgba(var(--lime-rgb),.4); opacity: 0; transition: opacity .85s ease; animation: spkpulse 1.3s ease-in-out infinite; animation-play-state: paused; }
.stagebox .feed.spk { z-index: 1; }
.stagebox .feed.spk::after { opacity: 1; transition-duration: .12s; animation-play-state: running; }
@media (prefers-reduced-motion: reduce) { .stagebox .feed::after { animation: none; transition: none; } }
@keyframes spkpulse {
  0%, 100% { box-shadow: inset 0 0 0 2.5px var(--lime), inset 0 0 12px 1px rgba(var(--lime-rgb),.30); }
  50%      { box-shadow: inset 0 0 0 3px var(--lime),   inset 0 0 30px 5px rgba(var(--lime-rgb),.70); }
}
/* muted badge */
.stagebox .feed .mutebadge { position: absolute; right: 8px; top: 8px; width: 24px; height: 24px; border-radius: 50%; background: var(--live); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 13px; box-shadow: 0 2px 8px rgba(0,0,0,.4); z-index: 3; }
.stagebox .feed .hidmark { position: absolute; left: 8px; top: 8px; width: 24px; height: 24px; border-radius: 50%; background: rgba(10,11,13,.6); backdrop-filter: blur(6px); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 13px; box-shadow: 0 2px 8px rgba(0,0,0,.4); z-index: 3; }
/* host hid this camera/avatar */
.stagebox .feed .hiddenph { display: flex; flex-direction: column; align-items: center; gap: 6px; color: var(--mute); font-size: 11px; }
.stagebox .feed .hiddenph i { font-size: 26px; }
.stagebox .feed video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.stagebox .ph { border: 1.5px dashed var(--ln2); background: var(--c2); flex-direction: column; gap: 6px; color: var(--mute); font-size: 11px; }
.stagebox .ph i { font-size: 24px; }

.stagebox .np { position: absolute; left: 8px; bottom: 8px; z-index: 2; display: flex; align-items: center; gap: 6px; background: rgba(10,11,13,.5); backdrop-filter: blur(8px); padding: 4px 9px; border-radius: 8px; font-size: 11px; font-weight: 500; }
.stagebox .np .mi { font-size: 13px; color: var(--lime); }
.stagebox .np .mi.off { color: var(--live); }
.stagebox .np { flex-wrap: wrap; }
.stagebox .np .npt { flex-basis: 100%; font-weight: 400; font-size: 9.5px; color: var(--lime); margin-left: 19px; margin-top: 1px; }
.stagebox .lower { position: absolute; left: 12px; bottom: 34px; z-index: 2; display: flex; flex-direction: column; padding: 7px 13px 7px 12px; background: rgba(10,11,13,.62); backdrop-filter: blur(8px); border-left: 3px solid var(--lime); border-radius: 0 9px 9px 0; }
.stagebox .lower .ln { font-family: 'Space Grotesk', sans-serif; font-weight: 500; font-size: 14px; display: inline-flex; align-items: center; gap: 7px; }
.stagebox .lower .lr { font-size: 10.5px; color: var(--lime); }
/* --- active-speaker equalizer (shown next to the name only while speaking) --- */
.stagebox .spkbars { display: none; align-items: flex-end; gap: 2px; height: 11px; flex: none; }
.stagebox .lower .spkbars { height: 13px; }
.stagebox .feed.spk .spkbars { display: inline-flex; }
.stagebox .spkbars i { width: 2.5px; height: 100%; background: var(--lime); border-radius: 2px; transform-origin: bottom; filter: drop-shadow(0 0 3px rgba(var(--lime-rgb),.55)); animation: spkbar .9s ease-in-out infinite; }
.stagebox .spkbars i:nth-child(1) { animation-delay: 0s; }
.stagebox .spkbars i:nth-child(2) { animation-delay: .18s; }
.stagebox .spkbars i:nth-child(3) { animation-delay: .36s; }
.stagebox .spkbars i:nth-child(4) { animation-delay: .12s; }
@keyframes spkbar { 0%, 100% { transform: scaleY(.34); } 50% { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) { .stagebox .spkbars i { animation: none; transform: scaleY(.7); } }

.stagebox .wmk { position: absolute; right: 11px; top: 10px; display: flex; align-items: center; gap: 5px; font-size: 10.5px; color: rgba(255,255,255,.68); background: rgba(10,11,13,.4); padding: 3px 9px; border-radius: 7px; }
.stagebox .wmk i { color: var(--lime); }
/* Ticker bar (template-driven: scroll / static / tape / breaking) */
.stagebox .tick { --tkbg: var(--lime); --tktx: var(--limd); --tkacc: var(--lime-rgb); --tkh: 32px; --tkfs: 11.5px; position: absolute; left: 6px; right: 6px; bottom: 6px; height: var(--tkh); background: var(--tkbg); color: var(--tktx); font-family: var(--tkfont, inherit); border-radius: var(--tkradius, 8px); overflow: hidden; display: flex; align-items: center; box-shadow: 0 4px 16px rgba(0,0,0,.35); }
.stagebox .tick.tktop { top: 6px; bottom: auto; }
.stagebox .tick .tk { position: relative; z-index: 1; flex: none; align-self: stretch; margin: 3px; display: flex; align-items: center; background: var(--tklblbg, rgba(0,0,0,.42)); color: var(--tklbl, #fff); border-radius: max(0px, calc(var(--tkradius, 8px) - 3px)); padding: 0 .95em; font-size: calc(var(--tkfs) * .82); font-weight: 700; letter-spacing: .7px; text-transform: uppercase; }
.stagebox .tick .tmwin { flex: 1; min-width: 0; align-self: stretch; overflow: hidden; position: relative; display: flex; align-items: center; }
.stagebox .tick .tmarq { display: flex; align-items: center; flex: none; width: max-content; white-space: nowrap; will-change: left, transform; animation-timing-function: linear; animation-iteration-count: infinite; }
.stagebox .tick.gap .tmarq { position: absolute; top: 0; bottom: 0; left: 0; animation: tkgap var(--tkdur, 12s) linear infinite; }
/* fill = two groups, each tiled with enough message copies to overflow the bar
   (see fitFillTickers) so the message repeats back-to-back and loops seamlessly */
.stagebox .tick.fill .tkgrp { flex: 0 0 auto; min-width: 100%; display: flex; align-items: center; white-space: nowrap; will-change: transform; animation: tkfill var(--tkdur, 12s) linear infinite; }
.stagebox .tick.fill .tkseg { margin-right: 52px; }
/* Tape uses its bullets for spacing (uniform 15px), so drop the 52px seam gap for
   tape+fill at any message count. Keep in sync with studio.html. */
.stagebox .tick.tape.fill .tkseg { margin-right: 0; }
.stagebox .tick .tkseg { display: flex; align-items: center; flex: none; }
.stagebox .tick .tkm { font-size: var(--tkfs); font-weight: 500; }
.stagebox .tick.scroll .tkm + .tkm { margin-left: 52px; }
.stagebox .tick .tksep { opacity: .55; margin: 0 var(--tksepgap, 15px); font-weight: 700; }
@keyframes tkgap { from { left: 100%; transform: translateX(0); } to { left: 0; transform: translateX(-100%); } }
@keyframes tkfill { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.stagebox .tick .tkfade { position: relative; flex: 1; min-width: 0; height: 100%; }
.stagebox .tick .tkf { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 0 14px; font-size: var(--tkfs); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: 0; }
/* Breaking-news presentation: a polished effect on the label chip whose colour
   follows the ticker's own accent (--tkacc). The chip sits on a dark "glass" base
   so the accent glow, text and dot stay legible on any bar colour. Optionally the
   whole bar gets a matching accent glow (private-message look). */
.stagebox .tick.breaking .tk { background: var(--tklblbg, rgba(8,10,14,.55)); }
/* Glow — a soft accent breathing pulse with a glowing halo. */
.stagebox .tick.bfx-glow .tk { box-shadow: 0 0 0 1px rgba(var(--tkacc), .5) inset; animation: bfxGlow 2s ease-in-out infinite; }
@keyframes bfxGlow {
  0%, 100% { box-shadow: 0 0 0 1px rgba(var(--tkacc), .35) inset, 0 0 4px rgba(var(--tkacc), .15); text-shadow: 0 0 4px rgba(var(--tkacc), .25); }
  50% { box-shadow: 0 0 0 1px rgba(var(--tkacc), .9) inset, 0 0 16px rgba(var(--tkacc), .6); text-shadow: 0 0 11px rgba(var(--tkacc), .8); }
}
/* Shimmer — an accent highlight streak sweeps across the label. */
.stagebox .tick.bfx-sweep .tk { position: relative; overflow: hidden; box-shadow: 0 0 0 1px rgba(var(--tkacc), .5) inset; }
.stagebox .tick.bfx-sweep .tk::after { content: ''; position: absolute; top: 0; bottom: 0; left: -60%; width: 50%; background: linear-gradient(100deg, transparent, rgba(var(--tkacc), .75), transparent); transform: skewX(-18deg); animation: bfxSweep 2.6s cubic-bezier(.5,0,.5,1) infinite; }
@keyframes bfxSweep { 0% { left: -60%; } 42%, 100% { left: 150%; } }
/* Glass — a frosted label on a dark chip with a bright accent edge and a slow light glint. */
.stagebox .tick.bfx-glass .tk { background: linear-gradient(180deg, rgba(255,255,255,.14), rgba(255,255,255,.02)), rgba(6,8,12,.5); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); box-shadow: 0 0 0 1px rgba(var(--tkacc), .75) inset, 0 1px 0 rgba(255,255,255,.2) inset; overflow: hidden; }
.stagebox .tick.bfx-glass .tk::after { content: ''; position: absolute; top: 0; bottom: 0; left: -70%; width: 45%; background: linear-gradient(100deg, transparent, rgba(255,255,255,.4), transparent); transform: skewX(-18deg); animation: bfxGlassShine 5s ease-in-out infinite; }
@keyframes bfxGlassShine { 0%, 100% { left: -70%; } 22%, 78% { left: 130%; } }
/* Live dot — the label holds steady while a pulsing accent dot draws the eye. */
.stagebox .tick.bfx-dot .tk { box-shadow: 0 0 0 1px rgba(var(--tkacc), .4) inset; }
.stagebox .tick.bfx-dot .tk::before { content: ''; flex: none; width: .62em; height: .62em; border-radius: 50%; margin-right: .55em; background: rgb(var(--tkacc)); animation: bfxDot 1.6s ease-out infinite; }
@keyframes bfxDot { 0% { box-shadow: 0 0 0 0 rgba(var(--tkacc), .7); } 70%, 100% { box-shadow: 0 0 0 .62em rgba(var(--tkacc), 0); } }
/* Whole-bar scope — a polished glassy accent panel echoing the guest private-message
   popup: the bar keeps its accent fill, dressed with an accent-tint corner sheen and a
   glassy top highlight, a bright accent border, layered drop-shadow + accent ring +
   outer glow, backdrop blur, and a soft accent pulse. */
.stagebox .tick.bfx-bar { background: linear-gradient(180deg, rgba(255,255,255,.14), rgba(255,255,255,0) 46%), linear-gradient(135deg, rgba(var(--tkacc), .34), rgba(var(--tkacc), 0) 62%), var(--tkbg); border: 1px solid rgba(var(--tkacc), .55); box-shadow: 0 14px 40px rgba(0,0,0,.5), 0 0 0 1px rgba(var(--tkacc), .22), 0 0 26px rgba(var(--tkacc), .4), inset 0 1px 0 rgba(255,255,255,.18); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); animation: bfxBar 2.8s ease-in-out infinite; }
@keyframes bfxBar {
  0%, 100% { box-shadow: 0 12px 34px rgba(0,0,0,.46), 0 0 0 1px rgba(var(--tkacc), .18), 0 0 16px rgba(var(--tkacc), .3), inset 0 1px 0 rgba(255,255,255,.16); }
  50% { box-shadow: 0 16px 44px rgba(0,0,0,.52), 0 0 0 1px rgba(var(--tkacc), .3), 0 0 34px rgba(var(--tkacc), .62), inset 0 1px 0 rgba(255,255,255,.2); }
}
/* Backdrop blur — frosts whatever shows through a low-opacity bar (private-message look). */
.stagebox .tick.tkblur { backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }
.stagebox .tick.tick-enter { animation: tickIn .5s cubic-bezier(.22,1,.36,1); }
.stagebox .tick.tktop.tick-enter { animation: tickInTop .5s cubic-bezier(.22,1,.36,1); }
/* keep the bar-glow pulse alive alongside the one-shot entrance */
.stagebox .tick.bfx-bar.tick-enter { animation: tickIn .5s cubic-bezier(.22,1,.36,1), bfxBar 2.8s ease-in-out infinite; }
.stagebox .tick.bfx-bar.tktop.tick-enter { animation: tickInTop .5s cubic-bezier(.22,1,.36,1), bfxBar 2.8s ease-in-out infinite; }
@keyframes tickIn { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@keyframes tickInTop { from { opacity: 0; transform: translateY(-16px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .stagebox .tick .tmarq, .stagebox .tick.fill .tkgrp { animation: none; } .stagebox .tick.bfx-glow .tk, .stagebox .tick.bfx-sweep .tk::after, .stagebox .tick.bfx-glass .tk::after, .stagebox .tick.bfx-dot .tk::before, .stagebox .tick.bfx-bar { animation: none; } .stagebox .tick.tick-enter, .stagebox .tick.tktop.tick-enter { animation: none; } }

.stagebox .lwrap { position: absolute; inset: 0; display: grid; gap: var(--tilegap, 6px); }
/* When a ticker is on stage (and nothing is screen-sharing), the tile grid shrinks
   so the bar never covers a camera/avatar. The FLIP in morphStage animates it. */
.stagebox .stage.tk-reflow .lwrap { bottom: var(--tkinset, 44px); }
.stagebox .stage.tk-reflow-top .lwrap { top: var(--tkinset, 44px); }
.stagebox .lwrap .feed, .stagebox .pipcam .feed, .stagebox .piprow .feed { width: 100%; height: 100%; }
.stagebox .slot { display: grid; min-width: 0; min-height: 0; border-radius: var(--tilerad, 10px); }
.stagebox .pipcam { position: absolute; right: 3.5%; bottom: 11%; left: auto; top: auto; width: 25%; aspect-ratio: 16/9; display: grid; border-radius: var(--tilerad, 10px); overflow: hidden; }
.stagebox .pipcam.chromed { box-shadow: none; }
.stagebox .pipcam.bc { left: 50%; right: auto; bottom: 9%; transform: translateX(-50%); }
/* during a layout morph, let inverted feeds glide in from outside their slot */
.stagebox .stage.morphing .pipcam, .stagebox .stage.morphing .cslot { overflow: visible; }
.stagebox .pipcam.tl { left: 3.5%; right: auto; top: 7%; bottom: auto; }
.stagebox .pipcam.tr { right: 3.5%; left: auto; top: 7%; bottom: auto; }
/* Floating PiP: a row of guest cameras overlaid over the top of the fullscreen screenshare. */
.stagebox .piprow { position: absolute; left: 0; right: 0; top: 0; height: 22%; display: flex; justify-content: center; gap: 6px; z-index: 2; }
.stagebox .pipcell { border-radius: var(--tilerad, 10px); overflow: hidden; }
.stagebox .pipcell.chromed { box-shadow: none; }

.stagebox .stage.fit { background: radial-gradient(120% 130% at 50% 0%, #1a1f27, #0b0c0e); }
.stagebox .stage.fit .slot { place-items: center; }
.stagebox .stage.fit .slot .feed { height: 100%; width: auto; max-width: 100%; aspect-ratio: 16/9; }
.stagebox .stage.fit .pipcam .feed { width: 100%; height: 100%; }

.stagebox .cslot { position: absolute; border-radius: var(--tilerad, 10px); overflow: hidden; display: grid; }
.stagebox .cslot .feed { width: 100%; height: 100%; }
.stagebox .cslot.fitslot { place-items: center; background: #0b0c0e; }
.stagebox .cslot.fitslot .feed { height: 100%; width: auto; max-width: 100%; aspect-ratio: 16/9; }

/* Camera/person-tile SHAPES (mirror of studio.html; person tiles are data-vid here). Screens
   stay rectangular. Non-rounded shapes reshape grid tiles to square in app.js (tilesSquare). */
.stagebox [data-shape=square] .feed[data-vid] { border-radius: 0; }
.stagebox [data-shape=circle] .feed[data-vid] { border-radius: 0; clip-path: circle(closest-side); }
.stagebox [data-shape=squircle] .feed[data-vid] { border-radius: 0; clip-path: polygon(100% 50%,99.1% 75.4%,96.5% 85.4%,92% 92%,85.4% 96.5%,75.4% 99.1%,50% 100%,24.6% 99.1%,14.6% 96.5%,8% 92%,3.5% 85.4%,0.9% 75.4%,0% 50%,0.9% 24.6%,3.5% 14.6%,8% 8%,14.6% 3.5%,24.6% 0.9%,50% 0%,75.4% 0.9%,85.4% 3.5%,92% 8%,96.5% 14.6%,99.1% 24.6%); }
.stagebox [data-shape=hexagon] .feed[data-vid] { border-radius: 0; clip-path: polygon(25% 0%,75% 0%,100% 50%,75% 100%,25% 100%,0% 50%); }
.stagebox [data-shape=circle] .feed[data-vid] .np, .stagebox [data-shape=hexagon] .feed[data-vid] .np { left: 50%; right: auto; transform: translateX(-50%); bottom: 10%; max-width: 76%; justify-content: center; }
.stagebox [data-shape=circle] .feed[data-vid] .lower, .stagebox [data-shape=hexagon] .feed[data-vid] .lower { left: 50%; right: auto; transform: translateX(-50%); bottom: 10%; max-width: 82%; border-left: none; border-radius: 9px; align-items: center; text-align: center; padding: 6px 12px; }
.stagebox [data-shape=circle] .feed[data-vid] .mutebadge, .stagebox [data-shape=hexagon] .feed[data-vid] .mutebadge { right: 12%; top: 11%; }
.stagebox [data-shape=circle] .feed[data-vid] .hidmark, .stagebox [data-shape=hexagon] .feed[data-vid] .hidmark { left: 12%; top: 11%; }

/* ---- reconnecting: this person's link dropped, the host is holding their slot ----
   Mirror of the .recon block in studio.html — keep both in sync.
   This one goes out on the LIVE stage, so it's deliberately restrained: desaturate
   and dim the tile so it reads as "held", and a small caption to say why. No red, no
   alarm — a wifi hiccup shouldn't look like a broadcast failure. */
.stagebox .feed.recon { filter: grayscale(1) brightness(.62); transition: filter .4s ease; }
.stagebox .feed.recon .phdisc { box-shadow: 0 12px 30px rgba(0,0,0,.6); }
/* Sized against the STAGE (cqmin), not the tile — .feed isn't a container and can't
   become one (container-type:size would kill the tile's aspect-ratio; see .phdisc).
   Clamped so it stays legible on a big solo tile and shrinks out of the way on a
   crowded grid; max-width keeps it inside the narrowest tile rather than bleeding out. */
.stagebox .feed .recon-ov { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 4; display: flex; align-items: center; justify-content: center; gap: 7px; padding: 5px 11px; border-radius: 999px; background: rgba(10,11,13,.72); backdrop-filter: blur(8px); box-shadow: 0 4px 14px rgba(0,0,0,.45); font-size: clamp(8px, 1.5cqmin, 12px); font-weight: 500; color: #e8eaee; white-space: nowrap; max-width: 92%; overflow: hidden; }
/* The overlay must NOT be greyed with the tile, or the caption goes mud-on-mud.
   filter creates a containing block, so lift it out with its own filter reset. */
.stagebox .feed.recon .recon-ov { filter: grayscale(0) brightness(1.6) saturate(1.2); }
.stagebox .feed .recon-dot { width: 6px; height: 6px; border-radius: 50%; background: #f0b429; box-shadow: 0 0 8px rgba(240,180,41,.8); animation: reconpulse 1.4s ease-in-out infinite; }
@keyframes reconpulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .stagebox .feed .recon-dot { animation: none; opacity: .9; } .stagebox .feed.recon { transition: none; } }
.stagebox .feed .recon-tx { overflow: hidden; text-overflow: ellipsis; }

/* "Waiting for the host to set the stage" placeholder */
.stagebox .stage-empty { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; color: var(--mute); font-size: 13px; text-align: center; padding: 20px; }
.stagebox .stage-empty i { font-size: 30px; }

/* self-view picture-in-picture */
#selfpip { position: absolute; right: 22px; bottom: 22px; width: 210px; max-width: 34%; aspect-ratio: 16/9; border-radius: 12px; overflow: hidden; background: var(--c2); box-shadow: 0 8px 24px rgba(0,0,0,.5), 0 0 0 2px rgba(11,12,14,.7); z-index: 6; display: flex; align-items: center; justify-content: center; transform-origin: bottom right; transition: opacity .3s ease, transform .3s cubic-bezier(.22,.61,.36,1); }
#selfpip.onair { box-shadow: 0 8px 24px rgba(0,0,0,.5), 0 0 0 2px var(--live); }
/* hidden once the guest is on stage (their camera is already in the program) */
#selfpip.gone { opacity: 0; transform: translateY(10px) scale(.92); pointer-events: none; }
#selfpip video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transform: scaleX(-1); }
#selfpip .simg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
#selfpip .savatar { width: 52px; height: 52px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 600; color: #fff; }
#selfpip .slabel { position: absolute; left: 8px; bottom: 8px; display: flex; align-items: center; gap: 6px; background: rgba(10,11,13,.6); backdrop-filter: blur(8px); padding: 3px 9px; border-radius: 8px; font-size: 10.5px; font-weight: 600; }
#selfpip .slabel .d { width: 6px; height: 6px; border-radius: 50%; background: var(--mute); }
#selfpip.onair .slabel .d { background: var(--live); }
