diff --git a/src/components/compose.css b/src/components/compose.css
index cbf94bc0..5b3f4ecd 100644
--- a/src/components/compose.css
+++ b/src/components/compose.css
@@ -24,7 +24,7 @@
   color: var(--text-insignificant-color);
 }
 
-#compose-container textarea{
+#compose-container textarea {
   width: 100%;
   max-width: 100%;
   height: 3em;
@@ -114,14 +114,16 @@
 #compose-container .toolbar-button:has([disabled]) > * {
   filter: opacity(0.3);
 }
-#compose-container .toolbar-button:not(.show-field) :is(input[type="checkbox"], select, input[type="file"]) {
+#compose-container
+  .toolbar-button:not(.show-field)
+  :is(input[type='checkbox'], select, input[type='file']) {
   opacity: 0;
   position: absolute;
   left: 0;
   height: 100%;
   margin: 0;
 }
-#compose-container .toolbar-button input[type="file"] {
+#compose-container .toolbar-button input[type='file'] {
   /* Move this out of the way, to fix cursor: pointer bug */
   left: -100vw !important;
 }
@@ -201,7 +203,7 @@
 #compose-container .media-preview {
   flex-shrink: 1;
 }
-#compose-container .media-preview > *{
+#compose-container .media-preview > * {
   min-width: 80px;
   width: 80px !important;
   height: 80px;
@@ -215,6 +217,22 @@
   flex-grow: 1;
   resize: none;
 }
+#compose-container .media-attachments .media-desc {
+  flex-grow: 1;
+}
+#compose-container .media-attachments .media-desc p {
+  font-size: 90%;
+  margin: 0;
+  padding: 0;
+  /* clamp 2 lines */
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+}
+#compose-container .media-attachments .media-desc p i {
+  color: var(--text-insignificant-color);
+}
 #compose-container .media-aside {
   display: flex;
   flex-direction: column;
@@ -226,7 +244,10 @@
   align-self: flex-start;
   color: var(--text-insignificant-color);
 }
+#compose-container .media-aside .close-button:hover {
+  color: var(--text-color);
+}
 #compose-container .media-aside .uploaded {
   color: var(--green-color);
   margin-bottom: 4px;
-}
\ No newline at end of file
+}
diff --git a/src/components/compose.jsx b/src/components/compose.jsx
index c1ec65bf..cfd2bd43 100644
--- a/src/components/compose.jsx
+++ b/src/components/compose.jsx
@@ -263,26 +263,33 @@ export default ({ onClose, replyToStatus }) => {
               if (mediaAttachments.length > 0) {
                 // Upload media attachments first
                 const mediaPromises = mediaAttachments.map((attachment) => {
-                  const params = {
-                    file: attachment.file,
-                    description: attachment.description || undefined,
-                  };
-                  return masto.mediaAttachments.create(params).then((res) => {
-                    // Update media attachment with ID
-                    if (res.id) {
-                      attachment.id = res.id;
-                    }
-                    return res;
-                  });
+                  const { file, description, sourceDescription, id } =
+                    attachment;
+                  console.log('UPLOADING', attachment);
+                  if (id) {
+                    // If already uploaded
+                    return attachment;
+                  } else {
+                    const params = {
+                      file,
+                      description,
+                    };
+                    return masto.mediaAttachments.create(params).then((res) => {
+                      // Update media attachment with ID
+                      if (res.id) {
+                        attachment.id = res.id;
+                      }
+                      return res;
+                    });
+                  }
                 });
                 const results = await Promise.allSettled(mediaPromises);
 
                 // If any failed, return
                 if (
-                  results.some(
-                    (result) =>
-                      result.status === 'rejected' || !result.value.id,
-                  )
+                  results.some((result) => {
+                    return result.status === 'rejected' || !result.value?.id;
+                  })
                 ) {
                   setUIState('error');
                   // Alert all the reasons
@@ -314,7 +321,8 @@ export default ({ onClose, replyToStatus }) => {
                 newStatus,
               });
             } catch (e) {
-              alert(e);
+              console.error(e);
+              alert(e?.reason || e);
               setUIState('error');
             }
           })();
@@ -410,63 +418,25 @@ export default ({ onClose, replyToStatus }) => {
         {mediaAttachments.length > 0 && (
           <div class="media-attachments">
             {mediaAttachments.map((attachment, i) => {
-              const { url, type, id } = attachment;
-              const suffixType = type.split('/')[0];
+              const { id } = attachment;
               return (
-                <div class="media-attachment" key={i + id}>
-                  <div class="media-preview">
-                    {suffixType === 'image' ? (
-                      <img src={url} alt="" />
-                    ) : suffixType === 'video' ? (
-                      <video src={url} playsinline muted />
-                    ) : suffixType === 'audio' ? (
-                      <audio src={url} controls />
-                    ) : null}
-                  </div>
-                  <textarea
-                    placeholder={
-                      {
-                        image: 'Image description',
-                        video: 'Video description',
-                        audio: 'Audio description',
-                      }[suffixType]
-                    }
-                    autoCapitalize="sentences"
-                    autoComplete="on"
-                    autoCorrect="on"
-                    spellCheck="true"
-                    dir="auto"
-                    disabled={uiState === 'loading'}
-                    maxlength="1500"
-                    // TODO: Un-hard-code this maxlength, ref: https://github.com/mastodon/mastodon/blob/b59fb28e90bc21d6fd1a6bafd13cfbd81ab5be54/app/models/media_attachment.rb#L39
-                    onInput={(e) => {
-                      const { value } = e.target;
-                      // Modify `description` in media attachment
-                      setMediaAttachments((attachments) => {
-                        const newAttachments = [...attachments];
-                        newAttachments[i].description = value;
-                        return newAttachments;
-                      });
-                    }}
-                  ></textarea>
-                  <div class="media-aside">
-                    <button
-                      type="button"
-                      class="plain close-button"
-                      disabled={uiState === 'loading'}
-                      onClick={() => {
-                        setMediaAttachments((attachments) => {
-                          return attachments.filter((_, j) => j !== i);
-                        });
-                      }}
-                    >
-                      <Icon icon="x" />
-                    </button>
-                    {!!id && (
-                      <Icon icon="upload" title="Uploaded" class="uploaded" />
-                    )}
-                  </div>
-                </div>
+                <MediaAttachment
+                  key={i + id}
+                  attachment={attachment}
+                  disabled={uiState === 'loading'}
+                  onDescriptionChange={(value) => {
+                    setMediaAttachments((attachments) => {
+                      const newAttachments = [...attachments];
+                      newAttachments[i].description = value;
+                      return newAttachments;
+                    });
+                  }}
+                  onRemove={() => {
+                    setMediaAttachments((attachments) => {
+                      return attachments.filter((_, j) => j !== i);
+                    });
+                  }}
+                />
               );
             })}
           </div>
@@ -529,3 +499,65 @@ export default ({ onClose, replyToStatus }) => {
     </div>
   );
 };
+
+function MediaAttachment({
+  attachment,
+  disabled,
+  onDescriptionChange = () => {},
+  onRemove = () => {},
+}) {
+  const { url, type, id } = attachment;
+  const suffixType = type.split('/')[0];
+  return (
+    <div class="media-attachment">
+      <div class="media-preview">
+        {suffixType === 'image' ? (
+          <img src={url} alt="" />
+        ) : suffixType === 'video' ? (
+          <video src={url} playsinline muted />
+        ) : suffixType === 'audio' ? (
+          <audio src={url} controls />
+        ) : null}
+      </div>
+      {!!id ? (
+        <div class="media-desc">
+          <span class="tag">Uploaded</span>
+          <p>{attachment.description || <i>No description</i>}</p>
+        </div>
+      ) : (
+        <textarea
+          value={attachment.description || ''}
+          placeholder={
+            {
+              image: 'Image description',
+              video: 'Video description',
+              audio: 'Audio description',
+            }[suffixType]
+          }
+          autoCapitalize="sentences"
+          autoComplete="on"
+          autoCorrect="on"
+          spellCheck="true"
+          dir="auto"
+          disabled={disabled}
+          maxlength="1500" // Not unicode-aware :(
+          // TODO: Un-hard-code this maxlength, ref: https://github.com/mastodon/mastodon/blob/b59fb28e90bc21d6fd1a6bafd13cfbd81ab5be54/app/models/media_attachment.rb#L39
+          onInput={(e) => {
+            const { value } = e.target;
+            onDescriptionChange(value);
+          }}
+        ></textarea>
+      )}
+      <div class="media-aside">
+        <button
+          type="button"
+          class="plain close-button"
+          disabled={disabled}
+          onClick={onRemove}
+        >
+          <Icon icon="x" />
+        </button>
+      </div>
+    </div>
+  );
+}
diff --git a/src/components/status.css b/src/components/status.css
index 2b10cc36..c4906fbd 100644
--- a/src/components/status.css
+++ b/src/components/status.css
@@ -1,23 +1,28 @@
 /* REBLOG + REPLY-TO */
 
 .status-reblog {
-  background: linear-gradient(to bottom right, var(
-    --reblog-faded-color
-  ), transparent 160px);
+  background: linear-gradient(
+    to bottom right,
+    var(--reblog-faded-color),
+    transparent 160px
+  );
 }
 .status-reply-to {
-  background: linear-gradient(to bottom right, var(
-    --reply-to-faded-color
-  ), transparent 160px);
+  background: linear-gradient(
+    to bottom right,
+    var(--reply-to-faded-color),
+    transparent 160px
+  );
 }
 .status-reblog .status-reply-to {
-  background: linear-gradient(to top left, var(
-    --reply-to-faded-color
-  ), transparent 160px);
+  background: linear-gradient(
+    to top left,
+    var(--reply-to-faded-color),
+    transparent 160px
+  );
 }
 .visibility-direct {
-  /* diagonal stripes of yellow */
-  background-image: repeating-linear-gradient(
+  --yellow-stripes: repeating-linear-gradient(
     -45deg,
     var(--reply-to-faded-color),
     var(--reply-to-faded-color) 10px,
@@ -25,6 +30,8 @@
     transparent 10px,
     transparent 20px
   );
+  /* diagonal stripes of yellow */
+  background-image: var(--yellow-stripes);
 }
 
 /* STATUS PRE META */
@@ -51,7 +58,18 @@
   align-items: flex-start;
 }
 .status.large {
+  --fade-in-out-bg: linear-gradient(
+    to bottom,
+    transparent,
+    var(--bg-color) 70px,
+    var(--bg-color) calc(100% - 50px),
+    transparent
+  );
   padding-bottom: 8px;
+  background-image: var(--fade-in-out-bg);
+}
+.status.large.visibility-direct {
+  background-image: var(--fade-in-out-bg), var(--yellow-stripes);
 }
 .status-pre-meta + .status {
   padding-top: 8px;
@@ -87,11 +105,11 @@
   min-height: 50px;
   justify-content: space-between;
 }
-.status > .container >  .meta .arrow {
+.status > .container > .meta .arrow {
   color: var(--reply-to-color);
   vertical-align: middle;
 }
-.status > .container >  .meta :is(.time, .edited) {
+.status > .container > .meta :is(.time, .edited) {
   color: inherit;
   text-align: end;
   opacity: 0.5;
@@ -100,17 +118,16 @@
   margin-left: 4px;
   white-space: nowrap;
 }
-.status > .container >  .meta a.time:hover {
+.status > .container > .meta a.time:hover {
   text-decoration: underline;
 }
-.status > .container >  .meta .reply-to {
+.status > .container > .meta .reply-to {
   opacity: 0.5;
   font-size: smaller;
 }
 
 .status.large .content-container {
   margin-left: calc(-50px - 16px);
-  background-image: linear-gradient(to bottom, transparent, var(--bg-color) 10px, var(--bg-color));
   padding-top: 10px;
   padding-bottom: 10px;
 }
@@ -124,13 +141,13 @@
   align-items: center;
 }
 .status .content-container.has-spoiler .spoiler ~ * {
-  filter: blur(6px) invert(.5);
+  filter: blur(6px) invert(0.5);
   pointer-events: none;
-  transition: filter .5s;
+  transition: filter 0.5s;
   user-select: none;
 }
 .status .content-container.has-spoiler .spoiler ~ .content ~ * {
-  opacity: .5;
+  opacity: 0.5;
 }
 .status .content-container.show-spoiler .spoiler {
   border-style: dotted;
@@ -148,7 +165,7 @@
   margin-top: 8px;
 }
 .status .content p {
-  margin-block: .75em;
+  margin-block: 0.75em;
 }
 .status .content p:first-child {
   margin-block-start: 0;
@@ -236,7 +253,7 @@
   height: 70px;
   border-radius: 50%;
   background-color: var(--bg-blur-color);
-  backdrop-filter: blur(6px) saturate(3) invert(.2);
+  backdrop-filter: blur(6px) saturate(3) invert(0.2);
   z-index: 1;
 }
 .status .media-video:after {
@@ -249,8 +266,9 @@
   width: 0;
   height: 0;
   border-style: solid;
-  border-width: 15px 0 15px 26.0px;
-  border-color: transparent transparent transparent var(--text-insignificant-color);
+  border-width: 15px 0 15px 26px;
+  border-color: transparent transparent transparent
+    var(--text-insignificant-color);
   pointer-events: none;
   opacity: 0.75;
   z-index: 2;
@@ -305,7 +323,7 @@
   overflow: hidden;
   display: -webkit-box;
   display: box;
-  -webkit-box-orient: vertical; 
+  -webkit-box-orient: vertical;
   box-orient: vertical;
   -webkit-line-clamp: 2;
   line-clamp: 2;
@@ -318,7 +336,7 @@
   overflow: hidden;
   display: -webkit-box;
   display: box;
-  -webkit-box-orient: vertical; 
+  -webkit-box-orient: vertical;
   box-orient: vertical;
   -webkit-line-clamp: 2;
   line-clamp: 2;
@@ -351,9 +369,15 @@ a.card:hover {
   display: flex;
   gap: 8px;
   justify-content: space-between;
-  background-image: linear-gradient(to right, var(--link-faded-color), var(--link-faded-color) var(--percentage), transparent var(--percentage), transparent);
+  background-image: linear-gradient(
+    to right,
+    var(--link-faded-color),
+    var(--link-faded-color) var(--percentage),
+    transparent var(--percentage),
+    transparent
+  );
   border-radius: 8px;
-  border: 1px solid rgba(128, 128, 128, .1);
+  border: 1px solid rgba(128, 128, 128, 0.1);
   align-items: center;
 }
 .poll-label {
@@ -391,8 +415,7 @@ a.card:hover {
 }
 .status.large .extra-meta {
   padding-top: 0;
-  margin-left: calc(-50px - 16px);
-  background-color: var(--bg-color);
+  margin-left: calc(-50px - 4px);
 }
 
 /* ACTIONS */
@@ -405,14 +428,12 @@ a.card:hover {
   justify-content: space-between;
 }
 .status.large .actions {
-  /* margin-left: -12px; */
   padding-top: 8px;
   padding-bottom: 16px;
   margin-left: calc(-50px - 16px);
-  background-image: linear-gradient(to bottom, var(--bg-color), var(--bg-color) calc(100% - 10px), transparent);
 }
 .status .actions > * {
-  opacity: .5;
+  opacity: 0.5;
   transition: opacity 0.2s ease-in-out;
 }
 .status:hover .actions > * {
@@ -459,9 +480,11 @@ a.card:hover {
   width: 100%;
   font-size: 90%;
   border: 1px solid var(--outline-color);
-  background: linear-gradient(to bottom right, var(
-    --bg-faded-color
-  ), transparent 160px);
+  background: linear-gradient(
+    to bottom right,
+    var(--bg-faded-color),
+    transparent 160px
+  );
 }
 
 /* MISC */
@@ -485,7 +508,7 @@ a.card:hover {
   min-height: 50dvh;
 }
 
-#edit-history :is(ol, ol li){
+#edit-history :is(ol, ol li) {
   list-style: none;
   margin: 0;
   padding: 0;