diff --git a/messages/de.json b/messages/de.json
index 545e59204..4abc23b6f 100644
--- a/messages/de.json
+++ b/messages/de.json
@@ -1321,6 +1321,7 @@
"defaultLabel": "Default",
"autoModeLabel": "Auto",
"overrideModeLabel": "Überschrieben",
+ "overrideToggleLabel": "Eigene Werte",
"resetAction": "Auf Default zurücksetzen",
"resetAllAction": "Alle auf Default zurücksetzen",
"minLabel": "Min",
diff --git a/messages/en.json b/messages/en.json
index 6639f5cde..05c96729c 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -1321,6 +1321,7 @@
"defaultLabel": "Default",
"autoModeLabel": "Auto",
"overrideModeLabel": "Override",
+ "overrideToggleLabel": "Custom range",
"resetAction": "Reset to default",
"resetAllAction": "Reset all to default",
"minLabel": "Min",
diff --git a/messages/es.json b/messages/es.json
index c3b6d7bc9..072956e69 100644
--- a/messages/es.json
+++ b/messages/es.json
@@ -1321,6 +1321,7 @@
"defaultLabel": "Default",
"autoModeLabel": "Auto",
"overrideModeLabel": "Override",
+ "overrideToggleLabel": "Custom range",
"resetAction": "Reset to default",
"resetAllAction": "Reset all to default",
"minLabel": "Mín",
diff --git a/messages/fr.json b/messages/fr.json
index 0d7d65f87..1f32a3c87 100644
--- a/messages/fr.json
+++ b/messages/fr.json
@@ -1321,6 +1321,7 @@
"defaultLabel": "Default",
"autoModeLabel": "Auto",
"overrideModeLabel": "Override",
+ "overrideToggleLabel": "Custom range",
"resetAction": "Reset to default",
"resetAllAction": "Reset all to default",
"minLabel": "Min",
diff --git a/messages/it.json b/messages/it.json
index 400746aed..aa96d2f21 100644
--- a/messages/it.json
+++ b/messages/it.json
@@ -1321,6 +1321,7 @@
"defaultLabel": "Default",
"autoModeLabel": "Auto",
"overrideModeLabel": "Override",
+ "overrideToggleLabel": "Custom range",
"resetAction": "Reset to default",
"resetAllAction": "Reset all to default",
"minLabel": "Min",
diff --git a/messages/pl.json b/messages/pl.json
index 8399074df..f815e202e 100644
--- a/messages/pl.json
+++ b/messages/pl.json
@@ -1321,6 +1321,7 @@
"defaultLabel": "Default",
"autoModeLabel": "Auto",
"overrideModeLabel": "Override",
+ "overrideToggleLabel": "Custom range",
"resetAction": "Reset to default",
"resetAllAction": "Reset all to default",
"minLabel": "Min",
diff --git a/src/components/settings/account-section.tsx b/src/components/settings/account-section.tsx
index ba833ad58..08862f54a 100644
--- a/src/components/settings/account-section.tsx
+++ b/src/components/settings/account-section.tsx
@@ -740,7 +740,13 @@ function PasskeyListSection({ isAuthenticated }: { isAuthenticated: boolean }) {
table only at `≥ md`, and at `< md` paint a card-list where
every passkey's name, device type, backup status, created
date, and delete action are all visible without scrolling. */}
-
+ {/* v1.4.33 — desktop table flips to card list at `lg` instead
+ of `md` so iPad portrait (768 px = exactly the `md`
+ inflection) lands on the card layout. The table needs
+ ~620 px of column width to read; below that it scrolls
+ horizontally and the destructive delete column is the one
+ that disappears. */}
+
- {/* Mobile card list — < md only. Each passkey gets its own
- card so the delete action stays visible and tap-targetable
- (44px) without the user having to horizontally scroll
- through a wide table. */}
+ {/* Mobile + tablet card list — < lg only. Each passkey gets
+ its own card so the delete action stays visible and
+ tap-targetable (44 px) without the user having to
+ horizontally scroll through a wide table. v1.4.33 bumped
+ the breakpoint from `md` to `lg` so iPad portrait (768 px)
+ stays on the card layout instead of flipping between
+ layouts on rotation. */}
diff --git a/src/components/settings/settings-shell.tsx b/src/components/settings/settings-shell.tsx
index 787d415aa..72b964f18 100644
--- a/src/components/settings/settings-shell.tsx
+++ b/src/components/settings/settings-shell.tsx
@@ -135,6 +135,29 @@ export function SettingsShell({ active, children }: SettingsShellProps) {
const { t } = useTranslations();
const activeSlug = deriveActiveSlug(pathname, active);
+ // v1.4.33 IW4 — scroll the active chip into view inside the
+ // horizontal mobile strip. On a 393 CSS px viewport the strip
+ // is 11 chips wide and the rightmost four sit below the fold; a
+ // user who tapped one of those chips lands on the new route
+ // with the strip still scrolled to the leftmost chip, which
+ // reads as if the navigation is broken. `inline: "center"`
+ // anchors the active chip in the visible middle of its scroll
+ // container so the user keeps spatial orientation between
+ // sections.
+ const mobileStripRef = React.useRef(null);
+ React.useEffect(() => {
+ if (typeof window === "undefined") return;
+ const strip = mobileStripRef.current;
+ if (!strip) return;
+ const active = strip.querySelector('[aria-current="page"]');
+ if (!active) return;
+ active.scrollIntoView({
+ block: "nearest",
+ inline: "center",
+ behavior: "smooth",
+ });
+ }, [activeSlug]);
+
// v1.4.25 W8 — AuthShell wraps the page in `px-4 py-6 md:px-6`
// already, so this inner shell only carries the wider max-width.
// Previously the duplicate `px-4 py-6 md:px-6 md:py-8` here was
@@ -150,6 +173,7 @@ export function SettingsShell({ active, children }: SettingsShellProps) {
page, which makes the page feel like every section card has
an overflow problem. */}
+ {/* v1.4.33 F17 — the switch label used to flip between
+ "Auto" and "Überschrieben" with the current state. The
+ maintainer's audit caught that as confusing: a user
+ looking at a row with "Auto" + the toggle off reads it
+ as "Auto is off, why are there no inputs?" instead of
+ "flip the switch to enter a custom range". Anchor the
+ label on the *action* ("Eigene Werte" / "Custom range")
+ so the affordance is unambiguous; the
+ `thresholds.sourceOverride` badge to the right still
+ announces when the override is active. */}