Show conversations as cards and adapt emails to the dark theme

Opening an email now shows its whole conversation, oldest first, one card
per email, the way Spark does. Emails before the first one that was unread
(or the one opened, if earlier) start collapsed to a line with the sender,
a preview and the date; a "New messages" divider marks where unread mail
begins. Clicking a card's header collapses or expands it, and the More menu
has Expand all and Collapse all. Opening a conversation marks all of it
read. Done, Trash, Set Aside and Snooze move the conversation's emails that
are in the same place as the one opened, so replies stay in Sent.

The store links messages into conversations as they arrive: by Message-ID,
In-Reply-To and References when the subjects agree (ignoring Re:/Fwd:
prefixes and list tags), and by Microsoft Graph's conversation id. A reply
that arrives before what it answers merges the two later. Existing mail is
linked when the database upgrades.

In the dark theme, HTML email follows Spark's rules: an email with its own
dark design shows it; one built to stay light (Outlook-style templates,
Amazon, Apple) keeps its white sheet; everything else has text that's hard
to read on the dark card lightened, and backgrounds darkened to match,
keeping each color's hue. Emails' prefers-color-scheme rules follow the
app's theme, not the system's. A reply's quote of earlier mail, in HTML or
plain text, folds behind a "•••" button, except in forwards.

The demo mailbox gains conversations, a quoted Gmail-style reply and a
styled HTML newsletter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bc1dc6d5d3Michael Rodriguez committed on 10/23/2026, 5:01:24 PMparent55c60ec
16 files changedLine totals unavailable