@ai-matrx/meet 0.11.42 → 0.11.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
 
4
4
  // src/skins/meet/components.tsx
5
- import { useEffect as useEffect6, useLayoutEffect, useRef as useRef6, useState as useState4 } from "react";
5
+ import { useEffect as useEffect6, useLayoutEffect, useRef as useRef6, useState as useState5 } from "react";
6
6
 
7
7
  // src/react/facade.ts
8
8
  import { useMemo as useMemo5 } from "react";
@@ -160,6 +160,8 @@ var MEET_ROUTES = {
160
160
  noteTakerStop: "/api/v1/meet/agent/stop",
161
161
  /** In-meeting Q&A. Streams NDJSON; body is `{meeting_id, question}` only. */
162
162
  intelligenceAsk: "/api/v1/meet/intelligence/ask",
163
+ /** Anyone in the meeting (guests with the room pass included) asks for captions for themselves. */
164
+ noteTakerCaptions: "/api/v1/meet/agent/captions",
163
165
  /** A host ends the meeting for everyone. Served by MRI-A6. */
164
166
  meetingEnd: "/api/v1/meet/end",
165
167
  /**
@@ -255,12 +257,39 @@ function recordingLabel(state) {
255
257
  }
256
258
  }
257
259
 
260
+ // src/core/live-policy.ts
261
+ var DEFAULT_LIVE_POLICY = {
262
+ chatMode: "everyone",
263
+ avLock: "off",
264
+ timeLimitMinutes: 0,
265
+ timeLimitWarningMinutes: 5,
266
+ recordingConsent: "notice"
267
+ };
268
+ var MODERATORS = /* @__PURE__ */ new Set(["host", "cohost"]);
269
+ function isLockedFor(policy, role, kind) {
270
+ if (MODERATORS.has(role)) return false;
271
+ return policy.avLock === "both" || (kind === "microphone" ? policy.avLock === "mic" : policy.avLock === "camera");
272
+ }
273
+ function consentPending(policy, role, recordingOn, given) {
274
+ return recordingOn && !given && policy.recordingConsent !== "notice" && !MODERATORS.has(role);
275
+ }
276
+ function canChat(policy, role) {
277
+ if (policy.chatMode === "everyone") return true;
278
+ return policy.chatMode === "hosts_only" && MODERATORS.has(role);
279
+ }
280
+ function minutesLeft(policy, startedAtMs, nowMs) {
281
+ if (policy.timeLimitMinutes <= 0 || startedAtMs === null) return null;
282
+ return Math.ceil((startedAtMs + policy.timeLimitMinutes * 6e4 - nowMs) / 6e4);
283
+ }
284
+
258
285
  // src/core/attendance.ts
286
+ var IDLE_PREVIEW = { state: "idle", unavailable: null };
259
287
  var IDLE_MEDIA_REGION = {
260
288
  permission: { microphone: "unknown", camera: "unknown" },
261
289
  audioOutput: "ok",
262
290
  notice: null,
263
- offer: null
291
+ offer: null,
292
+ preview: { microphone: IDLE_PREVIEW, camera: IDLE_PREVIEW }
264
293
  };
265
294
  var IDLE_TRACK = { enabled: false, unavailable: null };
266
295
  var IDLE_MEDIA = {
@@ -347,9 +376,17 @@ function autoAssign(identities, rooms, exclude = []) {
347
376
  return out;
348
377
  }
349
378
  function breakoutRemainingMs(plan, now) {
350
- if (plan === null || plan.state !== "open" || plan.endsAt === null) return null;
351
- const end = Date.parse(plan.endsAt);
352
- return Number.isNaN(end) ? null : Math.max(0, end - now);
379
+ if (plan === null || plan.state !== "open") return null;
380
+ const ends = [plan.endsAt, plan.closingAt].map((stamp) => stamp === null ? Number.NaN : Date.parse(stamp)).filter((time) => !Number.isNaN(time));
381
+ if (ends.length === 0) return null;
382
+ return Math.max(0, Math.min(...ends) - now);
383
+ }
384
+ var BREAKOUT_COUNTDOWN_MS = 3e4;
385
+ function breakoutClosingMs(plan, now) {
386
+ if (plan === null || plan.state !== "open") return null;
387
+ const remaining = breakoutRemainingMs(plan, now);
388
+ if (remaining === null) return null;
389
+ return plan.closingAt !== null || remaining <= BREAKOUT_COUNTDOWN_MS ? remaining : null;
353
390
  }
354
391
  function defaultCaptionLanguage(settings, viewerLanguage) {
355
392
  const configured = settings?.captionTranslationLanguage.trim() ?? "";
@@ -411,7 +448,7 @@ function effectiveStanding(snapshot) {
411
448
  var REACTION_TTL_MS = 5e3;
412
449
 
413
450
  // src/react/root.tsx
414
- import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
451
+ import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
415
452
 
416
453
  // src/core/media-supervisor.ts
417
454
  function classifyDeviceFailure(error, permission) {
@@ -473,7 +510,7 @@ function deviceFixSteps(kind, reason, where) {
473
510
  case "safari":
474
511
  return where.os === "ios" ? [`Settings \u203A Apps \u203A Safari \u203A ${device}`, "Choose Allow", "Return here and press Try again"] : ["Safari \u203A Settings for This Website", `Set ${device} to Allow`, "Press Try again"];
475
512
  default:
476
- return ["Click the icon left of the web address", `Set ${device} to Allow`, "Press Try again"];
513
+ return ["Click the site settings icon in the address bar", `Set ${device} to Allow`, "Press Try again"];
477
514
  }
478
515
  case "blocked_os": {
479
516
  const app = where.browser === "chrome" ? "Google Chrome" : where.browser === "edge" ? "Microsoft Edge" : where.browser === "firefox" ? "Firefox" : "your browser";
@@ -557,14 +594,31 @@ function webMediaPlatform() {
557
594
 
558
595
  // src/core/observation.ts
559
596
  function observedRole(role, standing) {
560
- if (role === "host" || role === "cohost") return role;
597
+ if (role === "host" || role === "cohost" || role === "presenter") return role;
561
598
  return isLinkFollower(standing) ? "guest" : "participant";
562
599
  }
563
- function observedDevice(track, permission = "unknown") {
600
+ function observedDevice(track, permission = "unknown", held = null) {
601
+ if (held === "locked") return "locked";
564
602
  if (track.enabled) return "on";
603
+ if (held === "muted_by_host") return "muted_by_host";
565
604
  const reason = deviceUnavailableReason(track, permission);
566
605
  return reason === null ? "muted_by_me" : `unavailable:${reason}`;
567
606
  }
607
+ function observedPreview(preview, permission = "unknown") {
608
+ if (permission === "denied") return "unavailable:denied";
609
+ switch (preview.state) {
610
+ case "on":
611
+ return "on";
612
+ case "off":
613
+ return "muted_by_me";
614
+ case "prompting":
615
+ return "prompting";
616
+ case "unavailable":
617
+ return `unavailable:${preview.unavailable?.reason ?? "failed"}`;
618
+ default:
619
+ return null;
620
+ }
621
+ }
568
622
  function endedRecord(snapshot, given) {
569
623
  const record = snapshot?.meeting ?? given;
570
624
  return record !== null && record.endedAt !== null;
@@ -588,20 +642,34 @@ function observe(input) {
588
642
  const canAdmit = actual !== "none" && ADMITTER_ROLES.has(actual);
589
643
  const role = actual === "none" || snapshot === null ? "none" : observedRole(actual, effectiveStanding(snapshot));
590
644
  const deviceInPlay = phase === "joining" || inCall;
645
+ const region = snapshot?.mediaRegion;
646
+ const atPrejoin = phase === "prejoin" && region !== void 0;
591
647
  return {
592
648
  phase,
593
649
  reason: phase === "ended" ? snapshot?.reason ?? null : snapshot?.reason ?? reasonOf(phase),
594
650
  role,
595
- connection: snapshot?.connection ?? "stable",
651
+ // `net-blip`: in the call, a drop shorter than `reconnect_banner_delay_ms` is not something the
652
+ // person sees — the contract says what is on screen, so it reads `stable` until the banner shows.
653
+ connection: snapshot === null ? "stable" : inCall && snapshot.connection !== "stable" && !snapshot.connectionBanner ? "stable" : snapshot.connection,
596
654
  hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : snapshot !== null && isWaitingPhase(snapshot.phase) ? snapshot.waiting?.admittersPresent ?? null : null,
597
655
  lobbyCount: canAdmit && snapshot !== null ? snapshot.lobby.filter((entry) => entry.state === "knocking").length : 0,
598
656
  recording: snapshot?.recording === "recording" || snapshot?.recording === "stopping",
599
657
  // S6c: the autoplay region is known only inside the room (no remote audio exists elsewhere).
600
658
  audioBlocked: inCall && snapshot !== null ? snapshot.mediaRegion.audioOutput === "blocked" : null,
601
- camera: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.camera, snapshot.mediaRegion.permission.camera) : null,
602
- microphone: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.microphone, snapshot.mediaRegion.permission.microphone) : null
659
+ camera: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.camera, snapshot.mediaRegion.permission.camera, lockedFor(snapshot, "camera", inCall)) : atPrejoin ? observedPreview(region.preview.camera, region.permission.camera) : null,
660
+ microphone: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.microphone, snapshot.mediaRegion.permission.microphone, lockedFor(snapshot, "microphone", inCall)) : atPrejoin ? observedPreview(region.preview.microphone, region.permission.microphone) : null
603
661
  };
604
662
  }
663
+ function lockedFor(snapshot, kind, inCall) {
664
+ if (!inCall) return null;
665
+ const role = effectiveRole(snapshot);
666
+ if (isLockedFor(snapshot.livePolicy, role, kind)) return "locked";
667
+ if (snapshot.livePolicy.recordingConsent === "view_only_until_agree" && consentPending(snapshot.livePolicy, role, snapshot.recording === "recording", snapshot.recordingConsentGiven)) {
668
+ return "locked";
669
+ }
670
+ if (kind === "microphone" && snapshot.mutedByHost) return "muted_by_host";
671
+ return null;
672
+ }
605
673
  function staticObservation(phase, reason = null) {
606
674
  return {
607
675
  phase,
@@ -704,7 +772,7 @@ function exactNoteTakerParticipant(meeting, participants) {
704
772
  }
705
773
  function noteTakerStatus(args) {
706
774
  const present = exactNoteTakerParticipant(args.meeting, args.participants) !== null;
707
- const raw = args.meeting?.metadata[NOTE_TAKER_METADATA_KEY];
775
+ const raw = args.meeting?.metadata?.[NOTE_TAKER_METADATA_KEY];
708
776
  const row = typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
709
777
  const recorded = readState(row["state"]);
710
778
  const detail = typeof row["reason"] === "string" && row["reason"].length > 0 ? row["reason"] : null;
@@ -843,7 +911,7 @@ function useCanRecord() {
843
911
  }
844
912
 
845
913
  // src/react/root.tsx
846
- import { jsx as jsx2 } from "react/jsx-runtime";
914
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
847
915
  function useCoreObservation(options = {}) {
848
916
  const snapshot = useMeetSnapshot();
849
917
  const { meeting, phase, reason } = options;
@@ -1000,7 +1068,7 @@ function useMeetAppPanel(meeting) {
1000
1068
  }
1001
1069
 
1002
1070
  // src/react/hooks.ts
1003
- import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState2, useSyncExternalStore as useSyncExternalStore2 } from "react";
1071
+ import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState3, useSyncExternalStore as useSyncExternalStore2 } from "react";
1004
1072
  import { useRealtimeManager as useRealtimeManager2 } from "@ai-matrx/realtime/react";
1005
1073
 
1006
1074
  // src/core/record.ts
@@ -1126,7 +1194,8 @@ function useRoom() {
1126
1194
  failure: snapshot?.failure ?? null,
1127
1195
  secondDevice: snapshot?.secondDevice ?? null,
1128
1196
  local,
1129
- canShareScreen: engine?.supportsScreenShare() ?? true,
1197
+ // An observer (role `viewer`) publishes nothing: no Share screen to press and be refused (MD-16).
1198
+ canShareScreen: (engine?.supportsScreenShare() ?? true) && !isObserverRole(snapshot?.grants.role ?? null),
1130
1199
  join: useCallback2(
1131
1200
  async (request) => requireEngine(engine, "join").join(request),
1132
1201
  [engine]
@@ -1183,7 +1252,7 @@ function useRoom() {
1183
1252
  }
1184
1253
  function useStage(pageSize = DEFAULT_PAGE_SIZE) {
1185
1254
  const snapshot = useMeetSnapshot();
1186
- const [page, setPage] = useState2(0);
1255
+ const [page, setPage] = useState3(0);
1187
1256
  const stage = useMemo4(
1188
1257
  () => computeStage({
1189
1258
  participants: snapshot?.participants ?? [],
@@ -1244,7 +1313,7 @@ function useLobby() {
1244
1313
  };
1245
1314
  }
1246
1315
  function useCountdown(untilMs) {
1247
- const [now, setNow] = useState2(() => Date.now());
1316
+ const [now, setNow] = useState3(() => Date.now());
1248
1317
  const active = typeof untilMs === "number" && untilMs > now;
1249
1318
  useEffect3(() => {
1250
1319
  if (!active) return void 0;
@@ -1257,7 +1326,7 @@ function useCountdown(untilMs) {
1257
1326
  }
1258
1327
  function useKnockNotice() {
1259
1328
  const lobby = useLobby();
1260
- const [dismissed, setDismissed] = useState2([]);
1329
+ const [dismissed, setDismissed] = useState3([]);
1261
1330
  const keyOf = (entry) => `${entry.identity}@${entry.knockedAt}`;
1262
1331
  const open = lobby.canAdmit ? lobby.waiting.filter((entry) => !dismissed.includes(keyOf(entry))) : [];
1263
1332
  const knocker = open[0] ?? null;
@@ -1343,11 +1412,11 @@ function useMeetAi() {
1343
1412
  const host = useMeetHost();
1344
1413
  const snapshot = useMeetSnapshot();
1345
1414
  const isHost = useIsHost();
1346
- const [asking, setAsking] = useState2(false);
1347
- const [answer, setAnswer] = useState2(null);
1348
- const [coverage, setCoverage] = useState2(null);
1349
- const [phase, setPhase] = useState2(null);
1350
- const [error, setError] = useState2(null);
1415
+ const [asking, setAsking] = useState3(false);
1416
+ const [answer, setAnswer] = useState3(null);
1417
+ const [coverage, setCoverage] = useState3(null);
1418
+ const [phase, setPhase] = useState3(null);
1419
+ const [error, setError] = useState3(null);
1351
1420
  const ai = host?.ai ?? null;
1352
1421
  const meeting = snapshot?.meeting ?? null;
1353
1422
  const participants = snapshot?.participants ?? [];
@@ -1457,12 +1526,51 @@ function useMeetAi() {
1457
1526
  }, [ai, meeting, dispatchNoteTaker])
1458
1527
  };
1459
1528
  }
1529
+ function useCaptions() {
1530
+ const host = useMeetHost();
1531
+ const snapshot = useMeetSnapshot();
1532
+ const ai = useMeetAi();
1533
+ const on = snapshot?.captionsOn === true;
1534
+ const refusal = snapshot?.captionsRefusal ?? null;
1535
+ const taker = ai.noteTaker;
1536
+ const meeting = snapshot?.meeting ?? null;
1537
+ const request = useCallback2(() => {
1538
+ if (host === null || meeting === null) return;
1539
+ void host.ai.requestCaptions({ meetingId: meeting.id });
1540
+ }, [host, meeting]);
1541
+ const toggle = useCallback2(() => {
1542
+ if (host === null) return;
1543
+ const next = !on;
1544
+ host.store.patch({ captionsOn: next, captionsRefusal: null });
1545
+ if (next && taker.state !== "joining" && taker.state !== "transcribing") request();
1546
+ }, [host, on, taker.state, request]);
1547
+ let state = "off";
1548
+ let reason = null;
1549
+ let remedy = null;
1550
+ if (on) {
1551
+ if (taker.state === "transcribing" && taker.present) {
1552
+ state = "live";
1553
+ } else if (taker.state === "joining") {
1554
+ state = "starting";
1555
+ } else if (refusal !== null && refusal.reason.length > 0) {
1556
+ state = "unavailable";
1557
+ reason = refusal.reason;
1558
+ remedy = refusal.remedy.length > 0 ? refusal.remedy : null;
1559
+ } else if (taker.state === "ended" || taker.state === "handoff_pending") {
1560
+ state = "unavailable";
1561
+ reason = noteTakerLabel(taker);
1562
+ } else {
1563
+ state = "starting";
1564
+ }
1565
+ }
1566
+ return { on, state, reason, remedy, toggle };
1567
+ }
1460
1568
  function useEndMeeting() {
1461
1569
  const host = useMeetHost();
1462
1570
  const snapshot = useMeetSnapshot();
1463
1571
  const isHost = useIsHost();
1464
- const [ending, setEnding] = useState2(false);
1465
- const [notice, setNotice] = useState2(null);
1572
+ const [ending, setEnding] = useState3(false);
1573
+ const [notice, setNotice] = useState3(null);
1466
1574
  const meeting = snapshot?.meeting ?? null;
1467
1575
  const session = host?.meetings ?? null;
1468
1576
  return {
@@ -1494,7 +1602,7 @@ function useConsentNotice() {
1494
1602
  const snapshot = useMeetSnapshot();
1495
1603
  const agent = noteTakerParticipant(snapshot?.participants ?? []);
1496
1604
  if (agent === null) return null;
1497
- return `${agent.displayName} is in this meeting: it is transcribing what is said and writing notes everyone here can read.`;
1605
+ return `AI notes are on. ${agent.displayName} is in this meeting, transcribing what is said and writing notes everyone here can read.`;
1498
1606
  }
1499
1607
  function useMediaSupervisor() {
1500
1608
  const host = useMeetHost();
@@ -1513,6 +1621,12 @@ function useMediaSupervisor() {
1513
1621
  retry: useCallback2(
1514
1622
  async (kind) => kind === "microphone" ? engine?.setMicrophoneEnabled(true) : engine?.setCameraEnabled(true),
1515
1623
  [engine]
1624
+ ),
1625
+ reportPreview: useCallback2(
1626
+ (kind, outcome) => {
1627
+ void engine?.previewDevice(kind, outcome);
1628
+ },
1629
+ [engine]
1516
1630
  )
1517
1631
  };
1518
1632
  }
@@ -1532,7 +1646,7 @@ function useReactions() {
1532
1646
  return snapshot?.reactions ?? [];
1533
1647
  }
1534
1648
  function useElapsed(startedAt) {
1535
- const [now, setNow] = useState2(() => Date.now());
1649
+ const [now, setNow] = useState3(() => Date.now());
1536
1650
  useEffect3(() => {
1537
1651
  if (startedAt === null) return void 0;
1538
1652
  const timer = setInterval(() => setNow(Date.now()), 1e3);
@@ -1549,7 +1663,7 @@ function useHostControls() {
1549
1663
  (participant) => participant.identity === snapshot.localIdentity
1550
1664
  );
1551
1665
  const actor = me === void 0 ? void 0 : { ...me, role };
1552
- const [busy, setBusy] = useState2(false);
1666
+ const [busy, setBusy] = useState3(false);
1553
1667
  const inRoom = host?.inRoom ?? null;
1554
1668
  const store = host?.store ?? null;
1555
1669
  const notice = snapshot?.actionNotice ?? null;
@@ -1632,7 +1746,7 @@ function useModerationNotice() {
1632
1746
  };
1633
1747
  }
1634
1748
  function useAudioLevel(stream) {
1635
- const [level, setLevel] = useState2(0);
1749
+ const [level, setLevel] = useState3(0);
1636
1750
  useEffect3(() => {
1637
1751
  if (stream === null || stream.getAudioTracks().length === 0) {
1638
1752
  setLevel(0);
@@ -1703,10 +1817,10 @@ function useGuestRecordAccess(meeting) {
1703
1817
  const host = useMeetHost();
1704
1818
  const api = host?.api ?? null;
1705
1819
  const stored = guestRecordAccessSetting(meeting);
1706
- const [chosen, setChosen] = useState2(null);
1707
- const [effective, setEffective] = useState2(null);
1708
- const [saving, setSaving] = useState2(false);
1709
- const [error, setError] = useState2(null);
1820
+ const [chosen, setChosen] = useState3(null);
1821
+ const [effective, setEffective] = useState3(null);
1822
+ const [saving, setSaving] = useState3(false);
1823
+ const [error, setError] = useState3(null);
1710
1824
  useEffect3(() => {
1711
1825
  setChosen(null);
1712
1826
  }, [stored, meeting?.id]);
@@ -1742,6 +1856,38 @@ function useGuestRecordAccess(meeting) {
1742
1856
  )
1743
1857
  };
1744
1858
  }
1859
+ function useLivePolicy() {
1860
+ const snapshot = useMeetSnapshot();
1861
+ const role = useRole();
1862
+ const [now, setNow] = useState3(() => Date.now());
1863
+ const limited = (snapshot?.livePolicy.timeLimitMinutes ?? 0) > 0;
1864
+ useEffect3(() => {
1865
+ if (!limited) return void 0;
1866
+ const timer = setInterval(() => setNow(Date.now()), 1e3);
1867
+ return () => clearInterval(timer);
1868
+ }, [limited]);
1869
+ const policy = snapshot?.livePolicy ?? DEFAULT_LIVE_POLICY;
1870
+ const left = minutesLeft(policy, snapshot?.sessionStartedAt ?? null, now);
1871
+ const host = useMeetHost();
1872
+ const pending = consentPending(policy, role, snapshot?.recording === "recording", snapshot?.recordingConsentGiven === true);
1873
+ const viewOnly = pending && policy.recordingConsent === "view_only_until_agree";
1874
+ const idle = snapshot !== null && snapshot.recording !== "recording" && snapshot.recording !== "starting" && snapshot.recording !== "stopping";
1875
+ const given = snapshot?.recordingConsentGiven === true;
1876
+ const store = host?.store ?? null;
1877
+ useEffect3(() => {
1878
+ if (idle && given) store?.patch({ recordingConsentGiven: false });
1879
+ }, [idle, given, store]);
1880
+ return {
1881
+ canChat: canChat(policy, role),
1882
+ chatMode: policy.chatMode,
1883
+ micLocked: isLockedFor(policy, role, "microphone") || viewOnly,
1884
+ cameraLocked: isLockedFor(policy, role, "camera") || viewOnly,
1885
+ consent: pending ? policy.recordingConsent === "ok_or_leave" ? "ok_or_leave" : "view_only_until_agree" : null,
1886
+ agree: () => store?.patch({ recordingConsentGiven: true }),
1887
+ minutesLeft: left,
1888
+ timeWarning: left !== null && left <= policy.timeLimitWarningMinutes
1889
+ };
1890
+ }
1745
1891
 
1746
1892
  // src/react/collab-hooks.ts
1747
1893
  import { useEffect as useEffect4, useRef as useRef4 } from "react";
@@ -1801,6 +1947,39 @@ function useCollabPanelRequest(onRequest) {
1801
1947
  // src/core/reactions.ts
1802
1948
  var MEET_REACTIONS = ["\u{1F496}", "\u{1F44D}", "\u{1F389}", "\u{1F44F}", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F914}", "\u{1F44E}"];
1803
1949
 
1950
+ // src/core/speaking-detector.ts
1951
+ function createSpeakingWhileMutedDetector(options = {}) {
1952
+ const threshold = options.threshold ?? 0.06;
1953
+ const holdMs = options.holdMs ?? 600;
1954
+ const gapMs = options.gapMs ?? 400;
1955
+ const cooldownMs = options.cooldownMs ?? 2e4;
1956
+ let speechStart = null;
1957
+ let lastLoud = null;
1958
+ let firedAt = null;
1959
+ return {
1960
+ feed(level, at) {
1961
+ if (level >= threshold) {
1962
+ if (speechStart === null || lastLoud === null || at - lastLoud > gapMs) speechStart = at;
1963
+ lastLoud = at;
1964
+ } else if (lastLoud !== null && at - lastLoud > gapMs) {
1965
+ speechStart = null;
1966
+ lastLoud = null;
1967
+ }
1968
+ if (speechStart === null || at - speechStart < holdMs) return false;
1969
+ if (firedAt !== null && at - firedAt < cooldownMs) return false;
1970
+ firedAt = at;
1971
+ speechStart = null;
1972
+ lastLoud = null;
1973
+ return true;
1974
+ },
1975
+ reset() {
1976
+ speechStart = null;
1977
+ lastLoud = null;
1978
+ firedAt = null;
1979
+ }
1980
+ };
1981
+ }
1982
+
1804
1983
  // src/react/facade.ts
1805
1984
  var NO_ACTIONS = {
1806
1985
  join: async () => void 0,
@@ -1865,10 +2044,10 @@ function useMeetCore() {
1865
2044
  import { Alert, AlertDescription, Button, Checkbox, ErrorBox, Label, SegmentedControl, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ai-matrx/design-system";
1866
2045
 
1867
2046
  // src/skins/meet/collab.tsx
1868
- import { useEffect as useEffect5, useRef as useRef5, useState as useState3 } from "react";
2047
+ import { useEffect as useEffect5, useRef as useRef5, useState as useState4 } from "react";
1869
2048
 
1870
2049
  // src/skins/meet/icons.tsx
1871
- import { jsx as jsx4, jsxs } from "react/jsx-runtime";
2050
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1872
2051
  function Icon({ children, ...props }) {
1873
2052
  return /* @__PURE__ */ jsx4(
1874
2053
  "svg",
@@ -1889,14 +2068,14 @@ function Icon({ children, ...props }) {
1889
2068
  );
1890
2069
  }
1891
2070
  function MicIcon(props) {
1892
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2071
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1893
2072
  /* @__PURE__ */ jsx4("path", { d: "M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z" }),
1894
2073
  /* @__PURE__ */ jsx4("path", { d: "M19 10v2a7 7 0 0 1-14 0v-2" }),
1895
2074
  /* @__PURE__ */ jsx4("path", { d: "M12 19v3" })
1896
2075
  ] });
1897
2076
  }
1898
2077
  function MicOffIcon(props) {
1899
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2078
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1900
2079
  /* @__PURE__ */ jsx4("path", { d: "M2 2l20 20" }),
1901
2080
  /* @__PURE__ */ jsx4("path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12" }),
1902
2081
  /* @__PURE__ */ jsx4("path", { d: "M15 9.34V5a3 3 0 0 0-5.94-.6" }),
@@ -1905,20 +2084,20 @@ function MicOffIcon(props) {
1905
2084
  ] });
1906
2085
  }
1907
2086
  function CameraIcon(props) {
1908
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2087
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1909
2088
  /* @__PURE__ */ jsx4("path", { d: "m23 7-7 5 7 5V7Z" }),
1910
2089
  /* @__PURE__ */ jsx4("rect", { x: "1", y: "5", width: "15", height: "14", rx: "2" })
1911
2090
  ] });
1912
2091
  }
1913
2092
  function CameraOffIcon(props) {
1914
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2093
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1915
2094
  /* @__PURE__ */ jsx4("path", { d: "M2 2l20 20" }),
1916
2095
  /* @__PURE__ */ jsx4("path", { d: "M10.66 5H14a2 2 0 0 1 2 2v3.34l1 1L23 7v10" }),
1917
2096
  /* @__PURE__ */ jsx4("path", { d: "M16 16a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2" })
1918
2097
  ] });
1919
2098
  }
1920
2099
  function ScreenShareIcon(props) {
1921
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2100
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1922
2101
  /* @__PURE__ */ jsx4("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
1923
2102
  /* @__PURE__ */ jsx4("path", { d: "M8 21h8M12 17v4" }),
1924
2103
  /* @__PURE__ */ jsx4("path", { d: "M12 13V8m0 0-2.5 2.5M12 8l2.5 2.5" })
@@ -1931,7 +2110,7 @@ function PhoneOffIcon(props) {
1931
2110
  return /* @__PURE__ */ jsx4(Icon, { fill: "currentColor", stroke: "none", ...props, children: /* @__PURE__ */ jsx4("path", { d: "M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08a.99.99 0 0 1-.29-.7c0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28a11.27 11.27 0 0 0-2.67-1.85.996.996 0 0 1-.56-.9v-3.1C15.15 9.25 13.6 9 12 9Z" }) });
1932
2111
  }
1933
2112
  function HandIcon(props) {
1934
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2113
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1935
2114
  /* @__PURE__ */ jsx4("path", { d: "M18 11V6a2 2 0 0 0-4 0v5" }),
1936
2115
  /* @__PURE__ */ jsx4("path", { d: "M14 10V4a2 2 0 0 0-4 0v7" }),
1937
2116
  /* @__PURE__ */ jsx4("path", { d: "M10 10.5V6a2 2 0 0 0-4 0v8" }),
@@ -1942,7 +2121,7 @@ function ChatIcon(props) {
1942
2121
  return /* @__PURE__ */ jsx4(Icon, { ...props, children: /* @__PURE__ */ jsx4("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z" }) });
1943
2122
  }
1944
2123
  function PeopleIcon(props) {
1945
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2124
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1946
2125
  /* @__PURE__ */ jsx4("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
1947
2126
  /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "7", r: "4" }),
1948
2127
  /* @__PURE__ */ jsx4("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75" })
@@ -1952,25 +2131,37 @@ function RecordIcon(props) {
1952
2131
  return /* @__PURE__ */ jsx4(Icon, { ...props, children: /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "8", fill: "currentColor", stroke: "none" }) });
1953
2132
  }
1954
2133
  function SparklesIcon(props) {
1955
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2134
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1956
2135
  /* @__PURE__ */ jsx4("path", { d: "M12 3l1.9 4.6L18.5 9.5l-4.6 1.9L12 16l-1.9-4.6L5.5 9.5l4.6-1.9L12 3Z" }),
1957
2136
  /* @__PURE__ */ jsx4("path", { d: "M19 15l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9L19 15Z" })
1958
2137
  ] });
1959
2138
  }
2139
+ function CaptionsIcon(props) {
2140
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2141
+ /* @__PURE__ */ jsx4("rect", { x: "3", y: "5", width: "18", height: "14", rx: "2" }),
2142
+ /* @__PURE__ */ jsx4("path", { d: "M10 10.5a2 2 0 1 0 0 3M16 10.5a2 2 0 1 0 0 3" })
2143
+ ] });
2144
+ }
2145
+ function NotesIcon(props) {
2146
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2147
+ /* @__PURE__ */ jsx4("path", { d: "M4 20l1-4L16.5 4.5a2.1 2.1 0 0 1 3 3L8 19l-4 1Z" }),
2148
+ /* @__PURE__ */ jsx4("path", { d: "M14 7l3 3" })
2149
+ ] });
2150
+ }
1960
2151
  function LockIcon(props) {
1961
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2152
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1962
2153
  /* @__PURE__ */ jsx4("rect", { x: "4", y: "10", width: "16", height: "11", rx: "2" }),
1963
2154
  /* @__PURE__ */ jsx4("path", { d: "M8 10V7a4 4 0 0 1 8 0v3" })
1964
2155
  ] });
1965
2156
  }
1966
2157
  function LayoutIcon(props) {
1967
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2158
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1968
2159
  /* @__PURE__ */ jsx4("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
1969
2160
  /* @__PURE__ */ jsx4("path", { d: "M3 9h18M9 21V9" })
1970
2161
  ] });
1971
2162
  }
1972
2163
  function SettingsIcon(props) {
1973
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2164
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1974
2165
  /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "3" }),
1975
2166
  /* @__PURE__ */ jsx4("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
1976
2167
  ] });
@@ -1982,19 +2173,19 @@ function CloseIcon(props) {
1982
2173
  return /* @__PURE__ */ jsx4(Icon, { ...props, children: /* @__PURE__ */ jsx4("path", { d: "M18 6 6 18M6 6l12 12" }) });
1983
2174
  }
1984
2175
  function PinIcon(props) {
1985
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2176
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1986
2177
  /* @__PURE__ */ jsx4("path", { d: "M12 17v5" }),
1987
2178
  /* @__PURE__ */ jsx4("path", { d: "M9 2h6l-1 6 3.5 3.5V14H6.5v-2.5L10 8 9 2Z" })
1988
2179
  ] });
1989
2180
  }
1990
2181
  function WifiLowIcon(props) {
1991
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2182
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1992
2183
  /* @__PURE__ */ jsx4("path", { d: "M12 20h.01" }),
1993
2184
  /* @__PURE__ */ jsx4("path", { d: "M8.5 16.5a5 5 0 0 1 7 0" })
1994
2185
  ] });
1995
2186
  }
1996
2187
  function SmileIcon(props) {
1997
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2188
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
1998
2189
  /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "10" }),
1999
2190
  /* @__PURE__ */ jsx4("path", { d: "M8 14s1.5 2 4 2 4-2 4-2" }),
2000
2191
  /* @__PURE__ */ jsx4("line", { x1: "9", x2: "9.01", y1: "9", y2: "9" }),
@@ -2002,20 +2193,20 @@ function SmileIcon(props) {
2002
2193
  ] });
2003
2194
  }
2004
2195
  function MoreIcon(props) {
2005
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2196
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2006
2197
  /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "1" }),
2007
2198
  /* @__PURE__ */ jsx4("circle", { cx: "19", cy: "12", r: "1" }),
2008
2199
  /* @__PURE__ */ jsx4("circle", { cx: "5", cy: "12", r: "1" })
2009
2200
  ] });
2010
2201
  }
2011
2202
  function SearchIcon(props) {
2012
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2203
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2013
2204
  /* @__PURE__ */ jsx4("circle", { cx: "11", cy: "11", r: "8" }),
2014
2205
  /* @__PURE__ */ jsx4("path", { d: "m21 21-4.3-4.3" })
2015
2206
  ] });
2016
2207
  }
2017
2208
  function KeyboardIcon(props) {
2018
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2209
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2019
2210
  /* @__PURE__ */ jsx4("path", { d: "M10 8h.01M12 12h.01M14 8h.01M16 12h.01M18 8h.01M6 8h.01M7 16h10M8 12h.01" }),
2020
2211
  /* @__PURE__ */ jsx4("rect", { width: "20", height: "16", x: "2", y: "4", rx: "2" })
2021
2212
  ] });
@@ -2024,7 +2215,7 @@ function SpotlightIcon(props) {
2024
2215
  return /* @__PURE__ */ jsx4(Icon, { ...props, children: /* @__PURE__ */ jsx4("path", { d: "M12 2 15 8.5 22 9.3 17 14 18.2 21 12 17.6 5.8 21 7 14 2 9.3 9 8.5Z" }) });
2025
2216
  }
2026
2217
  function SignalIcon({ bars, ...props }) {
2027
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2218
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2028
2219
  /* @__PURE__ */ jsx4("path", { d: "M4 20v-2", opacity: bars >= 1 ? 1 : 0.3 }),
2029
2220
  /* @__PURE__ */ jsx4("path", { d: "M10 20v-6", opacity: bars >= 2 ? 1 : 0.3 }),
2030
2221
  /* @__PURE__ */ jsx4("path", { d: "M16 20V9", opacity: bars >= 3 ? 1 : 0.3 }),
@@ -2032,14 +2223,14 @@ function SignalIcon({ bars, ...props }) {
2032
2223
  ] });
2033
2224
  }
2034
2225
  function SpeakerIcon(props) {
2035
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2226
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2036
2227
  /* @__PURE__ */ jsx4("path", { d: "M11 5 6 9H2v6h4l5 4V5Z" }),
2037
2228
  /* @__PURE__ */ jsx4("path", { d: "M15.54 8.46a5 5 0 0 1 0 7.07" }),
2038
2229
  /* @__PURE__ */ jsx4("path", { d: "M19.07 4.93a10 10 0 0 1 0 14.14" })
2039
2230
  ] });
2040
2231
  }
2041
2232
  function FlagIcon(props) {
2042
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2233
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2043
2234
  /* @__PURE__ */ jsx4("path", { d: "M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z" }),
2044
2235
  /* @__PURE__ */ jsx4("line", { x1: "4", x2: "4", y1: "22", y2: "15" })
2045
2236
  ] });
@@ -2048,35 +2239,35 @@ function PencilIcon(props) {
2048
2239
  return /* @__PURE__ */ jsx4(Icon, { ...props, children: /* @__PURE__ */ jsx4("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }) });
2049
2240
  }
2050
2241
  function ActivitiesIcon(props) {
2051
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2242
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2052
2243
  /* @__PURE__ */ jsx4("path", { d: "M8.3 10a.7.7 0 0 1-.626-1.079L11.4 3a.7.7 0 0 1 1.198-.043L16.3 8.9a.7.7 0 0 1-.572 1.1Z" }),
2053
2244
  /* @__PURE__ */ jsx4("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" }),
2054
2245
  /* @__PURE__ */ jsx4("circle", { cx: "17.5", cy: "17.5", r: "3.5" })
2055
2246
  ] });
2056
2247
  }
2057
2248
  function PollIcon(props) {
2058
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2249
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2059
2250
  /* @__PURE__ */ jsx4("line", { x1: "18", x2: "18", y1: "20", y2: "10" }),
2060
2251
  /* @__PURE__ */ jsx4("line", { x1: "12", x2: "12", y1: "20", y2: "4" }),
2061
2252
  /* @__PURE__ */ jsx4("line", { x1: "6", x2: "6", y1: "20", y2: "14" })
2062
2253
  ] });
2063
2254
  }
2064
2255
  function QuestionIcon(props) {
2065
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2256
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2066
2257
  /* @__PURE__ */ jsx4("path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z" }),
2067
2258
  /* @__PURE__ */ jsx4("path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" }),
2068
2259
  /* @__PURE__ */ jsx4("path", { d: "M12 17h.01" })
2069
2260
  ] });
2070
2261
  }
2071
2262
  function WhiteboardIcon(props) {
2072
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2263
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2073
2264
  /* @__PURE__ */ jsx4("path", { d: "M2 3h20" }),
2074
2265
  /* @__PURE__ */ jsx4("path", { d: "M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3" }),
2075
2266
  /* @__PURE__ */ jsx4("path", { d: "m7 21 5-5 5 5" })
2076
2267
  ] });
2077
2268
  }
2078
2269
  function BreakoutIcon(props) {
2079
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2270
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2080
2271
  /* @__PURE__ */ jsx4("rect", { width: "7", height: "18", x: "3", y: "3", rx: "1" }),
2081
2272
  /* @__PURE__ */ jsx4("rect", { width: "7", height: "7", x: "14", y: "3", rx: "1" }),
2082
2273
  /* @__PURE__ */ jsx4("rect", { width: "7", height: "7", x: "14", y: "14", rx: "1" })
@@ -2086,29 +2277,32 @@ function UpvoteIcon(props) {
2086
2277
  return /* @__PURE__ */ jsx4(Icon, { ...props, children: /* @__PURE__ */ jsx4("path", { d: "M9 18v-6H5l7-7 7 7h-4v6H9z" }) });
2087
2278
  }
2088
2279
  function EraserIcon(props) {
2089
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2280
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2090
2281
  /* @__PURE__ */ jsx4("path", { d: "m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21" }),
2091
2282
  /* @__PURE__ */ jsx4("path", { d: "M22 21H7" }),
2092
2283
  /* @__PURE__ */ jsx4("path", { d: "m5 11 9 9" })
2093
2284
  ] });
2094
2285
  }
2095
2286
  function HighlighterIcon(props) {
2096
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2287
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2097
2288
  /* @__PURE__ */ jsx4("path", { d: "m9 11-6 6v3h9l3-3" }),
2098
2289
  /* @__PURE__ */ jsx4("path", { d: "m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4" })
2099
2290
  ] });
2100
2291
  }
2101
2292
  function UndoIcon(props) {
2102
- return /* @__PURE__ */ jsxs(Icon, { ...props, children: [
2293
+ return /* @__PURE__ */ jsxs2(Icon, { ...props, children: [
2103
2294
  /* @__PURE__ */ jsx4("path", { d: "M9 14 4 9l5-5" }),
2104
2295
  /* @__PURE__ */ jsx4("path", { d: "M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11" })
2105
2296
  ] });
2106
2297
  }
2298
+ function ChevronUpIcon(props) {
2299
+ return /* @__PURE__ */ jsx4(Icon, { ...props, children: /* @__PURE__ */ jsx4("path", { d: "m6 15 6-6 6 6" }) });
2300
+ }
2107
2301
 
2108
2302
  // src/skins/meet/collab.tsx
2109
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
2303
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
2110
2304
  function useNotice() {
2111
- const [notice, setNotice] = useState3(null);
2305
+ const [notice, setNotice] = useState4(null);
2112
2306
  useEffect5(() => {
2113
2307
  if (notice === null) return void 0;
2114
2308
  const timer = setTimeout(() => setNotice(null), notice.failed ? 7e3 : 3e3);
@@ -2137,16 +2331,16 @@ function ActivitiesControl({
2137
2331
  active,
2138
2332
  onOpen
2139
2333
  }) {
2140
- const [open, setOpen] = useState3(false);
2334
+ const [open, setOpen] = useState4(false);
2141
2335
  const available = useAvailableActivities();
2142
2336
  const attention = useActivityAttention();
2143
2337
  if (available.length === 0) return null;
2144
- return /* @__PURE__ */ jsxs2("span", { className: "mx-meet__anchor", children: [
2145
- /* @__PURE__ */ jsxs2(ControlButton, { label: "Activities", active: open || active !== null, onClick: () => setOpen(!open), children: [
2338
+ return /* @__PURE__ */ jsxs3("span", { className: "mx-meet__anchor", children: [
2339
+ /* @__PURE__ */ jsxs3(ControlButton, { label: "Activities", active: open || active !== null, onClick: () => setOpen(!open), children: [
2146
2340
  /* @__PURE__ */ jsx5(ActivitiesIcon, {}),
2147
2341
  attention ? /* @__PURE__ */ jsx5("span", { className: "mx-meet__dot", "aria-hidden": "true" }) : null
2148
2342
  ] }),
2149
- open ? /* @__PURE__ */ jsx5(Popover, { label: "Activities", onClose: () => setOpen(false), children: /* @__PURE__ */ jsx5("div", { className: "mx-meet__menu", role: "menu", children: available.map((panel) => /* @__PURE__ */ jsxs2(
2343
+ open ? /* @__PURE__ */ jsx5(Popover, { label: "Activities", onClose: () => setOpen(false), children: /* @__PURE__ */ jsx5("div", { className: "mx-meet__menu", role: "menu", children: available.map((panel) => /* @__PURE__ */ jsxs3(
2150
2344
  MenuItem,
2151
2345
  {
2152
2346
  onSelect: () => {
@@ -2165,11 +2359,11 @@ function ActivitiesControl({
2165
2359
  }
2166
2360
  function PollComposer({ maxOptions, onDone }) {
2167
2361
  const { act } = useCollab();
2168
- const [question, setQuestion] = useState3("");
2169
- const [options, setOptions] = useState3(["", ""]);
2170
- const [multiple, setMultiple] = useState3(false);
2171
- const [anonymous, setAnonymous] = useState3(false);
2172
- const [busy, setBusy] = useState3(false);
2362
+ const [question, setQuestion] = useState4("");
2363
+ const [options, setOptions] = useState4(["", ""]);
2364
+ const [multiple, setMultiple] = useState4(false);
2365
+ const [anonymous, setAnonymous] = useState4(false);
2366
+ const [busy, setBusy] = useState4(false);
2173
2367
  const [notice, show] = useNotice();
2174
2368
  const filled = options.map((o) => o.trim()).filter(Boolean);
2175
2369
  const ready = question.trim().length > 0 && filled.length >= 2;
@@ -2192,7 +2386,7 @@ function PollComposer({ maxOptions, onDone }) {
2192
2386
  setBusy(false);
2193
2387
  onDone();
2194
2388
  };
2195
- return /* @__PURE__ */ jsxs2(
2389
+ return /* @__PURE__ */ jsxs3(
2196
2390
  "form",
2197
2391
  {
2198
2392
  className: "mx-meet__collab-card",
@@ -2201,7 +2395,7 @@ function PollComposer({ maxOptions, onDone }) {
2201
2395
  if (ready) void save(true);
2202
2396
  },
2203
2397
  children: [
2204
- /* @__PURE__ */ jsxs2("label", { className: "mx-meet__field", children: [
2398
+ /* @__PURE__ */ jsxs3("label", { className: "mx-meet__field", children: [
2205
2399
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__field-label", children: "Question" }),
2206
2400
  /* @__PURE__ */ jsx5(
2207
2401
  "input",
@@ -2215,7 +2409,7 @@ function PollComposer({ maxOptions, onDone }) {
2215
2409
  }
2216
2410
  )
2217
2411
  ] }),
2218
- options.map((option, index) => /* @__PURE__ */ jsxs2("div", { className: "mx-meet__composer-row", children: [
2412
+ options.map((option, index) => /* @__PURE__ */ jsxs3("div", { className: "mx-meet__composer-row", children: [
2219
2413
  /* @__PURE__ */ jsx5(
2220
2414
  "input",
2221
2415
  {
@@ -2230,16 +2424,16 @@ function PollComposer({ maxOptions, onDone }) {
2230
2424
  options.length > 2 ? /* @__PURE__ */ jsx5(ControlButton, { label: `Remove answer ${index + 1}`, onClick: () => setOptions(options.filter((_, i) => i !== index)), children: /* @__PURE__ */ jsx5(CloseIcon, { width: 14, height: 14 }) }) : null
2231
2425
  ] }, index)),
2232
2426
  options.length < maxOptions ? /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__link", onClick: () => setOptions([...options, ""]), children: "Add an answer" }) : null,
2233
- /* @__PURE__ */ jsxs2("label", { className: "mx-meet__toggle", children: [
2427
+ /* @__PURE__ */ jsxs3("label", { className: "mx-meet__toggle", children: [
2234
2428
  /* @__PURE__ */ jsx5("input", { type: "checkbox", checked: multiple, onChange: (event) => setMultiple(event.target.checked) }),
2235
2429
  "People can pick more than one"
2236
2430
  ] }),
2237
- /* @__PURE__ */ jsxs2("label", { className: "mx-meet__toggle", children: [
2431
+ /* @__PURE__ */ jsxs3("label", { className: "mx-meet__toggle", children: [
2238
2432
  /* @__PURE__ */ jsx5("input", { type: "checkbox", checked: anonymous, onChange: (event) => setAnonymous(event.target.checked) }),
2239
2433
  "Anonymous \u2014 nobody sees who picked what"
2240
2434
  ] }),
2241
2435
  /* @__PURE__ */ jsx5(Notice, { notice }),
2242
- /* @__PURE__ */ jsxs2("div", { className: "mx-meet__collab-actions", children: [
2436
+ /* @__PURE__ */ jsxs3("div", { className: "mx-meet__collab-actions", children: [
2243
2437
  /* @__PURE__ */ jsx5("button", { type: "submit", className: "mx-meet__primary mx-meet__primary--small", disabled: !ready || busy, children: "Launch" }),
2244
2438
  /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", disabled: !ready || busy, onClick: () => void save(false), children: "Save draft" }),
2245
2439
  /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__link", onClick: onDone, children: "Cancel" })
@@ -2250,7 +2444,7 @@ function PollComposer({ maxOptions, onDone }) {
2250
2444
  }
2251
2445
  function PollCard({ poll }) {
2252
2446
  const { act, isHost } = useCollab();
2253
- const [picked, setPicked] = useState3(poll.myVote.slice());
2447
+ const [picked, setPicked] = useState4(poll.myVote.slice());
2254
2448
  const [notice, show] = useNotice();
2255
2449
  useEffect5(() => setPicked(poll.myVote.slice()), [poll.myVote]);
2256
2450
  const counts = poll.options.some((o) => o.votes !== void 0);
@@ -2262,12 +2456,12 @@ function PollCard({ poll }) {
2262
2456
  if (!canVote) return;
2263
2457
  setPicked(poll.multiple ? picked.includes(id) ? picked.filter((p) => p !== id) : [...picked, id] : [id]);
2264
2458
  };
2265
- return /* @__PURE__ */ jsxs2("article", { className: "mx-meet__collab-card", "aria-label": poll.question, children: [
2266
- /* @__PURE__ */ jsxs2("header", { className: "mx-meet__collab-head", children: [
2459
+ return /* @__PURE__ */ jsxs3("article", { className: "mx-meet__collab-card", "aria-label": poll.question, children: [
2460
+ /* @__PURE__ */ jsxs3("header", { className: "mx-meet__collab-head", children: [
2267
2461
  /* @__PURE__ */ jsx5("strong", { className: "mx-meet__collab-title", children: poll.question }),
2268
2462
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__collab-state", children: stateWord })
2269
2463
  ] }),
2270
- /* @__PURE__ */ jsxs2("p", { className: "mx-meet__panel-note", children: [
2464
+ /* @__PURE__ */ jsxs3("p", { className: "mx-meet__panel-note", children: [
2271
2465
  poll.multiple ? "Pick any." : "Pick one.",
2272
2466
  poll.anonymous ? " Anonymous." : "",
2273
2467
  counts && poll.voterCount !== null ? ` ${poll.voterCount} voted.` : "",
@@ -2276,8 +2470,8 @@ function PollCard({ poll }) {
2276
2470
  /* @__PURE__ */ jsx5("ul", { className: "mx-meet__poll-options", children: poll.options.map((option) => {
2277
2471
  const share = counts && total > 0 ? Math.round((option.votes ?? 0) / total * 100) : 0;
2278
2472
  const chosen = picked.includes(option.id);
2279
- return /* @__PURE__ */ jsxs2("li", { children: [
2280
- /* @__PURE__ */ jsxs2(
2473
+ return /* @__PURE__ */ jsxs3("li", { children: [
2474
+ /* @__PURE__ */ jsxs3(
2281
2475
  "button",
2282
2476
  {
2283
2477
  type: "button",
@@ -2288,7 +2482,7 @@ function PollCard({ poll }) {
2288
2482
  children: [
2289
2483
  counts ? /* @__PURE__ */ jsx5("span", { className: "mx-meet__poll-bar", style: { width: `${share}%` }, "aria-hidden": "true" }) : null,
2290
2484
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__poll-text", children: option.text }),
2291
- counts ? /* @__PURE__ */ jsxs2("span", { className: "mx-meet__poll-count", children: [
2485
+ counts ? /* @__PURE__ */ jsxs3("span", { className: "mx-meet__poll-count", children: [
2292
2486
  option.votes ?? 0,
2293
2487
  " \xB7 ",
2294
2488
  share,
@@ -2301,7 +2495,7 @@ function PollCard({ poll }) {
2301
2495
  ] }, option.id);
2302
2496
  }) }),
2303
2497
  /* @__PURE__ */ jsx5(Notice, { notice }),
2304
- /* @__PURE__ */ jsxs2("div", { className: "mx-meet__collab-actions", children: [
2498
+ /* @__PURE__ */ jsxs3("div", { className: "mx-meet__collab-actions", children: [
2305
2499
  canVote ? /* @__PURE__ */ jsx5(
2306
2500
  "button",
2307
2501
  {
@@ -2321,11 +2515,11 @@ function PollCard({ poll }) {
2321
2515
  }
2322
2516
  function PollsPanel({ onClose }) {
2323
2517
  const { collab, isHost } = useCollab();
2324
- const [composing, setComposing] = useState3(false);
2518
+ const [composing, setComposing] = useState4(false);
2325
2519
  const polls = collab?.polls ?? [];
2326
2520
  const maxOptions = collab?.settings?.pollMaxOptions ?? 10;
2327
2521
  const ordered = [...polls].reverse();
2328
- return /* @__PURE__ */ jsxs2(PanelShell, { title: "Polls", onClose, children: [
2522
+ return /* @__PURE__ */ jsxs3(PanelShell, { title: "Polls", onClose, children: [
2329
2523
  collab?.error != null ? /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note mx-meet__collab-error", children: collab.error }) : null,
2330
2524
  isHost && !composing ? /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__primary mx-meet__primary--small", onClick: () => setComposing(true), children: "New poll" }) : null,
2331
2525
  isHost && composing ? /* @__PURE__ */ jsx5(PollComposer, { maxOptions, onDone: () => setComposing(false) }) : null,
@@ -2335,12 +2529,12 @@ function PollsPanel({ onClose }) {
2335
2529
  }
2336
2530
  function QuestionCard({ question }) {
2337
2531
  const { act, isHost } = useCollab();
2338
- const [answering, setAnswering] = useState3(false);
2339
- const [reply, setReply] = useState3("");
2532
+ const [answering, setAnswering] = useState4(false);
2533
+ const [reply, setReply] = useState4("");
2340
2534
  const [notice, show] = useNotice();
2341
- return /* @__PURE__ */ jsxs2("li", { className: `mx-meet__collab-card mx-meet__question mx-meet__question--${question.state}`, children: [
2342
- /* @__PURE__ */ jsxs2("div", { className: "mx-meet__question-row", children: [
2343
- /* @__PURE__ */ jsxs2(
2535
+ return /* @__PURE__ */ jsxs3("li", { className: `mx-meet__collab-card mx-meet__question mx-meet__question--${question.state}`, children: [
2536
+ /* @__PURE__ */ jsxs3("div", { className: "mx-meet__question-row", children: [
2537
+ /* @__PURE__ */ jsxs3(
2344
2538
  "button",
2345
2539
  {
2346
2540
  type: "button",
@@ -2355,15 +2549,15 @@ function QuestionCard({ question }) {
2355
2549
  ]
2356
2550
  }
2357
2551
  ),
2358
- /* @__PURE__ */ jsxs2("div", { className: "mx-meet__question-body", children: [
2359
- /* @__PURE__ */ jsxs2("span", { className: "mx-meet__chat-meta", children: [
2552
+ /* @__PURE__ */ jsxs3("div", { className: "mx-meet__question-body", children: [
2553
+ /* @__PURE__ */ jsxs3("span", { className: "mx-meet__chat-meta", children: [
2360
2554
  /* @__PURE__ */ jsx5("strong", { children: question.mine ? "You" : question.askerName }),
2361
2555
  question.mine && question.anonymous ? /* @__PURE__ */ jsx5("span", { className: "mx-meet__chat-private", children: "anonymous" }) : null,
2362
2556
  question.state !== "open" ? /* @__PURE__ */ jsx5("span", { className: "mx-meet__collab-state", children: question.state === "answered" ? "Answered" : "Dismissed" }) : null
2363
2557
  ] }),
2364
2558
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__chat-text", children: question.text }),
2365
- question.answer !== null ? /* @__PURE__ */ jsxs2("span", { className: "mx-meet__question-answer", children: [
2366
- /* @__PURE__ */ jsxs2("strong", { children: [
2559
+ question.answer !== null ? /* @__PURE__ */ jsxs3("span", { className: "mx-meet__question-answer", children: [
2560
+ /* @__PURE__ */ jsxs3("strong", { children: [
2367
2561
  question.answeredByName ?? "Host",
2368
2562
  ":"
2369
2563
  ] }),
@@ -2372,7 +2566,7 @@ function QuestionCard({ question }) {
2372
2566
  ] }) : null
2373
2567
  ] })
2374
2568
  ] }),
2375
- answering ? /* @__PURE__ */ jsxs2(
2569
+ answering ? /* @__PURE__ */ jsxs3(
2376
2570
  "form",
2377
2571
  {
2378
2572
  className: "mx-meet__composer-row",
@@ -2404,7 +2598,7 @@ function QuestionCard({ question }) {
2404
2598
  }
2405
2599
  ) : null,
2406
2600
  /* @__PURE__ */ jsx5(Notice, { notice }),
2407
- isHost || question.mine ? /* @__PURE__ */ jsxs2("div", { className: "mx-meet__collab-actions", children: [
2601
+ isHost || question.mine ? /* @__PURE__ */ jsxs3("div", { className: "mx-meet__collab-actions", children: [
2408
2602
  isHost && question.state === "open" && !answering ? /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => setAnswering(true), children: "Answer" }) : null,
2409
2603
  isHost && question.state === "open" ? /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => void act({ action: "question_dismiss", itemId: question.id }).then(show), children: "Dismiss" }) : null,
2410
2604
  isHost && question.state !== "open" ? /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => void act({ action: "question_reopen", itemId: question.id }).then(show), children: "Reopen" }) : null,
@@ -2414,9 +2608,9 @@ function QuestionCard({ question }) {
2414
2608
  }
2415
2609
  function QaPanel({ onClose }) {
2416
2610
  const { collab, act } = useCollab();
2417
- const [draft, setDraft] = useState3("");
2418
- const [anonymous, setAnonymous] = useState3(false);
2419
- const [order, setOrder] = useState3("popular");
2611
+ const [draft, setDraft] = useState4("");
2612
+ const [anonymous, setAnonymous] = useState4(false);
2613
+ const [order, setOrder] = useState4("popular");
2420
2614
  const [notice, show] = useNotice();
2421
2615
  const allowAnonymous = collab?.settings?.qaAnonymousAllowed === true;
2422
2616
  const questions = [...collab?.questions ?? []];
@@ -2424,9 +2618,9 @@ function QaPanel({ onClose }) {
2424
2618
  questions.sort(
2425
2619
  (a, b) => rank(a) !== rank(b) ? rank(a) - rank(b) : order === "popular" ? b.upvotes - a.upvotes || (b.createdAt ?? "").localeCompare(a.createdAt ?? "") : (b.createdAt ?? "").localeCompare(a.createdAt ?? "")
2426
2620
  );
2427
- return /* @__PURE__ */ jsxs2(PanelShell, { title: "Q&A", onClose, children: [
2621
+ return /* @__PURE__ */ jsxs3(PanelShell, { title: "Q&A", onClose, children: [
2428
2622
  collab?.error != null ? /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note mx-meet__collab-error", children: collab.error }) : null,
2429
- /* @__PURE__ */ jsxs2(
2623
+ /* @__PURE__ */ jsxs3(
2430
2624
  "form",
2431
2625
  {
2432
2626
  className: "mx-meet__composer mx-meet__composer--chat",
@@ -2440,7 +2634,7 @@ function QaPanel({ onClose }) {
2440
2634
  });
2441
2635
  },
2442
2636
  children: [
2443
- /* @__PURE__ */ jsxs2("div", { className: "mx-meet__composer-row", children: [
2637
+ /* @__PURE__ */ jsxs3("div", { className: "mx-meet__composer-row", children: [
2444
2638
  /* @__PURE__ */ jsx5(
2445
2639
  "input",
2446
2640
  {
@@ -2454,7 +2648,7 @@ function QaPanel({ onClose }) {
2454
2648
  ),
2455
2649
  /* @__PURE__ */ jsx5("button", { type: "submit", className: "mx-meet__send", disabled: draft.trim().length === 0, children: "Ask" })
2456
2650
  ] }),
2457
- allowAnonymous ? /* @__PURE__ */ jsxs2("label", { className: "mx-meet__toggle", children: [
2651
+ allowAnonymous ? /* @__PURE__ */ jsxs3("label", { className: "mx-meet__toggle", children: [
2458
2652
  /* @__PURE__ */ jsx5("input", { type: "checkbox", checked: anonymous, onChange: (event) => setAnonymous(event.target.checked) }),
2459
2653
  "Ask anonymously"
2460
2654
  ] }) : null
@@ -2505,10 +2699,10 @@ function StrokeView({ stroke, onPick }) {
2505
2699
  }
2506
2700
  function WhiteboardPanel({ onClose }) {
2507
2701
  const { collab, act, isHost, localIdentity } = useCollab();
2508
- const [tool, setTool] = useState3("pen");
2509
- const [color, setColor] = useState3(INK[0]);
2510
- const [drawing, setDrawing] = useState3(null);
2511
- const [pending, setPending] = useState3([]);
2702
+ const [tool, setTool] = useState4("pen");
2703
+ const [color, setColor] = useState4(INK[0]);
2704
+ const [drawing, setDrawing] = useState4(null);
2705
+ const [pending, setPending] = useState4([]);
2512
2706
  const [notice, show] = useNotice();
2513
2707
  const svgRef = useRef5(null);
2514
2708
  const strokes = collab?.strokes ?? [];
@@ -2542,8 +2736,8 @@ function WhiteboardPanel({ onClose }) {
2542
2736
  if (!result.ok) show(result);
2543
2737
  });
2544
2738
  };
2545
- return /* @__PURE__ */ jsxs2("section", { className: "mx-meet__whiteboard", "aria-label": "Whiteboard", children: [
2546
- /* @__PURE__ */ jsxs2("header", { className: "mx-meet__whiteboard-bar", children: [
2739
+ return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__whiteboard", "aria-label": "Whiteboard", children: [
2740
+ /* @__PURE__ */ jsxs3("header", { className: "mx-meet__whiteboard-bar", children: [
2547
2741
  /* @__PURE__ */ jsx5("strong", { className: "mx-meet__panel-title", children: "Whiteboard" }),
2548
2742
  /* @__PURE__ */ jsx5("div", { className: "mx-meet__pills", role: "group", "aria-label": "Tool", children: [
2549
2743
  ["pen", "Pen", /* @__PURE__ */ jsx5(PencilIcon, { width: 16, height: 16 }, "p")],
@@ -2593,7 +2787,7 @@ function WhiteboardPanel({ onClose }) {
2593
2787
  /* @__PURE__ */ jsx5(ControlButton, { label: "Close whiteboard", onClick: onClose, children: /* @__PURE__ */ jsx5(CloseIcon, { width: 16, height: 16 }) })
2594
2788
  ] }),
2595
2789
  /* @__PURE__ */ jsx5(Notice, { notice }),
2596
- /* @__PURE__ */ jsxs2(
2790
+ /* @__PURE__ */ jsxs3(
2597
2791
  "svg",
2598
2792
  {
2599
2793
  ref: svgRef,
@@ -2651,7 +2845,7 @@ function clock(ms) {
2651
2845
  }
2652
2846
  var BREAKOUT_EXPIRE_RETRY_MS = 5e3;
2653
2847
  function useNow(active) {
2654
- const [now, setNow] = useState3(() => Date.now());
2848
+ const [now, setNow] = useState4(() => Date.now());
2655
2849
  useEffect5(() => {
2656
2850
  if (!active) return void 0;
2657
2851
  const timer = setInterval(() => setNow(Date.now()), 1e3);
@@ -2666,11 +2860,11 @@ function BreakoutSetup() {
2666
2860
  const people = (snapshot?.participants ?? []).filter(
2667
2861
  (p) => !p.isAgent && p.role !== "host" && p.role !== "cohost"
2668
2862
  );
2669
- const [count, setCount] = useState3(Math.min(Math.max(2, Math.ceil(people.length / 4)), settings?.breakoutMaxRooms ?? 20));
2670
- const [mode, setMode] = useState3("auto");
2671
- const [minutes, setMinutes] = useState3(settings?.breakoutDefaultMinutes ?? 15);
2672
- const [manual, setManual] = useState3({});
2673
- const [busy, setBusy] = useState3(false);
2863
+ const [count, setCount] = useState4(Math.min(Math.max(2, Math.ceil(people.length / 4)), settings?.breakoutMaxRooms ?? 20));
2864
+ const [mode, setMode] = useState4("auto");
2865
+ const [minutes, setMinutes] = useState4(settings?.breakoutDefaultMinutes ?? 15);
2866
+ const [manual, setManual] = useState4({});
2867
+ const [busy, setBusy] = useState4(false);
2674
2868
  const [notice, show] = useNotice();
2675
2869
  const max = settings?.breakoutMaxRooms ?? 20;
2676
2870
  const rooms = Math.min(Math.max(1, count), max);
@@ -2682,8 +2876,8 @@ function BreakoutSetup() {
2682
2876
  (_, index) => people.filter((p) => (manual[p.identity] ?? -1) === index).map((p) => p.identity)
2683
2877
  ) : Array.from({ length: rooms }, () => []);
2684
2878
  const nameOf = (identity) => people.find((p) => p.identity === identity)?.displayName ?? identity;
2685
- return /* @__PURE__ */ jsxs2("div", { className: "mx-meet__collab-card", children: [
2686
- /* @__PURE__ */ jsxs2("label", { className: "mx-meet__field", children: [
2879
+ return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__collab-card", children: [
2880
+ /* @__PURE__ */ jsxs3("label", { className: "mx-meet__field", children: [
2687
2881
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__field-label", children: "Rooms" }),
2688
2882
  /* @__PURE__ */ jsx5(
2689
2883
  "input",
@@ -2712,7 +2906,7 @@ function BreakoutSetup() {
2712
2906
  },
2713
2907
  value
2714
2908
  )) }),
2715
- /* @__PURE__ */ jsxs2("label", { className: "mx-meet__field", children: [
2909
+ /* @__PURE__ */ jsxs3("label", { className: "mx-meet__field", children: [
2716
2910
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__field-label", children: "Timer (minutes, 0 for none)" }),
2717
2911
  /* @__PURE__ */ jsx5(
2718
2912
  "input",
@@ -2726,9 +2920,9 @@ function BreakoutSetup() {
2726
2920
  }
2727
2921
  )
2728
2922
  ] }),
2729
- mode === "manual" ? people.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note", children: "Nobody else is in the meeting yet." }) : /* @__PURE__ */ jsx5("ul", { className: "mx-meet__people", children: people.map((person) => /* @__PURE__ */ jsxs2("li", { className: "mx-meet__person", children: [
2923
+ mode === "manual" ? people.length === 0 ? /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note", children: "Nobody else is in the meeting yet." }) : /* @__PURE__ */ jsx5("ul", { className: "mx-meet__people", children: people.map((person) => /* @__PURE__ */ jsxs3("li", { className: "mx-meet__person", children: [
2730
2924
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__person-name", children: person.displayName }),
2731
- /* @__PURE__ */ jsxs2(
2925
+ /* @__PURE__ */ jsxs3(
2732
2926
  "select",
2733
2927
  {
2734
2928
  className: "mx-meet__select mx-meet__select--compact",
@@ -2737,15 +2931,15 @@ function BreakoutSetup() {
2737
2931
  onChange: (event) => setManual({ ...manual, [person.identity]: Number(event.target.value) }),
2738
2932
  children: [
2739
2933
  /* @__PURE__ */ jsx5("option", { value: -1, children: "Main room" }),
2740
- Array.from({ length: rooms }, (_, index) => /* @__PURE__ */ jsxs2("option", { value: index, children: [
2934
+ Array.from({ length: rooms }, (_, index) => /* @__PURE__ */ jsxs3("option", { value: index, children: [
2741
2935
  "Room ",
2742
2936
  index + 1
2743
2937
  ] }, index))
2744
2938
  ]
2745
2939
  }
2746
2940
  )
2747
- ] }, person.identity)) }) : mode === "auto" ? /* @__PURE__ */ jsx5("ul", { className: "mx-meet__breakout-rooms", children: assignment.map((members, index) => /* @__PURE__ */ jsxs2("li", { children: [
2748
- /* @__PURE__ */ jsxs2("strong", { children: [
2941
+ ] }, person.identity)) }) : mode === "auto" ? /* @__PURE__ */ jsx5("ul", { className: "mx-meet__breakout-rooms", children: assignment.map((members, index) => /* @__PURE__ */ jsxs3("li", { children: [
2942
+ /* @__PURE__ */ jsxs3("strong", { children: [
2749
2943
  "Room ",
2750
2944
  index + 1
2751
2945
  ] }),
@@ -2753,7 +2947,7 @@ function BreakoutSetup() {
2753
2947
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__panel-note", children: members.length === 0 ? "empty" : members.map(nameOf).join(", ") })
2754
2948
  ] }, index)) }) : /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note", children: "Everyone picks a room from their own screen." }),
2755
2949
  /* @__PURE__ */ jsx5(Notice, { notice }),
2756
- /* @__PURE__ */ jsxs2(
2950
+ /* @__PURE__ */ jsxs3(
2757
2951
  "button",
2758
2952
  {
2759
2953
  type: "button",
@@ -2786,7 +2980,7 @@ function BreakoutRun({ plan }) {
2786
2980
  const snapshot = useMeetSnapshot();
2787
2981
  const now = useNow(plan.endsAt !== null);
2788
2982
  const remaining = breakoutRemainingMs(plan, now);
2789
- const [broadcast, setBroadcast] = useState3("");
2983
+ const [broadcast, setBroadcast] = useState4("");
2790
2984
  const [notice, show] = useNotice();
2791
2985
  const nameOf = (identity) => displayNameFor(snapshot?.names ?? {}, identity, snapshot?.participants.find((p) => p.identity === identity)?.displayName);
2792
2986
  const mine = assignedRoom(plan, localIdentity);
@@ -2798,8 +2992,8 @@ function BreakoutRun({ plan }) {
2798
2992
  }
2799
2993
  show(await moveTo(roomId));
2800
2994
  };
2801
- return /* @__PURE__ */ jsxs2("div", { className: "mx-meet__collab-card", children: [
2802
- /* @__PURE__ */ jsxs2("p", { className: "mx-meet__panel-note", children: [
2995
+ return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__collab-card", children: [
2996
+ /* @__PURE__ */ jsxs3("p", { className: "mx-meet__panel-note", children: [
2803
2997
  plan.rooms.length,
2804
2998
  " room",
2805
2999
  plan.rooms.length === 1 ? "" : "s",
@@ -2810,15 +3004,15 @@ function BreakoutRun({ plan }) {
2810
3004
  /* @__PURE__ */ jsx5("ul", { className: "mx-meet__breakout-rooms", children: plan.rooms.map((room) => {
2811
3005
  const here = breakoutRoomId === room.id;
2812
3006
  const mayJoin = isHost || plan.allowChoose || mine?.id === room.id;
2813
- return /* @__PURE__ */ jsxs2("li", { className: here ? "mx-meet__breakout-room mx-meet__breakout-room--here" : "mx-meet__breakout-room", children: [
2814
- /* @__PURE__ */ jsxs2("div", { className: "mx-meet__collab-head", children: [
3007
+ return /* @__PURE__ */ jsxs3("li", { className: here ? "mx-meet__breakout-room mx-meet__breakout-room--here" : "mx-meet__breakout-room", children: [
3008
+ /* @__PURE__ */ jsxs3("div", { className: "mx-meet__collab-head", children: [
2815
3009
  /* @__PURE__ */ jsx5("strong", { children: room.name }),
2816
3010
  here ? /* @__PURE__ */ jsx5("span", { className: "mx-meet__collab-state", children: "You are here" }) : mayJoin ? /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => void join(room.id), children: "Join" }) : null
2817
3011
  ] }),
2818
3012
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__panel-note", children: room.identities.length === 0 ? "Nobody assigned" : room.identities.map(nameOf).join(", ") }),
2819
- isHost && room.identities.length > 0 ? /* @__PURE__ */ jsx5("ul", { className: "mx-meet__people", children: room.identities.map((identity) => /* @__PURE__ */ jsxs2("li", { className: "mx-meet__person", children: [
3013
+ isHost && room.identities.length > 0 ? /* @__PURE__ */ jsx5("ul", { className: "mx-meet__people", children: room.identities.map((identity) => /* @__PURE__ */ jsxs3("li", { className: "mx-meet__person", children: [
2820
3014
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__person-name", children: nameOf(identity) }),
2821
- /* @__PURE__ */ jsxs2(
3015
+ /* @__PURE__ */ jsxs3(
2822
3016
  "select",
2823
3017
  {
2824
3018
  className: "mx-meet__select mx-meet__select--compact",
@@ -2839,7 +3033,7 @@ function BreakoutRun({ plan }) {
2839
3033
  ] }, room.id);
2840
3034
  }) }),
2841
3035
  breakoutRoomId !== null ? /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => void join(null), children: "Return to the main room" }) : null,
2842
- isHost ? /* @__PURE__ */ jsxs2(
3036
+ isHost ? /* @__PURE__ */ jsxs3(
2843
3037
  "form",
2844
3038
  {
2845
3039
  className: "mx-meet__composer-row",
@@ -2875,7 +3069,7 @@ function BreakoutRun({ plan }) {
2875
3069
  type: "button",
2876
3070
  className: "mx-meet__primary mx-meet__primary--small",
2877
3071
  onClick: () => void act({ action: "breakout_close" }).then(show),
2878
- children: "Bring everyone back"
3072
+ children: "Close rooms"
2879
3073
  }
2880
3074
  ) : null
2881
3075
  ] });
@@ -2883,7 +3077,7 @@ function BreakoutRun({ plan }) {
2883
3077
  function BreakoutsPanel({ onClose }) {
2884
3078
  const { collab, isHost } = useCollab();
2885
3079
  const plan = collab?.breakout?.state === "open" ? collab.breakout : null;
2886
- return /* @__PURE__ */ jsxs2(PanelShell, { title: "Breakout rooms", onClose, children: [
3080
+ return /* @__PURE__ */ jsxs3(PanelShell, { title: "Breakout rooms", onClose, children: [
2887
3081
  collab?.error != null ? /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note mx-meet__collab-error", children: collab.error }) : null,
2888
3082
  plan !== null ? /* @__PURE__ */ jsx5(BreakoutRun, { plan }) : isHost ? /* @__PURE__ */ jsx5(BreakoutSetup, {}) : /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note", children: "Breakout rooms are closed." })
2889
3083
  ] });
@@ -2893,11 +3087,16 @@ function BreakoutBanner() {
2893
3087
  const { collab, act, moveTo, localIdentity, breakoutRoomId } = useCollab();
2894
3088
  const plan = collab?.breakout ?? null;
2895
3089
  const open = plan?.state === "open" ? plan : null;
2896
- const now = useNow(open?.endsAt != null);
3090
+ const now = useNow(open?.endsAt != null || open?.closingAt != null);
2897
3091
  const remaining = breakoutRemainingMs(open, now);
3092
+ const closing = breakoutClosingMs(open, now);
2898
3093
  const assigned = assignedRoom(open, localIdentity);
2899
- const [dismissedBroadcast, setDismissedBroadcast] = useState3(null);
2900
- const [failure, setFailure] = useState3(null);
3094
+ const [later, setLater] = useState4(null);
3095
+ const [autoSince, setAutoSince] = useState4(null);
3096
+ const AUTO_MOVE_MS = 1e4;
3097
+ const autoLeft = open?.moveMode === "auto" && assigned !== null && autoSince?.id === open.id && later !== open.id ? Math.max(0, AUTO_MOVE_MS - (now - autoSince.at)) : null;
3098
+ const [dismissedBroadcast, setDismissedBroadcast] = useState4(null);
3099
+ const [failure, setFailure] = useState4(null);
2901
3100
  const expireAsked = useRef5(null);
2902
3101
  const moveAt = collab?.moveRequest?.at ?? null;
2903
3102
  useEffect5(() => {
@@ -2908,6 +3107,19 @@ function BreakoutBanner() {
2908
3107
  if ((here ?? null) === request.roomId) return;
2909
3108
  void moveTo(request.roomId).then((result) => setFailure(result.ok ? null : result.message));
2910
3109
  }, [moveAt, host, moveTo]);
3110
+ const joinAssigned = async () => {
3111
+ if (assigned === null) return;
3112
+ const said = await act({ action: "breakout_join", roomId: assigned.id });
3113
+ const result = said.ok ? await moveTo(assigned.id) : said;
3114
+ setFailure(result.ok ? null : result.message);
3115
+ };
3116
+ useEffect5(() => {
3117
+ if (open === null || open.moveMode !== "auto" || assigned === null || breakoutRoomId !== null) return;
3118
+ if (autoSince?.id !== open.id) setAutoSince({ id: open.id, at: Date.now() });
3119
+ }, [open, assigned, breakoutRoomId, autoSince]);
3120
+ useEffect5(() => {
3121
+ if (autoLeft === 0) void joinAssigned();
3122
+ }, [autoLeft]);
2911
3123
  useEffect5(() => {
2912
3124
  if (open === null || remaining === null || remaining > 0) return;
2913
3125
  const asked = expireAsked.current;
@@ -2919,31 +3131,29 @@ function BreakoutBanner() {
2919
3131
  const showBroadcast = broadcast !== null && broadcast.at !== dismissedBroadcast && open !== null;
2920
3132
  const room = open?.rooms.find((r) => r.id === breakoutRoomId) ?? null;
2921
3133
  if (open === null && failure === null) return null;
2922
- return /* @__PURE__ */ jsxs2("div", { className: "mx-meet__breakout-banner", role: "status", children: [
3134
+ return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__breakout-banner", role: "status", children: [
2923
3135
  failure !== null ? /* @__PURE__ */ jsx5("span", { className: "mx-meet__collab-error", children: failure }) : null,
2924
- room !== null ? /* @__PURE__ */ jsxs2("span", { children: [
3136
+ closing !== null ? /* @__PURE__ */ jsxs3("span", { role: "status", "data-meet-notice": "breakout-closing", children: [
3137
+ "Rooms closing in ",
3138
+ Math.ceil(closing / 1e3),
3139
+ room !== null ? " \u2014 you return to the main meeting" : ""
3140
+ ] }) : null,
3141
+ room !== null ? /* @__PURE__ */ jsxs3("span", { children: [
2925
3142
  /* @__PURE__ */ jsx5("strong", { children: room.name }),
2926
- remaining !== null ? ` \xB7 ${clock(remaining)} left` : "",
3143
+ remaining !== null && closing === null ? ` \xB7 ${clock(remaining)} left` : "",
2927
3144
  /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => void moveTo(null), children: "Return to main room" })
2928
- ] }) : assigned !== null ? /* @__PURE__ */ jsxs2("span", { children: [
2929
- "You are assigned to ",
2930
- /* @__PURE__ */ jsx5("strong", { children: assigned.name }),
2931
- remaining !== null ? ` \xB7 ${clock(remaining)} left` : "",
2932
- /* @__PURE__ */ jsx5(
2933
- "button",
2934
- {
2935
- type: "button",
2936
- className: "mx-meet__primary mx-meet__primary--small",
2937
- onClick: () => void act({ action: "breakout_join", roomId: assigned.id }).then(async (said) => {
2938
- const result = said.ok ? await moveTo(assigned.id) : said;
2939
- setFailure(result.ok ? null : result.message);
2940
- }),
2941
- children: "Join"
2942
- }
2943
- )
2944
- ] }) : open?.allowChoose ? /* @__PURE__ */ jsx5("span", { children: "Breakout rooms are open \u2014 pick one under Activities." }) : null,
2945
- showBroadcast ? /* @__PURE__ */ jsxs2("span", { className: "mx-meet__breakout-broadcast", children: [
2946
- /* @__PURE__ */ jsxs2("strong", { children: [
3145
+ ] }) : assigned !== null && later !== open?.id ? /* @__PURE__ */ jsxs3("span", { children: [
3146
+ autoLeft !== null ? `You're being moved to ${assigned.name} in ${Math.ceil(autoLeft / 1e3)} s` : `You're invited to ${assigned.name}`,
3147
+ remaining !== null && closing === null ? ` \xB7 ${clock(remaining)} left` : "",
3148
+ /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__primary mx-meet__primary--small", onClick: () => void joinAssigned(), children: "Join room" }),
3149
+ /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => setLater(open?.id ?? null), children: "Later" })
3150
+ ] }) : assigned !== null ? /* @__PURE__ */ jsxs3("span", { children: [
3151
+ assigned.name,
3152
+ " is open",
3153
+ /* @__PURE__ */ jsx5("button", { type: "button", className: "mx-meet__chip", onClick: () => void joinAssigned(), children: "Join room" })
3154
+ ] }) : open?.allowChoose ? /* @__PURE__ */ jsx5("span", { children: "Rooms are open \u2014 pick one under Activities." }) : null,
3155
+ showBroadcast ? /* @__PURE__ */ jsxs3("span", { className: "mx-meet__breakout-broadcast", children: [
3156
+ /* @__PURE__ */ jsxs3("strong", { children: [
2947
3157
  broadcast.by,
2948
3158
  ":"
2949
3159
  ] }),
@@ -2963,10 +3173,10 @@ function CaptionLanguageSettings() {
2963
3173
  const preferred = defaultCaptionLanguage(settings, viewer);
2964
3174
  const current = collab?.captionLanguage ?? "";
2965
3175
  const choices = CAPTION_LANGUAGES.some((l) => l.tag === preferred) ? CAPTION_LANGUAGES : [{ tag: preferred, name: preferred }, ...CAPTION_LANGUAGES];
2966
- return /* @__PURE__ */ jsxs2("section", { className: "mx-meet__section", "aria-label": "Captions", children: [
2967
- /* @__PURE__ */ jsxs2("label", { className: "mx-meet__field", children: [
3176
+ return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__section", "aria-label": "Captions", children: [
3177
+ /* @__PURE__ */ jsxs3("label", { className: "mx-meet__field", children: [
2968
3178
  /* @__PURE__ */ jsx5("span", { className: "mx-meet__field-label", children: "Translate captions to" }),
2969
- /* @__PURE__ */ jsxs2(
3179
+ /* @__PURE__ */ jsxs3(
2970
3180
  "select",
2971
3181
  {
2972
3182
  className: "mx-meet__select",
@@ -2977,7 +3187,7 @@ function CaptionLanguageSettings() {
2977
3187
  },
2978
3188
  children: [
2979
3189
  /* @__PURE__ */ jsx5("option", { value: "", children: "Off \u2014 as spoken" }),
2980
- current === "" ? /* @__PURE__ */ jsxs2("option", { value: preferred, children: [
3190
+ current === "" ? /* @__PURE__ */ jsxs3("option", { value: preferred, children: [
2981
3191
  choices.find((c) => c.tag === preferred)?.name ?? preferred,
2982
3192
  " (yours)"
2983
3193
  ] }) : null,
@@ -2989,12 +3199,39 @@ function CaptionLanguageSettings() {
2989
3199
  collab?.captionTranslationError != null ? /* @__PURE__ */ jsx5("p", { className: "mx-meet__panel-note mx-meet__collab-error", children: collab.captionTranslationError }) : null
2990
3200
  ] });
2991
3201
  }
3202
+ function CaptionsControl() {
3203
+ const captions = useCaptions();
3204
+ return /* @__PURE__ */ jsx5(
3205
+ ControlButton,
3206
+ {
3207
+ label: captions.on ? "Turn off captions" : "Turn on captions",
3208
+ active: captions.on,
3209
+ pressed: captions.on,
3210
+ onClick: captions.toggle,
3211
+ children: /* @__PURE__ */ jsx5(CaptionsIcon, {})
3212
+ }
3213
+ );
3214
+ }
3215
+ function TakeNotesControl() {
3216
+ const ai = useMeetAi();
3217
+ if (!ai.canControlNoteTaker) return null;
3218
+ const running = ai.noteTaker.state === "joining" || ai.noteTaker.state === "transcribing";
3219
+ return /* @__PURE__ */ jsx5(
3220
+ ControlButton,
3221
+ {
3222
+ label: running ? "Stop taking notes" : "Take notes for me",
3223
+ active: running,
3224
+ onClick: () => void (running ? ai.stopNoteTaker() : ai.startNoteTaker()),
3225
+ children: /* @__PURE__ */ jsx5(NotesIcon, {})
3226
+ }
3227
+ );
3228
+ }
2992
3229
 
2993
3230
  // src/skins/meet/components.tsx
2994
- import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
3231
+ import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
2995
3232
  function InertNotice({ what }) {
2996
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__empty", role: "status", children: [
2997
- /* @__PURE__ */ jsxs3("p", { className: "mx-meet__empty-title", children: [
3233
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__empty", role: "status", children: [
3234
+ /* @__PURE__ */ jsxs4("p", { className: "mx-meet__empty-title", children: [
2998
3235
  what,
2999
3236
  " is not ready yet"
3000
3237
  ] }),
@@ -3039,6 +3276,7 @@ function ControlButton({
3039
3276
  label,
3040
3277
  active = false,
3041
3278
  danger = false,
3279
+ pressed,
3042
3280
  onClick,
3043
3281
  children
3044
3282
  }) {
@@ -3053,26 +3291,49 @@ function ControlButton({
3053
3291
  ].filter(Boolean).join(" "),
3054
3292
  "aria-label": label,
3055
3293
  title: label,
3294
+ ...pressed !== void 0 ? { "aria-pressed": pressed } : {},
3056
3295
  onClick,
3057
3296
  children
3058
3297
  }
3059
3298
  );
3060
3299
  }
3061
3300
  function RecordingIndicator() {
3062
- const { state, label } = useRecording();
3063
- if (label === null) return null;
3064
- return /* @__PURE__ */ jsxs3(
3065
- "span",
3066
- {
3067
- className: `mx-meet__recording mx-meet__recording--${state}`,
3068
- role: "status",
3069
- "aria-live": "polite",
3070
- children: [
3071
- /* @__PURE__ */ jsx6(RecordIcon, { width: 10, height: 10 }),
3072
- label
3073
- ]
3301
+ const { state, label, canStart } = useRecording();
3302
+ const snapshot = useMeetSnapshot();
3303
+ const previous = useRef6(state);
3304
+ const [stoppedAt, setStoppedAt] = useState5(null);
3305
+ useEffect6(() => {
3306
+ const was = previous.current;
3307
+ previous.current = state;
3308
+ if ((was === "recording" || was === "starting") && state !== "recording" && state !== "starting") {
3309
+ setStoppedAt(Date.now());
3310
+ const timer = setTimeout(() => setStoppedAt(null), 1e4);
3311
+ return () => clearTimeout(timer);
3074
3312
  }
3075
- );
3313
+ return void 0;
3314
+ }, [state]);
3315
+ const meetingId = snapshot?.meeting?.id ?? null;
3316
+ if (label === null && stoppedAt === null) return null;
3317
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
3318
+ label !== null ? /* @__PURE__ */ jsxs4(
3319
+ "span",
3320
+ {
3321
+ className: `mx-meet__recording mx-meet__recording--${state}`,
3322
+ role: "status",
3323
+ "aria-live": "polite",
3324
+ children: [
3325
+ /* @__PURE__ */ jsx6(RecordIcon, { width: 10, height: 10 }),
3326
+ label
3327
+ ]
3328
+ }
3329
+ ) : null,
3330
+ stoppedAt !== null ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__recording", role: "status", "data-meet-notice": "recording-stopped", children: "Recording stopped" }) : null,
3331
+ state === "processing" ? (
3332
+ // rec-processing: the host is told it is being made ready (the indicator says Processing…).
3333
+ /* @__PURE__ */ jsx6("span", { className: "mx-meet__recording", role: "status", "data-meet-notice": "recording-processing", children: "Your recording is being processed. A link appears here when it is ready." })
3334
+ ) : null,
3335
+ state === "available" && canStart && meetingId !== null ? /* @__PURE__ */ jsx6("a", { className: "mx-meet__link", href: `/meetings/${meetingId}`, target: "_blank", rel: "noreferrer", children: "View recording" }) : null
3336
+ ] });
3076
3337
  }
3077
3338
  function ConnectionDot({ quality }) {
3078
3339
  if (quality === "excellent" || quality === "good" || quality === "unknown") return null;
@@ -3095,7 +3356,7 @@ function ParticipantTile({
3095
3356
  const host = useMeetHost();
3096
3357
  const snapshot = useMeetSnapshot();
3097
3358
  const queue = useHandQueue();
3098
- const [menu, setMenu] = useState4(false);
3359
+ const [menu, setMenu] = useState5(false);
3099
3360
  const videoRef = useTrack(
3100
3361
  participant.identity,
3101
3362
  participant.screenSharing ? "screen" : "camera"
@@ -3105,7 +3366,7 @@ function ParticipantTile({
3105
3366
  const spotlit = snapshot?.spotlight === participant.identity;
3106
3367
  const presenting = snapshot?.presenter === participant.identity;
3107
3368
  const handPosition = participant.handRaised ? queue.findIndex((entry) => entry.identity === participant.identity) + 1 : 0;
3108
- return /* @__PURE__ */ jsxs3(
3369
+ return /* @__PURE__ */ jsxs4(
3109
3370
  "div",
3110
3371
  {
3111
3372
  className: [
@@ -3128,12 +3389,12 @@ function ParticipantTile({
3128
3389
  }
3129
3390
  ) : /* @__PURE__ */ jsx6("div", { className: "mx-meet__tile-placeholder", children: /* @__PURE__ */ jsx6(Avatar, { name: participant.displayName, url: participant.avatarUrl, size: featured ? 96 : 56 }) }),
3130
3391
  presenting ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__tile-presenting", role: "status", children: participant.isLocal ? "You are presenting" : `${participant.displayName} is presenting` }) : null,
3131
- participant.handRaised ? /* @__PURE__ */ jsxs3("span", { className: "mx-meet__tile-hand", title: `Hand raised \xB7 ${ordinal(handPosition)} in line`, children: [
3392
+ participant.handRaised ? /* @__PURE__ */ jsxs4("span", { className: "mx-meet__tile-hand", title: `Hand raised \xB7 ${ordinal(handPosition)} in line`, children: [
3132
3393
  /* @__PURE__ */ jsx6(HandIcon, { width: 14, height: 14 }),
3133
3394
  handPosition > 0 ? handPosition : null
3134
3395
  ] }) : null,
3135
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__tile-bar", children: [
3136
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__tile-name", children: [
3396
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__tile-bar", children: [
3397
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__tile-name", children: [
3137
3398
  spotlit ? /* @__PURE__ */ jsx6("span", { title: "Spotlighted for everyone", className: "mx-meet__tile-flag", children: /* @__PURE__ */ jsx6(SpotlightIcon, { width: 12, height: 12 }) }) : null,
3138
3399
  participant.displayName,
3139
3400
  participant.isLocal ? " (you)" : "",
@@ -3144,7 +3405,7 @@ function ParticipantTile({
3144
3405
  !participant.micEnabled ? /* @__PURE__ */ jsx6(MicOffIcon, { width: 14, height: 14 }) : null,
3145
3406
  /* @__PURE__ */ jsx6(QualityBars, { quality: participant.quality })
3146
3407
  ] }),
3147
- /* @__PURE__ */ jsxs3("div", { className: menu ? "mx-meet__tile-actions mx-meet__tile-actions--open" : "mx-meet__tile-actions", children: [
3408
+ /* @__PURE__ */ jsxs4("div", { className: menu ? "mx-meet__tile-actions mx-meet__tile-actions--open" : "mx-meet__tile-actions", children: [
3148
3409
  /* @__PURE__ */ jsx6(
3149
3410
  ControlButton,
3150
3411
  {
@@ -3154,7 +3415,7 @@ function ParticipantTile({
3154
3415
  children: /* @__PURE__ */ jsx6(PinIcon, { width: 16, height: 16 })
3155
3416
  }
3156
3417
  ),
3157
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__anchor", children: [
3418
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__anchor", children: [
3158
3419
  /* @__PURE__ */ jsx6(
3159
3420
  ControlButton,
3160
3421
  {
@@ -3192,12 +3453,12 @@ function Stage({ pageSize }) {
3192
3453
  const stage = useStage(pageSize);
3193
3454
  const columns = gridColumns(stage.tiles.length);
3194
3455
  if (stage.feature === null && stage.tiles.length === 0) {
3195
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__stage mx-meet__stage--empty", children: [
3456
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__stage mx-meet__stage--empty", children: [
3196
3457
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__empty-title", children: "Waiting for others to join" }),
3197
3458
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__empty-body", children: "Share the meeting link and people can join from anywhere \u2014 no account needed." })
3198
3459
  ] });
3199
3460
  }
3200
- return /* @__PURE__ */ jsxs3("div", { className: `mx-meet__stage${stage.feature !== null ? " mx-meet__stage--speaker" : ""}`, children: [
3461
+ return /* @__PURE__ */ jsxs4("div", { className: `mx-meet__stage${stage.feature !== null ? " mx-meet__stage--speaker" : ""}`, children: [
3201
3462
  stage.feature !== null ? /* @__PURE__ */ jsx6(ParticipantTile, { participant: stage.feature, featured: true }) : null,
3202
3463
  /* @__PURE__ */ jsx6(
3203
3464
  "div",
@@ -3207,7 +3468,7 @@ function Stage({ pageSize }) {
3207
3468
  children: stage.tiles.map((participant) => /* @__PURE__ */ jsx6(ParticipantTile, { participant }, participant.identity))
3208
3469
  }
3209
3470
  ),
3210
- stage.overflow > 0 ? /* @__PURE__ */ jsxs3("p", { className: "mx-meet__overflow", children: [
3471
+ stage.overflow > 0 ? /* @__PURE__ */ jsxs4("p", { className: "mx-meet__overflow", children: [
3211
3472
  "+",
3212
3473
  stage.overflow,
3213
3474
  " more ",
@@ -3219,17 +3480,18 @@ function Stage({ pageSize }) {
3219
3480
  function ControlBar({ onLeave }) {
3220
3481
  const room = useRoom();
3221
3482
  const recording = useRecording();
3222
- const [panel, setPanel] = useState4("none");
3223
- const [chatTo, setChatTo] = useState4(null);
3224
- const [popover, setPopover] = useState4("none");
3225
- const [shortcuts, setShortcuts] = useState4(false);
3483
+ const [panel, setPanel] = useState5("none");
3484
+ const [chatTo, setChatTo] = useState5(null);
3485
+ const [popover, setPopover] = useState5("none");
3486
+ const [shortcuts, setShortcuts] = useState5(false);
3226
3487
  const snapshot = useMeetSnapshot();
3227
3488
  const lobby = useLobby();
3228
3489
  const controls = useHostControls();
3229
3490
  const queue = useHandQueue();
3230
3491
  const micUnavailable = useLocalMedia().microphone.unavailable;
3492
+ const live = useLivePolicy();
3231
3493
  const unread = useUnreadChat(panel === "chat");
3232
- const [whiteboard, setWhiteboard] = useState4(false);
3494
+ const [whiteboard, setWhiteboard] = useState5(false);
3233
3495
  const app = useMeetAppPanel();
3234
3496
  const appOpened = useRef6(false);
3235
3497
  useEffect6(() => {
@@ -3263,7 +3525,7 @@ function ControlBar({ onLeave }) {
3263
3525
  help: () => setShortcuts(true)
3264
3526
  });
3265
3527
  const hasSpotlight = snapshot?.spotlight !== null && snapshot?.spotlight !== void 0;
3266
- return /* @__PURE__ */ jsxs3(Fragment, { children: [
3528
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
3267
3529
  /* @__PURE__ */ jsx6(MeetingOverlays, {}),
3268
3530
  shortcuts ? /* @__PURE__ */ jsx6(ShortcutsSheet, { onClose: () => setShortcuts(false) }) : null,
3269
3531
  panel === "chat" ? /* @__PURE__ */ jsx6(ChatPanel, { onClose: () => setPanel("none"), to: chatTo, onTo: setChatTo }) : null,
@@ -3293,9 +3555,10 @@ function ControlBar({ onLeave }) {
3293
3555
  ) }) }) : null,
3294
3556
  /* @__PURE__ */ jsx6(BreakoutBanner, {}),
3295
3557
  panel !== "people" ? /* @__PURE__ */ jsx6(KnockNotice, { onView: () => setPanel("people") }) : null,
3558
+ /* @__PURE__ */ jsx6(SpeakingWhileMutedNudge, {}),
3296
3559
  controls.notice !== null && panel !== "people" ? /* @__PURE__ */ jsx6(Toast, { text: controls.notice.text, failed: controls.notice.failed, onDone: controls.clearNotice }) : null,
3297
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__controls", children: [
3298
- /* @__PURE__ */ jsx6(
3560
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__controls", children: [
3561
+ live.micLocked ? null : /* @__PURE__ */ jsx6(
3299
3562
  ControlButton,
3300
3563
  {
3301
3564
  label: micUnavailable !== null ? `Unmute \u2014 ${micUnavailable.remedy}` : room.local?.micEnabled === true ? "Mute (\u2318D)" : "Unmute (\u2318D)",
@@ -3304,7 +3567,8 @@ function ControlBar({ onLeave }) {
3304
3567
  children: room.local?.micEnabled === true ? /* @__PURE__ */ jsx6(MicIcon, {}) : /* @__PURE__ */ jsx6(MicOffIcon, {})
3305
3568
  }
3306
3569
  ),
3307
- /* @__PURE__ */ jsx6(
3570
+ /* @__PURE__ */ jsx6(AudioSettingsControl, {}),
3571
+ live.cameraLocked ? null : /* @__PURE__ */ jsx6(
3308
3572
  ControlButton,
3309
3573
  {
3310
3574
  label: room.local?.cameraEnabled === true ? "Stop video (\u2318E)" : "Start video (\u2318E)",
@@ -3313,6 +3577,7 @@ function ControlBar({ onLeave }) {
3313
3577
  children: room.local?.cameraEnabled === true ? /* @__PURE__ */ jsx6(CameraIcon, {}) : /* @__PURE__ */ jsx6(CameraOffIcon, {})
3314
3578
  }
3315
3579
  ),
3580
+ /* @__PURE__ */ jsx6(CaptionsControl, {}),
3316
3581
  room.canShareScreen || room.local?.screenSharing === true ? /* @__PURE__ */ jsx6(
3317
3582
  ControlButton,
3318
3583
  {
@@ -3322,7 +3587,7 @@ function ControlBar({ onLeave }) {
3322
3587
  children: /* @__PURE__ */ jsx6(ScreenShareIcon, {})
3323
3588
  }
3324
3589
  ) : null,
3325
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__anchor", children: [
3590
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__anchor", children: [
3326
3591
  /* @__PURE__ */ jsx6(
3327
3592
  ControlButton,
3328
3593
  {
@@ -3354,11 +3619,11 @@ function ControlBar({ onLeave }) {
3354
3619
  }
3355
3620
  ),
3356
3621
  app !== null ? /* @__PURE__ */ jsx6(ControlButton, { label: app.title, active: panel === "app", onClick: () => toggle("app"), children: /* @__PURE__ */ jsx6(FlagIcon, {}) }) : null,
3357
- /* @__PURE__ */ jsxs3(ControlButton, { label: "Chat (\u2318\u2325C)", active: panel === "chat", onClick: () => toggle("chat"), children: [
3622
+ /* @__PURE__ */ jsxs4(ControlButton, { label: "Chat (\u2318\u2325C)", active: panel === "chat", onClick: () => toggle("chat"), children: [
3358
3623
  /* @__PURE__ */ jsx6(ChatIcon, {}),
3359
3624
  unread > 0 ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__dot", "aria-hidden": "true" }) : null
3360
3625
  ] }),
3361
- /* @__PURE__ */ jsxs3(
3626
+ /* @__PURE__ */ jsxs4(
3362
3627
  ControlButton,
3363
3628
  {
3364
3629
  label: lobby.waiting.length > 0 ? `People \u2014 ${lobby.waiting.length} waiting` : `People \u2014 ${(snapshot?.participants ?? []).length} in the meeting`,
@@ -3377,10 +3642,11 @@ function ControlBar({ onLeave }) {
3377
3642
  onOpen: openActivity
3378
3643
  }
3379
3644
  ),
3645
+ /* @__PURE__ */ jsx6(TakeNotesControl, {}),
3380
3646
  /* @__PURE__ */ jsx6(AiControl, { active: panel === "ai", onToggle: () => toggle("ai") }),
3381
3647
  recording.canStart ? /* @__PURE__ */ jsx6(ControlButton, { label: "Start recording", onClick: () => void recording.start(), children: /* @__PURE__ */ jsx6(RecordIcon, {}) }) : null,
3382
3648
  recording.canStop ? /* @__PURE__ */ jsx6(ControlButton, { label: "Stop recording", active: true, onClick: () => void recording.stop(), children: /* @__PURE__ */ jsx6(RecordIcon, {}) }) : null,
3383
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__anchor", children: [
3649
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__anchor", children: [
3384
3650
  /* @__PURE__ */ jsx6(
3385
3651
  ControlButton,
3386
3652
  {
@@ -3390,8 +3656,8 @@ function ControlBar({ onLeave }) {
3390
3656
  children: /* @__PURE__ */ jsx6(MoreIcon, {})
3391
3657
  }
3392
3658
  ),
3393
- popover === "more" ? /* @__PURE__ */ jsx6(Popover, { label: "More options", onClose: () => setPopover("none"), children: /* @__PURE__ */ jsxs3("div", { className: "mx-meet__menu", role: "menu", children: [
3394
- /* @__PURE__ */ jsxs3(
3659
+ popover === "more" ? /* @__PURE__ */ jsx6(Popover, { label: "More options", onClose: () => setPopover("none"), children: /* @__PURE__ */ jsxs4("div", { className: "mx-meet__menu", role: "menu", children: [
3660
+ /* @__PURE__ */ jsxs4(
3395
3661
  MenuItem,
3396
3662
  {
3397
3663
  onSelect: () => {
@@ -3404,7 +3670,7 @@ function ControlBar({ onLeave }) {
3404
3670
  ]
3405
3671
  }
3406
3672
  ),
3407
- /* @__PURE__ */ jsxs3(
3673
+ /* @__PURE__ */ jsxs4(
3408
3674
  MenuItem,
3409
3675
  {
3410
3676
  onSelect: () => {
@@ -3417,9 +3683,16 @@ function ControlBar({ onLeave }) {
3417
3683
  ]
3418
3684
  }
3419
3685
  ),
3420
- controls.isHost ? /* @__PURE__ */ jsxs3(Fragment, { children: [
3686
+ !room.canShareScreen && room.local?.screenSharing !== true ? (
3687
+ // `share-unsupported-mobile`: the control is absent; the menu says where it lives.
3688
+ /* @__PURE__ */ jsxs4("p", { className: "mx-meet__menu-note", role: "note", "data-meet-notice": "share-unsupported", children: [
3689
+ /* @__PURE__ */ jsx6(ScreenShareIcon, { width: 16, height: 16 }),
3690
+ " Present from a computer"
3691
+ ] })
3692
+ ) : null,
3693
+ controls.isHost ? /* @__PURE__ */ jsxs4(Fragment, { children: [
3421
3694
  /* @__PURE__ */ jsx6("div", { className: "mx-meet__menu-sep", role: "separator" }),
3422
- /* @__PURE__ */ jsxs3(
3695
+ /* @__PURE__ */ jsxs4(
3423
3696
  MenuItem,
3424
3697
  {
3425
3698
  onSelect: () => {
@@ -3432,7 +3705,24 @@ function ControlBar({ onLeave }) {
3432
3705
  ]
3433
3706
  }
3434
3707
  ),
3435
- /* @__PURE__ */ jsxs3(
3708
+ /* @__PURE__ */ jsxs4(
3709
+ MenuItem,
3710
+ {
3711
+ onSelect: () => {
3712
+ setPopover("none");
3713
+ void controls.run({
3714
+ action: "set_av_lock",
3715
+ value: snapshot?.livePolicy.avLock === "both" ? "off" : "both"
3716
+ });
3717
+ },
3718
+ children: [
3719
+ /* @__PURE__ */ jsx6(MicOffIcon, { width: 16, height: 16 }),
3720
+ " ",
3721
+ snapshot?.livePolicy.avLock === "both" ? "Turn on attendees' microphone and camera" : "Turn off attendees' microphone and camera"
3722
+ ]
3723
+ }
3724
+ ),
3725
+ /* @__PURE__ */ jsxs4(
3436
3726
  MenuItem,
3437
3727
  {
3438
3728
  onSelect: () => {
@@ -3445,7 +3735,7 @@ function ControlBar({ onLeave }) {
3445
3735
  ]
3446
3736
  }
3447
3737
  ),
3448
- queue.length > 0 ? /* @__PURE__ */ jsxs3(
3738
+ queue.length > 0 ? /* @__PURE__ */ jsxs4(
3449
3739
  MenuItem,
3450
3740
  {
3451
3741
  onSelect: () => {
@@ -3460,7 +3750,7 @@ function ControlBar({ onLeave }) {
3460
3750
  ]
3461
3751
  }
3462
3752
  ) : null,
3463
- hasSpotlight ? /* @__PURE__ */ jsxs3(
3753
+ hasSpotlight ? /* @__PURE__ */ jsxs4(
3464
3754
  MenuItem,
3465
3755
  {
3466
3756
  onSelect: () => {
@@ -3487,8 +3777,8 @@ var LEAVE_WORDS = {
3487
3777
  };
3488
3778
  function LeaveControl({ onLeave }) {
3489
3779
  const leave = useLeave();
3490
- const [open, setOpen] = useState4("none");
3491
- const [failure, setFailure] = useState4(null);
3780
+ const [open, setOpen] = useState5("none");
3781
+ const [failure, setFailure] = useState5(null);
3492
3782
  const words = LEAVE_WORDS[leave.policy.hostLeavePrompt];
3493
3783
  const run = (work, leaving) => {
3494
3784
  setFailure(null);
@@ -3499,7 +3789,7 @@ function LeaveControl({ onLeave }) {
3499
3789
  };
3500
3790
  const leaveNow = () => run(leave.leave, true);
3501
3791
  const endNow = () => run(leave.endForAll, false);
3502
- return /* @__PURE__ */ jsxs3("span", { className: "mx-meet__anchor", children: [
3792
+ return /* @__PURE__ */ jsxs4("span", { className: "mx-meet__anchor", children: [
3503
3793
  /* @__PURE__ */ jsx6(
3504
3794
  ControlButton,
3505
3795
  {
@@ -3513,7 +3803,7 @@ function LeaveControl({ onLeave }) {
3513
3803
  children: /* @__PURE__ */ jsx6(PhoneOffIcon, {})
3514
3804
  }
3515
3805
  ),
3516
- open !== "none" ? /* @__PURE__ */ jsx6(Popover, { label: open === "assign" ? words.assign_and_leave : "Leave", onClose: () => setOpen("none"), children: /* @__PURE__ */ jsxs3("div", { className: "mx-meet__menu", "data-meet-leave-menu": leave.policy.hostLeavePrompt, children: [
3806
+ open !== "none" ? /* @__PURE__ */ jsx6(Popover, { label: open === "assign" ? words.assign_and_leave : "Leave", onClose: () => setOpen("none"), children: /* @__PURE__ */ jsxs4("div", { className: "mx-meet__menu", "data-meet-leave-menu": leave.policy.hostLeavePrompt, children: [
3517
3807
  open === "menu" ? leave.choices.map((choice) => /* @__PURE__ */ jsx6(
3518
3808
  "button",
3519
3809
  {
@@ -3539,7 +3829,7 @@ function LeaveControl({ onLeave }) {
3539
3829
  },
3540
3830
  String(person.identity)
3541
3831
  )) : null,
3542
- open === "confirm" ? /* @__PURE__ */ jsxs3(Fragment, { children: [
3832
+ open === "confirm" ? /* @__PURE__ */ jsxs4(Fragment, { children: [
3543
3833
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__menu-item mx-meet__menu-item--danger", onClick: endNow, children: words.end_for_all }),
3544
3834
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__menu-item", onClick: () => setOpen("menu"), children: "Cancel" })
3545
3835
  ] }) : null,
@@ -3560,12 +3850,12 @@ function useUnreadChat(open) {
3560
3850
  const snapshot = useMeetSnapshot();
3561
3851
  const chat = snapshot?.chat ?? [];
3562
3852
  const local = snapshot?.localIdentity ?? null;
3563
- const [seen, setSeen] = useState4(0);
3853
+ const [seen, setSeen] = useState5(0);
3564
3854
  useEffect6(() => {
3565
3855
  if (open) setSeen(chat.length);
3566
3856
  }, [open, chat.length]);
3567
3857
  const loaded = snapshot?.chatLoaded === true;
3568
- const [baseline, setBaseline] = useState4(null);
3858
+ const [baseline, setBaseline] = useState5(null);
3569
3859
  useEffect6(() => {
3570
3860
  if (loaded && baseline === null) setBaseline(chat.length);
3571
3861
  }, [loaded, baseline, chat.length]);
@@ -3580,7 +3870,7 @@ function Popover({
3580
3870
  placement = "up"
3581
3871
  }) {
3582
3872
  const ref = useRef6(null);
3583
- const [style, setStyle] = useState4({
3873
+ const [style, setStyle] = useState5({
3584
3874
  position: "fixed",
3585
3875
  top: 0,
3586
3876
  left: 0,
@@ -3669,15 +3959,103 @@ function Toast({ text, failed, onDone }) {
3669
3959
  const timer = setTimeout(onDone, failed ? 7e3 : 4e3);
3670
3960
  return () => clearTimeout(timer);
3671
3961
  }, [text, failed, onDone]);
3672
- return /* @__PURE__ */ jsxs3("div", { className: failed ? "mx-meet__toast mx-meet__toast--failed" : "mx-meet__toast", role: "status", children: [
3962
+ return /* @__PURE__ */ jsxs4("div", { className: failed ? "mx-meet__toast mx-meet__toast--failed" : "mx-meet__toast", role: "status", children: [
3673
3963
  /* @__PURE__ */ jsx6("span", { children: text }),
3674
3964
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__toast-close", "aria-label": "Dismiss", onClick: onDone, children: /* @__PURE__ */ jsx6(CloseIcon, { width: 14, height: 14 }) })
3675
3965
  ] });
3676
3966
  }
3967
+ function AudioSettingsControl() {
3968
+ const host = useMeetHost();
3969
+ const devices = useDeviceSnapshot();
3970
+ const [open, setOpen] = useState5(false);
3971
+ const list = (devices?.devices.audioinput ?? []).filter((device) => device.deviceId.length > 0);
3972
+ if (host === null || list.length < 2) return null;
3973
+ const current = devices?.selected.audioinput ?? host.devices.resolve("audioinput");
3974
+ return /* @__PURE__ */ jsxs4("span", { className: "mx-meet__anchor", children: [
3975
+ /* @__PURE__ */ jsx6(
3976
+ ControlButton,
3977
+ {
3978
+ label: "Audio settings",
3979
+ active: open,
3980
+ onClick: () => {
3981
+ if (!open) void host.devices.refresh();
3982
+ setOpen(!open);
3983
+ },
3984
+ children: /* @__PURE__ */ jsx6(ChevronUpIcon, {})
3985
+ }
3986
+ ),
3987
+ open ? /* @__PURE__ */ jsx6(Popover, { label: "Microphone", onClose: () => setOpen(false), children: /* @__PURE__ */ jsx6("div", { className: "mx-meet__menu", role: "menu", "aria-label": "Microphone", children: list.map((device) => /* @__PURE__ */ jsxs4(
3988
+ "button",
3989
+ {
3990
+ type: "button",
3991
+ role: "menuitemradio",
3992
+ "aria-checked": device.deviceId === current,
3993
+ className: "mx-meet__menu-item",
3994
+ onClick: () => {
3995
+ setOpen(false);
3996
+ host.devices.select("audioinput", device.deviceId);
3997
+ void host.engine.switchDevice("audioinput", device.deviceId).catch(() => void 0);
3998
+ },
3999
+ children: [
4000
+ device.deviceId === current ? /* @__PURE__ */ jsx6(CheckIcon, { width: 16, height: 16 }) : /* @__PURE__ */ jsx6("span", { className: "mx-meet__menu-gap" }),
4001
+ device.label.length > 0 ? device.label : "Microphone"
4002
+ ]
4003
+ },
4004
+ device.deviceId
4005
+ )) }) }) : null
4006
+ ] });
4007
+ }
4008
+ function SpeakingWhileMutedNudge() {
4009
+ const room = useRoom();
4010
+ const host = useMeetHost();
4011
+ const devices = useDeviceSnapshot();
4012
+ const microphone = useLocalMedia().microphone;
4013
+ const mutedByMe = host !== null && room.local != null && room.local.micEnabled !== true && microphone.unavailable === null;
4014
+ const mic = devices?.selected.audioinput ?? host?.devices.resolve("audioinput") ?? null;
4015
+ const stream = useMicrophoneStream(mutedByMe ? mic : "off");
4016
+ const level = useAudioLevel(stream);
4017
+ const latest = useRef6(0);
4018
+ latest.current = level;
4019
+ const [shown, setShown] = useState5(false);
4020
+ const [detector] = useState5(() => createSpeakingWhileMutedDetector());
4021
+ useEffect6(() => {
4022
+ if (!mutedByMe) {
4023
+ detector.reset();
4024
+ setShown(false);
4025
+ return void 0;
4026
+ }
4027
+ const timer = setInterval(() => {
4028
+ if (detector.feed(latest.current, Date.now())) setShown(true);
4029
+ }, 150);
4030
+ return () => clearInterval(timer);
4031
+ }, [mutedByMe, detector]);
4032
+ useEffect6(() => {
4033
+ if (!shown) return void 0;
4034
+ const timer = setTimeout(() => setShown(false), 8e3);
4035
+ return () => clearTimeout(timer);
4036
+ }, [shown]);
4037
+ if (!shown || !mutedByMe) return null;
4038
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__notice-bar", role: "status", "data-meet-notice": "speaking-while-muted", children: [
4039
+ /* @__PURE__ */ jsx6(MicOffIcon, { width: 16, height: 16 }),
4040
+ /* @__PURE__ */ jsx6("span", { children: "You're muted" }),
4041
+ /* @__PURE__ */ jsx6(
4042
+ "button",
4043
+ {
4044
+ type: "button",
4045
+ className: "mx-meet__primary mx-meet__primary--small",
4046
+ onClick: () => {
4047
+ setShown(false);
4048
+ void room.toggleMicrophone();
4049
+ },
4050
+ children: "Unmute"
4051
+ }
4052
+ )
4053
+ ] });
4054
+ }
3677
4055
  function MediaNotices() {
3678
4056
  const media = useLocalMedia();
3679
4057
  const { region, where, enableAudio, acceptOffer, dismissOffer, dismissNotice, retry } = useMediaSupervisor();
3680
- const [fixing, setFixing] = useState4(null);
4058
+ const [fixing, setFixing] = useState5(null);
3681
4059
  const chips = ["microphone", "camera"].flatMap((kind) => {
3682
4060
  const reason = deviceUnavailableReason(media[kind], region.permission[kind]);
3683
4061
  return reason === null ? [] : [{ kind, reason }];
@@ -3687,8 +4065,8 @@ function MediaNotices() {
3687
4065
  const offer = region.offer;
3688
4066
  const name = (kind) => kind === "microphone" ? "Microphone" : "Camera";
3689
4067
  if (chips.length === 0 && region.audioOutput !== "blocked" && notice === null && offer === null) return null;
3690
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__media-notices", children: [
3691
- region.audioOutput === "blocked" ? /* @__PURE__ */ jsxs3(
4068
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__media-notices", children: [
4069
+ region.audioOutput === "blocked" ? /* @__PURE__ */ jsxs4(
3692
4070
  ErrorBox,
3693
4071
  {
3694
4072
  as: "div",
@@ -3703,7 +4081,7 @@ function MediaNotices() {
3703
4081
  ]
3704
4082
  }
3705
4083
  ) : null,
3706
- chips.map(({ kind, reason }) => /* @__PURE__ */ jsxs3("div", { className: "mx-meet__media-pill", role: "status", "data-meet-notice": deviceNoticeCode(kind, reason), children: [
4084
+ chips.map(({ kind, reason }) => /* @__PURE__ */ jsxs4("div", { className: "mx-meet__media-pill", role: "status", "data-meet-notice": deviceNoticeCode(kind, reason), children: [
3707
4085
  /* @__PURE__ */ jsx6("span", { children: deviceChipLabel(kind, reason) }),
3708
4086
  /* @__PURE__ */ jsx6(
3709
4087
  "button",
@@ -3717,9 +4095,9 @@ function MediaNotices() {
3717
4095
  }
3718
4096
  )
3719
4097
  ] }, kind)),
3720
- fixing !== null && fixReason !== null ? /* @__PURE__ */ jsxs3("div", { className: "mx-meet__popover mx-meet__fix-sheet", role: "dialog", "aria-label": `Fix ${name(fixing).toLowerCase()}`, children: [
4098
+ fixing !== null && fixReason !== null ? /* @__PURE__ */ jsxs4("div", { className: "mx-meet__popover mx-meet__fix-sheet", role: "dialog", "aria-label": `Fix ${name(fixing).toLowerCase()}`, children: [
3721
4099
  /* @__PURE__ */ jsx6("ol", { className: "mx-meet__fix-steps", children: deviceFixSteps(fixing, fixReason, where).map((step) => /* @__PURE__ */ jsx6("li", { children: step }, step)) }),
3722
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__fix-actions", children: [
4100
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__fix-actions", children: [
3723
4101
  /* @__PURE__ */ jsx6(
3724
4102
  "button",
3725
4103
  {
@@ -3736,7 +4114,7 @@ function MediaNotices() {
3736
4114
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__toast-close", "aria-label": "Close", onClick: () => setFixing(null), children: /* @__PURE__ */ jsx6(CloseIcon, { width: 14, height: 14 }) })
3737
4115
  ] })
3738
4116
  ] }) : null,
3739
- notice !== null ? /* @__PURE__ */ jsxs3(
4117
+ notice !== null ? /* @__PURE__ */ jsxs4(
3740
4118
  "div",
3741
4119
  {
3742
4120
  className: "mx-meet__media-pill",
@@ -3748,7 +4126,7 @@ function MediaNotices() {
3748
4126
  ]
3749
4127
  }
3750
4128
  ) : null,
3751
- offer !== null ? /* @__PURE__ */ jsxs3("div", { className: "mx-meet__media-pill", role: "status", children: [
4129
+ offer !== null ? /* @__PURE__ */ jsxs4("div", { className: "mx-meet__media-pill", role: "status", children: [
3752
4130
  /* @__PURE__ */ jsx6("span", { children: `New ${offer.kind}: ${offer.label || name(offer.kind)}` }),
3753
4131
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__primary mx-meet__primary--small", onClick: () => void acceptOffer(), children: "Use it" }),
3754
4132
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__toast-close", "aria-label": "Dismiss", onClick: dismissOffer, children: /* @__PURE__ */ jsx6(CloseIcon, { width: 14, height: 14 }) })
@@ -3759,14 +4137,50 @@ function MeetingOverlays() {
3759
4137
  const reactions = useReactions();
3760
4138
  const { notice, dismiss } = useModerationNotice();
3761
4139
  const room = useRoom();
3762
- return /* @__PURE__ */ jsxs3(Fragment, { children: [
4140
+ const live = useLivePolicy();
4141
+ const snapshot = useMeetSnapshot();
4142
+ const controls = useHostControls();
4143
+ const isHostNow = useRole() === "host";
4144
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
3763
4145
  /* @__PURE__ */ jsx6(ReactionOverlay, { reactions }),
3764
4146
  /* @__PURE__ */ jsx6(MediaNotices, {}),
4147
+ snapshot !== null && snapshot.phase === "in_call" && snapshot.participants.length >= 2 && !snapshot.participants.some((p) => p.role === "host" || p.role === "cohost") ? (
4148
+ // meeting-without-host: the call goes on; host-only controls are simply not on screen.
4149
+ /* @__PURE__ */ jsx6("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "host-absent", children: "The host has left the meeting. Host controls are not available until a host is back." })
4150
+ ) : null,
4151
+ live.consent !== null ? /* @__PURE__ */ jsx6("div", { className: "mx-meet__sheet-backdrop", children: /* @__PURE__ */ jsxs4("div", { className: "mx-meet__sheet", role: "alertdialog", "aria-label": "This meeting is being recorded", "data-meet-notice": "recording-consent", children: [
4152
+ /* @__PURE__ */ jsx6("h2", { className: "mx-meet__panel-title", children: "This meeting is being recorded" }),
4153
+ /* @__PURE__ */ jsx6("p", { className: "mx-meet__confirm-text", children: live.consent === "ok_or_leave" ? "By staying you agree to be recorded. You can leave now if you do not agree." : "Until you agree to the recording you can watch and listen, but not use your microphone or camera." }),
4154
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__menu-actions", children: [
4155
+ /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__send", onClick: live.agree, children: live.consent === "ok_or_leave" ? "OK" : "I agree" }),
4156
+ live.consent === "ok_or_leave" ? /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__link", onClick: () => void room.leave(), children: "Leave meeting" }) : null
4157
+ ] })
4158
+ ] }) }) : null,
4159
+ snapshot?.canReclaim === true && !isHostNow ? /* @__PURE__ */ jsxs4("div", { className: "mx-meet__notice-bar", role: "status", "data-meet-notice": "host-reclaim", children: [
4160
+ /* @__PURE__ */ jsx6("span", { children: "You started this meeting. Take back the host?" }),
4161
+ /* @__PURE__ */ jsx6(
4162
+ "button",
4163
+ {
4164
+ type: "button",
4165
+ className: "mx-meet__primary mx-meet__primary--small",
4166
+ onClick: () => void controls.run({ action: "reclaim_host" }),
4167
+ children: "Reclaim host"
4168
+ }
4169
+ )
4170
+ ] }) : null,
4171
+ live.micLocked || live.cameraLocked ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "mic-locked", children: live.micLocked && live.cameraLocked ? "Your microphone and camera are turned off by the organizer." : live.micLocked ? "Your microphone is turned off by the organizer." : "Your camera is turned off by the organizer." }) : null,
4172
+ live.timeWarning && live.minutesLeft !== null && live.minutesLeft > 0 ? /* @__PURE__ */ jsxs4("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "time-warning", children: [
4173
+ "This meeting will end in ",
4174
+ live.minutesLeft,
4175
+ " ",
4176
+ live.minutesLeft === 1 ? "minute" : "minutes",
4177
+ " (time limit)."
4178
+ ] }) : null,
3765
4179
  notice !== null && notice.kind !== "removed" ? (
3766
4180
  // A host's request ("the host is asking you to unmute"), not an error:
3767
4181
  // an assertive status, so it is announced at once without being filed
3768
4182
  // as a failure (design-system error-box census).
3769
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__notice-bar", role: "status", "aria-live": "assertive", children: [
4183
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__notice-bar", role: "status", "aria-live": "assertive", children: [
3770
4184
  /* @__PURE__ */ jsx6("span", { children: notice.text }),
3771
4185
  notice.kind === "ask-unmute" && room.local?.micEnabled !== true ? /* @__PURE__ */ jsx6(
3772
4186
  "button",
@@ -3793,7 +4207,7 @@ function ShortcutsSheet({ onClose }) {
3793
4207
  window.addEventListener("keydown", onKey);
3794
4208
  return () => window.removeEventListener("keydown", onKey);
3795
4209
  }, [onClose]);
3796
- return /* @__PURE__ */ jsx6("div", { className: "mx-meet__sheet-backdrop", onClick: onClose, children: /* @__PURE__ */ jsxs3(
4210
+ return /* @__PURE__ */ jsx6("div", { className: "mx-meet__sheet-backdrop", onClick: onClose, children: /* @__PURE__ */ jsxs4(
3797
4211
  "div",
3798
4212
  {
3799
4213
  className: "mx-meet__sheet",
@@ -3801,11 +4215,11 @@ function ShortcutsSheet({ onClose }) {
3801
4215
  "aria-label": "Keyboard shortcuts",
3802
4216
  onClick: (event) => event.stopPropagation(),
3803
4217
  children: [
3804
- /* @__PURE__ */ jsxs3("header", { className: "mx-meet__panel-head", children: [
4218
+ /* @__PURE__ */ jsxs4("header", { className: "mx-meet__panel-head", children: [
3805
4219
  /* @__PURE__ */ jsx6("h2", { className: "mx-meet__panel-title", children: "Keyboard shortcuts" }),
3806
4220
  /* @__PURE__ */ jsx6(ControlButton, { label: "Close", onClick: onClose, children: /* @__PURE__ */ jsx6(CloseIcon, { width: 16, height: 16 }) })
3807
4221
  ] }),
3808
- /* @__PURE__ */ jsx6("dl", { className: "mx-meet__shortcuts", children: MEET_SHORTCUTS.map((shortcut) => /* @__PURE__ */ jsxs3("div", { className: "mx-meet__shortcut", children: [
4222
+ /* @__PURE__ */ jsx6("dl", { className: "mx-meet__shortcuts", children: MEET_SHORTCUTS.map((shortcut) => /* @__PURE__ */ jsxs4("div", { className: "mx-meet__shortcut", children: [
3809
4223
  /* @__PURE__ */ jsx6("dt", { children: shortcut.label }),
3810
4224
  /* @__PURE__ */ jsx6("dd", { children: /* @__PURE__ */ jsx6("kbd", { className: "mx-meet__kbd", children: shortcut.keys }) })
3811
4225
  ] }, shortcut.id)) })
@@ -3837,8 +4251,8 @@ function PanelShell({
3837
4251
  observer.observe(header);
3838
4252
  return () => observer.disconnect();
3839
4253
  }, []);
3840
- return /* @__PURE__ */ jsxs3("aside", { ref, className: "mx-meet__panel", "aria-label": title, children: [
3841
- /* @__PURE__ */ jsxs3("header", { className: "mx-meet__panel-head", children: [
4254
+ return /* @__PURE__ */ jsxs4("aside", { ref, className: "mx-meet__panel", "aria-label": title, children: [
4255
+ /* @__PURE__ */ jsxs4("header", { className: "mx-meet__panel-head", children: [
3842
4256
  /* @__PURE__ */ jsx6("h2", { className: "mx-meet__panel-title", children: title }),
3843
4257
  /* @__PURE__ */ jsx6(ControlButton, { label: "Close panel", onClick: onClose, children: /* @__PURE__ */ jsx6(CloseIcon, { width: 16, height: 16 }) })
3844
4258
  ] }),
@@ -3852,8 +4266,9 @@ function ChatPanel({
3852
4266
  }) {
3853
4267
  const snapshot = useMeetSnapshot();
3854
4268
  const room = useRoom();
3855
- const [draft, setDraft] = useState4("");
3856
- const [recipient, setRecipient] = useState4(to);
4269
+ const live = useLivePolicy();
4270
+ const [draft, setDraft] = useState5("");
4271
+ const [recipient, setRecipient] = useState5(to);
3857
4272
  const listRef = useRef6(null);
3858
4273
  const messages = snapshot?.chat ?? [];
3859
4274
  const local = snapshot?.localIdentity ?? null;
@@ -3870,13 +4285,13 @@ function ChatPanel({
3870
4285
  setRecipient(next);
3871
4286
  onTo?.(next);
3872
4287
  };
3873
- return /* @__PURE__ */ jsxs3(PanelShell, { title: "Chat", onClose, children: [
3874
- /* @__PURE__ */ jsxs3("ul", { className: "mx-meet__chat", ref: listRef, children: [
4288
+ return /* @__PURE__ */ jsxs4(PanelShell, { title: "Chat", onClose, children: [
4289
+ /* @__PURE__ */ jsxs4("ul", { className: "mx-meet__chat", ref: listRef, children: [
3875
4290
  snapshot?.chatHistoryError != null ? /* @__PURE__ */ jsx6("li", { className: "mx-meet__panel-note", children: snapshot.chatHistoryError }) : null,
3876
4291
  snapshot?.chatLoaded !== true && messages.length === 0 ? /* @__PURE__ */ jsx6("li", { className: "mx-meet__panel-note", children: "Reading earlier messages\u2026" }) : messages.length === 0 && snapshot?.chatHistoryError == null ? /* @__PURE__ */ jsx6("li", { className: "mx-meet__panel-note", children: "No messages yet. Messages to everyone stay with the meeting, so people who join later see them." }) : null,
3877
4292
  messages.map((message) => /* @__PURE__ */ jsx6(ChatLine, { message, local, people }, message.id))
3878
4293
  ] }),
3879
- /* @__PURE__ */ jsxs3(
4294
+ !live.canChat ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__panel-note", role: "status", "data-meet-notice": "chat-restricted", children: live.chatMode === "off" ? "Chat is turned off for this meeting." : "Chat is limited to the host and co-hosts in this meeting." }) : /* @__PURE__ */ jsxs4(
3880
4295
  "form",
3881
4296
  {
3882
4297
  className: "mx-meet__composer mx-meet__composer--chat",
@@ -3889,7 +4304,7 @@ function ChatPanel({
3889
4304
  else void room.sendPrivateChat(recipient, text);
3890
4305
  },
3891
4306
  children: [
3892
- people.length > 0 ? /* @__PURE__ */ jsxs3(
4307
+ people.length > 0 ? /* @__PURE__ */ jsxs4(
3893
4308
  "select",
3894
4309
  {
3895
4310
  className: "mx-meet__select mx-meet__select--compact",
@@ -3898,14 +4313,14 @@ function ChatPanel({
3898
4313
  onChange: (event) => choose(event.target.value === "" ? null : event.target.value),
3899
4314
  children: [
3900
4315
  /* @__PURE__ */ jsx6("option", { value: "", children: "Everyone" }),
3901
- people.map((participant) => /* @__PURE__ */ jsxs3("option", { value: participant.identity, children: [
4316
+ people.map((participant) => /* @__PURE__ */ jsxs4("option", { value: participant.identity, children: [
3902
4317
  participant.displayName,
3903
4318
  " (private)"
3904
4319
  ] }, participant.identity))
3905
4320
  ]
3906
4321
  }
3907
4322
  ) : null,
3908
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__composer-row", children: [
4323
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__composer-row", children: [
3909
4324
  /* @__PURE__ */ jsx6(
3910
4325
  "input",
3911
4326
  {
@@ -3919,7 +4334,7 @@ function ChatPanel({
3919
4334
  ),
3920
4335
  /* @__PURE__ */ jsx6("button", { type: "submit", className: "mx-meet__send", disabled: draft.trim().length === 0, children: "Send" })
3921
4336
  ] }),
3922
- recipientName !== null ? /* @__PURE__ */ jsxs3("p", { className: "mx-meet__panel-note", children: [
4337
+ recipientName !== null ? /* @__PURE__ */ jsxs4("p", { className: "mx-meet__panel-note", children: [
3923
4338
  "Only ",
3924
4339
  recipientName,
3925
4340
  " sees this. Private messages are not saved."
@@ -3937,7 +4352,7 @@ function ChatLine({
3937
4352
  const mine = message.identity === local;
3938
4353
  const privateTo = message.to ?? null;
3939
4354
  const counterpart = privateTo === null ? null : mine ? people.find((p) => p.identity === privateTo)?.displayName ?? "them" : "you";
3940
- return /* @__PURE__ */ jsxs3(
4355
+ return /* @__PURE__ */ jsxs4(
3941
4356
  "li",
3942
4357
  {
3943
4358
  className: [
@@ -3946,9 +4361,9 @@ function ChatLine({
3946
4361
  message.failed !== void 0 ? "mx-meet__chat-line--failed" : ""
3947
4362
  ].filter(Boolean).join(" "),
3948
4363
  children: [
3949
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__chat-meta", children: [
4364
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__chat-meta", children: [
3950
4365
  /* @__PURE__ */ jsx6("strong", { children: mine ? "You" : message.displayName }),
3951
- counterpart !== null ? /* @__PURE__ */ jsxs3("span", { className: "mx-meet__chat-private", children: [
4366
+ counterpart !== null ? /* @__PURE__ */ jsxs4("span", { className: "mx-meet__chat-private", children: [
3952
4367
  "to ",
3953
4368
  counterpart,
3954
4369
  " \xB7 private"
@@ -3968,8 +4383,8 @@ function PeoplePanel({
3968
4383
  const snapshot = useMeetSnapshot();
3969
4384
  const controls = useHostControls();
3970
4385
  const queue = useHandQueue();
3971
- const [query, setQuery] = useState4("");
3972
- const [menuFor, setMenuFor] = useState4(null);
4386
+ const [query, setQuery] = useState5("");
4387
+ const [menuFor, setMenuFor] = useState5(null);
3973
4388
  const myRole = useRole();
3974
4389
  const local = snapshot?.localIdentity ?? null;
3975
4390
  const observersHidden = snapshot?.grants.observersVisibleTo === "hosts" && !controls.isHost;
@@ -3978,11 +4393,11 @@ function PeoplePanel({
3978
4393
  );
3979
4394
  const needle = query.trim().toLowerCase();
3980
4395
  const shown = needle.length === 0 ? everyone : everyone.filter((participant) => participant.displayName.toLowerCase().includes(needle));
3981
- return /* @__PURE__ */ jsxs3(PanelShell, { title: `People (${everyone.length})`, onClose, children: [
4396
+ return /* @__PURE__ */ jsxs4(PanelShell, { title: `People (${everyone.length})`, onClose, children: [
3982
4397
  /* @__PURE__ */ jsx6(LobbyPanel, {}),
3983
- queue.length > 0 ? /* @__PURE__ */ jsxs3("section", { className: "mx-meet__section", "aria-label": "Raised hands", children: [
3984
- /* @__PURE__ */ jsxs3("header", { className: "mx-meet__section-head", children: [
3985
- /* @__PURE__ */ jsxs3("h3", { className: "mx-meet__section-title", children: [
4398
+ queue.length > 0 ? /* @__PURE__ */ jsxs4("section", { className: "mx-meet__section", "aria-label": "Raised hands", children: [
4399
+ /* @__PURE__ */ jsxs4("header", { className: "mx-meet__section-head", children: [
4400
+ /* @__PURE__ */ jsxs4("h3", { className: "mx-meet__section-title", children: [
3986
4401
  "Raised hands \xB7 ",
3987
4402
  queue.length
3988
4403
  ] }),
@@ -3996,9 +4411,9 @@ function PeoplePanel({
3996
4411
  }
3997
4412
  ) : null
3998
4413
  ] }),
3999
- /* @__PURE__ */ jsx6("ol", { className: "mx-meet__queue", children: queue.map((participant) => /* @__PURE__ */ jsxs3("li", { className: "mx-meet__person", children: [
4414
+ /* @__PURE__ */ jsx6("ol", { className: "mx-meet__queue", children: queue.map((participant) => /* @__PURE__ */ jsxs4("li", { className: "mx-meet__person", children: [
4000
4415
  /* @__PURE__ */ jsx6(Avatar, { name: participant.displayName, url: participant.avatarUrl, size: 28 }),
4001
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__person-name", children: [
4416
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__person-name", children: [
4002
4417
  participant.displayName,
4003
4418
  participant.identity === local ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__you", children: " (you)" }) : null
4004
4419
  ] }),
@@ -4013,12 +4428,12 @@ function PeoplePanel({
4013
4428
  ) : null
4014
4429
  ] }, participant.identity)) })
4015
4430
  ] }) : null,
4016
- controls.isHost && everyone.length > 1 ? /* @__PURE__ */ jsxs3("div", { className: "mx-meet__bulk", children: [
4017
- /* @__PURE__ */ jsxs3("button", { type: "button", className: "mx-meet__chip", onClick: () => void controls.run({ action: "mute_all" }), children: [
4431
+ controls.isHost && everyone.length > 1 ? /* @__PURE__ */ jsxs4("div", { className: "mx-meet__bulk", children: [
4432
+ /* @__PURE__ */ jsxs4("button", { type: "button", className: "mx-meet__chip", onClick: () => void controls.run({ action: "mute_all" }), children: [
4018
4433
  /* @__PURE__ */ jsx6(MicOffIcon, { width: 14, height: 14 }),
4019
4434
  " Mute all"
4020
4435
  ] }),
4021
- /* @__PURE__ */ jsxs3(
4436
+ /* @__PURE__ */ jsxs4(
4022
4437
  "button",
4023
4438
  {
4024
4439
  type: "button",
@@ -4031,7 +4446,7 @@ function PeoplePanel({
4031
4446
  }
4032
4447
  )
4033
4448
  ] }) : null,
4034
- everyone.length > 4 ? /* @__PURE__ */ jsxs3("label", { className: "mx-meet__search", children: [
4449
+ everyone.length > 4 ? /* @__PURE__ */ jsxs4("label", { className: "mx-meet__search", children: [
4035
4450
  /* @__PURE__ */ jsx6(SearchIcon, { width: 16, height: 16 }),
4036
4451
  /* @__PURE__ */ jsx6(
4037
4452
  "input",
@@ -4045,10 +4460,10 @@ function PeoplePanel({
4045
4460
  )
4046
4461
  ] }) : null,
4047
4462
  controls.notice !== null ? /* @__PURE__ */ jsx6("p", { className: controls.notice.failed ? "mx-meet__error" : "mx-meet__notice", role: "status", children: controls.notice.text }) : null,
4048
- /* @__PURE__ */ jsxs3("ul", { className: "mx-meet__people", children: [
4049
- shown.map((participant) => /* @__PURE__ */ jsxs3("li", { className: "mx-meet__person", children: [
4463
+ /* @__PURE__ */ jsxs4("ul", { className: "mx-meet__people", children: [
4464
+ shown.map((participant) => /* @__PURE__ */ jsxs4("li", { className: "mx-meet__person", children: [
4050
4465
  /* @__PURE__ */ jsx6(Avatar, { name: participant.displayName, url: participant.avatarUrl, size: 32 }),
4051
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__person-name", children: [
4466
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__person-name", children: [
4052
4467
  participant.displayName,
4053
4468
  participant.identity === local ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__you", children: " (you)" }) : null,
4054
4469
  /* @__PURE__ */ jsx6(
@@ -4065,7 +4480,7 @@ function PeoplePanel({
4065
4480
  participant.handRaised ? /* @__PURE__ */ jsx6(HandIcon, { width: 14, height: 14 }) : null,
4066
4481
  !participant.micEnabled && !isNoteTaker(participant) ? /* @__PURE__ */ jsx6(MicOffIcon, { width: 14, height: 14 }) : null,
4067
4482
  /* @__PURE__ */ jsx6(QualityBars, { quality: participant.quality }),
4068
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__anchor", children: [
4483
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__anchor", children: [
4069
4484
  /* @__PURE__ */ jsx6(
4070
4485
  ControlButton,
4071
4486
  {
@@ -4086,7 +4501,7 @@ function PeoplePanel({
4086
4501
  ) : null
4087
4502
  ] })
4088
4503
  ] }, participant.identity)),
4089
- shown.length === 0 ? /* @__PURE__ */ jsxs3("li", { className: "mx-meet__panel-note", children: [
4504
+ shown.length === 0 ? /* @__PURE__ */ jsxs4("li", { className: "mx-meet__panel-note", children: [
4090
4505
  "Nobody matches \u201C",
4091
4506
  query,
4092
4507
  "\u201D."
@@ -4104,14 +4519,14 @@ function PersonMenu({
4104
4519
  const host = useMeetHost();
4105
4520
  const snapshot = useMeetSnapshot();
4106
4521
  const controls = useHostControls();
4107
- const [mode, setMode] = useState4("menu");
4108
- const [text, setText] = useState4("");
4522
+ const [mode, setMode] = useState5("menu");
4523
+ const [text, setText] = useState5("");
4109
4524
  const self = participant.identity === snapshot?.localIdentity;
4110
4525
  const moderate = controls.canModerate(participant);
4111
4526
  const pinned = snapshot?.pinned === participant.identity;
4112
4527
  const spotlit = snapshot?.spotlight === participant.identity;
4113
4528
  const hasAccount = participant.userId !== null;
4114
- const [refused, setRefused] = useState4(false);
4529
+ const [refused, setRefused] = useState5(false);
4115
4530
  const act = (request) => {
4116
4531
  setRefused(false);
4117
4532
  void controls.run(request).then((result) => {
@@ -4122,7 +4537,7 @@ function PersonMenu({
4122
4537
  const refusal = refused && controls.notice?.failed === true ? /* @__PURE__ */ jsx6(ErrorBox, { as: "p", className: "mx-meet__error", message: controls.notice.text, operation: "Change this participant", origin: "meet/components", children: controls.notice.text }) : null;
4123
4538
  if (mode === "rename" || mode === "report") {
4124
4539
  const renaming = mode === "rename";
4125
- return /* @__PURE__ */ jsx6(Popover, { label: renaming ? "Rename" : "Report", onClose, placement, children: /* @__PURE__ */ jsxs3(
4540
+ return /* @__PURE__ */ jsx6(Popover, { label: renaming ? "Rename" : "Report", onClose, placement, children: /* @__PURE__ */ jsxs4(
4126
4541
  "form",
4127
4542
  {
4128
4543
  className: "mx-meet__menu-form",
@@ -4134,7 +4549,7 @@ function PersonMenu({
4134
4549
  );
4135
4550
  },
4136
4551
  children: [
4137
- /* @__PURE__ */ jsxs3("label", { className: "mx-meet__field", children: [
4552
+ /* @__PURE__ */ jsxs4("label", { className: "mx-meet__field", children: [
4138
4553
  /* @__PURE__ */ jsx6("span", { className: "mx-meet__field-label", children: renaming ? "Name shown in this meeting" : `What did ${participant.displayName} do?` }),
4139
4554
  renaming ? /* @__PURE__ */ jsx6(
4140
4555
  "input",
@@ -4158,7 +4573,7 @@ function PersonMenu({
4158
4573
  )
4159
4574
  ] }),
4160
4575
  refusal,
4161
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__menu-actions", children: [
4576
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__menu-actions", children: [
4162
4577
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__link", onClick: () => setMode("menu"), children: "Back" }),
4163
4578
  /* @__PURE__ */ jsx6("button", { type: "submit", className: "mx-meet__send", disabled: text.trim().length === 0 || controls.busy, children: renaming ? "Rename" : "Report" })
4164
4579
  ] })
@@ -4168,10 +4583,10 @@ function PersonMenu({
4168
4583
  }
4169
4584
  if (mode === "remove" || mode === "transfer") {
4170
4585
  const removing = mode === "remove";
4171
- return /* @__PURE__ */ jsx6(Popover, { label: removing ? "Remove" : "Make host", onClose, placement, children: /* @__PURE__ */ jsxs3("div", { className: "mx-meet__menu-form", children: [
4586
+ return /* @__PURE__ */ jsx6(Popover, { label: removing ? "Remove" : "Make host", onClose, placement, children: /* @__PURE__ */ jsxs4("div", { className: "mx-meet__menu-form", children: [
4172
4587
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__confirm-text", children: removing ? `Remove ${participant.displayName}? They leave immediately and cannot rejoin this meeting.` : `Make ${participant.displayName} the host? They get every host control and own this meeting. You stay on as a co-host.` }),
4173
4588
  refusal,
4174
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__menu-actions", children: [
4589
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__menu-actions", children: [
4175
4590
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__link", onClick: () => setMode("menu"), children: "Cancel" }),
4176
4591
  /* @__PURE__ */ jsx6(
4177
4592
  "button",
@@ -4186,8 +4601,8 @@ function PersonMenu({
4186
4601
  ] })
4187
4602
  ] }) });
4188
4603
  }
4189
- return /* @__PURE__ */ jsx6(Popover, { label: `Options for ${participant.displayName}`, onClose, placement, children: /* @__PURE__ */ jsxs3("div", { className: "mx-meet__menu", role: "menu", children: [
4190
- /* @__PURE__ */ jsxs3(
4604
+ return /* @__PURE__ */ jsx6(Popover, { label: `Options for ${participant.displayName}`, onClose, placement, children: /* @__PURE__ */ jsxs4("div", { className: "mx-meet__menu", role: "menu", children: [
4605
+ /* @__PURE__ */ jsxs4(
4191
4606
  MenuItem,
4192
4607
  {
4193
4608
  onSelect: () => {
@@ -4201,7 +4616,7 @@ function PersonMenu({
4201
4616
  ]
4202
4617
  }
4203
4618
  ),
4204
- !self && !participant.isAgent && (onMessage !== void 0 || host !== null) ? /* @__PURE__ */ jsxs3(
4619
+ !self && !participant.isAgent && (onMessage !== void 0 || host !== null) ? /* @__PURE__ */ jsxs4(
4205
4620
  MenuItem,
4206
4621
  {
4207
4622
  onSelect: () => {
@@ -4218,37 +4633,44 @@ function PersonMenu({
4218
4633
  ]
4219
4634
  }
4220
4635
  ) : null,
4221
- controls.isHost ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "spotlight", identity: spotlit ? null : participant.identity }), children: [
4636
+ controls.isHost ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "spotlight", identity: spotlit ? null : participant.identity }), children: [
4222
4637
  /* @__PURE__ */ jsx6(SpotlightIcon, { width: 16, height: 16 }),
4223
4638
  " ",
4224
4639
  spotlit ? "Remove spotlight" : "Spotlight for everyone"
4225
4640
  ] }) : null,
4226
- moderate ? /* @__PURE__ */ jsxs3(Fragment, { children: [
4641
+ moderate ? /* @__PURE__ */ jsxs4(Fragment, { children: [
4227
4642
  /* @__PURE__ */ jsx6("div", { className: "mx-meet__menu-sep", role: "separator" }),
4228
- participant.micEnabled ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "mute", identity: participant.identity }), children: [
4643
+ participant.micEnabled ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "mute", identity: participant.identity }), children: [
4229
4644
  /* @__PURE__ */ jsx6(MicOffIcon, { width: 16, height: 16 }),
4230
4645
  " Mute"
4231
- ] }) : !participant.isAgent ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "ask_unmute", identity: participant.identity }), children: [
4646
+ ] }) : !participant.isAgent ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "ask_unmute", identity: participant.identity }), children: [
4232
4647
  /* @__PURE__ */ jsx6(MicIcon, { width: 16, height: 16 }),
4233
4648
  " Ask to unmute"
4234
4649
  ] }) : null,
4235
- participant.cameraEnabled ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "stop_video", identity: participant.identity }), children: [
4650
+ participant.cameraEnabled ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "stop_video", identity: participant.identity }), children: [
4236
4651
  /* @__PURE__ */ jsx6(CameraOffIcon, { width: 16, height: 16 }),
4237
4652
  " Stop video"
4238
4653
  ] }) : null,
4239
- participant.screenSharing ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "stop_screen", identity: participant.identity }), children: [
4654
+ participant.screenSharing ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "stop_screen", identity: participant.identity }), children: [
4240
4655
  /* @__PURE__ */ jsx6(ScreenShareIcon, { width: 16, height: 16 }),
4241
4656
  " Stop screen share"
4242
4657
  ] }) : null,
4243
- participant.handRaised ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "lower_hand", identity: participant.identity }), children: [
4658
+ participant.handRaised ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "lower_hand", identity: participant.identity }), children: [
4244
4659
  /* @__PURE__ */ jsx6(HandIcon, { width: 16, height: 16 }),
4245
4660
  " Lower hand"
4246
4661
  ] }) : null,
4247
- hasAccount && !participant.isAgent && participant.role !== "cohost" ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "make_cohost", identity: participant.identity }), children: [
4662
+ hasAccount && !participant.isAgent && participant.role !== "cohost" ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "make_cohost", identity: participant.identity }), children: [
4248
4663
  /* @__PURE__ */ jsx6(PeopleIcon, { width: 16, height: 16 }),
4249
4664
  " Make co-host"
4250
4665
  ] }) : null,
4251
- !participant.isAgent ? /* @__PURE__ */ jsxs3(
4666
+ !participant.isAgent && participant.role !== "cohost" && participant.role !== "host" ? participant.role === "presenter" ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "revoke_presenter", identity: participant.identity }), children: [
4667
+ /* @__PURE__ */ jsx6(ScreenShareIcon, { width: 16, height: 16 }),
4668
+ " Remove presenter"
4669
+ ] }) : /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "make_presenter", identity: participant.identity }), children: [
4670
+ /* @__PURE__ */ jsx6(ScreenShareIcon, { width: 16, height: 16 }),
4671
+ " Make presenter"
4672
+ ] }) : null,
4673
+ !participant.isAgent ? /* @__PURE__ */ jsxs4(
4252
4674
  MenuItem,
4253
4675
  {
4254
4676
  onSelect: () => {
@@ -4262,15 +4684,15 @@ function PersonMenu({
4262
4684
  }
4263
4685
  ) : null
4264
4686
  ] }) : null,
4265
- controls.isOwner && participant.role === "cohost" ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => act({ action: "revoke_cohost", identity: participant.identity }), children: [
4687
+ controls.isOwner && participant.role === "cohost" ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => act({ action: "revoke_cohost", identity: participant.identity }), children: [
4266
4688
  /* @__PURE__ */ jsx6(PeopleIcon, { width: 16, height: 16 }),
4267
4689
  " Remove co-host"
4268
4690
  ] }) : null,
4269
- controls.isOwner && !self && hasAccount && !participant.isAgent ? /* @__PURE__ */ jsxs3(MenuItem, { onSelect: () => setMode("transfer"), children: [
4691
+ controls.isOwner && !self && hasAccount && !participant.isAgent ? /* @__PURE__ */ jsxs4(MenuItem, { onSelect: () => setMode("transfer"), children: [
4270
4692
  /* @__PURE__ */ jsx6(SpotlightIcon, { width: 16, height: 16 }),
4271
4693
  " Make host"
4272
4694
  ] }) : null,
4273
- self ? /* @__PURE__ */ jsxs3(
4695
+ self ? /* @__PURE__ */ jsxs4(
4274
4696
  MenuItem,
4275
4697
  {
4276
4698
  onSelect: () => {
@@ -4283,7 +4705,7 @@ function PersonMenu({
4283
4705
  ]
4284
4706
  }
4285
4707
  ) : null,
4286
- !self && !participant.isAgent ? /* @__PURE__ */ jsxs3(
4708
+ !self && !participant.isAgent ? /* @__PURE__ */ jsxs4(
4287
4709
  MenuItem,
4288
4710
  {
4289
4711
  onSelect: () => {
@@ -4296,7 +4718,7 @@ function PersonMenu({
4296
4718
  ]
4297
4719
  }
4298
4720
  ) : null,
4299
- moderate && !participant.isAgent ? /* @__PURE__ */ jsxs3(MenuItem, { danger: true, onSelect: () => setMode("remove"), children: [
4721
+ moderate && !participant.isAgent ? /* @__PURE__ */ jsxs4(MenuItem, { danger: true, onSelect: () => setMode("remove"), children: [
4300
4722
  /* @__PURE__ */ jsx6(CloseIcon, { width: 16, height: 16 }),
4301
4723
  " Remove from meeting"
4302
4724
  ] }) : null
@@ -4304,7 +4726,7 @@ function PersonMenu({
4304
4726
  }
4305
4727
  function SettingsPanel({ onClose }) {
4306
4728
  const host = useRequiredMeetHost();
4307
- return /* @__PURE__ */ jsxs3(PanelShell, { title: "Settings", onClose, children: [
4729
+ return /* @__PURE__ */ jsxs4(PanelShell, { title: "Settings", onClose, children: [
4308
4730
  /* @__PURE__ */ jsx6(
4309
4731
  DeviceSettings,
4310
4732
  {
@@ -4327,15 +4749,15 @@ function DeviceSettings({
4327
4749
  const speaker = devices?.selected.audiooutput ?? host.devices.resolve("audiooutput");
4328
4750
  const stream = useMicrophoneStream(microphone);
4329
4751
  const level = useAudioLevel(stream);
4330
- const [testing, setTesting] = useState4(false);
4752
+ const [testing, setTesting] = useState5(false);
4331
4753
  useEffect6(() => {
4332
4754
  void host.devices.refresh();
4333
4755
  }, [host]);
4334
- return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__section", "aria-label": "Devices", children: [
4756
+ return /* @__PURE__ */ jsxs4("section", { className: "mx-meet__section", "aria-label": "Devices", children: [
4335
4757
  /* @__PURE__ */ jsx6(DevicePicker, { kind: "audioinput", label: "Microphone", onPick }),
4336
4758
  /* @__PURE__ */ jsx6("div", { className: "mx-meet__meter", role: "meter", "aria-label": "Microphone level", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(level * 100), children: /* @__PURE__ */ jsx6("span", { style: { width: `${Math.min(100, Math.round(level * 160))}%` } }) }),
4337
4759
  /* @__PURE__ */ jsx6(DevicePicker, { kind: "audiooutput", label: "Speaker", onPick }),
4338
- /* @__PURE__ */ jsxs3(
4760
+ /* @__PURE__ */ jsxs4(
4339
4761
  "button",
4340
4762
  {
4341
4763
  type: "button",
@@ -4357,7 +4779,7 @@ function DeviceSettings({
4357
4779
  }
4358
4780
  function EffectsSettings({ preview }) {
4359
4781
  const effects = useMediaEffects();
4360
- const [error, setError] = useState4(null);
4782
+ const [error, setError] = useState5(null);
4361
4783
  const fileRef = useRef6(null);
4362
4784
  const supported = effects.backgroundsSupported || preview != null || videoEffectsSupported();
4363
4785
  const apply = (next) => {
@@ -4370,8 +4792,8 @@ function EffectsSettings({ preview }) {
4370
4792
  );
4371
4793
  }
4372
4794
  };
4373
- return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__section", "aria-label": "Effects", children: [
4374
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__check", children: [
4795
+ return /* @__PURE__ */ jsxs4("section", { className: "mx-meet__section", "aria-label": "Effects", children: [
4796
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__check", children: [
4375
4797
  /* @__PURE__ */ jsx6(
4376
4798
  Checkbox,
4377
4799
  {
@@ -4380,12 +4802,12 @@ function EffectsSettings({ preview }) {
4380
4802
  onCheckedChange: (checked) => apply({ noiseSuppression: checked === true })
4381
4803
  }
4382
4804
  ),
4383
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__check-text", children: [
4805
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__check-text", children: [
4384
4806
  /* @__PURE__ */ jsx6(Label, { htmlFor: "mx-meet-noise", children: "Noise suppression" }),
4385
4807
  /* @__PURE__ */ jsx6("span", { className: "mx-meet__hint", children: "Filters keyboards, fans and background chatter." })
4386
4808
  ] })
4387
4809
  ] }),
4388
- supported ? /* @__PURE__ */ jsxs3("div", { className: "mx-meet__field", children: [
4810
+ supported ? /* @__PURE__ */ jsxs4("div", { className: "mx-meet__field", children: [
4389
4811
  /* @__PURE__ */ jsx6(Label, { children: "Background" }),
4390
4812
  /* @__PURE__ */ jsx6(
4391
4813
  SegmentedControl,
@@ -4479,14 +4901,20 @@ async function playTestSound(sinkId) {
4479
4901
  audio.pause();
4480
4902
  await context.close();
4481
4903
  }
4482
- function useMicrophoneStream(deviceId) {
4483
- const [stream, setStream] = useState4(null);
4904
+ function useMicrophoneStream(deviceId, report, attempt = 0) {
4905
+ const [stream, setStream] = useState5(null);
4906
+ const reportRef = useRef6(report);
4907
+ reportRef.current = report;
4484
4908
  useEffect6(() => {
4485
- if (deviceId === "off") return void 0;
4909
+ if (deviceId === "off") {
4910
+ reportRef.current?.("off");
4911
+ return void 0;
4912
+ }
4486
4913
  let live = true;
4487
4914
  let opened = null;
4488
4915
  const media = globalThis.navigator?.mediaDevices;
4489
4916
  if (media === void 0) return void 0;
4917
+ reportRef.current?.("prompting");
4490
4918
  void media.getUserMedia({ audio: deviceId === null ? true : { deviceId: { exact: deviceId } } }).then((next) => {
4491
4919
  if (!live) {
4492
4920
  next.getTracks().forEach((track) => track.stop());
@@ -4494,20 +4922,54 @@ function useMicrophoneStream(deviceId) {
4494
4922
  }
4495
4923
  opened = next;
4496
4924
  setStream(next);
4497
- }).catch(() => setStream(null));
4925
+ reportRef.current?.("on");
4926
+ }).catch((thrown) => {
4927
+ setStream(null);
4928
+ if (live) reportRef.current?.({ error: thrown });
4929
+ });
4498
4930
  return () => {
4499
4931
  live = false;
4500
4932
  opened?.getTracks().forEach((track) => track.stop());
4501
4933
  setStream(null);
4502
4934
  };
4503
- }, [deviceId]);
4935
+ }, [deviceId, attempt]);
4504
4936
  return stream;
4505
4937
  }
4938
+ function PreviewStatus({ onRetry }) {
4939
+ const { region, where } = useMediaSupervisor();
4940
+ const [waited, setWaited] = useState5(false);
4941
+ const prompting = region.preview.microphone.state === "prompting" || region.preview.camera.state === "prompting";
4942
+ useEffect6(() => {
4943
+ if (!prompting) {
4944
+ setWaited(false);
4945
+ return void 0;
4946
+ }
4947
+ const timer = setTimeout(() => setWaited(true), 800);
4948
+ return () => clearTimeout(timer);
4949
+ }, [prompting]);
4950
+ const refused = ["microphone", "camera"].flatMap((kind) => {
4951
+ const preview = region.preview[kind];
4952
+ const reason = region.permission[kind] === "denied" ? "denied" : preview.state === "unavailable" ? preview.unavailable?.reason ?? "failed" : null;
4953
+ return reason === null ? [] : [{ kind, reason }];
4954
+ });
4955
+ if (refused.length === 0) {
4956
+ if (!prompting || !waited) return null;
4957
+ return /* @__PURE__ */ jsx6("p", { className: "mx-meet__panel-note", role: "status", "data-meet-notice": "permission-prompt", children: "Allow camera and microphone when your browser asks" });
4958
+ }
4959
+ const first = refused[0];
4960
+ const both = refused.length === 2 && refused[0].reason === refused[1].reason;
4961
+ const label = both ? deviceChipLabel("camera", first.reason).replace(/^Camera/, "Camera and mic") : refused.map((r) => deviceChipLabel(r.kind, r.reason)).join(" \xB7 ");
4962
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__warning", role: "status", "data-meet-notice": deviceNoticeCode(first.kind, first.reason), children: [
4963
+ /* @__PURE__ */ jsx6("strong", { children: label }),
4964
+ /* @__PURE__ */ jsx6("ol", { className: "mx-meet__fix-steps", children: deviceFixSteps(first.kind, first.reason, where).map((step) => /* @__PURE__ */ jsx6("li", { children: step }, step)) }),
4965
+ /* @__PURE__ */ jsx6(Button, { type: "button", variant: "outline", size: "sm", onClick: onRetry, children: "Try again" })
4966
+ ] });
4967
+ }
4506
4968
  function KnockNotice({ onView }) {
4507
4969
  const { knocker, others, admit, dismiss } = useKnockNotice();
4508
4970
  if (knocker === null) return null;
4509
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__notice-bar", role: "status", "data-meet-notice": "knock-received", "data-meet-participant-name": knocker.displayName, children: [
4510
- /* @__PURE__ */ jsxs3("span", { children: [
4971
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__notice-bar", role: "status", "data-meet-notice": "knock-received", "data-meet-participant-name": knocker.displayName, children: [
4972
+ /* @__PURE__ */ jsxs4("span", { children: [
4511
4973
  knocker.displayName,
4512
4974
  " wants to join",
4513
4975
  others > 0 ? ` (+${others} more)` : ""
@@ -4531,15 +4993,15 @@ function KnockNotice({ onView }) {
4531
4993
  function LobbyPanel() {
4532
4994
  const lobby = useLobby();
4533
4995
  if (!lobby.canAdmit || lobby.waiting.length === 0 && lobby.declined.length === 0) return null;
4534
- return /* @__PURE__ */ jsxs3(Fragment, { children: [
4996
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
4535
4997
  lobby.waiting.length > 0 ? /* @__PURE__ */ jsx6(WaitingList, { lobby }) : null,
4536
4998
  lobby.declined.length > 0 ? /* @__PURE__ */ jsx6(DeclinedList, { lobby }) : null
4537
4999
  ] });
4538
5000
  }
4539
5001
  function DeclinedList({ lobby }) {
4540
- return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__lobby", "aria-label": "Declined requests", "data-meet-declined": "", children: [
5002
+ return /* @__PURE__ */ jsxs4("section", { className: "mx-meet__lobby", "aria-label": "Declined requests", "data-meet-declined": "", children: [
4541
5003
  /* @__PURE__ */ jsx6("header", { className: "mx-meet__lobby-head", children: /* @__PURE__ */ jsx6("h3", { className: "mx-meet__lobby-title", children: "Declined" }) }),
4542
- /* @__PURE__ */ jsx6("ul", { className: "mx-meet__lobby-list", children: lobby.declined.map((entry) => /* @__PURE__ */ jsxs3(
5004
+ /* @__PURE__ */ jsx6("ul", { className: "mx-meet__lobby-list", children: lobby.declined.map((entry) => /* @__PURE__ */ jsxs4(
4543
5005
  "li",
4544
5006
  {
4545
5007
  className: "mx-meet__lobby-row",
@@ -4565,12 +5027,12 @@ function DeclinedList({ lobby }) {
4565
5027
  ] });
4566
5028
  }
4567
5029
  function WaitingList({ lobby }) {
4568
- return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__lobby", "aria-label": "Waiting room", children: [
4569
- /* @__PURE__ */ jsxs3("header", { className: "mx-meet__lobby-head", children: [
5030
+ return /* @__PURE__ */ jsxs4("section", { className: "mx-meet__lobby", "aria-label": "Waiting room", children: [
5031
+ /* @__PURE__ */ jsxs4("header", { className: "mx-meet__lobby-head", children: [
4570
5032
  /* @__PURE__ */ jsx6("h3", { className: "mx-meet__lobby-title", children: lobby.waiting.length === 1 ? "1 person is waiting" : `${lobby.waiting.length} people are waiting` }),
4571
5033
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__link", onClick: () => void lobby.admitAll(), children: "Admit all" })
4572
5034
  ] }),
4573
- /* @__PURE__ */ jsx6("ul", { className: "mx-meet__lobby-list", children: lobby.waiting.map((entry) => /* @__PURE__ */ jsxs3(
5035
+ /* @__PURE__ */ jsx6("ul", { className: "mx-meet__lobby-list", children: lobby.waiting.map((entry) => /* @__PURE__ */ jsxs4(
4574
5036
  "li",
4575
5037
  {
4576
5038
  className: "mx-meet__lobby-row",
@@ -4578,7 +5040,7 @@ function WaitingList({ lobby }) {
4578
5040
  "data-meet-participant-name": entry.displayName,
4579
5041
  children: [
4580
5042
  /* @__PURE__ */ jsx6(Avatar, { name: entry.displayName, url: entry.avatarUrl, size: 32 }),
4581
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__person-name", children: [
5043
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__person-name", children: [
4582
5044
  entry.displayName,
4583
5045
  entry.userId === null ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__badge", children: "Guest" }) : null
4584
5046
  ] }),
@@ -4602,17 +5064,17 @@ function NoteTakerRow() {
4602
5064
  const ai = useMeetAi();
4603
5065
  const status = ai.noteTaker;
4604
5066
  const duplicateError = status.refusal !== null && ai.error !== null && status.refusal.reason === ai.error.message && status.refusal.remedy === ai.error.remedy;
4605
- return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__note-taker", "aria-label": "Note-taker", children: [
4606
- /* @__PURE__ */ jsxs3("p", { className: `mx-meet__note-taker-state mx-meet__note-taker-state--${status.state}`, children: [
5067
+ return /* @__PURE__ */ jsxs4("section", { className: "mx-meet__note-taker", "aria-label": "Note-taker", children: [
5068
+ /* @__PURE__ */ jsxs4("p", { className: `mx-meet__note-taker-state mx-meet__note-taker-state--${status.state}`, children: [
4607
5069
  /* @__PURE__ */ jsx6("span", { className: "mx-meet__note-taker-dot", "aria-hidden": "true" }),
4608
5070
  ai.noteTakerLabel
4609
5071
  ] }),
4610
5072
  status.detail !== null ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__panel-note", children: status.detail }) : null,
4611
- status.refusal !== null ? /* @__PURE__ */ jsxs3(ErrorBox, { as: "div", className: "mx-meet__refusal", error: status.refusal, operation: "Join this meeting", origin: "meet/components", children: [
5073
+ status.refusal !== null ? /* @__PURE__ */ jsxs4(ErrorBox, { as: "div", className: "mx-meet__refusal", error: status.refusal, operation: "Join this meeting", origin: "meet/components", children: [
4612
5074
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__refusal-reason", children: status.refusal.reason }),
4613
5075
  status.refusal.remedy.length > 0 ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__refusal-remedy", children: status.refusal.remedy }) : null
4614
5076
  ] }) : null,
4615
- ai.error !== null && !duplicateError ? /* @__PURE__ */ jsxs3(ErrorBox, { as: "div", className: "mx-meet__refusal", error: ai.error, operation: "Run the meeting assistant", origin: "meet/components", children: [
5077
+ ai.error !== null && !duplicateError ? /* @__PURE__ */ jsxs4(ErrorBox, { as: "div", className: "mx-meet__refusal", error: ai.error, operation: "Run the meeting assistant", origin: "meet/components", children: [
4616
5078
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__refusal-reason", children: ai.error.message }),
4617
5079
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__refusal-remedy", children: ai.error.remedy })
4618
5080
  ] }) : null,
@@ -4640,9 +5102,9 @@ function NoteList({
4640
5102
  notes,
4641
5103
  empty
4642
5104
  }) {
4643
- return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__note-group", "aria-label": title, children: [
5105
+ return /* @__PURE__ */ jsxs4("section", { className: "mx-meet__note-group", "aria-label": title, children: [
4644
5106
  /* @__PURE__ */ jsx6("h3", { className: "mx-meet__note-group-title", children: title }),
4645
- notes.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__panel-note", children: empty }) : /* @__PURE__ */ jsx6("ul", { className: "mx-meet__notes", children: notes.map((note) => /* @__PURE__ */ jsxs3("li", { className: "mx-meet__note", children: [
5107
+ notes.length === 0 ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__panel-note", children: empty }) : /* @__PURE__ */ jsx6("ul", { className: "mx-meet__notes", children: notes.map((note) => /* @__PURE__ */ jsxs4("li", { className: "mx-meet__note", children: [
4646
5108
  note.text,
4647
5109
  note.assigneeDisplayName !== void 0 && note.assigneeDisplayName !== null ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__assignee", children: note.assigneeDisplayName }) : null
4648
5110
  ] }, note.id)) })
@@ -4650,14 +5112,14 @@ function NoteList({
4650
5112
  }
4651
5113
  function AiPanel({ onClose }) {
4652
5114
  const ai = useMeetAi();
4653
- const [question, setQuestion] = useState4("");
4654
- return /* @__PURE__ */ jsxs3(PanelShell, { title: "Meeting assistant", onClose, children: [
5115
+ const [question, setQuestion] = useState5("");
5116
+ return /* @__PURE__ */ jsxs4(PanelShell, { title: "Meeting assistant", onClose, children: [
4655
5117
  /* @__PURE__ */ jsx6(NoteTakerRow, {}),
4656
- ai.summary !== null ? /* @__PURE__ */ jsxs3("section", { className: "mx-meet__note-group", "aria-label": "Summary", children: [
5118
+ ai.summary !== null ? /* @__PURE__ */ jsxs4("section", { className: "mx-meet__note-group", "aria-label": "Summary", children: [
4657
5119
  /* @__PURE__ */ jsx6("h3", { className: "mx-meet__note-group-title", children: "Summary" }),
4658
5120
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__summary", children: ai.summary.text })
4659
5121
  ] }) : null,
4660
- ai.wrapUp !== null ? /* @__PURE__ */ jsxs3("p", { className: "mx-meet__wrap-up-notice", role: "status", children: [
5122
+ ai.wrapUp !== null ? /* @__PURE__ */ jsxs4("p", { className: "mx-meet__wrap-up-notice", role: "status", children: [
4661
5123
  "The wrap-up is written \u2014 ",
4662
5124
  ai.wrapUp.noteIds.length,
4663
5125
  " ",
@@ -4693,9 +5155,9 @@ function AiPanel({ onClose }) {
4693
5155
  empty: "No action items yet."
4694
5156
  }
4695
5157
  ),
4696
- ai.transcript.length > 0 ? /* @__PURE__ */ jsxs3("section", { className: "mx-meet__note-group", "aria-label": "Transcript", children: [
5158
+ ai.transcript.length > 0 ? /* @__PURE__ */ jsxs4("section", { className: "mx-meet__note-group", "aria-label": "Transcript", children: [
4697
5159
  /* @__PURE__ */ jsx6("h3", { className: "mx-meet__note-group-title", children: "Transcript" }),
4698
- /* @__PURE__ */ jsx6("ul", { className: "mx-meet__transcript", children: ai.transcript.map((line) => /* @__PURE__ */ jsxs3(
5160
+ /* @__PURE__ */ jsx6("ul", { className: "mx-meet__transcript", children: ai.transcript.map((line) => /* @__PURE__ */ jsxs4(
4699
5161
  "li",
4700
5162
  {
4701
5163
  className: line.final && line.source === "record" ? "mx-meet__line" : "mx-meet__line mx-meet__line--interim",
@@ -4707,7 +5169,7 @@ function AiPanel({ onClose }) {
4707
5169
  line.id
4708
5170
  )) })
4709
5171
  ] }) : null,
4710
- /* @__PURE__ */ jsxs3(
5172
+ /* @__PURE__ */ jsxs4(
4711
5173
  "form",
4712
5174
  {
4713
5175
  className: "mx-meet__composer",
@@ -4734,7 +5196,7 @@ function AiPanel({ onClose }) {
4734
5196
  ),
4735
5197
  ai.asking && ai.phase !== null ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__panel-note", role: "status", children: ai.phase }) : null,
4736
5198
  ai.answer !== null ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__answer", children: ai.answer }) : null,
4737
- ai.answer !== null && ai.coverage !== null ? /* @__PURE__ */ jsxs3("p", { className: "mx-meet__coverage", children: [
5199
+ ai.answer !== null && ai.coverage !== null ? /* @__PURE__ */ jsxs4("p", { className: "mx-meet__coverage", children: [
4738
5200
  "Answered from ",
4739
5201
  ai.coverage.segmentsUsed,
4740
5202
  " of ",
@@ -4743,7 +5205,7 @@ function AiPanel({ onClose }) {
4743
5205
  ai.coverage.truncated ? " (the oldest were left out)" : "",
4744
5206
  "."
4745
5207
  ] }) : null,
4746
- ai.error !== null ? /* @__PURE__ */ jsxs3(ErrorBox, { as: "div", className: "mx-meet__refusal", error: ai.error, operation: "Run the meeting assistant", origin: "meet/components", children: [
5208
+ ai.error !== null ? /* @__PURE__ */ jsxs4(ErrorBox, { as: "div", className: "mx-meet__refusal", error: ai.error, operation: "Run the meeting assistant", origin: "meet/components", children: [
4747
5209
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__refusal-reason", children: ai.error.message }),
4748
5210
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__refusal-remedy", children: ai.error.remedy })
4749
5211
  ] }) : null
@@ -4753,11 +5215,22 @@ function Captions({ lines = 3 }) {
4753
5215
  const ai = useMeetAi();
4754
5216
  const visible = ai.transcript.slice(-lines);
4755
5217
  const translation = useCaptionTranslation(visible);
4756
- if (visible.length === 0) return null;
4757
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__captions", "aria-live": "polite", "aria-label": "Live captions", children: [
5218
+ const captions = useCaptions();
5219
+ if (!captions.on) return null;
5220
+ if (captions.state === "unavailable") {
5221
+ return /* @__PURE__ */ jsx6("div", { className: "mx-meet__captions", role: "status", "data-meet-notice": "captions-unavailable", children: /* @__PURE__ */ jsxs4("p", { className: "mx-meet__caption", children: [
5222
+ "Captions are unavailable. ",
5223
+ captions.reason,
5224
+ captions.remedy !== null ? ` ${captions.remedy}` : ""
5225
+ ] }) });
5226
+ }
5227
+ if (visible.length === 0) {
5228
+ return /* @__PURE__ */ jsx6("div", { className: "mx-meet__captions", "aria-live": "polite", "aria-label": "Live captions", "data-meet-caption": captions.state, children: /* @__PURE__ */ jsx6("p", { className: "mx-meet__caption mx-meet__caption--interim", children: captions.state === "starting" ? "Starting captions. They appear as people speak." : "Captions are on. They appear as people speak." }) });
5229
+ }
5230
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__captions", "aria-live": "polite", "aria-label": "Live captions", "data-meet-caption": "live", children: [
4758
5231
  visible.map((line) => {
4759
5232
  const translated = translation.language === null ? void 0 : translation.translations[line.id];
4760
- return /* @__PURE__ */ jsxs3(
5233
+ return /* @__PURE__ */ jsxs4(
4761
5234
  "p",
4762
5235
  {
4763
5236
  className: line.final ? "mx-meet__caption" : "mx-meet__caption mx-meet__caption--interim",
@@ -4777,7 +5250,7 @@ function Captions({ lines = 3 }) {
4777
5250
  function ConsentNotice() {
4778
5251
  const notice = useConsentNotice();
4779
5252
  if (notice === null) return null;
4780
- return /* @__PURE__ */ jsx6("p", { className: "mx-meet__consent", role: "status", children: notice });
5253
+ return /* @__PURE__ */ jsx6("p", { className: "mx-meet__consent", role: "status", "data-meet-notice": "notes-started", children: notice });
4781
5254
  }
4782
5255
  function AttendanceNotice() {
4783
5256
  const media = useLocalMedia();
@@ -4785,7 +5258,7 @@ function AttendanceNotice() {
4785
5258
  if (notice === null) return null;
4786
5259
  const refused = media.microphone.unavailable;
4787
5260
  const code = microphoneNoticeCode(media.microphone);
4788
- return /* @__PURE__ */ jsxs3(
5261
+ return /* @__PURE__ */ jsxs4(
4789
5262
  "p",
4790
5263
  {
4791
5264
  className: "mx-meet__banner mx-meet__banner--attendance",
@@ -4816,15 +5289,22 @@ function PreJoinBody({
4816
5289
  const recording = useRecording();
4817
5290
  const effects = useMediaEffects();
4818
5291
  const { notice } = useModerationNotice();
4819
- const [mode, setMode] = useState4("video");
4820
- const [microphone, setMicrophone] = useState4(true);
4821
- const [joining, setJoining] = useState4(false);
5292
+ const [mode, setMode] = useState5("video");
5293
+ const [microphone, setMicrophone] = useState5(true);
5294
+ const [joining, setJoining] = useState5(false);
4822
5295
  const camera = devices?.selected.videoinput ?? host.devices.resolve("videoinput");
4823
5296
  const mic = devices?.selected.audioinput ?? host.devices.resolve("audioinput");
4824
- const preview = useCameraPreview(mode === "video" ? camera : void 0, effects.effects);
4825
- const micStream = useMicrophoneStream(microphone ? mic : "off");
5297
+ const { reportPreview } = useMediaSupervisor();
5298
+ const [attempt, setAttempt] = useState5(0);
5299
+ const preview = useCameraPreview(
5300
+ mode === "video" ? camera : void 0,
5301
+ effects.effects,
5302
+ (outcome) => reportPreview("camera", outcome),
5303
+ attempt
5304
+ );
5305
+ const micStream = useMicrophoneStream(microphone ? mic : "off", (outcome) => reportPreview("microphone", outcome), attempt);
4826
5306
  const level = useAudioLevel(micStream);
4827
- const [speakerTesting, setSpeakerTesting] = useState4(false);
5307
+ const [speakerTesting, setSpeakerTesting] = useState5(false);
4828
5308
  useEffect6(() => {
4829
5309
  void host.devices.refresh();
4830
5310
  }, [host]);
@@ -4847,8 +5327,8 @@ function PreJoinBody({
4847
5327
  ...secondDevice !== void 0 ? { secondDevice } : {}
4848
5328
  }).then(() => onJoined?.()).catch(() => void 0).finally(() => setJoining(false));
4849
5329
  };
4850
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__prejoin", children: [
4851
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__preview", children: [
5330
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__prejoin", children: [
5331
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__preview", children: [
4852
5332
  mode === "video" && preview.preview !== null ? /* @__PURE__ */ jsx6(
4853
5333
  "video",
4854
5334
  {
@@ -4864,10 +5344,11 @@ function PreJoinBody({
4864
5344
  mode === "video" && preview.error !== null ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__preview-note", children: preview.error }) : null,
4865
5345
  microphone && micStream !== null ? /* @__PURE__ */ jsx6("div", { className: "mx-meet__meter mx-meet__meter--preview", role: "meter", "aria-label": "Microphone level", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(level * 100), children: /* @__PURE__ */ jsx6("span", { style: { width: `${Math.min(100, Math.round(level * 160))}%` } }) }) : null
4866
5346
  ] }),
4867
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__prejoin-panel", children: [
5347
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__prejoin-panel", children: [
4868
5348
  /* @__PURE__ */ jsx6("h1", { className: "mx-meet__prejoin-title", children: "Ready to join?" }),
5349
+ /* @__PURE__ */ jsx6(PreviewStatus, { onRetry: () => setAttempt((n) => n + 1) }),
4869
5350
  notice?.kind === "removed" ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__warning", children: notice.text }) : null,
4870
- devices?.labelsHidden === true ? /* @__PURE__ */ jsxs3("p", { className: "mx-meet__panel-note", children: [
5351
+ devices?.labelsHidden === true ? /* @__PURE__ */ jsxs4("p", { className: "mx-meet__panel-note", children: [
4871
5352
  "Your browser is hiding device names until you allow camera and microphone access.",
4872
5353
  /* @__PURE__ */ jsx6(
4873
5354
  "button",
@@ -4883,9 +5364,9 @@ function PreJoinBody({
4883
5364
  ] }) : null,
4884
5365
  devices?.fallbackNotice != null ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__warning", children: devices.fallbackNotice }) : null,
4885
5366
  /* @__PURE__ */ jsx6(DevicePicker, { kind: "audioinput", label: "Microphone" }),
4886
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__field-row", children: [
5367
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__field-row", children: [
4887
5368
  /* @__PURE__ */ jsx6(DevicePicker, { kind: "audiooutput", label: "Speaker" }),
4888
- /* @__PURE__ */ jsxs3(
5369
+ /* @__PURE__ */ jsxs4(
4889
5370
  Button,
4890
5371
  {
4891
5372
  type: "button",
@@ -4908,8 +5389,8 @@ function PreJoinBody({
4908
5389
  /* @__PURE__ */ jsx6(DevicePicker, { kind: "videoinput", label: "Camera" }),
4909
5390
  /* @__PURE__ */ jsx6(EffectsSettings, { preview: preview.preview }),
4910
5391
  recording.consentNotice !== null ? /* @__PURE__ */ jsx6(Alert, { variant: "info", children: /* @__PURE__ */ jsx6(AlertDescription, { children: recording.consentNotice }) }) : null,
4911
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__prejoin-actions", children: [
4912
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__check", children: [
5392
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__prejoin-actions", children: [
5393
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__check", children: [
4913
5394
  /* @__PURE__ */ jsx6(
4914
5395
  Checkbox,
4915
5396
  {
@@ -4920,7 +5401,7 @@ function PreJoinBody({
4920
5401
  ),
4921
5402
  /* @__PURE__ */ jsx6(Label, { htmlFor: "mx-meet-join-video", children: "Join with video" })
4922
5403
  ] }),
4923
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__check", children: [
5404
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__check", children: [
4924
5405
  /* @__PURE__ */ jsx6(
4925
5406
  Checkbox,
4926
5407
  {
@@ -4934,7 +5415,7 @@ function PreJoinBody({
4934
5415
  room.secondDevice === null ? /* @__PURE__ */ jsx6(Button, { type: "button", className: "mx-meet__join", disabled: joining, onClick: () => joinWith(), children: joining ? "Joining\u2026" : observe2 ? "Observe" : "Join now" }) : (
4935
5416
  // S7: ALREADY IN THIS MEETING on another tab or device — the meeting's choice
4936
5417
  // (Meet: Switch here / Join here too; Teams: Transfer here / Add this device).
4937
- /* @__PURE__ */ jsxs3("div", { className: "mx-meet__second-device", "data-meet-region": "second-device", children: [
5418
+ /* @__PURE__ */ jsxs4("div", { className: "mx-meet__second-device", "data-meet-region": "second-device", children: [
4938
5419
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__hint", children: "You're in this meeting on another device" }),
4939
5420
  /* @__PURE__ */ jsx6(
4940
5421
  Button,
@@ -4961,23 +5442,29 @@ function PreJoinBody({
4961
5442
  ] })
4962
5443
  )
4963
5444
  ] }),
4964
- room.failure !== null ? /* @__PURE__ */ jsxs3("p", { className: "mx-meet__error", children: [
5445
+ room.failure !== null ? /* @__PURE__ */ jsxs4("p", { className: "mx-meet__error", children: [
4965
5446
  room.failure.message,
4966
5447
  /* @__PURE__ */ jsx6("span", { className: "mx-meet__remedy", children: room.failure.remedy })
4967
5448
  ] }) : null
4968
5449
  ] })
4969
5450
  ] });
4970
5451
  }
4971
- function useCameraPreview(deviceId, effects) {
4972
- const [preview, setPreview] = useState4(null);
4973
- const [error, setError] = useState4(null);
5452
+ function useCameraPreview(deviceId, effects, report, attempt = 0) {
5453
+ const reportRef = useRef6(report);
5454
+ reportRef.current = report;
5455
+ const [preview, setPreview] = useState5(null);
5456
+ const [error, setError] = useState5(null);
4974
5457
  const current = useRef6(null);
4975
5458
  const initialEffect = useRef6(toVideoEffect(effects));
4976
5459
  initialEffect.current = toVideoEffect(effects);
4977
5460
  useEffect6(() => {
4978
- if (deviceId === void 0) return void 0;
5461
+ if (deviceId === void 0) {
5462
+ reportRef.current?.("off");
5463
+ return void 0;
5464
+ }
4979
5465
  let live = true;
4980
5466
  setError(null);
5467
+ reportRef.current?.("prompting");
4981
5468
  void createCameraPreview(deviceId, initialEffect.current).then((created) => {
4982
5469
  if (!live) {
4983
5470
  created.stop();
@@ -4985,8 +5472,10 @@ function useCameraPreview(deviceId, effects) {
4985
5472
  }
4986
5473
  current.current = created;
4987
5474
  setPreview(created);
5475
+ reportRef.current?.("on");
4988
5476
  }).catch((thrown) => {
4989
5477
  if (!live) return;
5478
+ reportRef.current?.({ error: thrown });
4990
5479
  const failure = thrown;
4991
5480
  const message = (failure.message ?? "").replace(/^meet\.[A-Za-z.()]+:\s*/, "");
4992
5481
  const sentence = message.length > 0 ? message.charAt(0).toUpperCase() + message.slice(1) : "";
@@ -4998,7 +5487,7 @@ function useCameraPreview(deviceId, effects) {
4998
5487
  current.current = null;
4999
5488
  setPreview(null);
5000
5489
  };
5001
- }, [deviceId]);
5490
+ }, [deviceId, attempt]);
5002
5491
  return {
5003
5492
  preview,
5004
5493
  error,
@@ -5021,9 +5510,9 @@ function DevicePicker({
5021
5510
  const triggerId = `mx-meet-device-${kind}`;
5022
5511
  const valueOf = (deviceId) => deviceId.length > 0 ? deviceId : "default";
5023
5512
  const current = devices?.selected[kind] ?? host.devices.resolve(kind) ?? "";
5024
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__field", children: [
5513
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__field", children: [
5025
5514
  /* @__PURE__ */ jsx6(Label, { htmlFor: triggerId, children: label }),
5026
- /* @__PURE__ */ jsxs3(
5515
+ /* @__PURE__ */ jsxs4(
5027
5516
  Select,
5028
5517
  {
5029
5518
  ...current.length > 0 ? { value: valueOf(current) } : {},
@@ -5110,19 +5599,19 @@ function MeetSkinRoom({
5110
5599
  if (screen === "refused" || screen === "exit") {
5111
5600
  return /* @__PURE__ */ jsx6("div", { className: "mx-meet mx-meet--lobby", children: /* @__PURE__ */ jsx6(ExitScreen, { ...onLeave !== void 0 ? { onLeave } : {} }) });
5112
5601
  }
5113
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet", children: [
5602
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet", children: [
5114
5603
  /* @__PURE__ */ jsx6(ConsentNotice, {}),
5115
5604
  /* @__PURE__ */ jsx6(AttendanceNotice, {}),
5116
- /* @__PURE__ */ jsxs3("header", { className: "mx-meet__header", children: [
5605
+ /* @__PURE__ */ jsxs4("header", { className: "mx-meet__header", children: [
5117
5606
  /* @__PURE__ */ jsx6("h1", { className: "mx-meet__title", children: snapshot?.meeting?.title ?? "Meeting" }),
5118
- /* @__PURE__ */ jsxs3("span", { className: "mx-meet__meta", children: [
5607
+ /* @__PURE__ */ jsxs4("span", { className: "mx-meet__meta", children: [
5119
5608
  participantSummary(snapshot?.participants ?? []),
5120
5609
  elapsed > 0 ? ` \xB7 ${formatDurationMs2(elapsed)}` : ""
5121
5610
  ] }),
5122
5611
  /* @__PURE__ */ jsx6(RecordingIndicator, {}),
5123
5612
  captureHeldOf(snapshot?.meeting) ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__badge", "data-meet-capture-held": "", children: "Confidential \xB7 not recorded" }) : null,
5124
5613
  isObserverRole(snapshot?.grants.role) ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__badge", "data-meet-observing": "self", children: "Observing" }) : null,
5125
- snapshot?.locked === true ? /* @__PURE__ */ jsxs3("span", { className: "mx-meet__badge", children: [
5614
+ snapshot?.locked === true ? /* @__PURE__ */ jsxs4("span", { className: "mx-meet__badge", children: [
5126
5615
  /* @__PURE__ */ jsx6(LockIcon, { width: 12, height: 12 }),
5127
5616
  " Locked"
5128
5617
  ] }) : null,
@@ -5138,9 +5627,17 @@ function MeetSkinRoom({
5138
5627
  }
5139
5628
  function ShareNotice() {
5140
5629
  const { share, actions } = useMeetCore();
5630
+ const [soundHintClosed, setSoundHintClosed] = useState5(null);
5631
+ if (share.state === "presenting" && share.audio === false && soundHintClosed !== share.at) {
5632
+ return /* @__PURE__ */ jsxs4("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "share-audio-missing", children: [
5633
+ "Sound not shared",
5634
+ /* @__PURE__ */ jsx6("span", { className: "mx-meet__remedy", children: "To include sound, share a tab and turn on Also share tab audio" }),
5635
+ /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__link", onClick: () => setSoundHintClosed(share.at), children: "Dismiss" })
5636
+ ] });
5637
+ }
5141
5638
  if (share.state !== "refused") return null;
5142
5639
  const text = share.reason === "unsupported" ? "You can't share your screen from this browser" : share.reason === "blocked" ? "Screen sharing is blocked" : "Couldn't start sharing your screen";
5143
- return /* @__PURE__ */ jsxs3("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "share-unavailable", children: [
5640
+ return /* @__PURE__ */ jsxs4("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "share-unavailable", children: [
5144
5641
  text,
5145
5642
  share.remedy !== null ? /* @__PURE__ */ jsx6("span", { className: "mx-meet__remedy", children: share.remedy }) : null,
5146
5643
  /* @__PURE__ */ jsx6("button", { type: "button", className: "mx-meet__link", onClick: actions.dismissShareNotice, children: "Dismiss" })
@@ -5168,7 +5665,7 @@ function clockText(ms) {
5168
5665
  }
5169
5666
  function ExitScreen({ onLeave }) {
5170
5667
  const { phase, reason, host, snapshot, actions, call, connection } = useMeetCore();
5171
- const [busy, setBusy] = useState4(false);
5668
+ const [busy, setBusy] = useState5(false);
5172
5669
  const failure = snapshot?.failure ?? null;
5173
5670
  const retryLeft = useCountdown(phase === "refused:lobby_rejects" ? failure?.retryAt ?? null : null);
5174
5671
  const rejoin = /* @__PURE__ */ jsx6(
@@ -5209,7 +5706,7 @@ function ExitScreen({ onLeave }) {
5209
5706
  const code = phase.slice("refused:".length);
5210
5707
  title = REFUSED_TITLES[code] ?? "You can't join this meeting";
5211
5708
  line = code === "too_early" || code === "registration_required" || code === "cancelled" ? failure?.remedy ?? null : null;
5212
- actionsNode = /* @__PURE__ */ jsxs3(Fragment, { children: [
5709
+ actionsNode = /* @__PURE__ */ jsxs4(Fragment, { children: [
5213
5710
  /* @__PURE__ */ jsx6(Button, { type: "button", variant: "outline", onClick: actions.retry, children: "Try again" }),
5214
5711
  home
5215
5712
  ] });
@@ -5220,7 +5717,7 @@ function ExitScreen({ onLeave }) {
5220
5717
  actionsNode = home;
5221
5718
  } else if (retryLeft === 0) {
5222
5719
  line = "You can ask to join again";
5223
- actionsNode = /* @__PURE__ */ jsxs3(Fragment, { children: [
5720
+ actionsNode = /* @__PURE__ */ jsxs4(Fragment, { children: [
5224
5721
  /* @__PURE__ */ jsx6(
5225
5722
  Button,
5226
5723
  {
@@ -5244,16 +5741,37 @@ function ExitScreen({ onLeave }) {
5244
5741
  switch (phase) {
5245
5742
  case "left":
5246
5743
  title = "You left the meeting";
5247
- actionsNode = /* @__PURE__ */ jsxs3(Fragment, { children: [
5744
+ actionsNode = /* @__PURE__ */ jsxs4(Fragment, { children: [
5248
5745
  rejoin,
5249
5746
  home
5250
5747
  ] });
5251
5748
  break;
5252
5749
  case "disconnected":
5750
+ if (failure?.stage === "join" && (failure.reason ?? null) === null) {
5751
+ title = "Can't connect to the meeting";
5752
+ line = connection === "offline" ? "You're offline. Check your internet connection." : "Check your network. A VPN, firewall or proxy may be blocking the call.";
5753
+ notice = "cannot-connect";
5754
+ actionsNode = /* @__PURE__ */ jsxs4(Fragment, { children: [
5755
+ /* @__PURE__ */ jsx6(
5756
+ Button,
5757
+ {
5758
+ type: "button",
5759
+ disabled: busy,
5760
+ onClick: () => {
5761
+ setBusy(true);
5762
+ void actions.rejoin().catch(() => void 0).finally(() => setBusy(false));
5763
+ },
5764
+ children: "Try again"
5765
+ }
5766
+ ),
5767
+ home
5768
+ ] });
5769
+ break;
5770
+ }
5253
5771
  title = "You lost your connection to the meeting";
5254
5772
  line = connection === "offline" ? "You're offline. You'll rejoin automatically when your internet is back." : connection === "server_unreachable" ? "Can't reach the meeting server. You'll rejoin automatically when it answers." : failure?.remedy ?? "Check your internet connection, then rejoin.";
5255
5773
  notice = "disconnected";
5256
- actionsNode = /* @__PURE__ */ jsxs3(Fragment, { children: [
5774
+ actionsNode = /* @__PURE__ */ jsxs4(Fragment, { children: [
5257
5775
  rejoin,
5258
5776
  home
5259
5777
  ] });
@@ -5266,14 +5784,14 @@ function ExitScreen({ onLeave }) {
5266
5784
  title = "You joined from another tab or device";
5267
5785
  line = "This screen left the meeting so you aren't in it twice.";
5268
5786
  notice = "displaced";
5269
- actionsNode = /* @__PURE__ */ jsxs3(Fragment, { children: [
5787
+ actionsNode = /* @__PURE__ */ jsxs4(Fragment, { children: [
5270
5788
  rejoin,
5271
5789
  home
5272
5790
  ] });
5273
5791
  break;
5274
5792
  case "inactive":
5275
5793
  title = "You left the meeting because this tab was inactive";
5276
- actionsNode = /* @__PURE__ */ jsxs3(Fragment, { children: [
5794
+ actionsNode = /* @__PURE__ */ jsxs4(Fragment, { children: [
5277
5795
  rejoin,
5278
5796
  home
5279
5797
  ] });
@@ -5296,7 +5814,7 @@ function ExitScreen({ onLeave }) {
5296
5814
  break;
5297
5815
  }
5298
5816
  }
5299
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__waiting", "data-meet-exit": phase, children: [
5817
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__waiting", "data-meet-exit": phase, children: [
5300
5818
  /* @__PURE__ */ jsx6(Avatar, { name: host?.identity.displayName ?? "", url: host?.identity.avatarUrl ?? null, size: 72 }),
5301
5819
  /* @__PURE__ */ jsx6("h1", { className: "mx-meet__prejoin-title", children: title }),
5302
5820
  line !== null ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__empty-body", children: line }) : null,
@@ -5307,7 +5825,7 @@ function ExitScreen({ onLeave }) {
5307
5825
  function WaitingRoom({ host, onLeave }) {
5308
5826
  const { waiting, withdraw, askAgain } = useWaiting();
5309
5827
  const { phaseNotice } = useMeetCore();
5310
- const [busy, setBusy] = useState4(false);
5828
+ const [busy, setBusy] = useState5(false);
5311
5829
  const admission = waiting?.admission ?? "knocking";
5312
5830
  const reknockLeft = useCountdown(admission === "denied" ? waiting?.reknockAt ?? null : null);
5313
5831
  const run = (action) => () => {
@@ -5330,21 +5848,21 @@ function WaitingRoom({ host, onLeave }) {
5330
5848
  line = `You can ask again in ${clockText(reknockLeft)}`;
5331
5849
  cooldownNotice = true;
5332
5850
  }
5333
- actions = /* @__PURE__ */ jsxs3(Fragment, { children: [
5851
+ actions = /* @__PURE__ */ jsxs4(Fragment, { children: [
5334
5852
  waiting?.reknockAllowed === true || waiting?.reknockAt != null && reknockLeft === 0 ? /* @__PURE__ */ jsx6(Button, { type: "button", disabled: busy, onClick: run(askAgain), children: "Ask to join again" }) : null,
5335
5853
  home
5336
5854
  ] });
5337
5855
  break;
5338
5856
  case "expired":
5339
5857
  title = "No one responded";
5340
- actions = /* @__PURE__ */ jsxs3(Fragment, { children: [
5858
+ actions = /* @__PURE__ */ jsxs4(Fragment, { children: [
5341
5859
  /* @__PURE__ */ jsx6(Button, { type: "button", disabled: busy, onClick: run(askAgain), children: "Ask again" }),
5342
5860
  home
5343
5861
  ] });
5344
5862
  break;
5345
5863
  case "withdrawn":
5346
5864
  title = "You left the waiting room";
5347
- actions = /* @__PURE__ */ jsxs3(Fragment, { children: [
5865
+ actions = /* @__PURE__ */ jsxs4(Fragment, { children: [
5348
5866
  /* @__PURE__ */ jsx6(Button, { type: "button", disabled: busy, onClick: run(askAgain), children: "Rejoin" }),
5349
5867
  home
5350
5868
  ] });
@@ -5358,7 +5876,7 @@ function WaitingRoom({ host, onLeave }) {
5358
5876
  line = waiting?.admittersPresent === false ? "The host isn't here yet" : null;
5359
5877
  actions = /* @__PURE__ */ jsx6(Button, { type: "button", variant: "outline", disabled: busy, onClick: run(withdraw), children: "Cancel request" });
5360
5878
  }
5361
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__waiting", children: [
5879
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__waiting", children: [
5362
5880
  /* @__PURE__ */ jsx6(Avatar, { name: host.identity.displayName, url: host.identity.avatarUrl, size: 72 }),
5363
5881
  /* @__PURE__ */ jsx6("h1", { className: "mx-meet__prejoin-title", children: title }),
5364
5882
  phaseNotice === "sent-to-waiting" ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__empty-body", role: "status", "data-meet-notice": "sent-to-waiting", children: "The host moved you back to the waiting room" }) : null,
@@ -5378,9 +5896,9 @@ function HostMenu() {
5378
5896
  const host = useRequiredMeetHost();
5379
5897
  const snapshot = useMeetSnapshot();
5380
5898
  const end = useEndMeeting();
5381
- const [confirmingEnd, setConfirmingEnd] = useState4(false);
5899
+ const [confirmingEnd, setConfirmingEnd] = useState5(false);
5382
5900
  const locked = snapshot?.locked === true;
5383
- return /* @__PURE__ */ jsxs3("div", { className: "mx-meet__host-menu", children: [
5901
+ return /* @__PURE__ */ jsxs4("div", { className: "mx-meet__host-menu", children: [
5384
5902
  /* @__PURE__ */ jsx6(
5385
5903
  "button",
5386
5904
  {
@@ -5392,7 +5910,7 @@ function HostMenu() {
5392
5910
  children: locked ? "Unlock meeting" : "Lock meeting"
5393
5911
  }
5394
5912
  ),
5395
- end.canEnd ? confirmingEnd ? /* @__PURE__ */ jsxs3("span", { className: "mx-meet__confirm", role: "group", "aria-label": "End this meeting?", children: [
5913
+ end.canEnd ? confirmingEnd ? /* @__PURE__ */ jsxs4("span", { className: "mx-meet__confirm", role: "group", "aria-label": "End this meeting?", children: [
5396
5914
  /* @__PURE__ */ jsx6("span", { className: "mx-meet__confirm-text", children: "End it for everyone? Every participant is disconnected, the note-taker stops, and the wrap-up is written. Nobody can rejoin this meeting afterwards." }),
5397
5915
  /* @__PURE__ */ jsx6(
5398
5916
  "button",
@@ -5448,9 +5966,9 @@ function GuestRecordAccessControl({
5448
5966
  const isHost = inRoomHost || viewerId !== null && meeting.hostUserId === viewerId;
5449
5967
  if (host === null || !isHost) return null;
5450
5968
  const resolved = access.setting === "default" && access.effective !== null ? ` Right now that means: ${guestRecordAccessLabel(access.effective.level).toLowerCase()}.` : "";
5451
- return /* @__PURE__ */ jsxs3("section", { className: "mx-meet__record-section", "aria-label": "What guests may read", children: [
5969
+ return /* @__PURE__ */ jsxs4("section", { className: "mx-meet__record-section", "aria-label": "What guests may read", children: [
5452
5970
  /* @__PURE__ */ jsx6("h2", { className: "mx-meet__record-section-title", children: "What guests may read" }),
5453
- /* @__PURE__ */ jsxs3("label", { className: "mx-meet__field", children: [
5971
+ /* @__PURE__ */ jsxs4("label", { className: "mx-meet__field", children: [
5454
5972
  /* @__PURE__ */ jsx6("span", { className: "mx-meet__field-label", children: "People who attended by link, without an account" }),
5455
5973
  /* @__PURE__ */ jsx6(
5456
5974
  "select",
@@ -5467,12 +5985,12 @@ function GuestRecordAccessControl({
5467
5985
  }
5468
5986
  )
5469
5987
  ] }),
5470
- /* @__PURE__ */ jsxs3("p", { className: "mx-meet__panel-note", children: [
5988
+ /* @__PURE__ */ jsxs4("p", { className: "mx-meet__panel-note", children: [
5471
5989
  guestRecordAccessExplanation(access.setting),
5472
5990
  resolved
5473
5991
  ] }),
5474
5992
  access.saving ? /* @__PURE__ */ jsx6("p", { className: "mx-meet__panel-note", role: "status", children: "Saving what guests may read\u2026" }) : null,
5475
- access.error !== null ? /* @__PURE__ */ jsxs3(ErrorBox, { as: "div", className: "mx-meet__refusal", error: access.error, operation: "Change who can join", origin: "meet/components", children: [
5993
+ access.error !== null ? /* @__PURE__ */ jsxs4(ErrorBox, { as: "div", className: "mx-meet__refusal", error: access.error, operation: "Change who can join", origin: "meet/components", children: [
5476
5994
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__refusal-reason", children: access.error.message }),
5477
5995
  /* @__PURE__ */ jsx6("p", { className: "mx-meet__refusal-remedy", children: access.error.remedy })
5478
5996
  ] }) : null
@@ -5491,9 +6009,11 @@ export {
5491
6009
  CameraOffIcon,
5492
6010
  CaptionLanguageSettings,
5493
6011
  Captions,
6012
+ CaptionsIcon,
5494
6013
  ChatIcon,
5495
6014
  ChatPanel,
5496
6015
  CheckIcon,
6016
+ ChevronUpIcon,
5497
6017
  CloseIcon,
5498
6018
  ConnectionDot,
5499
6019
  ConsentNotice,
@@ -5514,6 +6034,7 @@ export {
5514
6034
  MicIcon,
5515
6035
  MicOffIcon,
5516
6036
  MoreIcon,
6037
+ NotesIcon,
5517
6038
  PanelShell,
5518
6039
  ParticipantTile,
5519
6040
  PencilIcon,