Index: src/views/partials/fedi-node.ejs
===================================================================
--- src/views/partials/fedi-node.ejs	(revision 33e1dbd11a4cb4638e01c26e3f3c98e352e8892e)
+++ src/views/partials/fedi-node.ejs	(revision feced2ce628d8bee7974f77404806f4be6f2272b)
@@ -12,4 +12,21 @@
   </div>
   <div class="comment-content"><%- n.content %></div>
+  <%# Rich replies: media on our own sent replies (attachments on the Note).
+      Visitors see these too, and the reply editor (owner-only) may not render,
+      so make sure the stylesheet is on the page either way. %>
+  <% if (n.media && n.media.length) { %>
+    <% if (!locals.__reAssets) { locals.__reAssets = 1; %><link rel="stylesheet" href="/assets/css/reply-editor.css"><% } %>
+    <div class="re-reply-media">
+      <% n.media.forEach(function (m) { %>
+        <% if ((m.mediaType || '').indexOf('image/') === 0) { %>
+          <a href="<%= m.url %>" target="_blank" rel="noopener"><img src="<%= m.url %>" alt="<%= m.name || '' %>" loading="lazy"></a>
+        <% } else if ((m.mediaType || '').indexOf('audio/') === 0) { %>
+          <audio controls preload="none" src="<%= m.url %>"></audio>
+        <% } else { %>
+          <video controls preload="metadata" src="<%= m.url %>"></video>
+        <% } %>
+      <% }); %>
+    </div>
+  <% } %>
   <div class="comment-actions">
     <% if (n.mine && typeof canManageSite !== 'undefined' && canManageSite && n.outboxId) { %>
Index: src/views/partials/reply-editor.ejs
===================================================================
--- src/views/partials/reply-editor.ejs	(revision 33e1dbd11a4cb4638e01c26e3f3c98e352e8892e)
+++ src/views/partials/reply-editor.ejs	(revision feced2ce628d8bee7974f77404806f4be6f2272b)
@@ -18,5 +18,6 @@
 %>
 <% var _reLang = (typeof defaultLang !== 'undefined' && defaultLang) || (typeof lang !== 'undefined' ? lang : 'en'); %>
-<form method="post" action="<%= action %>" class="re-form" data-re>
+<form method="post" action="<%= action %>" class="re-form" data-re
+      data-upload="/posts/upload-reply-media" data-upload-err="<%= t('re.attach_err') %>">
   <% (typeof hiddenFields !== 'undefined' ? hiddenFields : []).forEach(function (h) { %>
     <input type="hidden" name="<%= h.name %>" value="<%= h.value %>">
@@ -35,5 +36,9 @@
     <button type="button" data-cmd="list" title="<%= t('re.list') %>" aria-label="<%= t('re.list') %>">•≡</button>
     <button type="button" data-cmd="quote" title="<%= t('re.quote') %>" aria-label="<%= t('re.quote') %>">❝</button>
+    <button type="button" data-cmd="attach" title="<%= t('re.attach') %>" aria-label="<%= t('re.attach') %>">📎</button>
+    <input type="file" class="re-file" accept="image/*,audio/*,video/*" multiple hidden>
   </div>
+  <input type="hidden" name="attachments" value="">
+  <div class="re-attachments" hidden></div>
   <textarea name="text" rows="<%= typeof rows !== 'undefined' ? rows : 3 %>" required placeholder="<%= placeholder %>"></textarea>
   <div class="re-editor" contenteditable="true" role="textbox" aria-multiline="true"
