diff --git a/package-lock.json b/package-lock.json
index 975b0ed9..63db590f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,6 +13,7 @@
         "fast-blurhash": "~1.1.2",
         "history": "~5.3.0",
         "iconify-icon": "~1.0.2",
+        "just-debounce-it": "^3.2.0",
         "masto": "~4.10.1",
         "mem": "~9.0.2",
         "preact": "~10.11.3",
@@ -4046,6 +4047,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/just-debounce-it": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/just-debounce-it/-/just-debounce-it-3.2.0.tgz",
+      "integrity": "sha512-WXzwLL0745uNuedrCsCs3rpmfD6DBaf7uuVwaq98/8dafURfgQaBsSpjiPp5+CW6Vjltwy9cOGI6qE71b3T8iQ=="
+    },
     "node_modules/kolorist": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.6.0.tgz",
@@ -8562,6 +8568,11 @@
       "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
       "dev": true
     },
+    "just-debounce-it": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/just-debounce-it/-/just-debounce-it-3.2.0.tgz",
+      "integrity": "sha512-WXzwLL0745uNuedrCsCs3rpmfD6DBaf7uuVwaq98/8dafURfgQaBsSpjiPp5+CW6Vjltwy9cOGI6qE71b3T8iQ=="
+    },
     "kolorist": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.6.0.tgz",
diff --git a/package.json b/package.json
index f0d1bb19..191757ff 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
     "fast-blurhash": "~1.1.2",
     "history": "~5.3.0",
     "iconify-icon": "~1.0.2",
+    "just-debounce-it": "^3.2.0",
     "masto": "~4.10.1",
     "mem": "~9.0.2",
     "preact": "~10.11.3",
diff --git a/src/app.css b/src/app.css
index 4e7cd710..bb889de9 100644
--- a/src/app.css
+++ b/src/app.css
@@ -137,6 +137,7 @@ a.mention span {
     transparent
   );
   background-repeat: no-repeat;
+  transition: opacity 0.3s ease-in-out;
 }
 .timeline.contextual > li:first-child {
   background-position: 0 16px;
@@ -274,13 +275,13 @@ a.mention span {
   left: calc(50px + 16px + 16px);
 }
 .timeline.contextual.loading > li:not(.hero) {
-  opacity: 0.2;
+  opacity: 0.5;
   pointer-events: none;
-  background-image: none !important;
+  /* background-image: none !important; */
 }
-.timeline.contextual.loading > li:not(.hero):before {
+/* .timeline.contextual.loading > li:not(.hero):before {
   content: none !important;
-}
+} */
 
 .timeline-deck.compact .status {
   max-height: max(25vh, 160px);
diff --git a/src/pages/status.jsx b/src/pages/status.jsx
index 71026c19..7d6f4dd8 100644
--- a/src/pages/status.jsx
+++ b/src/pages/status.jsx
@@ -1,3 +1,4 @@
+import debounce from 'just-debounce-it';
 import { Link } from 'preact-router/match';
 import {
   useEffect,
@@ -18,117 +19,163 @@ import useTitle from '../utils/useTitle';
 
 function StatusPage({ id }) {
   const snapStates = useSnapshot(states);
-  const cachedStatuses = store.session.getJSON('statuses-' + id);
-  const [statuses, setStatuses] = useState(cachedStatuses || [{ id }]);
+  const [statuses, setStatuses] = useState([]);
   const [uiState, setUIState] = useState('default');
+  const userInitiated = useRef(true); // Initial open is user-initiated
   const heroStatusRef = useRef();
 
+  const scrollableRef = useRef();
   useEffect(() => {
+    const onScroll = debounce(() => {
+      // console.log('onScroll');
+      const { scrollTop } = scrollableRef.current;
+      states.scrollPositions.set(id, scrollTop);
+    }, 100);
+    scrollableRef.current.addEventListener('scroll', onScroll, {
+      passive: true,
+    });
+    onScroll();
+    return () => {
+      scrollableRef.current?.removeEventListener('scroll', onScroll);
+    };
+  }, [id]);
+
+  useEffect(() => {
+    setUIState('loading');
+
     const containsStatus = statuses.find((s) => s.id === id);
     if (!containsStatus) {
+      // Case 1: On first load, or when navigating to a status that's not cached at all
       setStatuses([{ id }]);
     } else {
       const cachedStatuses = store.session.getJSON('statuses-' + id);
       if (cachedStatuses) {
-        setStatuses(cachedStatuses);
+        // Case 2: Looks like we've cached this status before, let's restore them to make it snappy
+        const reallyCachedStatuses = cachedStatuses.filter(
+          (s) => snapStates.statuses.has(s.id),
+          // Some are not cached in the global state, so we need to filter them out
+        );
+        setStatuses(reallyCachedStatuses);
+      } else {
+        // Case 3: Unknown state, could be a sub-comment. Let's slice off all descendant statuses after the hero status to be safe because they are custom-rendered with sub-comments etc
+        const heroIndex = statuses.findIndex((s) => s.id === id);
+        const slicedStatuses = statuses.slice(0, heroIndex + 1);
+        setStatuses(slicedStatuses);
       }
     }
-  }, [id]);
 
-  useEffect(async () => {
-    setUIState('loading');
-
-    const hasStatus = snapStates.statuses.has(id);
-    let heroStatus = snapStates.statuses.get(id);
-    try {
-      heroStatus = await masto.statuses.fetch(id);
-      states.statuses.set(id, heroStatus);
-    } catch (e) {
-      // Silent fail if status is cached
-      if (!hasStatus) {
-        setUIState('error');
-        alert('Error fetching status');
-      }
-      return;
-    }
-
-    try {
-      const context = await masto.statuses.fetchContext(id);
-      const { ancestors, descendants } = context;
-
-      ancestors.forEach((status) => {
-        states.statuses.set(status.id, status);
-      });
-      const nestedDescendants = [];
-      descendants.forEach((status) => {
-        states.statuses.set(status.id, status);
-        if (status.inReplyToAccountId === status.account.id) {
-          // If replying to self, it's part of the thread, level 1
-          nestedDescendants.push(status);
-        } else if (status.inReplyToId === heroStatus.id) {
-          // If replying to the hero status, it's a reply, level 1
-          nestedDescendants.push(status);
-        } else {
-          // If replying to someone else, it's a reply to a reply, level 2
-          const parent = descendants.find((s) => s.id === status.inReplyToId);
-          if (parent) {
-            if (!parent.__replies) {
-              parent.__replies = [];
-            }
-            parent.__replies.push(status);
-          } else {
-            // If no parent, it's probably a reply to a reply to a reply, level 3
-            console.warn('[LEVEL 3] No parent found for', status);
-          }
+    (async () => {
+      const hasStatus = snapStates.statuses.has(id);
+      let heroStatus = snapStates.statuses.get(id);
+      try {
+        heroStatus = await masto.statuses.fetch(id);
+        states.statuses.set(id, heroStatus);
+      } catch (e) {
+        // Silent fail if status is cached
+        if (!hasStatus) {
+          setUIState('error');
+          alert('Error fetching status');
         }
-      });
+        return;
+      }
 
-      console.log({ ancestors, descendants, nestedDescendants });
+      try {
+        const context = await masto.statuses.fetchContext(id);
+        const { ancestors, descendants } = context;
 
-      const allStatuses = [
-        ...ancestors.map((s) => ({
-          id: s.id,
-          ancestor: true,
-          accountID: s.account.id,
-        })),
-        { id, accountID: heroStatus.account.id },
-        ...nestedDescendants.map((s) => ({
-          id: s.id,
-          accountID: s.account.id,
-          descendant: true,
-          thread: s.account.id === heroStatus.account.id,
-          replies: s.__replies?.map((r) => r.id),
-        })),
-      ];
-      console.log({ allStatuses });
-      setStatuses(allStatuses);
-      store.session.setJSON('statuses-' + id, allStatuses);
-    } catch (e) {
-      console.error(e);
-      setUIState('error');
-    }
+        ancestors.forEach((status) => {
+          states.statuses.set(status.id, status);
+        });
+        const nestedDescendants = [];
+        descendants.forEach((status) => {
+          states.statuses.set(status.id, status);
+          if (status.inReplyToAccountId === status.account.id) {
+            // If replying to self, it's part of the thread, level 1
+            nestedDescendants.push(status);
+          } else if (status.inReplyToId === heroStatus.id) {
+            // If replying to the hero status, it's a reply, level 1
+            nestedDescendants.push(status);
+          } else {
+            // If replying to someone else, it's a reply to a reply, level 2
+            const parent = descendants.find((s) => s.id === status.inReplyToId);
+            if (parent) {
+              if (!parent.__replies) {
+                parent.__replies = [];
+              }
+              parent.__replies.push(status);
+            } else {
+              // If no parent, it's probably a reply to a reply to a reply, level 3
+              console.warn('[LEVEL 3] No parent found for', status);
+            }
+          }
+        });
 
-    setUIState('default');
+        console.log({ ancestors, descendants, nestedDescendants });
+
+        const allStatuses = [
+          ...ancestors.map((s) => ({
+            id: s.id,
+            ancestor: true,
+            accountID: s.account.id,
+          })),
+          { id, accountID: heroStatus.account.id },
+          ...nestedDescendants.map((s) => ({
+            id: s.id,
+            accountID: s.account.id,
+            descendant: true,
+            thread: s.account.id === heroStatus.account.id,
+            replies: s.__replies?.map((r) => r.id),
+          })),
+        ];
+
+        setUIState('default');
+        console.log({ allStatuses });
+        setStatuses(allStatuses);
+        store.session.setJSON('statuses-' + id, allStatuses);
+      } catch (e) {
+        console.error(e);
+        setUIState('error');
+      }
+    })();
   }, [id, snapStates.reloadStatusPage]);
 
   useLayoutEffect(() => {
-    if (heroStatusRef.current && statuses.length > 1) {
-      heroStatusRef.current.scrollIntoView({
-        behavior: 'smooth',
-        block: 'start',
-      });
+    if (!statuses.length) return;
+    const isLoading = uiState === 'loading';
+    if (userInitiated.current) {
+      const hasAncestors = statuses.findIndex((s) => s.id === id) > 0; // Cannot use `ancestor` key because the hero state is dynamic
+      if (!isLoading && hasAncestors) {
+        // Case 1: User initiated, has ancestors, after statuses are loaded, SNAP to hero status
+        console.log('Case 1');
+        heroStatusRef.current?.scrollIntoView();
+      } else if (isLoading && statuses.length > 1) {
+        // Case 2: User initiated, while statuses are loading, SMOOTH-SCROLL to hero status
+        console.log('Case 2');
+        heroStatusRef.current?.scrollIntoView({
+          behavior: 'smooth',
+          block: 'start',
+        });
+      }
+    } else {
+      const scrollPosition = states.scrollPositions.get(id);
+      if (scrollPosition && scrollableRef.current) {
+        // Case 3: Not user initiated (e.g. back/forward button), restore to saved scroll position
+        console.log('Case 3');
+        scrollableRef.current.scrollTop = scrollPosition;
+      }
     }
-  }, [id]);
+    console.log('No case', {
+      isLoading,
+      userInitiated: userInitiated.current,
+      statusesLength: statuses.length,
+      // scrollPosition,
+    });
 
-  useLayoutEffect(() => {
-    const hasAncestor = statuses.some((s) => s.ancestor);
-    if (hasAncestor) {
-      heroStatusRef.current?.scrollIntoView({
-        // behavior: 'smooth',
-        block: 'start',
-      });
+    if (!isLoading) {
+      // Reset user initiated flag after statuses are loaded
+      userInitiated.current = false;
     }
-  }, [statuses]);
+  }, [statuses, uiState]);
 
   const heroStatus = snapStates.statuses.get(id);
   const heroDisplayName = useMemo(() => {
@@ -175,11 +222,13 @@ function StatusPage({ id }) {
   }, [statuses.length, limit]);
 
   const hasManyStatuses = statuses.length > 40;
+  const hasDescendants = statuses.some((s) => s.descendant);
 
   return (
     <div class="deck-backdrop">
       <Link href={closeLink}></Link>
       <div
+        ref={scrollableRef}
         class={`status-deck deck contained ${
           statuses.length > 1 ? 'padded-bottom' : ''
         }`}
@@ -228,6 +277,9 @@ function StatusPage({ id }) {
                 status-link
               "
                     href={`#/s/${statusID}`}
+                    onClick={() => {
+                      userInitiated.current = true;
+                    }}
                   >
                     <Status
                       statusID={statusID}
@@ -247,7 +299,13 @@ function StatusPage({ id }) {
                     <ul>
                       {replies.map((replyID) => (
                         <li key={replyID}>
-                          <Link class="status-link" href={`#/s/${replyID}`}>
+                          <Link
+                            class="status-link"
+                            href={`#/s/${replyID}`}
+                            onClick={() => {
+                              userInitiated.current = true;
+                            }}
+                          >
                             <Status statusID={replyID} withinContext size="s" />
                           </Link>
                         </li>
@@ -258,7 +316,7 @@ function StatusPage({ id }) {
                 {uiState === 'loading' &&
                   isHero &&
                   !!heroStatus?.repliesCount &&
-                  statuses.length === 1 && (
+                  !hasDescendants && (
                     <div class="status-loading">
                       <Loader />
                     </div>
diff --git a/src/utils/states.js b/src/utils/states.js
index 613e52ba..cc3f6b3a 100644
--- a/src/utils/states.js
+++ b/src/utils/states.js
@@ -13,6 +13,7 @@ export default proxy({
   accounts: new Map(),
   reloadStatusPage: 0,
   spoilers: proxyMap([]),
+  scrollPositions: new Map(),
   // Modals
   showCompose: false,
   showSettings: false,