Index: src/routes/circle.js
===================================================================
--- src/routes/circle.js	(revision e091add199b4b576c0f965ef2bbe7a85b50fea81)
+++ src/routes/circle.js	(revision 5f3f9ec002fdbf1dddd640956bd34915e10695df)
@@ -19,7 +19,13 @@
   try { return s ? JSON.parse(s) : []; } catch { return []; }
 }
-function mediaImage(media_json) {
+// The cover image + (separately) a cover video from a remote note's media. NEVER use a video/audio
+// item as the cover image — that produced a broken <img> for an animated cover that federated as an
+// MP4 (the video becomes a <video> instead).
+function coverMedia(media_json) {
   const media = safeJson(media_json).map((m) => ({ ...m, url: safeUrl(m.url) })).filter((m) => m.url);
-  return media.find((m) => /image/i.test(m.type || '')) || media[0] || null;
+  const video = media.find((m) => /video/i.test(m.type || '')) || null;
+  const image = media.find((m) => /image/i.test(m.type || ''))
+    || (media[0] && !/(video|audio)/i.test(media[0].type || '') ? media[0] : null);
+  return { image, video };
 }
 function htmlToText(html) {
@@ -37,5 +43,5 @@
     const titleM = (r.content || '').match(/^\s*<p>\s*<strong>([\s\S]*?)<\/strong>/i);
     const realTitle = titleM ? htmlToText(titleM[1]).trim() : '';
-    const image = mediaImage(r.media_json);
+    const cover = coverMedia(r.media_json);
     const name = r.author_name || r.author_handle || 'Onbekend';
     return {
@@ -46,5 +52,6 @@
         : (text ? (text.length > 90 ? text.slice(0, 90) + '…' : text) : name),
       excerpt: '',
-      cover_image_url: image ? image.url : null,
+      cover_image_url: cover.image ? cover.image.url : null,
+      cover_video_url: cover.video ? cover.video.url : null,
       published_at: r.published,
       created_at: r.published,
Index: src/views/partials/post-card.ejs
===================================================================
--- src/views/partials/post-card.ejs	(revision e091add199b4b576c0f965ef2bbe7a85b50fea81)
+++ src/views/partials/post-card.ejs	(revision 5f3f9ec002fdbf1dddd640956bd34915e10695df)
@@ -16,5 +16,5 @@
 const _ext       = !!_external;
 const _src       = post.source_name || '';
-const _hasCover  = !!post.cover_image_url;
+const _hasCover  = !!post.cover_image_url || !!post.cover_video_url;
 const _typeLabel = (post.type && post.type !== 'overig' && post.type !== 'post') ? post.type : '';
 const _isPinned  = !!post.pinned;
@@ -49,8 +49,9 @@
        <% if (_ext) { %>target="_blank" rel="noopener"<% } else { %>hx-get="<%= _href %>?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="<%= _href %>" hx-indicator="#pcms-loading"<% } %>
        aria-label="<%= post.title || '(zonder titel)' %>" tabindex="-1">
-      <img src="<%= thumb(post.cover_image_url, 480) %>"
+      <% if (post.cover_image_url) { %><img src="<%= thumb(post.cover_image_url, 480) %>"
            srcset="<%= thumb(post.cover_image_url, 320) %> 320w, <%= thumb(post.cover_image_url, 640) %> 640w, <%= thumb(post.cover_image_url, 1280) %> 1280w"
            sizes="(min-width: 768px) 120px, 100vw"
            alt="" loading="lazy" decoding="async"<% if (post.cover_video_url) { %> data-ios-mp4="<%= post.cover_video_url %>"<% } %>>
+      <% } else if (post.cover_video_url) { %><video src="<%= post.cover_video_url %>" autoplay loop muted playsinline></video><% } %>
       <% if (post.nsfw) { %><span class="nsfw-veil"><span class="nsfw-veil-label">🔞 <%= post.content_warning || t('post.nsfw_warning') %></span><span class="nsfw-veil-btn"><%= t('post.nsfw_show') %></span></span><% } %>
     </a>
Index: src/views/partials/post-tile.ejs
===================================================================
--- src/views/partials/post-tile.ejs	(revision e091add199b4b576c0f965ef2bbe7a85b50fea81)
+++ src/views/partials/post-tile.ejs	(revision 5f3f9ec002fdbf1dddd640956bd34915e10695df)
@@ -6,5 +6,5 @@
 const _isPinned = !!post.pinned;
 const _isBoost = !!post.isBoost;
-const _hasCover = !!post.cover_image_url;
+const _hasCover = !!post.cover_image_url || !!post.cover_video_url;
 const _typeLabel = (post.type && post.type !== 'post') ? post.type : '';
 const _src = post.source_name || '';   // bron-site (cirkel-feed: van welke site komt deze post)
@@ -19,5 +19,5 @@
    <% if (_ext) { %>target="_blank" rel="noopener"<% } else { %>hx-get="<%= _href %>?partial=1" hx-target="#pcms-main" hx-swap="innerHTML" hx-push-url="<%= _href %>" hx-indicator="#pcms-loading"<% } %>>
 
-  <% if (_hasCover) { %><img class="grid-tile-img" src="<%= thumb(post.cover_image_url, 480) %>" alt="" loading="lazy" decoding="async"<% if (post.cover_video_url) { %> data-ios-mp4="<%= post.cover_video_url %>"<% } %>><% } %>
+  <% if (post.cover_image_url) { %><img class="grid-tile-img" src="<%= thumb(post.cover_image_url, 480) %>" alt="" loading="lazy" decoding="async"<% if (post.cover_video_url) { %> data-ios-mp4="<%= post.cover_video_url %>"<% } %>><% } else if (post.cover_video_url) { %><video class="grid-tile-img" src="<%= post.cover_video_url %>" autoplay loop muted playsinline></video><% } %>
 
   <% if (_typeLabel) { %>
