From a246e7bf55f8aa0465f64a93d991fc6770df5054 Mon Sep 17 00:00:00 2001 From: Miso Tanaka <22117028+miso-develop@users.noreply.github.com> Date: Fri, 18 Sep 2026 23:37:44 +0900 Subject: [PATCH 1/2] style(web): add space before passphrase divider --- web/src/style.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web/src/style.css b/web/src/style.css index 5c27f34..be7b188 100644 --- a/web/src/style.css +++ b/web/src/style.css @@ -125,6 +125,10 @@ h3 { margin-top: 24px; } border-top: 1px solid #e5e5e5; } +.security-subsection[data-security-subsection="change-passphrase"] { + margin-top: 48px; +} + .security-subsection > h3 { margin-top: 0; } @@ -458,4 +462,8 @@ button:disabled, input:disabled, select:disabled { .shell { padding: 24px; } .status div, .build-identity div { grid-template-columns: 1fr; gap: 4px; } .panel-heading { align-items: flex-start; flex-direction: column; } + + .security-subsection[data-security-subsection="change-passphrase"] { + margin-top: 40px; + } } From 0b271a9c293e9478ebc4b0363f17f7e7637f0ee4 Mon Sep 17 00:00:00 2001 From: Miso Tanaka <22117028+miso-develop@users.noreply.github.com> Date: Fri, 18 Sep 2026 23:37:48 +0900 Subject: [PATCH 2/2] test(web): pin passphrase divider spacing contract --- .../browser/post-provisioning-layout-smoke.ts | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/web/tests/browser/post-provisioning-layout-smoke.ts b/web/tests/browser/post-provisioning-layout-smoke.ts index f3b7a37..bbbafa4 100644 --- a/web/tests/browser/post-provisioning-layout-smoke.ts +++ b/web/tests/browser/post-provisioning-layout-smoke.ts @@ -640,10 +640,29 @@ async function verifySharedRouteGeometryPolicy(): Promise { assert(subsection.querySelector(":scope > hr") === null, `${name} must not duplicate the CSS divider with an hr`); assert(getComputedStyle(heading!).marginTop === "0px", `${name} heading must start immediately after the shared divider spacing`); } + const recoveryStyle = getComputedStyle(recoverySubsection); + const passphraseStyle = getComputedStyle(passphraseSubsection); assert( - getComputedStyle(recoverySubsection).borderTopColor === getComputedStyle(passphraseSubsection).borderTopColor, + recoveryStyle.borderTopColor === passphraseStyle.borderTopColor, "Recovery subsections must share the same neutral divider treatment", ); + assert( + parseFloat(recoveryStyle.marginTop) === 28, + "Recovery Package must retain the generic 28px security-subsection spacing", + ); + assert( + parseFloat(passphraseStyle.marginTop) >= 40, + "Change Recovery Passphrase must have at least 40px top margin before its divider at desktop width", + ); + assert( + parseFloat(passphraseStyle.marginTop) > parseFloat(recoveryStyle.marginTop), + "Change Recovery Passphrase must be more separated from preceding controls than the generic security subsection", + ); + assert( + passphraseSubsection.querySelectorAll(":scope > hr").length === 0 && + parseFloat(passphraseStyle.borderTopWidth) >= 1, + "Change Recovery Passphrase must keep exactly one CSS top divider and no duplicate hr", + ); for (const [index, section] of productionPanels.entries()) { const style = getComputedStyle(section); @@ -711,6 +730,20 @@ async function verifyStickyHeaderPolicy(): Promise { const overlayZ = Number.parseInt(getComputedStyle(presenceOverlay).zIndex, 10); assert(overlayZ > headerZ, "Security presence overlay must retain stacking priority over the sticky header"); + const narrowProvisioningFrame = await loadRouteFrame("index.html", 1200, 540); + frames.push(narrowProvisioningFrame); + const narrowProvisioningDoc = requiredFrameDocument(narrowProvisioningFrame); + const narrowRecovery = required(narrowProvisioningDoc, '[data-security-subsection="recovery-package"]'); + const narrowPassphrase = required(narrowProvisioningDoc, '[data-security-subsection="change-passphrase"]'); + const narrowRecoveryMargin = parseFloat(getComputedStyle(narrowRecovery).marginTop); + const narrowPassphraseMargin = parseFloat(getComputedStyle(narrowPassphrase).marginTop); + assert(narrowPassphraseMargin >= 40, "Narrow Change Recovery Passphrase spacing must not collapse below 40px"); + assert(narrowPassphraseMargin > narrowRecoveryMargin, "Narrow Change Recovery Passphrase spacing must remain larger than generic subsection spacing"); + assert( + narrowProvisioningDoc.documentElement.scrollWidth <= requiredFrameWindow(narrowProvisioningFrame).innerWidth, + "Narrow Change Recovery Passphrase spacing must not create horizontal overflow", + ); + const responsiveFrame = await loadRouteFrame("help.html", 360, 540); frames.push(responsiveFrame); const responsiveDoc = requiredFrameDocument(responsiveFrame);