/*
Theme Name: Nicolas Jones
Description: Custom block theme for nicolasjones.ch.
Author: Nicolas Jones
Version: 0.4.5
Requires at least: 6.6
Requires PHP: 7.4
License: GNU General Public License v2 or later
Text Domain: nicolasjones
*/

/*
 * Tokens (colours, fonts, sizes, spacing, widths, motion) and the styles of
 * core blocks and block styles live in theme.json. This file only holds what
 * theme.json can't express: pseudo-elements, counters, hover effects, the
 * sticky header, the hero, and line-length limits. Every value here refers
 * to a theme.json token.
 */

body {
	font-feature-settings: "ss01", "cv11";
	-webkit-font-smoothing: antialiased;
}

::selection {
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--base);
}

p:where(:not(.is-style-nj-display, .is-style-nj-giant)),
li {
	text-wrap: pretty;
}

h1,
h3 {
	text-wrap: balance;
}

/* Sections set their own spacing, so drop the default gap between header, main and footer. */
.wp-site-blocks > * + * {
	margin-block-start: 0;
}

.wp-site-blocks > footer.wp-block-template-part {
	margin-block-start: var(--wp--preset--spacing--70);
}

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

a {
	text-decoration-thickness: var(--wp--custom--rule--width);
	text-underline-offset: 0.2em;
	transition: color var(--wp--custom--motion--fast) ease;
}

/* ---------- Headings ---------- */

/* A heading straight after a section label sits closer to it. */
:where(.wp-block-post-content) h2 + * {
	margin-block-start: var(--wp--preset--spacing--30);
}

/* "Full stop" style: the red square of the logo ends the title. */
.is-style-nj-title::after {
	content: after the name in the footer.";
	color: var(--wp--preset--color--accent);
}

/* Big page titles hang slightly left so the letters align with the grid. */
.wp-block-post-title.has-giant-font-size,
h1.has-giant-font-size,
.is-style-nj-giant {
	margin-left: -0.04em;
}

/* ---------- Lists ---------- */

:where(.wp-block-list) li + li {
	margin-block-start: 0.4em;
}

/* "Ruled" list: two-digit red numbers and light rules, as in the project Tasks. */
.wp-block-list.is-style-nj-ruled {
	list-style: none;
	padding-left: 0;
	counter-reset: nj-item;
}

.wp-block-list.is-style-nj-ruled > li {
	counter-increment: nj-item;
	display: flex;
	gap: 12px;
	align-items: baseline;
	margin: 0;
	padding: 10px 0;
	border-bottom: var(--wp--custom--rule--width) solid var(--wp--preset--color--rule);
	line-height: 1.3;
}

.wp-block-list.is-style-nj-ruled > li::before {
	content: counter(nj-item, decimal-leading-zero);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-small);
	color: var(--wp--preset--color--accent);
}

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

.wp-block-image.alignleft {
	margin: 0 var(--wp--preset--spacing--30) var(--wp--preset--spacing--20) 0;
}

.wp-block-image.alignright {
	margin: 0 0 var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
}

.wp-block-image figcaption {
	margin-top: 8px;
}

/* Photo hover, as on the home hero: black and white under a red screen tint. */
.is-style-nj-framed {
	position: relative;
	overflow: hidden;
}

.is-style-nj-framed img {
	display: block;
	transition: filter var(--wp--custom--motion--base) ease, transform var(--wp--custom--motion--slow) ease;
}

.is-style-nj-framed:has(a)::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: var(--wp--preset--color--accent);
	mix-blend-mode: screen;
	opacity: 0;
	transition: opacity var(--wp--custom--motion--base) ease;
}

@media (hover: hover) {
	.is-style-nj-framed:has(a:hover) img {
		filter: grayscale(1) contrast(1.08);
		transition-duration: var(--wp--custom--motion--slow);
	}

	.is-style-nj-framed:has(a:hover)::after {
		opacity: 0.35;
		transition-duration: var(--wp--custom--motion--slow);
	}
}

/* ---------- Separators, tables, quotes ---------- */

.wp-block-separator {
	width: 100%;
	opacity: 1;
}

.wp-block-table table {
	border-collapse: collapse;
	width: 100%;
}

.wp-block-table th,
.wp-block-table td {
	border: 0;
	border-bottom: var(--wp--custom--rule--width) solid var(--wp--preset--color--rule);
	padding: 10px 16px 10px 0;
	text-align: left;
	vertical-align: baseline;
}

.wp-block-table thead th {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-meta);
	font-weight: 400;
	text-transform: uppercase;
	border-bottom-color: var(--wp--preset--color--contrast);
}

.wp-block-quote cite,
.wp-block-pullquote cite {
	display: block;
	margin-top: var(--wp--preset--spacing--20);
}

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

.wp-block-search__input {
	border: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
	border-radius: 0;
	padding: 12px;
}

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

.wp-site-blocks > header.wp-block-template-part {
	position: sticky;
	top: var(--wp-admin--admin-bar--height, 0px);
	z-index: 40;
}

@media (max-width: 600px) {
	/* The admin bar scrolls away on phones, so the header sticks to the very top. */
	.wp-site-blocks > header.wp-block-template-part {
		top: 0;
	}
}

/* The top border makes a 6px strip above the white area for the bar, so the logo and menu centre in the white. */
.nj-header {
	position: relative;
	border-top: 6px solid var(--wp--preset--color--contrast);
}

/* Signature top bar: 2px of red over 4px of ink, drawn over the top border. */
.nj-header::before {
	content: "";
	position: absolute;
	top: -6px;
	left: 0;
	right: 0;
	height: 6px;
	background: linear-gradient(to bottom, var(--wp--preset--color--accent) 0 2px, var(--wp--preset--color--contrast) 2px 6px);
}

/* No text line around the logo, so its box is exactly the artwork and it centres properly. */
.nj-logo a {
	display: block;
}

.nj-logo img {
	display: block;
	height: 18px !important;
	width: auto !important;
}

/*
 * The menu is in capitals, which leave the line's descender space empty, so
 * the letters looked 1.5px high. Nudge them down to centre the capitals.
 */
.nj-header .wp-block-navigation-item__content {
	position: relative;
	top: 0.125em;
}

.nj-header .wp-block-navigation .current-menu-item > a,
.nj-header .wp-block-navigation .current-menu-ancestor > a,
.nj-header .wp-block-navigation a[aria-current="page"] {
	color: var(--wp--preset--color--accent);
}

/* ---------- Hero (front page) ---------- */

.nj-hero {
	min-height: max(70vh, 520px) !important;
	align-items: stretch;
	background-color: var(--wp--preset--color--stone);
	border-bottom: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
}

.nj-hero .wp-block-cover__inner-container {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 48px;
	width: 100%;
	color: var(--wp--preset--color--contrast);
}

.nj-hero h1 {
	margin: 0;
	line-height: 0;
}

.nj-hero h1 img {
	display: block;
	width: clamp(240px, 46vw, 780px) !important;
	height: auto !important;
}

.nj-hero .wp-block-cover__image-background {
	transition: filter var(--wp--custom--motion--base) ease;
}

.nj-hero .wp-block-cover__background {
	background-color: var(--wp--preset--color--accent) !important;
	mix-blend-mode: screen;
	opacity: 0 !important;
	transition: opacity var(--wp--custom--motion--base) ease;
}

@media (hover: hover) {
	.nj-hero:hover .wp-block-cover__image-background {
		filter: grayscale(1) contrast(1.08);
		transition-duration: var(--wp--custom--motion--slow);
	}

	.nj-hero:hover .wp-block-cover__background {
		opacity: 0.35 !important;
		transition-duration: var(--wp--custom--motion--slow);
	}
}

/* ---------- Block style extras theme.json can't express ---------- */

/* The lead-out (Note style) under every page title spans ten of twelve columns. */
.is-style-nj-statement,
.is-style-nj-note {
	max-width: 83.333%;
}

.is-style-nj-statement {
	text-wrap: balance;
}

.is-style-nj-note strong {
	font-weight: 800;
}

/* Arrow after a display link ("Portfolio→") gets the design's 12px gap. */
.is-style-nj-display mark:last-child {
	margin-left: 0.115em;
}

.wp-block-columns.is-style-nj-row p {
	max-width: var(--wp--custom--measure--wide);
}

/*
 * Playful glyphs, drawn from the logo's red square. Add the class to a
 * paragraph (Advanced → Additional CSS class):
 * - nj-end-spark: ends the paragraph with a red AI spark; it turns on hover.
 * - nj-end-stack: ends the paragraph's link with a stack of prints (a
 *   gallery); the stack fans out on hover. Meant for white backgrounds.
 */
.nj-end-spark::after {
	content: "";
	display: inline-block;
	width: 0.9em;
	height: 0.9em;
	margin-left: 0.3em;
	vertical-align: -0.05em;
	background: var(--wp--preset--color--accent);
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 0C12 6.6 17.4 12 24 12C17.4 12 12 17.4 12 24C12 17.4 6.6 12 0 12C6.6 12 12 6.6 12 0Z'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 0C12 6.6 17.4 12 24 12C17.4 12 12 17.4 12 24C12 17.4 6.6 12 0 12C6.6 12 12 6.6 12 0Z'/%3E%3C/svg%3E") center / contain no-repeat;
	transition: transform var(--wp--custom--motion--slow) var(--wp--custom--motion--ease);
}

.nj-end-spark:hover::after {
	transform: rotate(90deg) scale(1.15);
}

/*
 * A stack of three prints: the box is the solid front square, and each
 * print behind it is a pair of shadows (a background-coloured square on a
 * red one, 0.06em bigger), so every print hides the one behind it.
 */
.nj-end-stack a::after {
	--nj-stack: 0.12em;
	--nj-paper: var(--wp--preset--color--base);
	content: "";
	display: inline-block;
	width: 0.5em;
	height: 0.5em;
	margin: 0 0.34em 0 0.28em; /* Room for the fanned stack, so the text never moves. */
	vertical-align: 0.02em;
	background: var(--wp--preset--color--accent);
	box-shadow:
		var(--nj-stack) calc(var(--nj-stack) * -1) 0 -0.06em var(--nj-paper),
		var(--nj-stack) calc(var(--nj-stack) * -1) 0 0 var(--wp--preset--color--accent),
		calc(var(--nj-stack) * 2) calc(var(--nj-stack) * -2) 0 -0.06em var(--nj-paper),
		calc(var(--nj-stack) * 2) calc(var(--nj-stack) * -2) 0 0 var(--wp--preset--color--accent);
	transition: box-shadow var(--wp--custom--motion--base) var(--wp--custom--motion--ease);
}

.nj-end-stack a:hover::after,
.nj-end-stack a:focus-visible::after {
	--nj-stack: 0.17em;
}

/* Reading widths for paragraphs placed in wide sections. */
.nj-measure {
	max-width: var(--wp--custom--measure--text);
}

/* Numbered list of posts (archive, search): the number comes from a CSS counter. */
.nj-numbered .wp-block-post-template {
	counter-reset: nj-post;
}

.nj-numbered .wp-block-post-template > li {
	counter-increment: nj-post;
}

.nj-numbered .nj-count::before {
	content: counter(nj-post, decimal-leading-zero);
}

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

.nj-footer-meta a {
	text-decoration: none;
	border-bottom: var(--wp--custom--rule--width) solid currentColor;
}

/*
 * Cookie note: a bitten cookie after the name in the footer.
 * Hover or focus shows a white card above it; the cookie tilts.
 */
.nj-cookie {
	position: relative;
}

.nj-cookie__toggle {
	display: block;
	padding: 8px; /* A bigger tap target; the negative margin keeps the layout. */
	margin: -8px;
	border: 0;
	background: none;
	color: inherit;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono);
	line-height: var(--wp--custom--leading--body);
	letter-spacing: var(--wp--custom--tracking--mono);
	text-transform: uppercase;
	cursor: help;
}

.nj-cookie__toggle::before {
	content: "";
	display: inline-block;
	vertical-align: -0.2em;
	width: 1.1em;
	height: 1.1em;
	background: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cmask id='m'%3E%3Crect width='24' height='24' fill='%23fff'/%3E%3Ccircle cx='20.5' cy='3' r='3.8'/%3E%3Ccircle cx='23.2' cy='8' r='2.8'/%3E%3Ccircle cx='8' cy='8' r='1.7'/%3E%3Ccircle cx='15' cy='12.5' r='1.7'/%3E%3Ccircle cx='8.5' cy='16' r='1.7'/%3E%3Ccircle cx='14.5' cy='18.8' r='1.1'/%3E%3C/mask%3E%3Ccircle cx='12' cy='12' r='11' mask='url(%23m)'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cmask id='m'%3E%3Crect width='24' height='24' fill='%23fff'/%3E%3Ccircle cx='20.5' cy='3' r='3.8'/%3E%3Ccircle cx='23.2' cy='8' r='2.8'/%3E%3Ccircle cx='8' cy='8' r='1.7'/%3E%3Ccircle cx='15' cy='12.5' r='1.7'/%3E%3Ccircle cx='8.5' cy='16' r='1.7'/%3E%3Ccircle cx='14.5' cy='18.8' r='1.1'/%3E%3C/mask%3E%3Ccircle cx='12' cy='12' r='11' mask='url(%23m)'/%3E%3C/svg%3E") center / contain no-repeat;
	transition: transform var(--wp--custom--motion--slow) var(--wp--custom--motion--ease);
}

.nj-cookie:hover .nj-cookie__toggle::before,
.nj-cookie__toggle:focus-visible::before {
	transform: rotate(-24deg) scale(1.15);
}

.nj-cookie__toggle:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 4px;
}

/* 46ch: tuned so the note ends on a full last line, never a lone wink. */
.nj-cookie__note {
	position: absolute;
	left: 0;
	bottom: calc(100% + 12px);
	z-index: 10;
	width: max-content;
	max-width: min(46ch, calc(100vw - var(--wp--style--root--padding-left) - var(--wp--style--root--padding-right)));
	padding: 14px 16px;
	background: var(--wp--preset--color--base);
	border: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--contrast);
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--mono);
	line-height: var(--wp--custom--leading--body);
	letter-spacing: normal;
	text-transform: none;
	text-wrap: wrap; /* Plain wrapping: balanced lines left a gap on the right. */
	opacity: 0;
	visibility: hidden;
	transform: translateY(4px);
	transition:
		opacity var(--wp--custom--motion--base) var(--wp--custom--motion--ease),
		transform var(--wp--custom--motion--base) var(--wp--custom--motion--ease),
		visibility var(--wp--custom--motion--base);
}

.nj-cookie__note strong {
	display: block;
	margin-bottom: 4px;
}

/* Bridges the gap to the icon, so the pointer can move onto the card. */
.nj-cookie__note::after {
	content: "";
	position: absolute;
	top: 100%;
	left: 0;
	right: 0;
	height: 12px;
}

.nj-cookie:hover .nj-cookie__note,
.nj-cookie:focus-within .nj-cookie__note {
	opacity: 1;
	visibility: visible;
	transform: none;
}

/* On phones the card spans the footer row, gutter to gutter. */
@media (max-width: 781px) {
	.nj-footer-meta {
		position: relative;
	}

	.nj-cookie {
		position: static;
	}

	.nj-cookie__note {
		left: 0;
		right: 0;
		width: auto;
		max-width: none;
	}
}

/* ---------- Contact template: the whole page is red ---------- */

body.page-template-page-contact {
	background: var(--wp--preset--color--accent);
}

/* ---------- Small screens ---------- */

@media (max-width: 781px) {
	.is-style-nj-statement,
	.is-style-nj-note {
		max-width: none;
	}

	/* Right-aligned text only makes sense when it sits in a column next to something. */
	.wp-block-columns .has-text-align-right {
		text-align: left;
	}

	/* Empty spacer columns would leave a gap when columns stack. */
	.wp-block-column:empty {
		display: none;
	}
}

/*
 * In-page links (#interests, #bio…) glide and stop just below the sticky
 * header. --nj-header-height is measured by a small script in functions.php.
 */
html {
	scroll-behavior: smooth;
	scroll-padding-top: calc(var(--nj-header-height, 64px) + var(--wp--preset--spacing--40));
}

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	html .nj-copy.is-copied::after {
		animation: none;
	}

	*,
	*::before,
	*::after {
		transition-duration: 0s !important;
	}
}

/* The Contact page's own ink section runs straight into the minimal footer. */
.page-template-page-contact .wp-site-blocks > footer.wp-block-template-part {
	margin-block-start: 0;
}

/* =========================================================
   Round 2: Portfolio and case studies
   ========================================================= */

/* Section label with a count or note on the right ("Selected work · 04 projects"). */
.nj-label-row {
	align-items: baseline;
	border-bottom: var(--wp--custom--rule--width) solid currentColor;
	padding-bottom: 10px;
}

.nj-label-row > * {
	margin: 0;
}

.nj-label-row > h2 {
	border: 0;
	padding: 0;
}

.nj-label-row > .wp-block-post-date {
	font-size: var(--wp--preset--font-size--mono);
}

/* Paragraph spanning seven of twelve columns (page intro text). */
.nj-span-7 {
	max-width: 58.333%;
}

@media (max-width: 781px) {
	.nj-span-7 {
		max-width: none;
	}
}

/* ---------- Project cards ---------- */

.nj-card {
	position: relative;
}

.nj-card__image {
	position: relative;
	overflow: hidden;
	margin: 0;
	background: var(--wp--preset--color--stone);
	border: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
}

.nj-card__image img {
	transition: filter var(--wp--custom--motion--base) ease, transform var(--wp--custom--motion--slow) ease;
}

.nj-card__image::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: var(--wp--preset--color--accent);
	mix-blend-mode: screen;
	opacity: 0;
	transition: opacity var(--wp--custom--motion--base) ease;
}

.nj-card__meta {
	align-items: baseline !important;
}

.nj-card__meta > * {
	margin: 0;
}

.nj-card .nj-count {
	flex: none;
}

.nj-card__title {
	flex: 1;
	min-width: 0;
	font-weight: 800;
	letter-spacing: -0.045em;
	line-height: 0.95;
	transition: color var(--wp--custom--motion--base) ease;
}

/* The title link covers the whole card, so the image and arrow are clickable too. */
.nj-card__title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.nj-card__arrow {
	flex: none;
	font-weight: 800;
	line-height: 0.95;
	transition: transform 300ms ease;
}

@media (hover: hover) {
	.nj-card:hover .nj-card__image img {
		filter: grayscale(1) contrast(1.08);
		transform: scale(1.02);
		transition-duration: var(--wp--custom--motion--slow);
	}

	.nj-card:hover .nj-card__image::after {
		opacity: 0.35;
		transition-duration: var(--wp--custom--motion--slow);
	}

	.nj-card:hover .nj-card__title a {
		color: var(--wp--preset--color--accent);
	}

	.nj-card:hover .nj-card__arrow {
		transform: translateX(6px);
	}
}

/* ---------- Case study ---------- */

.nj-cover {
	margin: 0;
	overflow: hidden;
	background: var(--wp--preset--color--mist);
	border: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
}

.nj-cover img {
	display: block;
	width: 100%;
	height: auto;
}

/* The cover clips its overflow, so the keyboard focus ring sits inside the frame. */
figure.nj-cover > a:focus-visible {
	outline-offset: -4px;
}

/* Tasks: the post's tags as a ruled, numbered list. */
.wp-block-post-terms.nj-tasks {
	display: flex;
	flex-direction: column;
	counter-reset: nj-task;
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--body);
	letter-spacing: normal;
	text-transform: none;
	line-height: 1.3;
}

.nj-tasks a {
	counter-increment: nj-task;
	display: flex;
	gap: 12px;
	align-items: baseline;
	padding: 10px 0;
	border-bottom: var(--wp--custom--rule--width) solid var(--wp--preset--color--rule);
}

.nj-tasks a::before {
	content: counter(nj-task, decimal-leading-zero);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-small);
	color: var(--wp--preset--color--accent);
}

.nj-tasks .wp-block-post-terms__separator {
	display: none;
}

/* Gallery: framed images on an auto-fitting grid, natural heights. */
.wp-block-gallery.has-nested-images.nj-gallery {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
	gap: var(--wp--custom--grid--gap);
	align-items: start;
}

.wp-block-gallery.has-nested-images.nj-gallery figure.wp-block-image:not(#individual-image) {
	width: auto;
	margin: 0;
	flex-direction: column;
	border: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
	background: var(--wp--preset--color--mist);
}

.wp-block-gallery.has-nested-images.nj-gallery figure.wp-block-image::before {
	content: none;
}

.wp-block-gallery.has-nested-images.nj-gallery figure.wp-block-image img {
	width: 100%;
	height: auto;
}

.wp-block-gallery.has-nested-images.nj-gallery figure.wp-block-image figcaption {
	position: static;
	background: none;
	color: var(--wp--preset--color--muted);
	text-shadow: none;
	text-align: left;
	padding: 8px 10px;
	margin: 0;
	max-height: none;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-small);
	text-transform: uppercase;
	border-top: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
}

.nj-gallery figure.wp-block-image > a,

.nj-cover > a {
	position: relative;
	display: block;
	overflow: hidden;
}

.nj-gallery figure.wp-block-image > a img,

.nj-cover > a img {
	transition: filter var(--wp--custom--motion--base) ease;
}

/* Red tint and the "Enlarge +" tag on hover (gallery images and the case study cover). */
.nj-gallery figure.wp-block-image > a::after,
.nj-cover > a::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--wp--preset--color--accent);
	mix-blend-mode: screen;
	opacity: 0;
	transition: opacity var(--wp--custom--motion--base) ease;
}

.nj-gallery figure.wp-block-image > a::before,

.nj-cover > a::before {
	content: "Enlarge +";
	position: absolute;
	right: 10px;
	bottom: 8px;
	z-index: 1;
	padding: 2px 6px;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-small);
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast);
	background: var(--wp--preset--color--base);
	border: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
	opacity: 0;
	transition: opacity var(--wp--custom--motion--base) ease;
}

.nj-gallery figure.wp-block-image > a:focus-visible,

.nj-cover > a:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

@media (hover: hover) {
	.nj-gallery figure.wp-block-image > a:hover img,
	.nj-cover > a:hover img {
		filter: grayscale(1) contrast(1.08);
		transition-duration: var(--wp--custom--motion--slow);
	}

	.nj-gallery figure.wp-block-image > a:hover::after,

	.nj-cover > a:hover::after {
		opacity: 0.35;
		transition-duration: var(--wp--custom--motion--slow);
	}

	.nj-gallery figure.wp-block-image > a:hover::before,

	.nj-cover > a:hover::before {
		opacity: 1;
	}
}

.nj-gallery figure.wp-block-image > a:focus-visible::before,

.nj-cover > a:focus-visible::before {
	opacity: 1;
}

/* Image viewer (assets/js/gallery.js). */
.nj-viewer {
	box-sizing: border-box;
	width: 100%;
	height: 100%;
	max-width: none;
	max-height: none;
	margin: 0;
	padding: clamp(16px, 3vw, 40px);
	border: 0;
	background: rgba(17, 17, 19, 0.94);
	color: var(--wp--preset--color--base);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-meta);
	text-transform: uppercase;
}

.nj-viewer[open] {
	display: grid;
	grid-template-rows: auto minmax(0, 1fr) auto;
	gap: 16px;
}

.nj-viewer::backdrop {
	background: transparent;
}

.nj-viewer__bar {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 16px;
}

.nj-viewer__bar:first-child {
	border-bottom: var(--wp--custom--rule--width) solid var(--wp--preset--color--base);
	padding-bottom: 10px;
}

.nj-viewer__stage {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 0;
}

.nj-viewer__stage img {
	display: block;
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	background: var(--wp--preset--color--mist);
}

.nj-viewer button {
	all: unset;
	cursor: pointer;
	padding: 8px 0;
	color: var(--wp--preset--color--base);
	transition: color var(--wp--custom--motion--fast) ease;
}

.nj-viewer button:hover {
	color: var(--wp--preset--color--accent);
}

.nj-viewer button:focus-visible {
	outline: 2px solid var(--wp--preset--color--base);
	outline-offset: 3px;
}

html.nj-viewer-open {
	overflow: hidden;
}

/* Previous / next project: two big cells between rules; the cell fills ink on hover. */
.nj-project-nav {
	border-top: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
	border-bottom: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
}

.nj-project-nav .wp-block-post-navigation-link {
	margin: 0;
	font-family: var(--wp--preset--font-family--sans);
	text-transform: none;
	letter-spacing: normal;
}

.nj-project-nav .post-navigation-link-next {
	grid-column-end: -1;
	border-left: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
}

.nj-project-nav .wp-block-post-navigation-link a {
	box-sizing: border-box; /* Padding stays inside the cell, so the hover fill doesn't spill over. */
	display: flex;
	flex-direction: column;
	gap: 16px;
	height: 100%;
	padding: clamp(24px, 4vw, 48px) var(--wp--style--root--padding-left);
	color: var(--wp--preset--color--contrast);
	transition: background-color var(--wp--custom--motion--fast) ease, color var(--wp--custom--motion--fast) ease;
}

.nj-project-nav .post-navigation-link-next a {
	align-items: flex-end;
	text-align: right;
}

.nj-project-nav .post-navigation-link__label {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-meta);
	text-transform: uppercase;
	color: var(--wp--preset--color--accent);
}

.nj-project-nav .post-navigation-link__title {
	font-size: clamp(28px, 3.6vw, 60px);
	font-weight: 800;
	letter-spacing: -0.05em;
	line-height: 0.95;
}

.nj-project-nav .wp-block-post-navigation-link a:hover {
	background: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--base);
}

@media (max-width: 719px) {
	/* The grid drops to one column below 720px. */
	.nj-project-nav .post-navigation-link-next {
		border-left: 0;
		border-top: var(--wp--custom--rule--width) solid var(--wp--preset--color--contrast);
	}
}

/* Breadcrumbs: red slashes, current page in grey. */
.wp-block-breadcrumbs li:not(:last-child)::after {
	color: var(--wp--preset--color--accent);
	opacity: 1;
}

.wp-block-breadcrumbs [aria-current="page"] {
	color: var(--wp--preset--color--muted);
}

.wp-block-breadcrumbs a {
	border-bottom: var(--wp--custom--rule--width) solid currentColor;
}

.single .wp-site-blocks > footer.wp-block-template-part {
	margin-block-start: var(--wp--preset--spacing--60);
}

/* =========================================================
   Round 3: Research, Activities, Contact
   ========================================================= */

/* A list of ruled rows right under a section label: the label's rule is the
   top line, the list closes with its own rule. */
.nj-rows {
	border-bottom: var(--wp--custom--rule--width) solid currentColor;
}

.nj-rows > .is-style-nj-row:first-child {
	border-top: 0;
}

/* List of light rows (supervised projects, presentations). */
.nj-light-rows {
	border-top: var(--wp--custom--rule--width) solid currentColor;
}

.nj-light-rows .wp-block-columns {
	align-items: baseline;
}

.nj-light-rows p {
	margin: 0;
}

.nj-note-muted {
	color: var(--wp--preset--color--muted);
	font-style: italic;
}

/* Section label sitting directly on its content (no gap). */
.nj-tight > h2 {
	margin-bottom: 0;
}

/* ---------- Activities: expandable rows ---------- */

.nj-activity__head {
	gap: 8px;
}

/* Meta line under a row title ("2019 to 2026", a role): also used on the home page. */
.nj-activity p.nj-activity__meta,
.wp-block-columns p.nj-meta {
	max-width: var(--wp--custom--measure--meta);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-meta);
	line-height: 1.35;
	letter-spacing: var(--wp--custom--tracking--mono);
	color: var(--wp--preset--color--muted);
}

.nj-activity__body {
	max-width: var(--wp--custom--measure--wide);
}

.nj-activity__body p {
	margin: 0;
}

.nj-activity__clip > * + * {
	margin-top: 16px;
}

.nj-activity__clip > :first-child {
	margin-top: 16px;
}

.nj-activity__clip .wp-block-image {
	margin-block: 8px;
}

.nj-activity__clip .wp-block-image img {
	width: 200px;
	height: auto;
	border: var(--wp--custom--rule--width) solid var(--wp--preset--color--rule);
}

/* Toggle: a red + that fills into the logo's red square on hover, and turns
   into an × whose hover shape is the red dot that ends each page title. */
.nj-activity__toggle {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	margin: -6px 0 -6px 2px;
	padding: 0;
	border: 0;
	border-radius: 0;
	background: transparent;
	color: var(--wp--preset--color--accent);
	vertical-align: middle;
	cursor: pointer;
	transition: transform 360ms var(--wp--custom--motion--ease), border-radius 360ms var(--wp--custom--motion--ease), background-color var(--wp--custom--motion--fast) ease, color var(--wp--custom--motion--fast) ease;
}

.nj-activity__toggle svg {
	display: block;
}

.nj-activity__toggle:hover {
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--base);
}

.nj-activity__toggle:active {
	background: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--base);
}

.nj-activity__toggle:focus {
	outline: none;
}

.nj-activity__toggle:focus-visible {
	outline: 2px solid var(--wp--preset--color--contrast);
	outline-offset: 3px;
}

.nj-activity__toggle[aria-expanded="true"] {
	transform: rotate(135deg);
	border-radius: 50%;
}

/* Panels are visible without JavaScript (and in the editor); the script
   collapses them. Closing is faster than opening. */
.js .nj-activity__more {
	display: grid;
	grid-template-rows: 1fr;
	opacity: 1;
	visibility: visible;
	transition: grid-template-rows 320ms var(--wp--custom--motion--ease), opacity 240ms ease 80ms, visibility 0s;
}

.js .nj-activity__more:not(.is-open) {
	grid-template-rows: 0fr;
	opacity: 0;
	visibility: hidden;
	transition: grid-template-rows 240ms var(--wp--custom--motion--ease), opacity 160ms ease, visibility 0s 240ms;
}

.js .nj-activity__clip {
	min-height: 0;
	overflow: hidden;
}

@media (max-width: 781px) {
	.wp-block-columns.nj-activity {
		gap: 8px;
		padding: 16px 0 32px;
	}

	.nj-activity__body {
		margin-top: 8px;
	}

	/* 44 × 44 tap target around the 32 × 32 toggle. */
	.nj-activity__toggle::after {
		content: "";
		position: absolute;
		inset: -6px;
	}
}

/* ---------- "On this page" quick nav (Research) ---------- */

/* Same look as the case study's Tasks list: ruled rows, red number, red ↓. */
.nj-toc {
	max-width: 320px;
}

.nj-toc ul {
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: nj-toc;
}

.nj-toc li {
	counter-increment: nj-toc;
	margin: 0;
	border-bottom: var(--wp--custom--rule--width) solid var(--wp--preset--color--rule);
}

.nj-toc li a {
	display: flex;
	gap: 12px;
	align-items: baseline;
	padding: 10px 0;
	font-size: var(--wp--preset--font-size--body);
	line-height: 1.3;
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
	transition: color var(--wp--custom--motion--fast) ease;
}

.nj-toc li a::before,
.nj-toc li a::after {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-small);
	color: var(--wp--preset--color--accent);
}

.nj-toc li a::before {
	content: counter(nj-toc, decimal-leading-zero);
}

.nj-toc li a::after {
	content: "↓";
	margin-left: auto;
}

.nj-toc li a:hover {
	color: var(--wp--preset--color--accent);
}

@media (max-width: 781px) {
	.nj-toc {
		max-width: none;
		margin-bottom: var(--wp--preset--spacing--30);
	}
}

/* ---------- Publications ---------- */

/* "← Research" above the title of a child page (patterns/back-to-parent.php). */
.nj-back {
	margin: 0;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-meta);
	text-transform: uppercase;
}

.nj-back a {
	display: inline-flex;
	gap: 8px;
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
}

.nj-back a::before {
	content: "←";
	color: var(--wp--preset--color--accent);
}

.nj-back a:hover {
	color: var(--wp--preset--color--accent);
}

/* One paper per row: year, then title / authors / venue, then links. */
.wp-block-columns.nj-pub {
	margin: 0;
	padding: 14px 0 18px;
	border-bottom: var(--wp--custom--rule--width) solid var(--wp--preset--color--rule);
}

/* The last paper of each year gets an ink rule, so the years read as groups. */
.nj-pub-year > .nj-pub:last-child {
	border-bottom-color: var(--wp--preset--color--contrast);
}

.nj-pub h3,
.nj-poster h3 {
	font-weight: 700;
	letter-spacing: -0.02em;
	line-height: 1.15;
	text-wrap: balance;
}

.nj-pub__year {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-meta);
	color: var(--wp--preset--color--accent);
}

.nj-pub__venue {
	max-width: 68ch;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono);
	line-height: 1.45;
	color: var(--wp--preset--color--muted);
}

/* "Ref ↗", "PDF ↗", "Poster ↗": typewriter caps, red, a 1px rule that turns ink (white on ink). */
.nj-links {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-meta);
	text-transform: uppercase;
}

.nj-links a {
	color: var(--wp--preset--color--accent);
	text-decoration: none;
	border-bottom: var(--wp--custom--rule--width) solid currentColor;
	transition: color var(--wp--custom--motion--fast) ease;
}

.nj-links a + a {
	margin-left: 16px;
}

.nj-links a:hover {
	color: var(--wp--preset--color--contrast);
}

.has-contrast-background-color .nj-links a:hover {
	color: var(--wp--preset--color--base);
}

/* Poster cards on the ink band. */
/* auto-fit (WordPress uses auto-fill): the cards stretch over the full width instead of leaving empty columns. */
.wp-block-group.nj-posters {
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
}

.nj-poster__image {
	margin: 0;
	background: var(--wp--preset--color--base);
	border: var(--wp--custom--rule--width) solid var(--wp--preset--color--base);
}

.nj-poster__image img {
	display: block;
	width: 100%;
	object-position: top;
}

.nj-poster__meta {
	padding-top: 10px;
	border-top: var(--wp--custom--rule--width) solid currentColor;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-small);
	text-transform: uppercase;
}

/* ---------- 404: the full stop falls off (assets/js/fall.js) ---------- */

/*
 * The full stop is drawn as a circle with the exact size and position of
 * Inter's "." (0.184em, 0.035em after the letter, 0.009em below the
 * baseline), so it can squash from its bottom when it lands.
 */
.nj-fall::after {
	content: "";
	display: inline-block;
	width: 0.184em;
	height: 0.184em;
	margin-left: 0.035em;
	vertical-align: -0.009em;
	border-radius: 50%;
	background: var(--wp--preset--color--accent);
	transform-origin: 50% 100%;
}

/*
 * --nj-drop (baseline to the rule below) and --nj-roll come from fall.js.
 * Falls (accelerating), squashes on the rule, then bounces three times,
 * lower each time, while rolling right.
 */
.nj-fall.is-fallen::after {
	--nj-floor: calc(var(--nj-drop) - 0.009em);
	transform: translate(var(--nj-roll), var(--nj-floor));
	animation: nj-fall 2s 0.5s both;
}

@keyframes nj-fall {
	/* Teeters on the edge… */
	0% { transform: translate(0, 0); animation-timing-function: ease-in-out; }
	5% { transform: translate(0.03em, 0); animation-timing-function: ease-in-out; }
	10% { transform: translate(0, 0); animation-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53); }
	/* …falls and squashes on the rule… */
	34% { transform: translate(calc(var(--nj-roll) * 0.08), var(--nj-floor)) scale(0.9, 1.1); animation-timing-function: linear; }
	37% { transform: translate(calc(var(--nj-roll) * 0.1), var(--nj-floor)) scale(1.4, 0.6); animation-timing-function: linear; }
	40% { transform: translate(calc(var(--nj-roll) * 0.12), var(--nj-floor)) scale(1, 1); animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94); }
	/* …bounce… */
	54% { transform: translate(calc(var(--nj-roll) * 0.35), calc(var(--nj-floor) * 0.55)) scale(0.95, 1.05); animation-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53); }
	68% { transform: translate(calc(var(--nj-roll) * 0.58), var(--nj-floor)); animation-timing-function: linear; }
	70% { transform: translate(calc(var(--nj-roll) * 0.61), var(--nj-floor)) scale(1.2, 0.8); animation-timing-function: linear; }
	72% { transform: translate(calc(var(--nj-roll) * 0.64), var(--nj-floor)); animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94); }
	/* …smaller bounce… */
	81% { transform: translate(calc(var(--nj-roll) * 0.77), calc(var(--nj-floor) * 0.82)); animation-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53); }
	90% { transform: translate(calc(var(--nj-roll) * 0.88), var(--nj-floor)); animation-timing-function: linear; }
	91.5% { transform: translate(calc(var(--nj-roll) * 0.9), var(--nj-floor)) scale(1.08, 0.92); animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94); }
	/* …a last tiny hop, and it rolls to a stop. */
	95.5% { transform: translate(calc(var(--nj-roll) * 0.95), calc(var(--nj-floor) * 0.95)); animation-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53); }
	100% { transform: translate(var(--nj-roll), var(--nj-floor)); }
}

@media (prefers-reduced-motion: reduce) {
	/* No fall: the full stop is already lying on the rule. */
	.nj-fall.is-fallen::after {
		animation: none;
	}
}

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

.nj-contact-intro {
	max-width: 28ch;
}

.nj-contact-title {
	font-size: clamp(64px, 15vw, 260px);
	letter-spacing: -0.07em;
	line-height: 0.82;
	margin-left: -0.05em;
}

/* On the red page the red full stop would vanish, so it turns ink. */
.page-template-page-contact .is-style-nj-title::after {
	color: var(--wp--preset--color--contrast);
}

/* The address with the Copy button right after it; the button wraps below on narrow screens. */
.nj-email-address {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 16px clamp(16px, 2vw, 32px);
	--nj-email-size: clamp(34px, 7.6vw, 150px);
	font-size: var(--nj-email-size);
	font-weight: 800;
	letter-spacing: -0.06em;
	line-height: 0.95;
	overflow-wrap: anywhere;
}

.nj-email-address a {
	color: inherit;
	text-decoration: none;
}

/* The button's bottom edge sits on the address's baseline (0.12em above the bottom of its line). */
.nj-email-address .nj-copy {
	align-self: flex-end;
	margin-bottom: calc(var(--nj-email-size) * 0.12);
}

.nj-email-address a:hover {
	color: var(--wp--preset--color--contrast);
}

.nj-copy {
	all: unset;
	flex: none;
	cursor: pointer;
	font-weight: 400;
	line-height: normal;
	letter-spacing: normal;
	padding: 6px 12px;
	border: var(--wp--custom--rule--width) solid currentColor;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono);
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast);
	transition: background-color 200ms ease, color 200ms ease;
}

/* Ink on the red page; fills ink on hover. */
.nj-copy:hover {
	background: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--base);
}

/* Copied: the button turns ink and the logo's red square pops in. */
.nj-copy.is-copied,
.nj-copy.is-copied:hover {
	background: var(--wp--preset--color--contrast);
	border-color: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--base);
}

.nj-copy.is-copied::after {
	content: "";
	display: inline-block;
	width: 0.75em;
	height: 0.75em;
	margin-left: 8px;
	vertical-align: -0.05em;
	background: var(--wp--preset--color--accent);
	animation: nj-pop 450ms var(--wp--custom--motion--ease) both;
}

@keyframes nj-pop {
	0% { transform: scale(0) rotate(-45deg); }
	60% { transform: scale(1.35) rotate(8deg); }
	100% { transform: scale(1) rotate(0); }
}

.nj-copy:focus-visible {
	outline: 2px solid var(--wp--preset--color--contrast);
	outline-offset: 3px;
}

/* Links on the white "More" band: ink with a 2px underline, red on hover. */
.nj-more a:not(.wp-element-button) {
	color: var(--wp--preset--color--contrast);
	text-decoration-thickness: 2px;
}

.nj-more a:not(.wp-element-button):hover {
	color: var(--wp--preset--color--accent);
}

/* CV buttons: "CV" in bold Inter, the rest in typewriter caps. */
.nj-cv .wp-element-button {
	display: flex;
	align-items: center;
	gap: 14px;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--mono-meta);
	font-weight: 400;
	letter-spacing: 0;
	text-transform: uppercase;
	white-space: nowrap;
}

.nj-cv .wp-element-button strong {
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--title);
	font-weight: 700;
	letter-spacing: -0.03em;
	text-transform: none;
}

.nj-measure-wide {
	max-width: var(--wp--custom--measure--wide);
}

/* Notes in the supervised-projects list ("Upcoming papers.") */
.nj-light-rows em {
	color: var(--wp--preset--color--muted);
}

/* PDF links in the light rows are red, as in running text. */
.nj-light-rows a {
	color: var(--wp--preset--color--accent);
	text-decoration: underline;
}

.nj-light-rows a:hover {
	color: var(--wp--preset--color--contrast);
}
