/*
 * 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
 */

/* ---------- Page transitions ---------- */

/* No cross-document transition between the feed, About and Contact pages — a
   plain hard cut on navigation (both directions, including browser Back). */
@view-transition { navigation: none; }

/* ---------- 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("/assets/fonts/SuisseIntl-Book.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Intl";
	src: url("/assets/fonts/SuisseIntl-BookIt.woff2") format("woff2");
	font-weight: 400;
	font-style: italic;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Intl";
	src: url("/assets/fonts/SuisseIntl-Medium.woff2") format("woff2");
	font-weight: 500;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Works";
	src: url("/assets/fonts/SuisseWorks-Regular-WebXL.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Works";
	src: url("/assets/fonts/SuisseWorks-RegularItalic-WebXL.woff2") format("woff2");
	font-weight: 400;
	font-style: italic;
	font-display: swap;
}
@font-face {
	font-family: "Suisse Works";
	src: url("/assets/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).
 */
::selection {
	background: var(--selection-bg, #f9b8c4);
	color: inherit;
}

: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 {
	/* No bottom padding: the last .feed-item's 3rem margin-bottom already gives a
	   single photo-gap before the footer (padding here would double it). */
	padding: var(--content-top) 0 0;
}

.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 {
		/* No bottom padding: the last .feed-item's 8vh margin-bottom is the single
		   end gap (padding here would add to it and double the space). */
		padding: 6vh 0 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;
	/* Crisper rendering for the dark text on the coloured background, and
	   sensible defaults for the figure / kerning features below. */
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/*
 * The biography sits toward the left, as wide as the CV (42rem) and a touch
 * larger than the CV for the reading text. A slightly looser line-height and a
 * hair of negative tracking give the sans a calmer reading rhythm.
 */
.bio {
	max-width: 38rem;
	margin-right: auto;
	font-family: var(--font-main);
	font-size: 0.95rem;
	line-height: 1.55;
	letter-spacing: -0.003em;
	text-wrap: pretty;
}

/* A little air between the two biography paragraphs. */
.bio p {
	margin: 0 0 0.9rem;
}

.bio p:last-child {
	margin-bottom: 0;
}

/*
 * Shared label for section headings (CV sections and the News heading). The
 * serif entries carry the page; the labels that introduce them switch to the
 * sans, small and letter-spaced, so the structure reads at a glance without
 * shouting.
 */
.section-title,
.cv-section .cv-section-title {
	text-align: left;
	font-family: var(--font-main);
	font-weight: 500;
	font-size: 0.7rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

.cv {
	max-width: 42rem;
	margin-top: 2.5rem;
	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.4;
}

.cv-section .cv-section-title {
	padding-top: 1.6rem;
	padding-bottom: 0.6rem;
}

.cv-year {
	vertical-align: top;
	white-space: nowrap;
	padding-right: 0.8rem;
	/* Lining, tabular figures so the year column stays in a tidy vertical
	   rule and digits do not jostle line to line. */
	font-variant-numeric: tabular-nums lining-nums;
	font-feature-settings: "tnum" 1, "lnum" 1;
}

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

/* CV rendered from Markdown (### section headings + "- " entries). Mirrors the
   old table look: small uppercase section labels, a bold-year prefix that lines
   up like the former year column. */
.cv-body h3 {
	font-family: var(--font-main);
	font-weight: 500;
	font-size: 0.7rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	margin: 1.6rem 0 0.6rem;
}
.cv-body h3:first-child { margin-top: 0; }
.cv-body ul {
	list-style: none;
	margin: 0;
	padding: 0;
	line-height: 1.4;
}
/* Two-column entry: a fixed year column on the left, description on the right.
   The hanging indent (padding-left + negative text-indent of the same width)
   keeps a wrapped second line aligned under the description, not under the
   year column. Fixed strong width so every year occupies the same column. */
.cv-body li {
	margin: 0.15rem 0;
	position: relative;
	padding-left: 6rem;
}
/* The year sits in an absolutely-positioned left column, so the description
   forms a clean right column: every line (first and wrapped) starts at the same
   6rem, and the literal space after the year in the Markdown collapses at the
   start of the line instead of nudging the first line out of alignment. */
.cv-body li strong {
	position: absolute;
	left: 0;
	width: 6rem;
	box-sizing: border-box;
	padding-right: 0.6rem;
	font-weight: inherit;
	font-variant-numeric: tabular-nums lining-nums;
	font-feature-settings: "tnum" 1, "lnum" 1;
}

/* ---------- News (current and upcoming shows) ---------- */

.news {
	max-width: 42rem;
	margin-top: 2.5rem;
	/* Whole block in the sans (matches the heading + biography); the site already
	   carries enough serif elsewhere. Headline weight distinguishes it. */
	font-family: var(--font-main);
	font-size: 0.9rem;
}

.news-title {
	margin: 0 0 0.6rem;
}

/*
 * Each show is two stacked lines (title/venue, then dates/type) so every entry
 * lines up to the same left edge as the section heading — there is no date
 * column pushing the text to a different indent than the CV.
 */
.news-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.news-item + .news-item {
	margin-top: 0.7rem;
}

/* Line 1: title and venue. */
.news-line {
	line-height: 1.4;
}

/* The show title carries a touch more weight than the surrounding detail. */
.news-headline {
	font-weight: 500;
}

/* Line 2: dates and type. */
.news-meta {
	font-family: var(--font-main);
	font-size: 0.85rem;
	line-height: 1.4;
}

/* "Now on" marker for a show whose dates include today. */
.news-now {
	display: inline-block;
	font-size: 0.65rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	border: 1px solid currentColor;
	border-radius: 1em;
	padding: 0.05em 0.5em;
	margin-left: 0.2em;
	white-space: nowrap;
	opacity: 1;
}

/* The whole title line is the link, so it inherits the serif styling; only the
   hover underline (from the global `a:hover`) sets it apart. */

/* ---------- Period note (shown only during the red phase) ---------- */

/*
 * A quiet footnote on the colored background, set in the serif italic. It is
 * rendered by the template only while the cycle is in its red phase.
 */
.period-note {
	max-width: 38rem;
	margin: 3rem 0 0;
	font-family: var(--font-alt);
	font-style: italic;
	font-size: 0.8rem;
	line-height: 1.5;
	opacity: 0.85;
}

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

	.cv,
	.news {
		margin-top: 3rem;
	}

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

/* ---------- 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;
	}
}
