/* WordPress glue.
 *
 * Everything here exists because WordPress emits markup the prototype never
 * had: core block classes in post content, paginate_links' own class
 * vocabulary, the admin bar. Nothing in this file belongs in the prototype, and
 * nothing the prototype owns belongs here - theme.css is generated and would
 * overwrite it. */

/* ── the fifth view ───────────────────────────────────────────────────
   The prototype carried four (home, dl, news, post). A WordPress site also has
   ordinary pages: about, contribute, the legal ones. */
#site[data-page="page"] .page--page { display: block; }

/* ── controls that became links ───────────────────────────────────────
   The category filter is a set of <a> to real archives rather than buttons that
   hide rows, so it can be bookmarked and paged through. The chip and cat rules
   in theme.css are class-based and carry over; only the underline has to go. */
#site .chip,
#site .cat { text-decoration: none; }

/* ── pagination ───────────────────────────────────────────────────────
   paginate_links names the current page and the ellipsis with classes, and puts
   the current one in a <span>, so theme.css's `.pager a[aria-current]` never
   matches. Map the vocabulary rather than rewriting the markup. */
#site .pager .page-numbers {
	display: grid;
	place-items: center;
	min-width: 2.15rem;
	height: 2.15rem;
	padding-inline: .55rem;
	font-family: var(--display);
	font-size: .85rem;
	color: var(--dim);
	text-decoration: none;
	border-radius: 8px;
}
#site .pager a.page-numbers:hover { background: var(--band); color: var(--ink); }
#site .pager .page-numbers.current {
	background: var(--orange);
	color: var(--on-accent);
	font-weight: 600;
}
#site .pager .page-numbers.dots { color: var(--dim); }

/* ── skip link ────────────────────────────────────────────────────────
   Off screen until focused, then a real control in the corner. */
.skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 300;
	padding: .7rem 1.1rem;
	font: 600 .9rem/1 system-ui, sans-serif;
	color: #fff;
	background: #c44400;
	border-radius: 0 0 8px 0;
	text-decoration: none;
}
.skip:focus {
	left: 0;
}

/* ── admin bar ────────────────────────────────────────────────────────
   The header is sticky at top:0, which puts it under the admin bar for a
   logged-in editor. Every offset measured from that header moves with it --
   the archive rail and the post rail both, or the panel parks where the
   header now is and its first heading reads as cut off. */
.admin-bar #site .top { top: 32px; }
.admin-bar #site .rail,
.admin-bar #site .prail { top: calc(4.6rem + 32px); }
/* and the same for what those rails jump to: a heading with only the
   header's worth of scroll margin lands beneath a taller one. */
.admin-bar #site .pyear,
.admin-bar #site .prose h2 { scroll-margin-top: calc(5.25rem + 32px); }
@media screen and (max-width: 782px) {
	.admin-bar #site .top { top: 46px; }
	.admin-bar #site .rail,
	.admin-bar #site .prail { top: calc(4.6rem + 46px); }
	.admin-bar #site .pyear,
	.admin-bar #site .prose h2 { scroll-margin-top: calc(5.25rem + 46px); }
}
/* Above 600px wide the admin bar is fixed; below it, it scrolls with the page,
   so a fixed offset would leave a gap. */
@media screen and (max-width: 600px) {
	.admin-bar #site .top { top: 0; }
	.admin-bar #site .pyear,
	.admin-bar #site .prose h2 { scroll-margin-top: 5.25rem; }
}

/* ── block editor output inside .prose ────────────────────────────────
   theme.css styles the elements a post is made of; these are the wrappers and
   alignment classes the editor adds around them. */
#site .prose .alignleft {
	float: left;
	margin: .3rem 1.4rem 1rem 0;
}
#site .prose .alignright {
	float: right;
	margin: .3rem 0 1rem 1.4rem;
}
#site .prose .aligncenter {
	margin-inline: auto;
	text-align: center;
}
#site .prose .alignwide {
	width: min(64rem, 100vw - 2rem);
	margin-inline: calc(50% - min(32rem, 50vw - 1rem));
}
#site .prose .alignfull {
	width: 100vw;
	margin-inline: calc(50% - 50vw);
	max-width: none;
}
#site .prose .wp-block-image,
#site .prose figure { margin-block: 1.9rem; }
#site .prose .wp-block-image img { border-radius: 10px; }
#site .prose .wp-caption-text,
#site .prose figcaption {
	margin-top: .7rem;
	font-size: .84rem;
	color: var(--dim);
	text-align: center;
}
#site .prose .wp-block-embed__wrapper,
#site .prose .wp-block-embed iframe { max-width: 100%; }
/* A classic [caption] prints its image's width inline -- 1024px, 1513px --
   which is wider than the measure, so it overflows on every screen. */
#site .prose .wp-caption { max-width: 100%; margin-inline: auto; }

/* A release body carries its demo video as plain <video> markup with the
   recording's own width on it -- 880px, wider than the measure -- so nothing
   above caps it and the post scrolls sideways. Sized to the measure instead,
   with the height capped the way theme.css caps a screenshot so a tall capture
   cannot become a two-screen wall. The ratio is 'auto 16/9': the file's own
   once its metadata arrives, and 16/9 until then, because a <video> with no
   metadata yet is 300x150 and the box would otherwise resize under the reader.
   The remote .mp4 takes its time, so that wait is the normal case. */
#site .prose video {
	display: block;
	width: 100%;
	max-width: 100%;
	height: auto;
	max-height: 32rem;
	aspect-ratio: auto 16 / 9;
	margin-inline: auto;
	border: 1px solid var(--line);
	border-radius: 12px;
	background: var(--band);
}

/* A code block is a block, not the inline <code> theme.css already styles. */
#site .prose pre,
#site .prose .wp-block-code {
	overflow-x: auto;
	padding: 1rem 1.15rem;
	font-family: var(--display);
	font-size: .86rem;
	line-height: 1.6;
	background: var(--band);
	border: 1px solid var(--line);
	border-radius: 10px;
}
#site .prose pre code {
	padding: 0;
	background: none;
	font-size: inherit;
}

/* Tables in post content, which the prototype never had to draw. */
#site .prose table {
	width: 100%;
	border-collapse: collapse;
	font-size: .92rem;
}
#site .prose th,
#site .prose td {
	padding: .6rem .8rem;
	text-align: left;
	border-bottom: 1px solid var(--line);
}
#site .prose th {
	font-family: var(--display);
	font-weight: 600;
	color: var(--ink);
}

/* Clear a float that would otherwise run past the end of the article. */
#site .prose::after {
	content: '';
	display: block;
	clear: both;
}

/* The empty state on an archive holds a link back, which reads as a chip. */
#site .pempty .chip { margin-left: .5ch; }

/* ── the wiki, under a search ─────────────────────────────────────────
   A search results page prints what wiki.mudlet.org said under the site's own
   rows and never mixed into them — the same order the palette draws in, out of
   the same call. Here rather than in theme.css because the prototype had no
   results page for this to be part of: it exists only once WordPress is
   answering a query. See inc/wiki-search.php and search.php.

   Rows and not cards, because the list above it is rows: the same date-rail
   shape as .prow with the date column taken out. */
#site .wres { margin-top: 2.5rem; padding-top: 1.4rem; border-top: 1px solid var(--line); }
#site .wres__h {
	display: flex;
	align-items: center;
	gap: 1.1ch;
	margin-bottom: .5rem;
	font-family: var(--display);
	font-size: .75rem;
	font-weight: 600;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--dim);
}
#site .wres__h::before { content: '>'; color: var(--mark); }
#site .wres__h::after { content: ''; flex: 1; height: 1px; background: var(--line); }
#site .wres__row {
	display: block;
	padding: .95rem .85rem;
	border-bottom: 1px solid var(--line);
	text-decoration: none;
	transition: background .15s;
}
#site .wres__row:hover { background: var(--band); }
#site .wres__row h3 { font-size: 1rem; transition: color .15s; }
/* the mark rides in on hover — the same > the rows above it use */
#site .wres__row h3::before {
	content: '>';
	margin-left: -1.1ch;
	margin-right: .35ch;
	color: var(--mark);
	opacity: 0;
	transition: opacity .15s;
}
#site .wres__row:hover h3 { color: var(--link); }
#site .wres__row:hover h3::before { opacity: 1; }
#site .wres__row p {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	margin-top: .3rem;
	font-size: .89rem;
	line-height: 1.6;
	color: var(--dim);
}
#site .wres__all { margin-top: 1.2rem; }

/* ── changelog height ─────────────────────────────────────────────────
   The prototype's changelog was eleven hand-written lines; a real one is four
   hundred. Left alone, that puts ten thousand pixels between the article and
   the footer and nobody ever reaches the end of the page.

   So the list scrolls inside its own box. No toggle: the cap already solves the
   problem a toggle would, and it does it with no JavaScript, so the changelog is
   complete and usable with scripting off.

   These rules are here rather than in theme.css because that file is generated
   from the prototype and would overwrite them. */
#site .chlog__body {
	max-height: min(60vh, 34rem);
	overflow-y: auto;
	overscroll-behavior: contain; /* reaching its end must not scroll the page on */
}

/* The count in the bar links to the compare page — the one place a link out is
   the right answer, since it is where the whole diff lives. */
#site .chlog__bar .n a {
	color: inherit;
	text-decoration: none;
}
#site .chlog__bar .n a:hover { color: var(--c-fg); }

/* ── the makers roster ────────────────────────────────────────────────
   /the-makers/ draws thirty people read out of Mudlet's About dialog. The
   prototype has no people grid to inherit, so the card is described here — and
   it is here rather than in theme.css for the usual reason: that file is
   generated from the prototype and would overwrite it.

   Built out of the same parts as .pcard so the page still looks like the rest
   of the site: same --card ground, same --line border, same hover lift. What
   differs is the shape of the content - a face, a name, and a sentence that
   runs to three lines - so it is a two-column card rather than a stacked one. */
#site .head--tight { margin-block: 2.6rem 1.1rem; }
#site .head--tight h3 {
	font-family: var(--display);
	font-size: 1.05rem;
	font-weight: 600;
	color: var(--ink);
	margin-bottom: .35rem;
}

#site .mkgrid {
	display: grid;
	gap: .7rem;
	grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
}
#site .mkcard {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: .25rem .85rem;
	align-items: start;
	/* Cards in a row are stretched to the tallest, and without this the short
	   ones push their sentence to the bottom of the box. */
	align-content: start;
	padding: 1rem 1.05rem;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: 11px;
	text-decoration: none;
	color: inherit;
	transition: .15s;
}
#site a.mkcard:hover {
	border-color: var(--accent2);
	box-shadow: 0 8px 20px -12px rgba(var(--sh), .45);
}

/* The face. Two thirds of the makers publish a GitHub handle and get their
   avatar; the rest get their initials, which is why the monogram is styled as
   carefully as the picture rather than treated as a missing image. */
#site .mkface {
	grid-row: span 2;
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	border-radius: 50%;
	overflow: hidden;
	background: var(--band);
	border: 1px solid var(--line);
}
#site .mkface img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
#site .mkinit {
	font-family: var(--display);
	font-size: .82rem;
	font-weight: 600;
	color: var(--dim);
	letter-spacing: .02em;
}

#site .mkwho { display: block; padding-top: .15rem; }
#site .mkwho b {
	display: block;
	font-size: .95rem;
	font-weight: 600;
	line-height: 1.3;
}
#site .mkhandle {
	font-family: 'IBM Plex Mono', ui-monospace, monospace;
	font-size: .72rem;
	color: var(--dim);
}
#site .mkdid {
	grid-column: 2;
	font-size: .87rem;
	line-height: 1.55;
	color: var(--dim);
}
#site .mkdid a { color: var(--link); }

/* The past contributors are twenty-two of the thirty. Same card, tighter: the
   sentences are shorter and the grid would otherwise run down the page. */
#site .mkgrid--past { grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }
#site .mkgrid--past .mkcard { padding: .8rem .9rem; }
#site .mkgrid--past .mkface { width: 2.1rem; height: 2.1rem; }
#site .mkgrid--past .mkinit { font-size: .68rem; }
#site .mkgrid--past .mkwho b { font-size: .88rem; }
#site .mkgrid--past .mkdid { font-size: .82rem; }

/* The "Also credited" region under the roster — hand-written in wp-admin, so
   it is .prose like the body above. The rule only separates it from the cards,
   which is what the acknowledgements block already does further down. */
#site .mktail {
	margin-top: 2.6rem;
	padding-top: 1.4rem;
	border-top: 1px solid var(--line);
}
#site .mktail h3 {
	font-family: var(--display);
	font-size: 1.05rem;
	font-weight: 600;
	color: var(--ink);
	margin-bottom: .6rem;
}

/* The prose Mudlet prints under its own credits: that the list is incomplete,
   who drew the icons, and thanks to people who never committed a line. */
#site .mknotes {
	margin-top: 2.6rem;
	padding-top: 1.4rem;
	border-top: 1px solid var(--line);
	font-size: .9rem;
	color: var(--dim);
}

/* The patreon names. A row of names, not cards - there is nothing else known
   about them and a card would be mostly empty. */
#site .mkpatrons {
	font-family: var(--display);
	font-size: .9rem;
	color: var(--ink);
	line-height: 2;
}
#site .mkpatrons .sep { color: var(--dim); margin-inline: .5ch; }

/* A maker's own page leads with their face at reading size. */
#site .mkface--big {
	width: 4.5rem;
	height: 4.5rem;
	margin-bottom: .9rem;
}
#site .mkface--big .mkinit { font-size: 1.3rem; }

/* ── /games/, the showcase ────────────────────────────────────────────
   The design this grew out of had no games page, only the front page's grid
   of logo tiles - so this one is WordPress's alone.

   It deliberately does not extend .pcard. That card is a logo, a name and a
   hostname packed fifteen to a screen; this one carries a blurb and a row of
   tags and comes four to a row at most. Two different objects that happen to
   both be a game. What it does reuse is .plogo, because the cream tile that
   keeps a logo readable in dark mode is the same problem in both places, and
   .chip, because the facet toggles are the news filter's chips doing the news
   filter's job. */

/* the panel: one game, picked per request, rebuilt in place by the shuffle */
#site .gfeat {
	display: grid;
	grid-template-columns: auto 1fr auto;
	align-items: start;
	gap: clamp(1rem, 3vw, 1.75rem);
	margin-bottom: clamp(2rem, 4vw, 2.75rem);
	padding: clamp(1.1rem, 3vw, 1.6rem);
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: 14px;
}
#site .gfeat__logo { width: 9rem; height: 4.6rem; }
#site .gfeat__body { min-width: 0; }
#site .gfeat__eyebrow {
	font-family: var(--display);
	font-size: .74rem;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--dim);
	margin: 0 0 .35rem;
}
/* ── the panel does not move ──────────────────────────────────────────
   Every row below is a fixed number of lines tall, because the shuffle
   replaces the game in place: a panel that grew or shrank would throw the grid
   under it up and down the screen while the pointer is still over the button
   that did it. Nothing here clips anything a visitor needs - the blurb's
   remaining lines are on the game's own page, one click away. */
#site .gfeat__name {
	font-size: clamp(1.2rem, 2.6vw, 1.5rem);
	margin: 0 0 .5rem;
	line-height: 1.25;
	/* Two of the forty-three names wrap on a mid-width screen. One line,
	   ellipsised, so the panel keeps its height there too - the full name is
	   the link's own text, so it is still read out in full and still in the
	   tooltip. */
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
#site .gfeat__name a { color: inherit; text-decoration: none; }
#site .gfeat__name a:hover { color: var(--link); }
#site .gfeat__lede {
	margin: 0 0 .85rem;
	color: var(--dim);
	max-width: 62ch;
	line-height: 1.6;
	/* exactly four lines: the shortest blurb here is "In Achaea, your name
	   carries weight." and the longest runs past a screen */
	height: calc(4 * 1.6em);
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 4;
	line-clamp: 4;
	overflow: hidden;
}
/* Two rows, not one: an address for the client on this machine and a link for
   the one in a tab. They are the same subject and are set as one block, which
   is why the first sits tight above the second rather than each carrying the
   gap that separates the pair from the tags. */
#site .gfeat__connect,
#site .gfeat__browser {
	display: flex;
	align-items: baseline;
	gap: .6ch;
	margin: 0 0 .3rem;
	/* the address and its hint stay on one line; a long host scrolls nothing
	   and wraps nothing, it just runs out of room like a terminal would */
	min-width: 0;
	white-space: nowrap;
	overflow: hidden;
}
#site .gfeat__browser { margin-bottom: .7rem; }
#site .gfeat__tags {
	display: flex;
	gap: .35rem;
	margin: 0;
	/* one row: a game with seven tags must not push the panel taller than one
	   with two */
	min-height: 1.35rem;
	overflow: hidden;
}

/* "another" — the panel redraws from a card already on the page, so this is
   free; it is hidden until theme.js is there to make it do anything */
#site .gfeat__again {
	font-family: var(--display);
	font-size: .78rem;
	color: var(--dim);
	background: transparent;
	border: 1px solid var(--line);
	border-radius: 999px;
	padding: .34rem .85rem;
	cursor: pointer;
	white-space: nowrap;
	transition: .15s;
}
#site .gfeat__again:hover { color: var(--ink); background: var(--band); border-color: var(--accent2); }

@media (max-width: 46rem) {
	#site .gfeat { grid-template-columns: 1fr; }
	#site .gfeat__again { justify-self: start; }
}

/* ── the telnet:// link ───────────────────────────────────────────────
   Mudlet registers itself for telnet:// and telnets://, so the address is a
   button as much as a fact. It is styled as the command it looks like rather
   than as a link, because that is what a reader is being invited to run - and
   the hint beside it says where it goes, since a scheme link that finds no
   handler does nothing at all and nothing on screen would explain why. */
#site .gplay {
	font-family: var(--display);
	color: var(--dim);
	text-decoration: none;
	border-radius: 6px;
	padding: .1rem .3rem;
	margin-inline: -.3rem;
	transition: .15s;
}
#site .gplay b { font-weight: 600; color: var(--ink); margin-inline: .55ch 1ch; }
#site .gplay .sep { color: var(--mark); opacity: .55; margin-inline: .6ch; }
#site .gplay__addr { border-bottom: 1px dashed var(--line); }
#site a.gplay:hover { background: var(--band); color: var(--ink); }
#site a.gplay:hover .gplay__addr { border-bottom-color: var(--accent2); }
#site .gplay__hint {
	font-family: var(--display);
	font-size: .7rem;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--dim);
	opacity: .7;
	margin-left: .8ch;
}
/* nothing to open: the anchor carries no href and is text, so drop the affordances */
#site .gplay:not([href]) .gplay__addr { border-bottom: 0; }
#site .gplay:not([href]) ~ .gplay__hint { display: none; }

/* ── the toolbar ──────────────────────────────────────────────────────
   Hidden in the markup and revealed by theme.js: a search field that cannot
   search is worse than no search field. Everything under it works without. */
#site .gbar {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: .5rem .75rem;
	margin-bottom: 1.25rem;
	padding-bottom: 1.1rem;
	border-bottom: 1px solid var(--line);
}
#site .gfind {
	display: flex;
	align-items: center;
	flex: 1 1 14rem;
	min-width: 0;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: 999px;
	padding: .34rem .95rem;
}
#site .gfind::before { content: '>'; color: var(--mark); font-family: var(--display); font-weight: 600; margin-right: .6ch; }
#site .gfind:focus-within { border-color: var(--accent2); }
#site .gfind input {
	flex: 1;
	min-width: 0;
	font: inherit;
	font-size: .88rem;
	color: var(--ink);
	background: transparent;
	border: 0;
	outline: none;
	padding: 0;
}
#site .gfind input::placeholder { color: var(--dim); }
#site .gfind input::-webkit-search-cancel-button { filter: grayscale(1); opacity: .5; }
#site .gfacets { display: flex; flex-wrap: wrap; gap: .35rem; }
#site .gcount {
	margin: 0;
	font-family: var(--display);
	font-size: .76rem;
	color: var(--dim);
	white-space: nowrap;
}

/* ── the shelf ────────────────────────────────────────────────────────
   Wider than .pgrid because these cards carry a paragraph. */
#site .gshelf {
	display: grid;
	gap: .8rem;
	grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr));
}
#site .gshelf__cta { margin-top: clamp(2rem, 4vw, 2.75rem); }

#site .gcard {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: .5rem;
	padding: .9rem;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: 11px;
	transition: .15s;
}
#site .gcard:hover { border-color: var(--accent2); box-shadow: 0 8px 20px -12px rgba(var(--sh), .45); }
#site .gcard[hidden] { display: none; }
#site .gcard__logo { flex: none; }
#site .gcard__name { font-size: .95rem; font-weight: 600; line-height: 1.3; margin: 0; }
#site .gcard__name a { color: inherit; text-decoration: none; }
/* one stretched link rather than a card-sized <a>: the card holds a whole
   paragraph, and wrapping that in the anchor would read the blurb out as the
   link's name on every card */
#site .gcard__name a::after { content: ''; position: absolute; inset: 0; border-radius: 11px; }
#site .gcard:hover .gcard__name a { color: var(--link); }
#site .gcard__domain {
	font-family: var(--display);
	font-size: .72rem;
	color: var(--dim);
	margin: -.3rem 0 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
#site .gcard__lede {
	margin: 0;
	font-size: .84rem;
	line-height: 1.55;
	color: var(--dim);
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
	line-clamp: 3;
	overflow: hidden;
}
/* the four profiles upstream ships with no blurb print their address instead,
   so the slot is never empty and the rows never go ragged */
#site .gcard__lede--connect { font-family: var(--display); font-size: .78rem; }
#site .gcard__tags { display: flex; flex-wrap: wrap; gap: .3rem; margin: auto 0 0; padding-top: .25rem; }

/* the tags themselves. On a card they are spans - a link inside a stretched
   link is a click target fighting the card - and on the panel they are real
   links, which is the one place their URL is reachable. */
#site .gtag {
	font-family: var(--display);
	font-size: .68rem;
	letter-spacing: .02em;
	color: var(--dim);
	background: var(--band);
	border: 1px solid transparent;
	border-radius: 999px;
	padding: .16rem .55rem .16rem .45rem;
	white-space: nowrap;
	/* the chip is a glyph and a word on one baseline, and the glyph never
	   shrinks: gap in ch so it tracks the display face, not the root size */
	display: inline-flex;
	align-items: center;
	gap: .45ch;
}
/* Sized in em so it follows the chip's own font-size, and dimmed a touch so a
   row of six reads as a row of words with marks on them rather than a row of
   icons. It inherits currentColor, which is what carries it through the hover
   state and both themes. */
#site .gtag__i { width: 1em; height: 1em; flex: none; opacity: .75; }
#site a.gtag:hover .gtag__i { opacity: 1; }
#site .gtag[data-tag="secure"],
#site .gtag[data-tag="own-ui"] { color: var(--link); background: transparent; border-color: var(--line); }
/* Every one of the forty-three has a website, and the card prints its domain
   two lines up, so the tag distinguishes nothing there. It stays in the markup
   because the panel's shuffle builds its one real link out of these, and it is
   the only place that URL is reachable. */
#site .gcard__tags .gtag[data-tag="site"] { display: none; }
#site .gcard__tags:not(:has(.gtag:not([data-tag="site"]))) { display: none; }
#site a.gtag { text-decoration: none; }
#site a.gtag:hover { color: var(--on-accent); background: var(--orange); border-color: var(--orange); }

/* One game's page: the spec run is a line of prose, so its glyphs sit on the
   baseline as inline marks rather than as flex items. Same set and same
   classification as the chips above, so a link a card showed as "Discord"
   keeps the mark it had under whatever upstream chose to call it here. */
#site .specs__i { width: 1em; height: 1em; vertical-align: -.14em; margin-right: .5ch; opacity: .75; }

#site .gnone {
	margin: 2rem 0 0;
	padding: 1.5rem;
	background: var(--band);
	border: 1px dashed var(--line);
	border-radius: 11px;
	color: var(--dim);
	text-align: center;
	max-width: 52ch;
	margin-inline: auto;
}

/* ── the hand-off's email form ────────────────────────────────────────
   The row, the drawer it slides open and the code inside it came from the
   prototype and live in theme.css. The mail face could not have: a static page
   has nowhere to send an address, so these rules live here for that reason and
   no other. Which is also why theme.css knows only
   how to show the `qr` face - the other one is declared below. */
#site .dlmore[data-face="mail"] .dlpane--mail {
	display: block;
}
#site .dlmail {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .5rem;
	margin-top: .8rem;
}
#site .dlmail input[type="email"] {
	font-family: var(--display);
	font-size: .84rem;
	color: var(--ink);
	background: var(--bg);
	border: 1px solid var(--line);
	border-radius: 8px;
	padding: .45rem .6rem;
	min-width: 15rem;
}
#site .dlmail .btn {
	font-size: .84rem;
	padding: .42rem .95rem;
}
/* The honeypot: off the page rather than display:none, which is the first
   thing a bot checks for. Nothing focusable follows it into the tab order —
   it carries tabindex="-1". */
#site .dlmail__hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	opacity: 0;
}
/* Its own line under the field. Two classes rather than one because the cap
   this has to lift - the 52ch theme.css puts on every paragraph in a drawer,
   which keeps its prose readable and would otherwise leave this line short
   enough to sit beside the button - is written `#site .dlpane p`. */
#site .dlmail .dlmail__msg {
	flex: none;
	width: 100%;
	max-width: none;
	margin: 0;
	font-size: .84rem;
	color: var(--dim);
}
#site .dlmail .dlmail__msg[data-state="bad"] {
	color: var(--mark);
}
/* The drawer opens on a row that is already narrow on a phone; the field
   would otherwise force the table wider than the screen. */
@media (max-width: 40rem) {
	#site .dlmail input[type="email"] {
		min-width: 0;
		flex: 1 1 12rem;
	}
}

/* WordPress's own label-hiding class, which this theme had no occasion to
   define until the games filter needed a label nobody has to read. */
#site .screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* ── /contact/ ────────────────────────────────────────────────────────
   Two panels — Discord and the message form — over a row of link cards.
   The design this grew out of had no contact page: this one is WordPress's
   alone, for the same reason the download page's mail form is.

   Built out of the same parts as .mkcard and .gcard so the page still looks
   like the rest of the site: --card ground, --line border, the same 11-12px
   radius and the same hover lift.

   align-items:start, so the two panels are each their own height. A grid
   stretches its items to the tallest row by default, and the form is half
   again as tall as the Discord panel - which left the Join button alone at
   the bottom of 250px of nothing, with the panel's border drawn around the
   gap. Two cards of honest heights read better than one padded out to match
   the other. */
#site .ctgrid {
	display: grid;
	align-items: start;
	gap: 1rem;
	/* min() so a narrow screen gets one column rather than a track wider than
	   the viewport - the message form's two-up row is already the widest thing
	   in here. */
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr));
	margin-top: 2.4rem;
}
#site .ctpanel {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: .85rem;
	padding: 1.35rem 1.4rem 1.5rem;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: 12px;
}
#site .ctpanel__top {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: .85rem;
	align-items: center;
	width: 100%;
}
/* The glyph gets a tile rather than sitting loose, so the two panels have the
   same left edge whatever the icon's own proportions are. */
#site .ctpanel__mark {
	display: grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 10px;
	background: var(--band);
	border: 1px solid var(--line);
	color: var(--mark);
}
#site .ctpanel__mark svg { width: 1.15rem; height: 1.15rem; }
#site .ctpanel h3 { font-size: 1.05rem; }
#site .ctpanel__meta {
	font-family: var(--display);
	font-size: .79rem;
	color: var(--dim);
	margin-top: .2rem;
}
#site .ctpanel__meta .sep { margin-inline: .35ch; }
#site .ctpanel p { color: var(--dim); font-size: .94rem; line-height: 1.65; max-width: 52ch; }
/* A little more air above the button than between the lines above it: it is
   the one thing in the panel that is not prose. */
#site .ctpanel > .btn { margin-top: .35rem; }

/* The presence dot. A fixed Discord green in both themes - it is a status
   light quoting another product's vocabulary, not a site colour. */
#site .ctdot {
	display: inline-block;
	width: .45rem;
	height: .45rem;
	border-radius: 50%;
	background: #3ba55d;
	margin-right: .45rem;
	vertical-align: .08em;
}

/* Avatars of whoever is online, overlapped. No names: see inc/discord.php.
   The 2px ring is --card and not a colour, so the overlap reads as depth in
   both themes; the row is padded by the same amount it pulls each face back,
   which keeps the first one flush with everything above it. */
#site .ctfaces {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	padding-left: .4rem;
}
#site .ctfaces img {
	width: 1.9rem;
	height: 1.9rem;
	border-radius: 50%;
	margin-left: -.4rem;
	border: 2px solid var(--card);
	background: var(--band);
	object-fit: cover;
}
#site .ctmore {
	margin-left: .6rem;
	font-family: var(--display);
	font-size: .78rem;
	color: var(--dim);
}

/* The form. Whatever a plugin puts in the slot inherits the field rules below,
   which is the point of styling by element rather than by class - a shortcode
   brings its own markup and none of our class names. */
#site .ctform {
	display: grid;
	gap: .65rem;
	width: 100%;
}
#site .ctform__row {
	display: grid;
	gap: .65rem;
	grid-template-columns: 1fr 1fr;
}
@media (max-width: 34rem) {
	#site .ctform__row { grid-template-columns: 1fr; }
}
#site .ctfield { display: grid; gap: .3rem; }
#site .ctform label {
	font-family: var(--display);
	font-size: .73rem;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--dim);
}
#site .ctform input,
#site .ctform textarea,
#site .ctform select {
	font-family: var(--body);
	font-size: .92rem;
	color: var(--ink);
	background: var(--bg);
	border: 1px solid var(--line);
	border-radius: 8px;
	padding: .5rem .65rem;
	width: 100%;
}
#site .ctform textarea { min-height: 6rem; resize: vertical; line-height: 1.6; }
/* The placeholder's controls are disabled, and have to look it. A form that
   reads as live and goes nowhere is worse than no form at all. */
#site .ctform :disabled {
	opacity: .5;
	cursor: not-allowed;
}
#site .ctform--soon { user-select: none; }

/* hCaptcha, when the form plugin carries one. What it draws is a cross-origin
   iframe and nothing here reaches inside it: on a free sitekey the only lever
   is light or dark, which theme.js now pulls from the toggle rather than the
   OS. What is ours is the box around it - space above, so it is not jammed
   against the textarea's resize grip, and the type of the message the plugin
   prints in the stand-in box when the frame is slow or never comes. Its colour
   stays the plugin's: red there means the captcha failed, and says so. */
#site .ctform .h-captcha { margin-top: .35rem; }
#site .h-captcha::after { font-family: var(--body); }

/* And it has to say so in words, not only in opacity. Dashed, because a dashed
   box is the one border on this site that means "not finished". */
#site .ctsoon {
	display: flex;
	gap: .55rem;
	align-items: flex-start;
	width: 100%;
	padding: .7rem .8rem;
	background: var(--band);
	border: 1px dashed var(--line);
	border-radius: 9px;
	font-size: .86rem;
	line-height: 1.55;
	color: var(--dim);
	max-width: none;
}
#site .ctsoon svg {
	width: 1rem;
	height: 1rem;
	flex: none;
	margin-top: .22rem;
	color: var(--mark);
}
#site .ctsoon a { color: var(--link); font-weight: 500; }

/* The address, under whichever of the two the panel is showing. Small and
   dim - it is the way round for people who would rather use their own mail
   client, not a second call to action competing with the Send button. */
#site .ctmail {
	font-size: .86rem;
	line-height: 1.55;
	color: var(--dim);
}
#site .ctmail a {
	color: var(--link);
	font-weight: 500;
	/* The address is entity-encoded and can wrap mid-word on a narrow screen;
	   breaking it anywhere but at the @ or a dot reads as a typo. */
	word-break: break-word;
}

/* The forum, GitHub and the wiki. Three destinations with a sentence each,
   which is a card and not a paragraph with a heading over it - which is what
   the forum had on the old page, and why it is down here now. */
#site .ctlinks {
	display: grid;
	gap: .7rem;
	grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
#site .ctlink {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: .2rem .8rem;
	align-items: start;
	align-content: start;
	padding: .95rem 1.05rem 1.05rem;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: 11px;
	text-decoration: none;
	color: inherit;
	transition: .15s;
}
#site .ctlink:hover {
	border-color: var(--accent2);
	box-shadow: 0 8px 20px -12px rgba(var(--sh), .45);
}
#site .ctlink svg {
	grid-row: span 2;
	width: 1.15rem;
	height: 1.15rem;
	margin-top: .2rem;
	color: var(--mark);
}
#site .ctlink b { font-size: .95rem; font-weight: 600; line-height: 1.3; }
#site .ctlink span { font-size: .87rem; line-height: 1.55; color: var(--dim); }

/* ── blocks inside .prose ─────────────────────────────────────────────
   assets/css/blocks.css carries these components' looks and is deliberately
   written without #site, because the block editor loads the same file and has
   no #site to match. The consequence is that theme.css's post rules — all of
   them `#site .prose …`, all of them carrying an id — outrank it on the page.
   These are those collisions and nothing else: they exist only where a prose
   rule reaches inside a component it knows nothing about. */

/* A card's name and blurb are card parts, not the article's headings and
   paragraphs; the prose rhythm would push them apart by two lines. */
#site .prose .rgame .rgame__name {
	margin-top: 0;
	font-size: 1rem;
}
#site .prose .rgame .rgame__blurb,
#site .prose .rgame .rgame__links {
	margin-top: 0;
}

/* Links in a card read as parts of the card. Underlining all four in a
   two-by-two grid turns it into a wall of orange. */
#site .prose .rgame a {
	font-weight: 600;
	text-decoration: none;
}
#site .prose .rgame a:hover {
	text-decoration: underline;
}
#site .prose .rgame__blurb {
	color: var(--dim);
}

/* The highlights card sets its heading in the eyebrow face; the prose heading
   rule would otherwise hand it the article's h3 size and top margin. */
#site .prose .is-style-mudlet-highlights h2,
#site .prose .is-style-mudlet-highlights h3,
#site .prose .is-style-mudlet-highlights h4 {
	margin-top: 0;
	font-size: .8rem;
}

/* media-text puts its own padding on the content column; .prose's vertical
   rhythm would add a second one above the heading inside it. */
#site .prose .is-style-mudlet-feature .wp-block-media-text__content > :first-child {
	margin-top: 0;
}

/* The screencast list is a <ul> inside .prose, and prose owns lists hard:
   it strips the marker, indents by 1.5rem and hangs an en dash off every
   item from an id-carrying selector. These are cards in a grid with a play
   triangle, so all three have to go. Same collision the credits block
   answers in theme.css, one stylesheet further out. */
#site .prose ul.is-style-mudlet-screencasts {
	padding-left: 0;
}
#site .prose ul.is-style-mudlet-screencasts > li {
	margin-top: 0;
}
#site .prose ul.is-style-mudlet-screencasts > li::before {
	content: '';
	left: .85rem;
	color: inherit;
}

/* A card's title is the card's, not the article's: prose underlines every
   link in it and sets them in the body face at 500. */
#site .prose ul.is-style-mudlet-screencasts > li > a {
	font-family: var(--display);
	font-weight: 600;
	color: var(--ink);
	text-decoration: none;
}
#site .prose ul.is-style-mudlet-screencasts > li > a:hover {
	color: var(--mark);
	text-decoration: underline;
}

/* The whole card opens the video, not just the four words of its title. The
   link stretches over the card with a pseudo-element rather than by wrapping
   the blurb in the anchor, which keeps the accessible name of the link the
   name of the video — a screen reader announcing a title and a sentence as one
   link is how a list of eight becomes unlistenable — and keeps the markup a
   list of links with their descriptions, which is what it has to stay.
   Hovering anywhere on the card is now hovering the anchor, so the title still
   answers. The price is that the blurb is no longer selectable text; for one
   sentence describing a video that is the right side of the trade.

   In wp.css and not in blocks.css with the rest of the component, because
   blocks.css is also the editor's stylesheet and an invisible overlay across
   the card is an overlay across the box somebody is trying to type in. */
#site .prose ul.is-style-mudlet-screencasts > li > a::after {
	content: '';
	position: absolute;
	inset: 0;
}

/* The carousel's slides are <figure>s nested inside the gallery <figure>,
   and #site .prose figure reaches all of them: 1.9rem of margin between
   slides that are supposed to be flush, and a 28rem height cap and
   width:auto on an image the frame is already sizing. The outer figure
   keeps its margin — that one is the block's spacing in the article. */
#site .prose .is-style-mudlet-carousel[data-carousel] figure.wp-block-image {
	margin-block: 0;
}
#site .prose .is-style-mudlet-carousel[data-carousel] figure.wp-block-image img {
	max-height: 100%;
	height: 100%;
	width: auto;
}
#site .prose .is-style-mudlet-carousel[data-carousel] figure.wp-block-image figcaption {
	margin-top: 0;
}
/* Prose prefixes every caption with a prompt >, which is the site's voice on
   a screenshot under a paragraph. Centred under a carousel it reads as a
   stray arrow next to the next-slide button, so the slides drop it and the
   block's own caption keeps it. */
#site .prose .is-style-mudlet-carousel[data-carousel] figure.wp-block-image figcaption::before {
	content: none;
}

/* ── the screenshot submission form ──────────────────────────────────────────
   [mudlet_screenshot_submit], drawn by template-parts/blocks/screenshot-submit.php
   for the Mudlet Screenshots plugin. Here rather than in theme.css because a
   static page has nowhere to send a file, and here rather than in blocks.css
   because a shortcode never renders in the editor canvas — the same split the
   download page's mail form is on.

   It sits in a page body, which means inside .prose: hence the max-width reset
   on its paragraphs, which would otherwise be capped for reading and leave the
   status line stranded under a button. */
#site .prose .shotform {
	margin: 1.6rem 0 0;
	padding: 1.15rem 1.25rem 1.25rem;
	background: var(--band);
	border: 1px solid var(--line);
	border-radius: 14px;
}
#site .prose .shotform p {
	max-width: none;
}
#site .prose .shotform__row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .55rem;
	margin-bottom: .7rem;
}
#site .prose .shotform__row label {
	flex: none;
	width: 7.5rem;
	font-family: var(--display);
	font-size: .82rem;
	color: var(--dim);
}
#site .prose .shotform input[type="text"] {
	flex: 1 1 16rem;
	min-width: 0;
	font-family: var(--display);
	font-size: .84rem;
	color: var(--ink);
	background: var(--bg);
	border: 1px solid var(--line);
	border-radius: 8px;
	padding: .45rem .6rem;
}
/* The drop zone. A <label> round a real file input, so a click anywhere in the
   box opens the picker with no script involved — see the template part. The
   input itself is clipped rather than display:none, which would take it out of
   the tab order, so the focus ring has to be drawn on the box instead. */
#site .prose .shotdrop {
	display: grid;
	place-items: center;
	gap: .35rem;
	padding: 1.5rem 1rem;
	margin-bottom: .9rem;
	text-align: center;
	background: var(--bg);
	border: 1px dashed var(--line);
	border-radius: 12px;
	cursor: pointer;
	transition: border-color .12s, background .12s, color .12s;
}
#site .prose .shotdrop:hover {
	border-color: var(--orange);
}
#site .prose .shotdrop__input {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}
#site .prose .shotdrop:has(.shotdrop__input:focus-visible) {
	outline: 2px solid var(--orange);
	outline-offset: 2px;
}
#site .prose .shotdrop__icon {
	width: 1.6rem;
	height: 1.6rem;
	color: var(--dim);
}
#site .prose .shotdrop__say {
	font-family: var(--display);
	font-size: .84rem;
	color: var(--ink);
}
#site .prose .shotdrop__rules {
	font-size: .78rem;
	color: var(--dim);
}
/* Empty until the script fills it in: the input's own copy of the filename is
   inside the pixel the rule above clipped away. */
#site .prose .shotdrop__file {
	font-size: .82rem;
	color: var(--ink);
	word-break: break-all;
}
#site .prose .shotdrop__file:empty {
	display: none;
}
/* Set while a file is being dragged over the box, and once one is chosen. The
   second is the only feedback that a drop landed — the picture is not shown,
   because a preview of it is a picture from a stranger drawn on the page, and
   the point of this whole feature is that that does not happen until an editor
   has said so. */
#site .prose .shotdrop[data-over],
#site .prose .shotdrop[data-has] {
	border-style: solid;
	border-color: var(--orange);
	background: var(--band);
}
#site .prose .shotdrop[data-has] .shotdrop__icon {
	color: var(--orange);
}
#site .prose .shotform__row--send {
	align-items: center;
	gap: .8rem;
	margin-top: 1rem;
	margin-bottom: 0;
}
#site .prose .shotform .btn {
	font-size: .84rem;
	padding: .42rem .95rem;
}
/* Beside the button, in space that is reserved whether or not there is
   anything to say. Every sentence here arrives after a press — the thank-you,
   the refusals, "Sending…" — so a line that collapsed when empty would shove
   the fine print, and the page under it, down and up again on every attempt.
   Two lines is what the longest of them takes at this measure. */
#site .prose .shotform__msg {
	flex: 1 1 14rem;
	margin: 0;
	font-size: .84rem;
	line-height: 1.35;
	min-height: 2.7em;
	color: var(--dim);
}
#site .prose .shotform__msg[data-state="bad"] {
	color: var(--mark);
}
#site .prose .shotform__fine {
	margin: .9rem 0 0;
	font-size: .78rem;
	color: var(--dim);
}
/* While the upload is in flight, and after one has gone through: the form is
   still there to send another, but nothing about it invites a second press of
   the same button on the same file. */
#site .prose .shotform[data-sending] {
	opacity: .7;
}
#site .prose .shotform[data-sent] .shotform__msg {
	color: var(--ink);
}
/* The honeypot: off the page rather than display:none, which is the first
   thing a bot checks for. Nothing focusable follows it into the tab order —
   it carries tabindex="-1". */
#site .prose .shotform__hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	opacity: 0;
}
@media (max-width: 40rem) {
	#site .prose .shotform__row label {
		width: 100%;
	}
	/* On its own line under the button, where the column is narrow enough for
	   the same sentences to run to four. Reserved, for the same reason. */
	#site .prose .shotform__msg {
		flex-basis: 100%;
		min-height: 5.4em;
	}
}

/* ── comments ─────────────────────────────────────────────────────────
   Here rather than in theme.css for the same reason the download page's mail
   form and the screenshot form are: a comment list has no meaning outside
   WordPress, and the static design this theme grew out of had nothing to draw
   for it. See inc/comments.php for why there are no avatars.

   The list is <ol> and threaded, so the nesting has to come from the markup
   rather than a fixed indent — .children is core's class and can go five deep
   before max_depth stops it. The indent is deliberately small: a fifteen-year
   thread five levels down would otherwise be a column two words wide. */
#site .cmts {
	margin: 2.2rem 0 0;
	padding-top: 1.6rem;
	border-top: 1px solid var(--line);
}
#site .cmts__head {
	font-family: var(--display);
	font-weight: var(--dw);
	font-size: 1.05rem;
	letter-spacing: var(--dls);
	margin: 0 0 1.1rem;
}
#site .cmts__list,
#site .cmts__list .children {
	list-style: none;
	margin: 0;
	padding: 0;
}
#site .cmts__list .children {
	margin-top: .9rem;
	padding-left: 1.1rem;
	border-left: 1px solid var(--line);
}
#site .cmt {
	margin: 0 0 1.1rem;
}
#site .cmt__body {
	padding: .9rem 1rem 1rem;
	background: var(--band);
	border: 1px solid var(--line);
	border-radius: 14px;
}
#site .cmt__head {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: .3rem;
	margin-bottom: .5rem;
	font-family: var(--display);
	font-size: .82rem;
	color: var(--dim);
}
#site .cmt__who {
	color: var(--ink);
	font-weight: 600;
}
/* Somebody who can edit posts here, so a reader can tell a maintainer's answer
   from a passer-by's. Not a role name: "Administrator" on a comment is an
   invitation, and what matters is only that they are one of the project's. */
#site .cmt__badge {
	font-size: .7rem;
	line-height: 1;
	padding: .2rem .4rem;
	border-radius: 999px;
	color: var(--on-accent);
	background: var(--orange);
}
#site .cmt__when {
	color: var(--dim);
	text-decoration: none;
}
#site .cmt__when:hover {
	color: var(--link);
	text-decoration: underline;
}
#site .cmt__held {
	margin: 0 0 .5rem;
	font-size: .82rem;
	color: var(--orange);
}
/* The body is untrusted prose from fifteen years of strangers, so it is capped
   the way .prose is and its images are held inside the box rather than trusted
   to be a sensible width. */
#site .cmt__text {
	font-size: .93rem;
	line-height: 1.6;
}
#site .cmt__text > :first-child { margin-top: 0 }
#site .cmt__text > :last-child { margin-bottom: 0 }
#site .cmt__text img {
	max-width: 100%;
	height: auto;
}
#site .cmt__text pre {
	overflow-x: auto;
}
/* Reply, and Cancel reply, are the same control at opposite ends of the same
   action, so they are drawn the same: a small ghost pill, .btn--ghost's colours
   at the size the two of them actually want. Not .btn--ghost itself — that is
   theme.css's, sized for the page's own buttons, and a comment needs something
   that sits inside a paragraph without pushing the line apart. */
#site .cmt__reply {
	margin: .6rem 0 0;
}
#site .cmt__reply a,
#site .comment-reply-title small a {
	display: inline-flex;
	align-items: center;
	padding: .3rem .75rem;
	font-family: var(--display);
	font-size: .76rem;
	font-weight: 600;
	line-height: 1;
	color: var(--ink);
	background: transparent;
	border: 1px solid var(--line);
	border-radius: 999px;
	text-decoration: none;
	cursor: pointer;
	transition: background .12s, border-color .12s, color .12s;
}
#site .cmt__reply a:hover,
#site .comment-reply-title small a:hover {
	color: var(--link);
	background: var(--band);
	border-color: var(--orange);
}
#site .cmt__reply a:focus-visible,
#site .comment-reply-title small a:focus-visible {
	outline: 2px solid var(--orange);
	outline-offset: 2px;
}
#site .cmts__closed {
	margin: 1.2rem 0 0;
	font-size: .88rem;
	color: var(--dim);
}

/* The form. Same shape as the screenshot form above — a stacked label/field
   row — because they are the only two places on the site a stranger types
   something and presses a button. */
#site .cmtform {
	margin-top: 1.6rem;
	padding: 1.15rem 1.25rem 1.25rem;
	background: var(--band);
	border: 1px solid var(--line);
	border-radius: 14px;
}
/* Pressing Reply swaps this heading's text and puts a Cancel reply pill inside
   it, and the pill is taller than the line of type it lands in - so the heading
   grew by a few pixels and shoved the form down at the moment of the click.
   A flex row with the pill's own height as a floor means the space is already
   reserved: the pill appears into it rather than pushing it open.

   The form still travels up the page to sit under the comment being answered.
   That move is core's comment-reply.js and is the point of the button; what is
   fixed here is the jolt that used to come with it. */
#site .comment-reply-title {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: .6ch;
	min-height: 1.5rem;
	font-family: var(--display);
	font-weight: var(--dw);
	font-size: 1rem;
	letter-spacing: var(--dls);
	margin: 1.8rem 0 0;
}
#site .cmtform__note {
	margin: 0 0 .8rem;
	font-size: .8rem;
	color: var(--dim);
}
#site .cmtform__row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .55rem;
	margin: 0 0 .7rem;
}
#site .cmtform__row label {
	flex: none;
	width: 7.5rem;
	font-family: var(--display);
	font-size: .82rem;
	color: var(--dim);
}
/* The textarea is a block, not a labelled row. A word in the left column
   beside a five-line box left "Comment" stranded at the top of a tall empty
   rectangle; the label is still there for screen readers (see
   inc/comments.php) and the placeholder carries the visible half. */
#site .cmtform__row--full {
	display: block;
}
#site .cmtform__row--full textarea {
	width: 100%;
}
#site .cmtform textarea::placeholder,
#site .cmtform input::placeholder {
	color: var(--dim);
	opacity: 1;
}
#site .cmtform input[type="text"],
#site .cmtform input[type="email"],
#site .cmtform textarea {
	flex: 1 1 16rem;
	min-width: 0;
	font-family: var(--display);
	font-size: .84rem;
	color: var(--ink);
	background: var(--bg);
	border: 1px solid var(--line);
	border-radius: 8px;
	padding: .45rem .6rem;
}
#site .cmtform textarea {
	line-height: 1.55;
	resize: vertical;
}
/* Right, under the fields rather than under the label column: the button is
   the end of the form, and every row above it has its right edge in the same
   place. */
#site .cmtform .form-submit {
	margin: 0;
	text-align: right;
}
#site .cmtform .form-submit input[type="submit"] {
	font-family: var(--display);
	font-size: .84rem;
}
/* Core prints "Cancel reply" inside the reply title, as a <small> around a
   link. The <small> is only a wrapper here — it is the <a> that gets drawn as
   the pill above, so this just gives it room and stops it inheriting the
   heading's size. */
#site .comment-reply-title small {
	font-size: 1rem;
	font-weight: 400;
}
/* The cookie opt-in is a checkbox and its sentence, not a labelled field, so it
   opts out of the label column the other rows share. */
#site .cmtform__row--check {
	gap: .4rem;
	font-size: .82rem;
	color: var(--dim);
}
#site .cmtform__row--check label {
	width: auto;
	flex: 1 1 auto;
	font-family: inherit;
	font-size: inherit;
}
/* A real Gravatar rather than the initials box. Same circle and same size, but
   an <img> needs the crop: the served file is square, and a theme that assumed
   so would stretch the first one that is not. */
#site .cmt__head .avatar--img {
	object-fit: cover;
	background: var(--band);
}
/* The required marker. Colour rather than weight: it sits inside a dim label,
   and a bolder asterisk in the same grey reads as a footnote. */
#site .cmtform__req {
	color: var(--orange);
}
/* Replying moves the form into the list, and core puts it there as a plain
   <div> sibling between two <li class="cmt">. The gap between comments lives on
   .cmt's own margin-bottom, which that div has not got, so the form's bottom
   edge sat flush against the comment underneath it — measured at 0px. It gets
   the same gap the comments give each other. The space above it comes from the
   .cmt it was opened under, so only this side was missing. */
#site .cmts__list #respond {
	margin-bottom: 1.1rem;
}

/* ── Cookie Notice ────────────────────────────────────────────────────
   The plugin prints its bar after #site has closed, so none of #site's custom
   properties reach it: the colours below are the dark theme's footer surfaces
   typed out, in both themes - a bar over the bottom of the page reads as part
   of the footer. It writes its background inline, hence the !important.

   After consent it keeps a "revoke" strip on every page. The old Divi theme
   shrank that to a tab peeking in at the right edge, with the sentence hidden
   and the button sliding out on hover - custom CSS kept in Divi's own options,
   which went with Divi. This is that tab again, in this theme's clothes. */
#cookie-notice {
	background-color: transparent !important;
	font-family: 'Figtree', system-ui, sans-serif;
	font-size: .9rem;
	line-height: 1.5;
	color: #ece0c9;
}
#cookie-notice .cookie-notice-container {
	padding: .9rem 1.25rem;
	background: #221b13;
	border-top: 1px solid #3a2f22;
}
#cookie-notice a,
#cookie-notice a:visited { color: #f56c27; }
#cookie-notice a:hover { color: #ff8a4d; }
#cookie-notice .cn-button.cn-button-custom {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	margin: 0 0 0 .75rem;
	padding: .45rem 1rem;
	font: 600 .85rem/1.2 'Figtree', system-ui, sans-serif;
	color: #17130e;
	background: #f56c27;
	border: 0;
	border-radius: 999px;
	cursor: pointer;
}
#cookie-notice .cn-button.cn-button-custom:hover { background: #ff8a4d; }
#cookie-notice .cn-button.cn-button-custom:focus-visible {
	outline: 2px solid #f56c27;
	outline-offset: 2px;
}

/* The tab. The strip under it is still full width, so it lets clicks through
   and only the button takes them. */
#cookie-notice.cookie-revoke-visible { pointer-events: none; }
#cookie-notice .cookie-revoke-container {
	padding: 0 0 .75rem;
	text-align: right;
}
#cookie-notice .cookie-revoke-container .cn-text-container { display: none; }
#cookie-notice .cookie-revoke-container .cn-revoke-cookie.cn-button-custom {
	pointer-events: auto;
	margin: 0;
	padding: .4rem .9rem .4rem .7rem;
	font-weight: 500;
	font-size: .8rem;
	color: #ece0c9;
	background: #221b13;
	border: 1px solid #3a2f22;
	border-right: 0;
	border-radius: 999px 0 0 999px;
	box-shadow: 0 6px 18px -8px rgba(0, 0, 0, .5);
	/* everything but the cookie tucked off the edge */
	transform: translateX(calc(100% - 2.05rem));
	transition: transform .25s ease;
}
#cookie-notice .cookie-revoke-container .cn-revoke-cookie.cn-button-custom:hover,
#cookie-notice .cookie-revoke-container .cn-revoke-cookie.cn-button-custom:focus-visible {
	transform: none;
	background: #2b2318;
}
/* the cookie: a disc with a bite out of it and three chips, as a mask so it
   takes the button's colour */
#cookie-notice .cookie-revoke-container .cn-revoke-cookie::before {
	content: "";
	flex: none;
	width: 1rem;
	height: 1rem;
	background: #f56c27;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a7 7 0 1 0 7 7 2.5 2.5 0 0 1-3-2.6A2.6 2.6 0 0 1 9.4 3 2 2 0 0 1 8 1zM5 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm1.5 4a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm3.5-1a1 1 0 1 1 0 2 1 1 0 0 1 0-2z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E") center / contain no-repeat;
	        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a7 7 0 1 0 7 7 2.5 2.5 0 0 1-3-2.6A2.6 2.6 0 0 1 9.4 3 2 2 0 0 1 8 1zM5 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm1.5 4a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm3.5-1a1 1 0 1 1 0 2 1 1 0 0 1 0-2z' fill='%23000' fill-rule='evenodd'/%3E%3C/svg%3E") center / contain no-repeat;
}
@media (prefers-reduced-motion: reduce) {
	#cookie-notice .cookie-revoke-container .cn-revoke-cookie.cn-button-custom { transition: none; }
}
