/*
 * Site styles.
 *
 * Mobile-first and intentionally plain. The goal at this stage is structure:
 * every meaningful element carries a class or id so the visual design can be
 * layered on later without touching the templates.
 *
 * Layout summary for the feed:
 *   - small screens: single column, image on top, both captions below it
 *   - wide screens : three columns, captions flanking a centered image
 */

/* ---------- Fonts ---------- */

/*
 * Suisse Intl is the main typeface (reading text, navigation, headings).
 * Suisse Works (a serif) is used for the CV and the feed captions. Both are
 * served as woff2. Three faces of each are loaded: book/regular (400),
 * its italic (400) and medium (500). Files live in ./fonts.
 */
@font-face {
	font-family: "Suisse Intl";
	src: url("/packages/standard/light/fonts/SuisseIntl-Book.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Intl";
	src: url("/packages/standard/light/fonts/SuisseIntl-BookIt.woff2") format("woff2");
	font-weight: 400;
	font-style: italic;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Intl";
	src: url("/packages/standard/light/fonts/SuisseIntl-Medium.woff2") format("woff2");
	font-weight: 500;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Works";
	src: url("/packages/standard/light/fonts/SuisseWorks-Regular-WebXL.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Works";
	src: url("/packages/standard/light/fonts/SuisseWorks-RegularItalic-WebXL.woff2") format("woff2");
	font-weight: 400;
	font-style: italic;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Works";
	src: url("/packages/standard/light/fonts/SuisseWorks-Medium-WebXL.woff2") format("woff2");
	font-weight: 500;
	font-style: normal;
	font-display: swap;
}

/* ---------- Reset / base ---------- */

* {
	box-sizing: border-box;
}

html,
body {
	margin: 0;
	padding: 0;
}

/*
 * Small-screen nav-box geometry, measured from the top of the viewport:
 *   --nav-top        gap above the nav box (= its top offset, 1rem − 0.3rem)
 *   --nav-box-bottom bottom edge of the box (nav top + 0.3rem×2 padding + one
 *                    1.4rem line of links)
 *   --content-top    where the feed / About content begins: the box bottom plus
 *                    another --nav-top, so the gap below the nav equals the gap
 *                    above it (the nav sits symmetrically between the top of the
 *                    page and the start of the content).
 */
:root {
	--nav-top: 0.7rem;
	--nav-box-bottom: 2.7rem;
	--content-top: calc(var(--nav-box-bottom) + var(--nav-top));
	--font-main: "Suisse Intl", Helvetica, Arial, sans-serif;
	--font-alt: "Suisse Works", Georgia, "Times New Roman", serif;
}

body {
	font-family: var(--font-main);
	font-size: 16px;
	line-height: 1.4;
	color: #000;
	background: #fff;
	-webkit-text-size-adjust: 100%;
}

img {
	display: block;
	max-width: 100%;
	height: auto;
}

a {
	color: inherit;
	text-decoration: none;
}

a:hover {
	text-decoration: underline;
}

/* The close glyph is not a text link. */
.site-close:hover {
	text-decoration: none;
}

/* Pages with the alternating colored background. */
.page-color {
	background: var(--cycle-bg, #836414);
}

/* ---------- Header / navigation ---------- */

/*
 * The header is just an out-of-flow wrapper; its two children (close button and
 * nav) position themselves as fixed. It deliberately does NOT create a stacking
 * context (no z-index), so the nav's blend mode can reach the page behind it.
 */
.site-header {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	padding: 1rem 1.25rem;
	pointer-events: none;
}

/* Keep links clickable while the bar itself ignores pointer events. */
.site-close,
.site-nav {
	pointer-events: auto;
}

.site-close {
	position: fixed;
	top: 1rem;
	left: 1.25rem;
	z-index: 20;
	font-size: 1.5rem;
	line-height: 1;
	pointer-events: auto;
}

/* The nav fixes itself to the top-right so it stays reachable while scrolling. */
.site-nav {
	position: fixed;
	top: 1rem;
	right: 1.25rem;
	z-index: 11;
	display: flex;
	gap: 1.5rem;
}

.nav-link.is-current {
	text-decoration: underline;
}

/* ---------- Feed (home) ---------- */

.feed {
	padding: var(--content-top) 0 3rem;
}

.feed-item {
	display: flex;
	flex-direction: column;
	margin: 0 auto 3rem;
	padding: 0 1.25rem;
}

/*
 * On small screens the image comes first, then both captions below it. Only the
 * image is separated from the caption block; the two captions stack directly,
 * with no margin between them (just their line-height).
 */
.feed-image-wrap {
	width: 100%;
	order: -1;
	margin-bottom: 0.6rem;
}

.feed-image {
	margin: 0 auto;
}

.caption {
	font-family: var(--font-alt);
	font-size: 0.8rem;
	line-height: 1.4;
	text-align: center;
}

.caption-text:empty {
	display: none;
}

/*
 * A caption that wraps prefers to break at a " | " separator (the pipe is bound
 * to the following field in the markup, so it never ends a line); the lines
 * balance so the break sits near the middle, and they are centred via .caption
 * above. overflow-wrap keeps an unusually long field from overflowing.
 */
.caption-text {
	text-wrap: balance;
	overflow-wrap: break-word;
}

/*
 * External-link marker: the ⧉ glyph (U+29C9) after the caption text. Kept
 * upright (text-orientation) so it reads the same way inside the vertical
 * captions on wide screens.
 */
.ext-icon {
	/* Logical margin so the small gap sits before the glyph in the reading
	   direction in both horizontal and vertical (wide-screen) captions. */
	margin-inline-start: 0.3em;
	font-size: 1em;
	text-orientation: upright;
}

/*
 * Wide screens: the image is centered with an even gap between entries
 * regardless of orientation. The captions are fixed to the screen edges,
 * vertically centered and rotated to read vertically. They never move while
 * scrolling; instead JavaScript shows only the captions of the entry whose
 * image is more than half visible (and hides them in between), so the caption
 * swaps as the next image takes over the viewport.
 */
@media (min-width: 800px) {
	.feed {
		padding: 6vh 0;
	}

	.feed-item {
		display: flex;
		justify-content: center;
		align-items: center;
		margin: 0 auto 8vh;
		padding: 0 2rem;
	}

	.feed-image-wrap {
		display: flex;
		align-items: center;
		justify-content: center;
		margin-bottom: 0;
	}

	/* Consistent image height across orientations. */
	.feed-image {
		max-height: 86vh;
		max-width: 60vw;
		width: auto;
		height: auto;
	}

	/*
	 * Each caption is a full-height fixed box pinned to a screen edge, with its
	 * text vertically centred via flexbox. Centring with flexbox (rather than a
	 * translateY(-50%) transform) keeps the box at integer coordinates, so the
	 * browser never re-rounds it sideways from frame to frame while scrolling.
	 * The horizontal edge anchors are fixed rem values, so the captions also do
	 * not shift as captions of different lengths swap in or images of different
	 * widths scroll past.
	 */
	.caption {
		position: fixed;
		top: 0;
		bottom: 0;
		display: flex;
		align-items: center;
		z-index: 5;
		opacity: 0;
		transition: opacity 0.25s ease;
		pointer-events: none;
	}

	.feed-item.is-active .caption {
		opacity: 1;
	}

	.feed-item.is-active .caption-text {
		pointer-events: auto;
	}

	.caption-left {
		left: 1.5rem;
	}

	.caption-right {
		right: 1.5rem;
	}

	/*
	 * Vertical (90-degree) caption text. The photo credit is forced onto its own
	 * line (a <br> in the markup), so it forms a second column; a long line before
	 * it may also wrap. text-align: center centres the text of each column along
	 * its length, so the columns sit vertically centred rather than anchored to the
	 * top edge.
	 */
	.caption-text {
		display: block;
		max-height: 86vh;
		font-size: 0.8rem;
		line-height: 1.5;
		text-align: center;
		text-wrap: wrap;
	}

	.caption-left .caption-text {
		writing-mode: vertical-rl;
		transform: rotate(180deg);
	}

	.caption-right .caption-text {
		writing-mode: vertical-rl;
	}
}

/* Single entry view. */
.feed-single {
	min-height: 60vh;
}

/* ---------- About ---------- */

.about {
	max-width: 60rem;
	margin: 0 auto;
	padding: var(--content-top) 1.25rem 3rem;
}

/*
 * The biography sits toward the left, as wide as the CV (42rem) and a touch
 * larger than the CV for the reading text.
 */
.bio {
	max-width: 42rem;
	margin-right: auto;
	font-size: 0.9rem;
}

.bio {
	font-family: var(--font-main);
}

/* Keep the two biography paragraphs close together. */
.bio p {
	margin: 0 0 0.5rem;
}

.cv {
	max-width: 42rem;
	margin-top: 3rem;
	font-family: var(--font-alt);
	/* CV runs at 90% of the base size. */
	font-size: 0.9rem;
}

.cv-table {
	width: 100%;
	border-collapse: collapse;
	line-height: 1.3;
}

.cv-section .cv-section-title {
	text-align: left;
	font-weight: normal;
	padding-top: 1.5rem;
	padding-bottom: 0.5rem;
}

.cv-year {
	vertical-align: top;
	white-space: nowrap;
	padding-right: 1rem;
}

.cv-text {
	vertical-align: top;
}

@media (min-width: 800px) {
	.about {
		padding: 4rem 2rem 4rem;
	}

	.cv {
		margin-top: 4rem;
	}

	.cv-year {
		width: 8rem;
	}
}

/* ---------- Contact ---------- */

/*
 * The contact page is exactly one viewport tall and never scrolls. The body is a
 * flex column so the footer (the copyright credit) sits at the bottom inside the
 * viewport instead of adding height below a full-height main; overflow: hidden is
 * a safety net against any sub-pixel rounding.
 */
body.t-contact {
	height: 100vh;
	overflow: hidden;
}

.contact {
	height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 2rem;
	overflow: hidden;
	/* An explicit cycle-color backdrop so the inverting circle's difference blend
	   has a precise colour to swap against (not the bare canvas). */
	background: var(--cycle-bg, #836414);
}

/*
 * The copyright credit is taken out of flow (fixed, bottom-left) so it neither
 * shifts the contact text off the true viewport centre — where the circle is
 * centred — nor adds height that would let the page scroll.
 */
.t-contact .site-footer {
	position: fixed;
	left: 0;
	bottom: 0;
}

.contact-rotated {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	transform: rotate(-45deg);
	transform-origin: center;
	white-space: nowrap;
}

/*
 * Cursor-driven inverting circle. A disc filled with the current cycle color is
 * centered on the viewport; js/site.js sizes it from the cursor distance (its
 * radius reaches to 20px short of the cursor). mix-blend-mode: difference makes
 * it an exact two-colour swap against the page: the cycle background underneath
 * turns black (cycle − cycle) and the black text turns the cycle color
 * (black − cycle), so the text covered by the disc reads in red/green precisely.
 * It is purely decorative (pointer-events: none) and sits below the fixed nav and
 * close button, so those are never inverted.
 */
.contact-invert {
	position: fixed;
	top: 50%;
	left: 50%;
	width: 0;
	height: 0;
	border-radius: 50%;
	background: var(--cycle-bg, #836414);
	transform: translate(-50%, -50%);
	mix-blend-mode: difference;
	pointer-events: none;
	z-index: 2;
}

/* ---------- 404 ---------- */

.not-found {
	max-width: 40rem;
	margin: 0 auto;
	padding: 4rem 1.25rem;
}

/* ---------- Footer ---------- */

/*
 * The copyright sits at the same place on every page: left-aligned, one content
 * margin (1.25rem) in from the left edge. (Previously the feed centered it,
 * which put it in a different spot than on About/Contact.)
 */
.site-footer {
	padding: 1.25rem 1.25rem;
	font-size: 0.8rem;
}

/* ---------- Lazy image fade-in ---------- */

.feed-image {
	opacity: 0;
	transition: opacity 0.4s ease;
}

.feed-image.is-loaded {
	opacity: 1;
}

/* ---------- Small-screen navigation ---------- */

/*
 * On the feed the navigation sits over the paintings, so it carries its own
 * solid white background with black text. This stays legible over any image
 * without depending on blend modes or backdrop filters (which render
 * inconsistently across browsers).
 */
.page-feed .site-nav {
	color: #000;
	background: #fff;
	padding: 0.3rem 0.6rem;
	/*
	 * Bleed the white box outward by its own padding so the link text keeps the
	 * exact same top/right position as on the About/Contact pages (which have no
	 * box). Without this the padding would push the text inward on the feed only,
	 * making the nav appear to shift between pages.
	 */
	top: calc(1rem - 0.3rem);
	right: calc(1.25rem - 0.6rem);
}

/*
 * About: the nav and close button stay fixed while the biography and CV
 * scroll beneath them. They carry a solid box in the current cycle color so the
 * scrolling text never shows through them (the same idea as the feed nav's white
 * box over the images, but matched to this page's background). The box bleeds out
 * by its own padding so the glyphs keep the exact position they have elsewhere.
 */
.t-about .site-nav {
	background: var(--cycle-bg, #836414);
	padding: 0.3rem 0.6rem;
	top: calc(1rem - 0.3rem);
	right: calc(1.25rem - 0.6rem);
}

.t-about .site-close {
	background: var(--cycle-bg, #836414);
	padding: 0.1rem 0.4rem;
	top: calc(1rem - 0.1rem);
	left: calc(1.25rem - 0.4rem);
}

@media (max-width: 799px) {
	.site-nav {
		gap: 1.25rem;
	}
}
