/*
Styles for the portfolio pages (index.php and portfolio.php).
*/

/* Both fonts are variable fonts: a single file contains all of the weights. They are licensed under the SIL Open Font License. */
@font-face
{
	font-family: 'Inter';
	src: url('/fonts/inter-latin-variable.woff2') format('woff2');
	font-weight: 100 900;
	font-display: swap;
}

@font-face
{
	font-family: 'Space Grotesk';
	src: url('/fonts/space-grotesk-latin-variable.woff2') format('woff2');
	font-weight: 300 700;
	font-display: swap;
}

/* The angle of the gradient in hovered borders. Registering it as an angle is what allows it to be animated. */
@property --gradient-angle
{
	syntax: '<angle>';
	initial-value: 0deg;
	inherits: false;
}

:root
{
	color-scheme: light dark;

	/* Each color is defined as light-dark(<light theme>, <dark theme>). */
	--color-bg: light-dark(#f8f8f8, #131316);
	--color-surface: light-dark(#ffffff, #1c1c21);
	--color-text: light-dark(#252525, #ececef);
	--color-text-muted: light-dark(#666666, #a3a3ad);
	--color-border: light-dark(#e4e4e4, #2e2e36);
	--color-border-strong: light-dark(#8c8c8c, #74747e);	/* For borders that need to be clearly visible, like those of inputs. */
	--color-accent: #fe2261;
	--color-link: light-dark(#d60045, #ff5c8a);	/* The accent color, adjusted to be readable at small text sizes. */
	--color-link-hover: light-dark(#a80036, #ff8aab);
	--color-button: light-dark(#333333, #ececef);
	--color-button-hover: light-dark(#4e4e4e, #ffffff);
	--color-button-text: light-dark(#ffffff, #131316);
	--color-success: light-dark(#1a7f47, #5fd08f);
	--color-danger: light-dark(#c0271a, #ff7b6e);
	--shadow: 0 12px 32px light-dark(rgb(0 0 0 / 0.14), rgb(0 0 0 / 0.5));
	--shadow-card: 0 1px 2px light-dark(rgb(0 0 0 / 0.06), transparent), 0 4px 16px light-dark(rgb(0 0 0 / 0.06), transparent);	/* Shadows are invisible on a dark background, so the dark theme does without. */

	/* The gradient is used sparingly: for lines, hovered borders and the glow in the introduction. */
	--gradient-colors: #20cfd5, #22a1dd, #2278dd, #a800ff, #f2269f, #fe2261, #fe3354, #fe584e, #ff9e40, #ffb540;
	--gradient: linear-gradient(90deg, var(--gradient-colors));
	--gradient-text: linear-gradient(90deg, #a800ff, #f2269f, #fe2261, #fe584e);	/* Leaves out the lightest colors, which are hard to read as text. */
	--gradient-button: linear-gradient(90deg, #a800ff, #cf1687, #e0144f);	/* Dark enough for white text. */

	--font-display: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
	--font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

	--radius: 16px;
	--radius-small: 8px;
	--header-height: 4.5rem;
}

/* Set by the theme toggle, to overrule the theme of the operating system. */
:root[data-theme="light"]
{
	color-scheme: light;
}

:root[data-theme="dark"]
{
	color-scheme: dark;
}

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

html
{
	scroll-padding-top: var(--header-height);	/* So that the sticky header doesn't cover the section titles when jumping to an anchor. */
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

body
{
	margin: 0;
	background-color: var(--color-bg);
	color: var(--color-text);
	font-family: var(--font-body);
	font-size: 1rem;
	line-height: 1.6;
	overflow-y: scroll;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

@media (prefers-reduced-motion: no-preference)
{
	html
	{
		scroll-behavior: smooth;
	}

	/* Cross-fades between the main page and the project pages. */
	@view-transition
	{
		navigation: auto;
	}
}

::selection
{
	background-color: var(--color-accent);
	color: #ffffff;
}

:focus-visible
{
	outline: 2px solid var(--color-link);
	outline-offset: 3px;
}

/* Elements that set their own 'display' would otherwise ignore the 'hidden' attribute. */
[hidden]
{
	display: none !important;
}

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

a
{
	color: var(--color-link);
	text-decoration: none;
	transition: color 0.15s;
}

a:hover
{
	color: var(--color-link-hover);
}

h1,
h2,
h3
{
	line-height: 1.2;
	letter-spacing: -0.02em;
	text-wrap: balance;
}

.container
{
	width: min(100% - 2rem, 70rem);
	margin-inline: auto;
}

.icon
{
	width: 1.2em;
	height: 1.2em;
	flex: none;
	vertical-align: -0.2em;
}

.icon-link .icon
{
	margin-right: 0.35em;
}

.skip-link
{
	position: absolute;
	left: 1rem;
	top: -10rem;
	z-index: 20;
	padding: 0.6rem 1rem;
	border-radius: var(--radius-small);
	background-color: var(--color-button);
	color: var(--color-button-text);
}

.skip-link:focus
{
	top: 1rem;
	color: var(--color-button-text);
}


/*
Header and navigation.
*/
.site-header
{
	position: sticky;
	top: 0;
	z-index: 10;
	background-color: color-mix(in srgb, var(--color-bg) 85%, transparent);
	-webkit-backdrop-filter: blur(12px);
	backdrop-filter: blur(12px);
	border-bottom: 1px solid var(--color-border);
}

.site-header-inner
{
	display: flex;
	align-items: center;
	gap: 1rem;
	min-height: var(--header-height);
}

.brand
{
	margin-right: auto;
	color: var(--color-text);
	font-family: var(--font-display);
	font-size: 1.6rem;
	font-weight: 300;
	text-transform: uppercase;
	white-space: nowrap;
}

.brand strong
{
	background: var(--gradient-text);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	font-weight: 700;
}

.brand:hover
{
	color: var(--color-text-muted);
}

.site-nav ul
{
	display: flex;
	gap: 0.25rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.site-nav a
{
	position: relative;
	display: block;
	padding: 0.5rem 0.9rem;
	color: var(--color-text-muted);
	font-size: 0.8rem;
	letter-spacing: 0.15em;
	text-transform: uppercase;
	white-space: nowrap;
	transition: color 0.15s;
}

/* The line below the navigation button of the current section. */
.site-nav a::after
{
	content: '';
	position: absolute;
	inset: auto 0.9rem 0.1rem;
	height: 2px;
	border-radius: 1px;
	background: var(--gradient-text);
	opacity: 0;
	transition: opacity 0.2s;
}

.site-nav a:hover
{
	color: var(--color-text);
}

.site-nav a[aria-current]
{
	color: var(--color-text);
}

.site-nav a[aria-current]::after
{
	opacity: 1;
}

.theme-toggle
{
	display: grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: none;
	color: var(--color-text-muted);
	font-size: 1rem;
	cursor: pointer;
	transition: color 0.15s, background-color 0.15s;
}

.theme-toggle:hover
{
	background-color: var(--color-border);
	color: var(--color-text);
}

/* The toggle shows the theme that it switches to: a moon in the light theme, and a sun in the dark theme. */
.theme-toggle-sun
{
	display: none;
}

:root[data-theme="dark"] .theme-toggle-moon
{
	display: none;
}

:root[data-theme="dark"] .theme-toggle-sun
{
	display: block;
}

@media (prefers-color-scheme: dark)
{
	:root:not([data-theme="light"]) .theme-toggle-moon
	{
		display: none;
	}

	:root:not([data-theme="light"]) .theme-toggle-sun
	{
		display: block;
	}
}

/* On phones everything in the header is made a little smaller, so that it fits on a single row. */
@media (max-width: 42rem)
{
	:root
	{
		--header-height: 3.5rem;
	}

	.site-header-inner
	{
		gap: 0.25rem;
	}

	.brand
	{
		font-size: 1.15rem;
	}

	.site-nav ul
	{
		gap: 0;
	}

	.site-nav a
	{
		padding: 0.85rem 0.4rem;
		font-size: 0.7rem;
		letter-spacing: 0.1em;
	}

	.site-nav a::after
	{
		inset: auto 0.4rem 0.5rem;
	}

	.theme-toggle
	{
		width: 2.25rem;
		height: 2.25rem;
	}
}

/* The narrowest phones need it smaller still. */
@media (max-width: 22.5rem)
{
	.brand
	{
		font-size: 1rem;
	}

	.site-nav a
	{
		padding-inline: 0.3rem;
		font-size: 0.65rem;
		letter-spacing: 0.06em;
	}

	.site-nav a::after
	{
		inset-inline: 0.3rem;
	}

	.theme-toggle
	{
		width: 2rem;
	}
}


/*
Introduction at the top of the main page.
*/
.hero
{
	position: relative;
	isolation: isolate;
	overflow: hidden;
	padding-block: clamp(3.5rem, 12vw, 8rem);
	background-color: var(--color-surface);
	border-bottom: 1px solid var(--color-border);
	font-family: var(--font-display);
}

/* A soft glow in the colors of the gradient, behind the text. */
.hero::before
{
	content: '';
	position: absolute;
	inset: 0;
	z-index: -1;
	background:
		radial-gradient(circle at 45% 110%, #20cfd5, transparent 35%),
		radial-gradient(circle at 70% -10%, #a800ff, transparent 40%),
		radial-gradient(circle at 100% 40%, #fe2261, transparent 35%),
		radial-gradient(circle at 85% 110%, #ffb540, transparent 30%);
	filter: blur(60px);
	opacity: 0.4;
}

@media (prefers-reduced-motion: no-preference)
{
	/* Lets the glow drift around slowly. It is made larger than the introduction, so that its edges stay out of view. */
	.hero::before
	{
		inset: -15%;
		animation: hero-glow-drift 24s ease-in-out infinite alternate;
		will-change: transform;
	}
}

@keyframes hero-glow-drift
{
	from
	{
		transform: translate3d(4%, -3%, 0) rotate(-4deg) scale(1);
	}
	to
	{
		transform: translate3d(-6%, 4%, 0) rotate(6deg) scale(1.15);
	}
}

.hero-greeting
{
	margin: 0 0 0.75rem;
	color: var(--color-text-muted);
	font-size: clamp(1rem, 2.5vw, 1.25rem);
}

.hero h1
{
	max-width: 18ch;
	margin: 0 0 1.25rem;
	font-size: clamp(2.25rem, 7vw, 4.25rem);
	font-weight: 700;
	line-height: 1.05;
	letter-spacing: -0.03em;
}

.hero-role
{
	margin: 0;
	color: var(--color-text-muted);
	font-family: var(--font-body);
	font-size: clamp(1.05rem, 2.5vw, 1.25rem);
	line-height: 1.4;
}


/*
Sections.
*/
.section
{
	padding-block: clamp(3rem, 8vw, 5rem);
}

.section-header
{
	display: flex;
	align-items: center;
	gap: 1.5rem;
	margin-bottom: 2rem;
}

/* The line that runs from the title to the other side of the page. */
.section-header::after
{
	content: '';
	flex: 1;
	height: 2px;
	border-radius: 1px;
	background: var(--gradient);
}

.section-title
{
	margin: 0;
	font-family: var(--font-display);
	font-size: clamp(2.25rem, 6vw, 3.25rem);
	font-weight: 700;
}

.section-header-link
{
	order: 1;	/* Places the link after the line. */
	color: var(--color-text-muted);
	font-size: 0.9rem;
	white-space: nowrap;
}

.section-header-link:hover
{
	color: var(--color-text);
}

.prose
{
	max-width: 44rem;
	font-size: 1.05rem;
	line-height: 1.7;
}

.prose > :first-child
{
	margin-top: 0;
}

.prose > :last-child
{
	margin-bottom: 0;
}

.prose a
{
	text-decoration-line: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
}

.notice
{
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
	margin: 0 0 1.5rem;
	padding: 1rem 1.25rem;
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-small);
	background-color: var(--color-surface);
}

.notice .icon
{
	margin-top: 0.2em;
}

.notice-success
{
	border-color: var(--color-success);
}

.notice-success .icon
{
	color: var(--color-success);
}

.notice-error
{
	border-color: var(--color-danger);
}

.notice-error .icon
{
	color: var(--color-danger);
}


/*
Portfolio tiles.
*/
.portfolio-group-title
{
	margin: 2.5rem 0 1rem;
	color: var(--color-text-muted);
	font-size: 0.8rem;
	font-weight: 600;
	letter-spacing: 0.15em;
	text-transform: uppercase;
}

.section-header + .portfolio-group-title
{
	margin-top: 0;
}

.portfolio-grid
{
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0.75rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 48rem)
{
	.portfolio-grid
	{
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 1.25rem;
	}
}

.portfolio-card
{
	display: flex;
	flex-direction: column;
	height: 100%;
	overflow: hidden;
	border: 2px solid transparent;
	border-radius: var(--radius);
	background: linear-gradient(var(--color-surface), var(--color-surface)) padding-box, var(--color-surface) border-box;
	box-shadow: var(--shadow-card);
	color: var(--color-text);
	transition: box-shadow 0.2s ease;
}

/*
The border shows the gradient, since it is the only part that the first (plain) background layer doesn't cover.
The gradient goes around the border, and ends in the color that it starts with so that there is no visible seam.
*/
.portfolio-card:hover,
.portfolio-card:focus-visible
{
	background: linear-gradient(var(--color-surface), var(--color-surface)) padding-box, conic-gradient(from var(--gradient-angle, 0deg), var(--gradient-colors), #20cfd5) border-box;
	box-shadow: var(--shadow);
	color: var(--color-text);
}

.portfolio-card-image
{
	position: relative;
	overflow: hidden;
}

/* The logo lies on top of the thumbnail, and stays still while the thumbnail zooms. */
.portfolio-card .portfolio-card-logo
{
	position: absolute;
	inset: 0;
	height: 100%;
}

.portfolio-card img
{
	display: block;
	width: 100%;
	aspect-ratio: 39 / 25;
	object-fit: cover;
}

@media (prefers-reduced-motion: no-preference)
{
	.portfolio-card img
	{
		transition: transform 0.4s ease;
	}

	.portfolio-card:hover img:not(.portfolio-card-logo),
	.portfolio-card:focus-visible img:not(.portfolio-card-logo)
	{
		transform: scale(1.05);
	}
}

.portfolio-card-caption
{
	padding: 0.75rem 0.9rem 0.9rem;
}

.portfolio-card-caption h4
{
	margin: 0;
	font-family: var(--font-display);
	font-size: 1rem;
	font-weight: 600;
	letter-spacing: -0.01em;
}

/*
The icon of a badge has the color of its text, until the tile is hovered. It then fades to pink and red, which is
what the moving blobs start from.
*/
.badge .gradient-icon-shape
{
	--gradient-icon-base: linear-gradient(90deg, #f2269f, #fe2261);

	display: inline-block;
	width: 1.2em;
	height: 1.2em;
	font-size: inherit;
	background: var(--color-text-muted);
	vertical-align: -0.2em;
}

.portfolio-card-subtitle
{
	margin: 0.2rem 0 0;
	color: var(--color-text-muted);
	font-size: 0.9rem;
	line-height: 1.4;
}

.portfolio-card-subtitle + .badge
{
	margin-top: 0.5rem;
}

.badge
{
	margin: 0.3rem 0 0;
	color: var(--color-text-muted);
	font-size: 0.85rem;
	line-height: 1.4;
}

@media (min-width: 48rem)
{
	.portfolio-card-caption
	{
		padding: 1rem 1.15rem 1.15rem;
	}

	.portfolio-card-caption h4
	{
		font-size: 1.15rem;
	}

	.portfolio-grid-featured
	{
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.portfolio-grid-featured .portfolio-card-caption h4
	{
		font-size: 1.4rem;
	}
}


/*
A group of tiles that only shows its first tiles until it is expanded. Without JavaScript the button can't work, so all
tiles are shown and the button is hidden.
*/
.js .portfolio-grid-collapsible:not(.is-expanded) .portfolio-extra
{
	display: none;
}

.expand-button
{
	display: none;
	align-items: center;
	gap: 0.5rem;
	margin: 1.25rem auto 0;
	padding: 0.7rem 1.5rem;
	border: 2px solid transparent;
	border-radius: 2rem;
	background: linear-gradient(var(--color-bg), var(--color-bg)) padding-box, var(--color-border-strong) border-box;
	color: var(--color-text-muted);
	font: inherit;
	font-size: 0.9rem;
	font-weight: 600;
	cursor: pointer;
	transition: color 0.15s;
}

.js .expand-button
{
	display: flex;
}

/* The border shows the gradient when hovered, the same way the tiles do. */
.expand-button:hover,
.expand-button:focus-visible
{
	background: linear-gradient(var(--color-bg), var(--color-bg)) padding-box, conic-gradient(from var(--gradient-angle, 0deg), var(--gradient-colors), #20cfd5) border-box;
	color: var(--color-text);
}

.expand-button .icon
{
	transition: transform 0.2s ease;
}

.expand-button[aria-expanded="true"] .icon
{
	transform: rotate(180deg);
}

@media (max-width: 47.99rem)
{
	.js .portfolio-grid-collapsible:not(.is-expanded) .portfolio-extra-fills-row
	{
		display: block;
	}
}

/* The tiles that appear when a group is expanded fade in and move up a little, one shortly after the other. */
@keyframes tile-appearing
{
	from
	{
		opacity: 0;
		transform: translateY(1rem);
	}
}

@media (prefers-reduced-motion: no-preference)
{
	.portfolio-grid-collapsible.is-expanded .portfolio-extra
	{
		animation: tile-appearing 0.4s ease backwards;
		animation-delay: calc(var(--extra-index) * 45ms);
	}
}

/* This tile was already visible on phones, so it stays put. */
@media (prefers-reduced-motion: no-preference) and (max-width: 47.99rem)
{
	.portfolio-grid-collapsible.is-expanded .portfolio-extra-fills-row
	{
		animation: none;
	}
}


/*
Credits: a compact list, to set these games apart from the projects that have their own tile and page.
*/
.portfolio-group-intro
{
	max-width: 44rem;
	margin: -0.25rem 0 1rem;
	color: var(--color-text-muted);
}

.credit-list
{
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
	gap: 0.75rem 1.25rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.credit-card
{
	display: flex;
	align-items: flex-start;
	gap: 0.85rem;
	height: 100%;
	padding: 0.9rem 1.15rem;
	border: 2px solid transparent;
	border-radius: var(--radius);
	background: linear-gradient(var(--color-surface), var(--color-surface)) padding-box, var(--color-surface) border-box;
	box-shadow: var(--shadow-card);
	color: var(--color-text);
	transition: box-shadow 0.2s ease;
}

/* Only the credits that are links react to being hovered. */
a.credit-card:hover,
a.credit-card:focus-visible
{
	background: linear-gradient(var(--color-surface), var(--color-surface)) padding-box, conic-gradient(from var(--gradient-angle, 0deg), var(--gradient-colors), #20cfd5) border-box;
	box-shadow: var(--shadow);
	color: var(--color-text);
}

.credit-card .gradient-icon-shape
{
	width: 1.5rem;
	height: 1.5rem;
	margin-top: 0.1rem;
}

/* The arrow that marks a credit as a link to another website. */
.credit-card .credit-card-arrow
{
	width: 1rem;
	height: 1rem;
	margin-left: auto;
	color: var(--color-text-muted);
}

.credit-list h4
{
	margin: 0;
	font-family: var(--font-display);
	font-size: 1rem;
	font-weight: 600;
	letter-spacing: -0.01em;
}

.credit-list p
{
	margin: 0.15rem 0 0;
	color: var(--color-text-muted);
	font-size: 0.9rem;
}


/*
Talks.
*/
.talk-list
{
	display: grid;
	gap: 1.25rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.talk-card
{
	display: flex;
	align-items: flex-start;
	gap: 1.25rem;
	padding: 1.25rem 1.5rem;
	border: 2px solid transparent;
	border-radius: var(--radius);
	background: linear-gradient(var(--color-surface), var(--color-surface)) padding-box, var(--color-surface) border-box;
	box-shadow: var(--shadow-card);
	color: var(--color-text-muted);
	transition: box-shadow 0.2s ease;
}

.talk-card:hover,
.talk-card:focus-within
{
	background: linear-gradient(var(--color-surface), var(--color-surface)) padding-box, conic-gradient(from var(--gradient-angle, 0deg), var(--gradient-colors), #20cfd5) border-box;
	box-shadow: var(--shadow);
	color: var(--color-text-muted);
}

/* A square in the colors of the gradient with a white icon in it. */
.gradient-icon
{
	display: grid;
	place-items: center;
	flex: none;
	width: 3rem;
	height: 3rem;
	border-radius: var(--radius-small);
	position: relative;
	isolation: isolate;
	overflow: hidden;
	background: var(--gradient-button);
	color: #ffffff;
	font-size: 1.25rem;
}

/*
Blobs in the colors of the gradient, which slowly move around and blend into each other. They lie between the regular
background of the icon and the icon itself, and fade in when the card or link around it is hovered.
Each blob is a background layer that is larger than the icon, so that moving the layer moves the blob across the icon.
The blobs start just outside of the icon and the last layer is the regular background, which makes the first frame look
the same as the icon does normally.
*/
.gradient-icon::before
{
	content: '';
	position: absolute;
	inset: 0;
	z-index: -1;
	opacity: 0;
	transition: opacity 0.8s ease;
	background:
		radial-gradient(circle, #20cfd5, transparent 65%) 210% 100% / 190% 190% no-repeat,
		radial-gradient(circle, #ffb540, transparent 60%) -130% 0% / 170% 170% no-repeat,
		radial-gradient(circle, #fe2261, transparent 65%) 50% -90% / 210% 210% no-repeat,
		var(--gradient-icon-base, var(--gradient-button));
}

/*
Shows the colors in the shape of an icon, instead of in a square behind an icon. The icon is used as a mask: only the
parts of the element that the icon covers are visible. See iconShape() in icons.php.
*/
.gradient-icon-shape
{
	--gradient-icon-base: var(--color-link);

	width: 1.6rem;
	height: 1.6rem;
	border-radius: 0;
	background: var(--color-link);
	-webkit-mask: var(--icon-shape) center / contain no-repeat;
	mask: var(--icon-shape) center / contain no-repeat;
}

/* Without movement the blobs would stay outside of the icon, so they are placed inside of it instead. */
@media (prefers-reduced-motion: reduce)
{
	.gradient-icon::before
	{
		background-position: 100% 80%, 0% 30%, 40% 0%, 0 0;
	}
}

:is(.talk-card, .contact-links a, a.credit-card, .portfolio-card):hover .gradient-icon::before,
:is(.talk-card:focus-within, .contact-links a:focus-visible, a.credit-card:focus-visible, .portfolio-card:focus-visible) .gradient-icon::before
{
	opacity: 1;
}

/* Moves the blobs into the icon once, after which blobs-drifting keeps them moving around. */
@keyframes blobs-entering
{
	to
	{
		background-position: 100% 80%, 0% 30%, 40% 0%, 0 0;
	}
}

@keyframes blobs-drifting
{
	0%
	{
		background-position: 100% 80%, 0% 30%, 40% 0%, 0 0;
	}
	50%
	{
		background-position: 40% 20%, 60% 90%, 0% 60%, 0 0;
	}
	100%
	{
		background-position: 80% 100%, 100% 40%, 70% 30%, 0 0;
	}
}

.talk-card h4
{
	margin: 0;
	color: var(--color-text);
	font-family: var(--font-display);
	font-size: 1.15rem;
	font-weight: 600;
	letter-spacing: -0.01em;
}

.talk-card p
{
	max-width: 44rem;
	margin: 0.5rem 0 0;
}

.talk-card .talk-card-venues
{
	margin-top: 0.25rem;
	font-size: 0.9rem;
}

.talk-card-links
{
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.75rem;
	margin: 0.9rem 0 0;
	padding: 0;
	list-style: none;
	font-size: 0.9rem;
}

.talk-card-links a
{
	font-weight: 600;
}

.talk-card-links a:hover
{
	text-decoration-line: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
}

/* The size of a file, next to its download link. */
.talk-card-size,
.download-size
{
	margin-left: 0.25rem;
	color: var(--color-text-muted);
	font-size: 0.85em;
	white-space: nowrap;
}

@media (max-width: 36rem)
{
	.talk-card
	{
		padding: 1rem;
	}

	.talk-card .gradient-icon
	{
		display: none;
	}
}


/*
Project pages.
*/
.back-link
{
	display: inline-block;
	margin-bottom: 1.5rem;
	color: var(--color-text-muted);
	font-size: 0.8rem;
	letter-spacing: 0.15em;
	text-transform: uppercase;
}

.back-link:hover
{
	color: var(--color-text);
}

.back-link .icon
{
	margin-right: 0.35em;
	transition: transform 0.2s ease;
}

.back-link:hover .icon
{
	transform: translateX(-4px);
}

.project .section-title
{
	margin-bottom: 2rem;
}

.project-header
{
	margin-bottom: 2rem;
}

.project-header .section-title
{
	margin-bottom: 0;
}

/* The one-line description of a project, below its title. */
.project-subtitle
{
	margin: 0.5rem 0 0;
	color: var(--color-text-muted);
	font-family: var(--font-display);
	font-size: clamp(1.1rem, 3vw, 1.4rem);
	line-height: 1.3;
}

.project-overview
{
	display: grid;
	gap: 2rem;
	align-items: start;
}

@media (min-width: 56rem)
{
	.project-overview
	{
		grid-template-columns: minmax(0, 1fr) 24rem;
		gap: 3rem;
	}
}

.project-data
{
	display: grid;
	gap: 1rem;
	margin: 0;
	padding: 1.25rem 1.5rem;
	border-radius: var(--radius);
	background-color: var(--color-surface);
	box-shadow: var(--shadow-card);
}

.project-data dt
{
	color: var(--color-text-muted);
	font-size: 0.75rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

.project-data dd
{
	margin: 0;
}

.project-links
{
	margin: 0;
	padding: 0;
	list-style: none;
	overflow-wrap: anywhere;
}

/* The links that belong to another link are indented, with a line that connects them. */
.project-links .project-links
{
	margin: 0.15rem 0 0.35rem 0.55rem;
	padding-left: 0.9rem;
	border-left: 1px solid var(--color-border-strong);
	font-size: 0.95em;
}

.project-media
{
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
	gap: 1.25rem;
	margin-top: 2.5rem;
}

.gallery,
.video
{
	position: relative;
	min-width: 0;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	border-radius: var(--radius);
	background-color: #000000;
}

.video iframe
{
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

/* The screenshots sit next to each other in a row that can be scrolled (or swiped) through, one screenshot at a time. */
.gallery-track
{
	display: flex;
	height: 100%;
	margin: 0;
	padding: 0;
	list-style: none;
	overflow-x: auto;
	overscroll-behavior-x: contain;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
}

@media (prefers-reduced-motion: no-preference)
{
	.gallery-track
	{
		scroll-behavior: smooth;
	}
}

.gallery-track:focus-visible
{
	outline-offset: -2px;
}

.gallery-track li
{
	flex: 0 0 100%;
	height: 100%;
	scroll-snap-align: center;
}

.gallery-track a
{
	display: block;
	height: 100%;
	cursor: zoom-in;
}

.gallery-track img
{
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.gallery-button
{
	position: absolute;
	top: 50%;
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background-color: rgb(0 0 0 / 0.55);
	color: #ffffff;
	font-size: 1.25rem;
	cursor: pointer;
	transform: translateY(-50%);
	transition: background-color 0.15s;
}

.gallery-button:hover
{
	background-color: rgb(0 0 0 / 0.8);
}

.gallery-button:focus-visible
{
	outline-color: #ffffff;
	outline-offset: -4px;
}

.gallery-button-prev
{
	left: 0.75rem;
}

.gallery-button-next
{
	right: 0.75rem;
}

.gallery-counter
{
	position: absolute;
	right: 0.75rem;
	bottom: 0.75rem;
	margin: 0;
	padding: 0.1rem 0.6rem;
	border-radius: 1rem;
	background-color: rgb(0 0 0 / 0.55);
	color: #ffffff;
	font-size: 0.8rem;
	font-variant-numeric: tabular-nums;
	pointer-events: none;
}


/*
Contact.
*/
.contact
{
	display: grid;
	gap: 2.5rem;
	align-items: start;
}

@media (min-width: 48rem)
{
	.contact
	{
		grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
		gap: 4rem;
	}
}

.contact-form-trap
{
	display: none;
}

.field
{
	margin-bottom: 1.25rem;
}

.field label
{
	display: block;
	margin-bottom: 0.35rem;
	font-size: 0.9rem;
	font-weight: 600;
}

.field input,
.field textarea
{
	display: block;
	width: 100%;
	padding: 0.65rem 0.85rem;
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-small);
	background-color: var(--color-surface);
	color: var(--color-text);
	font: inherit;
}

.field textarea
{
	min-height: 8rem;
	resize: vertical;
}

.field input:focus-visible,
.field textarea:focus-visible
{
	outline-offset: 0;
	border-color: var(--color-link);
}

/* Only marks a field as invalid after it has been interacted with, instead of straight away. */
.field input:user-invalid,
.field textarea:user-invalid
{
	border-color: var(--color-danger);
}

.button
{
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	width: 100%;
	padding: 0.8rem 1.75rem;
	border: 0;
	border-radius: 2rem;
	background: var(--gradient-button);
	color: #ffffff;
	font: inherit;
	font-weight: 600;
	cursor: pointer;
	transition: filter 0.15s, box-shadow 0.15s;
}

.button:hover
{
	filter: brightness(1.12);
	box-shadow: 0 6px 20px rgb(207 22 135 / 0.35);
}

.button:disabled
{
	cursor: progress;
	opacity: 0.7;
}

/* Show either the default icon, or the spinner icon, depending on the state of the form. */
.button-icon-busy,
.contact-form[aria-busy="true"] .button-icon-idle
{
	display: none;
}

.contact-form[aria-busy="true"] .button-icon-busy
{
	display: block;
	animation: rotating 1s linear infinite;
}

@keyframes gradient-rotating
{
	to
	{
		--gradient-angle: 360deg;
	}
}

@media (prefers-reduced-motion: no-preference)
{
	.portfolio-card:hover,
	.portfolio-card:focus-visible,
	.talk-card:hover,
	.talk-card:focus-within,
	a.credit-card:hover,
	a.credit-card:focus-visible,
	.expand-button:hover,
	.expand-button:focus-visible,
	.contact-links a:hover
	{
		animation: gradient-rotating 4s linear infinite;
	}

	/* The blobs only move while the card is hovered. They are paused in place otherwise, so that they don't jump while fading out. */
	.gradient-icon::before
	{
		animation: blobs-entering 3s ease-in-out forwards paused, blobs-drifting 9s ease-in-out 3s infinite alternate paused;
	}

	:is(.talk-card, .contact-links a, a.credit-card, .portfolio-card):hover .gradient-icon::before,
	:is(.talk-card:focus-within, .contact-links a:focus-visible, a.credit-card:focus-visible, .portfolio-card:focus-visible) .gradient-icon::before
	{
		animation-play-state: running;
	}
}

@keyframes rotating
{
	to
	{
		transform: rotate(360deg);
	}
}

.contact-form .notice
{
	margin: 1.25rem 0 0;
}

.contact-form-legal
{
	margin: 1rem 0 0;
	color: var(--color-text-muted);
	font-size: 0.8rem;
}

.contact-form-legal a
{
	color: inherit;
	text-decoration-line: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
}

/* The reCAPTCHA badge may be hidden as long as the form mentions reCAPTCHA, which .contact-form-legal does. */
.grecaptcha-badge
{
	visibility: hidden;
}

.contact-links
{
	display: grid;
	gap: 0.75rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.contact-links a
{
	display: flex;
	align-items: center;
	gap: 1rem;
	padding: 0.9rem 1.15rem;
	border: 2px solid transparent;
	border-radius: var(--radius);
	background: linear-gradient(var(--color-surface), var(--color-surface)) padding-box, var(--color-surface) border-box;
	box-shadow: var(--shadow-card);
	color: var(--color-text-muted);
	overflow-wrap: anywhere;
}

.contact-links a:hover
{
	background: linear-gradient(var(--color-surface), var(--color-surface)) padding-box, conic-gradient(from var(--gradient-angle, 0deg), var(--gradient-colors), #20cfd5) border-box;
}

.contact-links strong
{
	display: block;
	color: var(--color-text);
}


/*
Footer.
*/
.site-footer
{
	padding-block: 2rem;
	border-top: 1px solid var(--color-border);
	color: var(--color-text-muted);
	font-size: 0.85rem;
	text-align: center;
}

.site-footer p
{
	margin: 0;
}

.site-footer a
{
	color: inherit;
	text-decoration-line: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
}

.site-footer a:hover
{
	color: var(--color-text);
}


/*
Phones. These rules only apply to narrow screens, and leave larger screens as they are.
*/
@media (max-width: 42rem)
{
	/* The link in a section's header gets its own row below the title, which leaves the line next to the title its full length. */
	.section-header
	{
		flex-wrap: wrap;
		row-gap: 0;
	}

	.section-header-link
	{
		flex-basis: 100%;
	}

	/* Links are made taller than their text, so that they are easier to hit with a finger. */
	.section-header-link,
	.back-link
	{
		padding-block: 0.75rem;
	}

	.back-link
	{
		margin-bottom: 0.5rem;
	}

	.talk-card-links
	{
		flex-direction: column;
		gap: 0;
		margin-top: 0.4rem;
	}

	.talk-card-links a,
	.project-links a
	{
		display: inline-block;
		padding-block: 0.7rem;
	}

	.project-links .project-links
	{
		margin-block: 0;
	}

	/* The most important projects get the full width, instead of sharing a row. */
	.portfolio-grid-featured
	{
		grid-template-columns: minmax(0, 1fr);
	}

	.portfolio-grid-featured .portfolio-card-caption h4
	{
		font-size: 1.2rem;
	}

	/* The facts and links of a project are shown before its description, instead of after it. */
	.project-data
	{
		order: -1;
	}
}
