diff --git a/components/notification/NotificationCard.vue b/components/notification/NotificationCard.vue
index 052aab16..ed48ed4d 100644
--- a/components/notification/NotificationCard.vue
+++ b/components/notification/NotificationCard.vue
@@ -47,28 +47,8 @@ const { notification } = defineProps<{
       <!-- TODO: accept request -->
       <AccountCard :account="notification.account" />
     </template>
-    <template v-else-if="notification.type === 'favourite'">
-      <StatusCard :status="notification.status!" :faded="true">
-        <template #meta>
-          <div flex="~" gap-1 items-center mt1>
-            <div i-ri:heart-fill text-xl me-1 color-red />
-            <AccountInlineInfo text-primary font-bold :account="notification.account" me1 />
-          </div>
-        </template>
-      </StatusCard>
-    </template>
-    <template v-else-if="notification.type === 'reblog'">
-      <StatusCard :status="notification.status!" :faded="true">
-        <template #meta>
-          <div flex="~" gap-1 items-center mt1>
-            <div i-ri:repeat-fill text-xl me-1 color-green />
-            <AccountInlineInfo text-primary font-bold :account="notification.account" me1 />
-          </div>
-        </template>
-      </StatusCard>
-    </template>
     <template v-else-if="notification.type === 'update'">
-      <StatusCard :status="notification.status!" :faded="true">
+      <StatusCard :status="notification.status!" :in-notification="true" :actions="false">
         <template #meta>
           <div flex="~" gap-1 items-center mt1>
             <div i-ri:edit-2-fill text-xl me-1 text-secondary />
@@ -84,6 +64,7 @@ const { notification } = defineProps<{
       <StatusCard :status="notification.status!" />
     </template>
     <template v-else>
+      <!-- type 'favourite' and 'reblog' should always rendered by NotificationGroupedLikes -->
       <div text-red font-bold>
         [DEV] {{ $t('notification.missing_type') }} '{{ notification.type }}'
       </div>
diff --git a/components/notification/NotificationGroupedLikes.vue b/components/notification/NotificationGroupedLikes.vue
index f87c4e08..ee81c011 100644
--- a/components/notification/NotificationGroupedLikes.vue
+++ b/components/notification/NotificationGroupedLikes.vue
@@ -4,21 +4,58 @@ import type { GroupedLikeNotifications } from '~/types'
 const { group } = defineProps<{
   group: GroupedLikeNotifications
 }>()
+
+const reblogs = $computed(() => group.likes.filter(i => i.reblog))
+const likes = $computed(() => group.likes.filter(i => i.favourite && !i.reblog))
 </script>
 
 <template>
   <article flex flex-col relative>
-    <StatusCard :status="group.status!" :faded="true">
-      <template #meta>
-        <div flex flex-col gap-1 mt-1>
-          <div v-for="like of group.likes" :key="like.account.id" flex>
-            <div v-if="like.reblog" i-ri:repeat-fill text-xl me-2 color-green />
-            <div v-if="like.favourite && !like.reblog" i-ri:heart-fill text-xl me-2 color-red />
-            <AccountInlineInfo text-primary font-bold :account="like.account" me2 />
-            <div v-if="like.favourite && like.reblog" i-ri:heart-fill text-xl me-2 color-red />
+    <StatusLink :status="group.status!" pb2 pt3>
+      <div flex flex-col gap-2>
+        <div v-if="reblogs.length" flex="~ gap-1">
+          <div i-ri:repeat-fill text-xl me-1 color-green />
+          <template v-for="i, idx of reblogs" :key="idx">
+            <AccountHoverWrapper :account="i.account">
+              <NuxtLink :to="getAccountRoute(i.account)">
+                <AccountAvatar text-primary font-bold :account="i.account" class="h-1.5em w-1.5em" />
+              </NuxtLink>
+            </AccountHoverWrapper>
+          </template>
+          <div ml1>
+            {{ $t('notification.reblogged_post') }}
           </div>
         </div>
-      </template>
-    </StatusCard>
+        <div v-if="likes.length" flex="~ gap-1">
+          <div i-ri:heart-fill text-xl me-1 color-red />
+          <template v-for="i, idx of likes" :key="idx">
+            <AccountHoverWrapper :account="i.account">
+              <NuxtLink :to="getAccountRoute(i.account)">
+                <AccountAvatar text-primary font-bold :account="i.account" class="h-1.5em w-1.5em" />
+              </NuxtLink>
+            </AccountHoverWrapper>
+          </template>
+          <div ml1>
+            {{ $t('notification.favourited_post') }}
+          </div>
+        </div>
+      </div>
+      <div pl8 mt-1>
+        <StatusBody :status="group.status!" text-secondary />
+        <!-- When no text content is presented, we show media instead -->
+        <template v-if="!group.status!.content">
+          <StatusMedia
+            v-if="group.status!.mediaAttachments?.length"
+            :status="group.status!"
+            :is-preview="false"
+            pointer-events-none
+          />
+          <StatusPoll
+            v-else-if="group.status!.poll"
+            :status="group.status!"
+          />
+        </template>
+      </div>
+    </StatusLink>
   </article>
 </template>
diff --git a/components/notification/NotificationPaginator.vue b/components/notification/NotificationPaginator.vue
index ca52faf1..83a7f80e 100644
--- a/components/notification/NotificationPaginator.vue
+++ b/components/notification/NotificationPaginator.vue
@@ -75,9 +75,7 @@ function groupItems(items: mastodon.v1.Notification[]): NotificationSlot[] {
       }
       return
     }
-
-    const { status } = group[0]
-    if (status && group.length > 1 && (group[0].type === 'reblog' || group[0].type === 'favourite')) {
+    else if (group.length && group[0].status && (group[0].type === 'reblog' || group[0].type === 'favourite')) {
       // All notifications in these group are reblogs or favourites of the same status
       const likes: GroupedAccountLike[] = []
       for (const notification of group) {
@@ -96,7 +94,7 @@ function groupItems(items: mastodon.v1.Notification[]): NotificationSlot[] {
       results.push({
         id: `grouped-${id++}`,
         type: 'grouped-reblogs-and-favourites',
-        status,
+        status: group[0].status,
         likes,
       })
       return
diff --git a/components/status/StatusCard.vue b/components/status/StatusCard.vue
index 1dc0a380..424ef6be 100644
--- a/components/status/StatusCard.vue
+++ b/components/status/StatusCard.vue
@@ -7,7 +7,7 @@ const props = withDefaults(
     actions?: boolean
     context?: mastodon.v2.FilterContext
     hover?: boolean
-    faded?: boolean
+    inNotification?: boolean
     isPreview?: boolean
 
     // If we know the prev and next status in the timeline, we can simplify the card
@@ -77,19 +77,7 @@ const showReplyTo = $computed(() => !replyToMain && !directReply)
 </script>
 
 <template>
-  <div
-    :id="`status-${status.id}`"
-    ref="el"
-    relative flex="~ col gap1"
-    p="b-2 is-3 ie-4"
-    :class="{ 'hover:bg-active': hover }"
-    tabindex="0"
-    focus:outline-none focus-visible:ring="2 primary"
-    aria-roledescription="status-card"
-    :lang="status.language ?? undefined"
-    @click="onclick"
-    @keydown.enter="onclick"
-  >
+  <StatusLink :status="status" :hover="hover">
     <!-- Upper border -->
     <div :h="showUpperBorder ? '1px' : '0'" w-auto bg-border mb-1 />
 
@@ -101,7 +89,7 @@ const showReplyTo = $computed(() => !replyToMain && !directReply)
           m="is-5" p="t-1 is-5"
           :status="status"
           :is-self-reply="isSelfReply"
-          :class="faded ? 'text-secondary-light' : ''"
+          :class="inNotification ? 'text-secondary-light' : ''"
         />
         <div flex="~ col gap-1" items-center pos="absolute top-0 inset-is-0" w="77px" z--1>
           <template v-if="showReplyTo">
@@ -134,7 +122,7 @@ const showReplyTo = $computed(() => !replyToMain && !directReply)
       </div>
     </slot>
 
-    <div flex gap-3 :class="{ 'text-secondary': faded }">
+    <div flex gap-3 :class="{ 'text-secondary': inNotification }">
       <!-- Avatar -->
       <div relative>
         <div v-if="collapseRebloggedBy" absolute flex items-center justify-center top--6px px-2px py-3px rounded-full bg-base>
@@ -179,9 +167,16 @@ const showReplyTo = $computed(() => !replyToMain && !directReply)
         </div>
 
         <!-- Content -->
-        <StatusContent :status="status" :newer="newer" :context="context" :is-preview="isPreview" mb2 :class="{ 'mt-2 mb1': isDM }" />
+        <StatusContent
+          :status="status"
+          :newer="newer"
+          :context="context"
+          :is-preview="isPreview"
+          :in-notification="inNotification"
+          mb2 :class="{ 'mt-2 mb1': isDM }"
+        />
         <StatusActions v-if="actions !== false" v-show="!userSettings.zenMode" :status="status" />
       </div>
     </div>
-  </div>
+  </StatusLink>
 </template>
diff --git a/components/status/StatusContent.vue b/components/status/StatusContent.vue
index 7dc937c6..d6efd353 100644
--- a/components/status/StatusContent.vue
+++ b/components/status/StatusContent.vue
@@ -6,6 +6,7 @@ const { status, context } = defineProps<{
   newer?: mastodon.v1.Status
   context?: mastodon.v2.FilterContext | 'details'
   isPreview?: boolean
+  inNotification?: boolean
 }>()
 
 const isDM = $computed(() => status.visibility === 'direct')
diff --git a/components/status/StatusLink.vue b/components/status/StatusLink.vue
new file mode 100644
index 00000000..613042e5
--- /dev/null
+++ b/components/status/StatusLink.vue
@@ -0,0 +1,48 @@
+<script setup lang="ts">
+import type { mastodon } from 'masto'
+
+const props = defineProps<{
+  status: mastodon.v1.Status
+  hover?: boolean
+}>()
+
+const el = ref<HTMLElement>()
+const router = useRouter()
+const statusRoute = $computed(() => getStatusRoute(props.status))
+
+function onclick(evt: MouseEvent | KeyboardEvent) {
+  const path = evt.composedPath() as HTMLElement[]
+  const el = path.find(el => ['A', 'BUTTON', 'IMG', 'VIDEO'].includes(el.tagName?.toUpperCase()))
+  const text = window.getSelection()?.toString()
+  if (!el && !text)
+    go(evt)
+}
+
+function go(evt: MouseEvent | KeyboardEvent) {
+  if (evt.metaKey || evt.ctrlKey) {
+    window.open(statusRoute.href)
+  }
+  else {
+    cacheStatus(props.status)
+    router.push(statusRoute)
+  }
+}
+</script>
+
+<template>
+  <div
+    :id="`status-${status.id}`"
+    ref="el"
+    relative flex="~ col gap1"
+    p="b-2 is-3 ie-4"
+    :class="{ 'hover:bg-active': hover }"
+    tabindex="0"
+    focus:outline-none focus-visible:ring="2 primary"
+    aria-roledescription="status-card"
+    :lang="status.language ?? undefined"
+    @click="onclick"
+    @keydown.enter="onclick"
+  >
+    <slot />
+  </div>
+</template>