diff --git a/pwa/index.html b/pwa/index.html
index 2005b54..1a66208 100644
--- a/pwa/index.html
+++ b/pwa/index.html
@@ -25,7 +25,11 @@
diff --git a/pwa/src/main.ts b/pwa/src/main.ts
index 6b1a920..8701c0f 100644
--- a/pwa/src/main.ts
+++ b/pwa/src/main.ts
@@ -11,12 +11,44 @@ import './styles/main.css';
import 'leaflet/dist/leaflet.css';
import { initLocale } from './i18n/i18n';
import { init } from './app';
-import { setStatus } from './ui/status-bar';
-import { t } from './i18n/i18n';
import { maybeShow as maybeShowIosInstallHint } from './ui/install-hint';
console.info(`[tilfluktsrom] build ${__BUILD_REVISION__}`);
+// Make `registerType: 'autoUpdate'` actually auto-update the running tab.
+// vite-plugin-pwa's autoUpdate strategy makes the new service worker
+// skipWaiting + clientsClaim, but the JS already loaded in the open tab is
+// the *old* build until something triggers a navigation. Without this
+// listener, a deploy is invisible until the user manually refreshes.
+//
+// We *defer* the reload until the user next backgrounds the app
+// (visibilityState === 'hidden') instead of reloading immediately. This is
+// an emergency app: a mid-task reload would lose the selected shelter,
+// compass mode, and any in-flight UI state right when the user can least
+// afford to be surprised. Deferring keeps the "auto" promise (they're on
+// the new version next time they look at the screen) without interrupting
+// active use.
+//
+// The `wasAlreadyControlled` guard avoids reloading on the very first SW
+// install (when there was no previous controller — that's a fresh visit,
+// not an update).
+if ('serviceWorker' in navigator) {
+ const wasAlreadyControlled = !!navigator.serviceWorker.controller;
+ let pendingReload = false;
+
+ navigator.serviceWorker.addEventListener('controllerchange', () => {
+ if (!wasAlreadyControlled) return;
+ pendingReload = true;
+ });
+
+ document.addEventListener('visibilitychange', () => {
+ if (pendingReload && document.visibilityState === 'hidden') {
+ pendingReload = false;
+ window.location.reload();
+ }
+ });
+}
+
document.addEventListener('DOMContentLoaded', async () => {
initLocale();
@@ -25,14 +57,6 @@ document.addEventListener('DOMContentLoaded', async () => {
await navigator.storage.persist();
}
- // Listen for service worker updates — flash a status message when a new
- // version activates so the user knows they have fresh code/data.
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker.addEventListener('controllerchange', () => {
- setStatus(t('update_success'));
- });
- }
-
await init();
// Shown only on first iOS Safari visit, once per device. Placed after init()
diff --git a/pwa/src/styles/main.css b/pwa/src/styles/main.css
index 9e89200..f045d71 100644
--- a/pwa/src/styles/main.css
+++ b/pwa/src/styles/main.css
@@ -86,6 +86,13 @@ html, body {
cursor: not-allowed;
}
+#share-btn svg {
+ display: block;
+ /* `↻` and `ℹ` glyphs sit on a baseline; an SVG inside an inline-flex
+ container can otherwise pick up extra descender space and look
+ misaligned next to them. `display:block` removes that. */
+}
+
/* --- Main content area (map or compass) --- */
#main-content {
flex: 1;