/*
 * Y2K / Geocities.
 *
 * A personal homepage from 1999. Starfield, marquee, rainbow heading, buttons
 * with an outset bevel, an under-construction bar and a visitor counter that
 * has seen things.
 *
 * Everything is CSS, including the parts that look like extra markup. The
 * marquee is two pseudo-elements on `html`: one is the bar, the other is the
 * text sliding across it. The under-construction bar is a single box with two
 * background layers, one clipped to the content and one to the border. The
 * counter and the guestbook line are pseudo-elements on the footer. Nothing
 * here was added to the document, which is why the HTML theme is unaffected by
 * a theme this loud.
 *
 * Plain CSS, served straight from public/. No build step. Edit and reload.
 */

@font-face {
	font-family: "Comic Neue";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("/assets/fonts/comic-neue-400.woff2") format("woff2");
}

@font-face {
	font-family: "Comic Neue";
	font-style: normal;
	font-weight: 700;
	font-display: swap;
	src: url("/assets/fonts/comic-neue-700.woff2") format("woff2");
}

:root {
	--space: #000018;
	--text: #fff;
	--secondary: #ccf;

	--magenta: #f0f;
	--cyan: #0ff;
	--yellow: #ff0;
	--lime: #0f0;
	--red: #f00;

	/*
    * The marquee bar only. #ff00ff behind #ffff00 measures 2.92:1, which is
    * under AA for 14px bold, so the bar is deepened to 4.52:1. Every other
    * neon in this theme sits on near-black and clears AA by a mile, so this is
    * the one place the palette needed moving.
    */
	--marquee-bar: #c900c9;

	--comic: "Comic Neue", "Comic Sans MS", cursive;
	--measure: 60ch;
	--bar-height: 26px;
}

/* ==========================================================================
   Space
   ========================================================================== */

html {
	background-color: var(--space);
	background-image:
		radial-gradient(rgb(255 255 255 / 0.53) 1px, transparent 1.5px),
		radial-gradient(rgb(255 255 255 / 0.27) 1px, transparent 1.5px);
	background-size:
		90px 90px,
		50px 50px;
	background-position:
		0 0,
		25px 40px;
	color: var(--text);
	font-family: var(--comic);
	font-size: 18.5px;
	line-height: 1.5;
}

body {
	margin: 0 auto;
	/* Clear of the fixed marquee. */
	padding: calc(var(--bar-height) + 14px) 18px 30px;
	max-width: var(--measure);
	border: 4px ridge var(--magenta);
	min-height: 100vh;
}

/* The frame changes colour per page, the way a 1999 site would have had a
   different table border on every page because it was hand-edited. */
[data-page="/cv"] {
	border-color: var(--cyan);
}

[data-page="/projects"] {
	border-color: var(--lime);
}

[data-page="/photography"] {
	border-color: var(--yellow);
}

[data-page="/contact"] {
	border-color: var(--cyan);
}

hr {
	border: 0;
	border-top: 1px dashed var(--magenta);
	margin: 14px 0;
}

/* ==========================================================================
   The marquee
   Two pseudo-elements: `::before` is the bar, `::after` is the text crossing
   it. Both are fixed, so neither adds to the scrollable area and neither can
   produce a horizontal scrollbar while the text is off-screen.
   ========================================================================== */

html::before {
	content: "";
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	height: var(--bar-height);
	background: var(--marquee-bar);
	z-index: 100;
}

html::after {
	content: "★·.·´¯`·.·★ WeLcOmE tO iSaK's HoMePaGe!!! ★ sign my guestbook!!! ★";
	position: fixed;
	top: 0;
	left: 0;
	height: var(--bar-height);
	line-height: var(--bar-height);
	white-space: nowrap;
	color: var(--yellow);
	font-weight: 700;
	font-size: 17px;
	z-index: 101;
	animation: marq 9s linear infinite;
}

/* ==========================================================================
   Navigation, as buttons
   ========================================================================== */

nav ul {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 8px;
	list-style: none;
	margin: 0;
	padding: 0;
}

nav a,
nav strong {
	display: inline-block;
	background: #000;
	border: 2px outset #999;
	padding: 3px 8px;
	color: var(--lime);
	font-weight: 700;
	font-size: 16px;
	text-decoration: none;
}

nav a:hover,
nav a:focus-visible {
	background: var(--lime);
	color: #000;
}

nav strong {
	background: #00f;
	border-color: #99f;
	color: var(--yellow);
}

/* ==========================================================================
   Type
   ========================================================================== */

h1 {
	font-size: 42px;
	text-align: center;
	margin: 10px 0 4px;
	background-image: linear-gradient(90deg, #f0f, #ff0, #0ff, #0f0, #f0f);
	/*
    * Tiled rather than stretched. Clipped to the text, a gradient spanning the
    * whole block means a short heading like "CV" samples one slice of it and
    * comes out a single colour; at 260px it runs through the whole spectrum
    * whatever the heading says.
    */
	background-size: 260px 100%;
	background-repeat: repeat;
	-webkit-background-clip: text;
	background-clip: text;
	-webkit-text-fill-color: transparent;
	color: transparent;
	animation: rainbow 3s linear infinite;
}

[data-page="/cv"] h1 {
	font-size: 37px;
}

main > header p {
	text-align: center;
	color: var(--cyan);
	margin: 0 0 10px;
}

h2 {
	color: var(--yellow);
	font-size: 24.5px;
	text-shadow: 2px 2px 0 var(--magenta);
	margin: 18px 0 8px;
}

h3 {
	color: var(--lime);
	font-weight: 700;
	font-size: 18.5px;
	margin: 0;
}

/* The write-up's own headings. `#` is h3 and `##` is h4, and an unstyled h4
   outranks this theme's h3 on size, so the scale has to be stated. */
.write-up h3 {
	color: var(--yellow);
	font-size: 21px;
	text-shadow: 2px 2px 0 var(--magenta);
	margin: 18px 0 4px;
}

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

.write-up h5,
.write-up h6 {
	color: var(--cyan);
	font-size: 15px;
	font-weight: 700;
	margin: 12px 0 0;
}

p {
	margin: 8px 0;
	color: var(--secondary);
}

a {
	color: var(--cyan);
}

a:hover,
a:focus-visible {
	background: var(--cyan);
	color: var(--space);
}

small {
	color: #9ff;
	font-size: 13.5px;
}

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

kbd {
	background: #000;
	border: 2px outset #999;
	padding: 0 4px;
	color: var(--lime);
	font-weight: 700;
}

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

.section-links {
	list-style: none;
	margin: 8px 0 16px;
	padding: 0;
	text-align: center;
}

/* The obligatory blinking banner. One flash a second, which is well under the
   three-per-second WCAG ceiling, and switched off entirely below. */
[data-page="/"] .section-links::before {
	content: "★ NEW!! ★";
	display: block;
	color: var(--red);
	font-weight: 700;
	margin-bottom: 6px;
	animation: blink 1s step-end infinite;
}

.section-links li {
	margin: 3px 0;
	color: var(--secondary);
}

.section-links li a {
	font-weight: 700;
}

/*
 * The under-construction bar. One box, two background layers: the stripes fill
 * the border box and the black fills the content box, so the label sits on
 * black inside a striped frame without a second element to hold it.
 */
[data-page="/"] main::after {
	content: "🚧 ALWAYS UNDER CONSTRUCTION 🚧";
	display: block;
	margin: 16px auto 0;
	padding: 8px 14px;
	max-width: 24em;
	text-align: center;
	color: var(--yellow);
	font-weight: 700;
	font-size: 16px;
	border: 2px solid var(--yellow);
	background-image:
		linear-gradient(#000, #000),
		repeating-linear-gradient(45deg, #ff0 0 12px, #000 12px 24px);
	background-clip: content-box, border-box;
	background-origin: content-box, border-box;
	background-repeat: no-repeat, repeat;
}

details {
	border: 2px ridge var(--cyan);
	padding: 6px 10px;
	margin: 14px 0;
}

summary {
	color: var(--yellow);
	font-weight: 700;
	cursor: pointer;
}

/* ==========================================================================
   CV
   A box per section, each in its own accent, because restraint had not been
   invented yet.
   ========================================================================== */

.cv-section {
	border: 3px double;
	padding: 10px 14px;
	margin: 16px 0;
}

.cv-section h2 {
	margin: 0 0 8px;
	font-size: 22px;
}

.cv-section:nth-of-type(1) {
	border-color: var(--magenta);
	background: #1a0033;
}

.cv-section:nth-of-type(1) h2 {
	text-shadow: 2px 2px 0 var(--magenta);
}

.cv-section:nth-of-type(1) h2::before {
	content: "💼 ";
}

.cv-section:nth-of-type(2) {
	border-color: var(--cyan);
	background: #001a33;
}

.cv-section:nth-of-type(2) h2 {
	text-shadow: 2px 2px 0 #06c;
}

.cv-section:nth-of-type(2) h2::before {
	content: "🎓 ";
}

.cv-section:nth-of-type(3) {
	border-color: var(--yellow);
	background: #1a1a00;
}

.cv-section:nth-of-type(3) h2 {
	text-shadow: 2px 2px 0 #a60;
}

.cv-section:nth-of-type(3) h2::before {
	content: "💖 ";
}

.cv-entry + .cv-entry {
	margin-top: 12px;
	padding-top: 10px;
	border-top: 1px dashed rgb(255 255 255 / 0.25);
}

/* Direct children only: the description is markdown and brings its own. */
.cv-entry > p {
	margin: 2px 0 4px;
	color: #9ff;
	font-size: 13.5px;
}

.cv-description {
	color: var(--secondary);
	font-size: 15.5px;
}

.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: 10px 0;
	padding: 0;
}

/* The project's mark, in a tile of its own: beveled, and floated into the
   corner of the panel so the words wrap around it the way text wrapped around
   everything in 1999.

   The tile is light because the marks are. Most of them are drawn for a white
   page and several are near-black themselves, and on the black this tile used
   to be those went from a logo to an empty square. Pale lavender rather than
   plain white: it is the colour the rest of the theme's quiet text is already
   in, and a white square is a hole punched in a near-black page. */
.project-logo {
	float: left;
	width: 64px;
	height: 64px;
	object-fit: contain;
	margin: 0 12px 8px 0;
	padding: 6px;
	box-sizing: border-box;
	background: #e9e9f2;
	border: 2px outset #fff;
}

/* The panel has to close over the float, or the next project starts beside
   this one's mark. */
.project-list > li::after {
	content: "";
	display: block;
	clear: both;
}

@media (max-width: 600px) {
	.project-logo {
		float: none;
		margin: 0 0 8px;
	}

	/* The mark is a block at this width, so the summary starts below it and a
      floated badge would ride down the card with it, half way between the mark
      and the name. Pinned to the corner instead, which is empty here whichever
      way the mark is drawn.

      Out of the flow it cannot be wrapped around, so the panel is opened up by
      the badge's own height and the badge sits in that strip on its own. */
	.project-list > li[data-featured] {
		padding-top: 28px;
	}

	.featured-flag {
		position: absolute;
		top: 6px;
		right: 6px;
		float: none;
		margin: 0;
	}
}

.project-list > li {
	border: 2px ridge var(--magenta);
	padding: 8px 12px;
	margin: 10px 0;
	font-size: 16px;
}

.project-list > li a {
	font-size: 19.5px;
	font-weight: 700;
	color: var(--lime);
}

/* The whole panel opens the project, with the name still the only link in the
   page's structure. */
.project-list > li {
	position: relative;
}

.project-list > li a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.project-list > li:hover,
.project-list > li:has(a:focus-visible) {
	border-color: var(--cyan);
	background: #12002a;
}

.project-list > li:hover a,
.project-list > li:has(a:focus-visible) a {
	color: var(--yellow);
	text-shadow: 0 0 6px var(--magenta);
}

/* Featured: the panel every other one is quieter than. */
.project-list > li[data-featured] {
	border: 3px ridge var(--yellow);
	background: #1a1a00;
}

/* Up in the corner the border makes, rather than sitting on the title's
   baseline a padding's width inside it. The negative margins are the panel's
   own padding, cancelled: `8px 12px` on `.project-list > li`, so change one
   and change the other.

   Still a float, deliberately. Taken out of the flow it would be the same
   badge in the same place until a project name grew long enough to slide
   underneath it; floated, the summary's lines wrap around it and no name can.
   Nothing has to be reserved for it, either, so the description keeps the full
   width of the panel on every line below the badge. */
.featured-flag {
	float: right;
	margin: -8px -12px 6px 8px;
	font-size: 13.5px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--space);
	background: var(--yellow);
	padding: 1px 6px;
}

.album-list > li,
.contact-list > li,
.social-list > li {
	padding: 2px 0 2px 18px;
	position: relative;
	font-size: 16.5px;
}

.album-list > li::before,
.contact-list > li::before,
.social-list > li::before {
	content: "►";
	position: absolute;
	left: 0;
	color: var(--magenta);
	font-size: 13.5px;
}

address {
	font-style: normal;
}

.album-group {
	border: 2px ridge var(--yellow);
	padding: 6px 12px;
	margin: 12px 0;
}

.project-facts {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: 2px 12px;
	border: 2px ridge var(--cyan);
	padding: 8px 12px;
	margin: 12px 0;
	font-size: 16px;
}

.project-facts dt {
	color: var(--yellow);
	font-weight: 700;
}

.project-facts dd {
	margin: 0;
	color: var(--secondary);
}

/* ==========================================================================
   The skill filter
   A ridge box per group in a different neon, set in columns. A form in 1999 was
   a table of bordered cells and every cell was a different colour, so this is
   the one place in the theme where the markup was already shaped like the
   design.
   ========================================================================== */

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

.skill-filter form {
	columns: 12rem;
	column-gap: 14px;
}

.skill-filter fieldset {
	/* A box 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: 2px ridge var(--magenta);
	background: #000;
	margin: 0 0 12px;
	padding: 2px 10px 8px;
}

.skill-filter legend {
	padding: 0 6px;
	color: var(--magenta);
	font-weight: 700;
	font-size: 16px;
}

/* Five neons, cycling, so no two groups down a column match. Every one of them
   clears AA against the black the boxes are filled with. */
.skill-filter fieldset:nth-of-type(5n + 2) {
	border-color: var(--cyan);
}

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

.skill-filter fieldset:nth-of-type(5n + 3) {
	border-color: var(--yellow);
}

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

.skill-filter fieldset:nth-of-type(5n + 4) {
	border-color: var(--lime);
}

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

.skill-filter fieldset:nth-of-type(5n + 5) {
	border-color: var(--red);
}

.skill-filter fieldset:nth-of-type(5n + 5) legend {
	color: #f66;
}

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

.skill-filter li {
	font-size: 16px;
	color: var(--secondary);
	padding: 1px 0;
}

/*
 * A checkbox with the same inset bevel every control on a 1999 page had, and a
 * lime tick that could only be from a screenshot of one.
 *
 * 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. Nothing is fetched: the path is written here.
 */
.skill-filter input[type="checkbox"] {
	appearance: none;
	width: 16px;
	height: 16px;
	margin: 0 6px 0 0;
	vertical-align: -3px;
	background: #000;
	border: 2px inset #999;
	cursor: pointer;
}

.skill-filter input[type="checkbox"]:checked {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5 L6.5 12 L13 3.5' fill='none' stroke='%2300ff00' stroke-width='2.5' stroke-linecap='square'/%3E%3C/svg%3E");
	background-size: 14px 14px;
	background-position: center;
	background-repeat: no-repeat;
}

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

.skill-filter input[type="checkbox"]:focus-visible {
	outline: 2px solid var(--yellow);
	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.
 */
@media (forced-colors: active) {
	.skill-filter input[type="checkbox"] {
		appearance: auto;
	}
}

.skill-filter label {
	cursor: pointer;
}

.skill-filter form > p {
	column-span: all;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 8px 16px;
	margin: 2px 0 0;
	padding-top: 10px;
	border-top: 1px dashed var(--magenta);
}

/* The same bevel the nav buttons have, including the press. */
.skill-filter button {
	background: #000;
	border: 2px outset #999;
	padding: 4px 14px;
	color: var(--lime);
	font-family: inherit;
	font-weight: 700;
	font-size: 16px;
	cursor: pointer;
}

.skill-filter button:hover,
.skill-filter button:focus-visible {
	background: var(--lime);
	color: #000;
}

.skill-filter button:active {
	border-style: inset;
}

.skill-filter form > p a {
	font-weight: 700;
	font-size: 16px;
}

/* Nothing matched. A boxed notice rather than a line of prose, because this
   theme puts a border around anything it wants read. */
.project-list-empty {
	border: 2px ridge var(--yellow);
	background: #1a1a00;
	margin: 14px 0;
	padding: 10px 14px;
	color: var(--yellow);
	font-weight: 700;
	text-align: center;
}

/* ==========================================================================
   Photographs
   ========================================================================== */

/* Columns rather than a grid, so the framed thumbnails tile up the page with
   no gaps under the short ones. They read down a column, then across. */
.gallery {
	columns: 12rem;
	column-gap: 14px;
	list-style: none;
	margin: 16px 0;
	padding: 0;
}

.photo {
	/* A frame stays whole rather than splitting across a column break. */
	break-inside: avoid;
	display: inline-block;
	width: 100%;
	box-sizing: border-box;
	margin: 0 0 14px;
	border: 3px ridge var(--cyan);
	padding: 6px;
	background: #000;
}

.photo figure {
	margin: 0;
}

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

.photo figcaption {
	color: #9ff;
	font-size: 13.5px;
	padding-top: 4px;
}

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

pre {
	background: #000;
	border: 2px ridge var(--lime);
	padding: 8px 12px;
	overflow-x: auto;
	color: var(--lime);
	font-size: 15px;
}

/* ==========================================================================
   Footer
   The counter and the guestbook line are the footer's own pseudo-elements, and
   the sparkles belong to the copyright paragraph.
   ========================================================================== */

footer {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	/* No rule of its own: this theme keeps the document's `hr`, and that already
      draws a dashed magenta line immediately above the footer. */
	margin-top: 6px;
}

footer p {
	margin: 2px 0;
	color: var(--secondary);
}

footer small {
	color: var(--secondary);
	font-size: 16px;
}

footer p:first-of-type::before {
	content: "✦ ";
	color: var(--yellow);
	animation: sparkle 1.4s infinite;
}

footer p:first-of-type::after {
	content: " ✦";
	color: var(--yellow);
	animation: sparkle 1.4s 0.7s infinite;
}

[data-page="/"] footer::before {
	content: "You are visitor № 0042069";
	order: -1;
	margin-bottom: 8px;
	padding: 2px 8px;
	background: #000;
	border: 1px solid var(--lime);
	color: var(--lime);
	font-family: monospace;
	font-size: 16px;
}

[data-page="/"] footer::after {
	content: "✍ Sign my Guestbook! · Webring: ◄ prev  next ►";
	margin-top: 6px;
	color: var(--cyan);
	font-size: 16px;
}

/* ==========================================================================
   About
   The design's "AbOuT mE!!" page. A box per section in alternating neons, like
   the CV, plus a second marquee at the top of the page and a glitter sticker
   over the one face that is not for publishing. Every word that is not in the
   markup is in a `content` string below.
   ========================================================================== */

[data-page="/about"] {
	border-color: var(--lime);
}

/*
 * A marquee of its own, inside the page rather than fixed above it. One
 * pseudo-element is the bar and the text both: the text slides by animating
 * `text-indent`, which is relative to the bar's own width, so it never leaves
 * the box and never needs a second element to clip it.
 */
[data-page="/about"] main::before {
	content: "★ aLl AbOuT mEeEe!!! ★ 100% certified potato ★ pls pet my cats ★";
	display: block;
	overflow: hidden;
	white-space: nowrap;
	margin: 0 0 6px;
	padding: 3px 0;
	background: var(--lime);
	color: #000;
	font-weight: 700;
	font-size: 17px;
	animation: marq-indent 9s linear infinite;
}

[data-page="/about"] h1 {
	font-size: 37px;
}

[data-page="/about"] h1::after {
	content: " mE!!";
}

/* -- Intro: the portrait and the one-liner ------------------------------ */

/* The portrait down the left, the tagline and the traits stacked beside it. */
.about-intro {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 0 16px;
	align-items: center;
	margin: 14px 0;
}

/* This theme places the line, the flags and the traits as rows of the grid
   beside the portrait, so the element around them steps out of the way. */
.about-text {
	display: contents;
}

/* Spans the three rows the text column now needs - the line, the flags and
   the traits. Counted rather than `1 / -1`, which resolves against the
   explicit grid and this one has no `grid-template-rows`. */
.about-portrait {
	grid-row: 1 / span 3;
	margin: 0;
	padding: 3px;
	background: #000;
	border: 3px outset var(--magenta);
}

.about-portrait img {
	display: block;
	width: 100%;
	height: auto;
}

.about-tagline {
	margin: 0;
	font-size: 17px;
}

.about-tagline strong {
	color: var(--lime);
}

.about-age {
	color: var(--yellow);
	font-weight: 700;
}

/* The traits stack, the way a profile's "likes" were bulleted down the side
   of the page rather than run together. */
.trait-list {
	list-style: none;
	margin: 6px 0 0;
	padding: 0;
	color: #9ff;
	font-size: 15px;
}

.trait-list li {
	position: relative;
	padding: 1px 0 1px 16px;
}

.trait-list li::before {
	content: "\2666";
	position: absolute;
	left: 0;
	color: var(--magenta);
	font-size: 12px;
}

.about-portrait figcaption {
	margin-top: 3px;
	color: var(--yellow);
	font-size: 12px;
	text-align: center;
}

/* Two flags, bevelled like every other chrome on the page. */
.about-flags {
	display: flex;
	gap: 6px;
	margin: 8px 0 0;
}

.flag {
	width: 26px;
	height: 19px;
	border: 2px outset var(--cyan);
}

.trans-flag {
	background: 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 {
	background:
		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%
		),
		#ba0c2f;
}

/* -- The boxes ---------------------------------------------------------- */

.household,
.plex-list,
.interest-list,
.side-quests,
.about-outro {
	border: 3px double;
	padding: 10px 14px;
	margin: 12px 0;
}

[data-page="/about"] main > section h2 {
	margin: 0 0 8px;
	font-size: 22px;
}

.household {
	border-color: var(--magenta);
	background: #1a0033;
}

.household h2 {
	text-shadow: 2px 2px 0 var(--magenta);
}

.household h2::before {
	content: "🏠 ";
}

.on-repeat {
	border-color: var(--cyan);
	background: #001a33;
}

.on-repeat h2 {
	text-shadow: 2px 2px 0 #06c;
}

.on-repeat h2::before {
	content: "🎧 ";
}

.most-watched {
	border-color: var(--yellow);
	background: #1a1a00;
}

.most-watched h2 {
	text-shadow: 2px 2px 0 #a00;
}

.most-watched h2::before {
	content: "📺 ";
}

.plex-list h2::after {
	content: " this month…";
}

.interest-list {
	border-color: var(--lime);
	background: #001a00;
}

.interest-list h2 {
	text-shadow: 2px 2px 0 #070;
}

.interest-list h2::before {
	content: "⭐ ";
}

.side-quests {
	border-color: var(--cyan);
	background: #001a33;
}

.side-quests h2 {
	text-shadow: 2px 2px 0 #06c;
}

.side-quests h2::before {
	content: "💼 ";
}

.about-outro {
	border-color: var(--magenta);
	background: #1a0033;
	text-align: center;
}

/* -- The household ------------------------------------------------------ */

.household p {
	margin: 0 0 8px;
	font-size: 15.5px;
}

/* Three across, filling the box. The cap of 150px on each is what used to
   leave a gap along the right-hand side of the frame. */
.pet-list {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
	align-items: start;
	gap: 12px;
	list-style: none;
	margin: 0 0 12px;
	padding: 0;
}

.pet-list li {
	font-size: 15.5px;
}

.pet-list figure {
	margin: 0;
}

.pet-list img {
	display: block;
	width: 100%;
	height: auto;
	padding: 3px;
	box-sizing: border-box;
	background: #000;
	border: 2px outset #999;
}

.pet-list figcaption {
	margin-top: 4px;
	color: #9ff;
}

.pet-list strong {
	color: var(--lime);
}

.couple-photo {
	margin: 0;
}

.couple-photo .picture {
	position: relative;
	display: block;
	border: 2px outset #99f;
}

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

.couple-photo figcaption {
	margin-top: 6px;
	text-align: center;
	color: #9ff;
	font-size: 13.5px;
}

/*
 * The glitter sticker. The face under it is already a black block in the
 * file, so this is the joke rather than the cover: an opaque tile of neon
 * glitter, slid across itself, with a sparkle on each shoulder and the
 * yellow label the design pins beside it. The percentages are measured
 * against the photograph, which is why `.picture` wraps the image alone.
 */
.face-sticker {
	/* Where the blocked-out patch actually is in the photograph, measured off
      the file rather than guessed: 58.9% across, 13.3% down, 23.3% wide. These
      are a little larger and a little further left and up, so the sticker
      covers the patch with a margin all round.

      Set the sticker position in the Studio to override all three; a new
      photograph needs new numbers, and that is the field to put them in. */
	position: absolute;
	left: var(--face-x, 55%);
	top: var(--face-y, 7%);
	/* Bigger than the patch, because this one is stuck on at an angle and a
      rotated square leaves a corner of the patch showing at its own size. */
	width: var(--face-size, 30%);
	/* Square, because the patch is: the box would otherwise be stretched by
      whatever shape the photograph happens to be. */
	aspect-ratio: 1;
	rotate: -4deg;
	border: 2px outset #f9f;
	background-color: var(--magenta);
	background-image:
		radial-gradient(circle, #fff 1.5px, transparent 2.5px),
		radial-gradient(circle, var(--yellow) 2px, transparent 3px),
		radial-gradient(circle, var(--cyan) 1.5px, transparent 2.5px),
		linear-gradient(135deg, var(--magenta), #c0c, var(--magenta));
	background-size:
		14px 14px,
		22px 22px,
		18px 18px,
		100% 100%;
	background-position:
		0 0,
		7px 9px,
		3px 15px,
		0 0;
	box-shadow: 2px 3px 0 #000;
	animation: glitter 1.2s steps(4) infinite;
}

.face-sticker::before,
.face-sticker::after {
	position: absolute;
	color: var(--yellow);
	/* Decoration, not reading matter: the sparkles sit outside the sticker by
      a fixed amount, so growing them with the body text pushes them off the
      side of a phone. */
	font-size: 22px;
	line-height: 1;
	text-shadow: 0 0 4px #000;
}

.face-sticker::before {
	content: "✦";
	top: -12px;
	left: -10px;
	animation: sparkle 1.4s infinite;
}

.face-sticker::after {
	content: "✦";
	right: -10px;
	bottom: -8px;
	animation: sparkle 1.4s 0.7s infinite;
}

/* The label, under the sticker rather than beside it, and following it across
   as well as down: centred on the photograph it sat under the face it is not
   talking about.

   It hangs from the sticker's right edge and grows leftwards, into the room
   the photograph has. Anchored the other way round, and set `nowrap`, it ran
   past the edge of the photograph and took the page with it: eight pixels of
   sideways scroll on a phone. Growing inwards it cannot, at any width, and
   the sticker's own numbers are the only ones it needs.

   No arrow on it either: pointing straight up from the first word of a
   centred label is pointing at nothing in particular. */
.couple-photo .picture::after {
	content: "imagine a beautiful face here";
	position: absolute;
	/* The gap from the photograph's right edge to the sticker's, so the two
      right edges line up. */
	right: calc(100% - var(--face-x, 55%) - var(--face-size, 30%));
	/* Under the sticker, wherever that has been put. The sticker is square, so
      its height as a share of the photograph is its width times the
      photograph's own ratio; 1.78 is the 16:9 these are shot in.

      The fallbacks match the sticker's own, or the label would drift off on
      its own the moment nothing was set in the Studio. */
	top: calc(var(--face-y, 7%) + var(--face-size, 30%) * 1.78 + 2%);
	max-width: 88%;
	padding: 2px 8px;
	background: var(--yellow);
	color: #000;
	font-weight: 700;
	font-size: 13.5px;
	text-align: center;
	rotate: 4deg;
	pointer-events: none;
}

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

.plex-blurb {
	margin: -4px 0 8px;
}

.plex-blurb small {
	color: #9ff;
	font-size: 13px;
}

.plex-list ol {
	list-style: none;
	counter-reset: plays;
	margin: 0;
	padding: 0;
	font-size: 15.5px;
}

.plex-list li {
	counter-increment: plays;
	margin: 5px 0;
	color: var(--secondary);
}

.on-repeat li::before {
	content: counter(plays) ". ";
	color: var(--magenta);
	font-weight: 700;
}

.most-watched li::before {
	content: "▶ ";
	color: var(--red);
	animation: blink 1s step-end infinite;
}

.track,
.most-watched .title {
	color: var(--lime);
}

.play-count {
	color: var(--cyan);
	font-size: 13.5px;
}

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

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

.plex-empty,
.plex-note {
	margin: 4px 0 0;
	color: #9ff;
	font-size: 15px;
}

/* -- Interests, as buttons ---------------------------------------------- */

/* Ordinary flow rather than a flex row: the photograph floats to the side and
   the buttons wrap around it. */
.interest-list ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

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

.interest-list li:has(figure) {
	float: right;
	width: 140px;
	margin: 0 0 8px 12px;
	background: none;
	border: 0;
	padding: 0;
}

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

.interest-list li {
	display: inline-block;
	vertical-align: top;
	margin: 0 6px 6px 0;
	background: #000;
	border: 2px outset #999;
	padding: 2px 8px;
	color: var(--lime);
	font-weight: 700;
	font-size: 15px;
}

.interest-list figure {
	margin: 0;
	width: 140px;
}

/* Cropped, so a phone portrait beside the buttons does not stretch the box
   down past the last of them. */
.interest-list figure img {
	aspect-ratio: 4 / 5;
	object-fit: cover;
}

.interest-list img {
	display: block;
	width: 100%;
	height: auto;
	margin: 4px 0;
	border: 2px outset #999;
	box-sizing: border-box;
}

.interest-list figcaption {
	text-align: center;
}

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

.side-quests ul {
	list-style: none;
	margin: 0;
	padding: 0;
	font-size: 15.5px;
}

.side-quests li {
	padding: 2px 0 2px 18px;
	position: relative;
	color: var(--lime);
	font-weight: 700;
}

.side-quests li::before {
	content: "►";
	position: absolute;
	left: 0;
	color: var(--magenta);
	font-size: 13.5px;
}

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

.about-outro figure {
	display: inline-block;
	margin: 0;
	width: 160px;
}

.about-outro img {
	display: block;
	width: 100%;
	height: auto;
	padding: 3px;
	box-sizing: border-box;
	background: #000;
	border: 3px outset var(--cyan);
}

.about-outro figcaption,
.about-outro p {
	margin: 8px 0 0;
	color: var(--magenta);
	font-size: 15px;
}

.about-outro figcaption::before,
.about-outro p::before {
	content: "✦ ";
	color: var(--yellow);
	display: inline-block;
	animation: sparkle 1.4s infinite;
}

.about-outro figcaption::after,
.about-outro p::after {
	content: " ✦";
	color: var(--yellow);
	display: inline-block;
	animation: sparkle 1.4s 0.7s infinite;
}

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

	.about-portrait {
		grid-row: auto;
		margin-bottom: 8px;
	}

	.couple-photo .picture::after {
		font-size: 11px;
		padding: 1px 5px;
	}

	.face-sticker::before,
	.face-sticker::after {
		font-size: 17px;
	}
}

/* ==========================================================================
   Motion
   All of it is decoration. Asked to hold still, the page holds still: the
   marquee becomes a static banner short enough to read, and everything that
   blinks or sparkles simply stays lit.
   ========================================================================== */

@keyframes marq {
	from {
		transform: translateX(100vw);
	}

	to {
		transform: translateX(-100%);
	}
}

/* The in-page marquee: the text crosses its own box. */
@keyframes marq-indent {
	from {
		text-indent: 100%;
	}

	to {
		text-indent: -100%;
	}
}

/* The glitter sticker's tile sliding across itself. */
@keyframes glitter {
	to {
		background-position:
			14px 14px,
			29px 31px,
			21px 33px,
			0 0;
	}
}

@keyframes rainbow {
	to {
		filter: hue-rotate(360deg);
	}
}

@keyframes blink {
	0%,
	49% {
		opacity: 1;
	}

	50%,
	100% {
		opacity: 0;
	}
}

@keyframes sparkle {
	0%,
	100% {
		opacity: 1;
		transform: scale(1);
	}

	50% {
		opacity: 0.2;
		transform: scale(0.5);
	}
}

@media (prefers-reduced-motion: reduce) {
	html::after {
		content: "★ WeLcOmE tO iSaK's HoMePaGe!!! ★";
		animation: none;
		transform: none;
		left: 50%;
		translate: -50% 0;
	}

	[data-page="/about"] main::before {
		content: "★ aLl AbOuT mEeEe!!! ★";
		text-align: center;
		animation: none;
	}

	h1,
	[data-page="/"] .section-links::before,
	footer p:first-of-type::before,
	footer p:first-of-type::after,
	.face-sticker,
	.face-sticker::before,
	.face-sticker::after,
	.most-watched li::before,
	.about-outro figcaption::before,
	.about-outro figcaption::after,
	.about-outro p::before,
	.about-outro p::after {
		animation: none;
	}
}

/* The contents of a write-up, indented by depth. */
.toc ol {
	list-style: none;
	margin: 6px 0 0;
	padding: 0;
}

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

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

/* ==========================================================================
   Potatoes
   ========================================================================== */

/* The word in the title is a button; here it keeps the title's colours rather
   than arriving as a grey box in the middle of them. */
.potato-trigger {
	font: inherit;
	color: inherit;
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
}

.potato-trigger del {
	color: var(--cyan);
}

.potato-trigger:hover del,
.potato-trigger:focus-visible del {
	color: var(--yellow);
	text-shadow: 0 0 6px var(--magenta);
}

.potato-popover {
	max-width: 52ch;
	border: 3px ridge var(--magenta);
	background: #1a0033;
	color: var(--text);
	padding: 14px 18px;
}

.potato-popover::backdrop {
	background: rgb(0 0 24 / 0.6);
}

.potato-popover h2 {
	margin-top: 0;
	color: var(--yellow);
	text-shadow: 2px 2px 0 var(--magenta);
}

.potato-popover p {
	color: var(--secondary);
}

.potato-forms {
	margin: 0 0 14px;
	padding-left: 20px;
	color: var(--lime);
}

/* The print button and the popover's close button, beveled like every other
   control in here. */
.potato-popover > button,
.print-button {
	font-family: inherit;
	font-size: 15px;
	font-weight: 700;
	color: var(--lime);
	background: #000;
	border: 2px outset #999;
	padding: 4px 12px;
	cursor: pointer;
}

.print-button:active {
	border-style: inset;
}

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

/* The download link beside it is an anchor. Besides the box and the underline,
   it has to say what hovering does: the rule for links fills the background
   with cyan, which would swallow the bevel this button is made of. */
.download-button {
	display: inline-block;
	text-decoration: none;
}

.download-button:hover,
.download-button:focus-visible {
	background: #000;
	color: var(--lime);
}

.print-hint {
	font-size: 15px;
	color: var(--cyan);
}

/* Built with, as beveled badges. The brand colour lights the border, which is
   what this theme would have done in 2001 if it could have. */
.skill-list {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.skill-list li {
	display: flex;
	align-items: center;
	gap: 6px;
	background: #000;
	border: 2px outset var(--brand, #999);
	padding: 1px 8px;
	font-size: 13.5px;
	color: var(--lime);
}

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

.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 the slideshow this theme has been
   waiting for since 1999. Pure CSS:
   scroll snapping, with dots and arrows where the browser supports them.
   ========================================================================== */

.carousel {
	margin-bottom: 16px;
	display: flex;
	gap: 10px;
	list-style: none;
	margin: 10px 0 0;
	padding: 0 0 10px;
	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 92%;
	scroll-snap-align: center;
	border: 3px ridge var(--cyan);
	background: #000;
	padding: 4px;
}

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

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

.carousel > li::scroll-marker {
	content: "●";
	color: #445;
	font-size: 15px;
	line-height: 1;
}

.carousel > li::scroll-marker:target-current {
	color: var(--magenta);
	text-shadow: 0 0 6px var(--magenta);
}

.carousel::scroll-button(*) {
	font-family: inherit;
	font-size: 15px;
	font-weight: 700;
	color: var(--lime);
	background: #000;
	border: 2px outset #999;
	padding: 2px 10px;
	cursor: pointer;
}

.carousel::scroll-button(*):active {
	border-style: inset;
}

.carousel::scroll-button(*):disabled {
	color: #556;
	cursor: default;
}

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

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

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

/* ==========================================================================
   Contact form
   A form that looks like it was made in 2001, which is the only honest way to
   draw one in this theme.
   ========================================================================== */

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

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

.contact-form label {
	display: block;
	color: var(--yellow);
	font-weight: 700;
	font-size: 13.5px;
	margin-bottom: 3px;
}

.contact-form input,
.contact-form textarea {
	font-family: inherit;
	font-size: 15px;
	width: 100%;
	box-sizing: border-box;
	color: var(--lime);
	background: #000;
	border: 2px inset #999;
	padding: 5px 8px;
}

.contact-form textarea {
	resize: vertical;
}

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

.contact-form button {
	font-family: inherit;
	font-size: 15px;
	font-weight: 700;
	color: var(--space);
	background: var(--yellow);
	border: 2px outset #ffd;
	padding: 5px 20px;
	cursor: pointer;
}

.contact-form button:active {
	border-style: inset;
}

.form-outcome {
	border: 2px ridge var(--lime);
	background: #001a00;
	color: var(--lime);
	padding: 8px 12px;
	font-weight: 700;
}

.form-outcome[data-tone="bad"] {
	border-color: var(--yellow);
	background: #1a1a00;
	color: var(--yellow);
}

.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;
}

/* A window, because in 1999 a picture opened in a window: beveled edge, a hard
   shadow cast down and to the right, and a grey button to dismiss it. */
.image-viewer {
	max-width: min(94vw, 1400px);
	max-height: 92vh;
	padding: 6px;
	border: 3px outset var(--magenta);
	background: var(--space);
	box-shadow: 5px 5px 0 #000;
}

.image-viewer::backdrop {
	background: rgb(0 0 24 / 0.86);
}

.image-viewer-image {
	display: block;
	/* The button below is inside the dialog, so the picture takes what is left
      of the screen once the button and the padding have had theirs. */
	max-width: 100%;
	max-height: calc(92vh - 52px);
	object-fit: contain;
	border: 2px inset #999;
}

/* The grey button of the period, bevel and all. */
.image-viewer-close {
	display: block;
	margin: 6px auto 2px;
	padding: 2px 18px;
	border: 2px outset #e8e8e8;
	background: #c0c0c0;
	color: #000;
	font-family: var(--comic);
	font-size: 15px;
	font-weight: 700;
	cursor: pointer;
}

.image-viewer-close:active {
	border-style: inset;
}

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

/*
 * Selected text, in the loudest cyan the theme owns, with the deep space navy
 * on top of it. Magenta would have been louder still, and unreadable.
 */
::selection {
	background: var(--cyan);
	color: var(--space);
}
