{
  "title": "Render checks",
  "note": "These run after the document is rendered and before it is written to the output folder. A blocking failure stops the build, so the file never reaches a person. Every check is measured on the rendered page in print media, not asserted from the source.",
  "stage": "after render, before publish",
  "checks": [
    {
      "id": "page-fits",
      "name": "The page fits its sheet",
      "short": "Page fits",
      "measures": "The content height and width of every page element, measured in print media, against the sheet size the document declares.",
      "threshold": "No overflow in either axis. Two pixels of subpixel rounding is tolerated.",
      "proves": "Nothing has been pushed off the paper. This is the failure that hides best: the browser keeps scrolling, so the document looks complete on screen while the printer drops whatever ran past the edge.",
      "onFail": "The build stops. The file is not written and the run prints the page number and the overrun in inches.",
      "blocking": true
    },
    {
      "id": "no-orphan-heading",
      "name": "No orphan heading at a page foot",
      "short": "No orphans",
      "measures": "The room left below every section heading, h1 to h3, before the foot of the page it sits on. Card and cell titles below that level are not section headings and are not measured.",
      "threshold": "At least 0.9 inches of room below any heading.",
      "proves": "No section title is stranded at the bottom of a page with its body on the next one. It reads as a mistake even when nothing is missing.",
      "onFail": "The build stops and names the heading and the room measured. The fix is a page break before the heading, or trimming the section above it.",
      "blocking": true
    },
    {
      "id": "min-body-size",
      "name": "Body text at or above the floor",
      "short": "Type floor",
      "measures": "The computed font size of every paragraph, list item, and table cell carrying running text, in print media. Uppercase mono labels and page furniture are excluded and hold their own floor.",
      "threshold": "10.5 pixels, about 8 point.",
      "proves": "Nobody shrank the type to make the content fit. Shrinking type is the most common way an overflow gets hidden instead of fixed, and it passes the page fit check while making the document worse.",
      "onFail": "The build stops and prints the smallest run with its opening words, so the author can see which block was squeezed.",
      "blocking": true
    },
    {
      "id": "band-contrast",
      "name": "Contrast on dark bands",
      "short": "Band contrast",
      "measures": "Every text run whose effective background has a relative luminance below 0.2, scored against WCAG AA.",
      "threshold": "4.5 to 1 for normal text, 3 to 1 for text at 24 pixels, or 18.66 pixels and bold.",
      "proves": "Reversed type on the navy and steel bands is still readable, including after a colour is changed upstream in the brand tokens. One token edit can quietly break every band in the library.",
      "onFail": "The build stops and prints the ratio measured, the ratio required, and the offending text.",
      "blocking": true
    },
    {
      "id": "pages-declared",
      "name": "Every declared page is present",
      "short": "Page count",
      "measures": "The number of page objects in the rendered PDF against the page count declared in the document manifest.",
      "threshold": "Exactly equal.",
      "proves": "The document is the length it claims to be. An extra page usually means content reflowed, a missing page usually means a page break rule was dropped in an edit.",
      "onFail": "The build stops and prints both counts. The manifest is treated as the intent, so the document is fixed rather than the number.",
      "blocking": true
    },
    {
      "id": "image-resolution",
      "name": "Images at print resolution",
      "short": "Image ppi",
      "measures": "For every raster image, the intrinsic pixel width divided by the width it is printed at in inches.",
      "threshold": "200 pixels per inch effective.",
      "proves": "No screen sized asset has been dropped into a document that will be printed. A 320 pixel logo looks correct in a browser and soft on paper, and nobody notices until the box of printing arrives.",
      "onFail": "The build stops and names the file, the printed width, and the effective resolution. The fix is a larger source file, or inline SVG.",
      "blocking": true
    },
    {
      "id": "no-external-resources",
      "name": "No external resource except the font stylesheet",
      "short": "Self contained",
      "measures": "Every network request the document makes while it renders, and every stylesheet it links.",
      "threshold": "Zero requests off the document origin. One linked stylesheet, the font file at /assets/fonts/fonts.css.",
      "proves": "The document renders the same next year, offline, and inside an email client. A block pasted from elsewhere that quietly reaches a font CDN is the usual cause, and it fails silently at the worst moment.",
      "onFail": "The build stops and lists the offending URLs.",
      "blocking": true
    }
  ]
}
