QA release: backend 1.1.24, frontend 1.1.69 (frontend re-cut, 4th)

BACKEND UNCHANGED. Fourth set of bits under the frontend 1.1.69 tag:

  r1  sha256:0663eb0d1fb8506b02842d08610bdcfa404756651260c20b03cf61c1534d26a3
  r2  sha256:db98bc5371faa77e28563a65741f958ee2e5a722a2d2b1e28ac73786dcdcf9e0
  r3  sha256:62fdd046bd7c2f140ad77b6343f97642ada70e478157ce6ae14bdf991e5c1184
  r4  sha256:384c2f148699b1fc1163825a41e5c555ca20d193ea38902df26f0f7ac3468d49  <-- this
  backend sha256:548ef5e8d3c5a1bcc57a557b79fcde5ca8338868f0a89b44e2291938c17d624c

Built from e5276b94. Over r3, the single-tab behaviour changed materially:

  * NEWEST TAB WINS. Opening the app supersedes the older tab instead of
    turning the new one away. The old tab reloads (not just an overlay) so its
    engine and any live capture stop.
  * A tab IN A MEETING refuses to be superseded — #/room/:id keeps the lock and
    the claimer is told "Meeting in Progress". Without this, opening the app
    anywhere would have dropped a live call.
  * /download never blocks: it is a link people paste, and the one-tab rule has
    no session there to protect.
  * The "Close This Tab" button is gone. window.close() is refused for a tab
    the script did not open, so it had always been inert.
  * A holder on an older build that cannot hear the claim still degrades to the
    previous "Already Open" screen after 3s.

Also: /download works as a plain path, Crashlytics with native crash reporting,
and build number 29.

Bundle hash v=0811f7dde5c2, checked against r3's v=0d21d5692e06 before pushing
so a cache hit could not republish the old bundle under the same tag.

TAG REUSED — `docker compose up -d` will NOT fetch this on a host already
running an earlier 1.1.69. Force the pull:

  cd /usr/local/conferencing
  sudo bash setup.sh --upgrade --backend-tag 1.1.24 --frontend-tag 1.1.69

  docker inspect --format '{{.Image}}' conferencing_frontend
  expect sha256:384c2f148699...
This tag has no release notes.