/* Paper.
 *
 * Everything in this file is inside one `@media print` block, so linking it is
 * unconditional and it can never touch the screen. It is the only place print
 * rules live: the alternative — an `@media print` tail on each of page.css,
 * docs.css, rnd.css, admin.css and public.css — is five places to remember and
 * four of them are not loaded by the blog shell, which is a page people print.
 *
 * The single wrapper also keeps this file out of selfcheck.js's shell check,
 * which walks top-level rules looking for a bare page tag: a rule inside a
 * media block has no selectorText at that level and is never seen. That is the
 * right answer — a page laid out only on paper is still a page that lays out
 * wrong on screen — so do not unwrap this into bare rules with media="print"
 * on the link.
 *
 * # The palette flips at :root and nothing else has to know
 *
 * There is no light theme (see the head of main.css, which explains why), and
 * that is exactly the problem paper poses: a browser drops background colours
 * by default and keeps foreground ones, so printing this site unstyled gives
 * chalk text on white paper — a blank sheet with the ink used up on nothing.
 *
 * Every colour in this codebase is a token from main.css, including inside the
 * shadow roots of the widgets, because a custom property inherits across a
 * shadow boundary. So redefining the tokens here re-colours the whole site at
 * once — the documentation reader, the R&D pages, the blog, the comment panel
 * and the delivery register — and no component needs a print rule of its own.
 * Keep it that way: a hardcoded colour anywhere is a thing that stays dark on
 * paper, and there are none today.
 *
 * The surfaces are set to near-white rather than to a grey that reads well,
 * and that is deliberate. Whether the reader has "background graphics" switched
 * on is not knowable here, so every surface is chosen to look the same printed
 * as dropped. The two exceptions are the search marks, which mean nothing
 * without their fill and therefore ask for it explicitly.
 *
 * # Layout becomes blocks
 *
 * The page shells are flex and grid containers whose spacing comes from `gap`.
 * Both fragment unevenly across pages, so the vertical ones are turned into
 * blocks and their gaps restored as margins. Small horizontal groupings — a
 * meta row, a card's row — stay flex: they never span a page boundary.
 */

@media print {

/* --- The sheet ----------------------------------------------------------- */

@page {
	/* Roomy on the left for a punch or a staple, and a deeper foot because
	   that is where the browser puts the URL and the page number. */
	margin: 16mm 15mm 18mm 18mm;
}

/* The cross-report comparison is eighteen columns and the only thing here that
   is not prose. Named pages are ignored by browsers that do not implement them,
   which is why the table below is also made to wrap: portrait is the fallback,
   not a failure. */
@page wide {
	size: landscape;
	margin: 12mm;
}

pg-rnd-compare { page: wide; }

:root {
	/* Form controls, scrollbar corners and anything else the UA paints. */
	color-scheme: light;

	/* --- Palette, flipped --------------------------------------------- */

	--void: #FFFFFF;
	--surface-1: #FAFAFA;
	--surface-2: #F4F4F5;
	--scrim: #FFFFFF;

	/* The one hue survives, darkened until it is ink. #FF4A4A is 2.6:1 on
	   white and unreadable; this is 7.0:1, and it still reads as the same red
	   on a colour printer and as a distinctly darker grey on a mono one.
	   Do not lighten it back toward the screen value — red is the only hue
	   the interface has and on paper it has to carry that as text. */
	--redline: #A81919;
	--redline-hi: #8A1212;
	/* Rules and outlines only, as on screen. */
	--redline-dim: #C97A7A;
	--redline-tint: rgba(168, 25, 25, 0.14);

	--chalk: #111113;
	--chalk-dim: #2A2A2E;
	--chalk-tint: rgba(0, 0, 0, 0.08);

	/* Borders invert with the ground: dark at low alpha, not light. */
	--hairline: rgba(0, 0, 0, 0.22);
	--hairline-strong: rgba(0, 0, 0, 0.42);

	--dark-color-1: var(--surface-1);
	--dark-color-2: var(--surface-2);

	/* Foreground tiers. --light-color-4 is body copy in page.css and is not
	   dimmed for paper: a grey that reads as "secondary" on a backlit screen
	   reads as a bad photocopy printed. */
	--light-color-1: #0A0A0B;
	--light-color-2: #0A0A0B;
	--light-color-3: #1B1B1E;
	--light-color-4: #303036;

	--on-dark-1: #0A0A0B;
	--on-dark-2: rgba(10, 10, 11, 0.82);
	--on-dark-muted: rgba(10, 10, 11, 0.58);

	--lighten-color-1: rgba(0, 0, 0, 0.045);
	--lighten-color-2: rgba(0, 0, 0, 0.08);

	--darken-color-1: rgba(0, 0, 0, 0.03);
	--darken-color-2: #F7F7F8;

	/* Code. Near-monochrome as on screen, with the keyword on the red so a
	   diff still comes out red-out and black-in. */
	--code-comment: #56565E;
	--code-string: #26262C;
	--code-number: #8A3A16;
	--code-keyword: var(--redline);
	--code-type: #111113;
}

/* --- The document flow --------------------------------------------------- */

html {
	/* Every size in this codebase is a rem, so the whole scale is set here
	   once, in a unit that means something on paper. */
	font-size: 11pt;
	background: #FFFFFF;
}

body {
	display: block;
	min-height: 0;
	font-size: 1rem;
	background: #FFFFFF;
	/* Registered custom properties interpolate; nothing should be mid-flight
	   when the page is snapshotted. */
	transition: none;
}

pg-router {
	display: block;
	width: auto;
	flex: none;
}

/* The page shells — the two lists selfcheck.js reads, in page.css and rnd.css,
   plus .home-page, which is the server-rendered front page's root and not a
   component: see the note in page.css.
   `width: 100vw` is the window on screen and the paper here, which with any
   margin at all overflows the sheet; `overflow-x` clips a wide table at the
   edge of the last page it fits on. Both go. */
.home-page, pg-login, pg-verify-login, pg-activate, pg-account,
pg-confirm-email-change, pg-confirm-account-closure,
pg-write-posts, pg-write-post-edit, pg-admin-access, pg-docs,
pg-rnd, pg-rnd-wing, pg-rnd-session, pg-rnd-report, pg-rnd-study,
pg-rnd-compare {
	display: block;
	width: auto;
	overflow: visible;
}

/* Nothing floats over paper. A fixed or sticky box is either repeated on every
   sheet or stranded on the first one, and every one of them here is furniture:
   the nav bar, the progress bar, the document rail, the comments panel. */
* {
	position: static !important;
	animation: none !important;
	transition: none !important;
	box-shadow: none !important;
	scroll-margin-top: 0 !important;
}

/* --- What does not print ------------------------------------------------- */

/* Chrome, in both senses. A control is an offer to do something, and paper
   cannot take it up.
 *
   Listed one by one rather than hidden as `button`, and the exceptions are why:
   a rating in the report form and a cell in the access matrix are buttons whose
   *label is the data* — "Granted", "No", the ring that is on. A blanket rule
   would print those two pages blank in exactly the places worth printing them,
   and a value missing from a sheet of paper leaves nothing behind to notice. */
pg-nav-bar,
pg-loader,
pg-toast,
pg-tooltip,
pg-search,
.btn,
.actions,
.docs-nav,
.docs-aside,
.docs-nav-toggle,
.docs-source-toggle,
.docs-linkish,
.docs-comment-actions button,
.back-link,
.post-back,
a.join-btn,
.footer-links,
pg-verify-login .resend-row,
pg-write-post-edit .bar,
pg-rnd-report .rating button.clear,
.hp-field,
.visually-hidden {
	display: none !important;
}

/* The two that stay. Both say which state they are in with a fill, and a fill
   is the one thing a printer may decide not to lay down, so both restate it in
   weight and rule — which survives a mono printer and a dropped background
   alike. */
.rating button,
pg-admin-access .cell-btn {
	background: none;
	color: var(--light-color-1);
	border: 1px solid var(--hairline);
}

/* The colour is restated as well as the border: both of these are --void on a
   filled ground on screen, which is white ink once the fill is dropped. */
.rating button.on,
pg-admin-access .cell-btn.on,
pg-admin-access .cell-btn.armed {
	border: 2px solid var(--light-color-1);
	color: var(--light-color-1);
	background: none;
	font-weight: 700;
}

/* The gate's remaining text is worth printing — it says why the rest of the
   post is not there — but without its button it is a card with a hole in it.
   Qualified with .card because that is the rule it has to beat, further down. */
.card.gate { border: none; padding: 0; }

/* The photograph is a full-bleed absolutely-positioned frame with a gradient
   scrim over it, and neither survives pagination: the scrim is a background and
   is dropped, leaving white type on a photograph. The band prints as what it
   says instead. */
.home-page .hero-media,
.home-page .hero-scrim { display: none !important; }

/* The front page sets its own paddings on the shared bands — 88px and 72px, to
   give a page with four short blocks on it the air it is made of. On paper the
   sheet's margins are that air, and the 24px inline padding is an indent the
   rest of the site does not have. */
.home-page .header,
.home-page .header.hero,
.home-page .section {
	padding: 0;
	min-height: 0;
}

.home-page .header,
.home-page .header.hero { padding-bottom: 10pt; }

.home-page .section { margin: 0 0 14pt; }

/* --- Bands and containers ------------------------------------------------ */

/* Vertical flex and grid containers become blocks, and their `gap` comes back
   as margins. Flexbox and grid fragmentation across pages is where printed
   layouts actually break — a row split down the middle, or a card leaving its
   heading on the previous sheet. */
.header,
.header-inner,
.section,
.inner,
.card,
form,
.rnd-grid,
.rnd-now,
.rnd-prototypes,
pg-rnd section,
pg-rnd-wing section,
pg-rnd-session section,
pg-rnd-study section,
.docs-page,
.docs-content {
	display: block;
	width: auto;
	max-width: none;
	gap: 0;
}

.header-inner > * + * { margin-top: 5pt; }
.section > * + * { margin-top: 14pt; }
.inner > * + * { margin-top: 11pt; }
.card > * + * { margin-top: 10pt; }
form > * + * { margin-top: 10pt; }
.rnd-grid > * + * { margin-top: 8pt; }
.rnd-now > * + * { margin-top: 7pt; }
.rnd-prototypes > * + * { margin-top: 9pt; }
pg-rnd section > * + *,
pg-rnd-wing section > * + *,
pg-rnd-session section > * + *,
pg-rnd-study section > * + * { margin-top: 10pt; }

/* The title band. A filled strip is a page of solid ink; a rule under it says
   the same thing and stays with the heading it introduces. */
.header {
	background: none;
	border-bottom: 1px solid var(--hairline-strong);
	padding: 0 0 10pt;
	margin: 0 0 16pt;
	break-after: avoid;
	break-inside: avoid;
}

.section {
	padding: 0;
	margin: 0 0 14pt;
}

.card {
	border-radius: 0;
	padding: 10pt 12pt;
	break-inside: avoid;
}

/* --- Type ---------------------------------------------------------------- */

/* The clamps resolve against the paginated viewport, which is the page box, so
   they give something between "large" and "unpredictable" depending on paper
   size. Pinned instead. */
.header h1 { font-size: 20pt; line-height: 1.1; }
.section h2 { font-size: 13pt; }
.home-page .statement { font-size: 15pt; max-width: none; }
.home-page .lead { max-width: none; }

h1, h2, h3, h4, h5, h6,
.docs-title, .rnd-card h3, pg-rnd-report legend {
	break-after: avoid;
	break-inside: avoid;
}

p, li, blockquote, dd {
	orphans: 3;
	widows: 3;
}

/* A term stays with its answer. The report read view is nothing but these. */
dt { break-after: avoid; }
dd { break-inside: avoid; }

.rnd-card,
.rnd-prototype,
.rnd-now,
.row,
.meta > div,
pg-rnd-report .field,
pg-rnd-report fieldset { break-inside: avoid; }

/* --- Links --------------------------------------------------------------- */

/* Underlined, because on paper a coloured word with no rule under it reads as
   emphasis rather than as a reference — and on a mono printer it reads as
   nothing at all. */
.doc-body a,
.post-body a,
.section a { text-decoration: underline; }

/* The heading permalinks. `opacity: 0` hides them on screen but still reserves
   the space, which prints as a gap after every heading. */
.doc-body .anchor { display: none; }

/* An address is worth the ink only where it leads somewhere a reader with a
   sheet of paper can go. The cross-reference graph of `docs/` is eighty-odd
   backticked paths per document rendered as in-app links; expanding those would
   put `/docs?p=...` after every one of them and bury the prose. So: external
   links only, and never the code-links that carry the graph. */
.doc-body a[href^="http"]:not(.code-link)::after,
.post-body a[href^="http"]::after {
	content: " <" attr(href) ">";
	font-size: 0.85em;
	word-break: break-all;
	text-decoration: none;
}

/* --- Tables -------------------------------------------------------------- */

/* .table-scroll is a horizontal scroll container, which on paper is a clip:
   everything past the column width is simply not printed, silently. The tables
   in `docs/` are the reason the reader has a wider column than the rest of the
   site — 758 rows of them — so this is the rule that decides whether printing
   a document is worth doing at all. */
.doc-body .table-scroll,
.post-body .table-scroll,
pg-rnd-compare .table-scroll,
pg-rnd-wing .table-scroll,
pg-rnd-session .table-scroll,
pg-admin-access .matrix-scroll {
	overflow: visible;
	max-width: none;
	border-radius: 0;
}

table { break-inside: auto; }

/* Repeat the header on every sheet a table spans. It is the default, and it is
   stated because a `display` on thead anywhere would silently take it away and
   the second page of a table with no headings is unreadable. */
thead { display: table-header-group; }
tfoot { display: table-footer-group; }
tr { break-inside: avoid; break-after: auto; }

.doc-body table,
.post-body table { font-size: 8.5pt; }

.doc-body th, .doc-body td,
.post-body th, .post-body td { padding: 4pt 6pt; }

/* Eighteen columns onto one sheet. The screen rule sizes this to max-content
   and lets it scroll; here it has to fit, so the cells wrap and the type comes
   down. Combined with the landscape @page above it lands; without it — on a
   browser that ignores named pages — it still fits portrait, tightly. */
pg-rnd-compare .inner,
pg-rnd-compare .header-inner,
pg-rnd-compare .header-inner > * { max-width: none; }

pg-rnd-compare table {
	width: 100%;
	table-layout: auto;
	font-size: 7.5pt;
}

pg-rnd-compare th,
pg-rnd-compare td {
	white-space: normal;
	padding: 3pt 4pt;
}

/* --- Code ---------------------------------------------------------------- */

/* A code block is another scroll container. Wrapping is the only honest answer
   on paper — a clipped line is indistinguishable from a short one. */
pre, .doc-body pre, .doc-body .highlight pre, .post-body pre {
	overflow: visible;
	white-space: pre-wrap;
	word-break: break-word;
	border-radius: 0;
	break-inside: avoid;
	font-size: 8pt;
}

/* --- Images -------------------------------------------------------------- */

img {
	max-width: 100%;
	height: auto;
	break-inside: avoid;
}

/* --- Forms --------------------------------------------------------------- */

/* Not hidden. A report is read from `.answers` rather than from the form, but
   a draft open in the editor should still print what is in it. The controls
   inherit the flipped palette; only the screen's dark scheme has to be undone. */
input, textarea, select {
	color-scheme: light;
	background: none;
	border: 1px solid var(--hairline);
}

form label { background: none; }

/* --- The documentation reader -------------------------------------------- */

/* The rail and the outer column — the contents list, and what has been
   delivered against the document — are gone (above), so the document is the
   page. The paddings that placed it in the window are the sheet's margins
   now. */
.docs-content { padding: 0; margin: 0; }

.docs-content > * + * { margin-top: 14pt; }

.docs-main { min-width: 0; }

/* The source path stays, and it is the most useful thing on the sheet: it is
   the string that finds the file the printout came from, which is the whole
   reason it is shown on screen. */
.docs-source-row {
	display: block;
	padding-bottom: 6pt;
	margin-bottom: 14pt;
}

/* Tighter than the screen's 1.7. A document here runs to 180 KB and the leading
   that makes a backlit column comfortable costs about a tenth of the sheets. */
.doc-body {
	max-width: none;
	line-height: 1.55;
}

.doc-body h2 { margin: 22pt 0 7pt; padding-top: 7pt; }
.doc-body h3 { margin: 14pt 0 5pt; }
.doc-body h1 { font-size: 18pt; margin: 0 0 12pt; }

/* Both marks ask for their fill explicitly, because both mean something the
   text does not say. `.first` also has to stop being a filled chip: it is
   --void on --redline on screen, which with backgrounds dropped is white on
   white — the search result the reader printed, invisible. */
.doc-body mark.q,
.doc-body mark.q.first {
	background: var(--redline-tint);
	color: var(--light-color-1);
	print-color-adjust: exact;
	-webkit-print-color-adjust: exact;
}

.doc-body mark.q.first { box-decoration-break: clone; font-weight: 600; }

/* An open panel prints after the document rather than beside it, and without
   its scroll container: a panel capped at the height of a screen loses every
   comment past the first few. A resolved comment is dimmed on screen and
   printed at full strength — 0.62 opacity is legible backlit and grey on
   paper. */
.docs-comments {
	max-height: none;
	overflow: visible;
	border-left: none;
	border-top: 1px solid var(--hairline-strong);
	padding: 10pt 0 0;
	font-size: 9pt;
	break-before: auto;
}

/* On screen each note is placed level with the passage it quotes, which leaves
   it absolutely positioned with an inline `top` measured in screen pixels. Paper
   has no margin column to place anything in — the panel is under the document —
   so they go back into the flow, where the inline offset is inert rather than
   wrong. The clamp on the quote comes off with it: two lines is right beside a
   marked passage the reader can look at, and the marks are not printed. */
.docs-comments.anchored { position: static; }

.docs-comments.anchored > .docs-comment,
.docs-comments.anchored > .docs-comment-form {
	position: static;
	border: none;
	border-top: 1px solid var(--hairline-strong);
	border-radius: 0;
	background: none;
	padding: 8pt 0;
}

.docs-comments.anchored > .docs-comment.located .docs-comment-quote {
	display: block;
	overflow: visible;
	-webkit-line-clamp: none;
	line-clamp: none;
}

.docs-comment { opacity: 1; break-inside: avoid; }
.docs-comment.resolved { opacity: 1; }
.docs-comment-form,
.docs-comment-hint { display: none; }

.docs-comment-suggestion {
	white-space: pre-wrap;
	word-break: break-word;
}

/* --- The R&D module ------------------------------------------------------ */

/* A status is a word in a box on screen and a word in a box on paper — it is
   the state of the thing the sheet describes, not decoration. */
.rnd-status { print-color-adjust: exact; -webkit-print-color-adjust: exact; }

pg-rnd-report fieldset { border-color: var(--hairline); }

pg-rnd-report .answers dd,
pg-rnd-session .answers dd,
pg-rnd-wing .answers dd { break-inside: avoid; }

/* A document or a post opening on a heading puts that heading's own rule
   directly under the band's, which reads as a double line. The band already
   made the separation. */
.doc-body > :first-child,
.post-body > :first-child {
	margin-top: 0;
	padding-top: 0;
	border-top: none;
}

/* --- The server-rendered pages, and the footer every page now has --------- */

#page-main { display: block; width: auto; overflow: visible; }

/* The footer is site-wide chrome rather than the blog's (styles/page.css), so
   this reaches the SPA too. What it keeps on paper is the line naming the
   operating company; .footer-links is hidden above with the rest of the
   navigation, because three link labels with nothing behind them are noise on
   a sheet somebody is holding. The flex row goes with them. */
.page-footer {
	display: block;
	border-top: 1px solid var(--hairline);
	padding: 8pt 0 0;
	margin: 16pt 0 0;
	max-width: none;
	break-inside: avoid;
}

.post-body { max-width: none; }
.post-list-item { break-inside: avoid; }
.lock-chip { print-color-adjust: exact; -webkit-print-color-adjust: exact; }

/* --- The marking --------------------------------------------------------- */

/* Every page this application serves behind a session is internal — the
   documentation tree reaches unit economics, both royalty agreements and the
   decision log, and the R&D pages carry unreleased prototype detail. A sheet
   that has left the screen has left every gate with it, so it says what it is.
   It also says the thing this repository's working agreement says about
   documents: a printout is a copy, and a copy is the one thing here that cannot
   be corrected.
 *
   Written as an exclusion rather than a list, so it fails closed: a page added
   to the route table is marked internal until somebody decides otherwise, and
   the four public routes are named because being public was a decision. The
   blog shell has no <pg-router>, so it is never reached at all. */
pg-router > *::before {
	content: "Perigee — internal. This is a printed copy; the repository holds the current version.";
	display: block;
	margin-bottom: 10pt;
	padding-bottom: 4pt;
	border-bottom: 1px solid var(--redline-dim);
	color: var(--redline);
	font-size: 7.5pt;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	break-after: avoid;
}

pg-router > pg-login::before,
pg-router > pg-verify-login::before,
pg-router > pg-activate::before { content: none; }

}
