Print and export
Compliance reviewers read on paper and patients print results for appointments. What the print stylesheet does, and what a printed health value must carry.
What we guarantee
Printing is treated here as an accessibility surface rather than a convenience, for two reasons that are specific to this domain. Compliance reviewers read documentation on paper and annotate it. And patients print or screenshot results to take to an appointment, which means a printed health value becomes a clinical artefact in somebody else's hands, stripped of every tooltip and hover state that explained it.
app/globals.css carries a real @media print block. It does the following, and
each item is there because of a specific failure:
- Removes chrome that carries no information on paper, so the printed page
starts with the content. The banner, the main navigation, the sidebar, the
sub-navigation and the table of contents are each named individually. It never
removes
asideas an element, and it says so in a comment:<StubNotice>,<SafetyCallout>and<ResearchNote>are all asides, and the same block restores those three positively so that a later chrome selector cannot quietly take them out again. A caveat that vanishes on paper is worse than no caveat, because the reader cannot tell it was ever there. - Forces a white background and black text at 11pt, because a dark-theme print is unreadable and wastes toner.
- Strips
backdrop-filter,box-shadowandtext-shadowglobally. Translucency does not survive a printer; it prints as a grey smear over the text. - Puts a
1ptsolid black border around every[data-status]element and setsprint-color-adjust: exact. The status word is always present, so the colour is not load-bearing. Even so, the border means the pill is still visibly a discrete object after a black-and-white photocopy. - Resolves external link targets into the text, appending the URL after any
httplink insidemain. A printed page with a bare "see here" is useless in a review file. - Prevents tables, figures, code blocks, block quotes and safety callouts from splitting across a page break, and keeps headings with the content that follows them. A threshold table broken across two sheets is a classic way for a reviewer to misread a number.
- Sets an 18 mm page margin, so there is room to write in.
The product theme adds a second @media print block of its own in
app/product.css. It redeclares --background, --card, --foreground,
--card-foreground, --muted-foreground and --border as ink on paper, and it
carries every material rung to its opaque fallback. So a screen printed from the
dark theme prints as ink on white rather than as pale text on a dark fill. This is
the half a consuming product actually ships, because the product stylesheet travels
with the theme a product installs while the docs-site globals.css above does not.
What you own
What a printed result must still say. This is the important half of the page. A health value on paper has lost its context and gained an unknown reader. It must still carry:
- The value, its unit and its precision. They are never truncated and never abbreviated past recognition.
- When it was measured, as an absolute date and time.
RelativeTimerenders "2 hours ago" on screen, which is meaningless on a sheet of paper found next week. Anything printed resolves to an absolute stamp. - What measured it, where that affects how the number should be read. See Data provenance and device accuracy.
- The status word, not the status colour.
- The disclaimer, if one was shown on screen. A printout that drops the "this is not a diagnosis" line has changed what the document claims.
- A visible boundary. The print stylesheet drops a background colour and a
box-shadow, and it keeps an outline and a border. A surface that leaned on its
fill or its shadow to show where it ends prints as boundaryless content on a
same-coloured page. opsinjs draws a Surface edge as
an outline for exactly this reason, so a surface at a rung that publishes a
border keeps its boundary on paper. That is the
card,raised,sheetandoverlayrungs, which is what Card, MetricTile, Dialog and Sheet render. The three rungs that publish no border by design,canvas,insetandscrim, draw no edge on screen or on paper, so a panel built on one of those prints boundaryless, and a product that draws its own container edge must reach for a property in the second group, an outline or a real border, never the first.
Pagination of long data. A twelve-month log printed as one enormous table needs repeated headers on each page. That is a product decision.
Whether printing is offered at all. Some data should not be trivially exported. See On-screen privacy.
How to check
Print to PDF, then read the PDF
Read the file rather than the print preview. Expected result: no navigation, no translucency, no split tables, every external link resolved, and a date on every value. Failure looks like the sidebar occupying the first two pages.
Photocopy it in black and white
Or print it greyscale. Expected result: every status is still identifiable from its word and its border. This is the same check as Colour independence, applied to the medium where colour is most likely to be lost.
Print at a different paper size
A4 and US Letter differ enough to break a fixed-width table. Check both if the audience is international.
Hand it to somebody with no context
Give the printed page to a colleague who did not see the screen and ask what the numbers mean and when they were taken. Anything they cannot answer is missing from the output.
Measured results
scripts/capture-registry.mts. Run pnpm run generate and reload.Nothing on this site types a measured number by hand, so an ungenerated table shows this rather than an example.
There is no automated print check. A rendered-to-PDF snapshot of the reviewer path would be the right artefact, and it needs a browser automation pass that this project deliberately does not install.
Known gaps
- The print stylesheet has never been tested against a real printer, only reasoned about.
- There is no PDF export path, for the reviewer bundle or for anything else; printing is the only route to paper.
- The printed-value rules are implemented per component, but nothing verifies a
whole screen end to end. RelativeTime resolves to an absolute stamp in print
(
print:not-sr-only), Surface draws a printed boundary on every rung that publishes a border, and several components shipprint:rules, so the rules are no longer absent. What is still missing is any check that one screen carries the value with its unit and precision, the status word and the disclaimer onto paper together, because there is no automated print capture to assert against. - Page numbers, running headers and a printed provenance footer are not
implemented, beyond the review stamp the stylesheet appends to
[data-reviewed].
Updates to this page
Last read through against the system on 2026-09-02. Due for review every 12 months; expiry is reported by pnpm run check:freshness.
Cognitive accessibility
Reducing load, removing time limits and making every error recoverable is the accessibility work that matters most in health and is measured least.
Accessibility statement
A dated, honest statement of what has and has not been assessed, written so that a reviewer can tell the difference.