/*
 * Scrapbook / handwritten zine.
 *
 * Ruled paper, typewriter ink, and note cards stuck down with tape at a slight
 * angle. Every card, every strip of tape and every handwritten aside is CSS:
 * a background gradient, a rotated box, a pseudo-element. No images, no script.
 *
 * The markup underneath is the same semantic HTML every other document theme
 * renders. This theme leans harder on `content:` than the others, because a
 * zine's voice is part of its design - the ticks on the nav sticker, the aside
 * beside the CV heading, the notes in the margin. All of it is decoration laid
 * over prose that reads perfectly well without it.
 *
 * Plain CSS, served straight from public/. No build step. Edit and reload.
 */

@font-face {
	font-family: "Caveat";
	font-style: normal;
	/* One variable file covers the whole range the handwriting needs. */
	font-weight: 400 700;
	font-display: swap;
	src: url("/assets/fonts/caveat.woff2") format("woff2");
}

@font-face {
	font-family: "Special Elite";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("/assets/fonts/special-elite.woff2") format("woff2");
}

:root {
	--paper: #f5efe2;
	--card: #fff;
	--ink: #2e2a24;

	/*
    * The annotation colours are the designer's hues, darkened until each one
    * clears WCAG AA (4.5:1) against the paper. The originals - #b05070,
    * #4a7ab0, #6ba05a, #b09a4a and a #8a8274 for faded text - measured between
    * 2.42:1 and 4.34:1, so green and gold in particular were unreadable as
    * handwriting rather than merely pale. Hue is unchanged; only lightness.
    */
	--faded: #726c60;
	/* was #8a8274, 3.32:1 -> 4.55:1 */
	--pink: #ac4e6d;
	/* was #b05070, 4.34:1 -> 4.51:1 */
	--blue: #4470a0;
	/* was #4a7ab0, 3.90:1 -> 4.50:1 */
	--green: #507743;
	/* was #6ba05a, 2.69:1 -> 4.51:1 */
	--gold: #7b6c34;
	/* was #b09a4a, 2.42:1 -> 4.54:1 */

	--sticker-pink: #ffd9e8;
	--sticker-blue: #d9f0ff;
	--sticker-green: #e3ffd9;
	--sticker-yellow: #fff3c4;
	--sticker-purple: #eadcff;

	--tape: rgb(255 244 180 / 0.7);
	--card-shadow: 2px 3px 6px rgb(0 0 0 / 0.12);

	--hand: "Caveat", cursive;
	--typed: "Special Elite", "Courier New", monospace;

	--measure: 58ch;
}

/* ==========================================================================
   Paper
   ========================================================================== */

html {
	background-color: var(--paper);
	/* The faint blue rule of a notebook, every 28px. */
	background-image: repeating-linear-gradient(
		0deg,
		transparent 0 27px,
		rgb(120 140 180 / 0.18) 27px 28px
	);
	color: var(--ink);
	font-family: var(--typed);
	font-size: 19px;
	line-height: 1.55;
}

body {
	/* Transparent on purpose: the ruled lines belong to the page behind it. */
	margin: 0 auto;
	padding: 24px 20px 40px;
	max-width: var(--measure);
}

hr {
	display: none;
}

/* ==========================================================================
   Navigation, as stickers
   Five pastels and five angles, cycling, so no two neighbours match.
   ========================================================================== */

body > header {
	margin-bottom: 26px;
}

nav ul {
	display: flex;
	flex-wrap: wrap;
	gap: 10px 12px;
	list-style: none;
	margin: 0;
	padding: 0;
}

nav li {
	font-family: var(--hand);
	font-size: 22px;
	line-height: 1.2;
	padding: 2px 12px;
	text-transform: lowercase;
	box-shadow: 1px 2px 3px rgb(0 0 0 / 0.15);
}

nav li:nth-child(5n + 1) {
	background: var(--sticker-pink);
	transform: rotate(-3deg);
}

nav li:nth-child(5n + 2) {
	background: var(--sticker-blue);
	transform: rotate(2deg);
}

nav li:nth-child(5n + 3) {
	background: var(--sticker-green);
	transform: rotate(-1.5deg);
}

nav li:nth-child(5n + 4) {
	background: var(--sticker-yellow);
	transform: rotate(3deg);
}

nav li:nth-child(5n + 5) {
	background: var(--sticker-purple);
	transform: rotate(-2deg);
}

nav a {
	color: var(--ink);
	text-decoration: none;
}

nav a:hover,
nav a:focus-visible {
	text-decoration: underline wavy var(--pink);
	text-underline-offset: 3px;
}

nav strong {
	font-weight: 700;
}

nav strong::after {
	content: " ✓";
}

/* ==========================================================================
   Handwriting
   ========================================================================== */

h1 {
	font-family: var(--hand);
	font-weight: 400;
	font-size: 59px;
	line-height: 1.05;
	margin: 6px 0 4px;
	transform: rotate(-1.5deg);
	transform-origin: left center;
}

h2 {
	font-family: var(--hand);
	font-weight: 400;
	font-size: 30.5px;
	text-transform: lowercase;
	margin: 26px 0 8px;
}

h3 {
	font-family: var(--typed);
	font-size: 17.5px;
	font-weight: 700;
	margin: 0;
}

/* A write-up brings its own headings: `#` renders as h3 and `##` as h4. Left
   to the browser an h4 comes out bigger and bolder than this theme's h3, which
   puts a subsection above the section it belongs to. */
.write-up h3 {
	font-family: var(--hand);
	font-weight: 400;
	font-size: 27px;
	text-transform: lowercase;
	margin: 22px 0 2px;
}

.write-up h4 {
	font-family: var(--typed);
	font-size: 16.5px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	margin: 16px 0 0;
}

.write-up h5,
.write-up h6 {
	font-family: var(--typed);
	font-size: 15.5px;
	font-weight: 700;
	color: var(--faded);
	margin: 14px 0 0;
}

p {
	margin: 10px 0;
}

main > header p {
	font-size: 16.5px;
	margin: 0;
}

del {
	text-decoration-thickness: 2px;
	text-decoration-style: double;
}

small {
	font-size: 14px;
	color: var(--faded);
}

a {
	color: var(--ink);
	text-decoration: underline wavy var(--blue);
	text-underline-offset: 3px;
	text-decoration-skip-ink: none;
}

a:hover,
a:focus-visible {
	text-decoration-thickness: 2px;
}

abbr {
	text-decoration-color: var(--faded);
}

/* ==========================================================================
   Note cards
   A white card, a soft shadow, a slight angle, and a strip of tape holding it
   down. Everything that is a discrete piece of content gets one.
   ========================================================================== */

main > p,
.cv-section,
.project-list > li,
.album-group,
.photo,
details,
address {
	position: relative;
	background: var(--card);
	padding: 14px 16px;
	margin: 22px 0;
	box-shadow: var(--card-shadow);
}

/* The tape. Rotated the other way from its card, which is what stops the two
   angles reading as a single crooked object. */
main > p::before,
.cv-section::before,
.project-list > li::before,
.album-group::before,
.photo::before,
details::before,
address::before {
	content: "";
	position: absolute;
	top: -9px;
	left: 22px;
	width: 66px;
	height: 17px;
	background: var(--tape);
	box-shadow: 0 1px 2px rgb(0 0 0 / 0.08);
	transform: rotate(-3deg);
}

/* Alternating angles, so a column of cards looks stuck down by hand. */
main > p:nth-of-type(even),
.cv-section:nth-of-type(even),
.project-list > li:nth-child(even),
.photo:nth-child(even) {
	transform: rotate(0.7deg);
}

main > p:nth-of-type(odd),
.cv-section:nth-of-type(odd),
.project-list > li:nth-child(odd),
.photo:nth-child(odd) {
	transform: rotate(-0.5deg);
}

/* Tape parked somewhere different on every other card. */
.cv-section:nth-of-type(even)::before,
.project-list > li:nth-child(even)::before,
.photo:nth-child(even)::before {
	left: auto;
	right: 20px;
	transform: rotate(2.5deg);
}

.cv-section:nth-of-type(3n)::before,
.project-list > li:nth-child(3n)::before {
	left: 50%;
	right: auto;
	margin-left: -33px;
	transform: rotate(-1.5deg);
}

/* ==========================================================================
   Home
   ========================================================================== */

.section-links {
	list-style: none;
	margin: 12px 0 22px;
	padding: 0;
}

.section-links li {
	font-size: 17.5px;
	padding: 3px 0 3px 18px;
	position: relative;
}

.section-links li::before {
	content: "·";
	position: absolute;
	left: 4px;
	font-family: var(--hand);
	font-size: 25.5px;
	color: var(--faded);
}

/* The wavy underline changes colour down the list, the way a pen would run out
   and get swapped for whatever was nearest. */
.section-links li:nth-child(4n + 1) a {
	text-decoration-color: var(--pink);
}

.section-links li:nth-child(4n + 2) a {
	text-decoration-color: var(--blue);
}

.section-links li:nth-child(4n + 3) a {
	text-decoration-color: var(--green);
}

.section-links li:nth-child(4n + 4) a {
	text-decoration-color: var(--gold);
}

summary {
	font-family: var(--hand);
	font-size: 25.5px;
	cursor: pointer;
}

kbd {
	font-family: var(--typed);
	font-weight: 700;
	border-bottom: 1px solid var(--faded);
}

/* ==========================================================================
   CV
   Each section is a card with a handwritten label: work, education,
   volunteering, in pink, green and gold.
   ========================================================================== */

.cv-section h2 {
	margin: 0 0 10px;
	font-size: 30.5px;
}

/*
 * Each glyph is followed by U+FE0E, the text variation selector, and asks for
 * the text form again through `font-variant-emoji`. Without them the system
 * serves the emoji form, which arrives in full colour and ignores the
 * handwriting colour it is meant to match. Both are advisory: a machine with no
 * text-presentation glyph for ✎ falls back to the colour one regardless, which
 * is what happens on a stock Linux font stack.
 */
.cv-section h2::after {
	font-variant-emoji: text;
}

.cv-section:nth-of-type(1) h2 {
	color: var(--pink);
}

.cv-section:nth-of-type(1) h2::after {
	content: " ✎\FE0E";
}

.cv-section:nth-of-type(2) h2 {
	color: var(--green);
}

.cv-section:nth-of-type(2) h2::after {
	content: " ✏\FE0E";
}

.cv-section:nth-of-type(3) h2 {
	color: var(--gold);
}

.cv-section:nth-of-type(3) h2::after {
	content: " ♥\FE0E";
}

.cv-entry {
	padding: 0;
}

.cv-entry + .cv-entry {
	margin-top: 16px;
	padding-top: 14px;
	border-top: 1px dashed rgb(46 42 36 / 0.2);
}

/* Direct children only: the description is markdown and brings its own. */
.cv-entry > p {
	margin: 1px 0 4px;
	font-size: 14px;
	color: var(--faded);
}

.cv-description {
	font-size: 16px;
	line-height: 1.55;
}

.cv-description > * {
	margin: 0 0 8px;
}

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

.cv-description ul {
	padding-left: 20px;
}

/* ==========================================================================
   Projects, albums, contact
   ========================================================================== */

.project-list,
.album-list,
.contact-list,
.social-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* The project's mark, stuck on the card like a sticker.

   The edge is drawn with stacked drop-shadows rather than a border: a border
   follows the box, and what a sticker's edge follows is the shape of the thing
   on it. Each shadow spreads the mark's own silhouette a little further in
   white, and the last one puts it slightly off the paper.

   Ten of them, and that number is the whole trick. Most of these marks are not
   one shape: two houses, an X above a wordmark, a paw of separate toes. At the
   three shadows this started with, the white stopped before the gaps closed,
   so every piece got cut out on its own and the last shadow fell under each
   one separately, and the card wore four small stickers instead of one. Enough
   spread and the pieces' edges meet, the silhouette becomes a single shape,
   and the one dark shadow underneath follows that shape's outline.

   So the floor is however much white it takes to bridge the widest gap in the
   set. A new mark with pieces further apart than these needs another pair. */
.project-logo {
	--shadow-color: 0deg 0% 63%;
	display: block;
	width: 84px;
	height: 84px;
	object-fit: contain;
	margin: 0 0 8px;
	padding: 15px;
	box-sizing: border-box;
	border-radius: 10px;
	rotate: -3deg;
	background-color: var(--card);
	box-shadow:
		0.1px 0.5px 0.6px hsl(var(--shadow-color) / 0.29),
		0.4px 1.3px 1.5px -0.6px hsl(var(--shadow-color) / 0.29),
		0.7px 2.6px 3px -1.2px hsl(var(--shadow-color) / 0.29),
		1.4px 5.3px 6.2px -1.9px hsl(var(--shadow-color) / 0.29),
		2.8px 10.2px 11.9px -2.5px hsl(var(--shadow-color) / 0.29);
}

/* Stuck on by hand, so no two land in the same spot. Five variations of
   angle and how far along the card the sticker sits, which is enough that a
   column of them never repeats visibly. */
.project-list > li:nth-child(5n + 2) .project-logo {
	rotate: 2.5deg;
	margin-left: 90px;
}

.project-list > li:nth-child(5n + 3) .project-logo {
	rotate: -1.5deg;
	margin-left: auto;
	margin-right: 24px;
}

.project-list > li:nth-child(5n + 4) .project-logo {
	rotate: 4deg;
	margin-left: 40px;
}

.project-list > li:nth-child(5n + 5) .project-logo {
	rotate: -5deg;
	margin-left: 150px;
}

.project-list > li {
	font-size: 16px;
}

/* The whole card opens the project. The name stays the only link in the
   page's structure: a pseudo-element stretched over the card takes the
   clicks, so a screen reader still hears one link per project. The card is
   already `position: relative` for its tape. */
.project-list > li a::after {
	content: "";
	position: absolute;
	inset: 0;
}

/* Picked up off the paper: straightened, lifted, and a deeper shadow, the way
   you would hold a card to read it. */
.project-list > li {
	transition:
		transform 120ms ease-out,
		box-shadow 120ms ease-out;
}

.project-list > li:hover,
.project-list > li:has(a:focus-visible) {
	transform: rotate(0deg) translateY(-3px);
	box-shadow: 3px 6px 12px rgb(0 0 0 / 0.18);
}

.project-list > li:has(a:focus-visible) {
	outline: 2px dashed var(--pink);
	outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
	.project-list > li {
		transition: none;
	}

	.project-list > li:hover,
	.project-list > li:has(a:focus-visible) {
		transform: none;
	}
}

/* The one that was chosen rather than the one that is newest: the card is a
   sheet of the same green the nav's projects label is written on, rather than
   the white every other card is. */
.project-list > li[data-featured] {
	background: var(--sticker-green);
	padding-bottom: 26px;
	box-shadow: 3px 5px 10px rgb(0 0 0 / 0.16);
}

.featured-flag {
	font-family: var(--hand);
	font-size: 19px;
	color: var(--pink);
	background: var(--sticker-yellow);
	padding: 0 8px;
	rotate: -2deg;
	display: inline-block;
}

.project-list > li a {
	font-family: var(--hand);
	font-size: 28px;
}

.album-list > li,
.contact-list > li,
.social-list > li {
	font-size: 16.5px;
	padding: 3px 0;
}

address {
	font-style: normal;
}

.album-group > summary {
	margin-bottom: 6px;
}

.project-facts {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: 2px 12px;
	margin: 12px 0;
	font-size: 16px;
}

.project-facts dt {
	font-family: var(--hand);
	font-size: 22px;
	color: var(--faded);
}

.project-facts dd {
	margin: 0;
}

/* ==========================================================================
   The skill filter
   Another card, taped down by the `details` rule above. The groups set in
   columns and each type name is written in a different pen, the way a list
   copied out by hand ends up when the first one runs dry.
   ========================================================================== */

.skill-filter[open] > summary {
	margin-bottom: 10px;
}

.skill-filter form {
	columns: 13rem;
	column-gap: 22px;
}

.skill-filter fieldset {
	/* A group is never split down the middle by a column break. */
	break-inside: avoid;
	display: inline-block;
	width: 100%;
	box-sizing: border-box;
	min-width: 0;
	border: 0;
	margin: 0 0 14px;
	padding: 0;
}

.skill-filter legend {
	display: block;
	width: 100%;
	border-bottom: 1px dashed rgb(46 42 36 / 0.25);
	padding: 0 0 3px;
	font-family: var(--hand);
	font-size: 24.5px;
	line-height: 1.1;
	text-transform: lowercase;
}

.skill-filter fieldset:nth-of-type(4n + 1) legend {
	color: var(--pink);
}

.skill-filter fieldset:nth-of-type(4n + 2) legend {
	color: var(--blue);
}

.skill-filter fieldset:nth-of-type(4n + 3) legend {
	color: var(--green);
}

.skill-filter fieldset:nth-of-type(4n + 4) legend {
	color: var(--gold);
}

.skill-filter ul {
	list-style: none;
	margin: 5px 0 0;
	padding: 0;
}

.skill-filter li {
	font-size: 16px;
	padding: 1px 0;
}

/*
 * A box drawn by hand: square corners, a slight tilt, and a tick scribbled
 * across it in pink. Every box is drawn the same way, so the list reads as one
 * pass of the same pen rather than as a pile of different boxes.
 *
 * The tick is a two-line path in a data URI rather than a pseudo-element,
 * because generated content on a form control is a browser-by-browser
 * question and this is not. It is a path written in this file, same as every
 * other mark in the theme - nothing is fetched.
 */
.skill-filter input[type="checkbox"] {
	appearance: none;
	width: 16px;
	height: 16px;
	margin: 0 6px 0 0;
	vertical-align: -3px;
	border: 1.5px solid var(--ink);
	border-radius: 0;
	background: var(--card);
	transform: rotate(-2deg);
	cursor: pointer;
}

.skill-filter input[type="checkbox"]:checked {
	/* Drawn past the edges of the box, the way a tick in a hurry is. */
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8.5 L6 12.5 L14 2.5' fill='none' stroke='%23ac4e6d' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-size: 18px 18px;
	background-position: center;
	background-repeat: no-repeat;
}

.skill-filter input[type="checkbox"]:hover {
	border-color: var(--pink);
}

.skill-filter input[type="checkbox"]:focus-visible {
	outline: 2px dashed var(--pink);
	outline-offset: 2px;
}

/*
 * `appearance: none` throws away the control the operating system would have
 * drawn, and in a forced-colours mode that is the only one guaranteed to be
 * visible. Asked for one, this hands the box back, tilt and all removed.
 */
@media (forced-colors: active) {
	.skill-filter input[type="checkbox"] {
		appearance: auto;
		transform: none;
	}
}

.skill-filter label {
	cursor: pointer;
}

.skill-filter form > p {
	column-span: all;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px 16px;
	border-top: 1px dashed rgb(46 42 36 / 0.2);
	margin: 4px 0 0;
	padding-top: 12px;
}

/* A sticker, like the nav, rather than a button: this theme has no chrome in
   it anywhere else and a default control would be the only square thing here. */
.skill-filter button {
	font-family: var(--hand);
	font-size: 24.5px;
	line-height: 1.2;
	color: var(--ink);
	background: var(--sticker-yellow);
	border: 0;
	padding: 3px 14px;
	box-shadow: 1px 2px 3px rgb(0 0 0 / 0.15);
	transform: rotate(-1.5deg);
	cursor: pointer;
}

.skill-filter button:hover,
.skill-filter button:focus-visible {
	background: var(--sticker-pink);
}

.skill-filter form > p a {
	font-family: var(--hand);
	font-size: 22px;
	color: var(--faded);
	text-decoration-color: var(--pink);
}

/* Nothing matched. `main > p` already tapes this to the page as a card, which
   is exactly what a note explaining an empty page should be here. */
.project-list-empty {
	font-family: var(--hand);
	font-size: 25.5px;
	line-height: 1.3;
	color: var(--pink);
}

/* ==========================================================================
   Photographs, as taped-in prints
   ========================================================================== */

/* Columns rather than a grid: prints of different heights stack up the page
   with no dead space under the short ones, which is how a page of a real
   scrapbook fills up. Images run down a column before moving across. */
.gallery {
	columns: 12rem;
	column-gap: 20px;
	list-style: none;
	margin: 26px 0;
	padding: 0;
}

.photo {
	/* A print has a wider lip along the bottom than the other three sides. */
	padding: 12px 12px 14px;
	/* No print may be split down the middle by a column break. */
	break-inside: avoid;
	display: inline-block;
	width: 100%;
	box-sizing: border-box;
	margin: 0 0 26px;
}

.photo figure {
	margin: 0;
}

.photo img {
	display: block;
	width: 100%;
	height: auto;
}

.photo figcaption {
	font-family: var(--hand);
	font-size: 20.5px;
	color: var(--faded);
	padding-top: 6px;
	line-height: 1.2;
}

/* ==========================================================================
   Write-ups
   ========================================================================== */

pre {
	background: rgb(46 42 36 / 0.04);
	border-left: 3px solid var(--faded);
	padding: 8px 12px;
	overflow-x: auto;
	font-size: 15.5px;
}

samp,
code {
	font-family: var(--typed);
}

/* ==========================================================================
   About
   The personal page, so the zine voice is loudest here: polaroids of the
   household, label stickers for the interests, and two cards of what the
   Plex server has been playing. Every photograph is a print with a wider lip
   along the bottom, the way `.photo` is, because that is what a photograph
   stuck in a scrapbook looks like.
   ========================================================================== */

[data-page="/about"] h1 {
	text-transform: lowercase;
}

[data-page="/about"] h1::after {
	content: " (hi!)";
	font-size: 28px;
	color: var(--pink);
}

/* A print: white border, wider at the bottom, and a tilt. The shared shape
   every photograph on this page takes; each use sets its own angle. */
.about-portrait,
.pet-list figure,
.couple-photo,
.interest-list figure,
.about-outro figure {
	position: relative;
	background: var(--card);
	padding: 8px 8px 24px;
	margin: 0;
	box-shadow: var(--card-shadow);
}

.about-portrait img,
.pet-list img,
.couple-photo img,
.interest-list img,
.about-outro img {
	display: block;
	width: 100%;
	height: auto;
}

.about-portrait figcaption,
.pet-list figcaption,
.couple-photo figcaption,
.interest-list figcaption,
.about-outro figcaption {
	font-family: var(--hand);
	font-size: 20.5px;
	line-height: 1.2;
	color: var(--faded);
	text-align: center;
	padding-top: 6px;
	/* Written on the lip, not below it. */
	margin-bottom: -18px;
}

/* -- Intro ----------------------------------------------------------------- */

/* The print down the left, the typed line and the handwritten list stacked
   beside it. A grid, because they are siblings and the markup is shared.

   The flags are in the markup between those two, and are lifted out of the
   grid onto the print; see below. */
.about-intro {
	/* The print's width, in one place: the column is cut to it, the figure is
      set to it, and the flags are hung off its right edge. */
	--print: 1fr;
	position: relative;
	display: grid;
	grid-template-columns: var(--print) 1fr;
	/* Two rows of text against a print that is taller than both. The empty
      third row takes the difference: without it the surplus is shared out
      between the rows that do have something in them, and the typed line and
      the handwritten list drift apart as the photograph gets taller. */
	grid-template-rows: auto auto 1fr;
	gap: 6px 22px;
	align-items: start;
	margin-top: 16px;
}

/* This theme places the line, the flags and the traits against the print
   itself, so the element around them steps out of the way. */
.about-text {
	display: contents;
}

.about-portrait {
	grid-row: 1 / -1;
	width: var(--print);
	box-sizing: border-box;
	transform: rotate(-2.5deg);
}

.about-portrait::before {
	content: "";
	position: absolute;
	top: -8px;
	left: 32%;
	width: 60px;
	height: 16px;
	background: var(--tape);
	box-shadow: 0 1px 2px rgb(0 0 0 / 0.1);
	transform: rotate(2deg);
}

.about-tagline {
	font-size: 16px;
	line-height: 1.6;
	margin: 0;
}

.about-tagline strong {
	font-weight: 400;
}

/* The traits, in a different pen: a handwritten list under the typed line,
   each one ticked off the way a list in a notebook is. */
.trait-list {
	list-style: none;
	margin: 4px 0 0;
	padding: 0;
	font-family: var(--hand);
	font-size: 24.5px;
	line-height: 1.3;
	color: var(--blue);
}

.trait-list li {
	position: relative;
	padding-left: 26px;
}

.trait-list li::before {
	content: "✓\FE0E";
	font-variant-emoji: text;
	position: absolute;
	left: 0;
}

/* Two flags, stuck on at a slight angle like everything else on the page. The
   card colour shows through as the border, so they read as stickers.

   Stuck on the print rather than floating in the column beside it, which is
   what a sticker on a scrapbook page does. They hang off its right edge in a
   pair, half on the photograph and half on the paper.

   Measured down from the top of the grid rather than up from the bottom, and
   that is on purpose: the print's height is whatever the portrait's proportions
   make it, and the grid's is the taller of the print and the column of text
   beside it, so neither is a number this can be hung from. The top edge is the
   one both of them share. It clears the tape, which sits at `32%` across. */
.about-flags {
	display: flex;
	gap: 10px;
	margin: 0;
}

.flag {
	width: 30px;
	height: 22px;
	background-color: var(--card);
	border: 3px solid white;
	border-radius: 3px;
	box-shadow: var(--card-shadow);
	background-origin: content-box;
	background-clip: content-box;
}

.trans-flag {
	transform: rotate(-3deg);
	background-image: linear-gradient(
		to bottom,
		#5bcefa 0 20%,
		#f5a9b8 20% 40%,
		#fff 40% 60%,
		#f5a9b8 60% 80%,
		#5bcefa 80%
	);
}

/* The Nordic cross, off-centre the way the real one is: the bands sit 6/22
   across and 6/16 down, so the arm to the left of the cross is the short one. */
.norway-flag {
	transform: rotate(2deg);
	background-image:
		linear-gradient(
			to bottom,
			transparent 43.75%,
			#00205b 43.75% 56.25%,
			transparent 56.25%
		),
		linear-gradient(
			to right,
			transparent 31.82%,
			#00205b 31.82% 40.91%,
			transparent 40.91%
		),
		linear-gradient(
			to bottom,
			transparent 37.5%,
			#fff 37.5% 62.5%,
			transparent 62.5%
		),
		linear-gradient(
			to right,
			transparent 27.27%,
			#fff 27.27% 45.45%,
			transparent 45.45%
		),
		linear-gradient(#ba0c2f, #ba0c2f);
}

/* -- Cards ----------------------------------------------------------------- */

/* The two Plex lists are note cards, taped down the same way a CV section is,
   each with a handwritten label in its own pen.

   Household is not one of them. Everything inside it is already a print with
   its own tape - the cats, the two of us - and a card carrying cards is a
   scrapbook page glued onto a scrapbook page. The photographs sit straight on
   the paper instead, which is where they would be. */
.plex-list {
	position: relative;
	background: var(--card);
	padding: 14px 16px;
	margin: 24px 0 0;
	box-shadow: var(--card-shadow);
}

.plex-list::before {
	content: "";
	position: absolute;
	top: -8px;
	left: 12px;
	width: 64px;
	height: 16px;
	box-shadow: 0 1px 2px rgb(0 0 0 / 0.08);
}

.household {
	margin: 24px 0 0;
}

.on-repeat {
	transform: rotate(-0.8deg);
}

.on-repeat::before {
	left: auto;
	right: 24px;
	background: rgb(255 220 235 / 0.7);
	transform: rotate(-3deg);
}

.most-watched {
	transform: rotate(0.9deg);
}

.most-watched::before {
	left: 40%;
	background: rgb(227 255 217 / 0.8);
	transform: rotate(2deg);
}

.household h2,
.plex-list h2 {
	margin: 0;
}

.household h2 {
	color: var(--pink);
}

.household h2::after {
	content: " ♥\FE0E";
	font-variant-emoji: text;
}

.on-repeat h2 {
	color: var(--blue);
}

.on-repeat h2::after {
	content: " ♪\FE0E";
	font-variant-emoji: text;
}

.most-watched h2 {
	color: var(--gold);
}

.household > p,
.plex-list ol {
	font-size: 16px;
	line-height: 1.55;
	margin: 6px 0 0;
}

/* -- Household ------------------------------------------------------------- */

/* Three prints across the page, sharing the width between them. They used to
   be flex items fixed at 160px that never grew, so the row stopped short and
   left a strip of empty paper on the right. */
.pet-list {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
	gap: 18px 22px;
	list-style: none;
	margin: 14px 0 18px;
	padding: 0 6px;
}

.pet-list li:nth-child(odd) figure {
	transform: rotate(-2deg);
}

.pet-list li:nth-child(even) figure {
	transform: rotate(1.5deg);
}

.pet-list figcaption strong {
	font-weight: 700;
	color: var(--ink);
}

.couple-photo {
	transform: rotate(-1.2deg);
	margin: 4px 2px 8px;
	border: 1px solid rgb(0 0 0 / 0.08);
}

.couple-photo .picture {
	position: relative;
	display: block;
}

/*
 * The sticker. The face under it is already gone from the file - a black
 * block - so this covers the block with something nicer, not something
 * necessary. A flower in the sticker pink, drawn in a data URI like the
 * filter's tick, with a solid centre so nothing shows through, and a note in
 * the margin pointing at it.
 */
.face-sticker {
	/* Where the sticker sits is set per photograph in the Studio and arrives as
      custom properties on the element; the values here are the fallback for a
      photograph that has none. Swapping the photograph is then a swap, not a
      stylesheet edit. */
	position: absolute;
	left: var(--face-x, 53%);
	top: var(--face-y, 4%);
	width: var(--face-size, 34%);
	/* Square, so the flower is a flower rather than an oval stretched to fit a
      face-shaped box. */
	aspect-ratio: 1;
	background-image: url("/stickers/heart.svg");
	background-size: contain;
	background-position: center;
	background-repeat: no-repeat;
	filter: drop-shadow(1px 2px 2px rgb(0 0 0 / 0.3));
	rotate: 8deg;
}

/* The note under the sticker. It used to be pinned to the right of it and set
   `nowrap`, which ran it off the edge of the photograph and cut it in half.

   No arrow on it: the label is centred under a sticker that is not centred on
   the photograph, so an arrow at the start of the text pointed at whatever
   happened to be above the first word rather than at the sticker. */
.face-sticker::after {
	content: "imagine a beautiful face here";
	position: absolute;
	left: 50%;
	top: 104%;
	translate: -50% 0;
	width: max-content;
	max-width: 40vw;
	font-family: var(--hand);
	font-size: 22px;
	line-height: 1.1;
	text-align: center;
	color: var(--pink);
	background: rgb(255 255 255 / 0.85);
	padding: 1px 8px;
	rotate: -5deg;
}

/* -- Plex ------------------------------------------------------------------ */

.plex-blurb {
	margin: 0;
	font-family: var(--hand);
	font-size: 19px;
	line-height: 1.2;
}

.plex-blurb small {
	font-family: inherit;
	font-size: inherit;
	color: var(--faded);
}

.plex-list ol {
	padding-left: 22px;
	line-height: 1.9;
}

.plex-list li {
	padding-left: 2px;
}

.track,
.most-watched .title {
	font-weight: 400;
	text-decoration: underline wavy var(--blue);
	text-underline-offset: 3px;
}

/* The pen changes down the list, as it does on the home page. */
.plex-list li:nth-child(4n + 2) .track,
.plex-list li:nth-child(4n + 2) .title {
	text-decoration-color: var(--pink);
}

.plex-list li:nth-child(4n + 3) .track,
.plex-list li:nth-child(4n + 3) .title {
	text-decoration-color: var(--green);
}

.plex-list li:nth-child(4n + 4) .track,
.plex-list li:nth-child(4n + 4) .title {
	text-decoration-color: var(--gold);
}

.plex-list .artist::before {
	content: "- ";
}

.play-count {
	font-family: var(--hand);
	font-size: 19px;
	color: var(--faded);
	margin-left: 4px;
}

.play-count::before {
	content: "(";
}

.play-count::after {
	content: ")";
}

.plex-empty,
.plex-note {
	font-family: var(--hand);
	font-size: 22px;
	line-height: 1.25;
	color: var(--faded);
	margin: 8px 0 0;
}

/* -- Interests ------------------------------------------------------------- */

.interest-list h2 {
	transform: rotate(-1deg);
	transform-origin: left center;
}

.interest-list h2::after {
	content: "…";
}

/* Ordinary flow rather than a flex row, so the photograph can be floated to
   the side and the stickers can wrap around it. */
.interest-list ul {
	list-style: none;
	margin: 0;
	padding: 4px 0 0;
}

.interest-list::after {
	content: "";
	display: block;
	clear: both;
}

.interest-list li:has(figure) {
	float: right;
	width: 180px;
	margin: 0 0 12px 16px;
	box-shadow: none;
	background: none;
	padding: 0;
}

@media (max-width: 600px) {
	.interest-list li:has(figure) {
		float: none;
		width: 100%;
		margin: 0 0 12px;
	}
}

/* Label stickers, the same pastels and angles as the nav. */
.interest-list li {
	display: inline-block;
	vertical-align: top;
	margin: 0 10px 12px 0;
	font-family: var(--hand);
	font-size: 22px;
	line-height: 1.2;
	padding: 2px 12px;
	box-shadow: 1px 2px 3px rgb(0 0 0 / 0.15);
}

.interest-list li:nth-child(4n + 1) {
	background: var(--sticker-blue);
	transform: rotate(2deg);
}

.interest-list li:nth-child(4n + 2) {
	background: var(--sticker-green);
	transform: rotate(-2deg);
}

.interest-list li:nth-child(4n + 3) {
	background: var(--sticker-pink);
	transform: rotate(1deg);
}

.interest-list li:nth-child(4n + 4) {
	background: var(--sticker-yellow);
	transform: rotate(-3deg);
}

/* An interest with a photograph is a print instead, its label on the lip. */
.interest-list li:has(figure) {
	background: none;
	box-shadow: none;
	padding: 0;
	width: 170px;
}

.interest-list figure {
	padding: 6px 6px 22px;
}

.interest-list figcaption {
	color: var(--ink);
}

/* -- On the side ----------------------------------------------------------- */

.side-quests {
	margin-top: 22px;
	font-size: 16px;
	line-height: 1.6;
}

.side-quests h2 {
	display: inline;
	font-size: 22px;
	color: var(--faded);
	margin: 0;
}

/* The heading runs straight into the list as one sentence. It used to say
   "on the side" and needed ", I run:" to make sense of what followed; the
   heading says that itself now, so all it needs is the colon. */
.side-quests h2::after {
	content: ": ";
}

.side-quests ul {
	display: inline;
	list-style: none;
	margin: 0;
	padding: 0;
}

.side-quests li {
	display: inline;
}

/* Non-breaking spaces: the word is an inline block, so its own would collapse.
   The space after the first escape ends it, since "a" is a hex digit too. */
.side-quests li:not(:last-child)::after {
	content: "\00a0 and\00a0";
}

.side-quests li:last-child::after {
	content: ".";
}

/* Only the ones that go somewhere are underlined. A wavy line under a name
   with no link behind it reads as a link that has broken, which is worse than
   a plain name. */
.side-quests li:has(a) {
	text-decoration: underline wavy var(--pink);
	text-underline-offset: 3px;
}

.side-quests li::after {
	text-decoration: none;
	display: inline-block;
}

.side-quests li:nth-child(even):has(a) {
	text-decoration-color: var(--blue);
}

.side-quests a {
	text-decoration: none;
}

/* -- Outro ----------------------------------------------------------------- */

.about-outro {
	display: flex;
	justify-content: center;
	margin: 30px 0 10px;
}

.about-outro figure {
	width: 150px;
	transform: rotate(2deg);
}

.about-outro figure::before {
	content: "";
	position: absolute;
	top: -8px;
	left: 30%;
	width: 60px;
	height: 16px;
	background: var(--tape);
	transform: rotate(-3deg);
}

.about-outro figcaption {
	color: var(--pink);
}

@media (max-width: 600px) {
	.about-intro {
		grid-template-columns: 1fr;
		grid-template-rows: auto;
	}

	.about-portrait {
		grid-row: auto;
	}

	.face-sticker::after {
		font-size: 19px;
	}
}

/* ==========================================================================
   Footer
   ========================================================================== */

footer {
	display: flex;
	flex-wrap: wrap;
	gap: 0 6px;
	margin-top: 34px;
	font-family: var(--hand);
	font-size: 20.5px;
	color: var(--faded);
	transform: rotate(1deg);
}

footer p {
	margin: 2px 0;
}

footer small {
	font-family: var(--hand);
	font-size: 20.5px;
	color: var(--faded);
}

footer p + p::before {
	content: "· ";
}

footer a {
	color: var(--faded);
	text-decoration-color: var(--gold);
}

/* On the paragraph rather than the link, so the wavy underline stops where the
   link does and this reads as an aside rather than as part of it. */
footer p:last-child::after {
	content: ", if you like ✂\FE0E";
}

/* The contents of a write-up. Depth as an indent, so the shape of the page
   shows before it is read. */
.toc ol {
	list-style: none;
	margin: 6px 0 0;
	padding: 0;
}

.toc li[data-level="2"] {
	padding-left: 20px;
}

.toc li[data-level="3"] {
	padding-left: 40px;
}

/* ==========================================================================
   Potatoes
   The struck-out word in the title is a button, and a button drawn by the
   browser in the middle of a handwritten heading looks like a mistake. It
   gives up its chrome and keeps the hand it is written in.
   ========================================================================== */

.potato-trigger {
	font: inherit;
	color: inherit;
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
}

.potato-trigger del {
	text-decoration-color: var(--pink);
}

.potato-trigger:hover del,
.potato-trigger:focus-visible del {
	background: var(--sticker-yellow);
}

/* A card off the same pile as everything else on this paper, tape and all. */
.potato-popover {
	max-width: 46ch;
	background: var(--card);
	color: var(--ink);
	border: 0;
	padding: 22px 24px 18px;
	box-shadow: var(--card-shadow);
	rotate: -0.6deg;
}

.potato-popover::backdrop {
	background: rgb(46 42 36 / 0.45);
}

.potato-popover h2 {
	margin-top: 0;
}

.potato-forms-intro,
.potato-forms {
	font-family: var(--typed);
	font-size: 15.5px;
}

.potato-forms {
	margin: 0 0 16px;
	padding-left: 20px;
}

/* The print button and the popover's close button, as one of the same labels
   stuck on everything else. */
.potato-popover > button,
.print-button {
	font-family: var(--hand);
	font-size: 19px;
	background: var(--sticker-yellow, #fdf3b5);
	border: 0;
	padding: 3px 14px;
	box-shadow: 1px 2px 3px rgb(0 0 0 / 0.15);
	rotate: -1.5deg;
	cursor: pointer;
}

.cv-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
	margin: 12px 0 0;
}

/* The download link beside it is an anchor, so the wavy underline every link
   gets has to come off - a sticker with a line under it is just a link. */
.download-button {
	display: inline-block;
	text-decoration: none;
}

.download-button:hover,
.download-button:focus-visible {
	text-decoration: none;
}

.print-hint {
	font-family: var(--typed);
	font-size: 15.5px;
}

/* Built with, as a row of little labels with the mark stuck on the left. The
   brand colour tints the label rather than filling it, so a row of them still
   looks like paper rather than a toolbar. */
.skill-list {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 8px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.skill-list li {
	display: flex;
	align-items: center;
	gap: 6px;
	font-family: var(--typed);
	font-size: 14px;
	background: color-mix(in srgb, var(--brand, var(--ink)) 12%, #fff);
	border: 1px solid color-mix(in srgb, var(--brand, var(--ink)) 35%, #fff);
	padding: 1px 8px;
}

.skill-logo {
	width: 15px;
	height: 15px;
	object-fit: contain;
}

/* The socials keep their marks: a row of logos is the one place on this page
   that looks like the rest of the internet, and that is the joke. */
.social-list a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.social-logo {
	width: 18px;
	height: 18px;
	object-fit: contain;
}

/* ==========================================================================
   Carousel
   The screenshots on a project page, as a strip you push along with a finger,
   the way a stack of prints on a table works. Scroll snapping does it; the
   dots and arrows arrive on their own in browsers that have the carousel
   pseudo-elements.
   ========================================================================== */

.carousel {
	margin-bottom: 20px;
	display: flex;
	gap: 18px;
	list-style: none;
	margin: 14px 0 0;
	padding: 6px 6px 14px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	overscroll-behavior-x: contain;
	/* Dots above the strip rather than below it. Placed after, the group is
      not laid out inside the section that holds the strip and paints over
      whatever follows; before, it sits under the heading where it reads as
      part of the picture. */
	scroll-marker-group: before;
}

.carousel > li {
	flex: 0 0 88%;
	scroll-snap-align: center;
	background: var(--card);
	padding: 8px 8px 14px;
	box-shadow: var(--card-shadow);
}

.carousel > li:nth-child(even) {
	rotate: 0.6deg;
}

.carousel > li:nth-child(odd) {
	rotate: -0.5deg;
}

.carousel img {
	display: block;
	width: 100%;
	height: auto;
}

.carousel::scroll-marker-group {
	display: flex;
	justify-content: center;
	gap: 10px;
	padding: 8px 0 0;
}

.carousel > li::scroll-marker {
	content: "";
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: rgb(46 42 36 / 0.2);
}

.carousel > li::scroll-marker:target-current {
	background: var(--pink);
}

.carousel::scroll-button(*) {
	font-family: var(--hand);
	font-size: 22px;
	line-height: 1;
	border: 0;
	background: var(--sticker-yellow);
	color: var(--ink);
	padding: 2px 12px;
	box-shadow: 1px 2px 3px rgb(0 0 0 / 0.15);
	cursor: pointer;
}

.carousel::scroll-button(*):disabled {
	opacity: 0.4;
	cursor: default;
}

.carousel::scroll-button(left) {
	content: "back";
}

.carousel::scroll-button(right) {
	content: "next";
}

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

/* ==========================================================================
   Contact form
   A note to write on: ruled boxes, a handwritten label above each, and a
   sticker for a button.
   ========================================================================== */

.contact-form form {
	max-width: 44ch;
}

.contact-form p {
	margin: 12px 0;
}

.contact-form label {
	display: block;
	font-family: var(--hand);
	font-size: 20.5px;
	color: var(--blue);
	margin-bottom: 2px;
}

.contact-form input,
.contact-form textarea {
	font-family: var(--typed);
	font-size: 16px;
	width: 100%;
	box-sizing: border-box;
	color: var(--ink);
	background: var(--card);
	border: 0;
	border-bottom: 2px solid rgb(46 42 36 / 0.25);
	padding: 6px 8px;
	box-shadow: var(--card-shadow);
}

.contact-form textarea {
	resize: vertical;
}

.contact-form input:focus-visible,
.contact-form textarea:focus-visible {
	outline: 2px dashed var(--pink);
	outline-offset: 2px;
}

.contact-form button {
	font-family: var(--hand);
	font-size: 22px;
	color: var(--ink);
	background: var(--sticker-green);
	border: 0;
	padding: 3px 18px;
	box-shadow: 1px 2px 3px rgb(0 0 0 / 0.15);
	rotate: -1.5deg;
	cursor: pointer;
}

.form-outcome {
	font-family: var(--hand);
	font-size: 21px;
	color: var(--green);
	background: var(--sticker-green);
	display: inline-block;
	padding: 2px 12px;
	rotate: -0.8deg;
}

.form-outcome[data-tone="bad"] {
	color: var(--pink);
	background: var(--sticker-pink);
}

.form-trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* ==========================================================================
   Full-size viewer
   ========================================================================== */

/* Every photograph is a link to its own full-size file, which is the whole
   feature with no script: follow it and there is the big version. With
   `viewer.js` the click opens it in a dialog instead.

   An anchor is inline and the pictures inside these are laid out as blocks, so
   the box has to become one or the picture sits on a text baseline with a
   descender's worth of gap under it. The gallery caption's "see it full size"
   carries the same class and is a phrase in a sentence, which is what the
   `:has` keeps out of this. */
.full-size:has(img) {
	display: block;
	cursor: zoom-in;
}

/* The print, held up to the light: the same white card with the wide lower
   lip that every photograph on this page sits in, taped at the top like the
   rest of them, and big enough this time to actually look at.

   Straight, not tilted. The prints on the page are tilted because they are
   lying on paper at whatever angle they were stuck down; one held up on its
   own is being looked at, and looking at something crooked is a worse
   photograph rather than a more charming one. */
.image-viewer {
	position: relative;
	max-width: min(92vw, 1200px);
	max-height: 92vh;
	padding: 12px 12px 16px;
	border: 0;
	background: var(--card);
	box-shadow: var(--card-shadow);
	overflow: visible;
}

.image-viewer::backdrop {
	/* The colour of the paper, taken right down: a warm dark rather than a
      neutral one, so the page behind reads as dimmed rather than switched
      off. */
	background: rgb(46 42 36 / 0.78);
}

/* The same strip of tape as the prints on the page, over the top edge. */
.image-viewer::before {
	content: "";
	position: absolute;
	top: -9px;
	left: 50%;
	width: 82px;
	height: 18px;
	translate: -50% 0;
	rotate: -1.5deg;
	background: var(--tape);
	box-shadow: 0 1px 2px rgb(0 0 0 / 0.1);
}

.image-viewer-image {
	display: block;
	/* The lip below carries the button, so the picture is capped at the screen
      less the button, the padding and the tape above it. */
	max-width: 100%;
	max-height: calc(92vh - 72px);
	object-fit: contain;
}

/* Written on the lip, in the same pen as every caption on the page. */
.image-viewer-close {
	display: block;
	margin: 4px auto 0;
	padding: 0 6px;
	border: 0;
	background: none;
	color: var(--faded);
	font-family: var(--hand);
	font-size: 22px;
	line-height: 1.2;
	cursor: pointer;
}

.image-viewer-close:hover,
.image-viewer-close:focus-visible {
	color: var(--pink);
}

/*
 * Selected text, as a highlighter pen over the page. The same yellow the
 * stickers use, with the page's own ink on top.
 */
::selection {
	background: var(--sticker-yellow);
	color: var(--ink);
}
