diff --git a/client/src/mobile/mobile.css b/client/src/mobile/mobile.css
index 0b89257e1..2d9c7a191 100644
--- a/client/src/mobile/mobile.css
+++ b/client/src/mobile/mobile.css
@@ -123,9 +123,11 @@ html[dir='rtl']:has(.m-shell[data-size='wide'], .m-shell[data-size='split']) .m-
/* ── Keyframes ──────────────────────────────────────────────────────────── */
-/* The floating card pops in place, the way a native alert does. */
+/* The floating card pops in place, the way a native alert does. It is opaque
+ halfway through the pop, so the page behind never reads through its fields. */
@keyframes m-sheet-in {
from { opacity: 0; transform: translateY(10px) scale(.96); }
+ 45% { opacity: 1; }
to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes m-sheet-out {
diff --git a/client/tests/unit/mobile/MSheet.test.tsx b/client/tests/unit/mobile/MSheet.test.tsx
index dacbc2fe3..2eece0357 100644
--- a/client/tests/unit/mobile/MSheet.test.tsx
+++ b/client/tests/unit/mobile/MSheet.test.tsx
@@ -538,11 +538,35 @@ describe('MSheet', () => {
body
,
);
- const scrim = panel().closest('[role="presentation"]') as HTMLElement;
+ const root = panel().closest('[role="presentation"]') as HTMLElement;
+ const scrim = root.querySelector('[data-m-scrim]') as HTMLElement;
expect(scrim.className).toContain('bg-transparent');
expect(scrim.className).toContain('short:bg-[color:var(--m-dim)]');
});
+ it('FE-MOB-SHEET-036: the dim fades beside the sheet, never around it, so the opaque sheet is never see-through', () => {
+ const { rerender } = render(
+
{}} ariaLabel="Sheet">
+ body
+ ,
+ );
+ const root = panel().closest('[role="presentation"]') as HTMLElement;
+ const scrim = root.querySelector('[data-m-scrim]') as HTMLElement;
+ expect(scrim.className).toContain('m-fade-in');
+ expect(scrim.className).toContain('pointer-events-none');
+ expect(scrim.contains(panel())).toBe(false);
+ // No ancestor of the sheet animates its opacity.
+ for (let el: HTMLElement | null = panel().parentElement; el; el = el.parentElement) {
+ expect(el.className || '').not.toMatch(/\bm-fade-(in|out)\b/);
+ }
+ rerender(
+
{}} ariaLabel="Sheet">
+ body
+ ,
+ );
+ expect(scrim.className).toContain('m-fade-out');
+ });
+
it('FE-MOB-SHEET-035: the region lets taps through to the scrim, the sheet itself takes them', () => {
render(
{}} ariaLabel="Sheet">