diff --git a/assets/css/frontend/base.css b/assets/css/frontend/base.css index 6d6ef2a1..5508fd13 100644 --- a/assets/css/frontend/base.css +++ b/assets/css/frontend/base.css @@ -112,6 +112,24 @@ main.container, font-size: 12px; } +/* Keep the header multifunction search stable across route-specific CSS. + * Some routes load a later .abs-right utility, while the global input focus + * ring looks like an extra border against this transparent pill field. */ +.header-slider-search .line-form-input:focus, +.header-slider-search .line-form-input:focus-visible { + border: 0; + outline: 0; + box-shadow: none; +} + +.header-slider-search .line-form .abs-right { + position: absolute; + right: 0.7em; + top: 50%; + transform: translateY(-50%); + margin-top: 0; +} + @media (min-width: 576px) { .container, main.container { diff --git a/tests/widget-system/page-display-contract.test.cjs b/tests/widget-system/page-display-contract.test.cjs index 63ff512b..4338c825 100644 --- a/tests/widget-system/page-display-contract.test.cjs +++ b/tests/widget-system/page-display-contract.test.cjs @@ -190,6 +190,17 @@ test('footer brand icons keep the Brands font when legacy fa prefix is present', assert.match(icons, /'wechat'\s*=>\s*'fa fab fa-weixin'/) }) +test('header multifunction search keeps focus and submit alignment route-independent', () => { + assert.match( + frontendBaseCss, + /\.header-slider-search \.line-form-input:focus,[\s\S]*?\.header-slider-search \.line-form-input:focus-visible\s*\{[^}]*border:\s*0;[^}]*outline:\s*0;[^}]*box-shadow:\s*none;/, + ) + assert.match( + frontendBaseCss, + /\.header-slider-search \.line-form \.abs-right\s*\{[^}]*position:\s*absolute;[^}]*right:\s*0\.7em;[^}]*top:\s*50%;[^}]*transform:\s*translateY\(-50%\);[^}]*margin-top:\s*0;/, + ) +}) + test('save contract rejects invalid input and round-trips canonical nested values', () => { const result = spawnSync(process.env.PHP_BINARY || 'php', [path.join(__dirname, 'page-display-save-harness.php')], { cwd: root,