Index: src/routes/circle.js
===================================================================
--- src/routes/circle.js	(revision aa7f54824c022cb86c0b15cd77dd190ef333ce42)
+++ src/routes/circle.js	(revision 43dbf9c41de8e6cc1512805acbe92a1f05069786)
@@ -37,18 +37,26 @@
       .filter((m) => m.url);
     const image = media.find((m) => m.type === 'image') || null;
+    // Vorm de remote-post naar het lokale post-shape zodat post-card/post-tile
+    // (dezelfde timeline/grid-view als de home) 'm renderen. external_url maakt
+    // de partials extern-linkend (naar de bron) i.p.v. lokaal/htmx.
     return {
       id: r.id,
+      slug: encodeURIComponent(r.id),
       title: r.title || '(zonder titel)',
-      summary: r.summary || '',
-      url: safeUrl(r.url),
-      published: r.published,
-      actorName: r.actor_name || 'Onbekend',
-      actorUrl: safeUrl(r.actor_url),
-      actorAvatar: safeUrl(r.actor_avatar),
-      image: image ? image.url : null,
+      excerpt: r.summary || '',
+      cover_image_url: image ? image.url : null,
+      published_at: r.published,
+      created_at: r.published,
+      type: 'post',
+      tags: '',
+      pinned: 0,
+      status: 'published',
+      external_url: safeUrl(r.url),
+      source_name: r.actor_name || 'Onbekend',
+      source_url: safeUrl(r.actor_url),
     };
   });
 
-  renderPage(req, res, 'pages/circle-feed', { pageTitle: 'Cirkel', posts });
+  renderPage(req, res, 'pages/circle-feed', { pageTitle: 'Cirkel', bodyClass: 'on-cirkel', posts });
 });
 
Index: src/views/pages/circle-feed.ejs
===================================================================
--- src/views/pages/circle-feed.ejs	(revision aa7f54824c022cb86c0b15cd77dd190ef333ce42)
+++ src/views/pages/circle-feed.ejs	(revision 43dbf9c41de8e6cc1512805acbe92a1f05069786)
@@ -1,65 +1,44 @@
-<div class="container circle-page">
-  <header class="circle-head">
-    <h1>Cirkel</h1>
-    <p class="circle-sub">Wat er speelt bij de andere sites in deze cirkel.</p>
-  </header>
+<div class="container cirkel-head">
+  <h1>Cirkel</h1>
+  <p class="cirkel-sub">Wat er speelt bij de andere sites in deze cirkel.</p>
+</div>
 
-  <% if (!posts.length) { %>
-    <p class="circle-empty">Nog niets in je cirkel. Voeg sites toe via
+<% if (!posts.length) { %>
+  <div class="container">
+    <p class="cirkel-empty">Nog niets in je cirkel. Voeg sites toe via
       <a href="/admin/circle">Beheer &rsaquo; Cirkel</a> en ververs ze.</p>
-  <% } else { %>
-    <div class="circle-grid">
-      <% posts.forEach(function(p){ %>
-        <article class="circle-card">
-          <% if (p.image) { %>
-            <a class="cc-cover" <% if (p.url) { %>href="<%= p.url %>" target="_blank" rel="noopener"<% } %>>
-              <img loading="lazy" src="<%= p.image %>" alt="">
-            </a>
-          <% } %>
-          <div class="cc-body">
-            <div class="cc-src">
-              <% if (p.actorAvatar) { %><img class="cc-avatar" src="<%= p.actorAvatar %>" alt=""><% } %>
-              <% if (p.actorUrl) { %>
-                <a href="<%= p.actorUrl %>" target="_blank" rel="noopener"><%= p.actorName %></a>
-              <% } else { %><span><%= p.actorName %></span><% } %>
-            </div>
-            <h2 class="cc-title">
-              <% if (p.url) { %><a href="<%= p.url %>" target="_blank" rel="noopener"><%= p.title %></a>
-              <% } else { %><%= p.title %><% } %>
-            </h2>
-            <% if (p.summary) { %><p class="cc-summary"><%= p.summary %></p><% } %>
-            <div class="cc-foot">
-              <% if (p.published) { %><span class="cc-date"><%= p.published.slice(0,10) %></span><% } %>
-              <% if (p.url) { %><a class="cc-link" href="<%= p.url %>" target="_blank" rel="noopener">Lees bij de bron &rarr;</a><% } %>
-            </div>
-          </div>
-        </article>
+  </div>
+<% } else { %>
+
+  <%# Dezelfde view als de hoofdpagina: timeline (post-card) + grid (post-tile),
+      gewisseld door de view-switcher via body[data-feed-view]. De remote-posts
+      zijn in circle.js naar het lokale post-shape gevormd (met external_url,
+      zodat de kaarten naar de bron-site linken). %>
+
+  <!-- ===== TIMELINE (standaard) ===== -->
+  <div class="container feed-timeline">
+    <ul class="post-list feed-timeline-list">
+      <% posts.forEach(function(post){ %>
+        <%- include('../partials/post-card', { post: post }) %>
+      <% }); %>
+    </ul>
+  </div>
+
+  <!-- ===== GRID (body[data-feed-view="grid"]) ===== -->
+  <section class="feed-grid container" aria-label="Grid-weergave">
+    <div class="grid-tiles">
+      <% posts.forEach(function(post){ %>
+        <%- include('../partials/post-tile', { post: post }) %>
       <% }); %>
     </div>
-  <% } %>
-</div>
+  </section>
+
+<% } %>
 
 <style>
-.circle-page { max-width: 1000px; margin: 2.5rem auto; padding: 0 1rem; }
-.circle-head h1 { font-family: var(--font-display, serif); font-size: 2rem; margin: 0 0 .25rem; }
-.circle-sub { color: var(--ink-muted); margin: 0 0 2rem; }
-.circle-empty { color: var(--ink-muted); }
-.circle-empty a { color: var(--accent); }
-.circle-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.1rem; }
-.circle-card { display: flex; flex-direction: column; border: 1px solid var(--rule); border-radius: 12px; overflow: hidden; background: var(--paper-2); }
-.cc-cover { display: block; aspect-ratio: 16/9; overflow: hidden; }
-.cc-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
-.cc-body { padding: .9rem 1rem 1rem; display: flex; flex-direction: column; gap: .5rem; }
-.cc-src { display: flex; align-items: center; gap: .45rem; font-size: .8rem; color: var(--ink-muted); }
-.cc-src a { color: var(--ink-muted); text-decoration: none; }
-.cc-src a:hover { color: var(--accent); }
-.cc-avatar { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; }
-.cc-title { font-family: var(--font-display, serif); font-size: 1.15rem; margin: 0; line-height: 1.25; }
-.cc-title a { color: var(--ink); text-decoration: none; }
-.cc-title a:hover { color: var(--accent); }
-.cc-summary { margin: 0; font-size: .9rem; color: var(--ink-soft, var(--ink-muted)); line-height: 1.5;
-  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
-.cc-foot { display: flex; justify-content: space-between; align-items: center; gap: .5rem; margin-top: auto; padding-top: .35rem; font-size: .78rem; }
-.cc-date { color: var(--ink-muted); }
-.cc-link { color: var(--accent); text-decoration: none; white-space: nowrap; }
+.cirkel-head { margin-top: 2rem; }
+.cirkel-head h1 { font-family: var(--font-display, serif); font-size: 2rem; margin: 0 0 .25rem; }
+.cirkel-sub { color: var(--ink-muted); margin: 0 0 1.5rem; }
+.cirkel-empty { color: var(--ink-muted); }
+.cirkel-empty a { color: var(--accent); }
 </style>
Index: src/views/partials/post-card.ejs
===================================================================
--- src/views/partials/post-card.ejs	(revision aa7f54824c022cb86c0b15cd77dd190ef333ce42)
+++ src/views/partials/post-card.ejs	(revision 43dbf9c41de8e6cc1512805acbe92a1f05069786)
@@ -12,5 +12,8 @@
 
 const _base      = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '';
-const _href      = _base + '/' + post.slug;
+const _external  = post.external_url || null;
+const _href      = _external || (_base + '/' + post.slug);
+const _ext       = !!_external;
+const _src       = post.source_name || '';
 const _hasCover  = !!post.cover_image_url;
 const _typeLabel = (post.type && post.type !== 'overig' && post.type !== 'post') ? post.type : '';
@@ -43,6 +46,5 @@
   <% if (_hasCover) { %>
     <a class="post-list-cover" href="<%= _href %>"
-       hx-get="<%= _href %>?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
-       hx-push-url="<%= _href %>" hx-indicator="#pcms-loading"
+       <% 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="<%= post.cover_image_url %>" alt="" loading="lazy" decoding="async">
@@ -54,4 +56,5 @@
       <% if (_isPinned) { %><span class="post-list-pin" aria-label="Vastgepind">★</span><% } %>
       <time datetime="<%= post.published_at || post.created_at %>"><%= _ddmmyyyy(post.published_at || post.created_at) %></time>
+      <% if (_src) { %><span class="post-list-type">&middot; via <%= _src %></span><% } %>
       <% if (_typeLabel) { %>
         <span class="post-list-type">· <%= _typeLabel.charAt(0).toUpperCase() + _typeLabel.slice(1) %></span>
@@ -64,6 +67,5 @@
     <h3 class="post-list-title">
       <a href="<%= _href %>"
-         hx-get="<%= _href %>?partial=1" hx-target="#pcms-main" hx-swap="innerHTML"
-         hx-push-url="<%= _href %>" hx-indicator="#pcms-loading">
+         <% 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"<% } %>>
         <%= post.title || '(zonder titel)' %>
       </a>
Index: src/views/partials/post-tile.ejs
===================================================================
--- src/views/partials/post-tile.ejs	(revision aa7f54824c022cb86c0b15cd77dd190ef333ce42)
+++ src/views/partials/post-tile.ejs	(revision 43dbf9c41de8e6cc1512805acbe92a1f05069786)
@@ -8,14 +8,12 @@
 const _typeLabel = (post.type && post.type !== 'post') ? post.type : '';
 const _base = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : '';
-const _href = _base + '/' + post.slug;
+const _external = post.external_url || null;
+const _href = _external || (_base + '/' + post.slug);
+const _ext = !!_external;
 %>
 <a class="grid-tile<%= _hasCover ? '' : ' grid-tile-gradient' %><%= _isPinned ? ' is-pinned' : '' %>"
    href="<%= _href %>"
    <% if (_hasCover) { %>style="background-image: url('<%= post.cover_image_url %>'); --tile-hue: <%= _tileHue %>;"<% } else { %>style="--tile-hue: <%= _tileHue %>;"<% } %>
-   hx-get="<%= _href %>?partial=1"
-   hx-target="#pcms-main"
-   hx-swap="innerHTML"
-   hx-push-url="<%= _href %>"
-   hx-indicator="#pcms-loading">
+   <% 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 (_typeLabel) { %>
Index: src/views/shell.ejs
===================================================================
--- src/views/shell.ejs	(revision aa7f54824c022cb86c0b15cd77dd190ef333ce42)
+++ src/views/shell.ejs	(revision 43dbf9c41de8e6cc1512805acbe92a1f05069786)
@@ -385,5 +385,5 @@
   // navigate to home in the chosen view, so the switcher is never
   // a dead control.
-  var FEED_PAGE_CLASSES = ['on-home', 'on-archive', 'on-tag', 'on-type', 'on-user'];
+  var FEED_PAGE_CLASSES = ['on-home', 'on-archive', 'on-tag', 'on-type', 'on-user', 'on-cirkel'];
   function isFeedPage() {
     for (var i = 0; i < FEED_PAGE_CLASSES.length; i++) {
