/* Resume - /resume and its lane pages (/resume/<lane>).

   The page IS the resume: a centered document at its own measure (the
   on-screen stand-in for the 8.5x11 sheet it exports to), opted out of the
   shell's desktop grid - the tray overlays as a simple sticky bar.

   The wide layout thinks left-column-first: the left column (header with
   intro, current role, earlier roles) stacks NATURALLY, each piece its own
   row, its rhythm untouched. The right pieces (contracts, speaking/education)
   are ADDED AFTER that calculation - absolutely-positioned grid items
   centered on the left row they pair with (see the wide block below).

   Narrow screens: one flex column; `order` puts speaking/education after
   the earlier roles - current, contracts, earlier, more.

   All type comes from the voices; this file is geometry only. */

:root {
	--layout-resume-page: 66rem;
}

/* The /resume index lane picker - each lane is a small choice cluster
   (the label link, the roles it covers, its letter): air between the
   clusters, tight lines within - the same shape as the sheet's
   designation clusters. The em literals match the hand-authored rhythm
   in typography.css's .styled block. */
.resume-lanes {
	margin-top: 1.6em;

	li + li {
		margin-top: 1.4em;
	}

	li p {
		margin-top: 0.35em;
		max-width: 44em;
	}

	/* One voice per line: the global a.link rule carries calm-voice
	   metrics, which would bump these links a step over their
	   quiet-voice sentences (same fight as .resume-lane-nav). */
	li p a {
		font-family: inherit;
		font-size: inherit;
		font-weight: inherit;
		line-height: inherit;
	}
}

.resume {
	max-width: var(--layout-resume-page);
	margin-inline: auto;

	/* THE SPACING SYSTEM - Derek's pill sizes (his marked-up Figma
	   print, 2026-09-07), split per the house spacing model:

	   STRUCTURAL DIALS - plain rem (px in print), deliberately NOT
	   tracking type. Turn these to tune the sheet's composition:
	     --resume-space-entry  TEAL: between jobs, every column
	     --resume-space-lead   PURPLE: section leads (intro->first job,
	                           between the page's pieces)

	   READING RHYTHM - em, derives from the type it sits against
	   (these are the paragraph-level spaces, not layout dials):
	     --resume-space-cluster    RED: title->body, para->para in an entry
	     --resume-space-eyebrow    eyebrow->title inside a designation
	     --resume-space-paragraph  letter para->para: one blank em, the
	                               typographic standard for prose */
	--resume-space-entry: 1.5rem;
	--resume-space-lead: 2.6rem;
	--resume-space-break: 3.25rem;

	--resume-space-cluster: 0.75em;
	--resume-space-eyebrow: 0.3em;
	--resume-space-paragraph: 1em;

	/* Source order is the narrow reading order AND the parse order (ATS
	   bucketing: all work sections before speaking/education). No gap at
	   this level - each piece states its own space above (the wide and
	   print grids re-state these per their geometry). */
	display: flex;
	flex-direction: column;

	/* Narrow reads as one continuous job list (the section headings are
	   reader-only), so section boundaries between jobs use the JOB
	   rhythm; only the intro->first-job boundary is a lead. */
	.resume-current {
		margin-top: var(--resume-space-lead);
	}

	.resume-contracts,
	.resume-earlier {
		margin-top: var(--resume-space-entry);
	}

	/* The closing group (speaking/education) opens with the BREAK - the
	   one space on the sheet bigger than a lead. */
	.resume-more {
		margin-top: var(--resume-space-break);
	}


	/* Two mechanisms, by the house spacing model: READING RHYTHM is em
	   margins on siblings (the token values are em, so they resolve
	   against the type they sit beside); STRUCTURE (the piece stack, the
	   entry lists) is container gap below. */
	.resume-header p,
	.resume-speaking p,
	.resume-education p,
	.resume-entry p {
		margin-top: var(--resume-space-cluster);
	}

	.resume-intro p + p {
		margin-top: var(--resume-space-cluster);
	}

	.resume-entry hgroup h3 {
		margin-top: var(--resume-space-eyebrow);
	}

	/* The left column's jobs sit a full entry apart; the right column's
	   groups (the contracts, speaking/education) run slightly tighter -
	   proximity keeps each block reading as one visual group (Derek,
	   2026-09-08). Stated as a ratio of the entry dial, so tuning entry
	   keeps the relationship. */
	ol[role='list'] {
		display: grid;
		gap: var(--resume-space-entry);
	}

	.resume-contracts ol[role='list'],
	.resume-more {
		display: grid;
		gap: calc(var(--resume-space-entry) * 0.75);
	}

	/* The role sits on its own line under the name - one h1 (name + role
	   stay a single heading for readers and parsers), broken visually. */
	.resume-role {
		display: block;
	}

	/* Contact links stay links, but speak in the surrounding ink instead
	   of the accent - the header shouldn't shout its plumbing. */
	.resume-header a {
		color: inherit;
		text-decoration-color: var(--stroke-secondary);
	}


	.resume-intro {
		max-width: 44em;

		/* The intro speaks in the accent - the one colored voice on the
		   sheet (per the Figma comp), painted from the scope's slot so
		   every mood/flavor re-inks it. On the p too: the typography
		   layer gives p its own color. */
		color: var(--accent);

		p {
			color: var(--accent);
		}
	}

	/* Zero the margins the typography layer gives text elements - inside
	   the resume, ALL rhythm is container gap. */
	p,
	h1,
	h2,
	h3,
	hgroup {
		margin: 0;
	}



	/* The axis only exists where the parallel columns do. */
	.timeline-axis {
		display: none;
	}

	.resume-lane-nav {
		/* The meta nav sits two leads below the sheet - it's not resume. */
		margin-top: calc(2 * var(--resume-space-lead));

		/* One voice for the whole line: the global a.link rule carries
		   calm-voice metrics, which made the links shout over their
		   quiet-voice sentence. */
		a {
			font-family: inherit;
			font-size: inherit;
			font-weight: inherit;
			line-height: inherit;
		}
	}
}

@media (min-width: 1024px) {
	/* The lane pages opt OUT of the shell's desktop grid: this page is the
	   document, not a page-with-sidebar composition. Block flow is the
	   phone posture, which works at every width. The panel's placement for
	   this posture is restated beside the other posture rules in
	   settings-panel.css. The /resume index (data-page 'resume', no slash)
	   keeps the normal shell. */
	.page-wrapper[data-page^='resume/'] {
		display: block;
	}

	.resume {
		display: grid;
		grid-template-columns: 3fr 2fr;
		column-gap: 4em;
		align-items: start;
		position: relative;

		/* No row-gap - each left row states its space above: a lead
		   before the first job, the JOB rhythm between the job sections
		   (separate sections for parsing, one continuous list to the
		   eye). */
		.resume-current {
			margin-top: var(--resume-space-lead);
		}

		.resume-earlier {
			margin-top: var(--resume-space-entry);
		}

		/* The left column stacks naturally, each piece its own row. */
		.resume-header {
			grid-column: 1;
			grid-row: 1;
		}

		.resume-current {
			grid-column: 1;
			grid-row: 2;
		}

		.resume-earlier {
			grid-column: 1;
			grid-row: 3;
		}

		/* The right column is CALCULATED FROM the left one, never the other
		   way around. Each right piece is an absolutely-positioned grid
		   item: it still takes its grid area as its containing block (the
		   grid is position: relative), but it no longer sizes the track -
		   so the left column's flow is untouchable by anything over here.
		   Contracts use PE's row as their reference box and center on it,
		   overflowing above and below as their height needs; the
		   speaking/education block does the same against the earlier-roles
		   row. */
		/* NOTE the explicit end lines: on absolutely-positioned grid items
		   an auto end line means "to the edge of the grid", not "span 1" -
		   without /4 the reference box runs to the article's bottom and
		   the centering lands way low. */
		.resume-contracts {
			position: absolute;
			grid-column: 2 / 3;
			grid-row: 2 / 3;
			top: 50%;
			transform: translateY(-50%);
			width: 100%;
			/* The narrow stack's piece margin must not shift this
			   absolute box - placement here is the positioning math. */
			margin-top: 0;
			anchor-name: --resume-contracts;
		}

		.resume-more {
			position: absolute;
			grid-column: 2 / 3;
			grid-row: 3 / 4;
			top: 50%;
			transform: translateY(-50%);
			width: 100%;

			/* Centering can't see the contracts' tail hanging into this
			   band from the row above - bias the block down a BREAK so
			   the closing-group space survives content growth up there. */
			margin-top: var(--resume-space-break);
		}

		/* The real rule: the closing group hangs exactly one BREAK below
		   the contracts' actual bottom edge - computed per lane (their
		   contracts columns end at different heights), never a magic
		   number. The margin rule above is the no-anchor fallback. */
		@supports (top: anchor(top)) {
			.resume-more {
				top: calc(anchor(--resume-contracts bottom) + var(--resume-space-break));
				transform: none;
				margin-top: 0;
			}
		}

		/* The axis is drawn, not a grid track: an absolute line standing in
		   the column gap, at the 3/5 seam plus half the gap. */
		/* The axis wears the accent, like the intro - the story and its
		   direction are the same voice, re-inked by every mood/flavor. */
		.timeline-axis {
			display: block;
			position: absolute;

			/* The line starts 11px down, tucked behind the arrowhead's
			   solid base - at top: 0 it ran up behind the head's
			   transparent corners and its tip poked out past the apex
			   (Derek, 2026-09-08). The head pulls itself back up. */
			top: 11px;
			bottom: 0;
			left: calc((100% - 4em) * 0.6 + 2em);
			width: 2px;
			background: var(--accent);

			&::before {
				content: '';
				position: absolute;
				top: -11px;
				border-left: 7px solid transparent;
				border-right: 7px solid transparent;
				border-bottom: 12px solid var(--accent);
				transform: translateX(-6px);
			}
		}

		.resume-lane-nav {
			grid-column: 1 / -1;
			grid-row: 4;
		}
	}

}

/* COVER LETTER - the resume's sibling sheet (/resume/<lane>/cover-letter).
   The article wears both classes (.resume .cover-letter), so the identity
   header, the spacing dials, the wide grid with its axis, and the whole
   print pipeline all come from the resume rules above - this block is only
   the letter's own geometry: one column of prose in the left column, the
   right column deliberately empty (the wide margin is the letter's own
   posture; the axis still stands in the gap, same arrow, same accent). */
.cover-letter {
	.letter-body {
		margin-top: var(--resume-space-lead);
		max-width: 44em;
	}

	/* Letter paragraph rhythm is READING rhythm, not a structural dial
	   (walked with Derek, 2026-09-08 - cluster read as a wall, a
	   structural entry-ratio read as arbitrary): its own em token,
	   deriving from the type like all reading rhythm, at the one-blank-
	   em typographic standard for prose. */
	.letter-body p + p {
		margin-top: var(--resume-space-paragraph);
	}
}

/* The letter's closing detaches from the body (Derek's marked-up print,
   2026-09-08): a lead before the signoff, another before the signature -
   the farewell is its own moment, not the last paragraph. The p-qualified
   selectors are load-bearing: these ARE p + p siblings, and the body's
   cluster rule (0,2,2) silently beat the bare class (0,2,0) - which is
   exactly the tight closing Derek circled. */
.cover-letter .letter-body p.letter-signoff,
.cover-letter .letter-body p.letter-signature {
	margin-top: var(--resume-space-lead);
}


@media (min-width: 1024px) {
	.cover-letter {
		.letter-body {
			grid-column: 1;
		}

		/* The letter has no rows 2-3 of resume sections - let the nav
		   land after the letter naturally. */
		.resume-lane-nav {
			grid-row: auto;
		}
	}
}

/* PRINT - the resume routes export to a designed letter PDF (the ground
   truth is headless Chrome's --print-to-pdf, not the browser preview).
   Measured facts this block designs around (2026-09-06, verified in
   exported PDFs - don't re-derive):
     - print media queries evaluate at ~741px viewport width, so the
       screen breakpoints serve the narrow layout to print; the print
       layout is fully declared here with fixed dimensions, no
       min/max-width logic.
     - letter is 816x1056 CSS px; with @page margin 0.45in the content
       box is ~730px wide.
     - Chrome never auto-shrinks - overflow becomes extra pages, so page
       count is the fit signal.
   Scoped to the resume pages via data-page so the rest of the site's
   print behavior is untouched.

   The verification loop (run after ANY change in here):
     chrome --headless --print-to-pdf=out.pdf --no-pdf-header-footer <route>
     pdfinfo out.pdf   -> exactly 1 page
     pdffonts out.pdf  -> zero Type 3 (Type 3 = broken copy/paste)
     PDFKit (osascript) landmark offsets strictly increasing - the true
     probe for Preview copy/paste order; pdftotext alone misses paint-
     order regressions from positioned elements. */

/* Print fonts - STATIC cuts of the Product pair, self-hosted. Chrome
   embeds VARIABLE fonts into PDFs as Type 3 glyph programs with custom
   encoding, which breaks copy/paste and ATS text extraction ("Iteach
   productdesign"); static cuts embed as CID TrueType and extract clean
   (diagnosed 2026-09-06, resume-exploration session, via pdffonts).
   Distinct "* Print" family names so they can never shadow the screen's
   variable faces; the @media print block below points the font tokens at
   them. Files from Fontshare's static API (same faces the site already
   licenses), living in /fonts/print/. */
@font-face {
	font-family: 'Quicksand Print';
	font-weight: 500;
	src: url('/fonts/print/quicksand-500.woff2') format('woff2');
}

@font-face {
	font-family: 'Quicksand Print';
	font-weight: 600;
	src: url('/fonts/print/quicksand-600.woff2') format('woff2');
}

@font-face {
	font-family: 'Quicksand Print';
	font-weight: 700;
	src: url('/fonts/print/quicksand-700.woff2') format('woff2');
}

@font-face {
	font-family: 'Spline Sans Print';
	font-weight: 400;
	src: url('/fonts/print/spline-sans-400.woff2') format('woff2');
}

@font-face {
	font-family: 'Spline Sans Print';
	font-weight: 500;
	src: url('/fonts/print/spline-sans-500.woff2') format('woff2');
}

@font-face {
	font-family: 'Spline Sans Print';
	font-weight: 600;
	src: url('/fonts/print/spline-sans-600.woff2') format('woff2');
}

@font-face {
	font-family: 'General Sans Print';
	font-weight: 400;
	src: url('/fonts/print/general-sans-400.woff2') format('woff2');
}

@font-face {
	font-family: 'General Sans Print';
	font-weight: 500;
	src: url('/fonts/print/general-sans-500.woff2') format('woff2');
}

@media print {
	@page {
		size: letter;

		/* Top is taller on purpose: Derek's physical test print clipped
		   nearly the full name height at 0.4in - real printers' grip
		   margins eat into the sheet's top edge. */
		margin: 0.65in 0.4in 0.4in;
	}

	/* THE SHEET'S TYPE SPEC - pinned, not derived. The PDF bounces from
	   ONE theme (Derek's call, 2026-09-06), so print typography doesn't
	   stay theme-generic: each pattern gets an exact size/leading measured
	   against the Figma comp. px on purpose - print is a fixed medium and
	   these are design decisions, not preferences to scale. The root size
	   still feeds the em-based spacing below. */
	html {
		font-size: 12.5px;
	}

	.resume {
		/* Name and role: a compact identity cluster, not a hero. */
		h1 {
			font-size: 15px;
			line-height: 1.2;
		}

		.resume-role {
			font-size: 12.5px;
			line-height: 1.3;
		}

		/* Contact line: quiet plumbing. Links inherit the line's size -
		   the global a.link rule carries calm-voice metrics and would
		   otherwise bump them a step up. */
		.resume-header > p {
			font-size: 10.5px;
			line-height: 1.4;
		}

		.resume-header a {
			font-size: inherit;
			line-height: inherit;
		}

		.resume-intro p {
			font-size: 11.5px;
			line-height: 1.45;
		}

		/* Eyebrow: small, tracked, sitting tight over its title. The
		   selector must out-rank ".resume-entry p" (the body-size rule) -
		   the eyebrow IS a p, and a bare .stamp-voice loses that fight
		   (which silently swallowed three size changes, 2026-09-07). */
		.resume-entry p.stamp-voice {
			font-size: 9px;
			letter-spacing: 0.08em;
		}

		/* Entry titles: one confident step above body. */
		.resume-entry h3,
		.resume-more h2 {
			font-size: 13px;
			line-height: 1.25;
		}

		/* Body: solid paragraph color, set snug. */
		.resume-entry p,
		.resume-more p {
			font-size: 11.5px;
			line-height: 1.42;
		}
	}

	/* The hidden group headings ("Experience", ...) must make it into the
	   PDF TEXT LAYER for ATS segmenters, but stay invisible on the sheet.
	   The screen clip recipe (1px box) drops the glyphs from Chrome's
	   print output entirely, so print swaps the mechanism: in flow with
	   a small real band and transparent ink - no pixels, but the text
	   run lands in the PDF at its true position. */
	.resume .reader-only {
		position: static;
		width: auto;
		overflow: visible;
		clip-path: none;
		white-space: normal;
		margin: 0;
		color: transparent;

		/* The invisible glyphs own a REAL 12px band IN FLOW - no overlap
		   tricks (a negative-margin overlay left them a hair from the
		   eyebrow's line and extractors interleaved the two; a transform
		   shoved them to the stream's end via paint order). The band's
		   height is paid for by the row-gap below, so the visual lead
		   space stays exactly one purple. */
		font-size: 8px;
		height: 12px;
		line-height: 12px;
	}

	/* Nothing on the sheet that isn't resume: chrome, nav, footer. The
	   @page margin owns the sheet's margins, so main's screen padding
	   (including the 80px --page-top) hands its space back. The sheet
	   itself is paper-white regardless of theme - the one deliberate
	   color (the intro's accent) opts in via print-color-adjust below. */
	[data-page^='resume/'] {
		background: #fff;

		main {
			padding: 0;
			background: #fff;
		}

		.site-tray,
		.site-shade,
		.tray-sentinel,
		.rotate-notice,
		.site-footer,
		.resume-lane-nav {
			display: none;
		}
	}

	/* THE PRINT ACCENT - pinned, not inherited from the live theme (the
	   export's color must never be an accident of theme defaults). A
	   VIVID royal blue on purpose: blue is the one hue whose saturation
	   is nearly free in black-and-white (luminance is ~71% green, ~21%
	   red, ~7% blue), so this pops in color yet still grays to near-body
	   dark - unlike the screen green, which IS brightness and washes
	   out. A per-target brand color would re-dial this one token. */
	.resume {
		--resume-print-accent: #2a4abf;

		.resume-intro,
		.resume-intro p {
			color: var(--resume-print-accent);
		}
	}

	/* The static print families take over the tokens the voices read
	   from. This MUST land at :root - the voice family tokens
	   (--calm-voice-font-family etc.) are defined there, and a var()
	   inside a custom property resolves on the element that defines it,
	   so a lower-scope override never reaches them (same reason the
	   characters swap fonts on <html>). Scoped to resume pages via :has. */
	:root:has([data-page^='resume/']) {
		--font-heading: 'Quicksand Print', 'Quicksand', system-ui, sans-serif;
		--font-body: 'Spline Sans Print', 'Spline Sans', system-ui, sans-serif;
		--font-sans: 'General Sans Print', 'General Sans', system-ui, sans-serif;
	}

	.resume {
		/* The four space tokens, re-valued for paper (Derek's print check,
		   2026-09-07: one even rhythm between ALL jobs - section and entry
		   spaces are deliberately equal on the sheet). */
		--resume-space-section: 22px;
		--resume-space-entry: 22px;
		--resume-space-cluster: 7px;
		--resume-space-eyebrow: 2px;

		display: grid;
		grid-template-columns: 1fr 260px;
		column-gap: 44px;
		position: relative;
		max-width: none;

		/* No row-gap - each left row states its space above, minus the
		   hidden 12px heading band each section opens with: a lead before
		   the first job, the JOB rhythm between the job sections. */
		.resume-current {
			margin-top: calc(var(--resume-space-lead) - 12px);
		}

		.resume-earlier {
			margin-top: calc(var(--resume-space-entry) - 12px);
		}

		/* The timeline spine, drawn in the column gap - arrowhead up top
		   (reverse chronology: time flows upward), then the line. */
		&::before {
			content: '';
			position: absolute;
			top: 0;
			left: calc(100% - 282px);
			transform: translateX(-50%);
			border-left: 5px solid transparent;
			border-right: 5px solid transparent;
			border-bottom: 9px solid var(--resume-print-accent);
		}

		/* The spine wears the accent too - the intro and the timeline are
		   the same voice: this is the story, this is its direction. */
		&::after {
			content: '';
			position: absolute;
			top: 9px;
			bottom: 0;
			left: calc(100% - 282px);
			width: 1px;
			background: var(--resume-print-accent);
		}

		.resume-header {
			grid-column: 1;
			grid-row: 1;
		}

		.resume-current {
			grid-column: 1;
			grid-row: 2;
		}

		.resume-earlier {
			grid-column: 1;
			grid-row: 3;
		}

		/* Every section joins the POSITIONED paint phase (relative, no
		   offsets - zero visual effect). Why: the contracts block below is
		   position: absolute, and positioned boxes paint AFTER normal
		   flow - which pushed the contracts to the END of the PDF's
		   content stream, breaking extraction order (measured via PDFKit,
		   2026-09-06). With every sibling positioned, paint order = DOM
		   order, and the text stream reads: current, contracts, earlier,
		   speaking/education. */
		.resume-header,
		.resume-current,
		.resume-earlier,
		.resume-more {
			position: relative;
		}

		/* Same move as the screen layout: an absolutely-positioned grid
		   item takes PE's row as its containing block and centers on it,
		   sizing nothing. (Safe here because the sheet is one page - an
		   absolute block never fragments across pages.) */
		.resume-contracts {
			position: absolute;
			grid-column: 2 / 3;
			grid-row: 2 / 3;
			top: 50%;
			transform: translateY(-50%);
			width: 100%;
			/* The narrow stack's piece margin must not shift this
			   absolute box - placement here is the positioning math. */
			margin-top: 0;
			anchor-name: --resume-contracts;
		}

		/* Centered on the earlier-roles band, same as the screen layout -
		   the row is much taller than this block, so centering costs no
		   height and sits clear of the contracts' tail above. */
		.resume-more {
			grid-column: 2;
			grid-row: 3 / 4;
			align-self: center;

			/* The contracts above are out of flow, so the space between
			   their tail and this block can't derive naturally - the
			   margin biases the centering down by a BREAK (doubled: a
			   centered box shifts by only half its margin). */
			margin-top: calc(2 * var(--resume-space-break));
		}

		/* The real rule: one BREAK below the contracts' actual bottom,
		   computed per lane - never a magic number. The margin rule
		   above is the no-anchor-support fallback; headless Chrome,
		   the entire print pipeline, takes this one. */
		@supports (top: anchor(top)) {
			.resume-more {
				position: absolute;
				top: calc(anchor(--resume-contracts bottom) + var(--resume-space-break));
				align-self: auto;
				width: 100%;
				margin-top: 0;
			}
		}

		.resume-entry,
		.resume-speaking,
		.resume-education {
			break-inside: avoid;
		}

		/* Links read as text on paper - the URLs already say what they
		   are; underlines read "webpage". The ::after glyph marks (the
		   outward arrows from setup.css) come off too: they pull a system
		   font into the PDF and mean nothing on paper. */
		a {
			text-decoration: none;
			color: inherit;

			&::after {
				content: none;
			}
		}

		/* The intro keeps its accent - the one deliberate color on the
		   sheet - so ask the printer to honor it. */
		.resume-intro {
			print-color-adjust: exact;
		}
	}

	/* The cover letter on paper: prose in the left column of the same
	   print grid, the right column empty on purpose - the spine and
	   arrow stand in the gap exactly where the resume puts them, so the
	   pair reads as one set. Letter prose sits at the resume's body
	   size AND leading - the pair must read as one set (a looser 1.5
	   was tried and read as mismatched; Derek, 2026-09-08). */
	.cover-letter {
		.letter-body {
			grid-column: 1;
			margin-top: var(--resume-space-lead);
		}

		.letter-body p {
			font-size: 11.5px;
			line-height: 1.42;
		}
	}

}
