Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 15f1cb57a2792167f63aa562ececc415c9943088)
+++ src/services/ActivityPubService.js	(revision 2a1044514fb6dd87ad43ab100954639ef3720d11)
@@ -2410,12 +2410,4 @@
     return `<p><video controls playsinline preload="metadata"${poster} src="${a.url}"></video></p>`;
   }).join('');
-  // The web tile (Robins aanwijzing, 30-7): a video post's first video
-  // becomes the cover video, so the grid plays it muted-looping as its own
-  // thumbnail, exactly like an animated cover. Deliberately NO cover image
-  // next to it: the tile's image branch would win and freeze the tile. A
-  // photo post gets its first image as cover, instead of the (untitled)
-  // gradient.
-  const coverVid = media.find((a) => a.mediaType.startsWith('video/'));
-  const coverImg = media.find((a) => a.mediaType.startsWith('image/'));
   const postId = crypto.randomUUID();
   const slug = 'n-' + postId.slice(0, 8);
@@ -2428,8 +2420,10 @@
   const vis = c2sVisibility(object);
   const fanOnly = (vis === 'friends' || vis === 'direct') ? 1 : 0;
-  db.prepare(`INSERT INTO posts (id, site_id, slug, author_id, title, content, excerpt, status, type, language, fan_only, ap_visibility, cover_image_url, cover_video_url, created_at, updated_at, published_at)
-              VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
-    .run(postId, site.id, slug, user.id, '', html + mediaHtml, '', 'published', 'post', object.language || 'nl', fanOnly, vis,
-      coverVid ? null : (coverImg ? coverImg.url : null), coverVid ? coverVid.url : null, now, now, now);
+  // Deliberately NO cover (Robins besluit, 30-7): the media lives in the
+  // content, and a cover next to it showed the same video twice on the post
+  // page. The tiles derive their picture from the content instead.
+  db.prepare(`INSERT INTO posts (id, site_id, slug, author_id, title, content, excerpt, status, type, language, fan_only, ap_visibility, created_at, updated_at, published_at)
+              VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)
+    .run(postId, site.id, slug, user.id, '', html + mediaHtml, '', 'published', 'post', object.language || 'nl', fanOnly, vis, now, now, now);
   if (media.length) { try { db.prepare('UPDATE posts SET c2s_attachments = ? WHERE id = ?').run(JSON.stringify(media), postId); } catch { /* column exists via ensureColumn */ } }
   try { db.prepare('UPDATE posts SET content_rendered = ? WHERE id = ?').run(bakePostContent(html + mediaHtml), postId); } catch { /* render fallback covers it */ }
@@ -2437,5 +2431,5 @@
   try { db.prepare('INSERT INTO posts_fts(content, title, author, post_id) VALUES (?,?,?,?)').run(HtmlSanitizerService.toPlainText(html), '', user.username || '', postId); } catch { /* FTS non-fatal */ }
   if (vis !== 'direct') {
-    deliverCreate(site, { id: postId, slug, title: '', content: html + mediaHtml, published_at: now, created_at: now, fan_only: fanOnly, ap_visibility: vis, cover_image_url: coverVid ? null : (coverImg ? coverImg.url : null), cover_video_url: coverVid ? coverVid.url : null, c2s_attachments: media.length ? JSON.stringify(media) : null }).catch(() => { /* best-effort */ });
+    deliverCreate(site, { id: postId, slug, title: '', content: html + mediaHtml, published_at: now, created_at: now, fan_only: fanOnly, ap_visibility: vis, c2s_attachments: media.length ? JSON.stringify(media) : null }).catch(() => { /* best-effort */ });
   }
   return { status: 201, id: postId, url: `${base}/ap/notes/${postId}` };
