diff --git a/.vscode/settings.json b/.vscode/settings.json
index ca64273..e369383 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -32,6 +32,5 @@
   },
   "prettier.requireConfig": true,
   "prettier.configPath": ".prettierrc.mjs",
-  "editor.defaultFormatter": "esbenp.prettier-vscode",
   "editor.formatOnSave": true
 }
diff --git a/src/components/AgeRestrictedModal.astro b/src/components/AgeRestrictedModal.astro
index 19940a5..1d7392d 100644
--- a/src/components/AgeRestrictedModal.astro
+++ b/src/components/AgeRestrictedModal.astro
@@ -57,8 +57,8 @@ import { IconTriangleExclamation } from "./icons";
 <script>
   const ageRestrictedModalSetup = () => {
     const modal = document.querySelector<HTMLElementTagNameMap["div"]>("div#modal-age-restricted");
-    // Not an age-restricted page
     if (!modal) {
+      // Not an age-restricted page
       return;
     }
     if (modal !== document.querySelector("body>div#modal-age-restricted")) {
diff --git a/src/components/ExternalPosts.astro b/src/components/ExternalPosts.astro
new file mode 100644
index 0000000..bbbe1db
--- /dev/null
+++ b/src/components/ExternalPosts.astro
@@ -0,0 +1,100 @@
+---
+import type { Posts } from "../content/config";
+import { t, type Lang } from "../i18n";
+import { IconEkasPortal, IconFurAffinity, IconInkbunny, IconSoFurry, IconWeasyl } from "./icons/brands";
+
+type Props = {
+  lang: Lang;
+  posts?: Posts;
+};
+
+const { lang, posts } = Astro.props;
+const { eka, furaffinity, inkbunny, sofurry, weasyl } = posts ?? {};
+const isVisible = eka || furaffinity || inkbunny || sofurry || weasyl;
+---
+
+{
+  isVisible ? (
+    <section id="external-posts-section" class="my-5 px-2 font-serif" aria-describedby="title-external-posts">
+      <>
+        <h2 id="title-external-posts" class="py-2 font-serif text-xl font-semibold text-stone-800 dark:text-stone-100">
+          {t(lang, "published_content/syndication_see_also_on")}
+        </h2>
+        <ul id="external-posts" class="flex flex-wrap justify-around">
+          {eka ? (
+            <li class="min-w-12 grow">
+              <a
+                class="u-syndication text-link w-full"
+                href={eka.link}
+                target="_blank"
+                aria-label={t(lang, "published_content/syndication_eka")}
+              >
+                <IconEkasPortal class="mx-auto" width="2rem" height="2rem" />
+              </a>
+            </li>
+          ) : null}
+          {furaffinity ? (
+            <li class="min-w-12 grow">
+              <a
+                class="u-syndication text-link w-full"
+                href={furaffinity.link}
+                target="_blank"
+                aria-label={t(lang, "published_content/syndication_furaffinity")}
+              >
+                <IconFurAffinity class="mx-auto" width="2rem" height="2rem" />
+              </a>
+            </li>
+          ) : null}
+          {inkbunny ? (
+            <li class="min-w-12 grow">
+              <a
+                class="u-syndication text-link w-full"
+                href={inkbunny.link}
+                target="_blank"
+                aria-label={t(lang, "published_content/syndication_inkbunny")}
+              >
+                <IconInkbunny class="mx-auto" width="2rem" height="2rem" />
+              </a>
+            </li>
+          ) : null}
+          {sofurry ? (
+            <li class="min-w-12 grow">
+              <a
+                class="u-syndication text-link w-full"
+                href={sofurry.link}
+                target="_blank"
+                aria-label={t(lang, "published_content/syndication_sofurry")}
+              >
+                <IconSoFurry class="mx-auto" width="2rem" height="2rem" />
+              </a>
+            </li>
+          ) : null}
+          {weasyl ? (
+            <li class="min-w-12 grow">
+              <a
+                class="u-syndication text-link w-full"
+                href={weasyl.link}
+                target="_blank"
+                aria-label={t(lang, "published_content/syndication_weasyl")}
+              >
+                <IconWeasyl class="mx-auto" width="2rem" height="2rem" />
+              </a>
+            </li>
+          ) : null}
+        </ul>
+      </>
+    </section>
+  ) : null
+}
+
+<script>
+  import tippy from "tippy.js";
+  import "tippy.js/dist/tippy.css";
+
+  const clipboardItems = document.querySelectorAll<HTMLElement>("ul#external-posts a[aria-label]");
+
+  tippy(clipboardItems, {
+    content: (el) => (el as HTMLElement).getAttribute("aria-label")!,
+    theme: "bm",
+  });
+</script>
diff --git a/src/components/MastodonComments.astro b/src/components/MastodonComments.astro
index 01d610e..7203230 100644
--- a/src/components/MastodonComments.astro
+++ b/src/components/MastodonComments.astro
@@ -8,9 +8,10 @@ type Props = {
   instance: string;
   user: string;
   postId: string;
+  blacklistedComments?: string[];
 };
 
-const { link, instance, user, postId } = Astro.props;
+const { link, instance, user, postId, blacklistedComments } = Astro.props;
 ---
 
 <section
@@ -21,6 +22,7 @@ const { link, instance, user, postId } = Astro.props;
   data-instance={instance}
   data-user={user}
   data-post-id={postId}
+  data-blacklisted={(blacklistedComments ?? []).join(",")}
 >
   <h2 id="title-comments-section" class="py-2 font-serif text-xl font-semibold text-stone-800 dark:text-stone-100">
     Comments
@@ -45,7 +47,7 @@ const { link, instance, user, postId } = Astro.props;
     class="group mx-auto w-64 rounded-lg bg-bm-300 px-4 py-1 text-stone-800 disabled:bg-bm-400 dark:bg-green-800 dark:text-stone-100 dark:disabled:bg-green-900"
     id="load-comments-button"
   >
-    <span class="block underline group-disabled:hidden">Click to load comments</span>
+    <span class="block hover:underline group-focus:underline group-disabled:hidden">Click to load comments</span>
     <span class="hidden group-disabled:block">
       <svg
         style={{ width: "1.25rem", height: "1.25rem", display: "inline" }}
@@ -144,6 +146,7 @@ const { link, instance, user, postId } = Astro.props;
     reblogs_count: number;
     created_at: string;
     edited_at: string | null;
+    language: string | null;
     account: {
       username: string;
       acct: string;
@@ -162,7 +165,7 @@ const { link, instance, user, postId } = Astro.props;
     descendants: Status[];
   }
 
-  async function renderComments(section: Element, post: MastodonPost) {
+  async function renderComments(section: Element, post: MastodonPost, blacklistedComments: Set<string>) {
     const commentsDescription = section.querySelector<HTMLElementTagNameMap["p"]>("p#comments-description")!;
     const loadCommentsButton = section.querySelector<HTMLElementTagNameMap["button"]>("button#load-comments-button")!;
     try {
@@ -198,6 +201,13 @@ const { link, instance, user, postId } = Astro.props;
       )!;
 
       data.descendants.forEach((comment) => {
+        if (blacklistedComments.has(comment.id)) {
+          return;
+        }
+        if (blacklistedComments.has(comment.in_reply_to_id)) {
+          blacklistedComments.add(comment.id);
+          return;
+        }
         const commentBox = commentTemplate.content.cloneNode(true) as DocumentFragment;
         commentBox.firstElementChild!.id = `comment-${comment.id}`;
 
@@ -303,6 +313,8 @@ const { link, instance, user, postId } = Astro.props;
     if (!post.link || !post.instance || !post.user || !post.postId) {
       return;
     }
+    const blacklisted = commentSection.dataset.blacklisted;
+    const blacklistedComments = new Set(blacklisted ? blacklisted.split(",") : undefined);
     const loadCommentsButton =
       commentSection.querySelector<HTMLElementTagNameMap["button"]>("button#load-comments-button")!;
     loadCommentsButton.addEventListener(
@@ -310,7 +322,7 @@ const { link, instance, user, postId } = Astro.props;
       (e) => {
         e.preventDefault();
         loadCommentsButton.disabled = true;
-        renderComments(commentSection, post as MastodonPost);
+        renderComments(commentSection, post as MastodonPost, blacklistedComments);
       },
       { once: true },
     );
diff --git a/src/components/icons/brands/IconEkasPortal.astro b/src/components/icons/brands/IconEkasPortal.astro
new file mode 100644
index 0000000..dfd61aa
--- /dev/null
+++ b/src/components/icons/brands/IconEkasPortal.astro
@@ -0,0 +1,15 @@
+---
+import SVGIcon from "../SVGIcon.astro";
+
+type Props = {
+  width: string;
+  height: string;
+  class?: string;
+};
+---
+
+<SVGIcon {...Astro.props} viewBox="0 0 64 64">
+  <path
+    d="m 32.722,49.22 c 0.042,-0.098 2.462,-0.072 2.586,0.1 0.123,0.172 0.198,0.56 0.198,0.685 0,0.126 -2.513,0.126 -2.54,0.033 -0.028,-0.092 -0.286,-0.719 -0.244,-0.817 z M 23.158,-0.01 c -0.203,0.019 -0.403,0.076 -0.719,0.172 -0.63,0.193 -0.958,0.608 -1.978,1.508 -1.018,0.9 -2.66,2.249 -4.145,3.838 -1.484,1.59 -3.344,3.707 -4.646,5.762 -1.302,2.05 -2.003,3.729 -3.13,6.464 -1.129,2.738 -2.484,7.326 -3.435,10 -0.95,2.676 -1.352,3.194 -2.224,6.065 -0.874,2.87 -2.343,7.677 -2.73,11.213 -0.386,3.536 0.079,9.002 0.2,9.799 0.123,0.795 0.482,1.68 0.813,2.021 0.33,0.34 1.161,1.156 2.727,0.705 1.566,-0.452 5.828,-5.378 6.754,-7.047 0.596,-1.144 1.298,-1.828 1.888,-3.082 0.484,-1.031 0.845,-2.591 1.397,-3.857 0.419,-1.03 0.46,-2.239 0.502,-3.047 0.043,-0.81 0.518,-7.403 1.175,-10.445 0.527,-1.76 1.888,-5.43 2.668,-7.688 0.781,-2.258 1.467,-4.44 2.018,-5.863 0.552,-1.423 1.13,-2.204 1.451,-2.336 0.322,-0.131 0.628,0.218 0.748,0.371 0.12,0.154 3.473,4.336 3.574,4.576 0.101,0.24 -0.237,0.798 -0.687,1.166 -0.451,0.368 -2.8,1.888 -3.604,3.004 -0.803,1.117 -0.343,0.874 -1.212,2.932 -0.869,2.056 -3.428,6.613 -4.043,9.396 -0.617,2.783 -0.12,5.404 -0.22,6.08 -0.099,0.677 -0.143,0.837 -0.342,2.12 -0.198,1.284 0.222,2.497 0.528,2.562 0.306,0.065 0.491,-0.997 0.87,-1.854 0.377,-0.856 1.012,-1.722 2.37,-1.246 0.983,0.606 0.648,3.765 0.9,4.68 0.253,0.915 0.3,1.356 0.54,1.396 0.24,0.04 0.436,-0.705 0.644,-1.373 0.208,-0.669 0.476,-1.451 0.823,-1.302 0.347,0.15 2.135,1.568 2.32,2.273 0.185,0.705 0.198,1.93 0.453,1.986 0.255,0.057 0.74,-1.437 0.936,-1.929 0.195,-0.491 0.91,-0.752 1.32,-0.93 0.41,-0.178 0.258,0.903 0.884,1.283 0.347,0.21 0.989,0.887 1.268,1.516 0.225,0.505 0.328,1.269 0.48,1.268 0,0 0.569,-0.939 0.97,-1.006 0.4,-0.066 1.465,1.225 1.928,1.453 0.462,0.227 1.375,0.537 1.564,0.707 0.187,0.168 0.61,0.585 0.53,0.765 -0.08,0.182 -0.50439,0.457755 -1.109395,0.785821 -0.605005,0.328067 -2.284966,1.008178 -2.86944,1.215165 -0.584474,0.206987 -4.103324,0.255544 -4.632324,0.970545 -0.53,0.715 -0.679281,2.172808 -0.638962,3.232839 0.06552,1.722607 -0.810214,0.955141 -0.854138,2.642662 -0.01625,0.624199 0.218914,1.090968 0.53865,1.090968 H 48.242 c 1.3,0 0.105,-4.107 -0.398,-5.305 -0.503,-1.196 -1.129,-1.485 -1.42,-1.992 -0.29,-0.508 -0.395,-1.203 -0.44,-1.797 -0.043,-0.594 0.026,-2.27 0.153,-2.982 0.125,-0.71 0.854,-1.613 1.847,-1.598 0.994,0.016 0.857,2.607 1.17,4.48 0.315,1.873 1.53,9.194 2.041,9.194 H 61.287 C 62.994,62.364 63.734,59.92 64,57.134 V 40.514 C 64,35.88 63.802,32.961 63.266,29.344 62.729,25.728 61.173,21.781 60.336,18.836 59.499,15.889 58.816,13.904 58.26,11.662 57.703,9.42 57.525,6.792 56.957,5.406 56.388,4.022 56.107,3.296 55.201,2.75 54.294,2.203 53.178,2.006 52.127,1.979 c -1.05,-0.028 -2.507,-0.01 -3.482,0.5 -0.975,0.51 -1.265,0.915 -2.02,2.423 -0.755,1.507 -1.263,4.86 -1.615,6.768 -0.353,1.91 -0.066,3.887 -0.61,4.648 -0.544,0.762 -1.71,0.582 -2.02,0.202 -0.448622,-0.557624 -1.127331,-0.879854 -1.843,-0.875 -0.928,0.003 -1.364,0.975 -2.2,1.38 -0.834,0.406 -1.685,0.854 -2.32,0.608 -0.633,-0.247 -0.44,-0.884 -1.18,-0.973 -0.739,-0.089 -1.382,0.309 -1.636,0.62 -0.254,0.31 -0.533,1.417 -1.123,1.241 -0.59,-0.176 -0.441,-0.564 -1.244,-0.73 -0.803,-0.165 -0.726,-0.063 -1.18,0.146 -0.451,0.208 -0.313,0.356 -0.71,-0.103 -0.399,-0.46 0.023,-2.56 0,-2.928 C 28.921,14.538 26.157,8.226 25.831,7.72 25.506,7.215 25.821,4.786 25.787,4.096 25.753,3.406 25.825,2.722 25.611,1.871 25.397,1.021 24.55,0.18 23.895,0.055 23.567,-0.007 23.361,-0.028 23.158,-0.01 Z m 0.156,1.59 c 0.06593,0.00211 0.130958,0.015991 0.192,0.041 0.48,0.202 0.604,0.403 0.664,0.77 h 0.002 c 0.06,0.366 0.136,2.318 -0.092,2.796 -0.228,0.478 -3.453,7.08 -3.596,7.26 -0.142,0.18 -1.721,3.26 -2.328,4.75 -1.327,3.85 -3.615,10.209 -3.985,11.438 -0.712,1.976 -1.032,5.902 -1.56,9.821 -0.235,1.724 -0.186,2.824 -0.463,3.862 -0.275,1.037 -0.286,1.909 -1.056,2.075 C 10.32,44.558 9.985,44.113 9.494,42.586 9.004,41.059 9.338,37.743 9.396,36.196 9.454,34.649 9.583,34.356 9.162,33.773 8.741,33.19 8.092,32.853 7.291,32.713 6.489,32.571 5.674,32.865 5.337,32.442 5,32.02 7.532,25.457 8.589,22.742 c 1.057,-2.717 1.444,-4.706 2.337,-6.586 0.892,-1.88 1.862,-3.462 2.785,-4.857 0.924,-1.396 1.43,-2.05 2.644,-3.537 1.216,-1.488 3.57,-3.961 3.866,-4.24 0.295,-0.281 1.278,-1.199 1.656,-1.362 0.33,-0.141 0.964,-0.602 1.437,-0.58 z M 51.03,3.416 c 0.92,-0.067 1.922,0.128 2.62,0.455 0.929,0.436 1.357,1.794 1.652,2.678 0.295,0.885 1.088,5.282 1.511,6.69 0.423,1.407 1.193,4.054 1.57,5.503 0.379,1.45 0.823,3.322 1.112,4.528 0.288,1.204 1.337,4.106 1.819,7.324 0.032,0.7 0.111,1.025 0.11,1.308 -0.18,0.158 -3.777,1.153 -5.058,2.084 -1.28,0.931 -2.227,4.276 -2.474,6.164 -0.247,1.888 -0.184,2.448 -0.557,3.688 -0.371,1.24 -1.036,2.766 -1.695,3.664 -0.659,0.898 -2.552,1.268 -2.613,0.886 -0.062,-0.382 -0.573,-4.447 -0.694,-5.199 -0.121,-0.752 -1.774,-27.056 -1.914,-27.666 -0.14,-0.61 0.216,-5.148 0.613,-6.835 0.397,-1.69 0.277,-2.33 0.895,-3.202 0.617,-0.871 1.134,-1.564 2.226,-1.91 0.273,-0.086 0.571,-0.137 0.877,-0.16 z M 30.2,24.189 c 1.282,0.02 1.777,2.14 2.475,2.778 0.697,0.637 0.899,1.099 1.566,1.16 0.669,0.063 1.463,-0.908 1.867,-0.908 0.406,0 2.977,-0.883 3.293,-1.121 0.318,-0.24 0.773,-0.75 1.41,-0.846 0.637,-0.097 0.705,0.805 0.907,1.26 0.203,0.454 0.505,2.694 0.758,3.94 0.252,1.244 1.168,2.519 0.79,3.132 -0.379,0.612 -3.429,0.741 -4.005,0.684 -0.576,-0.06 -0.745,0.45 -0.557,0.894 0.189,0.444 4.26,-0.322 4.822,0.106 0.563,0.428 0.567,0.922 0.559,1.236 -0.008,0.314 -0.003,0.934 -0.137,1.113 -0.134,0.18 -0.71,0.004 -1.377,-0.174 -0.667,-0.178 -1.557,-0.182 -2.222,-0.152 -0.666,0.03 -1.259,-10e-4 -1.744,0.28 -0.486,0.279 -1.02,0.85 -1.008,1.236 0.009,0.387 0.083,0.53 0.484,0.535 0.4,0.006 0.878,-0.755 1.348,-0.877 0.47,-0.123 1.906,-0.197 1.906,-0.197 0,0 -0.133,1.302 -0.184,2.072 -0.05,0.77 -0.014,1.702 0.163,2.336 0.176,0.635 0.328,1.13 0.789,1.32 0.46,0.192 1.024,-0.177 1.324,-0.404 0.298,-0.228 0.614,-0.92 0.636,-1.123 0.023,-0.203 -0.117,-3.167 0.249,-3.205 0.364,-0.04 0.347,0.571 0.488,1.29 0.14,0.72 1.613,6.99 0.1,9.346 -1.514,2.358 -5.673,2.872 -6.44,2.909 -0.577227,0.02725 -1.155733,-0.0029 -1.727,-0.09 -0.44,-0.06 -0.802,-0.138 -1.556,-0.49 -0.754,-0.353 -1.77,-1.303 -2.838,-2.174 -1.07,-0.87 -2.549,-2.381 -3.28,-3.16 -0.73,-0.78 -1.988,-2.129 -2.425,-3.133 -0.437,-1.006 -1.172,-3.108 -1.172,-4.31 -0.002,-1.203 0.219,-4.653 0.496,-5.665 0.277,-1.012 -0.017,-1.137 0.637,-1.473 0.654,-0.337 1.789,0.118 2.377,0.272 0.588,0.154 0.889,0.564 1.181,0.287 0.292,-0.276 0.291,-0.68 -0.216,-1.18 -0.507,-0.499 -2.908,-0.474 -3.006,-0.722 -0.098,-0.248 0.014,-0.576 0.06,-0.815 0.047,-0.238 -0.063,-1.973 0.48,-3.088 0.542,-1.115 1.449,-2.899 2.73,-2.879 z m -1.664,10.35 c -0.424,0.013 -0.831,0.08 -1.064,0.156 -0.466,0.156 -0.483,0.165 -0.582,0.432 -0.1,0.268 -0.096,0.847 0.215,0.967 0.562,-0.229 1.457,-0.704 1.625,-0.399 0.05,0.61 -0.36,1.946 -0.297,2.739 0.063,0.791 0.252,1.612 0.529,1.945 0.278,0.333 0.259,0.345 0.53,0.252 0.27,-0.093 0.393,-0.415 0.505,-1.012 0.113,-0.596 0.04,-1.964 0.045,-2.323 0.005,-0.36 0.068,-0.95 0.068,-0.95 0,0 0.349,0.334 0.544,0.47 0.195,0.136 0.469,-0.498 0.347,-0.908 -0.12,-0.41 -0.717,-0.952 -1.307,-1.213 -0.295,-0.13 -0.734,-0.17 -1.158,-0.156 z m 14.651,4.19 c 0.276,0.21 0.087,1.287 0.08,1.71 -0.008,0.423 0.007,1.383 -0.143,1.723 -0.152,0.34 -0.231,0.572 -0.56,0.545 -0.329,-0.027 -0.43,-0.314 -0.534,-0.713 -0.105,-0.399 -0.066,-1.168 -0.004,-1.773 0.061,-0.606 -0.043,-1.45 0.382,-1.653 0.374,-0.178 0.585,0.015 0.779,0.161 z M 27.473023,60.42187 c -0.303402,-0.0485 -0.09884,-1.813772 0.387667,-2.468772 0.29743,-0.400445 1.004288,-0.447544 2.649391,-0.594811 1.045763,-0.09361 2.113151,-0.411545 1.877675,-0.138733 -0.235476,0.272812 -1.094922,0.993716 -1.609305,1.313219 -0.514383,0.319503 -3.002026,1.937602 -3.305428,1.889097 z M 43.662,56.931 c 0.24,0.013 0.486,0.07 0.734,0.187 0.995,0.473 1.468,0.868 1.913,1.979 0.444,1.108 1.157,3.391 0.732,3.736 -0.425,0.345 -6.892,0.276 -7.332,-0.227 -0.44,-0.502 -0.042,-1.703 0.28,-2.476 0.32,-0.773 1.19,-2.31 1.818,-2.643 0.47,-0.25 1.134,-0.596 1.855,-0.556 z"
+  ></path>
+</SVGIcon>
diff --git a/src/components/icons/brands/IconFurAffinity.astro b/src/components/icons/brands/IconFurAffinity.astro
new file mode 100644
index 0000000..9fceda4
--- /dev/null
+++ b/src/components/icons/brands/IconFurAffinity.astro
@@ -0,0 +1,15 @@
+---
+import SVGIcon from "../SVGIcon.astro";
+
+type Props = {
+  width: string;
+  height: string;
+  class?: string;
+};
+---
+
+<SVGIcon {...Astro.props} viewBox="0 0 64 64">
+  <path
+    d="M26.197 62.886c-.26-.57-.257-1.057.007-1.817.2-.57.362-1.875.362-2.9 0-1.024.128-1.941.285-2.038 1.27-.785.657-4.073-1.004-5.388l-1.314-1.041.222.884c.399 1.59-.388 3.432-1.466 3.432-1.18 0-1.549-.907-1.142-2.812.472-2.215-.546-4.19-1.369-2.654-.22.412-.673.643-1.258.643-1.03 0-1.81-.724-1.457-1.352.129-.229-.546.325-1.5 1.23-.953.906-2.645 2.124-3.76 2.707-2.369 1.239-3.332 2.276-4.082 4.396-.985 2.787-1.11 2.997-1.972 3.325-1.23.467-2.955-.16-3.208-1.167-.407-1.62.63-3.175 4.858-7.278 2.49-2.416 2.904-2.757 4.02-3.309 1.626-.804 3.983-3.186 2.987-3.02-.701.118-1.058-.089-1.058-.612 0-.318.18-.77.402-1.004.332-.352.27-.357-.363-.031-1.122.579-1.68-.338-.99-1.628.747-1.395-1.864-1.486-3.832-.132-2.813 1.935-5.868 1.241-5.375-1.22.398-1.992 2.175-2.917 4.968-2.586 1.732.205 4.062-1.346 3.154-2.1-1.436-1.191-6.902-2.055-8.294-1.31-2.124 1.137-3.654-1.47-1.581-2.695.871-.515 1.05-.52 2.13-.07 1.503.629 2.804.626 4.032-.01.62-.32 1.319-.426 1.927-.293 1.982.436 2.909-.86 2.139-2.989-.354-.978-.33-1.146.223-1.551.482-.352.535-.54.237-.839-.212-.211-.385-.868-.385-1.458 0-.591-.304-1.485-.675-1.987-1.115-1.508-.449-2.277 1.972-2.277h1.918v-1.44c0-1.22-.134-1.523-.884-1.993-.486-.306-1.474-1.085-2.196-1.732-.72-.648-2.055-1.424-2.964-1.726-3.855-1.28-4.364-5.327-.67-5.327 1.56 0 5.525 2.526 6.935 4.418 1.123 1.507 1.414 1.718 2.077 1.512.649-.202 1.56.655 1.56 1.465 0 .779.845 1.608 1.637 1.608.536 0 .614-.197.54-1.367-.082-1.292-.038-1.368.804-1.399 1.486-.054 1.187-1.634-.896-4.727-1.851-2.749-1.46-5.423.652-4.46 1.095.498 1.822 1.763 2.417 4.2.357 1.466.686 2.158 1.058 2.23.83.16.692-1.731-.264-3.615-.442-.87-.805-1.81-.808-2.09-.003-.28-.435-1.232-.96-2.116-1.088-1.835-1.18-2.475-.445-3.085.71-.59 2.053.935 2.053 2.33 0 .538.204 1.362.453 1.83.248.47.688 1.505.978 2.301.809 2.227 3.578 5.132 4.148 4.352.286-.39.67-.532 1.125-.413 1.164.305 1.42-2.364.706-7.378C32.602.433 32.751 0 34.157 0c1.09 0 1.27.25 1.15 1.608-.19 2.131-.058 5.275.232 5.564.193.194.352.576.352.85 0 .767 1.65.618 2.492-.225.397-.398.94-.723 1.206-.723s1.005-.28 1.641-.62c2.394-1.284 3.58.705 1.918 3.216-1.041 1.573-1.093 1.35.7 3.044 1.122 1.06 1.699 1.392 2.171 1.25 1.491-.45 1.926-.324 2.031.586.151 1.312.953 1.102 2.78-.73 2.294-2.3 3.221-1.887 1.46.65-.308.441-.657 1.116-.775 1.497-.119.382-.427.87-.685 1.085-.724.6-.622 2.562.134 2.562.332 0 .783.217 1.004.482.225.272.926.482 1.607.482 2.043 0 2.49 1.51.833 2.814-.786.618-.463 1.366.59 1.366.82 0 1.287 1.245.706 1.887-.449.496-.436.584.135.94.346.217.63.268.63.113 0-.329 3.939-1.334 5.225-1.333.725 0 .884.144.884.794 0 1.21-.966 1.543-3.723 1.284-2.708-.253-3.146.194-1.54 1.575.684.588.794.876.578 1.512-.146.431-.245.869-.22.972.026.103-.126.19-.338.195-1.09.02-2.821 1.457-2.255 1.87.473.346.5.54.179 1.247-.288.631-.29.817-.006.758.692-.143.616.983-.111 1.66-1.071.998-1.026 1.956.102 2.181 1.026.206 2.19 1.61 2.19 2.642 0 .797-1.354.924-3.104.29-1.501-.542-1.744-.043-.48.988.777.635 1.043 1.087.962 1.638-.152 1.044-.655 1.125-1.602.258-1.926-1.763-2.055-1.789-1.227-.25.429.797 1.02 1.775 1.315 2.175.538.728.468 1.971-.132 2.368-.661.438-1.61-.196-2.176-1.453-.328-.726-1.033-1.827-1.568-2.446l-.974-1.125-.008 1.85-.008 1.85-1.045-.082c-1.913-.15-1.004 3.988 1.673 7.614 2.381 3.227 2.42 5.363.1 5.588-1.294.125-2.12-1.067-2.608-3.758-.456-2.518-2.838-7.082-4.068-7.794-2.097-1.215-3.449-.196-2.768 2.085 1.146 3.838 1.119 4.722-.162 5.305-1.593.726-2.054.058-2.054-2.974 0-2.659-.433-3.736-1.503-3.736-.18 0-.584-.285-.9-.633-.511-.565-.643-.583-1.234-.17-.363.256-.976.385-1.362.288-.917-.23-2.396 2.17-2.396 3.89 0 .642-.136 1.423-.302 1.733-.166.31-.375 1.741-.464 3.18-.234 3.792-2.028 5.593-3.14 3.152zM38.94 48.043c2.979-1.951 3.15-7.58.306-10.077-.683-.6-1.105-1.264-1.105-1.743 0-6.205-6.566-8.681-10.748-4.052-.842.932-1.543 1.355-2.663 1.606-3.005.673-4.574 2.26-5.255 5.317-.894 4.007 1.283 5.78 6.681 5.442 3.475-.218 4.882.271 6.538 2.272 1.251 1.511 4.764 2.206 6.246 1.235zm8.48-8.987c2.208-1.858 1.868-6.062-.683-8.444-2.214-2.068-6.94 3.056-5.991 6.493.696 2.522 4.629 3.672 6.674 1.951zm-23.706-6.441c2.343-1.212 2.512-5.785.304-8.256l-.9-1.008-1.443.551c-2.068.79-4.022 2.572-4.474 4.08-1.087 3.627 2.931 6.485 6.513 4.633zm18.185-3.055c3.839-1.455 4.88-8.123 1.93-12.358-2.445-3.508-6.237-.349-7.336 6.11-.75 4.401 1.973 7.548 5.406 6.248zm6.473-1.691c.072-.61-.045-.86-.402-.86-.349 0-.504.306-.504.992 0 1.23.757 1.12.906-.132zm-15.173-2.166c2.732-2.508 3.919-8.787 2.118-11.209-2.789-3.753-10.61 3.976-9.105 8.998.953 3.18 4.654 4.352 6.987 2.21zm-9.527-5.482c0-.457-.849-.33-1.283.193-.218.263-.297.733-.176 1.045.225.578 1.46-.468 1.46-1.238zm18.65-6.234c0-.821-.44-1.073-.814-.467-.267.433.05 1.27.482 1.27.182 0 .331-.361.331-.803zm-6.584-1.793c.116-.367.13-.75.029-.85-.268-.268-1.163.559-1.163 1.075 0 .695.898.517 1.134-.225zm17.27 46.245c-.512-.632-1.524-3.723-1.295-3.952.656-.656 3.148 1.338 3.148 2.52 0 1.223-1.245 2.185-1.853 1.432zm-20.976-1.864c0-.694 1.017-2.272 1.386-2.15.537.177.67 1.466.207 2.023-.445.536-1.593.627-1.593.127zM1.7 52.196c-.576-.576-.199-1.715.568-1.715.798 0 1.388.959.988 1.605-.226.366-1.229.437-1.556.11zm8.21-5.637c-.554-.555-.487-1.865.097-1.865.265 0 .482-.14.482-.31 0-.474 1.175-.999 1.745-.78.813.312.59 1.096-.642 2.257-1.326 1.25-1.187 1.193-1.682.698zm48.029-.441c-1.177-1.177-.24-2.489 1.284-1.795.943.43 1.031 1.501.161 1.967-.804.43-.847.425-1.445-.172zM5.799 22.585c-.539-.366-.766-1.669-.441-2.523.387-1.02 1.378-.985 2.214.077.864 1.1.89 2.369.05 2.369-.34 0-.81.07-1.045.157-.236.087-.586.05-.778-.08zm48.74-2.96c0-.934 1.221-1.5 1.86-.863.41.41.424.586.083.996-.615.742-1.942.65-1.942-.133zm2.686.14c-.212-.551.34-1.102 1.115-1.11.638-.008.32 1.415-.345 1.542a.716.716 0 0 1-.77-.431zM8.94 19.213c.073-.518.353-.753.986-.825.949-.11 1.195.466.499 1.162-.682.683-1.6.474-1.485-.337zm44.13-7.42c-.329-.857.458-2.197 1.226-2.088 1.012.145 1.121 1.207.197 1.918-.91.7-1.206.735-1.423.17zM38.392 5.736c-.523-1.57.417-2.74 1.784-2.22 1.267.482 1.14 1.544-.256 2.127-1.344.562-1.371.563-1.528.093z"
+  ></path>
+</SVGIcon>
diff --git a/src/components/icons/brands/IconInkbunny.astro b/src/components/icons/brands/IconInkbunny.astro
new file mode 100644
index 0000000..7a5f4db
--- /dev/null
+++ b/src/components/icons/brands/IconInkbunny.astro
@@ -0,0 +1,15 @@
+---
+import SVGIcon from "../SVGIcon.astro";
+
+type Props = {
+  width: string;
+  height: string;
+  class?: string;
+};
+---
+
+<SVGIcon {...Astro.props} viewBox="0 0 72 72">
+  <path
+    d="M58.914 44.015c-.247.468-1.187 1.528-1.95 1.98-1.493.873-1.984 1.014-1.65.48.299-.483-1.403-.035-2.613.696-.55.326-1.211.898-1.326.783-.388-.388-1.69 3.786-1.535 4.82.174 2.417-1.846 3.545-3.733 5.455-1.885 1.908-3.682 3.793-3.816 3.793-.134 0-.756-.771-2.183-2.496-3.132-3.781-4.04-5.785-4.088-8.04.07-.472 1.116-.812 1.943-1.045 1.046-.29 2.79-1.198 2.79-1.198s2.917-1.63 3.026-1.694c.684-.35 1.374-.929 1.755-1.268 1.093-.943 1.736-2.4 1.929-3.16.134-.536-.288-1.356-.756-2.11l-.66-1.14.813-3.384c.467-1.795.455-4.315 1.54-5.147 2.835-.935 5.735-5.197 8.36-9.084 4.032-5.97 5.191-10.89 3.14-13.33-1.568-1.86-3.662-1.506-10.12 1.713-2.213 1.104-5.978 3.183-8.363 4.618-2.385 1.438-4.386 2.57-4.437 2.519-.05-.055.13-1.459.401-3.121.755-4.594.97-9.542.503-11.495C37.381 1.068 36.273-.016 34.83 0c-.864.008-1.846.413-2.893 1.234-4.306 3.384-9.427 10.025-11.403 16.29-1.62 5.134-3.793 16.975-3.538 19.958.52 6.127.924 5.226-.33 7.368C13.137 50.87 11 59.585 11 67.936c0 3.744-.43 4.064.125 4.064h2.986c.444-.083.287-.795.444-5.393.196-5.765.79-9.322 2.342-14.018.849-2.57 3.149-7.487 4.092-8.737.16-.216.44-.381.46-.577.035-.32-.134-.74-.516-1.534-.57-1.182-.837-2.047-.837-5.317.173-3.352.232-3.984.845-5.364.126-.291.524-1.019.68-1.56.33-1.125.311-2.488.546-3.863 1.584-9.31 3.232-14.91 8.526-20.452 3.168-2.848 4.552-3.734 4.54 1.023.334 4-1.334 12.948-3.056 17.381-.519 1.337-1.179 2.638-1.123 2.693.255.326 3.547-.484 3.91-1.597.133-.405.174-.398.318-.376.143.021 1.478 1.026 1.921 1.131.495.11 1.828-.515 1.876-.715.046-.2-2.593-1.83-2.774-1.997-.034-.388-.099-.453-.015-.825.084-.372.14-.615.899-1.105.758-.49 16.982-10.218 19.577-10.27.94-.039 1.35 1.426 1.368 1.935.017.509.04 2.72-.999 4.24-1.038 1.521-8.414 11.11-9.282 11.873-.867.763-2.678.75-3.319.386s-3.705-1.568-3.437-1.069c.271.503 1.255 1.324 1.79 1.933.369.44.99 1.265 1.38 1.835l.585.998-1.65 7.365.758 1.113c.597 1.014.605 1.143.126 2.142-.236.479-1.026 1.245-1.706 1.93-.31.286-4.578 3.006-6.96 3.776-1.781.515-1.615.295-3.12-.008-1.506-.302-4.52-2.453-5.124-1.858-.604.596.877 1.813 1.328 1.988.45.174.61.564 1.328.859.501.216 1.186 1.002 1.221 1.486.031.633.055.525.094 1.126.095 3.914.833 5.966 3.942 12.862 1.207 2.677 2.29 5.247 2.41 5.715.14.562.11.845.542.845h1.963c.597 0-.059-1.753-2.244-6.626-3.474-7.758-4.613-11.628-2.877-9.005.62 1.03 2.13 3.055 3.352 4.493 4.453 5.247 5.384 7.306 4.39 9.688-.42 1.002-.594 1.45-.26 1.45h2.09c.448 0 .579-.137.898-.896.573-1.378 1.536-2.204.95-3.842l-.243-1.14 2.936-4.048c1.064-1.399 2.203-3.179 2.738-3.761.538-.582.664-.797.664-.797.495.24 2.253-.09 2.522-.351.268-.261-.632-.143-.749-.538-.102-.169.707-.677 1.422-.965 1.418-.57 2.842-2.264 2.932-2.975.245-.297.267.551.277.93-.024.628-1.583 2.249-2.043 3.22-.46.973-.692 1.46-.543 2.44.149.98 1.215 1.857 2.648 1.787 1.432-.07 2.275-.936 2.295-2.316.02-1.565-1.778-6.887-1.667-6.864.11.028.382-7.094.22-7.793-.162-.699-.437-.795-.437-.795zm-33.575-7.213c.008.425 1.333.585 1.44-.075.157-.99 1.24-1.77 2.004-1.707.764.061 1.194.103 1.556.815.363.713.14 1.378.24 1.654.102.276 1.16.317 1.227-.133.066-.451.319-2.732-.927-3.389-1.247-.657-2.26-.776-3.545-.294-1.286.482-2.019 1.863-1.995 3.13zm15.64 1.859c.066-.21.446-.797.856-.574.41.222.252.614.245.81-.007.195.68.652.798.415.118-.237.186-.63.191-.795.006-.166.081-.753-.226-1.053-.307-.3-.894-.548-1.583-.33-.69.217-1.111.871-1.195 1.15-.084.277.846.587.913.377zm-6.251-1.067s.998 1.791 1.358 2.158c.36.367 1.502.72 2.08.456.578-.263 1.245-1.528 1.276-1.775a136.192 136.192 0 0 1-4.714-.84zm-.063 5.955c-.837.182-2.516.256-3.887-.012-1.371-.271-2.343.357-2.013.676.668.637 1.955.795 2.753.906 1.268.173 2.766-.017 3.207-.085.44-.068 1.364-.557 1.482-.47.06.044.616.507 1.245.822.596.298 1.47.464 1.727.503.256.039.982-.631.795-.747-.188-.115-.727-.27-1.018-.367a4.407 4.407 0 0 1-1.13-.542c-.533-.351-1.057-.865-1.2-1.23-.144-.366-.389.024-.7.157-.412.177-.424.205-1.261.39zm15.387 14.486c-1.143 1.549-1.374 1.888-2.364 3.201-1.446 1.91-2.78 3.526-2.955 3.585-.177.058-.511-.19-.735-.55-.374-.602-.146-.956 2.542-3.946 1.154-1.29 1.563-1.734 2.73-3.012.252-.272.458-.51.59-.503.132.006.631.368.732.44.1.072-.145.329-.54.785zM20.637 68.697c-.146 2.28-.126 3.301.118 3.301h1.764c.181 0 .123-.427.13-.887.031-3.03.812-8.371 1.31-12.02.116-.793-.597-1.307-1.142-1.115-.543.192-1.968 7.365-2.18 10.721z"
+  ></path>
+</SVGIcon>
diff --git a/src/components/icons/brands/IconSoFurry.astro b/src/components/icons/brands/IconSoFurry.astro
new file mode 100644
index 0000000..32703e9
--- /dev/null
+++ b/src/components/icons/brands/IconSoFurry.astro
@@ -0,0 +1,15 @@
+---
+import SVGIcon from "../SVGIcon.astro";
+
+type Props = {
+  width: string;
+  height: string;
+  class?: string;
+};
+---
+
+<SVGIcon {...Astro.props} viewBox="0 0 64 64">
+  <path
+    d="M16.998 56.139c-3.483-.313-6.077-1.151-8.817-2.85-1.2-.745-1.99-1.373-3.22-2.565-1.27-1.23-2.101-2.23-3.042-3.663C1.323 46.154.004 43.696 0 43.484c-.003-.127.642-.091 1.265.07.316.082.59.134.609.116.019-.019-.066-.356-.187-.75-.703-2.275-.741-5.302-.1-7.857.679-2.702 2.023-5.117 3.99-7.169l1-1.043.178.567c.098.311.18.697.184.856.004.159.034.29.067.29s.41-.214.839-.474c3.491-2.12 7.817-2.179 11.225-.154.818.486 2.199 1.744 2.774 2.528.545.742 1.16 2.037 1.461 3.08.431 1.489.534 3.07.317 4.867l-.052.428-.707-.185c-1.395-.363-3.021-.203-4.173.411-.818.437-1.795 1.463-2.194 2.306-.32.674-.34.79-.34 1.876 0 1.085.021 1.203.337 1.87.415.876 1.157 1.613 2.083 2.069.722.356 1.837.636 2.527.636 1.224 0 3.052-.707 4.125-1.596 1.722-1.427 2.622-3.392 2.738-5.979.126-2.809-.505-5.298-2.39-9.42-1.822-3.984-2.493-6.404-2.599-9.38-.047-1.327-.022-1.926.118-2.764.42-2.509 1.414-4.424 3.18-6.127 2.175-2.097 5.092-3.31 8.256-3.437 1.262-.05 2.372.037 3.056.241.138.041.18-.07.23-.611.094-1.003.13-1.059.533-.851 1.488.766 3.272 2.398 4.234 3.875 1.201 1.842 1.712 3.483 1.802 5.79.065 1.662-.025 2.381-.92 7.387-.766 4.282-.875 5.151-.878 7.034-.003 1.482.024 1.76.228 2.31.198.533.775 1.323.965 1.321.032 0 .246-.367.476-.816.76-1.484 2.01-3.227 3.211-4.478 1.323-1.376 2.578-2.318 4.01-3.01l1.006-.486-.208-.473c-.146-.332-.223-.795-.258-1.56l-.05-1.086.41.07c1.318.222 2.772.758 3.846 1.42.282.173.524.315.538.315.013 0 .033-.344.045-.764.01-.42.06-.873.11-1.006l.09-.243.646.432c.847.565 2.001 1.717 2.788 2.78.347.47.661.865.698.88.038.014.2-.227.361-.535.161-.308.43-.722.597-.92l.305-.361.321.702c1.306 2.858 1.648 8.456.85 13.93-.844 5.791-2.563 9.862-5.357 12.686-2.172 2.195-4.194 3.067-7.104 3.063-1.668-.002-2.857-.2-4.497-.747-1.439-.48-2.255-.873-3.407-1.639-.922-.612-2.01-1.65-1.907-1.818.087-.14.98-.44 1.32-.443.53-.003.57-.121.27-.797-1.435-3.23-1.511-7.903-.197-12.062.147-.466.228-.882.18-.925-.048-.042-.29-.155-.537-.25-1.532-.593-2.635-1.942-3.154-3.858-.153-.565-.185-1.116-.181-3.158.004-2.199.044-2.772.362-5.158.468-3.513.507-5.76.121-6.88-.694-2.01-2.422-3.286-4.155-3.069-1.851.232-3.602 2.117-3.965 4.27-.295 1.75.205 3.449 2.138 7.258 1.965 3.873 2.696 5.787 3.218 8.42.623 3.15.589 6.597-.091 9.26-1.628 6.378-6.329 10.363-13.474 11.424-1.344.2-4.718.285-6.158.156zm38.56-5.629c1.611-.75 3.426-3.418 4.488-6.598 1.291-3.866 1.285-8.376-.015-11.01-.432-.875-1.105-1.543-1.66-1.647-.81-.152-2.248.65-3.448 1.922-1.708 1.81-2.954 4.326-3.559 7.182-.318 1.505-.4 4.178-.17 5.572.39 2.366 1.245 3.993 2.402 4.57.69.343 1.238.346 1.961.01zm-42.375-7.5c.099-1.947.728-3.439 2.058-4.878 1.197-1.295 2.751-2.147 4.532-2.484.538-.101.962-.234.962-.3 0-.066-.094-.485-.208-.931-.487-1.904-1.661-3.363-3.396-4.22-1.314-.648-2.2-.823-3.87-.764-1.518.054-2.535.329-3.684.995-.964.56-2.384 1.997-2.976 3.014-.489.838-1.332 3.164-1.196 3.3.106.105 1.495-.15 1.873-.345.175-.091.342-.142.37-.114.028.028.155.692.282 1.475.127.783.253 1.446.281 1.474.028.027.642-.086 1.366-.252.724-.167 1.39-.305 1.479-.307.138-.004.156.142.119.988-.076 1.746.384 3.107 1.37 4.056.244.233.474.425.512.425.038 0 .095-.51.126-1.132z"
+  ></path>
+</SVGIcon>
diff --git a/src/components/icons/brands/IconWeasyl.astro b/src/components/icons/brands/IconWeasyl.astro
new file mode 100644
index 0000000..3093a53
--- /dev/null
+++ b/src/components/icons/brands/IconWeasyl.astro
@@ -0,0 +1,15 @@
+---
+import SVGIcon from "../SVGIcon.astro";
+
+type Props = {
+  width: string;
+  height: string;
+  class?: string;
+};
+---
+
+<SVGIcon {...Astro.props} viewBox="0 0 24 24">
+  <path
+    d="M21.23 4.156a8.488 8.488 0 0 0-5.871-1.857c-3.766.243-6.324 2.662-7.364 6.481-1.28-1.224-1.892-3.238-2.093-5.54-1.02.215-1.658.702-2.233 1.237.445 2.316 1.802 4.015 3.264 5.158-2.559.317-5.99 2.442-6.771 4.904-.507 1.598.258 3.415 1.283 4.52 1.237 1.333 3.75 1.998 6.355 1.754.037.362-.104.536-.058.907 4.067-.306 7.174-1.646 10.04-3.894 1.119-.877 2.659-2.037 3.756-3.227 1.101-1.192 2.296-2.578 2.443-4.52.21-2.79-1.236-4.694-2.751-5.923zm-1.434 10.938c-1.035 1.001-2.241 1.797-3.351 2.675-1.249-1.987-2.583-3.984-3.887-5.917.017 2.63.006 5.432.04 7.957-.78.381-1.789.558-2.744.763-1.935-2.917-3.968-5.99-5.961-8.908.693-.447 1.627-.785 2.478-1.075 1.419 2.05 2.729 4.253 4.171 6.333.019-3.113-.009-6.673-.061-9.919a14.175 14.175 0 0 0 1.527-.434c1.813 2.721 3.553 5.628 5.464 8.359a547.35 547.35 0 0 1-.018-9.768c.858-.282 1.803-.535 2.669-.809.02 3.499-.338 7.128-.327 10.743z"
+  ></path>
+</SVGIcon>
diff --git a/src/components/icons/brands/index.ts b/src/components/icons/brands/index.ts
new file mode 100644
index 0000000..699bf44
--- /dev/null
+++ b/src/components/icons/brands/index.ts
@@ -0,0 +1,5 @@
+export { default as IconEkasPortal } from "./IconEkasPortal.astro";
+export { default as IconFurAffinity } from "./IconFurAffinity.astro";
+export { default as IconInkbunny } from "./IconInkbunny.astro";
+export { default as IconSoFurry } from "./IconSoFurry.astro";
+export { default as IconWeasyl } from "./IconWeasyl.astro";
diff --git a/src/content/blog/drafts/.gitignore b/src/content/blog/drafts/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/src/content/blog/drafts/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/src/content/config.ts b/src/content/config.ts
index a3f4d34..6013507 100644
--- a/src/content/config.ts
+++ b/src/content/config.ts
@@ -78,6 +78,14 @@ const websiteLinks = z.object({
       return { link, username };
     }),
   ),
+  sofurrybeta: z.object({ link: z.string().url(), username: z.string() }).or(
+    z.string().transform((link, ctx) => {
+      const { username } = parseRegex<{ username: string }>(
+        /^(?:https?:\/\/)?sofurrybeta.com\/u\/(?<username>[^\/]+)\/?$/,
+      )(link, ctx);
+      return { link, username };
+    }),
+  ),
   mastodon: z
     .object({ link: z.string().url(), username: z.string().regex(/^[^@]+@[^@]+$/) })
     .or(
@@ -144,7 +152,6 @@ const publishedContent = z.object({
   // Required parameters
   title: z.string(),
   authors: userList,
-  contentWarning: z.string().trim(),
   // Required parameters, but optional for drafts (isDraft === true)
   pubDate: z
     .date()
@@ -154,10 +161,10 @@ const publishedContent = z.object({
   tags: z.array(z.string()),
   // Optional parameters
   isDraft: z.boolean().default(false),
+  isAgeRestricted: z.boolean().default(true),
   relatedStories: z.array(reference("stories")).default([]),
   relatedGames: z.array(reference("games")).default([]),
   lang: lang,
-  copyrightedCharacters: copyrightedCharacters,
   series: reference("series").optional(),
   posts: z
     .object({
@@ -191,6 +198,18 @@ const publishedContent = z.object({
         )(link, ctx);
         return { link, postId };
       }),
+      sofurrybeta: z.string().transform((link, ctx) => {
+        const { postId } = parseRegex<{ postId: string }>(
+          /^(?:https?:\/\/)sofurrybeta\.com\/s\/(?<postId>[a-zA-Z0-9]+)\/?$/,
+        )(link, ctx);
+        return { link, postId };
+      }),
+      itch: z.string().transform((link, ctx) => {
+        const { user, postId } = parseRegex<{ user: string; postId: string }>(
+          /^(?:https?:\/\/)(?<user>[a-z-]+)\.itch\.io\/(?<postId>[a-z0-9_-]+)\/?$/,
+        )(link, ctx);
+        return { link, user, postId };
+      }),
       twitter: z.string().transform((link, ctx) => {
         const { user, postId } = parseRegex<{ user: string; postId: string }>(
           /^(?:https?:\/\/)(?:www\.)?(?:twitter\.com|x\.com)\/(?<user>[a-zA-Z0-9_-]+)\/status\/(?<postId>[1-9]\d*)\/?$/,
@@ -212,6 +231,7 @@ const publishedContent = z.object({
     })
     .partial()
     .default({}),
+  blacklistedMastodonComments: z.array(z.string()).default([]),
 });
 
 // Types
@@ -232,17 +252,19 @@ const storiesCollection = defineCollection({
     z
       .object({
         // Required parameters, but optional for drafts (isDraft === true)
+        contentWarning: z.string().trim(),
         wordCount: z.number().int().optional(),
         thumbnail: image().optional(),
         // Optional parameters
-        shortTitle: z.string().optional(),
-        commissioners: userList.optional(),
-        requesters: userList.optional(),
-        summary: z.string().trim().optional(),
         thumbnailWidth: z.number().int().optional(),
         thumbnailHeight: z.number().int().optional(),
         prev: reference("stories").nullish(),
         next: reference("stories").nullish(),
+        copyrightedCharacters: copyrightedCharacters,
+        shortTitle: z.string().optional(),
+        commissioners: userList.optional(),
+        requesters: userList.optional(),
+        summary: z.string().trim().optional(),
       })
       .and(publishedContent)
       .refine(({ isDraft, description }) => isDraft || description, `Missing "description" for published story`)
@@ -253,7 +275,11 @@ const storiesCollection = defineCollection({
       .refine(({ isDraft, wordCount }) => isDraft || wordCount, `Missing "wordCount" for published story`)
       .refine(({ isDraft, pubDate }) => isDraft || pubDate, `Missing "pubDate" for published story`)
       .refine(({ isDraft, thumbnail }) => isDraft || thumbnail, `Missing "thumbnail" for published story`)
-      .refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published story`),
+      .refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published story`)
+      .refine(
+        ({ posts, blacklistedMastodonComments }) => !blacklistedMastodonComments.length || posts.mastodon,
+        `Cannot include "blacklistedMastodonComments" without a Mastodon post`,
+      ),
 });
 
 const gamesCollection = defineCollection({
@@ -262,6 +288,7 @@ const gamesCollection = defineCollection({
     z
       .object({
         // Required parameters, but optional for drafts (isDraft === true)
+        contentWarning: z.string().trim(),
         platforms: z.array(platform).default([]),
         thumbnail: image().optional(),
         // Optional parameters
@@ -269,6 +296,7 @@ const gamesCollection = defineCollection({
         thumbnailHeight: z.number().int().optional(),
         prev: reference("games").nullish(),
         next: reference("games").nullish(),
+        copyrightedCharacters: copyrightedCharacters,
       })
       .and(publishedContent)
       .refine(({ isDraft, description }) => isDraft || description, `Missing "description" for published game`)
@@ -276,7 +304,36 @@ const gamesCollection = defineCollection({
       .refine(({ isDraft, platforms }) => isDraft || platforms.length, `Missing "platforms" for published game`)
       .refine(({ isDraft, pubDate }) => isDraft || pubDate, `Missing "pubDate" for published game`)
       .refine(({ isDraft, thumbnail }) => isDraft || thumbnail, `Missing "thumbnail" for published game`)
-      .refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published game`),
+      .refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published game`)
+      .refine(
+        ({ posts, blacklistedMastodonComments }) => !blacklistedMastodonComments.length || posts.mastodon,
+        `Cannot include "blacklistedMastodonComments" without a Mastodon post`,
+      ),
+});
+
+const blogCollection = defineCollection({
+  type: "content",
+  schema: ({ image }) =>
+    z
+      .object({
+        // Required parameters, but optional for drafts (isDraft === true)
+        thumbnail: image().optional(),
+        // Optional parameters
+        summary: z.string().trim().optional(),
+        thumbnailWidth: z.number().int().optional(),
+        thumbnailHeight: z.number().int().optional(),
+        prev: reference("blog").nullish(),
+        next: reference("blog").nullish(),
+      })
+      .and(publishedContent)
+      .refine(({ isDraft, description }) => isDraft || description, `Missing "description" for published story`)
+      .refine(({ isDraft, pubDate }) => isDraft || pubDate, `Missing "pubDate" for published story`)
+      .refine(({ isDraft, thumbnail }) => isDraft || thumbnail, `Missing "thumbnail" for published story`)
+      .refine(({ isDraft, tags }) => isDraft || tags.length, `Missing "tags" for published story`)
+      .refine(
+        ({ posts, blacklistedMastodonComments }) => !blacklistedMastodonComments.length || posts.mastodon,
+        `Cannot include "blacklistedMastodonComments" without a Mastodon post`,
+      ),
 });
 
 // Data collections
@@ -332,6 +389,7 @@ const tagCategoriesCollection = defineCollection({
 export const collections = {
   stories: storiesCollection,
   games: gamesCollection,
+  blog: blogCollection,
   users: usersCollection,
   series: seriesCollection,
   "tag-categories": tagCategoriesCollection,
diff --git a/src/content/stories/accommodation.md b/src/content/stories/accommodation.md
index 0a1efdf..3ebdd19 100644
--- a/src/content/stories/accommodation.md
+++ b/src/content/stories/accommodation.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245838/accommodation-vore-story
   inkbunny: https://inkbunny.net/s/3009993
   sofurry: https://www.sofurry.com/view/1992347
+  sofurrybeta: https://sofurrybeta.com/s/dmBBW6Zm
 tags:
   - anal vore
   - anthro predator
diff --git a/src/content/stories/addictive-additions.md b/src/content/stories/addictive-additions.md
index 0340e47..8a12cd5 100644
--- a/src/content/stories/addictive-additions.md
+++ b/src/content/stories/addictive-additions.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245835/c-addictive-additions-vore-story
   inkbunny: https://inkbunny.net/s/3009992
   sofurry: https://www.sofurry.com/view/1992344
+  sofurrybeta: https://sofurrybeta.com/s/ZmM3E4q1
 tags:
   - oral vore
   - anal vore
@@ -30,6 +31,7 @@ tags:
   - semi-willing prey
   - similar size
   - implied perma endo
+  - endo trait theft
   - straight sex
   - gay sex
   - hyper
diff --git a/src/content/stories/annivoresary.md b/src/content/stories/annivoresary.md
index 5ae7d34..38fb640 100644
--- a/src/content/stories/annivoresary.md
+++ b/src/content/stories/annivoresary.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245812/annivoresary-vore-story
   inkbunny: https://inkbunny.net/s/3009934
   sofurry: https://www.sofurry.com/view/1992300
+  sofurrybeta: https://sofurrybeta.com/s/3egLylPm
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/better-in-bully-batter.md b/src/content/stories/better-in-bully-batter.md
index abbd9b3..238f6e9 100644
--- a/src/content/stories/better-in-bully-batter.md
+++ b/src/content/stories/better-in-bully-batter.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245853/c-better-in-bully-batter-vore-story
   inkbunny: https://inkbunny.net/s/3010009
   sofurry: https://www.sofurry.com/view/1992371
+  sofurrybeta: https://sofurrybeta.com/s/dmW3GPwm
 tags:
   - cock vore
   - anthro predator
@@ -27,6 +28,7 @@ tags:
   - unwilling prey
   - similar size
   - implied perma endo
+  - endo trait theft
   - straight sex
   - gay sex
   - orgy
diff --git a/src/content/stories/big-haul.md b/src/content/stories/big-haul.md
index 60f12f8..a5c4492 100644
--- a/src/content/stories/big-haul.md
+++ b/src/content/stories/big-haul.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2326739/big-haul-vore-story
   inkbunny: https://inkbunny.net/s/3179339
   sofurry: https://www.sofurry.com/view/2074207
+  sofurrybeta: https://sofurrybeta.com/s/GnDLVoGn
 tags:
   - unbirth
   - anthro predator
diff --git a/src/content/stories/birdroom.md b/src/content/stories/birdroom.md
index ce1768a..07cafa7 100644
--- a/src/content/stories/birdroom.md
+++ b/src/content/stories/birdroom.md
@@ -18,6 +18,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245859/birdroom-vore-story
   inkbunny: https://inkbunny.net/s/3010032
   sofurry: https://www.sofurry.com/view/1992379
+  sofurrybeta: https://sofurrybeta.com/s/7ejYXvL1
 tags:
   - Sam Brendan
   - Beetle
diff --git a/src/content/stories/bladder-filler.md b/src/content/stories/bladder-filler.md
index 9425763..0aa8b21 100644
--- a/src/content/stories/bladder-filler.md
+++ b/src/content/stories/bladder-filler.md
@@ -18,6 +18,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2322878/bladder-filler-vore-story
   inkbunny: https://inkbunny.net/s/3168729
   sofurry: https://www.sofurry.com/view/2069991
+  sofurrybeta: https://sofurrybeta.com/s/J1O5Z3zm
 tags:
   - Beetle
   - cock vore
diff --git a/src/content/stories/bottom-of-the-food-chain.md b/src/content/stories/bottom-of-the-food-chain.md
index 4de1990..f3d9ac4 100644
--- a/src/content/stories/bottom-of-the-food-chain.md
+++ b/src/content/stories/bottom-of-the-food-chain.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2308019/bottom-of-the-food-chain-vore-story
   inkbunny: https://inkbunny.net/s/3130702
   sofurry: https://www.sofurry.com/view/2054568
+  sofurrybeta: https://sofurrybeta.com/s/Vm2b34Gm
 tags:
   - Muno
   - oral vore
diff --git a/src/content/stories/butting-into-their-plans.md b/src/content/stories/butting-into-their-plans.md
index bea9fdb..a0f078b 100644
--- a/src/content/stories/butting-into-their-plans.md
+++ b/src/content/stories/butting-into-their-plans.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245850/butting-into-their-plans-vore-story
   inkbunny: https://inkbunny.net/s/3010005
   sofurry: https://www.sofurry.com/view/1992365
+  sofurrybeta: https://sofurrybeta.com/s/znJE5M3m
 tags:
   - anal vore
   - feral predator
diff --git a/src/content/stories/delicacy-s-dare.md b/src/content/stories/delicacy-s-dare.md
index 00bb4c7..3b793bd 100644
--- a/src/content/stories/delicacy-s-dare.md
+++ b/src/content/stories/delicacy-s-dare.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245840/delicacy-s-dare-vore-story
   inkbunny: https://inkbunny.net/s/3009994
   sofurry: https://www.sofurry.com/view/1992348
+  sofurrybeta: https://sofurrybeta.com/s/V1YARGy1
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/eggs-for-months.md b/src/content/stories/eggs-for-months.md
index d70fd38..2000639 100644
--- a/src/content/stories/eggs-for-months.md
+++ b/src/content/stories/eggs-for-months.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245808/eggs-for-months-vore-story
   inkbunny: https://inkbunny.net/s/3009928
   sofurry: https://www.sofurry.com/view/1992262
+  sofurrybeta: https://sofurrybeta.com/s/lmXB9VG1
 tags:
   - sheath vore
   - feral predator
diff --git a/src/content/stories/engaging-contacts.md b/src/content/stories/engaging-contacts.md
index 8810056..32ba22f 100644
--- a/src/content/stories/engaging-contacts.md
+++ b/src/content/stories/engaging-contacts.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2291372/engaging-contacts-vore-story
   inkbunny: https://inkbunny.net/s/3088451
   sofurry: https://www.sofurry.com/view/2035092
+  sofurrybeta: https://sofurrybeta.com/s/YnLrbBpe
 tags:
   - oral vore
   - unbirth
diff --git a/src/content/stories/flavorful-favor.md b/src/content/stories/flavorful-favor.md
index 3a890cf..f234fd4 100644
--- a/src/content/stories/flavorful-favor.md
+++ b/src/content/stories/flavorful-favor.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245855/flavorful-favor-vore-story
   inkbunny: https://inkbunny.net/s/3010014
   sofurry: https://www.sofurry.com/view/1992375
+  sofurrybeta: https://sofurrybeta.com/s/WelWOaj1
 tags:
   - Beetle
   - oral vore
diff --git a/src/content/stories/for-the-night.md b/src/content/stories/for-the-night.md
index 5f645df..12d5189 100644
--- a/src/content/stories/for-the-night.md
+++ b/src/content/stories/for-the-night.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245830/for-the-night-vore-story
   inkbunny: https://inkbunny.net/s/3009989
   sofurry: https://www.sofurry.com/view/1992339
+  sofurrybeta: https://sofurrybeta.com/s/P1EMLv81
 tags:
   - anal vore
   - anthro predator
diff --git a/src/content/stories/gentle-and-cruel.md b/src/content/stories/gentle-and-cruel.md
index 85898a7..ad36fc9 100644
--- a/src/content/stories/gentle-and-cruel.md
+++ b/src/content/stories/gentle-and-cruel.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2320112/gentle-and-cruel-vore-story
   inkbunny: https://inkbunny.net/s/3161450
   sofurry: https://www.sofurry.com/view/2066780
+  sofurrybeta: https://sofurrybeta.com/s/3egLyEdm
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/hate-to-sea-it.md b/src/content/stories/hate-to-sea-it.md
index d254dfd..ff5fb7a 100644
--- a/src/content/stories/hate-to-sea-it.md
+++ b/src/content/stories/hate-to-sea-it.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245852/hate-to-sea-it-vore-story
   inkbunny: https://inkbunny.net/s/3010007
   sofurry: https://www.sofurry.com/view/1992369
+  sofurrybeta: https://sofurrybeta.com/s/pnGE786e
 tags:
   - unbirth
   - feral predator
diff --git a/src/content/stories/hungry-for-love.md b/src/content/stories/hungry-for-love.md
index cd8bc25..bcfabb7 100644
--- a/src/content/stories/hungry-for-love.md
+++ b/src/content/stories/hungry-for-love.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245845/hungry-for-love-vore-story
   inkbunny: https://inkbunny.net/s/3010001
   sofurry: https://www.sofurry.com/view/1992358
+  sofurrybeta: https://sofurrybeta.com/s/pnGE787e
 tags:
   - oral vore
   - feral predator
diff --git a/src/content/stories/hyper-hunger.md b/src/content/stories/hyper-hunger.md
index 746769b..1ed13a4 100644
--- a/src/content/stories/hyper-hunger.md
+++ b/src/content/stories/hyper-hunger.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245818/hyper-hunger-vore-story
   inkbunny: https://inkbunny.net/s/3009945
   sofurry: https://www.sofurry.com/view/1992317
+  sofurrybeta: https://sofurrybeta.com/s/JewQ7gYn
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/insistence-and-assistance.md b/src/content/stories/insistence-and-assistance.md
index d2e1b6b..4edeb9c 100644
--- a/src/content/stories/insistence-and-assistance.md
+++ b/src/content/stories/insistence-and-assistance.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245823/insistence-and-assistance-vore-story
   inkbunny: https://inkbunny.net/s/3009949
   sofurry: https://www.sofurry.com/view/1992324
+  sofurrybeta: https://sofurrybeta.com/s/A1pxJED1
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/lactation-action.md b/src/content/stories/lactation-action.md
index f90f218..0f827fc 100644
--- a/src/content/stories/lactation-action.md
+++ b/src/content/stories/lactation-action.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245829/lactation-action-vore-story
   inkbunny: https://inkbunny.net/s/3009986
   sofurry: https://www.sofurry.com/view/1992335
+  sofurrybeta: https://sofurrybeta.com/s/0mvw0ZQn
 tags:
   - nipple vore
   - oral vore
diff --git a/src/content/stories/latest-catch.md b/src/content/stories/latest-catch.md
index 7e7df5e..47f2322 100644
--- a/src/content/stories/latest-catch.md
+++ b/src/content/stories/latest-catch.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245828/latest-catch-vore-story
   inkbunny: https://inkbunny.net/s/3009984
   sofurry: https://www.sofurry.com/view/1992331
+  sofurrybeta: https://sofurrybeta.com/s/rn6Jyzpn
 tags:
   - cock vore
   - anthro predator
diff --git a/src/content/stories/never-too-late.md b/src/content/stories/never-too-late.md
index a4ee1d5..0c8178f 100644
--- a/src/content/stories/never-too-late.md
+++ b/src/content/stories/never-too-late.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245821/never-too-late-vore-story
   inkbunny: https://inkbunny.net/s/3009947
   sofurry: https://www.sofurry.com/view/1992320
+  sofurrybeta: https://sofurrybeta.com/s/5nz8gOle
 tags:
   - cock vore
   - anthro predator
diff --git a/src/content/stories/noble-fire.md b/src/content/stories/noble-fire.md
index b7d32d4..a63f1c3 100644
--- a/src/content/stories/noble-fire.md
+++ b/src/content/stories/noble-fire.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2305403/noble-fire-vore-story
   inkbunny: https://inkbunny.net/s/3124162
   sofurry: https://www.sofurry.com/view/2051777
+  sofurrybeta: https://sofurrybeta.com/s/lmXB9qy1
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/overzealous-zenko.md b/src/content/stories/overzealous-zenko.md
index 15e4033..f9baa7a 100644
--- a/src/content/stories/overzealous-zenko.md
+++ b/src/content/stories/overzealous-zenko.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2291367/r-overzealous-zenko-vore-story
   inkbunny: https://inkbunny.net/s/3088442
   sofurry: https://www.sofurry.com/view/2035087
+  sofurrybeta: https://sofurrybeta.com/s/Xek5wP5n
 tags:
   - chest maw vore
   - taur predator
diff --git a/src/content/stories/part-of-the-show.md b/src/content/stories/part-of-the-show.md
index 557fb47..6d75547 100644
--- a/src/content/stories/part-of-the-show.md
+++ b/src/content/stories/part-of-the-show.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2257653/part-of-the-show-vore-story
   inkbunny: https://inkbunny.net/s/3030429
   sofurry: https://www.sofurry.com/view/2001881
+  sofurrybeta: https://sofurrybeta.com/s/r17DQXBe
 tags:
   - Sam Brendan
   - anthro predator
diff --git a/src/content/stories/pet-sit-saturday.md b/src/content/stories/pet-sit-saturday.md
index d4f0417..ad4e42f 100644
--- a/src/content/stories/pet-sit-saturday.md
+++ b/src/content/stories/pet-sit-saturday.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245810/pet-sit-saturday-vore-story
   inkbunny: https://inkbunny.net/s/3009931
   sofurry: https://www.sofurry.com/view/1992266
+  sofurrybeta: https://sofurrybeta.com/s/qmywZNW1
 tags:
   - anal vore
   - anthro predator
diff --git a/src/content/stories/playing-it-safe.md b/src/content/stories/playing-it-safe.md
index 0b956c0..fb5bc2c 100644
--- a/src/content/stories/playing-it-safe.md
+++ b/src/content/stories/playing-it-safe.md
@@ -16,6 +16,7 @@ posts:
   furaffinity: https://www.furaffinity.net/view/57675502/
   inkbunny: https://inkbunny.net/s/3391838
   sofurry: https://www.sofurry.com/view/2161474
+  sofurrybeta: https://sofurrybeta.com/s/dmBBkvXm
   weasyl: https://www.weasyl.com/~badmanners/submissions/2401625/playing-it-safe
   twitter: https://x.com/BadManners__/status/1821526198150680589
   bluesky: https://bsky.app/profile/badmanners.xyz/post/3kz7gvvwyvt2c
diff --git a/src/content/stories/reaching-for-the-full-moon.md b/src/content/stories/reaching-for-the-full-moon.md
index 0e375bb..a09fc5d 100644
--- a/src/content/stories/reaching-for-the-full-moon.md
+++ b/src/content/stories/reaching-for-the-full-moon.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245847/reaching-for-the-full-moon-vore-story
   inkbunny: https://inkbunny.net/s/3010003
   sofurry: https://www.sofurry.com/view/1992360
+  sofurrybeta: https://sofurrybeta.com/s/V1YARWD1
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/rose-s-binge.md b/src/content/stories/rose-s-binge.md
index 7db3dcc..e4d907b 100644
--- a/src/content/stories/rose-s-binge.md
+++ b/src/content/stories/rose-s-binge.md
@@ -15,6 +15,7 @@ posts:
   furaffinity: https://www.furaffinity.net/view/57459926/
   inkbunny: https://inkbunny.net/s/3377727
   sofurry: https://www.sofurry.com/view/2156241
+  sofurrybeta: https://sofurrybeta.com/s/ZmM3QrW1
   weasyl: https://www.weasyl.com/~badmanners/submissions/2396279/c-rose-s-binge
   mastodon: https://meow.social/@BadManners/112827108738415986
 tags:
diff --git a/src/content/stories/ruffling-some-feathers.md b/src/content/stories/ruffling-some-feathers.md
index 90968e4..388335c 100644
--- a/src/content/stories/ruffling-some-feathers.md
+++ b/src/content/stories/ruffling-some-feathers.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245848/ruffling-some-feathers-vore-story
   inkbunny: https://inkbunny.net/s/3010004
   sofurry: https://www.sofurry.com/view/1992363
+  sofurrybeta: https://sofurrybeta.com/s/k1VYoGDn
 tags:
   - Muno
   - oral vore
diff --git a/src/content/stories/spontaneous-sleepover.md b/src/content/stories/spontaneous-sleepover.md
index ea9c5f1..c045913 100644
--- a/src/content/stories/spontaneous-sleepover.md
+++ b/src/content/stories/spontaneous-sleepover.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245831/spontaneous-sleepover-vore-story
   inkbunny: https://inkbunny.net/s/3009991
   sofurry: https://www.sofurry.com/view/1992340
+  sofurrybeta: https://sofurrybeta.com/s/rm8DNdqm
 tags:
   - tail vore
   - anthro predator
diff --git a/src/content/stories/taken-in.md b/src/content/stories/taken-in.md
index c588196..8c5ea84 100644
--- a/src/content/stories/taken-in.md
+++ b/src/content/stories/taken-in.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2345545/taken-in
   inkbunny: https://inkbunny.net/s/3231516
   sofurry: https://www.sofurry.com/view/2096828
+  sofurrybeta: https://sofurrybeta.com/s/B1QQYaz1
 tags:
   - Sam Brendan
   - feral predator
diff --git a/src/content/stories/tasting-high-consequences.md b/src/content/stories/tasting-high-consequences.md
index 6c62828..e169d28 100644
--- a/src/content/stories/tasting-high-consequences.md
+++ b/src/content/stories/tasting-high-consequences.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245857/tasting-high-consequences-vore-story
   inkbunny: https://inkbunny.net/s/3010016
   sofurry: https://www.sofurry.com/view/1992377
+  sofurrybeta: https://sofurrybeta.com/s/Oe5RNpMm
 tags:
   - oral vore
   - feral predator
diff --git a/src/content/stories/team-building.md b/src/content/stories/team-building.md
index 011f668..12c9a9d 100644
--- a/src/content/stories/team-building.md
+++ b/src/content/stories/team-building.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2341116/c-team-building
   inkbunny: https://inkbunny.net/s/3219382
   sofurry: https://www.sofurry.com/view/2091230
+  sofurrybeta: https://sofurrybeta.com/s/RnoXYox1
 tags:
   - cock vore
   - anal vore
diff --git a/src/content/stories/team-effort.md b/src/content/stories/team-effort.md
index a0b8747..3c11d9e 100644
--- a/src/content/stories/team-effort.md
+++ b/src/content/stories/team-effort.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2291370/r-team-effort-vore-story
   inkbunny: https://inkbunny.net/s/3088444
   sofurry: https://www.sofurry.com/view/2035089
+  sofurrybeta: https://sofurrybeta.com/s/ynZ7L8w1
 tags:
   - cock vore
   - anthro predator
diff --git a/src/content/stories/the-last-livestream.md b/src/content/stories/the-last-livestream.md
index 9998c86..62dd7a2 100644
--- a/src/content/stories/the-last-livestream.md
+++ b/src/content/stories/the-last-livestream.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245824/the-last-livestream-vore-story
   inkbunny: https://inkbunny.net/s/3009975
   sofurry: https://www.sofurry.com/view/1992325
+  sofurrybeta: https://sofurrybeta.com/s/B1QQYK71
 tags:
   - unbirth
   - anthro predator
diff --git a/src/content/stories/the-lost-of-the-marshes/bonus-1-quince-s-fantasy.md b/src/content/stories/the-lost-of-the-marshes/bonus-1-quince-s-fantasy.md
index 7a94dd6..6d7dece 100644
--- a/src/content/stories/the-lost-of-the-marshes/bonus-1-quince-s-fantasy.md
+++ b/src/content/stories/the-lost-of-the-marshes/bonus-1-quince-s-fantasy.md
@@ -17,6 +17,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245842/the-lost-of-the-marshes-bonus-quince-s-fantasy
   inkbunny: https://inkbunny.net/s/3009997
   sofurry: https://www.sofurry.com/view/1992350
+  sofurrybeta: https://sofurrybeta.com/s/k1VYoJGn
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-1.md b/src/content/stories/the-lost-of-the-marshes/chapter-1.md
index 660a607..64b1705 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-1.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-1.md
@@ -15,6 +15,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245800/the-lost-of-the-marshes-chapter-1-found
   inkbunny: https://inkbunny.net/s/3009918
   sofurry: https://www.sofurry.com/view/1992256
+  sofurrybeta: https://sofurrybeta.com/s/Rm0K4OKe
 tags:
   - oral vore
   - feral predator
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-10.md b/src/content/stories/the-lost-of-the-marshes/chapter-10.md
index 60325f1..086b422 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-10.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-10.md
@@ -17,6 +17,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245861/the-lost-of-the-marshes-chapter-10-memory
   inkbunny: https://inkbunny.net/s/3010039
   sofurry: https://www.sofurry.com/view/1992381
+  sofurrybeta: https://sofurrybeta.com/s/ve3QaApn
 tags:
   - oral vore
   - anal vore
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-11.md b/src/content/stories/the-lost-of-the-marshes/chapter-11.md
index 4a87c01..b5cdd71 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-11.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-11.md
@@ -15,6 +15,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2325367/the-lost-of-the-marshes-chapter-11-familiar
   inkbunny: https://inkbunny.net/s/3175040
   sofurry: https://www.sofurry.com/view/2072674
+  sofurrybeta: https://sofurrybeta.com/s/RnoXYo01
 tags:
   - oral vore
   - cock vore
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-2.md b/src/content/stories/the-lost-of-the-marshes/chapter-2.md
index 8da97a6..9696b31 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-2.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-2.md
@@ -17,6 +17,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245802/the-lost-of-the-marshes-chapter-2-trust
   inkbunny: https://inkbunny.net/s/3009921
   sofurry: https://www.sofurry.com/view/1992257
+  sofurrybeta: https://sofurrybeta.com/s/dePdgr5e
 tags:
   - oral vore
   - feral predator
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-3.md b/src/content/stories/the-lost-of-the-marshes/chapter-3.md
index 8c3f2df..f33488b 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-3.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-3.md
@@ -17,6 +17,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245804/the-lost-of-the-marshes-chapter-3-home
   inkbunny: https://inkbunny.net/s/3009926
   sofurry: https://www.sofurry.com/view/1992259
+  sofurrybeta: https://sofurrybeta.com/s/q1xJz8Zm
 tags:
   - oral vore
   - macro predator
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-4.md b/src/content/stories/the-lost-of-the-marshes/chapter-4.md
index 7076b78..482bf57 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-4.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-4.md
@@ -19,6 +19,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245805/the-lost-of-the-marshes-chapter-4-change
   inkbunny: https://inkbunny.net/s/3009927
   sofurry: https://www.sofurry.com/view/1992260
+  sofurrybeta: https://sofurrybeta.com/s/ynd4LA7n
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-5.md b/src/content/stories/the-lost-of-the-marshes/chapter-5.md
index bc1bee8..2e75939 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-5.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-5.md
@@ -19,6 +19,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245811/the-lost-of-the-marshes-chapter-5-intersection
   inkbunny: https://inkbunny.net/s/3009933
   sofurry: https://www.sofurry.com/view/1992297
+  sofurrybeta: https://sofurrybeta.com/s/zeRb9Nge
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-6.md b/src/content/stories/the-lost-of-the-marshes/chapter-6.md
index 3df13df..2237ff2 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-6.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-6.md
@@ -17,6 +17,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245813/the-lost-of-the-marshes-chapter-6-pleasure
   inkbunny: https://inkbunny.net/s/3009938
   sofurry: https://www.sofurry.com/view/1992302
+  sofurrybeta: https://sofurrybeta.com/s/J1O5Zqgm
 tags:
   - oral vore
   - unbirth
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-7.md b/src/content/stories/the-lost-of-the-marshes/chapter-7.md
index 5c6bbdd..4845b5e 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-7.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-7.md
@@ -17,6 +17,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245817/the-lost-of-the-marshes-chapter-7-honesty
   inkbunny: https://inkbunny.net/s/3009943
   sofurry: https://www.sofurry.com/view/1992307
+  sofurrybeta: https://sofurrybeta.com/s/GnDLVbjn
 tags:
   - oral vore
   - anal vore
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-8.md b/src/content/stories/the-lost-of-the-marshes/chapter-8.md
index 128390f..5f1b9f9 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-8.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-8.md
@@ -15,6 +15,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245827/the-lost-of-the-marshes-chapter-8-estranged
   inkbunny: https://inkbunny.net/s/3009983
   sofurry: https://www.sofurry.com/view/1992326
+  sofurrybeta: https://sofurrybeta.com/s/rn92NpQ1
 tags:
   - oral vore
   - anal vore
diff --git a/src/content/stories/the-lost-of-the-marshes/chapter-9.md b/src/content/stories/the-lost-of-the-marshes/chapter-9.md
index 9e8b18d..41bdc26 100644
--- a/src/content/stories/the-lost-of-the-marshes/chapter-9.md
+++ b/src/content/stories/the-lost-of-the-marshes/chapter-9.md
@@ -15,6 +15,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245844/the-lost-of-the-marshes-chapter-9-stuck
   inkbunny: https://inkbunny.net/s/3010000
   sofurry: https://www.sofurry.com/view/1992354
+  sofurrybeta: https://sofurrybeta.com/s/znJE5M7m
 tags:
   - oral vore
   - slit vore
diff --git a/src/content/stories/tiny-accident.md b/src/content/stories/tiny-accident.md
index cdc5c74..087ecab 100644
--- a/src/content/stories/tiny-accident.md
+++ b/src/content/stories/tiny-accident.md
@@ -15,6 +15,7 @@ posts:
   furaffinity: https://www.furaffinity.net/view/56026627/
   inkbunny: https://inkbunny.net/s/3283508
   sofurry: https://www.sofurry.com/view/2118138
+  sofurrybeta: https://sofurrybeta.com/s/0mvwLB0n
   weasyl: https://www.weasyl.com/~badmanners/submissions/2363560/tiny-accident
   bluesky: https://bsky.app/profile/badmanners.xyz/post/3kok52wijz32c
   mastodon: https://meow.social/@BadManners/112157812554023271
diff --git a/src/content/stories/tomo-moku.md b/src/content/stories/tomo-moku.md
index a95fc3d..4a0f471 100644
--- a/src/content/stories/tomo-moku.md
+++ b/src/content/stories/tomo-moku.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245854/tomo-moku-lipu-pi-moku-musi
   inkbunny: https://inkbunny.net/s/3010010
   sofurry: https://www.sofurry.com/view/1992374
+  sofurrybeta: https://sofurrybeta.com/s/4nAMWvAn
 tags:
   - oral vore
   - ambiguous predator
diff --git a/src/content/stories/trouble-sleeping.md b/src/content/stories/trouble-sleeping.md
index 20662b9..d319d47 100644
--- a/src/content/stories/trouble-sleeping.md
+++ b/src/content/stories/trouble-sleeping.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2305405/trouble-sleeping-vore-story
   inkbunny: https://inkbunny.net/s/3124166
   sofurry: https://www.sofurry.com/view/2051787
+  sofurrybeta: https://sofurrybeta.com/s/qmywZjQ1
 tags:
   - unbirth
   - anthro predator
diff --git a/src/content/stories/warped-friendship.md b/src/content/stories/warped-friendship.md
index 4603d7d..3e9e992 100644
--- a/src/content/stories/warped-friendship.md
+++ b/src/content/stories/warped-friendship.md
@@ -16,6 +16,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2291371/r-warped-friendship-vore-story
   inkbunny: https://inkbunny.net/s/3088450
   sofurry: https://www.sofurry.com/view/2035090
+  sofurrybeta: https://sofurrybeta.com/s/AnKr5QPm
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/stories/within-limits.md b/src/content/stories/within-limits.md
index 75b17d1..63da3ff 100644
--- a/src/content/stories/within-limits.md
+++ b/src/content/stories/within-limits.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2331157/c-within-limits
   inkbunny: https://inkbunny.net/s/3191950
   sofurry: https://www.sofurry.com/view/2079346
+  sofurrybeta: https://sofurrybeta.com/s/J1O5Z3km
 tags:
   - unbirth
   - cock vore
diff --git a/src/content/stories/woofer-exploration.md b/src/content/stories/woofer-exploration.md
index 7ae6766..16ce4a4 100644
--- a/src/content/stories/woofer-exploration.md
+++ b/src/content/stories/woofer-exploration.md
@@ -19,6 +19,7 @@ posts:
   furaffinity: https://www.furaffinity.net/view/57459921/
   inkbunny: https://inkbunny.net/s/3377722
   sofurry: https://www.sofurry.com/view/2156237
+  sofurrybeta: https://sofurrybeta.com/s/rm8DBRWm
   weasyl: https://www.weasyl.com/~badmanners/submissions/2396278/woofer-exploration
   mastodon: https://meow.social/@BadManners/112827104119035982
 tags:
diff --git a/src/content/stories/you-re-home.md b/src/content/stories/you-re-home.md
index c15de64..f06fd69 100644
--- a/src/content/stories/you-re-home.md
+++ b/src/content/stories/you-re-home.md
@@ -14,6 +14,7 @@ posts:
   weasyl: https://www.weasyl.com/~badmanners/submissions/2245815/you-re-home-vore-story
   inkbunny: https://inkbunny.net/s/3009942
   sofurry: https://www.sofurry.com/view/1992304
+  sofurrybeta: https://sofurrybeta.com/s/RnoXY6o1
 tags:
   - oral vore
   - anthro predator
diff --git a/src/content/tag-categories/6-vore-related-scenarios.yaml b/src/content/tag-categories/6-vore-related-scenarios.yaml
index 793ce9b..65c80f4 100644
--- a/src/content/tag-categories/6-vore-related-scenarios.yaml
+++ b/src/content/tag-categories/6-vore-related-scenarios.yaml
@@ -65,5 +65,9 @@ tags:
       - cock vore
   - name: soul vore
     description: Scenarios where predators consume a soul instead of their prey's body.
+  - name: endo trait theft
+    description: Scenarios where predators acquire traits from their prey without digestion.
+    related:
+      - transformation
   - name: Vore Day
     description: Stories created in commemoration of Vore Day, which is celebrated on August 8th, and/or are set in said day.
diff --git a/src/content/tag-categories/8-other-kinks.yaml b/src/content/tag-categories/8-other-kinks.yaml
index 0da71f6..10b0efe 100644
--- a/src/content/tag-categories/8-other-kinks.yaml
+++ b/src/content/tag-categories/8-other-kinks.yaml
@@ -9,6 +9,8 @@ tags:
       - object vore
   - name: transformation
     description: Scenarios where a character changes body and/or species.
+    related:
+      - endo trait theft
   - name: netorare
     description: Scenarios involving a character cheating on their partner with or without consent, and/or cuckoldry.
   - name: sizeplay
diff --git a/src/content/users/bad-manners.yaml b/src/content/users/bad-manners.yaml
index 20f6f6d..03cfcfb 100644
--- a/src/content/users/bad-manners.yaml
+++ b/src/content/users/bad-manners.yaml
@@ -10,6 +10,7 @@ links:
   sofurry:
     link: https://bad-manners.sofurry.com/
     username: Bad Manners
+  sofurrybeta: https://sofurrybeta.com/u/BadManners
   weasyl: https://www.weasyl.com/~BadManners
   twitter: https://twitter.com/BadManners__
   mastodon: https://meow.social/@BadManners
diff --git a/src/data/licenses.toml b/src/data/licenses.toml
index fb5dc6a..650d8c9 100644
--- a/src/data/licenses.toml
+++ b/src/data/licenses.toml
@@ -51,6 +51,34 @@ author = "Noto Project Authors"
 source = "https://github.com/notofonts/latin-greek-cyrillic"
 license = { name = "SIL Open Font License v1.1", url = "https://opensource.org/license/ofl-1-1" }
 
+[[attributions]]
+author = "Simple Icons"
+description = "Icons for third-party brands."
+type = "icons"
+source = "https://simpleicons.org"
+license = { name = "CC0 1.0 Universal", url = "https://creativecommons.org/publicdomain/zero/1.0/" }
+items = [
+  "Weasyl",
+]
+notes = """All third-party copyrights and trademarks belong to their respective owners, \
+and I'm not affiliated with any of them."""
+
+[[attributions]]
+description = "Edited icons for other websites."
+type = "icons"
+author = { name = "Bad Manners", url = "https://badmanners.xyz", email = "me@badmanners.xyz>" }
+source = "https://git.badmanners.xyz/badmanners/badmanners.xyz/src/branch/main/src/components/icons/brands"
+license = { name = "CC0 1.0 Universal", url = "https://creativecommons.org/publicdomain/zero/1.0/" }
+items = [
+  "Eka's Portal",
+  "Fur Affinity",
+  "Inkbunny",
+  "SoFurry",
+]
+notes = """Original icons edited for personal use and released under a permissive license.
+All third-party copyrights and trademarks belong to their respective owners, \
+and I'm not affiliated with any of them."""
+
 [[attributions]]
 author = "Font Awesome"
 description = "Generic icons."
diff --git a/src/i18n/index.ts b/src/i18n/index.ts
index 9456b57..9cd4e84 100644
--- a/src/i18n/index.ts
+++ b/src/i18n/index.ts
@@ -113,6 +113,30 @@ const UI_STRINGS = {
     en: "Click to reveal",
     tok: "Click to reveal summary in English",
   },
+  "published_content/syndication_see_also_on": {
+    en: "See also on...",
+    tok: "o lukin lon ma ante",
+  },
+  "published_content/syndication_eka": {
+    en: "Eka's Portal",
+    tok: "lipu Ikapoto",
+  },
+  "published_content/syndication_furaffinity": {
+    en: "Fur Affinity",
+    tok: "lipu Panapinisi",
+  },
+  "published_content/syndication_inkbunny": {
+    en: "Inkbunny",
+    tok: "lipu Inpani",
+  },
+  "published_content/syndication_sofurry": {
+    en: "SoFurry",
+    tok: "lipu Sopanli",
+  },
+  "published_content/syndication_weasyl": {
+    en: "Weasyl",
+    tok: "lipu Wise",
+  },
   // Story page-specific strings
   "story/return_to_stories": {
     en: "Return to stories",
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index 2cd6138..17d4707 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -7,9 +7,10 @@ import AgeRestrictedModal from "../components/AgeRestrictedModal.astro";
 type Props = {
   pageTitle: string;
   lang?: string;
+  isAgeRestricted: boolean;
 };
 
-const { pageTitle, lang = "en" } = Astro.props;
+const { pageTitle, lang = "en", isAgeRestricted } = Astro.props;
 ---
 
 <html lang={lang}>
@@ -38,6 +39,6 @@ const { pageTitle, lang = "en" } = Astro.props;
   <body>
     <slot />
     <DarkModeScript />
-    <AgeRestrictedModal />
+    {isAgeRestricted ? <AgeRestrictedModal /> : null}
   </body>
 </html>
diff --git a/src/layouts/GalleryLayout.astro b/src/layouts/GalleryLayout.astro
index ab1a9b2..28c0b79 100644
--- a/src/layouts/GalleryLayout.astro
+++ b/src/layouts/GalleryLayout.astro
@@ -17,18 +17,19 @@ import {
 
 type Props = {
   pageTitle: string;
+  isAgeRestricted?: boolean;
   enablePagefind?: boolean;
   class?: string;
 };
 
-const { pageTitle, enablePagefind, class: className } = Astro.props;
+const { pageTitle, enablePagefind, class: className, isAgeRestricted } = Astro.props;
 const logo = await getImage({ src: logoBM, width: 192 });
 const currentYear = new Date().getFullYear().toString();
 const isCurrentRoute = (path: string) =>
   Astro.url.pathname === path || (path !== "/" && Astro.url.pathname === `${path}/`);
 ---
 
-<BaseLayout pageTitle={pageTitle}>
+<BaseLayout pageTitle={pageTitle} isAgeRestricted={isAgeRestricted ?? true}>
   <Fragment slot="head">
     <meta property="og:title" content={pageTitle || "Bad Manners"} />
     <meta property="og:url" content={Astro.url} />
diff --git a/src/layouts/GameLayout.astro b/src/layouts/GameLayout.astro
index e5c76b3..75a76af 100644
--- a/src/layouts/GameLayout.astro
+++ b/src/layouts/GameLayout.astro
@@ -22,6 +22,7 @@ const relatedGames = (await getEntries(props.relatedGames)).filter((game) => !ga
   title={props.title}
   lang={props.lang}
   isDraft={props.isDraft}
+  isAgeRestricted={props.isAgeRestricted}
   pubDate={props.pubDate}
   description={props.description}
   summary={undefined}
diff --git a/src/layouts/PublishedContentLayout.astro b/src/layouts/PublishedContentLayout.astro
index 3480126..4b1a109 100644
--- a/src/layouts/PublishedContentLayout.astro
+++ b/src/layouts/PublishedContentLayout.astro
@@ -20,6 +20,7 @@ import {
   IconChevronRight,
   IconArrowUp,
 } from "../components/icons";
+import ExternalPosts from "../components/ExternalPosts.astro";
 
 interface RelatedContent {
   link: string;
@@ -31,6 +32,7 @@ type Props = {
   title: string;
   lang: Lang;
   isDraft: boolean;
+  isAgeRestricted: boolean;
   pubDate?: Date;
   description: string;
   summary?: string;
@@ -88,7 +90,7 @@ const returnTo = series
   : props.labelReturnTo.title;
 ---
 
-<BaseLayout pageTitle={props.title} lang={props.lang}>
+<BaseLayout pageTitle={props.title} lang={props.lang} isAgeRestricted={props.isAgeRestricted}>
   <Fragment slot="head">
     {props.isDraft ? <meta name="robots" content="noindex" /> : null}
     <meta property="og:title" content={props.title} data-pagefind-meta="title[content]" />
@@ -153,11 +155,11 @@ const returnTo = series
                 <a
                   href={props.prev.link}
                   rel="prev"
-                  class="text-link flex items-center justify-center border-r border-stone-400 px-1 py-3 underline dark:border-stone-600"
+                  class="h-entry u-url text-link flex items-center justify-center border-r border-stone-400 px-1 py-3 underline dark:border-stone-600"
                   aria-label={props.labelPreviousContent}
                 >
                   <IconChevronLeft width="1.25rem" height="1.25rem" />
-                  <span class="ml-1">{props.prev.title}</span>
+                  <span class="p-name ml-1">{props.prev.title}</span>
                 </a>
               ) : (
                 <div class="h-full border-r border-stone-400 dark:border-stone-600" aria-hidden="true" />
@@ -166,10 +168,10 @@ const returnTo = series
                 <a
                   href={props.next.link}
                   rel="next"
-                  class="text-link flex items-center justify-center px-1 py-3 underline"
+                  class="h-entry u-url text-link flex items-center justify-center px-1 py-3 underline"
                   aria-label={props.labelNextContent}
                 >
-                  <span class="mr-1">{props.next.title}</span>
+                  <span class="p-name mr-1">{props.next.title}</span>
                   <IconChevronRight width="1.25rem" height="1.25rem" />
                 </a>
               ) : (
@@ -376,6 +378,7 @@ const returnTo = series
           </section>
         ) : null
       }
+      <ExternalPosts lang={props.lang} posts={props.posts} />
       {props.posts.mastodon ? <MastodonComments lang={props.lang} {...props.posts.mastodon} /> : null}
     </main>
     <div
diff --git a/src/layouts/StoryLayout.astro b/src/layouts/StoryLayout.astro
index 9477911..33e199d 100644
--- a/src/layouts/StoryLayout.astro
+++ b/src/layouts/StoryLayout.astro
@@ -27,6 +27,7 @@ const wordCount = props.wordCount?.toString();
   title={props.title}
   lang={props.lang}
   isDraft={props.isDraft}
+  isAgeRestricted={props.isAgeRestricted}
   pubDate={props.pubDate}
   description={props.description}
   summary={props.summary}
diff --git a/src/pages/index.astro b/src/pages/index.astro
index b3733c6..ebcb7a5 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -79,8 +79,7 @@ const latestItems: LatestItemsEntry[] = await Promise.all(
   <hr class="mb-3 ml-[2px] mt-2 h-[4px] max-w-xs rounded-sm bg-stone-800 dark:bg-stone-100" />
   <div class="p-summary">
     <p class="my-4">
-      Glad to see you here. You can expect lots of safe vore/endosoma ahead. Use the navigation menu to navigate through
-      my content.
+      Hey there, welcome to my corner of the Internet! You can expect lots of safe vore/endosoma ahead.
     </p>
     <ul class="list-disc pl-8">
       <li><a class="text-link underline" href="/stories/1">Read my stories!</a></li>
diff --git a/src/utils/get_website_link_for_user.ts b/src/utils/get_website_link_for_user.ts
index 0de0c4f..9ee867b 100644
--- a/src/utils/get_website_link_for_user.ts
+++ b/src/utils/get_website_link_for_user.ts
@@ -80,6 +80,13 @@ export function getWebsiteLinkForUser(
         return `ib!${getUserDataForWebsite(user, "inkbunny").username}`;
       }
       break;
+    case "sofurrybeta":
+      if ("sofurrybeta" in links) {
+        return `@${links.sofurrybeta!.username}`;
+      } else if ("sofurry" in links) {
+        return `[${links.sofurry!.username}](${links.sofurry!.link})`;
+      }
+      break;
     case "twitter":
       if ("twitter" in links) {
         return `@${getUserDataForWebsite(user, "twitter").username}`;
diff --git a/src/utils/qualify_local_urls_in_markdown.ts b/src/utils/qualify_local_urls_in_markdown.ts
index 002bb08..94004ae 100644
--- a/src/utils/qualify_local_urls_in_markdown.ts
+++ b/src/utils/qualify_local_urls_in_markdown.ts
@@ -1,5 +1,5 @@
 import { getCollection, getEntry } from "astro:content";
-import type { Lang, PostWebsite } from "../content/config";
+import type { Lang, PostWebsite, UserWebsite } from "../content/config";
 import { getWebsiteLinkForUser } from "./get_website_link_for_user";
 import { getUsernameForLang } from "./get_username_for_lang";
 
@@ -56,8 +56,8 @@ export async function qualifyLocalURLsInMarkdown(originalText: string, lang: Lan
           if (!story) {
             throw new Error(`Couldn't find story with slug "${slug}"`);
           }
-          if (typeof website === "string" && story.data.posts[website]?.link) {
-            replacements.push(`[${text}](${story.data.posts[website].link})`);
+          if (typeof website === "string" && story.data.posts[website as PostWebsite]?.link) {
+            replacements.push(`[${text}](${story.data.posts[website as PostWebsite]!.link})`);
             continue;
           }
           break;
@@ -66,8 +66,8 @@ export async function qualifyLocalURLsInMarkdown(originalText: string, lang: Lan
           if (!game) {
             throw new Error(`Couldn't find game with slug "${slug}"`);
           }
-          if (typeof website === "string" && game.data.posts[website]?.link) {
-            replacements.push(`[${text}](${game.data.posts[website].link})`);
+          if (typeof website === "string" && game.data.posts[website as PostWebsite]?.link) {
+            replacements.push(`[${text}](${game.data.posts[website as PostWebsite]!.link})`);
             continue;
           }
           break;
@@ -78,8 +78,8 @@ export async function qualifyLocalURLsInMarkdown(originalText: string, lang: Lan
           }
           // If there's a label in the link, use that if possible
           if (text) {
-            if (typeof website === "string" && user.data.links[website]?.link) {
-              replacements.push(`[${text}](${user.data.links[website].link})`);
+            if (typeof website === "string" && user.data.links[website as UserWebsite]?.link) {
+              replacements.push(`[${text}](${user.data.links[website as UserWebsite]!.link})`);
               continue;
             } else if (user.data.preferredLink) {
               replacements.push(`[${text}](${user.data.links[user.data.preferredLink]!.link})`);
@@ -87,7 +87,9 @@ export async function qualifyLocalURLsInMarkdown(originalText: string, lang: Lan
             }
           }
           // Otherwise (i.e. label is empty), use the username for the website
-          replacements.push(getWebsiteLinkForUser(user, website, (user) => getUsernameForLang(user, lang)));
+          replacements.push(
+            getWebsiteLinkForUser(user, website as UserWebsite, (user) => getUsernameForLang(user, lang)),
+          );
           continue;
         default:
           const unknown: never = contentPrefix;