Two print bugs, both in the @media print block of web/src/styles/app.css.
Printing carried the screen theme. A dark reader printed a dark sheet. body { background: #fff } was not enough: every card, header and detail row paints from --bg-elev / --bg-sunken / --fg, and the message body renders in a shadow root that no rule in this stylesheet can select into — it follows the app palette through inherited custom properties (EMAIL_BASE_CSS in web/src/lib/html.ts). Pinning the tokens themselves to a light set is what reaches it. Backgrounds go white rather than the light theme greys, so a printer is not asked to ink the whole sheet. Mail that brings colours of its own is untouched — it was never themed.
!important rather than a longer selector: the dark palettes live on :root[data-theme] and :root[data-palette][data-accent], and out-specifying all of them is a chain the next palette breaks.
Page one was blank apart from the subject.break-inside: avoid on .message cannot be honoured by a message taller than a sheet; Chrome answers by moving the card to a fresh page and breaking it there anyway. Only .message-head is indivisible now, and break-after: avoid keeps it with the body it introduces.
Also hidden for print: the pane splitter, and the star / details buttons in the message header — controls that print as ink and do nothing on paper.
Verified
Headless Chrome print-to-PDF of the reading pane markup against this stylesheet, data-theme="dark", message body in a real shadow root with the themed class.
before
after
pages
3
2
page 1
subject only, on a near-black sheet
subject + sender + body, white
Re-rendered with the dark theme off as well: still 2 pages, content from page 1.
Two print bugs, both in the `@media print` block of `web/src/styles/app.css`.
**Printing carried the screen theme.** A dark reader printed a dark sheet. `body { background: #fff }` was not enough: every card, header and detail row paints from `--bg-elev` / `--bg-sunken` / `--fg`, and the message body renders in a shadow root that no rule in this stylesheet can select into — it follows the app palette through inherited custom properties (`EMAIL_BASE_CSS` in `web/src/lib/html.ts`). Pinning the tokens themselves to a light set is what reaches it. Backgrounds go white rather than the light theme greys, so a printer is not asked to ink the whole sheet. Mail that brings colours of its own is untouched — it was never themed.
`!important` rather than a longer selector: the dark palettes live on `:root[data-theme]` and `:root[data-palette][data-accent]`, and out-specifying all of them is a chain the next palette breaks.
**Page one was blank apart from the subject.** `break-inside: avoid` on `.message` cannot be honoured by a message taller than a sheet; Chrome answers by moving the card to a fresh page and breaking it there anyway. Only `.message-head` is indivisible now, and `break-after: avoid` keeps it with the body it introduces.
Also hidden for print: the pane splitter, and the star / details buttons in the message header — controls that print as ink and do nothing on paper.
## Verified
Headless Chrome print-to-PDF of the reading pane markup against this stylesheet, `data-theme="dark"`, message body in a real shadow root with the themed class.
| | before | after |
|---|---|---|
| pages | 3 | 2 |
| page 1 | subject only, on a near-black sheet | subject + sender + body, white |
Re-rendered with the dark theme off as well: still 2 pages, content from page 1.
**Merged** 2026-09-01 as coffey-labs/ihasmail@a16faa1789c2
<sub>Rebuilt from: git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two print bugs, both in the
@media printblock ofweb/src/styles/app.css.Printing carried the screen theme. A dark reader printed a dark sheet.
body { background: #fff }was not enough: every card, header and detail row paints from--bg-elev/--bg-sunken/--fg, and the message body renders in a shadow root that no rule in this stylesheet can select into — it follows the app palette through inherited custom properties (EMAIL_BASE_CSSinweb/src/lib/html.ts). Pinning the tokens themselves to a light set is what reaches it. Backgrounds go white rather than the light theme greys, so a printer is not asked to ink the whole sheet. Mail that brings colours of its own is untouched — it was never themed.!importantrather than a longer selector: the dark palettes live on:root[data-theme]and:root[data-palette][data-accent], and out-specifying all of them is a chain the next palette breaks.Page one was blank apart from the subject.
break-inside: avoidon.messagecannot be honoured by a message taller than a sheet; Chrome answers by moving the card to a fresh page and breaking it there anyway. Only.message-headis indivisible now, andbreak-after: avoidkeeps it with the body it introduces.Also hidden for print: the pane splitter, and the star / details buttons in the message header — controls that print as ink and do nothing on paper.
Verified
Headless Chrome print-to-PDF of the reading pane markup against this stylesheet,
data-theme="dark", message body in a real shadow root with the themed class.Re-rendered with the dark theme off as well: still 2 pages, content from page 1.
Merged 2026-09-01 as coffey-labs/ihasmail@a16faa1789
Rebuilt from: git history, session transcript.