diff --git a/examples/game.md b/examples/game.md
index bdc1e52..b07c1ad 100644
--- a/examples/game.md
+++ b/examples/game.md
@@ -12,6 +12,7 @@ description: |
   Some funny text.
 # descriptionPlaintext: >
 #   Some funny text.
+platforms: [web, windows, linux, macos, android, ios]
 # mastodonPost:
 #   instance: meow.social
 #   user: BadManners
diff --git a/examples/user.yaml b/examples/user.yaml
index 044d44d..b180ede 100644
--- a/examples/user.yaml
+++ b/examples/user.yaml
@@ -9,7 +9,7 @@ links:
   furaffinity:
     - https://www.furaffinity.net/user/NamelessUser
     - Nameless_User
-  inkbunny: https://inkbunny.net/NamelessManners
+  inkbunny: https://inkbunny.net/NamelessUser
   sofurry:
     - https://nameless-user.sofurry.com/
     - Nameless User
diff --git a/package-lock.json b/package-lock.json
index 9ba452b..12df10b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "gallery-badmanners-xyz",
-  "version": "1.3.0",
+  "version": "1.3.1",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "gallery-badmanners-xyz",
-      "version": "1.3.0",
+      "version": "1.3.1",
       "dependencies": {
         "@astrojs/check": "^0.5.10",
         "@astrojs/rss": "^4.0.5",
diff --git a/package.json b/package.json
index 9744152..4848f28 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "gallery-badmanners-xyz",
   "type": "module",
-  "version": "1.3.0",
+  "version": "1.3.1",
   "scripts": {
     "dev": "astro dev",
     "start": "astro dev",
diff --git a/src/components/WidthSlotSwitcher.astro b/src/components/WidthSlotSwitcher.astro
new file mode 100644
index 0000000..eb7c03c
--- /dev/null
+++ b/src/components/WidthSlotSwitcher.astro
@@ -0,0 +1,36 @@
+---
+type Props = {
+  breakpoint: number;
+};
+
+const { breakpoint } = Astro.props;
+---
+
+<div id="slot-switch" data-breakpoint={breakpoint}></div>
+<template id="slot-switch-big">
+  <slot />
+</template>
+<template id="slot-switch-small">
+  <slot />
+</template>
+
+<script>
+  const slotSwitch = document.querySelector("div#slot-switch") as HTMLDivElement;
+  const breakpointAttribute = slotSwitch.getAttribute("data-breakpoint");
+  if (breakpointAttribute && !isNaN(parseInt(breakpointAttribute))) {
+    const breakpoint = parseInt(breakpointAttribute);
+    const slotSwitchBig = document.querySelector("template#slot-switch-big") as HTMLTemplateElement;
+    const slotSwitchSmall = document.querySelector("template#slot-switch-small") as HTMLTemplateElement;
+    let displayBig: boolean | null = null;
+    function handleResize() {
+      const newDisplayBig = window.innerWidth >= breakpoint;
+      if (newDisplayBig !== displayBig) {
+        displayBig = newDisplayBig;
+        const template = displayBig ? slotSwitchBig : slotSwitchSmall;
+        slotSwitch.replaceChildren(template.content.cloneNode(true));
+      }
+    }
+    window.addEventListener("resize", handleResize);
+    handleResize();
+  }
+</script>
diff --git a/src/content/config.ts b/src/content/config.ts
index 7f931ae..c0e2c49 100644
--- a/src/content/config.ts
+++ b/src/content/config.ts
@@ -22,6 +22,7 @@ const refineCopyrightedCharacters = (value: Record<string, any>) => !("" in valu
 
 const lang = z.enum(["eng", "tok"]).default("eng");
 const website = z.enum(WEBSITE_LIST);
+const platform = z.enum(["web", "windows", "linux", "macos", "android", "ios"]);
 const mastodonPost = z.object({
   instance: z.string(),
   user: z.string(),
@@ -48,7 +49,7 @@ const storiesCollection = defineCollection({
       authors: z
         .union([reference("users"), z.array(reference("users"))])
         .default("bad-manners")
-        .refine(refineAuthors, "authors cannot be empty"),
+        .refine(refineAuthors, `"authors" cannot be empty`),
       descriptionPlaintext: z.string().optional(),
       summary: z.string().optional(),
       thumbnail: image().optional(),
@@ -60,10 +61,7 @@ const storiesCollection = defineCollection({
       copyrightedCharacters: z
         .record(z.string(), reference("users"))
         .default({})
-        .refine(
-          refineCopyrightedCharacters,
-          "copyrightedCharacters cannot have an empty catch-all key with other keys",
-        ),
+        .refine(refineCopyrightedCharacters, `"copyrightedCharacters" cannot mix empty catch-all key with other keys`),
       lang,
       prev: reference("stories").nullish(),
       next: reference("stories").nullish(),
@@ -88,19 +86,17 @@ const gamesCollection = defineCollection({
       authors: z
         .union([reference("users"), z.array(reference("users"))])
         .default("bad-manners")
-        .refine(refineAuthors, "authors cannot be empty"),
+        .refine(refineAuthors, `"authors" cannot be empty`),
       descriptionPlaintext: z.string().optional(),
       thumbnail: image().optional(),
       thumbnailWidth: z.number().int().optional(),
       thumbnailHeight: z.number().int().optional(),
       series: reference("series").optional(),
+      platforms: z.array(platform).refine((platforms) => platforms.length > 0, `"platforms" cannot be empty`),
       copyrightedCharacters: z
         .record(z.string(), reference("users"))
         .default({})
-        .refine(
-          refineCopyrightedCharacters,
-          "copyrightedCharacters cannot have an empty catch-all key with other keys",
-        ),
+        .refine(refineCopyrightedCharacters, `"copyrightedCharacters" cannot mix empty catch-all key with other keys`),
       lang,
       relatedStories: z.array(reference("stories")).default([]),
       relatedGames: z.array(reference("games")).default([]),
@@ -125,7 +121,7 @@ const usersCollection = defineCollection({
       .refine(
         ({ links, preferredLink }) => !preferredLink || preferredLink in links,
         ({ preferredLink }) => ({
-          message: `"${preferredLink}" not defined in links`,
+          message: `"${preferredLink}" not defined in "links"`,
           path: ["preferredLink"],
         }),
       ),
@@ -136,7 +132,7 @@ const seriesCollection = defineCollection({
   schema: z.object({
     // Required
     name: z.string(),
-    url: z.string().regex(localUrlRegex, "must be a local URL"),
+    url: z.string().regex(localUrlRegex, `"url" must be a local URL`),
   }),
 });
 
@@ -149,7 +145,7 @@ const tagCategoriesCollection = defineCollection({
     tags: z.array(
       z.union([
         z.string(),
-        z.record(lang, z.string()).refine((tag) => "eng" in tag, 'Object-formatted tag must have an "eng" key'),
+        z.record(lang, z.string()).refine((tag) => "eng" in tag, `object-formatted tag must have an "eng" key`),
       ]),
     ),
   }),
diff --git a/src/content/games/crossing-over.md b/src/content/games/crossing-over.md
index 2d169b3..348a579 100644
--- a/src/content/games/crossing-over.md
+++ b/src/content/games/crossing-over.md
@@ -26,6 +26,12 @@ descriptionPlaintext: >
   An original soundtrack with 9 exclusive songs;
   A challenging physics-based fishing minigame with scaling difficulty;
   And a special cutscene...
+platforms:
+  - web
+  - windows
+  - linux
+  - macos
+  - android
 mastodonPost:
   instance: meow.social
   user: BadManners
diff --git a/src/i18n/index.ts b/src/i18n/index.ts
index bb029f9..f11fa95 100644
--- a/src/i18n/index.ts
+++ b/src/i18n/index.ts
@@ -91,6 +91,9 @@ export const UI_STRINGS: Record<string, TranslationRecord> = {
   "story/requested_by": {
     eng: (arg: string) => `Requested by ${arg}`,
   },
+  "story/draft_warning": {
+    eng: "DRAFT VERSION – DO NOT REDISTRIBUTE",
+  },
   "characters/characters_are_copyrighted_by": {
     eng: (owner: string, charactersList: string[]) =>
       charactersList.length == 1
@@ -100,6 +103,32 @@ export const UI_STRINGS: Record<string, TranslationRecord> = {
   "characters/all_characters_are_copyrighted_by": {
     eng: (owner: string) => `All characters are © ${owner}`,
   },
+  "game/platforms": {
+    eng: (platforms: string[]) => {
+      const translatedPlatforms = platforms.map(
+        (platform) => (UI_STRINGS[`game/platform_${platform}`]?.eng as string | undefined) || platform,
+      );
+      return `A game for ${(UI_STRINGS["util/join_names"]!.eng as (arg: string[]) => string)(translatedPlatforms)}`;
+    },
+  },
+  "game/platform_web": {
+    eng: "web browsers",
+  },
+  "game/platform_windows": {
+    eng: "Windows",
+  },
+  "game/platform_linux": {
+    eng: "Linux",
+  },
+  "game/platform_macos": {
+    eng: "macOS",
+  },
+  "game/platform_android": {
+    eng: "Android",
+  },
+  "game/platform_ios": {
+    eng: "iOS",
+  },
 };
 
 export function t(lang: Lang, stringOrSource: string | TranslationRecord, ...args: any[]): string {
diff --git a/src/layouts/GalleryLayout.astro b/src/layouts/GalleryLayout.astro
index 7583b74..0cb23b6 100644
--- a/src/layouts/GalleryLayout.astro
+++ b/src/layouts/GalleryLayout.astro
@@ -70,7 +70,10 @@ const logo = await getImage({ src: logoBM, width: 192 });
         </button>
       </div>
     </div>
-    <main class="ml-0 max-w-6xl px-2 pb-12 pt-4 md:ml-60 md:px-4 print:pb-0" data-pagefind-body={enablePagefind ? "" : undefined}>
+    <main
+      class="ml-0 max-w-6xl px-2 pb-12 pt-4 md:ml-60 md:px-4 print:pb-0"
+      data-pagefind-body={enablePagefind ? "" : undefined}
+    >
       <slot />
     </main>
   </div>
diff --git a/src/layouts/GameLayout.astro b/src/layouts/GameLayout.astro
index 3db7952..96c443b 100644
--- a/src/layouts/GameLayout.astro
+++ b/src/layouts/GameLayout.astro
@@ -61,10 +61,18 @@ const thumbnail =
     <meta property="og:title" content={props.title} data-pagefind-meta="title[content]" />
     <meta property="og:description" content={props.contentWarning} />
     <meta property="og:url" content={Astro.url} data-pagefind-meta="url[content]" />
-    {thumbnail ? <Fragment>
-      <meta content={thumbnail.src} property="og:image" data-pagefind-meta="image[content]" />
-      <meta property="og:image:alt" content={`Cover art for ${props.title}`} data-pagefind-meta="image_alt[content]" />
-    </Fragment> : null}
+    {
+      thumbnail ? (
+        <Fragment>
+          <meta content={thumbnail.src} property="og:image" data-pagefind-meta="image[content]" />
+          <meta
+            property="og:image:alt"
+            content={`Cover art for ${props.title}`}
+            data-pagefind-meta="image_alt[content]"
+          />
+        </Fragment>
+      ) : null
+    }
     <meta name="theme-color" content="#7DD05A" data-react-helmet="true" />
   </Fragment>
   <div
@@ -134,10 +142,13 @@ const thumbnail =
         <Authors lang={props.lang}>
           {authors.map((author) => <UserComponent lang={props.lang} user={author} />)}
         </Authors>
+        <div id="platforms">
+          <p>{t(props.lang, "game/platforms", props.platforms)}</p>
+        </div>
         {
           props.isDraft ? (
             <p id="draft-warning" class="py-2 text-center text-2xl font-semibold not-italic text-red-600">
-              DRAFT VERSION &ndash; DO NOT REDISTRIBUTE
+              {t(props.lang, "story/draft_warning")}
             </p>
           ) : null
         }
@@ -174,7 +185,7 @@ const thumbnail =
             id="draft-warning-bottom"
             class="py-2 text-center font-serif text-2xl font-semibold not-italic text-red-600"
           >
-            DRAFT VERSION &ndash; DO NOT REDISTRIBUTE
+            {t(props.lang, "story/draft_warning")}
           </p>
         ) : (
           <p
@@ -195,7 +206,7 @@ const thumbnail =
       }
       <section id="description" class="px-2 font-serif" aria-describedby="title-description">
         <h2 id="title-description" class="py-2 font-serif text-xl font-semibold text-stone-800 dark:text-stone-100">
-          Description
+          {t(props.lang, "story/description")}
         </h2>
         <Prose>
           <Markdown of={props.description} />
@@ -208,7 +219,7 @@ const thumbnail =
             ><path
               d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"
             ></path></svg
-          ><span>To top</span></a
+          ><span>{t(props.lang, "story/to_top")}</span></a
         >
       </div>
       <section id="tags" aria-describedby="title-tags" class="my-5">
diff --git a/src/layouts/StoryLayout.astro b/src/layouts/StoryLayout.astro
index 195c404..a86cbe1 100644
--- a/src/layouts/StoryLayout.astro
+++ b/src/layouts/StoryLayout.astro
@@ -71,10 +71,18 @@ const thumbnail =
     <meta property="og:title" content={props.title} data-pagefind-meta="title[content]" />
     <meta property="og:description" content={`Word count: ${props.wordCount}. ${props.contentWarning}`} />
     <meta property="og:url" content={Astro.url} data-pagefind-meta="url[content]" />
-    {thumbnail ? <Fragment>
-      <meta content={thumbnail.src} property="og:image" data-pagefind-meta="image[content]" />
-      <meta property="og:image:alt" content={`Cover art for ${props.shortTitle || props.title}`} data-pagefind-meta="image_alt[content]" />
-    </Fragment> : null}
+    {
+      thumbnail ? (
+        <Fragment>
+          <meta content={thumbnail.src} property="og:image" data-pagefind-meta="image[content]" />
+          <meta
+            property="og:image:alt"
+            content={`Cover art for ${props.shortTitle || props.title}`}
+            data-pagefind-meta="image_alt[content]"
+          />
+        </Fragment>
+      ) : null
+    }
     <meta name="theme-color" content="#7DD05A" data-react-helmet="true" />
   </Fragment>
   <div
@@ -184,7 +192,7 @@ const thumbnail =
         {
           props.isDraft ? (
             <p id="draft-warning" class="py-2 text-center text-2xl font-semibold not-italic text-red-600">
-              DRAFT VERSION &ndash; DO NOT REDISTRIBUTE
+              {t(props.lang, "story/draft_warning")}
             </p>
           ) : null
         }
@@ -236,7 +244,7 @@ const thumbnail =
             id="draft-warning-bottom"
             class="py-2 text-center font-serif text-2xl font-semibold not-italic text-red-600"
           >
-            DRAFT VERSION &ndash; DO NOT REDISTRIBUTE
+            {t(props.lang, "story/draft_warning")}
           </p>
         ) : (
           <p
diff --git a/src/pages/feed.xml.ts b/src/pages/feed.xml.ts
index 9539c75..e4e91f9 100644
--- a/src/pages/feed.xml.ts
+++ b/src/pages/feed.xml.ts
@@ -83,9 +83,10 @@ export const GET: APIRoute = async ({ site }) => {
           title: `New game! "${data.title}"`,
           pubDate: toNoonUTCDate(data.pubDate),
           link: `/games/${slug}`,
-          description: `${data.contentWarning} ${data.descriptionPlaintext || data.description}`
-            .replaceAll(/[\n ]+/g, " ")
-            .trim(),
+          description:
+            `${t(data.lang, "game/platforms", data.platforms)}. ${data.contentWarning} ${data.descriptionPlaintext || data.description}`
+              .replaceAll(/[\n ]+/g, " ")
+              .trim(),
           categories: ["game"],
           content: sanitizeHtml(
             `<h1>${data.title}</h1>` +
@@ -101,6 +102,7 @@ export const GET: APIRoute = async ({ site }) => {
                   );
                 }),
               )}</p>` +
+              `<hr><p>${t(data.lang, "game/platforms", data.platforms)}</p>` +
               `<hr><p><em>${data.contentWarning.trim()}</em></p>` +
               `<hr>${tinyDecode(await marked(body))}` +
               `<hr>${tinyDecode(await marked(data.description))}`,
diff --git a/src/pages/search.astro b/src/pages/search.astro
index 9ca1bf5..8556985 100644
--- a/src/pages/search.astro
+++ b/src/pages/search.astro
@@ -1,11 +1,10 @@
 ---
 import SearchComponent from "astro-pagefind/components/Search";
 import GalleryLayout from "../layouts/GalleryLayout.astro";
-
 ---
 
 <GalleryLayout pageTitle="Search">
   <meta slot="head-description" property="og:description" content="Bad Manners || Search" />
   <h1 class="m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">Search</h1>
-  <SearchComponent id="search" className="my-4 pagefind-ui" />
-</GalleryLayout>
\ No newline at end of file
+  <SearchComponent id="search" className="pagefind-ui my-4" />
+</GalleryLayout>
diff --git a/src/pages/stories/the-lost-of-the-marshes.astro b/src/pages/stories/the-lost-of-the-marshes.astro
index 69d33e4..b57997c 100644
--- a/src/pages/stories/the-lost-of-the-marshes.astro
+++ b/src/pages/stories/the-lost-of-the-marshes.astro
@@ -16,11 +16,21 @@ const mainChaptersWithSummaries = mainChapters.filter((story) => story.data.summ
 ---
 
 <GalleryLayout pageTitle={series.data.name} enablePagefind={true}>
-  <meta slot="head-description" property="og:description" content="Bad Manners || The story of Quince, Nikili, and Suu."/>
+  <meta
+    slot="head-description"
+    property="og:description"
+    content="Bad Manners || The story of Quince, Nikili, and Suu."
+  />
   <h1 class="m-2 text-2xl font-semibold text-stone-800 dark:text-stone-100">{series.data.name}</h1>
   <p class="my-4">This is the main hub for the story of Quince, Nikili, and Suu, as well as all bonus content.</p>
   <section class="my-2" aria-labelledby="main-chapters">
-    <h2 id="main-chapters" class="p-2 text-xl font-semibold text-stone-800 dark:text-stone-100" data-pagefind-meta="type:series">Main chapters</h2>
+    <h2
+      id="main-chapters"
+      class="p-2 text-xl font-semibold text-stone-800 dark:text-stone-100"
+      data-pagefind-meta="type:series"
+    >
+      Main chapters
+    </h2>
     <details
       class="mx-3 mb-6 mt-1 rounded-lg border border-stone-400 bg-stone-300 dark:border-stone-500 dark:bg-stone-700"
     >
diff --git a/src/pages/tags.astro b/src/pages/tags.astro
index 4864988..81f3611 100644
--- a/src/pages/tags.astro
+++ b/src/pages/tags.astro
@@ -84,7 +84,7 @@ if (uncategorizedTagsSet.size > 0) {
 
 <GalleryLayout pageTitle="Tags">
   <meta
-    property="og:description"  
+    property="og:description"
     slot="head-description"
     content="Bad Manners || Find all content with a specific tag."
   />
diff --git a/src/styles/base.css b/src/styles/base.css
index b21b740..da6dd59 100644
--- a/src/styles/base.css
+++ b/src/styles/base.css
@@ -3,7 +3,8 @@
 @tailwind utilities;
 
 @layer components {
-  .text-link, .pagefind-ui .pagefind-ui__result-link {
+  .text-link,
+  .pagefind-ui .pagefind-ui__result-link {
     @apply text-stone-800 hover:text-bm-500 focus:text-bm-500 dark:text-zinc-300 dark:hover:text-bm-400 dark:focus:text-bm-400;
   }