--- name: html-template-authoring description: Author or repair a Portwood HTML template that renders correctly through Blob.toPdf (Flying Saucer). Use when writing a new template, converting a design to a template, or fixing one whose PDF output doesn't match the source — collapsed layout, missing images, wrong fonts, broken charts. --- # Authoring HTML templates for Portwood **HTML is the recommended source format.** It skips the DOCX→HTML parse and lands more reliably in the renderer. Steer new authors here, and chart authors here without exception. ## The renderer is CSS 2.1 `Blob.toPdf` is Flying Saucer: **CSS 2.1 plus a small CSS 3 subset**. Unsupported properties are _silently ignored_ — the page still renders, but layout collapses to default block flow. Nothing warns you. ### Never use - `display: flex`, `display: grid`, `gap` - `linear-gradient(...)` and friends - `calc(...)` - CSS custom properties (`var(--x)`) - most CSS 3 layout ### Use instead - ``-based layout for anything multi-column - solid background colors - absolute lengths (`pt`, `in`) and percentages - `display: table-cell` / `table-row` on `
` where you need cell behavior without a real table ### The `tbody` trap ```css table > tbody > tr > td { ... } /* silently matches NOTHING */ ``` The parse tree has no implied `
`. Use `td` attribute selectors or class-only selectors: ```css td.total { ... } ``` ## Images **URLs must be relative.** Absolute `https://…` URLs and `data:` URIs both render broken — this is a hard constraint of the renderer, not a bug to work around. If the same image appears at two different sizes, the renderer caches **one layout size per URL**. Vary the URL to force a re-layout (the engine appends a size key for this reason). ## Fonts and symbols The base font families resolve to the base-14 PDF fonts (Helvetica / Times / Courier, WinAnsi). **Anything outside Latin-1 renders as nothing** — not a box, not a fallback, absent. Checkmarks, arrows, CJK, Greek, Cyrillic all disappear. `'Arial Unicode MS'` is the one family that draws them, embedding as a subsetted CID font. The trade-off is real and worth knowing: | | Symbols / CJK | Bold | | -------------------- | ------------- | ------------------------------------------------------ | | `'Arial Unicode MS'` | ✅ | ❌ — no bold face; `font-weight: bold` renders regular | | every other family | ❌ | ✅ | So a symbol-heavy document gives up bold. Build hierarchy from **size, colour and fill bands** instead — reversed white-on-dark headers, tinted totals rows, a solid band behind the key number. Embedding costs roughly 1.5KB → 70KB per page that uses it, and only for the glyphs used. ## `@page` conflicts The engine builds a `