* { margin: 0; padding: 0; box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; height: 100%; overflow: hidden; }   /* fullscreen app — lock the window scroll; inner panes scroll themselves */
body {
    font-family: 'Noto Kufi Arabic', 'Tahoma', sans-serif;
    /* Clubhouse-style flat near-black, with a whisper of top elevation */
    background: radial-gradient(130% 80% at 50% -12%, rgba(255,255,255,0.045), transparent 60%), #0b0b0f;
    color: #e8eaf6;
    height: 100%; min-height: 100vh; min-height: 100dvh;
    overflow: hidden; user-select: none;
    -webkit-tap-highlight-color: transparent;
}
button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }

/* height cascade: 100vh fallback -> 100dvh -> JS-measured --app-vh (set from the real
   visual viewport so a standalone/home-screen launch can't push the bottom dock off-screen). */
.app-container { display: flex; flex-direction: column; height: 100vh; height: 100dvh; height: var(--app-vh, 100dvh); position: relative; }

/* Two-row header: a compact status/chrome bar on top, the title on its OWN
   full-width row below so long Arabic titles read cleanly and wrap to 2 lines
   instead of truncating. */
.meeting-header {
    display: flex; flex-direction: column; gap: 7px; padding: 11px 14px;
    background: rgba(18,18,24,0.72); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
    border-bottom: 1px solid rgba(255,255,255,0.06); z-index: 10;
}
.header-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-width: 0; }
.header-status { display: flex; align-items: center; gap: 8px; font-size: 13px; color: #a0a4c0; min-width: 0; flex: 1 1 auto; }
.header-status #listenerCount { white-space: nowrap; }
/* Title owns its row: centered, up to 2 lines, then ellipsis. unicode-bidi:plaintext
   keeps a mixed Arabic/Latin title from being clipped at its leading edge in RTL. */
.header-title {
    font-size: 18px; font-weight: 700; letter-spacing: -.2px; line-height: 1.4; text-align: center;
    unicode-bidi: plaintext; word-break: break-word; padding: 0 6px;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* Clubhouse-style leave pill (top, trailing) */
.btn-leave-pill { flex-shrink: 0; display: inline-flex; align-items: center; gap: 6px; padding: 9px 15px; border-radius: 20px; background: rgba(255,255,255,0.08); color: #ff6b6b; font-weight: 700; font-size: 14px; white-space: nowrap; transition: background .2s, transform .1s; }
.btn-leave-pill:hover { background: rgba(255,107,107,0.16); }
.btn-leave-pill:active { transform: scale(.94); }
.live-badge { display: inline-flex; align-items: center; gap: 6px; color: #ff6b6b; font-weight: 600; }
.live-dot { width: 8px; height: 8px; border-radius: 50%; background: #ff4757; animation: pulse-live 1.5s ease-in-out infinite; }
@keyframes pulse-live { 0%,100%{opacity:1;transform:scale(1);} 50%{opacity:.5;transform:scale(.85);} }
.separator { color: #4a4e6e; }
.btn-icon-only { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: 12px; color: #c5c7df; transition: background .2s; }
.btn-icon-only:hover, .btn-icon-only:active { background: rgba(255,255,255,0.08); }

.tier-badge { font-size: 11px; font-weight: 600; padding: 4px 10px; border-radius: 12px; background: linear-gradient(135deg,#ffd700,#ffa500); color: #1a1d2e; }
.tier-badge.vip { background: linear-gradient(135deg,#a78bfa,#7c3aed); color: #fff; }
.tier-badge.tier2 { background: linear-gradient(135deg,#60a5fa,#2563eb); color: #fff; }
.tier-badge.tier1 { background: linear-gradient(135deg,#34d399,#059669); color: #fff; }
.tier-badge.free { background: rgba(255,255,255,0.1); color: #c5c7df; }

.section-title { font-size: 14px; font-weight: 600; color: #a0a4c0; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
.section-title .count { font-size: 12px; color: #6e7396; }

/* Single scroll region holding BOTH speakers (stage) and listeners (audience) so the whole
   roster scrolls as ONE list (was two separate scroll zones — confusing on mobile). */
.roster-scroll { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.stage { padding: 18px 16px 8px; }
/* Flex-wrap (not grid) so a few speakers CENTER instead of clustering to the
   RTL edge and leaving a void; many speakers wrap naturally across rows. */
.stage-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px 16px; }
.stage-grid .speaker-tile { flex: 0 0 auto; width: 92px; }

.speaker-tile, .listener-tile { display: flex; flex-direction: column; align-items: center; gap: 8px; position: relative; cursor: pointer; }
.speaker-tile .avatar-wrap { position: relative; width: 72px; height: 72px; }
.avatar { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; background: #2a2f4a; border: 3px solid transparent; transition: border-color .2s; }
.speaker-tile.is-host .avatar { border-color: #ffd700; }
.speaker-tile.is-cohost .avatar { border-color: #a78bfa; }
.speaker-tile.is-moderator .avatar { border-color: #34d399; }
.speaker-tile.is-speaking .avatar-wrap::before { content:''; position:absolute; inset:-6px; border:3px solid #34d399; border-radius:50%; animation: speaking-pulse 1.2s ease-out infinite; }
@keyframes speaking-pulse { 0%{transform:scale(.95);opacity:1;} 100%{transform:scale(1.15);opacity:0;} }
.speaker-tile .mic-badge { position:absolute; bottom:-2px; inset-inline-end:-2px; inset-inline-start:auto; width:22px; height:22px; border-radius:50%; background:#0b0b0f; border:2px solid #0b0b0f; display:flex; align-items:center; justify-content:center; font-size:11px; }
.mic-badge.muted { background:#ff4757; }
.mic-badge.unmuted { background:#34d399; }
.speaker-tile video { width:100%; height:100%; border-radius:50%; object-fit:cover; }
/* unicode-bidi:plaintext → each name picks its OWN base direction from its first
   strong char, independent of the RTL page. Latin names like "Administrator"
   become LTR so the ellipsis lands at the trailing end ("Administ…") instead of
   chopping the start ("…inistrator"); Arabic names stay RTL. */
.name { font-size: 13px; font-weight: 500; color: #e8eaf6; max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center; unicode-bidi: plaintext; }
/* tier star + name on one centered row (star is the leading glyph in RTL) */
.name-row { display: flex; align-items: center; justify-content: center; gap: 5px; max-width: 96px; }
.name-row .name { min-width: 0; max-width: none; }
.listener-tile .name-row { max-width: 68px; }

.audience { padding: 16px; }
.audience-grid { display: grid; grid-template-columns: repeat(auto-fill, 60px); gap: 16px 10px; justify-content: center; justify-items: center; }
.audience-sep { height: 1px; background: rgba(255,255,255,0.08); margin: 2px 0 16px; }   /* speakers | audience divider (replaced the «الجمهور» label) */
.listener-tile .avatar { width: 48px; height: 48px; border: 2px solid transparent; }
.listener-tile:active .avatar { transform: scale(.92); }
.listener-tile.has-raised-hand .avatar { border-color: #fbbf24; }
.listener-tile .hand-badge { position:absolute; top:-4px; inset-inline-end:-4px; width:22px; height:22px; background:#fbbf24; color:#1a1d2e; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:12px; border:2px solid #1a1d2e; }
.listener-tile .name { font-size: 10px; color: #a0a4c0; max-width: 56px; }

/* Mobile: smaller tiles so more fit per row + the single roster list scans quickly. */
@media (max-width: 700px) {
    .stage { padding: 14px 12px 6px; }
    .stage-grid { gap: 14px 12px; }
    .stage-grid .speaker-tile { width: 64px; }
    .speaker-tile .avatar-wrap { width: 52px; height: 52px; }
    .speaker-tile .mic-badge { width: 18px; height: 18px; font-size: 9px; }
    .speaker-tile .name { font-size: 11px; max-width: 64px; }
    .speaker-tile .name-row { max-width: 68px; }
    .audience { padding: 12px; }
    .audience-grid { grid-template-columns: repeat(auto-fill, 48px); gap: 12px 8px; }
    .listener-tile .avatar { width: 40px; height: 40px; }
    .listener-tile .name { font-size: 9px; max-width: 46px; }
    .listener-tile .name-row { max-width: 50px; }
    .section-title { margin-bottom: 10px; font-size: 13px; }
}

.bottom-bar { display:flex; align-items:center; flex-wrap:nowrap; overflow-x:auto; padding:12px 14px; padding-bottom:max(12px,env(safe-area-inset-bottom)); background:rgba(15,17,23,0.92); backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px); border-top:1px solid rgba(255,255,255,0.06); gap:8px; flex-shrink:0; position:relative; z-index:30; }
.reactions-buttons { display:flex; gap:5px; flex-shrink:0; position:relative; }
.twemoji { display:inline-block; width:1em; height:1em; vertical-align:-.125em; object-fit:contain; pointer-events:none; }
.btn-react-trigger { width:38px; height:38px; border-radius:50%; background:rgba(255,255,255,0.06); font-size:22px; display:flex; align-items:center; justify-content:center; flex-shrink:0; transition:transform .1s,background .2s; }
.btn-react-trigger:hover { background:rgba(255,255,255,0.12); }
.btn-react-trigger:active { transform:scale(.85); }
.btn-react-trigger[aria-expanded="true"] { background:rgba(255,255,255,0.16); }
/* Reaction pop-up: vertical stack of large emojis ABOVE the trigger. Re-parented to <body>
   + position:fixed in JS so the bottom bar's overflow-x:auto cannot clip it. */
.react-menu { position:fixed; left:50%; bottom:96px; transform:translateX(-50%) translateY(6px) scale(.96); transform-origin:bottom center;  /* safe default while closed (JS sets left/bottom on open) so it never parks off-viewport */
  display:flex; flex-direction:column-reverse; gap:8px; padding:8px; border-radius:22px;
  background:rgba(20,20,26,0.96); backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
  border:1px solid rgba(255,255,255,0.10); box-shadow:0 12px 40px rgba(0,0,0,.5);
  z-index:75; opacity:0; pointer-events:none; transition:opacity .18s ease, transform .18s cubic-bezier(.22,1,.36,1); }
.react-menu.is-open { opacity:1; pointer-events:auto; transform:translateX(-50%) translateY(0) scale(1); }
.react-menu.is-fading { opacity:0; transition:opacity 1.1s ease; }
.react-menu-item { width:46px; height:46px; border-radius:50%; background:rgba(255,255,255,0.06); font-size:30px; display:flex; align-items:center; justify-content:center; transition:transform .1s, background .18s; }
.react-menu-item:hover { background:rgba(255,255,255,0.14); }
.react-menu-item:active { transform:scale(.82); }
@media (prefers-reduced-motion: reduce) {
  .react-menu { transition:opacity .12s ease; transform:translateX(-50%); }
  .react-menu.is-open { transform:translateX(-50%); }
  .react-menu.is-fading { transition:opacity .25s ease; }
}
.center-controls { display:flex; gap:8px; flex:1; min-width:0; justify-content:center; align-items:center; flex-wrap:nowrap; }
.btn-speak { white-space:nowrap; }
.more-dots { font-size:24px; line-height:1; font-weight:700; letter-spacing:0; }
.btn-action { padding:10px 18px; border-radius:22px; background:rgba(255,255,255,0.08); color:#e8eaf6; font-size:14px; font-weight:600; display:inline-flex; align-items:center; gap:6px; transition:background .2s, transform .1s; }
.btn-action:hover { background:rgba(255,255,255,0.14); }
.btn-action:active { transform:scale(.96); }
.btn-action.primary { background:#2f7bff; color:#fff; }
.btn-action.primary:hover { background:#2563eb; }
/* the prominent Clubhouse "ask to speak" / mic pill */
.btn-speak { padding:13px 26px; font-size:15px; border-radius:24px; box-shadow:0 6px 18px rgba(47,123,255,0.28); }
.btn-speak.active { box-shadow:0 6px 18px rgba(52,211,153,0.28); }
.btn-action.danger { background:#ef4444; }
.btn-action.active { background:#34d399; color:#0f1117; }
.btn-action.has-badge { position:relative; }
.btn-action .badge { position:absolute; top:-6px; inset-inline-end:-6px; background:#fbbf24; color:#1a1d2e; border-radius:10px; min-width:18px; height:18px; font-size:11px; display:flex; align-items:center; justify-content:center; padding:0 4px; }
.btn-leave { display:inline-flex; align-items:center; gap:6px; padding:10px 16px; border-radius:22px; background:#ef4444; color:#fff; font-weight:600; font-size:14px; }

/* Bottom-anchored BAND (not full-screen): floats spawn at bottom:80px and rise
   260px — capping the band at 420px means a reaction flood can never paint a
   curtain over the SPEAKERS panel at the top (it sat at z-index:50, above the
   tiles' targeted emojis — half of the "reactions conflict" bug). */
.reactions-overlay { position:absolute; inset-inline:0; bottom:0; top:auto; height:min(420px, 55%); pointer-events:none; overflow:hidden; z-index:50; }
.float-emoji { position:absolute; bottom:80px; font-size:34px; animation: floatUp 2.6s ease-out forwards; }

/* Reaction attribution — a vertical "applause ribbon" in the bottom-LEFT corner, the mirror
   twin of the bottom-RIGHT .chat-flash (same dark-glass material, opposite corner). Body-
   level + position:fixed, anchored to the PHYSICAL left: this is a screen-corner HUD that
   mirrors the physical-right chat, so `left` is intentional (NOT text-flow-relative) and
   stays put in both RTL and LTR. pointer-events:none → never blocks a tap. Newest pill
   springs in at the BOTTOM; older pills are shoved UP (FLIP in JS); the oldest fades from
   the TOP. Up to 7, ~8s each. */
.react-attrib {
    position: fixed;
    left: 10px;
    bottom: calc(84px + env(safe-area-inset-bottom, 0px));   /* clear the bottom bar (mirrors .chat-flash) */
    z-index: 60;
    display: flex;
    flex-direction: column;          /* DOM order top→bottom: first child = oldest (top), last = newest (bottom) */
    align-items: flex-start;
    gap: 0;                          /* stacked-cards: chips overlap via the negative margin below */
    direction: ltr;                  /* lock the flex cross-axis to the physical left; pills set their own rtl */
    pointer-events: none;
    max-width: min(64vw, 250px);
    transition: bottom .25s ease;    /* raise smoothly when the chat one-liner appears */
}
/* The reaction stack sits at the bottom-left by default; when the chat one-liner is showing,
   raise it above so the two bottom-left popups never overlap (chat owns the lowest slot).
   The clearance is DYNAMIC: --cf-h is the chat bubble's measured height (set by showChatFlash)
   so the reaction clears a 1-, 2-, or 3-line chat. A static offset (was 140px) overlapped
   multi-line chats — the reaction got painted behind the taller bubble. 84px = the chat's own
   bottom; +12px gap. Fallback 56px ≈ a one-line bubble. */
body.chat-flash-on .react-attrib { bottom: calc(84px + env(safe-area-inset-bottom, 0px) + var(--cf-h, 56px) + 12px); }
.react-chip {
    direction: rtl;                  /* inner content reads RTL: avatar (leading/right) → name → glyph (left) */
    --rc-tier: rgba(255,255,255,0.45);
    margin-top: -10px;               /* stacked-cards overlap (~25%); newest is last in DOM → paints on top */
    display: flex; align-items: center; gap: 8px;
    max-width: 100%;
    padding: 4px 11px 4px 5px;       /* snug on the avatar (leading) side */
    border-radius: 999px;
    background: rgba(18,18,24,0.72);
    backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
    border: 1px solid rgba(255,255,255,0.08);
    box-shadow: 0 6px 20px -8px rgba(0,0,0,0.6);
    transform-origin: left center;
    will-change: transform, opacity;
}
.react-chip[data-tier="red"]   { --rc-tier: #e23b3b; }
.react-chip[data-tier="green"] { --rc-tier: #1f9d4d; }
.react-chip[data-tier="gold"]  { --rc-tier: #C8A24A; }
.react-chip[data-tier="blue"]  { --rc-tier: #2BA7E0; }
.rc-av {
    flex-shrink: 0;
    width: 30px; height: 30px;
    border-radius: 50%;
    object-fit: cover;
    background: #2a2f4a;
    border: 2px solid var(--rc-tier);
}
.rc-name {
    min-width: 0;
    font-size: 12.5px; font-weight: 600;
    color: #e8eaf6;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    unicode-bidi: plaintext;         /* Latin names go LTR so the ellipsis lands at the trailing end */
}
.rc-emoji {
    flex-shrink: 0;
    font-size: 17px; line-height: 1;
    filter: drop-shadow(0 1px 1px rgba(0,0,0,0.5));
}
/* Compound entry: spring up (pill) + pop (emoji) + a tier-colour halo rippling off the avatar. */
@keyframes rcSpringIn {
    0%   { opacity: 0; transform: translateY(22px) scale(.9); }
    55%  { opacity: 1; transform: translateY(-4px) scale(1.03); }   /* overshoot */
    100% { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes rcPop {
    0%   { transform: scale(1.5); }
    55%  { transform: scale(.9); }
    100% { transform: scale(1); }
}
@keyframes rcHalo {
    0%   { box-shadow: 0 0 0 0 var(--rc-tier); }
    70%  { box-shadow: 0 0 0 9px rgba(0,0,0,0); }
    100% { box-shadow: 0 0 0 9px rgba(0,0,0,0); }
}
@keyframes rcBump {
    0%, 100% { transform: scale(1); }
    40%      { transform: scale(1.06); }
}
.react-chip.is-entering { animation: rcSpringIn 480ms ease-out both; }
.react-chip.is-entering .rc-av { animation: rcHalo 720ms ease-out both; }
.react-chip.is-entering .rc-emoji,
.react-chip .rc-emoji.rc-pop   { animation: rcPop 480ms 60ms ease-out both; }
.react-chip.is-bump { animation: rcBump 360ms ease-out; }
.react-chip.is-leaving {
    opacity: 0; transform: translateY(-10px) scale(.92);
    transition: opacity 340ms ease, transform 340ms ease;
}
@media (prefers-reduced-motion: reduce) {
    .react-chip.is-entering, .react-chip.is-entering .rc-av,
    .react-chip.is-entering .rc-emoji, .react-chip .rc-emoji.rc-pop,
    .react-chip.is-bump { animation: none; }
    .react-chip.is-leaving { transform: none; transition: opacity 200ms ease; }
}
@media (max-width: 700px) {
    .react-attrib { left: 8px; bottom: calc(78px + env(safe-area-inset-bottom, 0px)); gap: 6px; max-width: 60vw; }
    .rc-av { width: 26px; height: 26px; }
    .rc-name { font-size: 11.5px; }
    .rc-emoji { font-size: 15px; }
}
@keyframes floatUp { 0%{transform:translateY(0) scale(.6);opacity:0;} 15%{opacity:1;transform:translateY(-20px) scale(1.1);} 100%{transform:translateY(-260px) scale(1);opacity:0;} }

/* Side drawer for «طلبات الكلام». RTL gotcha: the drawer must slide in from
   inline-start (which is the visual RIGHT in RTL). Earlier we used physical
   `left:0` + `translateX(-100%)`; in RTL that anchors the drawer to the
   visual LEFT and pushes the speaker tile out — the exact iPhone 13 Pro bug
   the user reported. Switch to logical properties (`inset-inline-start`),
   move the border to `border-inline-end`, and invert the transform sign to
   `+100%` so in RTL the off-screen rest position is past the visual right
   edge. For LTR locales there's a defence-in-depth html[dir="ltr"] block
   right after this rule that flips the transform back. */
.mod-panel { position:absolute; inset-block:0; inset-inline-start:0; width:300px; max-width:85vw; background:#1a1d2e; border-inline-end:1px solid rgba(255,255,255,0.08); transform:translateX(100%); transition:transform .25s; z-index:60; display:flex; flex-direction:column; }
.mod-panel[aria-hidden="false"] { transform:translateX(0); }
html[dir="ltr"] .mod-panel { transform:translateX(-100%); }
html[dir="ltr"] .mod-panel[aria-hidden="false"] { transform:translateX(0); }
.mod-panel header { display:flex; align-items:center; justify-content:space-between; padding:16px; border-bottom:1px solid rgba(255,255,255,0.08); }
.mod-panel header button { font-size:24px; color:#a0a4c0; }
.raised-hands-list { flex:1; overflow-y:auto; padding:12px; }
.raised-hand-item { display:flex; align-items:center; gap:10px; padding:8px; border-radius:10px; }
.raised-hand-item:hover { background:rgba(255,255,255,0.05); }
.raised-hand-item .avatar { width:40px; height:40px; }
.raised-hand-item .rh-name { flex:1; font-size:14px; }
.raised-hand-item button { padding:6px 12px; border-radius:14px; background:#6366f1; font-size:12px; font-weight:600; }
.raised-hand-item .rh-approve { background:#16a34a; color:#fff; }
.raised-hand-item .rh-reject { background:rgba(239,68,68,0.16); color:#fca5a5; }
.hand-declined { justify-content:center; text-align:center; }

.conn-status { position:absolute; top:70px; left:50%; transform:translateX(-50%); background:rgba(0,0,0,0.7); padding:6px 14px; border-radius:14px; font-size:13px; z-index:40; transition:opacity .3s; }
.conn-status.hidden { opacity:0; pointer-events:none; }

.join-overlay { position:absolute; inset:0; background:rgba(10,12,20,0.95); display:flex; align-items:center; justify-content:center; z-index:100; }
.join-overlay.hidden { display:none; }
.join-card { text-align:center; padding:32px; max-width:340px; }
.join-card h2 { font-size:22px; margin-bottom:10px; }
.join-card p { color:#a0a4c0; margin-bottom:20px; }
.join-card .btn-action { font-size:16px; padding:14px 32px; }
.join-error { color:#ff6b6b; font-size:13px; margin-top:14px; min-height:18px; }


.avatar-wrap{position:relative}
.listener-tile .avatar-wrap{width:48px;height:48px}
/* tier star — inline beside the name (no longer on the avatar) and enlarged.
   The asterisk glyph sits high in the em-box, so nudge it down to center on text. */
.mb-tier-star{flex-shrink:0;font-family:Arial,sans-serif;font-weight:900;line-height:1;pointer-events:none;transform:translateY(0.18em);text-shadow:0 0 3px #0b0b0f,0 1px 2px rgba(0,0,0,.85)}
.speaker-tile .mb-tier-star{font-size:42px}
.listener-tile .mb-tier-star{font-size:32px}
.mb-tier-red{color:#e23b3b}.mb-tier-green{color:#1f9d4d}.mb-tier-gold{color:#C8A24A}.mb-tier-blue{color:#2BA7E0}

/* ============================================================ Clubhouse chat + sheets */

/* step-down — compact round icon (⬇), quiet vs the blue mic pill */
.btn-stepdown { font-size:20px; color:#c5c7df !important; }

/* round icon buttons in the bottom bar (chat / more / step-down) */
.btn-chat { position:relative; width:42px; height:42px; border-radius:50%; background:rgba(255,255,255,0.06); color:#e8eaf6; font-size:20px; display:flex; align-items:center; justify-content:center; flex-shrink:0; transition:background .2s, transform .1s; }
.btn-chat:hover { background:rgba(255,255,255,0.12); }
.btn-chat:active { transform:scale(.9); }
.chat-badge { position:absolute; top:-3px; inset-inline-end:-3px; min-width:18px; height:18px; padding:0 4px; border-radius:9px; background:#2f7bff; color:#fff; font-size:11px; font-weight:700; display:flex; align-items:center; justify-content:center; box-shadow:0 0 0 2px #0b0b0f; animation:chat-pulse 1.8s ease-in-out infinite; }
@keyframes chat-pulse { 0%,100%{transform:scale(1);} 50%{transform:scale(1.12);} }

/* chat drawer = bottom sheet
   iOS keyboard awareness: --mb-kbd-h is set by the visualViewport listener
   in meeting.js. When the keyboard opens (chat input focused), the panel
   lifts above it so the input row + send button stay reachable. Without
   this, iOS Safari overlays the keyboard ON TOP of the panel's bottom edge
   and the user can't see what they're typing. Falls back to 0 when the
   visualViewport API isn't available (older browsers; not our target). */
/* ---- admin room-log panel (mirrors the chat-panel positioning) ---- */
.roomlog-panel { position:fixed; inset-inline:0; bottom:var(--mb-kbd-h, 0); z-index:71; display:flex; flex-direction:column;
    max-height:62dvh; background:rgba(20,20,26,0.97); backdrop-filter:blur(22px); -webkit-backdrop-filter:blur(22px);
    border-top:1px solid rgba(255,255,255,0.08); border-radius:20px 20px 0 0; box-shadow:0 -12px 40px rgba(0,0,0,.5);
    transform:translateY(100%); transition:transform .32s cubic-bezier(.22,1,.36,1); }
.roomlog-panel[aria-hidden="false"] { transform:translateY(0); }
.roomlog-list { flex:1; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:10px 16px 16px; display:flex; flex-direction:column; gap:2px; }
.rl-row { display:flex; align-items:baseline; justify-content:space-between; gap:10px; padding:7px 2px; border-bottom:1px solid rgba(255,255,255,0.04); }
.rl-text { font-size:13.5px; color:#e8eaf6; line-height:1.5; }
.rl-when { flex-shrink:0; font-size:11px; color:#8a8fb0; font-variant-numeric:tabular-nums; }
.rl-empty { padding:24px 12px; text-align:center; color:#8a8fb0; font-size:13px; }
@media (min-width: 701px) {
  .roomlog-panel { inset-block:0; inset-inline-end:0; inset-inline-start:auto; width:380px; max-width:90vw; max-height:none;
    border-radius:0; border-top:none; border-inline-start:1px solid rgba(255,255,255,0.08); box-shadow:12px 0 40px rgba(0,0,0,.5);
    transform:translateX(-100%); transition:transform .32s cubic-bezier(.22,1,.36,1); }
  .roomlog-panel[aria-hidden="false"] { transform:translateX(0); }
  html[dir="ltr"] .roomlog-panel { transform:translateX(100%); }
  html[dir="ltr"] .roomlog-panel[aria-hidden="false"] { transform:translateX(0); }
}
/* confetti burst (🎉 'party' reaction) */
.confetti-overlay { position:fixed; inset:0; pointer-events:none; z-index:80; overflow:hidden; }
.confetti-piece { position:absolute; top:-14px; width:9px; height:14px; border-radius:2px; opacity:.95;
    animation:confetti-fall 2.6s cubic-bezier(.3,.6,.4,1) forwards; }
@keyframes confetti-fall {
  0% { transform:translateY(-14px) translateX(0) rotate(0); opacity:0; }
  10% { opacity:1; }
  100% { transform:translateY(104vh) translateX(var(--cf-x,0)) rotate(var(--cf-rot,360deg)); opacity:1; }
}
@media (prefers-reduced-motion: reduce) { .confetti-overlay { display:none; } }

/* 🎉 party-reaction cooldown: dim the button + a gold ring that empties over the 3-min lock.
   Driven from meeting.js (--cd-dur / --cd-delay); admins/owner are never put in this state. */
@property --cd-pct { syntax: '<percentage>'; inherits: false; initial-value: 100%; }
.react-menu-item.is-cooldown { position:relative; pointer-events:none; }     /* not clickable */
.react-menu-item.is-cooldown > * { opacity:.32; filter:grayscale(.6); }      /* dim the glyph */
.react-menu-item.is-cooldown::after {
    content:''; position:absolute; inset:-3px; border-radius:50%; pointer-events:none;
    background:conic-gradient(var(--mb-gold, #C8A24A) var(--cd-pct), rgba(255,255,255,.14) 0);
    -webkit-mask:radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
            mask:radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
    animation:party-cd var(--cd-dur, 180s) linear var(--cd-delay, 0s) forwards; }
@keyframes party-cd { from { --cd-pct:100%; } to { --cd-pct:0%; } }
@media (prefers-reduced-motion: reduce) {
    .react-menu-item.is-cooldown::after { animation:none;
        background:conic-gradient(var(--mb-gold,#C8A24A) 50%, rgba(255,255,255,.14) 0); } }

/* 🫏 laughing-donkey broadcast reaction — a big one-shot overlay: pop-in -> laugh bob+wobble
   -> gallop off-screen with a dust puff. Mirrors the confetti pattern (body-level, fixed,
   pointer-events:none). Layered so the flat cut-out photo still feels alive. */
.donkey-overlay { position:fixed; inset:0; pointer-events:none; z-index:85; overflow:hidden;
    display:flex; align-items:center; justify-content:center; }
.dk-runner { position:relative; transform-box:fill-box; transform-origin:50% 100%;
    animation:dk-act 5s cubic-bezier(.4,1.3,.5,1) forwards; }
.dk-bob { animation:dk-bob .5s ease-in-out infinite alternate; }
.dk-img { display:block; width:min(56vmin,460px); height:auto; transform-box:fill-box;
    transform-origin:50% 92%; animation:dk-wobble .28s ease-in-out infinite alternate;
    filter:drop-shadow(0 18px 14px rgba(0,0,0,.45)); }
.dk-dust { position:absolute; inset-inline-start:30%; bottom:12%; opacity:0; animation:dk-dust 5s linear forwards; }
.dk-dust b { display:inline-block; background:#cfc6b6; border-radius:50%; margin:0 3px; vertical-align:bottom; }
.dk-dust b:nth-child(1){ width:22px; height:22px; }
.dk-dust b:nth-child(2){ width:15px; height:15px; opacity:.8; }
.dk-dust b:nth-child(3){ width:10px; height:10px; opacity:.6; }
@keyframes dk-act {
  0%   { transform:translateX(0) translateY(60px) scale(.16); opacity:0; }
  6%   { transform:translateX(0) translateY(-8px) scale(1.06); opacity:1; }
  10%  { transform:translateX(0) translateY(0) scale(1); opacity:1; }
  54%  { transform:translateX(0) translateY(0) scale(1); opacity:1; }
  60%  { transform:translateX(28px) translateY(-6px) scale(1.03); opacity:1; }
  78%  { transform:translateX(-62vw) translateY(-26px) scale(.6); opacity:1; }
  82%  { opacity:0; }
  100% { transform:translateX(-62vw) translateY(-26px) scale(.6); opacity:0; }
}
@keyframes dk-bob { from { transform:translateY(0); } to { transform:translateY(-12px); } }
@keyframes dk-wobble { from { transform:rotate(-4deg); } to { transform:rotate(4deg); } }
@keyframes dk-dust { 0%,58% { opacity:0; } 62% { opacity:.85; } 78% { opacity:.25; } 80%,100% { opacity:0; } }
@media (prefers-reduced-motion: reduce) { .donkey-overlay { display:none; } }
/* donkey thumbnail inside the reaction-menu button */
.react-menu-item .donkey-thumb { width:100%; height:100%; object-fit:contain; display:block;
    border-radius:50%; background:rgba(255,255,255,0.06); }
/* Donkey reaction hidden for all users (2026-06-09, per request) — re-enable by deleting this rule. */
.react-menu-item.react-donkey { display:none !important; }

.chat-panel { position:fixed; inset-inline:0; bottom:var(--mb-kbd-h, 0); z-index:70; display:flex; flex-direction:column;
    max-height:62dvh; background:rgba(20,20,26,0.96); backdrop-filter:blur(22px); -webkit-backdrop-filter:blur(22px);
    border-top:1px solid rgba(255,255,255,0.08); border-radius:20px 20px 0 0; box-shadow:0 -12px 40px rgba(0,0,0,.5);
    transform:translateY(100%); transition:transform .32s cubic-bezier(.22,1,.36,1), bottom .18s ease-out; }
.chat-panel[aria-hidden="false"] { transform:translateY(0); }
.chat-grab { width:40px; height:4px; border-radius:3px; background:rgba(255,255,255,0.22); margin:8px auto 2px; }
.chat-header { display:flex; align-items:center; justify-content:space-between; padding:8px 16px 10px; border-bottom:1px solid rgba(255,255,255,0.06); }
.chat-header h3 { font-size:15px; font-weight:700; }
.chat-header-actions { display:flex; align-items:center; gap:6px; }
.chat-clear { font-size:13px; font-weight:600; color:#ff6b6b; padding:6px 10px; border-radius:12px; }
.chat-clear:active { background:rgba(255,107,107,0.14); }
.chat-close { font-size:24px; line-height:1; color:#a0a4c0; width:34px; height:34px; border-radius:10px; }
.chat-close:active { background:rgba(255,255,255,0.08); }
.chat-list { flex:1; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:12px 16px; display:flex; flex-direction:column; gap:12px; }
.chat-msg { animation:chat-in .22s ease-out; }
@keyframes chat-in { from{opacity:0; transform:translateY(6px);} to{opacity:1; transform:none;} }
.chat-head { display:flex; align-items:center; gap:6px; margin-bottom:2px; }
.chat-name { display:flex; align-items:center; gap:5px; font-size:13px; font-weight:700; color:#c9cbe6; }
.chat-name .mb-tier-star { font-size:17px; transform:translateY(0.16em); }
.chat-time { font-size:11px; font-weight:500; color:#8a8fb0; font-variant-numeric:tabular-nums; opacity:.8; }
.chat-del { margin-inline-start:auto; width:22px; height:22px; border-radius:7px; color:#8a8fb0; font-size:16px; line-height:1; opacity:.55; }
.chat-del:hover, .chat-del:active { opacity:1; background:rgba(255,107,107,0.16); color:#ff6b6b; }
/* author edit pen (mirrors .chat-del, neutral→blue) */
.chat-edit { width:22px; height:22px; border-radius:7px; color:#8a8fb0; font-size:13px; line-height:1; opacity:.55; }
.chat-edit:hover, .chat-edit:active { opacity:1; background:rgba(126,177,255,0.16); color:#7db1ff; }
.chat-edited-mark { font-size:10.5px; color:#8a8fb0; opacity:.75; margin-inline-start:2px; }
/* tap a name to quote-reply */
.chat-name-tap { cursor:pointer; }
.chat-name-tap:hover { text-decoration:underline; text-underline-offset:2px; }
/* quoted message rendered above a reply */
.chat-quote { margin:1px 0 4px; padding:4px 9px; border-inline-start:3px solid #2f7bff;
  background:rgba(47,123,255,0.10); border-radius:8px; display:flex; flex-direction:column; gap:1px;
  direction:rtl; text-align:start; }
.chat-quote-name { font-size:11px; font-weight:700; color:#9fb4ff; }
.chat-quote-text { font-size:12px; color:#b9bcd6; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* reply/edit context chip above the composer */
.chat-composer-chip { display:flex; align-items:center; gap:8px; margin:0 14px; padding:6px 12px;
  background:rgba(47,123,255,0.12); border:1px solid rgba(47,123,255,0.22); border-radius:14px 14px 6px 6px; direction:rtl; }
.chat-composer-chip[hidden] { display:none; }
.cc-info { min-width:0; flex:1; display:flex; flex-direction:column; gap:1px; overflow:hidden; }
.cc-label { font-size:11.5px; font-weight:700; color:#9fb4ff; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cc-text { font-size:12px; color:#aeb2cf; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cc-x { flex-shrink:0; width:24px; height:24px; border-radius:7px; color:#8a8fb0; font-size:16px; line-height:1; }
.cc-x:hover, .cc-x:active { opacity:1; background:rgba(255,255,255,0.08); color:#e8eaf6; }
.chat-text { font-size:14px; line-height:1.55; color:#e8eaf6; word-break:break-word; white-space:pre-wrap; direction:rtl; text-align:start; unicode-bidi:plaintext; }
/* Chat content is selectable/copyable — overrides the global body{user-select:none}; the rest
   of the app stays selection-locked. -webkit-touch-callout:default re-enables iOS long-press copy. */
.chat-text, .chat-name, .cf-text { user-select:text; -webkit-user-select:text; -webkit-touch-callout:default; cursor:text; }
/* Emoji-only message: render the native glyphs ~3× and force RTL alignment (emoji are
   bidi-neutral, so unicode-bidi:plaintext was defaulting them to LTR/left). Structure of
   the glyphs themselves is untouched — only the wrapper is scaled/aligned + a pop-in. */
.chat-text.chat-emoji-only { font-size:42px; line-height:1.15; direction:rtl; text-align:start; unicode-bidi:normal;
    transform-origin:inline-end; animation:emoji-pop .42s cubic-bezier(.22,1.4,.36,1) both; }
@keyframes emoji-pop { 0%{transform:scale(.3); opacity:0;} 60%{transform:scale(1.18);} 100%{transform:scale(1); opacity:1;} }
@media (prefers-reduced-motion: reduce) { .chat-text.chat-emoji-only { animation:none; } }
.chat-link { color:#7db1ff; text-decoration:underline; text-underline-offset:2px; word-break:break-all; cursor:pointer; }
.chat-link:hover, .chat-link:active { color:#a9caff; }
/* Unified composer pill — the input + embedded send button read as ONE rounded control
   (was a detached send circle floating in the corner). The row IS the pill; the input is
   borderless/transparent inside; the send circle sits at the trailing edge. */
.chat-input-row { position:relative; display:flex; align-items:flex-end; gap:6px; margin:10px 14px; margin-bottom:max(10px,env(safe-area-inset-bottom));
    padding:5px; padding-inline-start:16px; background:rgba(255,255,255,0.07); border:1px solid rgba(255,255,255,0.08);
    border-radius:26px; transition:border-color .18s, background .18s; }
.chat-input-row:focus-within { border-color:#2f7bff; background:rgba(255,255,255,0.10); }
/* Multiline RTL composer: a textarea that auto-grows (JS) so long Arabic wraps and the
   whole message stays visible; dir:rtl keeps Arabic right-aligned AND makes an inserted
   emoji sit in the SAME place here as in the sent .chat-text (both rtl → consistent bidi). */
.chat-input { flex:1; min-width:0; background:transparent; border:none; color:#e8eaf6; font-family:inherit;
    font-size:14px; line-height:1.5; padding:8px 0; outline:none; resize:none;
    direction:rtl; text-align:start; unicode-bidi:plaintext;
    white-space:pre-wrap; word-break:break-word; overflow-wrap:anywhere;
    max-height:120px; overflow-y:auto; }
.chat-input::placeholder { color:#6e7396; }
.chat-send { width:38px; height:38px; flex-shrink:0; border-radius:50%; background:#2f7bff; color:#fff; display:flex; align-items:center; justify-content:center; transition:background .2s, transform .1s; }
.chat-send:hover { background:#2563eb; }
.chat-send:active { transform:scale(.9); }
.chat-send svg { transform:scaleX(-1); }              /* RTL: plane points the send direction (up-left) */
html[dir="ltr"] .chat-send svg { transform:none; }
/* Emoji picker: 😊 toggle in the composer + a twemoji grid that floats above the input row. */
.chat-emoji-btn { width:38px; height:38px; flex-shrink:0; border-radius:50%; background:rgba(255,255,255,0.06); font-size:20px; display:flex; align-items:center; justify-content:center; transition:background .2s, transform .1s; }
.chat-emoji-btn:hover { background:rgba(255,255,255,0.12); }
.chat-emoji-btn:active { transform:scale(.9); }
.chat-emoji-btn .twemoji { width:22px; height:22px; }
.chat-emoji-picker { position:absolute; inset-inline:0; bottom:calc(100% + 8px); z-index:6;
  display:grid; grid-template-columns:repeat(auto-fill, minmax(40px, 1fr)); gap:4px; padding:10px;
  max-height:184px; overflow-y:auto; -webkit-overflow-scrolling:touch;
  background:rgba(20,20,26,0.98); backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
  border:1px solid rgba(255,255,255,0.12); border-radius:18px; box-shadow:0 -10px 34px rgba(0,0,0,0.55); }
.chat-emoji-picker[hidden] { display:none; }
.chat-emoji-item { width:100%; aspect-ratio:1; min-height:40px; border-radius:10px; background:transparent; display:flex; align-items:center; justify-content:center; font-size:22px; transition:background .15s, transform .1s; }
.chat-emoji-item:hover { background:rgba(255,255,255,0.10); }
.chat-emoji-item:active { transform:scale(.85); }
.chat-emoji-item .twemoji { width:24px; height:24px; }

/* Desktop: dock the chat as a fixed full-height side panel instead of a full-width bottom
   sheet. Pinned to inset-inline-end = visual LEFT in RTL (the mirror of the .mod-panel
   «طلبات الكلام» drawer, which uses inset-inline-start). Mobile (<=700px) keeps the bottom
   sheet above. The reduced-motion block (later) already neutralises .chat-panel transitions. */
@media (min-width: 701px) {
  .chat-panel {
    inset-block: 0; inset-inline-end: 0; inset-inline-start: auto;
    width: 380px; max-width: 90vw; max-height: none;
    border-radius: 0; border-top: none;
    border-inline-start: 1px solid rgba(255,255,255,0.08);
    box-shadow: 12px 0 40px rgba(0,0,0,.5);
    transform: translateX(-100%);                 /* RTL rest: off-screen physical LEFT */
    transition: transform .32s cubic-bezier(.22,1,.36,1);
  }
  .chat-panel[aria-hidden="false"] { transform: translateX(0); }
  html[dir="ltr"] .chat-panel { transform: translateX(100%); }
  html[dir="ltr"] .chat-panel[aria-hidden="false"] { transform: translateX(0); }
  .chat-grab { display: none; }
}

/* transient "latest chat line" popup — small, low-opacity, hugs the RIGHT edge
   above the bottom bar so it never blocks the screen-share. Replaced by each
   newer line, fades ~10s after the last. Tap to open the full chat. */
/* Latest-chat one-liner — a single rotating pill at the bottom-LEFT (under the reaction
   stack): [avatar] [name] [message] on ONE line, replaced by each new message, fades ~10s.
   Tap to open the full chat (misses are fine — history lives in the panel). */
.chat-flash {
  position: fixed; left: 10px; right: auto;
  bottom: calc(84px + env(safe-area-inset-bottom));
  display: flex; align-items: flex-start; gap: 8px;
  max-width: min(80vw, 340px); box-sizing: border-box;
  padding: 8px 14px 9px 7px; border-radius: 18px;        /* multi-line bubble (was a 1-line pill) */
  background: rgba(18,18,26,0.62);
  backdrop-filter: blur(14px) saturate(1.1); -webkit-backdrop-filter: blur(14px) saturate(1.1);
  border: 1px solid rgba(255,255,255,0.07);
  box-shadow: 0 8px 22px -10px rgba(0,0,0,.6);
  cursor: pointer; z-index: 60;
  opacity: 0; transform: translateY(10px);
  transition: opacity .3s cubic-bezier(.22,1,.36,1), transform .3s cubic-bezier(.22,1,.36,1);
}
.chat-flash.is-in { opacity: 0.97; transform: none; }
.chat-flash.is-leaving { opacity: 0; transform: translateY(6px); transition: opacity .9s ease, transform .9s ease; }
.cf-av { width: 30px; height: 30px; flex-shrink: 0; margin-top: 1px; border-radius: 50%; object-fit: cover; background: #2a2f4a; }
.cf-col { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cf-line { min-width: 0; display: flex; align-items: center; gap: 6px; }
.cf-name { flex-shrink: 0; font-size: 11px; font-weight: 700; color: #9fb4ff; max-width: 60vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Up to 3 lines of the latest message, wrapped + RTL (was a 1-line ellipsis, so multi-line chats vanished). */
.cf-text { min-width: 0; font-size: 12.5px; line-height: 1.45; color: #e8ebff;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
  white-space: normal; word-break: break-word; direction: rtl; text-align: start; unicode-bidi: plaintext; }
.cf-text.cf-emoji-only { font-size: 26px; line-height: 1.2; unicode-bidi: normal; }   /* larger emoji, still clamped to 3 lines */
.chat-flash .mb-tier-star { font-size: 13px; transform: translateY(0.1em); flex-shrink: 0; }
@media (prefers-reduced-motion: reduce) {
  .chat-flash { transition: opacity .25s ease; transform: none; }
  .chat-flash.is-leaving { transition: opacity .9s ease; transform: none; }
}

/* moderator action sheet */
/* Backdrop fills the layout viewport (incl. the area behind the keyboard,
   so the dim layer doesn't have a bright keyboard-sized stripe). The inner
   sheet sits at the bottom via `align-items:flex-end`; we lift it above
   the iOS keyboard by giving the FLEX CONTAINER itself a `padding-bottom`
   of the keyboard height. Padding on the flex container reduces the
   available space for flex-end alignment, so children naturally shift up
   by that amount — works around the flex+margin-bottom quirk where
   `margin-bottom` on the child gets collapsed by `align-items:flex-end`. */
.action-sheet { position:fixed; inset:0; z-index:80; background:rgba(0,0,0,0.5); display:flex; align-items:flex-end; justify-content:center; opacity:1; padding-bottom: var(--mb-kbd-h, 0); transition: opacity .2s, padding-bottom .18s ease-out; }
.action-sheet[aria-hidden="true"] { display:none; }
.sheet-card { width:100%; max-width:520px; background:rgba(20,20,26,0.98); backdrop-filter:blur(22px); -webkit-backdrop-filter:blur(22px); border-radius:20px 20px 0 0; padding:10px 14px max(14px,env(safe-area-inset-bottom)); display:flex; flex-direction:column; gap:8px; animation:sheet-up .28s cubic-bezier(.22,1,.36,1); }
@keyframes sheet-up { from{transform:translateY(100%);} to{transform:none;} }
.sheet-head { display:flex; align-items:center; gap:10px; padding:10px 6px 12px; border-bottom:1px solid rgba(255,255,255,0.08); margin-bottom:4px; }
.sheet-head .avatar { width:40px; height:40px; border-radius:50%; object-fit:cover; background:#2a2f4a; }
.sheet-head span { font-size:15px; font-weight:700; }
.sheet-btn { width:100%; padding:15px; border-radius:14px; font-size:15px; font-weight:600; background:rgba(255,255,255,0.06); color:#e8eaf6; transition:background .16s, transform .1s; }
.sheet-btn:active { transform:scale(.98); }
.sheet-blue { background:#2f7bff; color:#fff; }
.sheet-red { background:rgba(239,68,68,0.16); color:#ff6b6b; }
.sheet-gold { background:var(--gold,#C8A24A); color:#0E1013; }
.sheet-cancel { background:transparent; color:#a0a4c0; margin-top:2px; }

/* === Premium management sheet — refined dark/gold action LIST, no emojis === */
.sheet-card--manage { gap:0; padding-top:8px; }
.sheet-handle { width:40px; height:4px; border-radius:99px; background:rgba(245,242,234,0.22); align-self:center; margin:2px 0 12px; }
.sheet-title { position:relative; text-align:center; padding-bottom:14px; margin-bottom:10px; }
.sheet-title span { font-family:var(--font-display,'Aref Ruqaa','Noto Kufi Arabic',serif); font-size:19px; font-weight:700; color:var(--paper,#F5F2EA); letter-spacing:.3px; }
.sheet-title::after { content:''; position:absolute; inset-inline:0; bottom:0; height:1px; margin-inline:auto; width:64px; background:linear-gradient(90deg,transparent,var(--gold,#C8A24A),transparent); opacity:.6; }
.sheet-list { display:flex; flex-direction:column; background:rgba(255,255,255,0.035); border:1px solid var(--rule,rgba(245,242,234,0.08)); border-radius:16px; overflow:hidden; }
.sheet-list + .sheet-list { margin-top:10px; }
.sheet-list--danger { background:rgba(239,68,68,0.06); border-color:rgba(239,68,68,0.18); }
.sheet-row { display:flex; align-items:center; gap:13px; width:100%; min-height:58px; padding:10px 14px; background:transparent; color:var(--paper,#F5F2EA); text-align:start;
    -webkit-tap-highlight-color:transparent; transition:background .15s;
    animation:rowIn .32s var(--ease-stage,cubic-bezier(.2,.7,.2,1)) both; animation-delay:calc(var(--i,0)*42ms); }
.sheet-row + .sheet-row { border-block-start:1px solid var(--rule,rgba(245,242,234,0.07)); }
.sheet-row:hover:not(.is-disabled) { background:rgba(245,242,234,0.04); }
.sheet-row:active:not(.is-disabled) { background:rgba(245,242,234,0.07); }
.sheet-row-ic { flex:0 0 auto; width:38px; height:38px; border-radius:11px; display:grid; place-items:center; background:var(--gold-soft,rgba(200,162,74,0.16)); color:var(--gold,#C8A24A); }
.sheet-row-ic svg { width:20px; height:20px; }
.sheet-row-label { flex:1; font-size:15px; font-weight:600; unicode-bidi:plaintext; }
.sheet-row-meta { flex:0 0 auto; min-width:22px; height:22px; padding:0 7px; border-radius:99px; display:inline-flex; align-items:center; justify-content:center; font-size:12px; font-weight:700; background:var(--gold,#C8A24A); color:#0E1013; }
.sheet-row.is-disabled { opacity:.42; }
.sheet-row.is-disabled .sheet-row-meta { background:var(--rule-strong,rgba(245,242,234,0.16)); color:var(--ink-mute,#a0a4c0); }
.sheet-row.is-armed { background:var(--gold-soft,rgba(200,162,74,0.16)); }
.sheet-row.is-armed .sheet-row-label { color:var(--gold,#C8A24A); }
.sheet-row--danger .sheet-row-ic { background:rgba(239,68,68,0.14); color:#ff7a7a; }
.sheet-row--danger .sheet-row-label { color:#ff8a8a; }
@keyframes rowIn { from{opacity:0;transform:translateY(6px);} to{opacity:1;transform:none;} }
/* Destructive confirm view (single-tap; replaces hold-to-confirm) */
.sheet-confirm { display:flex; flex-direction:column; align-items:center; text-align:center; padding:6px 16px 4px; gap:9px; animation:rowIn .26s var(--ease-stage,ease) both; }
.sheet-confirm-ic { width:60px; height:60px; border-radius:50%; display:grid; place-items:center; background:rgba(239,68,68,0.12); border:1px solid rgba(239,68,68,0.35); color:#ff7a7a; margin-bottom:2px; }
.sheet-confirm-ic svg { width:28px; height:28px; }
.sheet-confirm-h { font-family:var(--font-display,'Aref Ruqaa','Noto Kufi Arabic',serif); font-size:19px; font-weight:700; color:var(--paper,#F5F2EA); }
.sheet-confirm-sub { font-size:13.5px; line-height:1.6; color:var(--ink-mute,#a0a4c0); max-width:300px; }
.sheet-confirm-actions { display:flex; flex-direction:column; gap:8px; width:100%; margin-top:10px; }
.sheet-danger-solid { background:#e0413f; color:#fff; }
.sheet-danger-solid:active { background:#c5332f; }
@media (prefers-reduced-motion: reduce) { .sheet-row, .sheet-confirm { animation:none; } }

/* Poll create-form inputs (inside the sheet). */
.poll-input { width:100%; padding:12px 14px; border-radius:12px; border:1px solid var(--rule-strong,rgba(245,242,234,0.16));
    background:rgba(255,255,255,0.05); color:#e8eaf6; font:500 15px/1.4 inherit; }
.poll-input::placeholder { color:#7e82a0; }
.poll-opts-wrap { display:flex; flex-direction:column; gap:8px; }

/* Poll banner (active poll) — pinned-link slot pattern: gold-edge card above roster. */
.poll-banner { position:relative; flex:0 0 auto; z-index:8; margin:0 12px 8px; padding:12px 14px;
    background:rgba(20,20,26,0.96); border:1px solid var(--gold-edge,rgba(200,162,74,0.42)); border-radius:16px;
    display:flex; flex-direction:column; gap:8px; animation:pinSlideIn 320ms var(--ease-stage,cubic-bezier(.2,.7,.2,1)) both; }
/* display:flex above would otherwise BEAT the [hidden] attribute (author styles
   override the UA's [hidden]{display:none}) — the empty gold frame bug. */
.poll-banner[hidden] { display:none !important; }
.poll-head { display:flex; align-items:center; gap:8px; }
.poll-eyebrow { font-size:11px; font-weight:700; letter-spacing:1px; color:var(--gold,#C8A24A); }
.poll-timer { font-size:12px; color:#a0a4c0; font-variant-numeric:tabular-nums; }
.poll-min { margin-inline-start:auto; width:28px; height:28px; border-radius:9px; background:rgba(255,255,255,0.06); color:#c5c7df; font-size:18px; line-height:1; }
.poll-q { font-size:15.5px; font-weight:700; color:#F5F2EA; unicode-bidi:plaintext; line-height:1.4; }
.poll-opt { position:relative; overflow:hidden; display:flex; align-items:center; gap:8px; width:100%; padding:11px 12px; border-radius:12px;
    background:rgba(255,255,255,0.05); color:#e8eaf6; text-align:start; transition:background .16s; }
.poll-opt:hover:not(:disabled) { background:rgba(255,255,255,0.09); }
.poll-opt:disabled { cursor:default; }
.poll-opt .poll-bar { position:absolute; inset-inline-start:0; top:0; bottom:0; width:0; background:var(--gold-soft,rgba(200,162,74,0.18)); transition:width .4s var(--ease-stage,ease); z-index:0; }
.poll-opt.is-mine { box-shadow:inset 0 0 0 1.5px var(--gold,#C8A24A); }
.poll-opt.is-mine .poll-bar { background:rgba(200,162,74,0.34); }
.poll-opt-label { position:relative; z-index:1; flex:1; font-size:14.5px; font-weight:600; unicode-bidi:plaintext; }
.poll-opt-pct { position:relative; z-index:1; font-size:13px; font-weight:700; color:#cfd3e6; font-variant-numeric:tabular-nums; }
.poll-foot { display:flex; align-items:center; gap:10px; font-size:12.5px; color:#a0a4c0; }
.poll-close-btn { margin-inline-start:auto; padding:6px 12px; border-radius:10px; background:rgba(239,68,68,0.16); color:#ff8a8a; font-size:12.5px; font-weight:600; }
/* Poll create/edit config (duration + multi-select + hide-results toggles). */
.poll-count { margin-inline-end:auto; }
.poll-foot .poll-close-btn { margin-inline-start:0; }   /* the group is pushed right by .poll-count's auto-margin */
.poll-edit-btn { background:rgba(200,162,74,0.16) !important; color:var(--gold,#C8A24A) !important; }
.poll-del-btn  { background:rgba(239,68,68,0.22) !important; color:#ff9a9a !important; }
.poll-cfg { display:flex; gap:8px; flex-wrap:wrap; margin-top:4px; }
.poll-dur { width:100%; padding:10px 12px; border-radius:12px; border:1px solid var(--rule-strong,rgba(245,242,234,0.16));
    background:rgba(255,255,255,0.04); color:#F5F2EA; font-size:14px; }
.poll-tog { flex:1; min-width:120px; padding:10px 12px; border-radius:12px; border:1px solid var(--rule-strong,rgba(245,242,234,0.16));
    background:rgba(255,255,255,0.04); color:#a0a4c0; font-size:13px; font-weight:600; }
.poll-tog.on { background:rgba(200,162,74,0.18); border-color:var(--gold-edge,rgba(200,162,74,0.5)); color:var(--gold,#C8A24A); }
.poll-tog.on::before { content:'✓ '; }
/* Minimized floating chip. */
.poll-chip { position:fixed; inset-inline-end:12px; bottom:calc(76px + env(safe-area-inset-bottom,0px)); z-index:28;
    padding:9px 15px; border-radius:20px; background:var(--gold,#C8A24A); color:#0E1013; font-weight:700; font-size:13.5px;
    box-shadow:0 8px 28px rgba(0,0,0,0.45); }

/* invite-to-speak banner (non-blocking, top) */
.speak-invite { position:fixed; top:0; inset-inline:0; z-index:90; display:flex; align-items:center; gap:10px;
    padding:12px 16px; padding-top:max(12px,env(safe-area-inset-top));
    background:rgba(18,18,26,0.97); backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
    border-bottom:1px solid rgba(47,123,255,0.5); box-shadow:0 8px 24px rgba(0,0,0,.4);
    animation:si-down .3s cubic-bezier(.22,1,.36,1); }
@keyframes si-down { from{transform:translateY(-100%);} to{transform:none;} }
.speak-invite .si-text { flex:1; font-size:14px; font-weight:600; color:#e8eaf6; }
.speak-invite .si-accept { padding:9px 18px; border-radius:20px; background:#2f7bff; color:#fff; font-weight:700; font-size:14px; }
.speak-invite .si-accept:active { transform:scale(.95); }
.speak-invite .si-later { padding:9px 14px; border-radius:20px; background:rgba(255,255,255,0.08); color:#a0a4c0; font-weight:600; font-size:14px; }

/* U3: mic-permission primer + denial-recovery popup. One shared centered card (#permCard) —
   primer and recovery are mutually exclusive. RTL-safe: logical properties only. */
.perm-card-wrap { position:fixed; inset:0; z-index:9991; display:flex; align-items:center; justify-content:center;
    padding:20px; background:rgba(8,8,12,0.55); backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px); }
.perm-card { display:flex; flex-direction:column; gap:12px; width:min(92vw,340px); padding:20px 18px;
    background:rgba(20,20,26,0.97); border:1px solid var(--gold-edge,rgba(200,162,74,0.42)); border-radius:18px;
    box-shadow:0 12px 44px rgba(0,0,0,0.5); text-align:center;
    animation:permPop .24s var(--ease-stage,cubic-bezier(.2,.7,.2,1)) both; }
@keyframes permPop { from{opacity:0; transform:scale(.92);} to{opacity:1; transform:none;} }
.perm-text { font-size:15px; font-weight:700; line-height:1.7; color:#F5F2EA; unicode-bidi:plaintext; }
.perm-steps { font-size:13.5px; font-weight:500; line-height:1.9; color:#c5c7df; unicode-bidi:plaintext; }
.perm-go { padding:12px 18px; border-radius:999px; background:var(--gold,#C8A24A); color:#0E1013; font-weight:700; font-size:14.5px; }
.perm-go:active { transform:scale(.97); }
.perm-later { padding:9px 14px; border-radius:999px; background:rgba(255,255,255,0.08); color:#a0a4c0; font-weight:600; font-size:13.5px; }
@media (prefers-reduced-motion: reduce) { .perm-card { animation:none; } }

/* U5: unmuted-iOS warning pill — small, persistent, dismissible (priority 'pill':
   actionable banners sit at z 9990+ AND the registry hides the pill when one shows).
   RTL-safe: logical properties only. */
.ios-mic-pill { position:fixed; inset-block-start:max(8px,env(safe-area-inset-top)); inset-inline:0;
    margin-inline:auto; width:max-content; max-width:90vw; z-index:9985;
    display:flex; align-items:center; gap:10px; padding:9px 14px; border-radius:10px;
    background:rgba(24,24,30,0.92); border:1px solid rgba(255,255,255,0.12);
    appearance:none; -webkit-appearance:none; cursor:pointer; font:inherit; text-align:start;
    box-shadow:0 2px 10px rgba(0,0,0,0.3); }
.ios-mic-pill[hidden] { display:none !important; }
.ios-mic-pill .imp-text { font-size:12.5px; font-weight:500; line-height:1.5; color:#cdd1da; unicode-bidi:plaintext; }
.ios-mic-pill .imp-x { flex:0 0 auto; color:#8b8f9c; font-size:13px; line-height:1; }
.ios-mic-pill:active { opacity:.7; }

/* U5: podium mode — full-black OLED screen-keeper. The WHOLE surface is the exit
   tap target; label stays dim (~35%) so the panel emits almost no light. Above the
   banners (9990s) but BELOW the terminal notices (99999) so «انتهى اللقاء» always wins. */
.podium-overlay { position:fixed; inset:0; z-index:99980; display:flex; flex-direction:column;
    align-items:center; justify-content:center; gap:12px; background:#000; opacity:.97;
    cursor:pointer; -webkit-tap-highlight-color:transparent; }
.podium-label { color:rgba(245,242,234,0.35); font-size:16px; font-weight:600; line-height:1.9;
    text-align:center; padding:0 24px; unicode-bidi:plaintext; }
.podium-sub { color:rgba(245,242,234,0.22); font-size:13px; font-weight:500; }

/* U8: phantom-speaker badge «متوقف مؤقتًا» — server-verified "unmuted but the room
   can't hear them" state (usually backgrounded). Small amber pill pinned to the
   bottom of the stage tile (tiles are position:relative); the avatar dims so the
   state reads at a glance. RTL-safe: logical properties only. */
.speaker-tile.is-phantom .avatar { filter:grayscale(.55) brightness(.78); }
.phantom-badge { position:absolute; inset-block-end:6px; inset-inline:0; margin-inline:auto;
    width:max-content; max-width:94%; padding:2px 9px; border-radius:999px; z-index:6;
    background:rgba(166,108,20,0.94); border:1px solid rgba(255,255,255,0.28); color:#fff;
    font-size:10.5px; font-weight:700; line-height:1.7; pointer-events:none;
    unicode-bidi:plaintext; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
@media (max-width: 480px) { .phantom-badge { font-size:10px; padding:2px 7px; } }

/* targeted-reaction picker row (inside the action sheet) */
.react-picker { display:flex; justify-content:center; gap:6px; flex-wrap:wrap; padding:8px 4px 12px; border-bottom:1px solid rgba(255,255,255,0.08); margin-bottom:6px; }
.react-opt { width:44px; height:44px; border-radius:50%; background:rgba(255,255,255,0.06); font-size:22px; display:flex; align-items:center; justify-content:center; transition:transform .1s, background .18s; }
.react-opt:hover { background:rgba(255,255,255,0.12); }
.react-opt:active { transform:scale(.85); }

/* targeted reaction overlays on tiles (tiles are position:relative) */
.tile-react-s { position:absolute; bottom:32%; font-size:22px; pointer-events:none; z-index:6; animation:tr-rise 5s ease-out forwards; }
@keyframes tr-rise { 0%{opacity:0;transform:translateY(0) scale(.6);} 12%{opacity:1;} 70%{opacity:1;} 100%{opacity:0;transform:translateY(-110px) scale(1);} }
.tile-react-b { position:absolute; top:48%; left:50%; transform:translate(-50%,-50%); font-size:54px; pointer-events:none; z-index:7; filter:drop-shadow(0 2px 7px rgba(0,0,0,.65)); animation:tr-pop 7s ease-out forwards; }
@keyframes tr-pop {
    0%{opacity:0;transform:translate(-50%,-50%) scale(.3);}
    8%{opacity:1;transform:translate(-50%,-50%) scale(1.3);}
    16%{transform:translate(-50%,-50%) scale(1);}
    88%{opacity:1;transform:translate(-50%,-50%) scale(1);}
    100%{opacity:0;transform:translate(-50%,-50%) scale(1.08);}
}

@media (prefers-reduced-motion: reduce) {
    .chat-panel, .sheet-card, .chat-msg, .chat-badge, .speak-invite { transition:none !important; animation:none !important; }
    .tile-react-s { animation-duration:.01s !important; }
    /* show the big targeted emoji statically (no motion) for its full lifetime instead of flashing away */
    .tile-react-b { animation:none !important; }
}

/* ============================================================ Presenter Gadget
   Editorial-salon aesthetic: charcoal canvas, gold spine, paper-grain backdrop.
   Phase 1 ships image mode; video/link rules will graft onto this shell. */
:root {
    --ink: #0E1013;
    --ink-2: #15171D;
    --ink-3: #1D2029;
    --paper: #F5F2EA;
    --gold: #C8A24A;
    --gold-soft: rgba(200,162,74,0.18);
    --gold-edge: rgba(200,162,74,0.42);
    --cyan: #45C2FF;
    --rule: rgba(245,242,234,0.08);
    --rule-strong: rgba(245,242,234,0.16);
    --ink-mute: rgba(245,242,234,0.56);
    --shadow-edit: 0 18px 60px rgba(0,0,0,0.55), 0 1px 0 rgba(255,255,255,0.04) inset;
    --ease-stage: cubic-bezier(0.2, 0.7, 0.2, 1);
    --font-display: 'Aref Ruqaa', 'Noto Kufi Arabic', serif;
    --font-ui: 'Readex Pro', 'Noto Kufi Arabic', sans-serif;
}

/* The gadget claims the audience's vertical space when active (audience is
   hidden on mobile and dimmed-but-scrollable on desktop). */
.presenter-gadget {
    position: relative;
    display: none;
    flex-direction: row;
    min-height: 0;
    flex: 1;
    background: var(--ink-2);
    background-image:
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.96  0 0 0 0 0.95  0 0 0 0 0.92  0 0 0 0.06 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
    background-size: 160px 160px;
    box-shadow: var(--shadow-edit);
    isolation: isolate;
    animation: pgRise 280ms var(--ease-stage) both;
}
.presenter-gadget[aria-hidden="false"] { display: flex; }
@keyframes pgRise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* Drag-to-expand grab handle — sits at the very top of the gadget, spanning
   the full width. The gadget becomes a flex-column shell: grab on top, body
   (spine + frame) below. The .pg-body wrapper preserves the old desktop
   row layout of spine + frame; on mobile it collapses to a column. The
   resize is local-only (each viewer adjusts their own view) and resets at
   the start of every new share. */
.presenter-gadget { flex-direction: column; }
.pg-body {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
    flex-direction: row;
}
@media (max-width: 700px) {
    .pg-body { flex-direction: column; }
}
.pg-grab {
    flex: 0 0 14px;
    width: 100%;
    display: flex; align-items: center; justify-content: center;
    cursor: ns-resize;
    background: var(--ink-3);
    border-block-end: 1px solid var(--rule);
    touch-action: none;
    user-select: none;
    transition: background 180ms;
}
.pg-grab:hover, .pg-grab.is-dragging { background: var(--gold-soft); }
.pg-grab-pill {
    width: 36px; height: 4px; border-radius: 999px;
    background: var(--gold-edge);
    box-shadow: 0 0 0 1px rgba(0,0,0,0.18);
}
.pg-grab:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }

/* Spine — the gold-anchored identity strip on the start edge (right in RTL).
   On mobile it collapses to a horizontal strip above the frame. */
.pg-spine {
    flex: 0 0 56px;
    display: flex; flex-direction: column; align-items: center;
    padding: 16px 0; gap: 18px;
    border-inline-end: 1px solid var(--gold-edge);
    background: linear-gradient(180deg, var(--ink-3), transparent 80%);
    animation: pgFadeIn 280ms var(--ease-stage) both;
}
@keyframes pgFadeIn { from { opacity: 0; } to { opacity: 1; } }
.pg-spine-glyph { font-size: 22px; color: var(--gold); line-height: 1; font-family: var(--font-display); }
.pg-spine-avatar {
    width: 40px; height: 40px; border-radius: 50%; object-fit: cover;
    border: 1px solid var(--gold-edge); background: var(--ink-3);
    transition: opacity 200ms;
}
.pg-spine-thread { flex: 1; width: 1px; background: var(--gold-edge); }

/* Frame: head + stage column. min-height:0 lets the stage shrink properly
   instead of being pushed down by the head's intrinsic height (which created
   a large empty band above the image on mobile). */
.pg-frame {
    flex: 1; min-width: 0; min-height: 0;
    display: flex; flex-direction: column;
    animation: pgFadeIn 280ms 80ms var(--ease-stage) both;
}
.pg-frame-head {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 18px;
    border-block-end: 1px solid var(--rule);
}
.pg-mode-label {
    font-family: var(--font-display);
    font-size: 18px; font-weight: 700; color: var(--paper); letter-spacing: 0.2px;
}
.pg-presenter {
    font-family: var(--font-ui);
    font-size: 14px; color: var(--ink-mute);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pg-tools { display: flex; gap: 6px; margin-inline-start: auto; }
/* Close/end-share — a clear, LABELLED red pill («✕ إغلاق المشاركة») so it's
   unmistakably the way OUT of the share. It sits on the header's top line,
   pushed to the end (the empty corner); the tool rail wraps onto the line below. */
.pg-close {
    width: auto; min-width: max-content; height: 36px;
    padding: 0 16px; border-radius: 999px;
    display: inline-flex; align-items: center; gap: 7px;
    background: rgba(229,68,68,0.18); color: #ff6b6b;
    border: 1px solid rgba(229,68,68,0.55);
    font-family: var(--font-ui); font-size: 13.5px; font-weight: 700;
    line-height: 1; white-space: nowrap;
    margin-inline-start: auto; flex-shrink: 0;
    transition: background 160ms, color 160ms, transform 100ms, box-shadow 160ms;
}
.pg-close:hover { background: #e54444; color: #fff; border-color: #e54444; box-shadow: 0 6px 16px -8px rgba(229,68,68,.9); }
.pg-close:active { transform: scale(.96); }

.pg-stage {
    position: relative; flex: 1; min-height: 0; overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    padding: 18px;
    animation: pgFadeIn 280ms 140ms var(--ease-stage) both;
}

/* Both mode containers use an explicit `display`, which means the default
   `[hidden] { display:none }` UA rule gets out-specificity'd — when both
   surfaces have `hidden` attr the cream passe-partout was still flexing in
   alongside the letterbox. Explicit attribute-selector override fixes it. */
.pg-passe-partout[hidden],
.pg-letterbox[hidden] { display: none !important; }

/* Image mode — passe-partout (matted print) treatment. Fills the entire
   stage so the cream mat IS the canvas, eliminating the dark gap above
   the image that appeared when the passe-partout was content-sized. */
.pg-passe-partout {
    position: relative;
    background: var(--paper);
    padding: 12px;
    border: 1px solid var(--gold-edge);
    box-shadow: 0 12px 40px rgba(0,0,0,0.45);
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
}
.pg-image {
    /* Parent-relative cap — viewport-relative calc broke mobile when the
       tool rail head took too much vertical space; the image overflowed
       .pg-stage and got clipped to invisibility. */
    display: block;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    pointer-events: none;
}
/* PDF mode (S1) — full-width, scrollable page for mobile readability. The page fills
   the width (tall pages scroll vertically); zoom widens the image and the container
   pans via native scroll. Annotation canvases are hidden (PDF has none). Scoped to
   [data-mode="pdf"] so image/video/link rendering is untouched. */
.presenter-gadget[data-mode="pdf"] .pg-passe-partout {
    display: block;            /* not flex — a zoomed/tall page scrolls from the top-left */
    overflow: auto;
    padding: 66px 0 calc(72px + env(safe-area-inset-bottom, 0px));   /* clear the top deck; generous bottom margin so the last line isn't flush to the edge */
    -webkit-overflow-scrolling: touch;
    touch-action: pan-x pan-y; /* native 1-finger scroll; 2-finger pinch handled in JS */
}
.presenter-gadget[data-mode="pdf"] .pg-image {
    width: 100%;
    height: auto;
    max-width: none;           /* allow >100% width when zoomed */
    max-height: none;
    object-fit: initial;
    display: block;
}
/* PDF annotation: the canvases overlay the scrollable page (sized + positioned by
   sizePdfCanvas so they pan + zoom WITH it). Drawing is opt-in via the tool rail; the
   default 'interact' tool keeps the canvas pointer-events:none so pan/zoom passes through. */
.presenter-gadget[data-mode="pdf"] .pg-canvas,
.presenter-gadget[data-mode="pdf"] .pg-canvas-preview { display: block; }
/* Canvas + preview canvas overlay the image's actual rendered box. Position
   is set by JS (sizeCanvas) to match `img.getBoundingClientRect()` relative
   to the passe-partout, so strokes always align with the image even when
   object-fit:contain creates cream-mat margins around it. */
.pg-canvas {
    position: absolute;
    pointer-events: none;
    touch-action: none;
}
.pg-pointer {
    position: absolute;
    width: 18px; height: 18px; border-radius: 50%;
    background: radial-gradient(circle, var(--gold) 0%, rgba(200,162,74,0) 70%);
    pointer-events: none;
    transform: translate(-50%, -50%);
    animation: pgPulse 1.2s ease-in-out infinite;
    will-change: transform, opacity;
}
@keyframes pgPulse {
    0%,100% { transform: translate(-50%,-50%) scale(0.85); opacity: 0.7; }
    50%     { transform: translate(-50%,-50%) scale(1.15); opacity: 1.0; }
}

/* Share-type sheet — reuses the existing .sheet-card / .sheet-btn rules,
   but the title row gets the display font for the editorial tone. */
.sheet-share-title {
    font-family: var(--font-display);
    font-size: 17px; color: var(--paper);
    padding: 4px 0 12px; text-align: center;
}

/* Entry button — the ▣ frame glyph in center-controls */
.btn-share-entry {
    width: 44px; height: 44px; border-radius: 50%;
    background: var(--ink-3);
    color: var(--gold);
    border: 1px solid var(--gold-edge);
    font-size: 22px; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    transition: background 200ms, transform 100ms;
}
.btn-share-entry:hover { background: var(--gold-soft); }
.btn-share-entry:active { transform: scale(.94); }
.btn-share-entry.is-ending { color: #ff8a8a; border-color: rgba(255,138,138,0.4); }

/* Mobile: spine becomes a row across the top; audience hidden while sharing. */
@media (max-width: 700px) {
    .presenter-gadget { flex-direction: column; }
    .pg-spine {
        flex: 0 0 auto;
        flex-direction: row; padding: 10px 14px; gap: 12px;
        width: 100%;
        border-inline-end: none;
        border-block-end: 1px solid var(--gold-edge);
    }
    .pg-spine-thread { display: none; }
    .pg-image { max-height: 100%; }
    /* On phones the rail leaves the header and DOCKS to the bottom of the
       gadget (thumb reach). The gadget is position:relative and fills the area
       above the bottom-bar, so an absolute dock here floats just above the bar
       — no overlap, no fixed/backdrop-filter containing-block trap. Grouped to
       ~5 controls so it never needs to scroll. Popovers open UPWARD. */
    .pg-frame-head { flex-wrap: nowrap; }
    .app-container.has-share .pg-tools,
    .app-container:has(.presenter-gadget[aria-hidden="false"]) .pg-tools {
        position: absolute; z-index: 26; bottom: 12px; inset-inline: 10px; margin-inline-start: 0;
        justify-content: center; gap: 10px; overflow: visible; flex-wrap: nowrap;
        background: rgba(15,17,23,0.9); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
        border: 1px solid var(--rule-strong); border-radius: 18px;
        padding: 8px 10px max(8px, env(safe-area-inset-bottom, 0px));
    }
    .app-container.has-share .pg-tools .pg-pop,
    .app-container:has(.presenter-gadget[aria-hidden="false"]) .pg-tools .pg-pop {
        top: auto; bottom: calc(100% + 8px);
    }
    /* ≥40px touch targets on the dock; the take-pen pill stays auto-width. */
    .app-container.has-share .pg-tool,
    .app-container:has(.presenter-gadget[aria-hidden="false"]) .pg-tool { width: 40px; height: 40px; font-size: 17px; }
    /* Hide the audience section while a share is active so the gadget gets
       the full remaining height. Two selectors for browser support:
       :has() works on Chrome 105+/Safari 15.4+/Firefox 121+; the .has-share
       class is toggled by JS in renderShare/teardownShare as a fallback. */
    .app-container:has(.presenter-gadget[aria-hidden="false"]) .roster-scroll,
    .app-container.has-share .roster-scroll {
        display: none;
    }
    /* Tighten the stage padding on mobile so the image gets a bit more area. */
    .pg-stage { padding: 8px; }
    .pg-frame-head { padding: 10px 12px; }
    /* The inline step-down arrow is moved into the more menu on mobile to
       save the always-crowded bottom-bar real estate. */
    #btnStepDown { display: none !important; }
    /* iPhone-SE-tight bottom dock. Width budget: 375px viewport - 16px
       horizontal padding = 359px usable. Reactions (3 × 38 + 2 × 3 = 120) +
       mic pill 52 + chat 44 + more 44 + 4 inter-group gaps × 4 = 276px.
       Comfortable on 375; loose on 390 (iPhone 13 Pro). Touch targets are
       bumped to 44px for chat / more (Apple HIG); reactions stay at 38px
       (acceptable as a tertiary emoji rail per HIG when grouped). */
    .bottom-bar { gap: 4px; padding: 8px 10px; padding-bottom: max(8px, env(safe-area-inset-bottom)); }
    .btn-mic-pill { width: 52px; height: 52px; font-size: 22px; }
    .btn-chat, .btn-share-entry { width: 44px; height: 44px; font-size: 18px; }
    .btn-action { padding: 10px 14px; min-height: 44px; }
    .btn-react-trigger { width: 38px; height: 38px; font-size: 20px; }
    .reactions-buttons { gap: 3px; }
    .react-menu-item { width: 44px; height: 44px; font-size: 28px; }
}

/* New mic control — icon-only circular pill, color-coded by state.
   Replaces the old "🎤 صامت" text-pill which was ~112px wide and overflowed
   the bottom bar on small phones, hiding the heart reaction. */
.btn-mic-pill {
    width: 56px; height: 56px;
    border-radius: 50%;
    border: none;
    display: inline-flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    font-size: 24px; line-height: 1;
    transition: background 200ms, transform 100ms, box-shadow 200ms;
    cursor: pointer;
}
.btn-mic-pill:active { transform: scale(.94); }
/* States — distinct colors give the speaker an at-a-glance read. */
.btn-mic-pill.is-pre    { background: #2f7bff; color: #fff;    box-shadow: 0 4px 16px rgba(47,123,255,0.28); }
.btn-mic-pill.is-on     { background: #34d399; color: #0f1117; box-shadow: 0 4px 16px rgba(52,211,153,0.28); }
.btn-mic-pill.is-muted  { background: #ef4444; color: #fff;    box-shadow: 0 4px 16px rgba(239,68,68,0.28); }
.btn-mic-pill.is-pre:hover    { background: #2563eb; }
.btn-mic-pill.is-on:hover     { background: #22c993; }
.btn-mic-pill.is-muted:hover  { background: #dc2626; }

/* ============================================================ Phase 3 — Video
   Cinematic letterbox: 16:9 black backdrop, max 1000px wide, with provider
   iframe (YouTube / Vimeo) or native <video> mounted inside. The duck moon
   sits at the bottom-end; the cyan drift-sweep is a 2px line that animates
   left-to-right when an audience client just re-synced to the speaker. */
.pg-letterbox {
    position: relative;
    background: #000;
    aspect-ratio: 16 / 9;
    width: 100%;
    max-width: 1000px;
    margin: auto;
    border-radius: 6px;
    overflow: hidden;
    box-shadow: 0 12px 40px rgba(0,0,0,0.55);
    animation: pgFadeIn 280ms 80ms var(--ease-stage) both;
}
.pg-video-mount {
    position: absolute; inset: 0;
    background: #000;
}
.pg-video-mount iframe,
.pg-video-mount video {
    width: 100%; height: 100%;
    border: 0;
    display: block;
}

/* Annotation overlay above the iframe. Stays click-through (none) so the
   YouTube player keeps control of its own taps; the moment the pointer
   owner picks a draw tool (pen / highlight / shape / eraser) we add
   .is-drawing and the canvas intercepts. */
.pg-video-canvas {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    pointer-events: none;
    /* In interact mode the canvas is touch-transparent so taps on the play
       button / YouTube controls reach the iframe underneath. Mobile browsers
       (iOS Safari + some Chromium variants) treat `touch-action:none` as a
       gesture claim and refuse to forward the touch sequence even when
       `pointer-events` is none — so the default must be `auto`. The drawing
       modes opt back into `touch-action:none` below to block scroll while a
       stroke is in progress. */
    touch-action: auto;
    z-index: 2;
}
.pg-video-canvas.is-drawing {
    pointer-events: auto;
    cursor: crosshair;
    touch-action: none;
}
.pg-video-canvas.is-drawing.tool-eraser { cursor: cell; }
.pg-video-canvas.is-drawing.tool-pointer { cursor: none; }
/* The preview overlay sits above the committed strokes — never intercepts. */
.pg-video-canvas-preview { pointer-events: none !important; z-index: 3; }
/* Smart-duck toggle — moon glyph that crossfades between 🌑 (full volume)
   and 🌒 (ducked, ~30% volume for audience). Only the share owner sees it. */
.pg-duck {
    position: absolute;
    bottom: 10px;
    inset-inline-end: 10px;
    width: 38px; height: 38px;
    border-radius: 50%;
    background: rgba(14, 16, 19, 0.6);
    color: var(--paper);
    font-size: 18px; line-height: 1;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--rule-strong);
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer;
    z-index: 3;
    transition: background 200ms, transform 240ms;
}
.pg-duck:hover { background: rgba(14, 16, 19, 0.8); }
.pg-duck:active { transform: scale(.92); }
.pg-duck.is-ducked { color: var(--gold); transform: rotate(-12deg); }

/* Drift sweep — a thin cyan line that fills bottom-to-top of the letterbox
   when the audience player auto-seeks to catch the speaker. Adding
   .is-drifting triggers it; the class is removed after the animation. */
.pg-drift-sweep {
    position: absolute;
    bottom: 0; inset-inline-start: 0;
    width: 0; height: 2px;
    background: var(--cyan);
    pointer-events: none;
    z-index: 2;
}
.pg-letterbox.is-drifting .pg-drift-sweep {
    width: 100%;
    transition: width 400ms var(--ease-stage);
}

/* Live-stream badge — for YouTube live where seek doesn't work. */
.pg-live-badge {
    position: absolute;
    top: 10px;
    inset-inline-end: 10px;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(239, 68, 68, 0.92);
    color: #fff;
    font-family: var(--font-ui);
    font-size: 11px; font-weight: 600;
    letter-spacing: 0.4px;
    z-index: 3;
}

/* PDF page-as-image mode — a clear, always-visible control bar floated bottom-center over
   the page. Two zones: ZOOM (−/⤢/＋ — shown to everyone; zoom is local per-viewer) and PAGER
   (‹ count › — prev/next for the share authority only, count for everyone). The old bar was
   a 60%-transparent pill with hairline-only buttons that blended into the bright full-width
   page and was easy to miss — now it's solid dark glass with filled chip buttons so it reads
   unmistakably. RTL: «التالي» (next) advances leftward. */
.pg-pdf-nav {
    position: absolute;
    top: 12px;                 /* deck floats at the TOP so it doesn't block the page */
    left: 50%; transform: translateX(-50%); /* symmetric centering — safe in RTL & LTR */
    display: flex; align-items: center; gap: 5px;
    padding: 5px;
    border-radius: 999px;
    background: rgba(12, 13, 16, 0.92);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid rgba(255, 255, 255, 0.16);
    box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.75);
    z-index: 5;
    max-width: calc(100% - 24px);
}
.pg-pdf-zoom, .pg-pdf-pager { display: flex; align-items: center; gap: 4px; }
/* RTL pagination must read «‹ ›» (next on the LEFT, prev on the RIGHT). Lock the visual order
   regardless of inherited direction so it's deterministic. */
.pg-pdf-pager { direction: ltr; }
.pg-pdf-pager #pgPdfNext { order: 0; }   /* LEFT  — ‹ (next/التالي) */
.pg-pdf-pager #pgPdfPrev { order: 1; }   /* RIGHT — › (prev/السابقة) */
.pg-pdf-btn {
    width: 42px; height: 42px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
    color: #eef0fb;
    font-size: 22px; line-height: 1; font-weight: 600;
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: background 180ms, transform 120ms;
}
.pg-pdf-btn:hover { background: rgba(255, 255, 255, 0.16); }
.pg-pdf-btn:active { transform: scale(.9); }
.pg-pdf-btn:disabled { opacity: .3; cursor: default; }
.pg-pdf-fit { font-size: 19px; }
.pg-pdf-count {
    font-family: var(--font-ui);
    font-size: 13px; font-weight: 700;
    color: #eef0fb;
    padding: 0 10px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    border-inline: 1px solid rgba(255, 255, 255, 0.12);   /* hairline divider between the two zones */
}
.pg-pdf-prep {
    position: absolute;
    top: calc(100% + 8px); left: 50%; transform: translateX(-50%);   /* below the top-docked bar */
    font-family: var(--font-ui);
    font-size: 12px; color: #dfe2f5;
    background: rgba(12, 13, 16, 0.92);
    border: 1px solid rgba(255, 255, 255, 0.14);
    padding: 5px 12px; border-radius: 999px;
    white-space: nowrap;
    box-shadow: 0 8px 24px -10px rgba(0, 0, 0, 0.7);
}
/* Author display:flex/inline-flex above out-specificities the UA [hidden] rule (same pitfall
   as .pg-passe-partout[hidden] earlier) — restore hide-on-attribute. */
/* Jump-to-page input (presenter only) — type a page number instead of tapping dozens of times. */
.pg-pdf-input {
    width: 54px; height: 38px; border-radius: 11px; text-align: center;
    background: rgba(255, 255, 255, 0.08); color: #eef0fb;
    border: 1px solid rgba(255, 255, 255, 0.16);
    font: 700 14px/1 var(--font-ui); font-variant-numeric: tabular-nums;
}
.pg-pdf-input:focus { outline: none; border-color: rgba(255, 255, 255, 0.4); background: rgba(255, 255, 255, 0.14); }
.pg-pdf-input::-webkit-outer-spin-button, .pg-pdf-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pg-pdf-nav[hidden], .pg-pdf-btn[hidden], .pg-pdf-input[hidden], .pg-pdf-prep[hidden] { display: none !important; }
@media (max-width: 700px) {
    /* Full-width bar so the prev/next pager can NEVER be clipped off the edges of the
       centered pill — on narrow phones the desktop pill overflowed and the arrows
       (at the RTL ends) were pushed out of view while the centered count stayed. */
    .pg-pdf-nav {
        left: 8px; right: 8px; transform: none; max-width: none;
        top: 10px; gap: 6px 4px; padding: 5px 8px;
        justify-content: center; flex-wrap: wrap;
    }
    .pg-pdf-btn { width: 40px; height: 40px; font-size: 20px; }
    .pg-pdf-count { font-size: 12px; padding: 0 7px; }
}

@media (max-width: 700px) {
    .pg-letterbox { border-radius: 4px; }
    .pg-duck { width: 34px; height: 34px; font-size: 16px; bottom: 8px; }
    .pg-live-badge { top: 8px; font-size: 10px; padding: 3px 8px; }
}

/* ============================================================ Pen request
   Popup shown on the share creator's screen when a non-host stage member
   asks to take the pen. Stacks vertically if multiple arrive at once.
   Auto-expires after 30s (silent deny). */
#penRequests {
    position: fixed;
    top: 12px;
    /* RTL-safe horizontal centering: inset-inline-start:50% + translateX(-50%)
       double-bids in RTL because RTL flips the inline axis but translateX is
       physical, so the popup ends up off-centre. Instead, anchor both inline
       edges to 0 and let margin-inline:auto centre the box on the inline axis
       — works identically in LTR and RTL with no transform side-effects. */
    inset-inline-start: 0;
    inset-inline-end: 0;
    margin-inline: auto;
    display: flex; flex-direction: column; gap: 8px;
    z-index: 200;
    max-width: min(420px, 92vw);
    pointer-events: none; /* the children re-enable */
}
.pen-request {
    pointer-events: auto;
    background: rgba(14,16,19,0.94);
    border: 1px solid var(--gold-edge);
    border-radius: 16px;
    padding: 10px 14px;
    display: flex; align-items: center; gap: 10px;
    backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
    box-shadow: 0 10px 30px rgba(0,0,0,0.5);
    color: var(--paper);
    font-family: var(--font-ui);
    animation: pgRise 240ms var(--ease-stage) both;
}
.pen-request img {
    width: 36px; height: 36px;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--gold-edge);
    flex-shrink: 0;
    background: #2a2f4a;
}
.pen-request .pr-text {
    flex: 1; min-width: 0;
    font-size: 13.5px;
    line-height: 1.3;
    overflow: hidden; text-overflow: ellipsis;
    color: var(--paper);
}
.pen-request .pr-text strong { color: var(--gold); font-weight: 600; }
.pen-request button {
    padding: 7px 14px;
    border-radius: 16px;
    font-family: var(--font-ui);
    font-weight: 600;
    font-size: 12.5px;
    cursor: pointer;
    border: 1px solid transparent;
    transition: transform 100ms, background 180ms;
    flex-shrink: 0;
}
.pen-request button:active { transform: scale(.94); }
.pen-request .pr-grant {
    background: #34d399; color: #0f1117;
}
.pen-request .pr-grant:hover { background: #22c993; }
.pen-request .pr-deny {
    background: rgba(255,255,255,0.06);
    color: #ff8a8a;
    border-color: rgba(255,138,138,0.32);
}
.pen-request .pr-deny:hover { background: rgba(255,138,138,0.12); }

@media (max-width: 700px) {
    #penRequests { top: 8px; max-width: 96vw; }
    .pen-request { padding: 8px 10px; gap: 8px; }
    .pen-request img { width: 30px; height: 30px; }
    .pen-request .pr-text { font-size: 12.5px; }
    .pen-request button { padding: 6px 11px; font-size: 12px; }
}

/* ============================================================ Phase 6 — Pinned-link banner
   Editorial strip above the speaker tiles. Set by the host (administrator),
   appears for everyone in the room. Paper-grain backdrop with gold accents
   and Aref Ruqaa display title — same editorial-salon language as the
   presenter gadget so the meeting reads as one curated room.

   Layout: thin row, full width, fixed below the meeting header. Mobile
   collapses padding + truncates the description line. */
.pinned-link {
    position: relative;
    flex: 0 0 auto;
    display: flex; flex-direction: column;
    background:
      linear-gradient(180deg, rgba(200,162,74,0.04) 0%, transparent 60%),
      var(--ink);
    background-image:
      linear-gradient(180deg, rgba(200,162,74,0.04) 0%, transparent 60%),
      url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.96  0 0 0 0 0.95  0 0 0 0 0.92  0 0 0 0.04 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
    background-size: auto, 160px 160px;
    border-block-end: 1px solid var(--gold-edge);
    overflow: hidden;
    animation: pinSlideIn 320ms var(--ease-stage) both;
    z-index: 8;
}
.pinned-link[hidden] { display: none !important; }
@keyframes pinSlideIn {
    from { opacity: 0; transform: translateY(-12px); max-height: 0; }
    to   { opacity: 1; transform: none; max-height: 200px; }
}

/* Gold gradient hairline on the top edge — sweeps in once when pinned. */
.pl-rule {
    position: absolute;
    top: 0; inset-inline-start: 0;
    height: 2px; width: 100%;
    background: linear-gradient(90deg, transparent 0%, var(--gold) 30%, var(--gold) 70%, transparent 100%);
    transform-origin: center;
    animation: pinRule 700ms var(--ease-stage) both;
}
@keyframes pinRule {
    from { transform: scaleX(0); opacity: 0; }
    to   { transform: scaleX(1); opacity: 1; }
}

.pl-row {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 22px;
    max-width: 1100px;
    width: 100%;
    margin: 0 auto;
}

.pl-leading {
    display: flex; align-items: center; gap: 14px;
    flex: 1; min-width: 0;
}

/* The pin glyph wobbles softly the first time the banner appears. */
.pl-pin {
    font-size: 22px;
    line-height: 1;
    flex-shrink: 0;
    animation: pinWobble 1.6s var(--ease-stage) both;
    filter: drop-shadow(0 0 6px rgba(200,162,74,0.45));
}
@keyframes pinWobble {
    0%   { transform: rotate(-30deg) scale(0.6); opacity: 0; }
    40%  { transform: rotate(10deg) scale(1.18); opacity: 1; }
    60%  { transform: rotate(-6deg) scale(1); }
    80%  { transform: rotate(3deg); }
    100% { transform: rotate(0deg); }
}

.pl-text {
    display: flex; flex-direction: column; gap: 2px;
    min-width: 0;
}
.pl-eyebrow {
    font-family: var(--font-ui);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: var(--gold);
    line-height: 1;
}
.pl-title {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 700;
    color: var(--paper);
    line-height: 1.35;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 1;
    line-clamp: 1;
    -webkit-box-orient: vertical;
    transition: color 180ms;
}
.pl-title:hover { color: var(--gold); }
.pl-title:empty::before { content: 'ملاحظة من المسؤول'; color: var(--ink-mute); }

.pl-host {
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 400;
    color: var(--ink-mute);
    line-height: 1;
    letter-spacing: 0.2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.pl-host:empty { display: none; }

.pl-trailing {
    display: flex; align-items: center; gap: 8px;
    flex-shrink: 0;
}

/* Solid gold "افتح ↗" pill — high contrast against the dark backdrop. */
.pl-open {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 8px 16px;
    border-radius: 999px;
    background: var(--gold);
    color: var(--ink);
    font-family: var(--font-ui);
    font-weight: 600;
    font-size: 13px;
    text-decoration: none;
    box-shadow: 0 4px 14px rgba(200,162,74,0.32);
    transition: background 180ms, transform 100ms;
    white-space: nowrap;
}
.pl-open:hover { background: #D7B560; }
.pl-open:active { transform: scale(.96); }

/* × shown only to the host. */
.pl-close {
    width: 32px; height: 32px;
    border-radius: 50%;
    background: transparent;
    color: var(--ink-mute);
    font-size: 18px; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background 180ms, color 180ms;
}
.pl-close:hover { background: var(--gold-soft); color: var(--gold); }
.pl-close[hidden] { display: none !important; }

@media (max-width: 700px) {
    .pl-row { padding: 10px 14px; gap: 10px; }
    .pl-leading { gap: 10px; }
    .pl-pin { font-size: 18px; }
    .pl-title { font-size: 14.5px; line-height: 1.3; }
    .pl-eyebrow { font-size: 9px; letter-spacing: 2px; }
    .pl-host { font-size: 10px; }
    .pl-open { padding: 7px 12px; font-size: 12px; }
    .pl-close { width: 28px; height: 28px; font-size: 16px; }
}

/* ============================================================ Phase 4 — Link
   Two render paths: an embedded iframe when X-Frame-Options + CSP frame-
   ancestors allow it, or a curated editorial card when they don't. The card
   is the editorial-salon centerpiece — eyebrow + Aref Ruqaa title + gold
   hairline + Readex Pro description + a single typographic action link. */

/* Embedded in-meet browser — iframe is always loaded via the server-side
   proxy so X-Frame-Options of the origin site doesn't block embedding.
   Two overlay canvases give the speaker the same draw tools as image/video. */
.pg-link-frame {
    position: relative;
    width: 100%; height: 100%;
    background: var(--ink-2);
    border-radius: 6px;
    overflow: hidden;
    box-shadow: 0 12px 40px rgba(0,0,0,0.55);
    animation: pgFadeIn 280ms 80ms var(--ease-stage) both;
}
.pg-link-frame[hidden] { display: none !important; }
.pg-iframe {
    /* JS (fitLink) sets width/height to the presenter's fixed logical viewport and a
       translate()+scale() transform to letterbox it; position:absolute makes the translate
       offset measure from the frame's top-left. Fallback 100%/100% before fitLink runs. */
    position: absolute; top: 0; left: 0;
    width: 100%; height: 100%;
    border: 0;
    background: var(--ink-2);
    display: block;
}

/* Annotation canvases over the iframe. Default: pointer-events:none so the
   page receives scrolls/clicks; toggle .is-drawing for the pen-style tools. */
.pg-link-canvas {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    pointer-events: none;
    touch-action: none;
    z-index: 2;
}
.pg-link-canvas.is-drawing { pointer-events: auto; cursor: crosshair; }
.pg-link-canvas.is-drawing.tool-eraser { cursor: cell; }
.pg-link-canvas.is-drawing.tool-pointer { cursor: none; }
.pg-link-canvas-preview { pointer-events: none !important; z-index: 3; }

/* "Open in new tab" pill — compact glyph for the share owner, wider labeled
   pill for audience (since they cannot scroll the embed independently, this
   is their escape hatch to read the page on their own). */
.pg-link-newtab {
    position: absolute;
    top: 10px; inset-inline-end: 10px;
    height: 34px;
    min-width: 34px;
    padding: 0;
    border-radius: 999px;
    background: rgba(14,16,19,0.72);
    color: var(--gold);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--gold-edge);
    display: inline-flex; align-items: center; justify-content: center;
    gap: 6px;
    font-size: 14px;
    font-family: var(--font-ui);
    font-weight: 500;
    text-decoration: none;
    z-index: 4;
    transition: background 200ms, transform 100ms, padding 200ms;
}
.pg-link-newtab:hover { background: rgba(14,16,19,0.92); color: var(--paper); }
.pg-link-newtab:active { transform: scale(.96); }
/* Audience escape pill — solid gold on charcoal text so it stays unmistakable
   regardless of the iframe's background colour underneath. */
.pg-link-newtab.is-audience {
    padding: 0 16px;
    font-size: 13px;
    font-weight: 600;
    background: var(--gold);
    color: var(--ink);
    border-color: var(--gold);
    box-shadow: 0 4px 14px rgba(0,0,0,0.35);
}
.pg-link-newtab.is-audience:hover {
    background: #D7B560;
    color: var(--ink);
}
.pg-link-newtab.is-audience::before {
    content: 'افتح في تبويب جديد';
}
@media (max-width: 700px) {
    .pg-link-newtab.is-audience { font-size: 12px; padding: 0 12px; height: 30px; }
}

/* Editorial card — used when the URL refuses framing.
   Layered ❝ glyph behind the title for the curated-magazine feel. */
.pg-link-card {
    position: relative;
    max-width: 560px;
    margin: auto;
    padding: 28px 32px 24px;
    background: var(--ink-3);
    border: 1px solid var(--gold-edge);
    border-radius: 12px;
    box-shadow: var(--shadow-edit);
    overflow: hidden;
    isolation: isolate;
    animation: pgFadeIn 280ms 80ms var(--ease-stage) both;
}
.pg-link-card[hidden] { display: none !important; }
.pg-link-card::before {
    content: '❝';
    position: absolute;
    inset-inline-start: -8px;
    top: -28px;
    font-size: 140px;
    line-height: 1;
    font-family: var(--font-display);
    color: var(--gold-soft);
    pointer-events: none;
    z-index: 0;
}
.pg-link-card > * { position: relative; z-index: 1; }

.pg-link-eyebrow {
    display: block;
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--gold);
    margin-bottom: 10px;
}
.pg-link-eyebrow:empty { display: none; }

.pg-link-title {
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 700;
    line-height: 1.35;
    color: var(--paper);
    margin: 0 0 12px;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}
.pg-link-title::after {
    content: '';
    display: block;
    width: 56px;
    height: 1px;
    background: var(--gold);
    margin-top: 14px;
}

.pg-link-image {
    display: block;
    width: 100%;
    max-height: 220px;
    object-fit: cover;
    border-radius: 6px;
    margin: 16px 0 12px;
    background: var(--ink-2);
}

.pg-link-desc {
    font-family: var(--font-ui);
    font-size: 14.5px;
    font-weight: 300;
    line-height: 1.65;
    color: var(--ink-mute);
    margin: 0 0 18px;
}
.pg-link-desc:empty { display: none; }

.pg-link-open {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-ui);
    font-size: 14px;
    font-weight: 500;
    color: var(--gold);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    padding-bottom: 2px;
    transition: border-color 180ms, color 180ms;
}
.pg-link-open:hover { color: var(--paper); border-bottom-color: var(--gold); }
/* owner-only «try to embed anyway» escape hatch under the preview card */
.pg-link-tryembed {
    margin-top: 12px;
    font-family: var(--font-ui); font-size: 12.5px; font-weight: 500;
    color: rgba(245,242,234,0.7);
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.12); border-radius: 999px;
    padding: 7px 16px; cursor: pointer;
    transition: background 160ms, color 160ms, border-color 160ms;
}
.pg-link-tryembed:hover { background: rgba(255,255,255,0.12); color: var(--paper); border-color: rgba(255,255,255,0.22); }
.pg-link-tryembed[hidden] { display: none; }

@media (max-width: 700px) {
    .pg-link-card { padding: 20px 18px 16px; }
    .pg-link-card::before { font-size: 100px; top: -16px; }
    .pg-link-title { font-size: 21px; }
    .pg-link-desc { font-size: 13.5px; }
    .pg-link-image { max-height: 160px; }
}

@media (prefers-reduced-motion: reduce) {
    .presenter-gadget, .pg-spine, .pg-frame, .pg-stage,
    .pg-pointer, .pg-spine-avatar, .pg-close, .btn-share-entry {
        animation: none !important; transition: none !important;
    }
}

/* Phase 2 — Drawing tool rail + take-pointer affordance */
.pg-spine-avatar.is-pointer-owner {
    box-shadow: 0 0 0 2px var(--gold), 0 0 12px var(--gold-soft);
}
.pg-tools { display: flex; gap: 6px; align-items: center; }
.pg-tool {
    position: relative;   /* anchors the grouped-control popovers */
    width: 36px; height: 36px; border-radius: 10px;
    background: var(--ink-3);
    border: 1px solid var(--gold-edge);
    color: var(--paper);
    font-size: 16px; line-height: 1;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background 180ms, color 180ms, transform 100ms;
}
/* Grouped-control trigger (draw-tools, colour+width chip) + its popover. Only
   ONE popover is open at a time (JS enforces); outside-tap dismisses. Default
   opens downward (desktop rail sits at the top of the frame); the mobile dock
   flips it upward below. */
.pg-tool-group.pop-open { background: var(--gold-soft); border-color: var(--gold); }
.pg-chip-dot { width: 16px; height: 16px; border-radius: 50%; border: 1.5px solid rgba(245,242,234,0.55); display: block; }
.pg-pop {
    position: absolute; z-index: 60; top: calc(100% + 8px); inset-inline-end: 0; bottom: auto;
    background: rgba(20,20,26,0.98); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
    border: 1px solid var(--gold-edge); border-radius: 14px; padding: 8px;
    box-shadow: var(--shadow-edit); display: flex; flex-direction: column; gap: 8px;
    animation: pgFadeIn 140ms var(--ease-stage) both;
}
.pg-pop-grid { display: grid; grid-template-columns: repeat(4, 40px); gap: 6px; }
.pg-pop-swatches { display: flex; gap: 8px; }
.pg-pop-widths { display: flex; gap: 10px; justify-content: center; align-items: center; border-block-start: 1px solid var(--rule); padding-block-start: 8px; }
.pg-tool:hover { background: var(--gold-soft); }
.pg-tool:active { transform: scale(.94); }
.pg-tool.is-active { background: var(--gold); color: var(--ink); border-color: var(--gold); }
.pg-tool.is-disabled { opacity: 0.35; pointer-events: none; }
.pg-tool-divider { width: 1px; height: 22px; background: var(--rule-strong); margin: 0 2px; }
.pg-tool.is-danger { color: #ff8a8a; border-color: rgba(255,138,138,0.4); }
.pg-tool.is-danger:hover { background: rgba(255,138,138,0.12); }
/* "خذ القلم" (take the pen) — a clear gold CTA pill, NOT a square icon tool.
   width:auto + nowrap stop the label from wrapping into the 36px tool box. */
.pg-tool-takeover {
    width: auto; min-width: max-content; height: 36px;
    padding: 0 16px; white-space: nowrap;
    font-family: var(--font-ui); font-size: 13.5px; font-weight: 700;
    gap: 7px; border-radius: 999px; border: 0;
    color: #3a2c08;
    background: linear-gradient(135deg, #E6CD86, var(--gold) 55%, #9f7e34);
    box-shadow: 0 6px 16px -8px rgba(200,162,74,.85);
}
.pg-tool-takeover:hover { filter: brightness(1.05); background: linear-gradient(135deg, #E6CD86, var(--gold) 55%, #9f7e34); color: #3a2c08; }
.pg-tool-takeover:active { transform: scale(.96); }
.pg-tool-takeover:disabled { filter: grayscale(.3) brightness(.92); }

/* Pen-thickness presets — three growing dots; mirrors the swatch row styling. */
.pg-width-row {
    display: inline-flex; align-items: center; gap: 5px;
    padding-inline-start: 4px; margin-inline-start: 2px;
    border-inline-start: 1px solid var(--rule-strong);
}
.pg-width {
    width: 32px; height: 32px; border-radius: 9px;
    background: var(--ink-3); border: 1px solid var(--gold-edge);
    display: inline-flex; align-items: center; justify-content: center;
    transition: background 160ms, transform 100ms;
}
.pg-width:hover { background: var(--gold-soft); }
.pg-width:active { transform: scale(.94); }
.pg-width.is-active { background: var(--gold); border-color: var(--gold); }
.pg-width-dot { display: block; border-radius: 50%; background: var(--paper); }
.pg-width.is-active .pg-width-dot { background: var(--ink); }

/* Canvas becomes interactive only for the pointer owner. */
.pg-canvas { pointer-events: none; }
.pg-canvas.is-interactive { pointer-events: auto; cursor: crosshair; }
.pg-canvas.tool-pointer { cursor: none; }
.pg-canvas.tool-eraser { cursor: cell; }

/* Hint banner when a non-owner stage member sees who's holding the pointer. */
.pg-pointer-hint {
    position: absolute; top: 10px; inset-inline-start: 50%; transform: translateX(50%);
    background: rgba(14,16,19,0.72);
    border: 1px solid var(--gold-edge);
    border-radius: 999px;
    padding: 6px 14px;
    font-family: var(--font-ui); font-size: 12px; color: var(--paper);
    backdrop-filter: blur(8px);
    pointer-events: none;
    opacity: 0; transition: opacity 240ms;
}
.pg-pointer-hint.is-visible { opacity: 1; }

/* Color swatches — six editorially-coherent options. The active swatch
   wears a gold ring; an inner border keeps light colors visible on paper. */
.pg-swatch-row {
    display: inline-flex; align-items: center; gap: 6px;
    padding-inline-start: 4px;
    border-inline-start: 1px solid var(--rule-strong);
    margin-inline-start: 2px;
}
.pg-swatch {
    width: 22px; height: 22px; border-radius: 50%;
    border: 1px solid rgba(245,242,234,0.32);
    box-shadow: inset 0 0 0 1px rgba(0,0,0,0.18);
    cursor: pointer;
    padding: 0;
    transition: transform 100ms ease;
}
.pg-swatch:hover { transform: scale(1.12); }
.pg-swatch.is-active {
    box-shadow: 0 0 0 2px var(--gold), inset 0 0 0 1px rgba(0,0,0,0.18);
}

/* The frame head wraps gracefully when the tool rail and color row need
   more horizontal room than the meeting title leaves over. */
.pg-frame-head { flex-wrap: wrap; row-gap: 8px; }
/* tools take their own full-width line BELOW the title + the إغلاق pill */
.pg-tools { flex-wrap: wrap; row-gap: 6px; flex-basis: 100%; margin-inline-start: 0; }

/* Live shape preview is drawn on a separate overlay so we don't have to
   redraw every committed stroke on every pointermove of a shape drag. */
.pg-canvas-preview {
    position: absolute;
    pointer-events: none;
    touch-action: none;
}

@media (max-width: 700px) {
    .pg-tools { flex-wrap: wrap; }
    .pg-tool { width: 32px; height: 32px; font-size: 14px; }
    /* keep the take-pen pill auto-width so the .pg-tool 32px rule can't squish it */
    .pg-tool-takeover { width: auto; min-width: max-content; height: 34px; font-size: 12.5px; padding: 0 14px; }
    .pg-swatch { width: 20px; height: 20px; }
    .pg-swatch-row { gap: 5px; padding-inline-start: 3px; }
    .pg-width { width: 30px; height: 30px; }
    .pg-close { width: auto; min-width: max-content; height: 34px; padding: 0 14px; font-size: 12.5px; }
}

/* ===== Connection-quality dots (quality-stats loop, R4/R6) =====
   4 dots in a row, centered ABOVE each stage avatar (in flow, first child of
   the flex-column tile). Patched in place by applyQualityLevels() — never via
   render(). Lit dots = level+1: 1 red / 2 amber / 3 light-green / 4 green;
   'u' = stale-but-present (unstable, pulsing); 'n' = no data yet (all dim,
   always present so dots appearing never shift the layout). pointer-events
   none keeps tile taps working. */
.q-chip {
    display: flex;
    gap: 3px;
    align-items: center;
    justify-content: center;
    height: 9px;
    pointer-events: none;
}
.q-chip b { width: 7px; height: 7px; border-radius: 50%; background: #343b50; }
.q-chip[data-q="0"] b:nth-child(1) { background: #ff5d5d; }
.q-chip[data-q="1"] b:nth-child(-n+2) { background: #e3b341; }
.q-chip[data-q="2"] b:nth-child(-n+3) { background: #7bd88f; }
.q-chip[data-q="3"] b { background: #39d98a; }
.q-chip[data-q="u"] { opacity: .7; }
.q-chip[data-q="u"] b:nth-child(1) { background: #ff8a5d; animation: qPulse 1.2s ease-in-out infinite; }
.q-chip[data-q="n"] { opacity: .3; }
@keyframes qPulse { 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) { .q-chip b { animation: none !important; } }
@media (max-width: 480px) { .q-chip b { width: 6px; height: 6px; } .q-chip { gap: 2px; } }
/* own indicator: inline in the header next to the live timer */
#qSelf { display: inline-flex; margin-inline-start: 8px; vertical-align: middle; }
