diff --git a/.codex/skills/design-vpn-client-ui/SKILL.md b/.codex/skills/design-vpn-client-ui/SKILL.md
index 42febc4..d2bf230 100644
--- a/.codex/skills/design-vpn-client-ui/SKILL.md
+++ b/.codex/skills/design-vpn-client-ui/SKILL.md
@@ -33,6 +33,7 @@ Preserve the repo's focused one-screen VPN client language: a centered primary a
- Prefer one clear value over unsupported detail. Hide subscription fields the provider does not supply.
- Keep client UI compact and calm. Do not introduce dashboard cards, decorative chrome, or admin-console density.
- Do not use a modal, popup, or blocking backdrop unless the user explicitly asks for one. Prefer inline disclosure or a non-modal layer that preserves the main screen.
+- When the owner explicitly chooses modal treatment for critical confirmations, reuse one accessible full-screen confirmation popup: blur and block the background, reveal from center, then stage text and actions.
- Avoid borders, divider lines, and framed regions by default. Build hierarchy with spacing, typography, subtle surface changes, light, and depth; use a line only when it communicates an essential state.
- In client-side editors, prefer flat text controls and accessible custom pickers over browser-native menus when the native surface breaks the visual language. Do not append another blank row until the current row is complete.
diff --git a/.codex/skills/design-vpn-client-ui/references/motion-and-interaction.md b/.codex/skills/design-vpn-client-ui/references/motion-and-interaction.md
index 5451650..b61c231 100644
--- a/.codex/skills/design-vpn-client-ui/references/motion-and-interaction.md
+++ b/.codex/skills/design-vpn-client-ui/references/motion-and-interaction.md
@@ -87,7 +87,14 @@ Use exponential ease-out curves such as `cubic-bezier(0.16, 1, 0.3, 1)` for arri
- When an existing subscription is being edited and the field is idle, use the mode-accent underline as a five-second timeout indicator: start bright, fade to quiet, then restore display mode.
- Pause the timeout once the user enters content.
- Close and clear unfinished input on outside click or Escape.
-- Animate the trash lid independently on hover. Open an inline, non-blocking confirmation surface instead of a browser-native confirm dialog.
+- Animate the trash lid independently on hover. Use the shared critical confirmation popup instead of a browser-native confirm dialog.
+
+## Critical confirmation popup
+
+- Reserve the blocking popup for explicit destructive or data-loss confirmation. It must cover the viewport, make the background inert, and use `alertdialog` with `aria-modal`.
+- Fade and blur the backdrop first, resolve the popup from the center, then reveal its title, description, and actions in a short sequence.
+- Put initial focus on the safe action, trap Tab within the popup, let Escape and backdrop click choose the safe action, and restore the invoking focus on close.
+- Reuse the same component and motion vocabulary for every critical confirmation. Reduced motion presents the final state immediately.
## First-run initialization
diff --git a/.codex/skills/design-vpn-client-ui/references/visual-language.md b/.codex/skills/design-vpn-client-ui/references/visual-language.md
index dc4795a..5ad27e0 100644
--- a/.codex/skills/design-vpn-client-ui/references/visual-language.md
+++ b/.codex/skills/design-vpn-client-ui/references/visual-language.md
@@ -48,7 +48,7 @@ Design for a macOS user glancing at a small VPN control surface in a quiet deskt
- Use one fast translucent cloud treatment for explanatory tooltips. Place the cloud above its target with strong enough contrast to survive busy content beneath it.
- Keep a tooltip as a sibling of the animated icon/button it describes. A tooltip must never rotate, glow, blur, scale, or move with the control.
-- Use inline confirmation for destructive subscription removal. Explain that VPN stops and proxy-dependent applications lose connectivity until a new subscription is configured.
+- Use the shared full-screen critical confirmation popup for destructive actions and unsaved-data exits. Keep the centered surface flat, with hierarchy from blur, spacing, type, and staged motion rather than borders or rounded cards.
- Animate physical icon parts when their function suggests it, such as lifting a trash lid on hover, while keeping hit areas and nearby text fixed.
- Keep advanced client editors flat inside their side layer: rows, notes, selectors, and actions should not become nested cards, bordered fields, or raised buttons. Use spacing, type, focus light, and state color for hierarchy.
diff --git a/src/shared/versions.js b/src/shared/versions.js
index 33fd823..f415153 100644
--- a/src/shared/versions.js
+++ b/src/shared/versions.js
@@ -1,6 +1,6 @@
export const HARBOR_VERSIONS = Object.freeze({
- macClient: '0.5.0',
- gatewayClient: '0.5.0',
+ macClient: '0.5.1',
+ gatewayClient: '0.5.1',
gatewayBackend: '0.5.0',
});
diff --git a/src/web/components/ClientOverviewPage.jsx b/src/web/components/ClientOverviewPage.jsx
index 59a7926..6f0c1e4 100644
--- a/src/web/components/ClientOverviewPage.jsx
+++ b/src/web/components/ClientOverviewPage.jsx
@@ -13,6 +13,7 @@ import {
import { formatBytes } from '../utils/format.js';
import { instructionBlocks } from '../instructions.js';
import { createLatestRequest, operationBlocked } from '../state/operations.js';
+import { ConfirmationPopup } from './ConfirmationPopup.jsx';
import { canAppendRouteRule } from '../../shared/routingRules.js';
import {
HARBOR_VERSIONS,
@@ -326,7 +327,6 @@ function LocalRulesPanel({
blocked,
dirty,
restartPending,
- confirmingClose,
error,
operations,
panelRef,
@@ -334,8 +334,6 @@ function LocalRulesPanel({
onChange,
onRemove,
onRemoveComplete,
- onKeepEditing,
- onDiscard,
onClose,
onSave,
}) {
@@ -373,16 +371,6 @@ function LocalRulesPanel({