From 4a1f7f93dfe4b15edbf19b644837cc1d3e1c52b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?=
Date: Sat, 27 Jun 2026 22:23:17 +0200
Subject: [PATCH] fix(security): keep second-factor controls reachable on touch
The inline rename save/cancel controls on the security-key and passkey lists and
the passkey-nudge dismiss button sat at 32px, below the 44px touch minimum. Give
them the same min-h-11/min-w-11 phone target that collapses to 32px from sm up.
Add an xs (30rem) breakpoint and stack the recovery-code grid one-up below it so
the 11-character codes no longer crowd at 320px.
---
src/app/globals.css | 4 ++++
.../settings/security-section/passkey-list-section.tsx | 4 ++--
.../settings/security-section/passkey-upgrade-nudge.tsx | 2 +-
.../settings/security-section/recovery-codes-panel.tsx | 2 +-
.../settings/security-section/security-keys-card.tsx | 4 ++--
5 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/app/globals.css b/src/app/globals.css
index 20db09ff5..95ee9ba77 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -33,6 +33,10 @@
@custom-variant dark (&:is(.dark *));
@theme inline {
+ /* Extra-small breakpoint (30rem / 480px) for the narrowest phones — the
+ default scale starts at sm (640px), which leaves a gap between an iPhone SE
+ and a small tablet where two-up grids of fixed-width content overflow. */
+ --breakpoint-xs: 30rem;
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-sans);
diff --git a/src/components/settings/security-section/passkey-list-section.tsx b/src/components/settings/security-section/passkey-list-section.tsx
index 03e1e6fc4..eda11e875 100644
--- a/src/components/settings/security-section/passkey-list-section.tsx
+++ b/src/components/settings/security-section/passkey-list-section.tsx
@@ -165,7 +165,7 @@ export function PasskeyListSection({
type="submit"
variant="ghost"
size="icon"
- className="h-8 w-8 shrink-0"
+ className="min-h-11 min-w-11 shrink-0 sm:h-8 sm:min-h-0 sm:w-8 sm:min-w-0"
disabled={
rename.isPending || editName.trim().length === 0
}
@@ -181,7 +181,7 @@ export function PasskeyListSection({
type="button"
variant="ghost"
size="icon"
- className="h-8 w-8 shrink-0"
+ className="min-h-11 min-w-11 shrink-0 sm:h-8 sm:min-h-0 sm:w-8 sm:min-w-0"
onClick={() => setEditingId(null)}
aria-label={t("common.cancel")}
>
diff --git a/src/components/settings/security-section/passkey-upgrade-nudge.tsx b/src/components/settings/security-section/passkey-upgrade-nudge.tsx
index e1d1caa2a..0f953ce0f 100644
--- a/src/components/settings/security-section/passkey-upgrade-nudge.tsx
+++ b/src/components/settings/security-section/passkey-upgrade-nudge.tsx
@@ -41,7 +41,7 @@ export function PasskeyUpgradeNudge() {
type="button"
variant="ghost"
size="icon"
- className="h-8 w-8 shrink-0"
+ className="min-h-11 min-w-11 shrink-0 sm:h-8 sm:min-h-0 sm:w-8 sm:min-w-0"
onClick={() => dismiss.mutate()}
disabled={dismiss.isPending}
aria-label={t("common.dismiss")}
diff --git a/src/components/settings/security-section/recovery-codes-panel.tsx b/src/components/settings/security-section/recovery-codes-panel.tsx
index 858b0720d..84eee7741 100644
--- a/src/components/settings/security-section/recovery-codes-panel.tsx
+++ b/src/components/settings/security-section/recovery-codes-panel.tsx
@@ -53,7 +53,7 @@ export function RecoveryCodesPanel({ codes }: { codes: string[] }) {
{t("settings.security.recovery.saveNowHint")}
{codes.map((code) => (
diff --git a/src/components/settings/security-section/security-keys-card.tsx b/src/components/settings/security-section/security-keys-card.tsx
index 974df7b95..4a1a5353f 100644
--- a/src/components/settings/security-section/security-keys-card.tsx
+++ b/src/components/settings/security-section/security-keys-card.tsx
@@ -166,7 +166,7 @@ export function SecurityKeysCard({ keys }: { keys: WebauthnKeyInfo[] }) {
type="submit"
variant="ghost"
size="icon"
- className="h-8 w-8 shrink-0"
+ className="min-h-11 min-w-11 shrink-0 sm:h-8 sm:min-h-0 sm:w-8 sm:min-w-0"
disabled={
rename.isPending || editName.trim().length === 0
}
@@ -182,7 +182,7 @@ export function SecurityKeysCard({ keys }: { keys: WebauthnKeyInfo[] }) {
type="button"
variant="ghost"
size="icon"
- className="h-8 w-8 shrink-0"
+ className="min-h-11 min-w-11 shrink-0 sm:h-8 sm:min-h-0 sm:w-8 sm:min-w-0"
onClick={() => setEditingId(null)}
aria-label={t("common.cancel")}
>