:
contentHeight = section.scrollHeight ← includes clipped overflow
frameHeight = svg.viewBox.height ← the visible frame (720)
overflowY = max(0, contentHeight - frameHeight)
fillRatio = contentHeight / frameHeight
```
`scrollHeight` reports the **full** content height including the clipped portion, which is exactly the diagnostic we need.
## Gotcha: Marp does not render ` ```mermaid ` fences
Marp CLI has **no built-in mermaid support**. A ` ```mermaid ` fenced code block is emitted into the rendered HTML/PDF/PPTX as a literal `…
` block — never a diagram, and with no warning. Client-side mermaid.js plugins only work in `--html` output; they leave a static `` in `--pdf`/`--pptx`. The reliable fix is to **pre-render every ` ```mermaid ` fence to an SVG on disk** during deck assembly (via `mermaid-cli` / `mmdc`) and replace the fence with a `` image reference, then constrain image height in CSS so the SVG fits the 720 px viewBox.
> **Full recipe** — `mmdc` pre-render script, mermaid syntax gotchas (`{}`/`()`/`[]` in labels, `
`, backticks), regression detection, and diagram-sizing CSS: [`references/mermaid-prerender.md`](references/mermaid-prerender.md).
### Gotcha — `section img { display: block }` pushes inline emoji onto their own line
The diagram-sizing rule above (`section img { … display: block; … }`) is a **broad selector**: it matches *every* `
` Marp emits, not just your mermaid SVGs. If the theme renders emoji as images (Twemoji — the default on many Marp themes turns `☕`, `🐢`, `🌐` into `
`), `display: block` forces each emoji onto its own line, so a bullet like `… at 2 a.m. ☕` wraps the coffee cup to a new line and a one-line contact row (`🌐 site 🐙 github 🐦 x`) collapses into a vertical stack.
Fix: scope a counter-rule for the emoji class, on the affected slide (`