diff --git a/web/sections/CarouselItems.tsx b/web/sections/CarouselItems.tsx
index c818c9d..b600dbf 100644
--- a/web/sections/CarouselItems.tsx
+++ b/web/sections/CarouselItems.tsx
@@ -5,7 +5,7 @@ import { Input } from '@/components/ui/input';
import { useClient } from 'hooks/useClient';
import { MediaPicker } from '../MediaPicker';
import { readableError } from '../errors';
-import { thumbUrl } from '../thumbnail';
+import { mediaThumbUrl } from '../thumbnail';
/**
* One carousel's contents: what is in it, in what order, and what each picture is called.
@@ -151,7 +151,7 @@ export const CarouselItems = ({ carouselId, onChanged }: { carouselId: number; o
and a browser cannot show the original at all.
*/}
({ section }: { section: Su
{photos.map((photo) => (
-

+
{photo.name}
diff --git a/web/thumbnail.ts b/web/thumbnail.ts
index f2112b1..c2529b9 100644
--- a/web/thumbnail.ts
+++ b/web/thumbnail.ts
@@ -48,3 +48,20 @@ export const originalUrl = (path: string, width: number): string => {
const encoded = path.split('/').map(encodeURIComponent).join('/');
return `/api/fofos-admin/original/${encoded}?width=${Math.round(width)}&token=${encodeURIComponent(token)}`;
};
+
+/** Extensions av-club treats as video. The same list the site's own `kindFor` uses. */
+const VIDEO = /\.(mp4|mov|webm|m4v|avi|mkv)$/i;
+
+/**
+ * A thumbnail for anything in the media store, picture or video.
+ *
+ * A video has no width rungs — `poster-448.webp` and friends are cut from a still, and asking for
+ * `320.webp` gets a 404 and a broken image. Every grid in this panel was doing exactly that, so a
+ * carousel holding a video showed a broken tile with no clue why.
+ *
+ * `posterUrl` already existed for this and nothing called it. One helper that decides from the
+ * extension, so a screen showing mixed media does not have to know the difference — which is the
+ * whole point, since a carousel is explicitly allowed to hold both.
+ */
+export const mediaThumbUrl = (path: string, width: 256 | 320 | 480 | 640 | 960 | 1280 = 320): string =>
+ VIDEO.test(path) ? posterUrl(path) : thumbUrl(path, width);