diff --git a/server/templates/my_cases.html b/server/templates/my_cases.html
index e802224..2c999fe 100644
--- a/server/templates/my_cases.html
+++ b/server/templates/my_cases.html
@@ -160,6 +160,38 @@ try {
});
})();
+// Preserve scroll position across POST-redirects (close, reopen,
+// bulk-*). Browsers keep scroll on location.reload() but NOT on a
+// redirect-driven navigation, even when the target URL matches the
+// referer. Without this, clicking close on row 30 of a long list
+// dumps the user back at scrollY=0 with the action-row off-screen.
+//
+// Mechanism: capture scrollY in sessionStorage before every form
+// submit on this page, restore it on the very next load, then delete.
+// Using the classic two-arg scrollTo(0, y) form — the options-object
+// variant is silently ignored in some older browsers.
+(() => {
+ const STASH = 'doctate:scrollY';
+ try {
+ document.querySelectorAll('form').forEach((f) => {
+ f.addEventListener('submit', () => {
+ sessionStorage.setItem(STASH, String(window.scrollY));
+ });
+ });
+ const stashed = sessionStorage.getItem(STASH);
+ if (stashed !== null) {
+ sessionStorage.removeItem(STASH);
+ const y = parseInt(stashed, 10);
+ if (!isNaN(y)) {
+ window.scrollTo(0, y);
+ }
+ }
+ } catch (_) {
+ // sessionStorage may be blocked (strict privacy mode) — silent fail,
+ // scroll returns to 0 like it did before this feature.
+ }
+})();
+
// Live-update bus: any case event for this user triggers a debounced
// page reload. Debounce collapses event bursts (e.g. bulk-delete) into
// one reload. EventSource auto-reconnects on network drops.