diff --git a/frontend/public/icon-maskable-192.png b/frontend/public/icon-maskable-192.png
index 395f73c..32e778b 100644
Binary files a/frontend/public/icon-maskable-192.png and b/frontend/public/icon-maskable-192.png differ
diff --git a/frontend/public/icon-maskable-512.png b/frontend/public/icon-maskable-512.png
index 43336b8..f224a78 100644
Binary files a/frontend/public/icon-maskable-512.png and b/frontend/public/icon-maskable-512.png differ
diff --git a/frontend/src/components/thread/ThreadView.tsx b/frontend/src/components/thread/ThreadView.tsx
index 6ef64a7..15caa4e 100644
--- a/frontend/src/components/thread/ThreadView.tsx
+++ b/frontend/src/components/thread/ThreadView.tsx
@@ -464,6 +464,8 @@ function MessageItem({
const t = useT();
const { locale } = useLocale();
const [showDetails, setShowDetails] = useState(false);
+ // On a phone the reply / translate / actions buttons get a row of their own.
+ const mobile = useIsMobile();
// Translation (app/translation.py): the message's languages, as the server
// found them ("zh-Hans,pl,en"), and the language it is shown in (null: as sent).
const [language, setLanguage] = useState(message.content_language ?? "");
@@ -511,6 +513,73 @@ function MessageItem({
const allTargets = replyTargets(message, ownAddresses, "reply_all");
const multiRecipient = allTargets.to.length + allTargets.cc.length > 1;
+ // The full header (From, To, Cc, Subject, Date, Size), opened with ▼.
+ const details = (
+
+
{t("mail.from")}
+
{formatList(message.from_addr)}
+
{t("mail.to")}
+
{formatList(message.to_addr)}
+ {message.cc_addr.length > 0 && (
+ <>
+
Cc
+
{formatList(message.cc_addr)}
+ >
+ )}
+
{t("mail.subjectLabel")}
+
{message.subject || "(no subject)"}
+
{t("mail.dateLabel")}
+
{fmtFull(message.date)}
+
{t("mail.sizeLabel")}
+
{fmtSize(message.size_bytes)}
+
+ );
+
+ // Reply, Translate, Actions and plugin verbs: beside the recipients, or on
+ // a phone on a row below them.
+ const actions = (
+ <>
+ {canReply && (
+
+ )}
+ {offerTranslate && (target || translateTo) && (
+
+ )}
+
+ {/* Plugin-contributed per-message actions (SPEC §11.3 message.actions). */}
+
+ >
+ );
+
return (
- )}
+ {showDetails && !mobile && details}
+ {/* On a phone the full header takes the card's width, not the column beside the avatar. */}
+ {showDetails && mobile &&