Index: src/views/partials/post-card.ejs
===================================================================
--- src/views/partials/post-card.ejs	(revision 99989f9fba023a32bcfaa01464bb0a172952ab1f)
+++ src/views/partials/post-card.ejs	(revision a64d7051ecc17fc913a8a15fca76be421fbfd720)
@@ -138,5 +138,8 @@
     margin-right: calc(-1 * clamp(1.25rem, 4vw, 2rem));
     width: calc(100% + 2 * clamp(1.25rem, 4vw, 2rem)) !important;
-    background: var(--paper-2);
+    /* Accent-gradient placeholder shown while the cover loads (the image fades in over it). */
+    background-image: linear-gradient(135deg,
+        color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2)) 0%,
+        color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2)) 100%);
   }
   .post-list-cover img {
@@ -144,5 +147,7 @@
     object-fit: cover;
     display: block;
-  }
+    transition: opacity .4s ease;
+  }
+  .post-list-cover img.is-loading { opacity: 0; }
 
   /* Re-apply rounded corners on slightly larger phones */
Index: src/views/shell.ejs
===================================================================
--- src/views/shell.ejs	(revision 99989f9fba023a32bcfaa01464bb0a172952ab1f)
+++ src/views/shell.ejs	(revision a64d7051ecc17fc913a8a15fca76be421fbfd720)
@@ -200,5 +200,5 @@
 
 <!-- v9 stylesheet (full palette system) -->
-<link rel="stylesheet" href="/assets/css/style.css?v=60">
+<link rel="stylesheet" href="/assets/css/style.css?v=61">
 <script>
 /* iOS safe-area, built by hand. env(safe-area-inset-top) resolves to 0 on this iOS in
@@ -737,4 +737,25 @@
      click reveals instead of following the card link or firing htmx navigation. -->
 <script>
+// Cover fade-in: a cover image that's still loading is hidden so the accent-gradient
+// placeholder behind it shows; it fades in once loaded. Cached/complete images stay
+// visible (no flash). Runs on load + htmx swaps.
+(function () {
+  if (window.__coverFadeWired) return; window.__coverFadeWired = true;
+  function scan(root) {
+    (root || document).querySelectorAll('.grid-tile-img, .post-list-cover img').forEach(function (img) {
+      if (img.dataset.fade) return; img.dataset.fade = '1';
+      if (img.complete && img.naturalWidth > 0) return;   // already loaded → leave visible
+      img.classList.add('is-loading');
+      var done = function () { img.classList.remove('is-loading'); };
+      img.addEventListener('load', done, { once: true });
+      img.addEventListener('error', done, { once: true });
+    });
+  }
+  scan(document);
+  document.body.addEventListener('htmx:afterSettle', function (e) { scan(e.target); });
+})();
+</script>
+
+<script>
 (function () {
   if (window.__nsfwWired) return; window.__nsfwWired = true;
