diff --git a/static/style.css b/static/style.css index 3577982b..81b10888 100644 --- a/static/style.css +++ b/static/style.css @@ -2728,6 +2728,7 @@ /* ── Message action buttons (copy, edit, retry) ── */ .msg-actions{display:flex;align-items:center;gap:2px;opacity:0;transition:opacity .15s;margin-left:auto;} .msg-row:hover .msg-actions{opacity:1;} +/* Keep !important so this beats equal-specificity .msg-foot-with-usage fades during measurement rerenders. */ .vscroll-measuring .msg-foot, .vscroll-measuring .msg-actions, .vscroll-measuring .msg-time{transition:none !important;} diff --git a/tests/test_issue4346_vscroll_footer_jitter.py b/tests/test_issue4346_vscroll_footer_jitter.py index 1ac34c8f..d7afca96 100644 --- a/tests/test_issue4346_vscroll_footer_jitter.py +++ b/tests/test_issue4346_vscroll_footer_jitter.py @@ -12,18 +12,14 @@ def test_css_vscroll_measuring_guard(): """style.css suppresses opacity transitions on .msg-foot and .msg-actions while .vscroll-measuring is present on the scroll container.""" assert 'vscroll-measuring' in CSS - assert re.search( - r'\.vscroll-measuring\s+\.msg-foot.*transition\s*:\s*none\s*!important', - CSS, re.DOTALL - ), "missing transition:none !important for .vscroll-measuring .msg-foot" - assert re.search( - r'\.vscroll-measuring\s+\.msg-actions.*transition\s*:\s*none\s*!important', - CSS, re.DOTALL - ), "missing transition:none !important for .vscroll-measuring .msg-actions" - assert re.search( - r'\.vscroll-measuring\s+\.msg-time.*transition\s*:\s*none\s*!important', - CSS, re.DOTALL - ), "missing transition:none !important for .vscroll-measuring .msg-time" + guard_match = re.search( + r'(?m)^\.vscroll-measuring\s+\.msg-foot,\n' + r'^\.vscroll-measuring\s+\.msg-actions,\n' + r'^\.vscroll-measuring\s+\.msg-time\{transition:none !important;\}$', + CSS, + ) + assert guard_match, \ + "missing contiguous .vscroll-measuring transition:none !important guard block" def test_js_compensate_adds_vscroll_measuring():