--- name: a4-print-path description: Two non-obvious constraints in the A4 report print path — the print-root must be a direct body child, and flushSync (not rAF) must precede window.print() metadata: type: project --- Two constraints in `frontend/src/components/ReportEditor/a4/print/` that are easy to silently break and whose failure mode is a blank or wrong printed page. **1. `.print-root` must sit on the element appended directly to ``.** `print.css` hides the app with `body > *:not(.print-root)` — a CHILD combinator. The app mounts into `
`, itself a direct body child, so the print container is its sibling. If the class lived only on `PrintDocument`'s inner div, the appended container would match the hiding rule and print a blank page. **Why:** the selector is the entire mechanism for hiding the editor during print; there is no other switch. **How to apply:** when changing how the print container mounts, keep the class on the container itself. `printReport.js` sets it; `PrintDocument` repeats it for the standalone case. **2. `flushSync` — never `requestAnimationFrame` — before `window.print()`.** `window.print()` reads the DOM synchronously while React 18 commits asynchronously, so an unflushed render prints an empty container. rAF was the first fix tried and is wrong: it does not fire in a background or hidden tab, so a print click would hang instead of printing. **Why:** discovered when tests showed `window.print` never being reached behind a double-rAF await; the background-tab case is the production version of the same bug. **How to apply:** any new print entry point wraps its `root.render` in `flushSync` from `react-dom`. Related: `.a4-print-page` is deliberately NOT `.a4-page` — `A4Canvas.css` already owns `.a4-page` for the on-screen editor canvas, and both stylesheets load together.