# Marp - Themes, Export, and Deck QA
Marp decks fail silently in repeatable ways: theme CSS that no-ops, exports that drop slides, and page math that drifts. Each failure has a fix and a cheap mechanical check.
## Key points
- A CSS-only footer rides the `section::after` pseudo-element with `top: 30px; bottom: auto`, right-anchored like the header. A `<!-- footer: -->` directive is not needed.
- Marpit emits `data-footer` only when the footer text is non-empty, and Marp CSS uses that attribute for bottom padding. `footer: ""` silently removes the padding, so tall slides drift into the footer zone. `footer: " "` (one space) keeps both with no visible text.
- Marp strips inline `style` attributes from HTML divs, so an inline layout override silently no-ops and theme classes take over. Declare custom layout classes in the deck's `style:` front-matter block.
- A theme that sets `img { display: block }` blocks `text-align: center` from centering images. Use `margin: auto` on images instead.
- A punchline class that renders both `##` and `#` headings at full punchline size forces a punchline slide to carry exactly one `#` line and no `##` heading. Otherwise the two headings overlap.
- A theme rule `pre { overflow: hidden }` clips wide code instead of scaling it when the theme lacks the `@auto-scaling` metadata, so split dense code slides rather than shrink them.
- Marp wraps every diagram in `<marp-auto-scaling data-downscale-only>` with a `width: max-content` container, so a theme `width: 100%` diagram rule is inert: diagrams never upscale, small ones stay tiny, and `max-height` letterboxes tall ones. Put palette and scale rules on the auto-scaling container or in `themeCSS`.
- On advanced-background slides, Marp layers a pseudo section above the content section, and its opaque footer band hides the real footer text. Footer workarounds must target all pseudo sections, not only image-slide classes.
- Decorative images can land on Marp's reserved pagination pseudo-element. Move them off that element.
- CSS rule order can silently break modifier classes: a block placed after the color-modifier rules overrides them with no warning. Pixel sampling found this when CSS review missed it.
- `*` list items render as `<li data-marpit-fragment="1">` and trigger progressive reveals, while `-` items render plain. A format-on-save pass that rewrites `-` to `*` changes the reveal behavior. It is not a style-only change.
- `marp --theme-set <file>` fails. Point `--theme-set` at a CSS directory, driven by a `marp.config.js` with `themeSet`.
- `npx marp --input-dir slides/ --output dist/ --html` is the portable build command with local npm dependencies and a `marp.config.js`.
- Marp inlines theme CSS into exported HTML but leaves `url()` references to `fonts/` and `assets/` relative. The browser resolves them against `presentation.html`, not the canonical CSS, so standalone HTML needs output-local resources. PDF export masks this failure because Marp resolves source paths while rendering.
- An HTML deck that loads diagrams from kroki.io at load time can show none of them on flaky conference Wi-Fi. Present from an offline HTML variant that embeds the diagrams.
- The `--images` export can silently drop slides. Deck QA needs the PDF path, rendered to per-slide images.
- `grep -c "^---
quot;` gives the exact slide count without parsing front matter or running the renderer.
- Splitting deck markdown on `---` to compute page numbers is off by one against the real PDF because of the front-matter block. Locate pages by heading text from `pdftotext` instead.
- Not every color in pptx XML is content: editor guides appear as named colors and over-report the palette. The real accents match the theme assets.
- Unzip a pptx and byte-compare `ppt/media/*` against theme assets. Byte-identity proves a variant was captured, and leftover media names are exactly the uncaptured variants.
- Put a prose-cleanup pass between the author pass and the coherence review. It removes style-level tropes before the holistic reviewer judges the whole deck. Otherwise feedback mixes structural and stylistic concerns.
- Render inside the review loop: render, review, fix, render. The PDF stays current when the reviewer judges it, and the pipeline exports it on pass. A one-shot end-of-pipeline render leaves the PDF stale after every revision.
## How to apply
```bash
# exact slide count without running the renderer
grep -c "^---quot; <deck>.md
# portable build with local npm deps and marp.config.js
npx marp --input-dir slides/ --output dist/ --html
# contact sheet of every slide for a fast visual pass
pdftoppm -r 40 -png <deck>.pdf /tmp/p && montage /tmp/p-*.png -tile 4x -geometry +3+3 /tmp/m.png
# render only problem pages at higher resolution, for example -r 60
# slide geometry (content extent vs footer band) when image analysis is unavailable
pdftotext -bbox <deck>.pdf
# pixel check on rendered pages; fixed coordinates only, percent syntax is not supported
magick ... %[pixel:p{20,40}]
```
Run deck QA on the PDF, never on the `--images` export.
## Observations
- [export] `--theme-set` takes a CSS directory through `marp.config.js`, never a single file. #marp (source: agent sessions, 2026-04)
- [process] Render inside the review loop so the reviewed PDF is never stale. #process (source: agent sessions, 2026-06)
- [export] Exported HTML resolves relative asset URLs against itself, not the theme CSS. #marp (source: agent sessions, 2026-08)
- [export] The image export can drop slides silently, so QA runs on the PDF. #presentations (source: agent sessions, 2026-09)
- [qa] Markdown page math is off by one against the PDF, so locate pages by heading text. #pdf (source: agent sessions, 2026-11)
- [assets] Named colors in pptx XML include editor guides, so theme assets hold the true palette. #pptx (source: agent sessions, 2026-11)
## Relations
- relates_to [[resources/documentation/Hugo - Drafts and PaperMod Upkeep]] (publishing pipelines for generated content)
- relates_to [[resources/patterns/Verify Claims Against Primary Sources]] (deck QA checks rendered output, not the source)
- relates_to [[resources/documentation/Vale - Prose Linting for Docs and Vaults]] (prose-cleanup passes in a content pipeline)
## Sources
- Personal agent-session notes, January 2026 to November 2026