Phoenix.Component function components shared by email (via
Accrue.Emails.HtmlBridge + <mj-raw>) and PDF (via
Accrue.Invoices.Layouts.print_shell/1).
Single source of truth
Both the email HTML body and the PDF body assemble these four
components (invoice_header/1, line_items/1, totals/1,
footer/1) against the same RenderContext. That is the entire
point of the Wave-2 render architecture — one component library,
two output pipelines, byte-identical money strings.
Inline-style discipline (Pitfall 2)
Every structural element carries its CSS via brand_style/1, which
reads from the frozen branding snapshot in @context.branding.
MJML's post-render CSS inliner does NOT descend into <mj-raw>
blocks — classname-only styles would be invisible in the final
email. Inline-or-nothing.
Transactional-only footer (D6-07)
Accrue emails are transactional (receipts, dunning, invoice
notifications) — CAN-SPAM exempts them from opt-out requirements,
and adding an opt-out link to a receipt is actively harmful UX.
The footer intentionally renders business_name + support_email
- conditional
company_addressand NOTHING ELSE.