/* ============================================================
   josephguzik.com
   Two panels: a fixed portrait, a scrolling content column.
   Palette sampled from the portrait — warm gold from the
   sunrise light, teal from the Atlantic.
   ============================================================ */

:root {
	/* surfaces */
	--ink:        #0b0d10;
	--rule:       rgba(255, 255, 255, 0.10);
	--rule-soft:  rgba(255, 255, 255, 0.07);

	/* type */
	--paper:  #f1efea;
	--muted:  #b3b9c1;
	--faint:  #868d97;

	/* accents */
	--gold:   #f0b95c;
	--teal:   #6fd0c4;

	/* ---- type scale: six steps, no in-between sizes ---- */
	/* the name is nowrap, so this cap is bounded by panel width, not taste.
	   Space Grotesk Bold sets wide — re-measure the rendered glyph width
	   before raising it. */
	--t-display: clamp(2.5rem, 4.2vw, 3.6rem);
	--t-quote:   clamp(1.45rem, 2.2vw, 1.8rem);
	--t-lead:    1.125rem;   /* 18px — role + article titles      */
	--t-body:    1rem;       /* 16px — paragraphs, list items     */
	--t-small:   0.9375rem;  /* 15px — notes, quieter sections    */
	--t-micro:   0.8125rem;  /* 13px — labels, tagline, nav       */

	/* layout */
	--panel:   44vw;
	--measure: 36rem;   /* ~68 characters at --t-body */
	--column:  46rem;   /* outer lane; footer spans this */

	/* Shared alignment: the masthead is exactly this tall, and the
	   content column starts exactly this far down. The top of the photo
	   and the top of the quote therefore land on the same line, which is
	   what makes the two halves read as one composition. */
	--head: 12rem;

	--serif: "Instrument Serif", Georgia, "Times New Roman", serif;
	/* the name only — its own family, so it stays distinct from both the body
	   (Inter) and the labels (JetBrains Mono) */
	--display: "Space Grotesk", "Inter", -apple-system, Helvetica, Arial, sans-serif;
	--sans:  "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
	--mono:  "JetBrains Mono", ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
	margin: 0;
	background: var(--ink);
	color: var(--paper);
	font-family: var(--sans);
	font-size: var(--t-body);
	line-height: 1.7;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

/* ---------- skip link ---------- */

.skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
	padding: 0.75rem 1.25rem;
	background: var(--gold);
	color: var(--ink);
	font: 500 var(--t-micro)/1 var(--sans);
	text-decoration: none;
}
.skip:focus { left: 0; }

/* ============================================================
   Portrait panel — fixed, full height
   ============================================================ */

.portrait {
	position: fixed;
	inset: 0 auto 0 0;
	width: var(--panel);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	border-right: 1px solid var(--rule);
	background: var(--ink);
}

/* ---------- the wash ----------
   A blurred, darkened copy of the same photo filling the whole panel. This is
   what removes the hard edges: the sharp photo can keep its true aspect and
   crop while still having imagery above and below it, at any window size.
   Because it is blurred there is nothing sharp to look distorted, so it can be
   over-scaled to fill freely — which stretching the real photo could not do.
   scale(1.25) hides the transparent fringe blur leaves at the edges. */
.portrait__wash {
	position: absolute;
	inset: 0;
	z-index: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 56% 42%;
	transform: scale(1.25);
	/* Two separate things are going on here; keep both.

	   1. STEPPED BY HEIGHT. `cover` on a tall panel upscales the source
	      enormously — at 1900px tall the image renders ~3565px wide, where a
	      small fixed blur is barely 1% of the image and the face stays
	      recognisable behind the real photo. The blur has to grow with it.

	   2. !important IS LOAD-BEARING. Browser extensions (dark-mode, reader
	      and accessibility ones) inject `style="filter: invert(0);"` onto
	      <img> elements. An inline style beats a normal stylesheet rule, so
	      that silently wipes out the whole declaration — no blur, no dimming,
	      just a sharp second face behind the portrait. Author !important
	      outranks a non-important inline style, which is what wins it back.
	      Confirmed in Chrome 151 with such an extension installed. */
	filter: blur(48px) saturate(0.75) brightness(0.4) !important;
	pointer-events: none;
}

@media (min-height: 900px) {
	.portrait__wash { filter: blur(64px) saturate(0.75) brightness(0.4) !important; }
}
@media (min-height: 1200px) {
	.portrait__wash { filter: blur(88px) saturate(0.75) brightness(0.38) !important; }
}
@media (min-height: 1600px) {
	.portrait__wash { filter: blur(116px) saturate(0.75) brightness(0.36) !important; }
}
@media (min-height: 2000px) {
	.portrait__wash { filter: blur(140px) saturate(0.75) brightness(0.34) !important; }
}

/* Darkens the wash where the name and links sit, so text stays legible over
   it, and sinks the very top and bottom into the ink so the panel has no
   visible seam against the page. */
.portrait__veil {
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(
		to bottom,
		rgba(11, 13, 16, 0.94) 0%,
		rgba(11, 13, 16, 0.62) 14%,
		rgba(11, 13, 16, 0.42) 34%,
		rgba(11, 13, 16, 0.48) 62%,
		rgba(11, 13, 16, 0.88) 86%,
		rgba(11, 13, 16, 0.97) 100%
	);
}

.portrait__masthead,
.portrait__media,
.portrait__links { position: relative; z-index: 2; }

/* fixed height so the photo below it starts on the shared --head line */
.portrait__masthead {
	flex: none;
	height: var(--head);
	display: flex;
	flex-direction: column;
	justify-content: center;
	padding: 0 clamp(1.75rem, 3.5vw, 3.25rem);
}

.portrait__name {
	margin: 0;
	font-family: var(--display);
	font-weight: 700;
	font-size: var(--t-display);
	line-height: 1.05;
	letter-spacing: -0.035em;
	white-space: nowrap;
}

.portrait__name .family { color: var(--gold); }

.portrait__role {
	margin: 1rem 0 0;
	font-family: var(--mono);
	font-size: var(--t-micro);
	line-height: 1.8;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--muted);
}

.portrait__role .sep { color: var(--gold); padding: 0 0.35em; }

/* keeps each phrase whole — "Food-first" would otherwise be free to break
   at its hyphen when the panel narrows */
.portrait__role .role__item { white-space: nowrap; }

/* The source photo is landscape (3:2). Sizing the media box by its own
   aspect ratio keeps the crop near the original framing. Tie the cap to
   panel WIDTH, not viewport height, or a tall narrow window crops it down
   to a slice of his face. */
.portrait__media {
	position: relative;
	flex: 1 1 auto;
	width: 100%;
	aspect-ratio: 6 / 5;
	max-height: calc(var(--panel) * 1.15);
	min-height: 0;
	overflow: hidden;
	/* deliberately no background: a solid fill here would paint a hard-edged
	   rectangle behind the feathered photo and reinstate the very cut lines
	   the mask exists to remove. The wash shows through instead. */
}

/* Feathered top and bottom rather than a scrim: a mask fades the sharp photo
   into the blurred wash behind it, so there is no cut line under the title or
   above the links — the image emerges from and dissolves back into the panel.
   A scrim could not do this; it would paint flat ink over the wash. */
.portrait__img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 56% 42%;
	-webkit-mask-image: linear-gradient(
		to bottom,
		transparent 0%,
		rgba(0, 0, 0, 0.10) 10%,
		rgba(0, 0, 0, 0.42) 24%,
		rgba(0, 0, 0, 0.80) 37%,
		#000 47%,
		#000 72%,
		rgba(0, 0, 0, 0.55) 88%,
		rgba(0, 0, 0, 0.16) 96%,
		transparent 100%
	);
	mask-image: linear-gradient(
		to bottom,
		transparent 0%,
		rgba(0, 0, 0, 0.10) 10%,
		rgba(0, 0, 0, 0.42) 24%,
		rgba(0, 0, 0, 0.80) 37%,
		#000 47%,
		#000 72%,
		rgba(0, 0, 0, 0.55) 88%,
		rgba(0, 0, 0, 0.16) 96%,
		transparent 100%
	);
}

/* margin-top:auto pins these to the bottom edge, so the panel reads as a
   balanced column: name, photo, links */
.portrait__links {
	flex: none;
	display: flex;
	flex-wrap: wrap;
	gap: 1.5rem;
	margin: 0;
	margin-top: auto;
	padding: clamp(1.25rem, 2.5vw, 1.75rem) clamp(1.75rem, 3.5vw, 3.25rem) clamp(1.75rem, 3.5vw, 3.25rem);
	list-style: none;
	font-family: var(--mono);
	font-size: var(--t-micro);
	letter-spacing: 0.04em;
}

.portrait__links a {
	color: var(--muted);
	text-decoration: none;
	border-bottom: 1px solid transparent;
	padding-bottom: 2px;
	transition: color 0.18s ease, border-color 0.18s ease;
}
.portrait__links a:hover,
.portrait__links a:focus-visible {
	color: var(--teal);
	border-bottom-color: var(--teal);
}

/* ============================================================
   Content column
   ============================================================ */

.content {
	margin-left: var(--panel);
	padding: var(--head) clamp(1.5rem, 4vw, 4rem) 5rem;
}

.content__inner { max-width: var(--column); }

/* one left edge for everything in this column; only the max-width varies */
.section__body,
.quote,
.footer > * { max-width: var(--measure); }

/* ---------- opening pull quote ---------- */

.quote {
	position: relative;
	margin: 0 0 clamp(2.5rem, 5vh, 4rem);
	padding-left: 2.5rem;
	max-width: 40rem;
}

/* hanging quote mark, sized off the text it opens */
.quote::before {
	content: "\201C";
	position: absolute;
	left: 0;
	top: -0.18em;
	font-family: var(--serif);
	font-size: 3.25rem;
	line-height: 1;
	color: var(--gold);
	opacity: 0.6;
}

.quote p {
	margin: 0;
	font-family: var(--serif);
	font-size: var(--t-quote);
	line-height: 1.34;
	letter-spacing: -0.01em;
	color: var(--paper);
	text-wrap: pretty;
}

.quote cite {
	display: block;
	margin-top: 1rem;
	font-family: var(--mono);
	font-size: var(--t-micro);
	font-style: normal;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--faint);
}

.quote cite::before { content: "\2014\00a0"; color: var(--gold); }

/* ---------- sections ---------- */

.section {
	padding: clamp(2.25rem, 5vh, 3.25rem) 0;
	border-top: 1px solid var(--rule-soft);
}

/* one rule per section boundary — the label carries no second hairline */
.section:first-of-type { border-top: 0; padding-top: 0; }

.section__label {
	margin: 0 0 1.35rem;
	font-family: var(--mono);
	font-size: var(--t-micro);
	font-weight: 500;
	line-height: 1.4;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--teal);
}

.section p { margin: 0 0 1.1rem; color: var(--muted); }
.section p:last-child { margin-bottom: 0; }
.section p strong { color: var(--paper); font-weight: 600; }

/* ---------- links in body copy ---------- */

.section a,
.footer a {
	color: var(--paper);
	text-decoration: none;
	border-bottom: 1px solid rgba(240, 185, 92, 0.45);
	transition: color 0.18s ease, border-color 0.18s ease;
}
.section a:hover,
.section a:focus-visible,
.footer a:hover,
.footer a:focus-visible {
	color: var(--gold);
	border-bottom-color: var(--gold);
}

/* ---------- Now: day job + side projects ---------- */

.role {
	margin: 0 0 2rem;
	padding-left: 1.25rem;
	border-left: 2px solid var(--gold);
}

.role__title {
	margin: 0 0 0.4rem;
	font-size: var(--t-lead);
	font-weight: 600;
	line-height: 1.45;
	color: var(--paper);
}

.role__note { margin: 0; font-size: var(--t-small); color: var(--faint); }

.aside-label {
	margin: 0 0 1rem;
	font-family: var(--serif);
	font-size: var(--t-lead);
	font-style: italic;
	color: var(--faint);
}

.stack { margin: 0; padding: 0; list-style: none; }

/* Marker is positioned rather than a flex child: as flex items the text
   nodes and the <a> become separate boxes, which breaks link text onto
   its own line. This keeps each item a single wrapping text run. */
.stack li {
	position: relative;
	padding: 0.45rem 0 0.45rem 1.7rem;
	font-size: var(--t-body);
	line-height: 1.6;
	color: var(--muted);
}

.stack li::before {
	content: "+";
	position: absolute;
	left: 0;
	top: 0.45rem;
	font-family: var(--mono);
	font-weight: 500;
	line-height: 1.6;
	color: var(--gold);
}

/* ---------- Previously / Consuming: tagged rows ---------- */

.rows { margin: 0; padding: 0; list-style: none; }

.rows li {
	padding: 0.85rem 0;
	border-bottom: 1px solid var(--rule-soft);
	font-size: var(--t-body);
	line-height: 1.65;
	color: var(--muted);
}
.rows li:first-child { padding-top: 0; }
.rows li:last-child  { border-bottom: 0; padding-bottom: 0; }

.tag {
	display: inline-block;
	margin-right: 0.7rem;
	font-family: var(--mono);
	font-size: 0.6875rem;
	font-weight: 500;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--teal);
	/* optical lift so the small caps sit centred against body text */
	transform: translateY(-1px);
}

/* Consuming carries the least weight on the page — a step down in size,
   not a step down into illegibility */
.section--quiet .rows li {
	font-size: var(--t-small);
	color: var(--faint);
}

/* ---------- Writing ----------
   Currently UNUSED — the Writing section was removed from index.html, but
   is expected back, so these rules are kept deliberately. Do not delete as
   dead code. The markup to restore it is in README.md, under
   "Restoring the Writing section". */

.pieces { margin: 0; padding: 0; list-style: none; }

.pieces li {
	padding: 0.9rem 0;
	border-bottom: 1px solid var(--rule-soft);
}
.pieces li:first-child { padding-top: 0; }
.pieces li:last-child  { border-bottom: 0; padding-bottom: 0; }

.pieces a {
	display: block;
	border-bottom-color: transparent;
}

.piece__title {
	display: block;
	font-size: var(--t-lead);
	font-weight: 500;
	line-height: 1.45;
	color: var(--paper);
}

.piece__sub {
	display: block;
	margin-top: 0.3rem;
	font-size: var(--t-small);
	line-height: 1.55;
	color: var(--faint);
}

/* underline only the title, not the whole two-line block */
.pieces a:hover .piece__title,
.pieces a:focus-visible .piece__title {
	color: var(--gold);
	box-shadow: inset 0 -1px 0 var(--gold);
}

/* ---------- footer ---------- */

.footer {
	margin-top: clamp(2.5rem, 5vh, 3.5rem);
	padding-top: clamp(2rem, 4vh, 2.75rem);
	border-top: 1px solid var(--rule);
}

/* the closing quote gets the full lane — it reads as a line, not a column */
.footer__quote {
	max-width: none;
	margin: 0 0 1.5rem;
	font-family: var(--serif);
	font-size: clamp(1.2rem, 1.9vw, 1.55rem);
	font-style: italic;
	line-height: 1.4;
	color: var(--muted);
	text-wrap: balance;
}

.footer__meta {
	max-width: none;
	margin: 0;
	font-family: var(--mono);
	font-size: var(--t-micro);
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--faint);
}

/* ============================================================
   Focus + motion
   ============================================================ */

:focus-visible {
	outline: 2px solid var(--teal);
	outline-offset: 3px;
	border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		transition-duration: 0.01ms !important;
		animation-duration: 0.01ms !important;
	}
}

/* ============================================================
   Narrow screens — portrait becomes a hero, content flows below
   ============================================================ */

@media (max-width: 900px) {
	.portrait {
		position: relative;
		inset: auto;
		width: 100%;
		height: auto;
		border-right: 0;
		border-bottom: 1px solid var(--rule);
	}

	/* the shared --head line only exists in the two-column layout */
	.portrait__masthead {
		height: auto;
		padding: clamp(2rem, 7vw, 2.75rem) clamp(1.25rem, 6vw, 2.5rem) clamp(1.5rem, 5vw, 2rem);
	}

	/* the panel is full-width here, so the width-based cap no longer
	   applies — let the photo take a natural landscape band instead */
	.portrait__media {
		flex: none;
		aspect-ratio: 4 / 3;
		max-height: 58vh;
	}

	.portrait__img { object-position: 56% 34%; }

	.portrait__links { padding: 1.25rem clamp(1.25rem, 6vw, 2.5rem) 1.75rem; }

	.content {
		margin-left: 0;
		padding: clamp(2.5rem, 8vw, 3.5rem) clamp(1.25rem, 6vw, 2.5rem) 3.5rem;
	}

	.content__inner { max-width: none; }
}

@media (max-width: 480px) {
	.portrait__media { aspect-ratio: 5 / 4; }
	.portrait__links { gap: 1.15rem; }

	/* the name is one line by design; let it shrink rather than overflow */
	.portrait__name { font-size: clamp(2rem, 10.5vw, 2.5rem); }
}

/* ============================================================
   Print
   ============================================================ */

@media print {
	body { background: #fff; color: #000; }
	.portrait { position: static; width: 100%; height: auto; border: 0; }
	.portrait__masthead { height: auto; }
	.portrait__img, .portrait__scrim { display: none; }
	.portrait__name, .portrait__name .family { color: #000; }
	.content { margin-left: 0; padding: 0; }
	.section p, .stack li, .rows li { color: #222; }
	.section a { color: #000; border-bottom-color: #999; }
}
