/*
 * myblog — the theme's only stylesheet.
 *
 * Copyright (C) 2026 kynzo
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 * Design ported from the earlier Astro build (projects/blog-v3): neutral grey
 * surfaces with a single green accent, expressed in OKLCH; a fluid modular
 * type scale; and Geist Mono everywhere, including body copy.
 *
 * Colour is entirely custom properties, so a redesign is a change to :root and
 * the dark-mode block and nothing else. There is deliberately no theme toggle —
 * the palette follows the browser/OS setting and nothing overrides it.
 */

/* ---------------------------------------------------------------- fonts */

/*
 * Self-hosted so there is no third-party request and no build step. Variable
 * weight axis 100-900. `swap` so text paints immediately in the fallback
 * monospace rather than blocking on the download.
 */
@font-face {
	font-family: 'Geist Mono Variable';
	font-style: normal;
	font-display: swap;
	font-weight: 100 900;
	src: url('../fonts/geist-mono-latin-wght-normal.woff2') format('woff2-variations');
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
		U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
		U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------------------------------------------------------------- tokens */

:root {
	--font-mono: 'Geist Mono Variable', ui-monospace, SFMono-Regular, 'SF Mono', Menlo,
		Consolas, 'Liberation Mono', monospace;

	/* Light — neutral greys, no warm or cool tint. */
	--color-bg: oklch(98% 0 0);
	--color-surface: oklch(95% 0 0);
	--color-fg: oklch(22% 0 0);
	--color-fg-muted: oklch(48% 0 0);
	--color-border: oklch(88% 0 0);

	--color-accent: oklch(52% 0.14 140);
	--color-accent-hover: oklch(45% 0.16 140);
	--color-accent-soft: oklch(88% 0.06 140);

	/* Reserved for destructive affordances: removing a filter, clearing them
	   all. Not the rant category's red, which happens to be a similar hue but
	   carries an unrelated meaning. */
	--color-danger: oklch(55% 0.19 25);

	/* Per-category accents. Hue carries the meaning; chroma and lightness are
	   held close so no one category shouts louder than the rest. */
	--type-essay: oklch(55% 0.1 140);
	--type-note: oklch(62% 0.11 70);
	--type-guide: oklch(58% 0.1 220);
	--type-log: oklch(60% 0.13 50);
	--type-rant: oklch(58% 0.16 25);
	--type-interview: oklch(58% 0.13 290);
	--type-recipe: oklch(62% 0.14 35);
	--type-link: oklch(55% 0.1 140);

	/* Fluid type scale, pinned endpoints. */
	--size-step--2: clamp(0.78rem, 0.74rem + 0.18vw, 0.89rem);
	--size-step--1: clamp(0.88rem, 0.82rem + 0.27vw, 1.04rem);
	--size-step-0: clamp(1rem, 0.91rem + 0.43vw, 1.25rem);
	--size-step-1: clamp(1.13rem, 1rem + 0.65vw, 1.5rem);
	--size-step-2: clamp(1.27rem, 1.09rem + 0.92vw, 1.8rem);
	--size-step-3: clamp(1.42rem, 1.18rem + 1.25vw, 2.16rem);
	--size-step-4: clamp(1.6rem, 1.27rem + 1.66vw, 2.59rem);
	--size-step-5: clamp(1.8rem, 1.36rem + 2.18vw, 3.11rem);
	--size-step-6: clamp(2.03rem, 1.46rem + 2.83vw, 3.73rem);

	/* Layout */
	--content-width: 65ch;
	--site-max: 1200px;
	--space-gutter: clamp(1rem, 0.5rem + 1.5vw, 2rem);
	--radius-sm: 0.25rem;
	--radius-md: 0.5rem;
	--radius-lg: 0.75rem;
}

@media (prefers-color-scheme: dark) {
	:root {
		/* Neutral medium-dark grey, deliberately not black. */
		--color-bg: oklch(22% 0 0);
		--color-surface: oklch(27% 0 0);
		--color-fg: oklch(92% 0 0);
		--color-fg-muted: oklch(68% 0 0);
		--color-border: oklch(35% 0 0);

		--color-accent: oklch(75% 0.16 140);
		--color-accent-hover: oklch(82% 0.16 140);
		--color-accent-soft: oklch(32% 0.1 140);

		--color-danger: oklch(74% 0.17 25);

		--type-essay: oklch(75% 0.13 140);
		--type-note: oklch(78% 0.13 70);
		--type-guide: oklch(75% 0.12 220);
		--type-log: oklch(75% 0.14 50);
		--type-rant: oklch(72% 0.17 25);
		--type-interview: oklch(74% 0.15 290);
		--type-recipe: oklch(75% 0.16 35);
		--type-link: oklch(75% 0.13 140);
	}
}

/* ------------------------------------------------------------------ reset */

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

* {
	margin: 0;
}

/*
 * html carries the background so the over-scroll area is covered. Capping the
 * body height instead leaves a lighter strip above the content when scrolling.
 */
html {
	background-color: var(--color-bg);
	font-family: var(--font-mono);
	font-size: 100%;
	font-weight: 400;
	/* Geist Mono stylistic alternates: more legible 0 and 1. */
	font-feature-settings: 'ss01' on, 'cv11' on;
	color-scheme: light dark;
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
}

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

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}
}

body {
	background-color: var(--color-bg);
	color: var(--color-fg);
	font-size: var(--size-step-0);
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
	padding-inline: var(--space-gutter);
}

img,
picture,
video,
canvas,
svg,
iframe {
	display: block;
	max-width: 100%;
}

img,
video,
iframe {
	height: auto;
}

input,
button,
textarea,
select {
	font: inherit;
	color: inherit;
}

p,
h1,
h2,
h3,
h4,
h5,
h6 {
	overflow-wrap: break-word;
	text-wrap: pretty;
}

h1,
h2,
h3,
h4,
h5,
h6 {
	text-wrap: balance;
}

a {
	color: inherit;
	text-decoration-thickness: 0.08em;
	text-underline-offset: 0.15em;
}

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

:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
	border-radius: var(--radius-sm);
}

/* -------------------------------------------------------------- typography */

h1 {
	font-size: var(--size-step-5);
	font-weight: 700;
	letter-spacing: -0.02em;
	border-bottom: 2px solid var(--color-accent-soft);
	padding-bottom: 0.3em;
}

h2 {
	font-size: var(--size-step-3);
	font-weight: 600;
	letter-spacing: -0.015em;
}

h3 {
	font-size: var(--size-step-2);
	font-weight: 600;
}

h4 {
	font-size: var(--size-step-1);
	font-weight: 600;
}

h5,
h6 {
	font-size: var(--size-step-0);
	font-weight: 600;
}

small {
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
}

code,
pre,
kbd,
samp {
	font-family: var(--font-mono);
}

code {
	font-size: 0.95em;
	padding: 0.125em 0.3em;
	background-color: var(--color-surface);
	border-radius: var(--radius-sm);
}

pre {
	font-size: var(--size-step--1);
	line-height: 1.6;
	overflow-x: auto;
	padding: 1rem;
	background-color: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
}

pre code {
	padding: 0;
	background: none;
	font-size: inherit;
}

blockquote {
	border-inline-start: 3px solid var(--color-accent-soft);
	padding-inline-start: 1.2rem;
	color: var(--color-fg-muted);
}

hr {
	border: none;
	border-top: 1px solid var(--color-border);
	margin-block: 2rem;
}

table {
	border-collapse: collapse;
	width: 100%;
	font-size: var(--size-step--1);
}

th,
td {
	border: 1px solid var(--color-border);
	padding: 0.5em 0.7em;
	text-align: start;
}

th {
	background-color: var(--color-surface);
	font-weight: 600;
}

/* ------------------------------------------------------------ a11y utils */

.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.screen-reader-text:focus,
.skip-link:focus {
	clip-path: none;
	background-color: var(--color-surface);
	border: 2px solid var(--color-accent);
	border-radius: var(--radius-md);
	color: var(--color-fg);
	display: block;
	font-weight: 700;
	height: auto;
	inset-inline-start: 1rem;
	inset-block-start: 1rem;
	line-height: normal;
	margin: 0;
	padding: 0.8em 1.2em;
	position: fixed;
	text-decoration: none;
	width: auto;
	z-index: 100000;
}

/* ---------------------------------------------------------------- layout */

.site {
	display: flex;
	flex-direction: column;
	min-height: 100vh;
}

.site-shell {
	width: 100%;
	max-width: var(--site-max);
	margin-inline: auto;
}

.site-main {
	flex: 1 0 auto;
}

/* The reading column. Everything long-form sits in here. */
.prose {
	max-width: var(--content-width);
	margin-inline: auto;
}

/*
 * Vertical rhythm for flow content.
 *
 * Two levels, deliberately: on pages that print the_content() straight into
 * .prose the body markup is a direct child, but on single posts it is wrapped
 * in .entry-content. Without the second selector everything inside a post body
 * collapses to zero spacing, because the reset above strips all margins.
 */
.prose > * + *,
.prose .entry-content > * + * {
	margin-block-start: 1.25em;
}

.prose h2,
.prose h3,
.prose h4 {
	margin-block-start: 2em;
	margin-block-end: 0.5em;
}

.prose a {
	color: var(--color-accent);
	text-decoration-color: color-mix(in oklch, var(--color-accent) 50%, transparent);
}

.prose a:hover {
	color: var(--color-accent-hover);
	text-decoration-color: var(--color-accent-hover);
}

.prose ul,
.prose ol {
	padding-inline-start: 1.4em;
}

.prose li + li {
	margin-block-start: 0.4em;
}

.prose img {
	border-radius: var(--radius-md);
}

.prose figure {
	margin-inline: 0;
}

.prose figcaption,
.wp-element-caption {
	color: var(--color-fg-muted);
	font-size: var(--size-step--1);
	text-align: center;
	margin-block-start: 0.5rem;
}

/*
 * Wide and full blocks break out of the reading column. Both are clamped to
 * the shell width so nothing can cause a horizontal scrollbar.
 */
.prose > .alignwide,
.prose > .alignfull {
	width: 100%;
	max-width: none;
}

/* ---------------------------------------------------------------- header */

.site-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	flex-wrap: wrap;
	padding-block: 1.25rem 1rem;
	border-bottom: 1px solid var(--color-border);
	margin-bottom: 2.5rem;
}

.site-branding {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	min-width: 0;
}

.site-branding .custom-logo-link {
	display: block;
	flex-shrink: 0;
	line-height: 0;
}

.site-branding .custom-logo {
	width: auto;
	height: 2.25rem;
	border-radius: var(--radius-sm);
}

.site-title {
	font-size: var(--size-step-1);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.2;
	/* h1 elsewhere carries an accent underline; the brand must not. */
	border-bottom: 0;
	padding-bottom: 0;
}

.site-title a {
	color: var(--color-fg);
	text-decoration: none;
}

.site-title a:hover {
	color: var(--color-accent);
}

.site-description {
	color: var(--color-fg-muted);
	font-size: var(--size-step--2);
	flex-basis: 100%;
	margin-block-start: -0.6rem;
}

.main-navigation ul {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 1.25rem;
	list-style: none;
	margin: 0;
	padding: 0;
	font-size: var(--size-step--1);
}

.main-navigation a {
	color: var(--color-fg-muted);
	text-decoration: none;
	transition: color 0.15s ease;
}

.main-navigation a:hover {
	color: var(--color-accent);
}

.main-navigation .current-menu-item > a,
.main-navigation .current_page_item > a,
.main-navigation .current-menu-ancestor > a,
.main-navigation .current-post-ancestor > a,
.main-navigation .current_page_parent > a {
	color: var(--color-accent);
}

/* ------------------------------------------------------------------ home */

.intro {
	margin-block: 1.5rem 4rem;
}

.intro-inner {
	display: grid;
	grid-template-columns: 320px minmax(0, 1fr);
	gap: 3rem;
	align-items: center;
}

.intro-inner--no-avatar {
	grid-template-columns: minmax(0, 1fr);
}

.intro-avatar {
	width: 320px;
	height: 320px;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: 1rem;
	border: 1px solid var(--color-border);
}

.intro-text {
	min-width: 0;
	max-width: none;
	margin-inline: 0;
}

.intro-text h1 {
	font-size: var(--size-step-6);
	margin-block-end: 0.5em;
}

.intro-text p {
	font-size: var(--size-step-1);
	line-height: 1.6;
}

@media (max-width: 900px) {
	.intro-inner {
		grid-template-columns: minmax(0, 1fr);
		gap: 1.75rem;
		justify-items: start;
	}

	.intro-avatar {
		width: 200px;
		height: 200px;
	}
}

.section-header {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	flex-wrap: wrap;
	margin-bottom: 1.5rem;
}

.section-header h2 {
	margin: 0;
}

.see-all {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	white-space: nowrap;
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
	text-decoration: none;
}

.see-all:hover {
	color: var(--color-accent);
}

/* ---------------------------------------------------------- filter bar */

.filters {
	margin-block-end: 1.75rem;
	padding: 0.9rem 1rem;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: color-mix(in oklch, var(--color-surface) 60%, transparent);
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
}

.filter-row {
	display: flex;
	align-items: baseline;
	gap: 0.75rem;
	flex-wrap: wrap;
}

.filter-label {
	flex-shrink: 0;
	width: 4.5rem;
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	text-transform: lowercase;
	letter-spacing: 0.05em;
}

.filter-controls {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.45rem;
	flex: 1 1 16rem;
	min-width: 0;
}

.filter-row--search {
	gap: 0.5rem;
}

.filter-row--search .filter-search {
	flex: 1 1 16rem;
	display: block;
}

/*
 * The submit button is the no-JS path: without it the search box could not be
 * used at all. The script hides it, because with the script the search runs as
 * you type and a submit button would just be a second way to do nothing new.
 */
.filter-submit {
	font-size: var(--size-step--2);
	color: var(--color-bg);
	background-color: var(--color-accent);
	border: 1px solid var(--color-accent);
	border-radius: var(--radius-sm);
	padding: 0.45em 0.9em;
	cursor: pointer;
	white-space: nowrap;
}

.filter-submit:hover {
	background-color: var(--color-accent-hover);
	border-color: var(--color-accent-hover);
}

/* Chips, pills and clear are anchors now; they must not look like body links. */
.filter-chip,
.tag-pill,
.posts-clear,
.tag-panel__add {
	text-decoration: none;
}

.filter-search__input,
.tag-panel__input {
	width: 100%;
	font-size: var(--size-step--1);
	color: var(--color-fg);
	background-color: var(--color-bg);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	padding: 0.5em 0.7em;
}

.filter-search__input:focus,
.tag-panel__input:focus {
	border-color: var(--color-accent);
	outline: none;
}

/* Category chips reuse .type-chip, so they carry the category's own colour. */
.filter-chip {
	cursor: pointer;
	background-color: transparent;
	opacity: 0.75;
	transition: opacity 0.15s ease, background-color 0.15s ease;
}

.filter-chip:hover:not( :disabled ) {
	opacity: 1;
}

.filter-chip.is-active {
	opacity: 1;
	background-color: color-mix(in oklch, var(--type-color, var(--color-accent)) 22%, transparent);
	box-shadow: inset 0 0 0 1px var(--type-color, var(--color-accent));
}

.filter-chip:disabled {
	opacity: 0.3;
	cursor: default;
}

.filter-chip__count {
	font-variant-numeric: tabular-nums;
	opacity: 0.7;
}

/* Selected tags, shown inline and removable. */
.tag-filter {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.4rem;
}

.tag-pill {
	display: inline-flex;
	align-items: center;
	gap: 0.35em;
	cursor: pointer;
	font-size: var(--size-step--2);
	color: var(--color-fg);
	background-color: color-mix(in oklch, var(--color-accent) 18%, transparent);
	border: 1px solid var(--color-accent);
	border-radius: 999px;
	padding: 0.2em 0.65em;
}

.tag-pill:hover,
.tag-pill:focus-visible {
	color: var(--color-danger);
	border-color: var(--color-danger);
	background-color: color-mix(in oklch, var(--color-danger) 18%, transparent);
}

/* The × is the thing being confirmed, so it leads the colour change. */
.tag-pill:hover span[aria-hidden] {
	font-weight: 700;
}

.tag-trigger-wrap {
	position: relative;
}

.tag-trigger,
.filter-sort__select,
.posts-clear {
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	background-color: var(--color-bg);
	border: 1px dashed var(--color-border);
	border-radius: 999px;
	padding: 0.25em 0.7em;
	cursor: pointer;
}

.filter-sort__select {
	border-style: solid;
	border-radius: var(--radius-sm);
}

.tag-trigger:hover {
	color: var(--color-accent);
	border-color: var(--color-accent);
}

/*
 * Pushed to the end of the last filter row, which puts it at the bottom right
 * of the bar — away from the controls that add filters, since it undoes them.
 */
.posts-clear {
	margin-inline-start: auto;
}

.posts-clear:hover,
.posts-clear:focus-visible {
	color: var(--color-danger);
	border-color: var(--color-danger);
	background-color: color-mix(in oklch, var(--color-danger) 12%, transparent);
}

.tag-panel {
	position: absolute;
	z-index: 20;
	inset-block-start: calc(100% + 0.4rem);
	inset-inline-start: 0;
	width: min(18rem, 80vw);
	padding: 0.6rem;
	background-color: var(--color-bg);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
}

.tag-panel__list {
	list-style: none;
	margin: 0.5rem 0 0;
	padding: 0;
	max-height: 15rem;
	overflow-y: auto;
}

.tag-panel__add {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	width: 100%;
	text-align: start;
	font-size: var(--size-step--2);
	color: var(--color-fg);
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	padding: 0.35em 0.5em;
	cursor: pointer;
}

.tag-panel__add:hover {
	background-color: var(--color-surface);
	color: var(--color-accent);
}

.tag-panel__count {
	color: var(--color-fg-muted);
	font-variant-numeric: tabular-nums;
}

.tag-panel__empty {
	margin: 0.5rem 0 0;
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	text-align: center;
}

.posts-count {
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	font-variant-numeric: tabular-nums;
	margin-inline-start: auto;
}

.posts-empty {
	color: var(--color-fg-muted);
	text-align: center;
	padding-block: 3rem;
}

@media (max-width: 560px) {
	.filter-label {
		width: 100%;
	}

	.posts-count {
		margin-inline-start: 0;
	}
}

/* ------------------------------------------------------------ post grid */

/*
 * Column-based masonry. Cards vary in height and `break-inside: avoid` keeps
 * each one whole. The trade-off is that reading order runs down each column
 * rather than across, which suits a browsable archive.
 */
.post-grid {
	column-count: 1;
	column-gap: 1.5rem;
	column-fill: balance;
}

@media (min-width: 700px) {
	.post-grid {
		column-count: 2;
	}
}

@media (min-width: 1100px) {
	.post-grid {
		column-count: 3;
	}
}

.post-grid > * {
	break-inside: avoid;
	margin-bottom: 1.5rem;
	display: block;
	width: 100%;
}

.post-card {
	position: relative;
	background-color: var(--color-surface);
	border: 2px solid var(--color-border);
	border-radius: var(--radius-md);
	overflow: hidden;
	transition: border-color 0.18s ease, transform 0.18s ease;
}

.post-card:hover {
	border-color: var(--color-accent);
	transform: translateY(-1px);
}

/*
 * The card's whole surface is the link. The browser would paint its own focus
 * ring on the inner <a> in its own colour, so that is suppressed and the state
 * is shown on the card instead — same affordance, right palette.
 */
.post-card .card-link,
.post-card .card-link:hover,
.post-card .card-link:focus,
.post-card .card-link:focus-visible {
	display: block;
	text-decoration: none;
	color: inherit;
	outline: none;
}

.post-card:focus-within {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
}

.post-card .card-link:hover .card-title {
	color: var(--color-accent);
}

.card-cover {
	width: 100%;
	aspect-ratio: 16 / 10;
	object-fit: cover;
	border-radius: 0;
}

.card-body {
	padding: 1rem;
}

.card-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	align-items: center;
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	margin-bottom: 0.6rem;
}

.card-title {
	font-size: var(--size-step-2);
	font-weight: 600;
	letter-spacing: -0.02em;
	line-height: 1.25;
	margin-block: 0 0.5rem;
	/* Cards use h2/h3; the accent underline belongs to page titles only. */
	border-bottom: 0;
	padding-bottom: 0;
}

.card-excerpt {
	color: var(--color-fg-muted);
	font-size: var(--size-step--1);
	line-height: 1.5;
}

.card-excerpt p {
	margin: 0;
}

/* ------------------------------------------------- category treatments */

/*
 * Every category binds --type-color, and everything below reads from it: the
 * chip, the hover border, the focus ring, the icons. Adding a category is a
 * colour token, an icon, and one rule here.
 */
.is-type-essay {
	--type-color: var(--type-essay);
}

.is-type-note {
	--type-color: var(--type-note);
}

.is-type-guide {
	--type-color: var(--type-guide);
}

.is-type-log {
	--type-color: var(--type-log);
}

.is-type-rant {
	--type-color: var(--type-rant);
}

.is-type-interview {
	--type-color: var(--type-interview);
}

.is-type-recipe {
	--type-color: var(--type-recipe);
}

.is-type-link {
	--type-color: var(--type-link);
}

/* Typed cards take their category's colour on hover and focus. */
.post-card:hover {
	border-color: var(--type-color, var(--color-accent));
}

.post-card:focus-within {
	outline-color: var(--type-color, var(--color-accent));
}

.post-card .card-link:hover .card-title {
	color: var(--type-color, var(--color-accent));
}

/*
 * Border signatures. Each category gets a distinct combination of style, width
 * and radius, so a grid of mixed posts has visible texture rather than eight
 * identical rectangles in different colours.
 */

/* Essay — editorial neutrality: a clean frame, nothing else. */
.post-card.is-type-essay {
	border-style: solid;
	border-width: 2px;
}

/* Note — notebook page: thinner dashed edge, rounder corners. */
.post-card.is-type-note {
	border-style: dashed;
	border-width: 2px;
	border-radius: 1.1rem;
}

/* Guide — tutorial header: a heavier top edge. */
.post-card.is-type-guide {
	border-top-width: 6px;
}

/* Log — daybook tab: heavier right edge, plus binding holes down the left. */
.post-card.is-type-log {
	border-right-width: 6px;
	--log-dot: var(--color-border);
}

.post-card.is-type-log:hover {
	--log-dot: var(--type-log);
}

.post-card.is-type-log::before {
	content: '';
	position: absolute;
	inset-inline-start: 5px;
	inset-block: 18px;
	width: 5px;
	background-image: radial-gradient(
		circle at 50% 50%,
		var(--log-dot) 0,
		var(--log-dot) 1.5px,
		transparent 1.9px
	);
	background-size: 5px 16px;
	background-repeat: repeat-y;
	background-position: center top;
	pointer-events: none;
	z-index: 1;
}

/* Rant — corner banner: heavier top and left, and a faint tint. */
.post-card.is-type-rant {
	border-top-width: 6px;
	border-left-width: 6px;
	background-color: color-mix(in oklch, var(--type-rant) 6%, var(--color-surface));
}

/* Interview — conversational: double rule, larger radius. */
.post-card.is-type-interview {
	border-style: double;
	border-width: 6px;
	border-radius: var(--radius-lg);
}

/* Recipe — kitchen card: extra-rounded corners. */
.post-card.is-type-recipe {
	border-width: 3px;
	border-radius: 1.25rem;
}

/* Link — outbound signal boost: dashed, slightly rounder. */
.post-card.is-type-link {
	border-style: dashed;
	border-width: 3px;
	border-radius: 0.6rem;
}

/* The chip itself. */
.type-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.3em;
	padding: 0.2em 0.55em;
	border-radius: var(--radius-sm);
	border: 1px solid var(--type-color, var(--color-border));
	color: var(--type-color, var(--color-fg-muted));
	background-color: color-mix(in oklch, var(--type-color, var(--color-fg-muted)) 12%, transparent);
	font-size: var(--size-step--2);
	text-transform: lowercase;
	letter-spacing: 0.05em;
	line-height: 1.2;
	white-space: nowrap;
	text-decoration: none;
}

.type-chip svg {
	flex-shrink: 0;
}

/*
 * On a single post the chip is a link inside .prose, and `.prose a` — a class
 * plus an element — outweighs the bare `.type-chip` class, so the label came
 * out accent green instead of the category's own colour. Naming the element
 * ties the weight and wins on order.
 */
a.type-chip,
a.type-chip:hover,
a.type-chip:focus-visible {
	color: var(--type-color, var(--color-fg-muted));
	text-decoration: none;
}

a.type-chip:hover {
	background-color: color-mix(in oklch, var(--type-color, var(--color-fg-muted)) 22%, transparent);
}

/* Link's chip is dashed too, matching its card. */
.type-chip--link {
	border-style: dashed;
}

/* Card header variants ---------------------------------------------------- */

/* Note, rant and interview lead with the icon beside the title. */
.card-icon-header {
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
	margin-bottom: 0.6rem;
}

.card-icon-header svg {
	flex-shrink: 0;
	color: var(--type-color, var(--color-fg-muted));
	margin-top: 0.15em;
}

.card-icon-header .card-title {
	font-size: var(--size-step-1);
	margin-block: 0;
}

/* Rant titles are set in italic — the one place type style carries meaning. */
.is-type-rant .card-title,
.entry--single.is-type-rant .entry-title {
	font-style: italic;
}

/* Log leads with the date, large and in its own colour. */
.card-log-hero {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 1rem;
	padding: 1rem 1rem 0.5rem;
	padding-inline-start: 1.5rem;
}

.card-log-date {
	font-size: var(--size-step-3);
	font-weight: 700;
	color: var(--type-log);
	line-height: 1;
	letter-spacing: -0.02em;
}

.card-log-weekday {
	display: block;
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
	line-height: 1.4;
}

.card-log-hero svg {
	color: var(--color-fg-muted);
	opacity: 0.6;
	flex-shrink: 0;
}

/* Log's binding dots sit at the left edge, so its body clears them. */
.is-type-log .card-body,
.is-type-log .card-tags {
	padding-inline-start: 1.5rem;
}

/* Guide shows its compass in a band above the title. */
.card-guide-band {
	padding: 1rem 1rem 0;
	color: var(--type-guide);
}

/* Rendered outside the card link so each tag stays individually clickable. */
.card-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem;
	padding: 0 1rem 1rem;
}

.tag-chip {
	display: inline-flex;
	align-items: center;
	white-space: nowrap;
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	text-decoration: none;
	border: 1px solid var(--color-border);
	border-radius: 999px;
	padding: 0.15em 0.6em;
	background-color: var(--color-bg);
}

/*
 * Same trap as the category chip: inside .prose these are links, and
 * `.prose a` outweighs a bare `.tag-chip`, so on a single post every tag came
 * out accent green. Naming the element ties the weight and wins on order.
 */
a.tag-chip {
	color: var(--color-fg-muted);
	text-decoration: none;
}

a.tag-chip:hover,
a.tag-chip:focus-visible {
	color: var(--color-accent);
	border-color: var(--color-accent);
}

/* -------------------------------------------------------------- archives */

.page-header {
	margin-bottom: 2.5rem;
}

.page-title {
	margin: 0;
}

.archive-description {
	color: var(--color-fg-muted);
	font-size: var(--size-step--1);
	margin-block-start: 0.75rem;
}

/* ----------------------------------------------------------- single post */

.entry--single .entry-header,
.entry--page .entry-header {
	margin-bottom: 2rem;
}

/*
 * A page spans the shell, not the reading column.
 *
 * `.prose` is kept for its typography, but its max-width is not what a page
 * wants: the front page already widens `.intro-text` the same way, so leaving
 * this constrained made every ordinary page ~400px narrower than the front
 * page and indented relative to the header above it.
 */
.entry--page {
	max-width: none;
	margin-inline: 0;
}

.entry-type {
	margin-block-end: 0.9rem;
}

.entry-title {
	margin-block-end: 0.5rem;
}

/*
 * On a typed post the title's underline takes the category's colour, so the
 * page reads as belonging to that category before you get to the chip.
 */
.entry--single[class*='is-type-'] .entry-title {
	border-bottom-color: color-mix(in oklch, var(--type-color) 35%, transparent);
}

/* The rant disclaimer, from the category description. */
.entry-disclaimer {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-block-start: 1.5rem;
	padding: 0.7rem 0.9rem;
	border: 1px solid color-mix(in oklch, var(--type-rant) 40%, transparent);
	background-color: color-mix(in oklch, var(--type-rant) 8%, transparent);
	border-radius: var(--radius-md);
	color: var(--color-fg-muted);
	font-size: var(--size-step--1);
	font-style: italic;
}

.entry-disclaimer svg {
	flex-shrink: 0;
	color: var(--type-rant);
}

.entry-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 1rem;
	align-items: center;
	color: var(--color-fg-muted);
	font-size: var(--size-step--1);
	margin-block-start: 1rem;
}

.entry-meta a {
	color: inherit;
}

/*
 * The tag row moved into the header, under the meta line. It is a separate
 * block rather than another item in .entry-meta so it wraps as its own row
 * instead of trailing off the end of the date and byline.
 */
.entry-header .tags-links {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	align-items: center;
	margin-block-start: 0.9rem;
}

.entry-meta a:hover {
	color: var(--color-accent);
}

.post-thumbnail {
	display: block;
	margin-block-end: 2rem;
}

.post-thumbnail img {
	border-radius: var(--radius-md);
	width: 100%;
}

.entry-footer {
	margin-block-start: 2.5rem;
	padding-block-start: 1.25rem;
	border-block-start: 1px solid var(--color-border);
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	align-items: center;
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
}

/* ------------------------------------------------------------- members */

/*
 * The About page grid.
 *
 * Landscape cards — picture beside the text, not above it — so a row of them
 * reads across rather than as three tall columns. The cards are wide, so the
 * grid fits two or three across the shell and drops to one on a phone without
 * any breakpoint of its own.
 *
 * .prose ul indents lists for their bullets and .prose li + li spaces list
 * items apart; both land on this grid and both have to be undone, or the cards
 * sit indented and each one after the first is nudged out of line.
 *
 * Note the `ul.` on the list selectors below. `.prose ul` is a class plus an
 * element, so a bare `.member-tags` is *lighter* and loses — the chips keep
 * the bullet indent and sit shifted right of the text above them, which reads
 * as a bad centring rather than as an indent. Naming the element ties the
 * specificity and wins on order, in the reading column and out of it.
 */

ul.member-grid {
	list-style: none;
	margin: 2rem 0;
	padding-inline-start: 0;
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(auto-fill, minmax(min(22rem, 100%), 1fr));
}

.prose .member-grid > li + li {
	margin-block-start: 0;
}

.member-card {
	position: relative;
	display: flex;
	background-color: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	transition: border-color 0.15s ease;
}

.member-card:hover {
	border-color: var(--color-accent);
}

.member-card:focus-within {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
}

.member-card__link,
.member-card__link:hover,
.member-card__link:focus,
.member-card__link:focus-visible {
	display: flex;
	flex: 1;
	align-items: flex-start;
	gap: 1rem;
	padding: 1rem;
	text-decoration: none;
	color: inherit;
	outline: none;
}

/*
 * Two classes, not one: .prose img sets a small border-radius on every image
 * in the reading column and would otherwise win on specificity, leaving a
 * rounded square behind each round avatar.
 */
.member-card .member-card__picture {
	width: 72px;
	height: 72px;
	flex-shrink: 0;
	border-radius: 50%;
	object-fit: cover;
	background-color: var(--color-bg);
}

/* A column, so the chips can be pushed to the bottom of the text block. */
.member-card__text {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	min-width: 0;
	flex: 1;
	align-self: stretch;
}

.member-card__name {
	font-size: var(--size-step-0);
	font-weight: 600;
	line-height: 1.25;
}

.member-card__link:hover .member-card__name {
	color: var(--color-accent);
}

.member-card__tagline {
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
	line-height: 1.45;
}

/* Tags are labels, not links — no hover, no pointer, nothing to click. */
/*
 * The chips are a <ul> on the profile header and a run of <span>s inside a
 * card, so the shared rule cannot name an element. `ul.member-tags` carries
 * only the list reset, and needs the element in its selector to outweigh
 * `.prose ul`, which would otherwise indent the chips for bullets they do not
 * have.
 */
.member-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem;
	margin: 0;
}

ul.member-tags {
	list-style: none;
	padding-inline-start: 0;
}

.prose .member-tags > li + li {
	margin-block-start: 0;
}

/*
 * Bottom of the text block, so a one-line tagline and a three-line one still
 * put their chips on the same baseline across a row of equal-height cards.
 */
.member-tags--card {
	margin-block-start: auto;
	padding-block-start: 0.6rem;
}

.member-tag {
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	border: 1px solid var(--color-border);
	border-radius: 999px;
	padding: 0.15em 0.6em;
	background-color: var(--color-bg);
	white-space: nowrap;
	line-height: 1.6;
}

/* --- author cards under a post */

/*
 * The same grid as the About page. One author gets one wide card rather than a
 * card stretched across the page, which is what makes the two views read as
 * the same component.
 */
/* `ul.` again: the base `ul.member-grid` sets margin-inline through its
 * shorthand and would otherwise outweigh this and keep the grid hard left. */
ul.member-grid--authors {
	margin-block-start: 3rem;
	/*
	 * Lined up with the post body, not the shell. These cards belong to the
	 * article above them, and the replies below them are in the same column —
	 * spanning the full width left them starting at the far edge while
	 * everything around them was indented.
	 */
	max-width: var(--content-width);
	margin-inline: auto;
}

/* --- the byline: a small picture, and the card on hover */

.byline-author {
	position: relative;
	display: inline-block;
	/* The picture and the name are one unit; never break between them. */
	white-space: nowrap;
}

/*
 * The picture is an ordinary inline image next to the link, offset from the
 * baseline so it sits centred on the text rather than resting on it. It is not
 * a flex item: an inline-flex box takes its baseline from its first child, and
 * an image's baseline is its bottom edge — so the whole link rode high and the
 * words between the names dropped by a few pixels.
 */
.byline-avatar {
	width: 1.25em;
	height: 1.25em;
	border-radius: 50%;
	object-fit: cover;
	background-color: var(--color-surface);
	display: inline-block;
	vertical-align: -0.35em;
	margin-inline-end: 0.35em;
}

/*
 * The card is in the page already, hidden — not fetched on hover — so it needs
 * no JavaScript and appears with no wait. visibility rather than display:none
 * so it can be transitioned, and so it is still reachable by the keyboard
 * through :focus-within.
 */
.byline-card {
	/*
	 * .byline-author carries white-space: nowrap so a picture and the name
	 * beside it never break apart. The card is a descendant of that element,
	 * so it inherited the rule and its tagline ran straight out of the box and
	 * across the page instead of wrapping.
	 */
	white-space: normal;
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: calc(100% + 0.5rem);
	z-index: 20;
	/* Matches the About card's minimum, so the two are the same shape. */
	width: max(22rem, 100%);
	opacity: 0;
	visibility: hidden;
	transform: translateY(-0.25rem);
	transition: opacity 0.12s ease, transform 0.12s ease, visibility 0.12s;
	pointer-events: none;
}

.byline-author:hover .byline-card,
.byline-author:focus-within .byline-card {
	opacity: 1;
	visibility: visible;
	transform: none;
}

/* Cards near the right edge would otherwise push the page sideways. */
.byline-author:last-child .byline-card {
	inset-inline-start: auto;
	inset-inline-end: 0;
}

.member-card--hover {
	box-shadow: 0 8px 24px rgb(0 0 0 / 35%);
	background-color: var(--color-surface);
	text-align: start;
	/*
	 * The card lives inside .entry-meta, which is muted and a step smaller.
	 * Without resetting both, the card inherits the byline's styling and reads
	 * as part of the meta line rather than as a card.
	 */
	color: var(--color-fg);
	font-size: var(--size-step--1);
}

.member-card--hover .member-card__name {
	color: var(--color-fg);
}

/* Nothing inside the hover card is clickable, so it must not look it. */
.member-card--hover .member-card__link {
	cursor: default;
}

.member-card--hover:hover {
	border-color: var(--color-border);
}

@media (prefers-reduced-motion: reduce) {
	.byline-card {
		transition: none;
		transform: none;
	}
}

/*
 * Nothing here hides the card on a touch screen. `@media (hover: none)` looked
 * like the right guard and is not: a laptop with a touchscreen can report it,
 * and the card then never appears on a device that can hover perfectly well.
 * Since it only ever shows on :hover or :focus-within, and carries
 * pointer-events: none so it cannot swallow a tap, a device that cannot hover
 * simply never triggers it.
 */

/* --- the profile page an About card links to */

.member-profile {
	display: flex;
	gap: 1.5rem;
	align-items: flex-start;
	flex-wrap: wrap;
	margin-block-end: 2.5rem;
	padding-block-end: 1.5rem;
	border-block-end: 1px solid var(--color-border);
}

.member-profile .member-profile__picture {
	width: 160px;
	height: 160px;
	border-radius: 50%;
	object-fit: cover;
	background-color: var(--color-surface);
	flex-shrink: 0;
}

.member-profile__text {
	flex: 1 1 20rem;
	min-width: 0;
}

.member-profile__name {
	margin: 0;
	font-size: var(--size-step-3);
	line-height: 1.1;
	border-bottom: 0;
	padding-bottom: 0;
}

.member-profile__tagline {
	margin: 0.4rem 0 0;
	color: var(--color-fg-muted);
	font-size: var(--size-step-0);
}

.member-tags--profile {
	margin-block-start: 0.9rem;
}

.member-profile__bio {
	margin: 1rem 0 0;
	max-width: var(--content-width);
}

/*
 * Links row. The icons are the theme's own stroke set, so they take their
 * colour from the text and pick up the accent on hover like any other link.
 */
ul.member-links {
	list-style: none;
	margin: 1.1rem 0 0;
	padding-inline-start: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
}

.prose .member-links > li + li {
	margin-block-start: 0;
}

.member-link__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	color: var(--color-fg-muted);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-bg);
	text-decoration: none;
	transition: color 0.15s ease, border-color 0.15s ease;
}

.member-link__link:hover,
.member-link__link:focus-visible {
	color: var(--color-accent);
	border-color: var(--color-accent);
}

/*
 * Uploaded icons are arbitrary artwork rather than stroke glyphs, so they
 * cannot inherit currentColor. Sizing them to match is all that keeps the row
 * even.
 */
.member-link__custom-icon {
	width: 20px;
	height: 20px;
	object-fit: contain;
	border-radius: 0;
}

.member-profile__count {
	margin: 1rem 0 0;
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
}

@media (max-width: 30rem) {
	.member-profile {
		gap: 1rem;
	}

	.member-profile .member-profile__picture {
		width: 96px;
		height: 96px;
	}
}

/* ------------------------------------------------------------ navigation */

.pagination {
	margin-block-start: 3rem;
	padding-block-start: 1.5rem;
	border-block-start: 1px solid var(--color-border);
	font-size: var(--size-step--1);
}

.pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	align-items: center;
}

.pagination .page-numbers {
	padding: 0.35em 0.75em;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	text-decoration: none;
	color: var(--color-fg-muted);
}

.pagination .page-numbers:hover {
	color: var(--color-accent);
	border-color: var(--color-accent);
}

.pagination .page-numbers.current {
	background-color: var(--color-accent);
	border-color: var(--color-accent);
	color: var(--color-bg);
}

/* -------------------------------------------------------------- comments */

.comments-area {
	max-width: var(--content-width);
	margin-inline: auto;
	margin-block-start: 3.5rem;
	padding-block-start: 2rem;
	border-block-start: 1px solid var(--color-accent-soft);
}

.comments-title {
	font-size: var(--size-step-2);
	font-weight: 600;
	margin: 0;
	border-bottom: 0;
	padding-bottom: 0;
}

.comments-intro {
	color: var(--color-fg-muted);
	font-size: var(--size-step--1);
	margin-block: 0.5rem 2rem;
}

.comment-list,
.comment-list .children {
	list-style: none;
	padding: 0;
	margin: 0;
}

.comment-list > li {
	margin-bottom: 1.5rem;
}

.comment-list .children {
	margin-block-start: 1.25rem;
	margin-inline-start: 0.75rem;
	padding-inline-start: 1.25rem;
	border-inline-start: 2px solid var(--color-border);
}

@media (max-width: 480px) {
	.comment-list .children {
		margin-inline-start: 0.25rem;
		padding-inline-start: 0.75rem;
	}
}

.comment-body {
	background-color: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	padding: 1rem 1.15rem;
}

.comment-list .children > li {
	margin-bottom: 1.25rem;
}

.comment-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.4rem 1rem;
	margin-bottom: 0.6rem;
}

.comment-author {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	min-width: 0;
}

.comment-author img {
	border-radius: 50%;
	flex-shrink: 0;
	width: 40px;
	height: 40px;
}

.comment-author__names {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.comment-author__name {
	font-weight: 600;
	overflow-wrap: anywhere;
}

.comment-author__name a {
	color: var(--color-fg);
	text-decoration: none;
}

.comment-author__name a:hover {
	color: var(--color-accent);
}

.comment-author__handle {
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	text-decoration: none;
	overflow-wrap: anywhere;
}

.comment-author__handle:hover {
	color: var(--color-accent);
	text-decoration: underline;
}

.comment-author__identity {
	display: flex;
	align-items: center;
	gap: 0.35rem;
	min-height: 1.2em;
}

.comment-protocol {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	color: var(--color-fg-muted);
}

.comment-protocol svg {
	display: block;
	width: 0.9rem;
	height: 0.9rem;
	fill: currentColor;
}

.comment-author__badge {
	font-size: var(--size-step--2);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--color-bg);
	background-color: var(--color-fg-muted);
	border-radius: 999px;
	padding: 0.15em 0.55em;
	margin-inline-start: 0.4em;
	vertical-align: 0.1em;
}

.comment-metadata {
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	white-space: nowrap;
}

.comment-metadata a {
	color: inherit;
	text-decoration: none;
}

.comment-metadata a:hover {
	color: var(--color-accent);
	text-decoration: underline;
}

.comment-content {
	font-size: var(--size-step--1);
}

.comment-content > * + * {
	margin-block-start: 0.8em;
}

.comment-content p {
	overflow-wrap: break-word;
}

.comment-content a {
	color: var(--color-accent);
}

.comment-awaiting-moderation {
	flex-basis: 100%;
	margin: 0;
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	font-style: italic;
}

.reply {
	margin-block-start: 0.7rem;
	font-size: var(--size-step--2);
}

.comment-reply-link {
	display: inline-flex;
	align-items: center;
	gap: 0.3em;
	color: var(--color-fg-muted);
	text-decoration: none;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	padding: 0.25em 0.6em;
}

.comment-reply-link:hover {
	color: var(--color-accent);
	border-color: var(--color-accent);
}

/* --------------------------------------------- reply panel (no form here) */

/* --- the way in, above the thread */

.replies-header {
	margin-block-end: 2rem;
}

.replies-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.75rem 1rem;
	margin-block-start: 1.2rem;
}

/* Equal treatment: the logo and label identify the network, not visual weight. */
.foc-reply__button,
.bluesky-reply-link {
	font: inherit;
	font-size: var(--size-step--1);
	font-weight: 600;
	line-height: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.55em;
	min-height: 2.75rem;
	padding: 0.65em 1em;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
	color: var(--color-fg);
	cursor: pointer;
	text-decoration: none;
	transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.foc-reply__button:hover,
.bluesky-reply-link:hover {
	background-color: var(--color-accent-soft);
	border-color: var(--color-accent);
	color: var(--color-fg);
}

.foc-reply__button:active,
.bluesky-reply-link:active {
	transform: translateY(1px);
}

.foc-reply__button[hidden] {
	display: none;
}

.foc-reply__icon,
.bluesky-reply-link .comment-protocol {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
}

.foc-reply__icon svg,
.bluesky-reply-link .comment-protocol svg {
	display: block;
	width: 1.1rem;
	height: 1.1rem;
}

.replies-follow {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	flex-wrap: wrap;
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
}

.replies-reactions {
	margin-block-start: 1.2rem;
	font-size: var(--size-step--1);
}

/* --- the handle panel */

/*
 * Anchored under the button, not a modal.
 *
 * This began as a <dialog> opened with showModal(), which puts the element in
 * the top layer and positions it against the viewport — so it appeared in a
 * corner with no visible relationship to the button that opened it, and dimmed
 * the whole page behind one text field. A panel that drops from the control is
 * both less ceremony and easier to connect to what you just clicked.
 */
.foc-reply {
	position: relative;
	display: inline-block;
}

.foc-reply__controls {
	display: inline-flex;
	align-items: center;
	gap: 0.6rem;
}

.foc-reply__change {
	font: inherit;
	font-size: var(--size-step--2);
	padding: 0;
	border: 0;
	background: none;
	color: var(--color-fg-muted);
	text-decoration: underline;
	text-underline-offset: 0.15em;
	cursor: pointer;
}

.foc-reply__change:hover {
	color: var(--color-accent);
}

.foc-reply__change[hidden] {
	display: none;
}

.foc-reply__panel {
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: calc(100% + 0.5rem);
	z-index: 30;
	/*
	 * Wider than the button it hangs from: the wrapper is inline-block and so
	 * sized to the button, and a panel that narrow put the hint on five lines
	 * and pushed the submit button onto its own row.
	 */
	width: max(24rem, 100%);
	max-width: min(28rem, calc(100vw - 2rem));
	padding: 1rem;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
	box-shadow: 0 8px 24px rgb(0 0 0 / 35%);
	text-align: start;
}

.foc-reply__panel[hidden] {
	display: none;
}

.foc-reply__form {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.foc-reply__label {
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
}

.foc-reply__input {
	font: inherit;
	width: 100%;
	padding: 0.55em 0.7em;
	color: var(--color-fg);
	background-color: var(--color-bg);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
}

.foc-reply__input:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 1px;
	border-color: var(--color-accent);
}

.foc-reply__hint {
	margin: 0;
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	line-height: 1.5;
}

.foc-reply__error {
	margin: 0;
	font-size: var(--size-step--2);
	color: var(--color-danger);
}

.foc-reply__error[hidden] {
	display: none;
}

.foc-reply__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.6rem;
	margin-block-start: 0.25rem;
}

.foc-reply__remember {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	font-size: var(--size-step--2);
	color: var(--color-fg-muted);
	cursor: pointer;
}

.foc-reply__submit {
	font: inherit;
	font-size: var(--size-step--1);
	padding: 0.5em 1em;
	border: 1px solid var(--color-accent);
	border-radius: var(--radius-sm);
	background-color: var(--color-accent);
	color: var(--color-bg);
	cursor: pointer;
}

.foc-reply__submit:hover:not( :disabled ) {
	background-color: var(--color-accent-hover);
	border-color: var(--color-accent-hover);
}

.foc-reply__submit:disabled {
	opacity: 0.6;
	cursor: progress;
}

.foc-reply__button:disabled {
	opacity: 0.7;
	cursor: progress;
}

/*
 * Once a handle is remembered the label carries it, and a handle has no length
 * limit — a long one would stretch the button past the column it sits in.
 */
.foc-reply__button {
	max-width: min(100%, 24rem);
}

.foc-reply__button-label {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* --- the manual fallback, folded away */

.reply-manual {
	margin-block-start: 2.5rem;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
}

.reply-manual__summary {
	padding: 0.9rem 1.2rem;
	cursor: pointer;
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
}

.reply-manual__summary:hover {
	color: var(--color-accent);
}

.reply-manual[open] .reply-manual__summary {
	border-block-end: 1px solid var(--color-border);
}

.reply-manual__body {
	padding: 1.1rem 1.2rem 1.3rem;
	font-size: var(--size-step--1);
}

.reply-manual__body > p:first-child {
	margin-block-start: 0;
	color: var(--color-fg-muted);
}

.reply-manual__steps {
	margin: 1rem 0 0;
	padding-inline-start: 1.3em;
}

.reply-manual__steps li {
	margin-block-end: 0.6rem;
}

.reply-manual__route {
	margin-block-start: 1.1rem;
}

.reply-manual__follow {
	margin-block: 1.1rem 0;
	padding-block-start: 1rem;
	border-block-start: 1px solid var(--color-border);
}

.reply-manual__note {
	margin-block: 1.1rem 0;
	color: var(--color-fg-muted);
}

/* --- where a reply came from */

.comment-origin {
	display: inline-flex;
	align-items: center;
	gap: 0.25em;
	margin-inline-start: 0.5em;
	opacity: 0.75;
}

.comment-permalink {
	display: inline-flex;
	align-items: baseline;
	gap: 0.15em;
	flex-wrap: wrap;
	text-decoration: none;
}

.comment-permalink:hover {
	color: var(--color-accent);
}

.comment-permalink:hover .comment-origin {
	opacity: 1;
}

.reply-prompt__copy {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	flex-wrap: wrap;
	max-width: 100%;
}

.reply-prompt__copy code {
	background-color: var(--color-bg);
	border: 1px solid var(--color-border);
	overflow-wrap: anywhere;
}

.copy-inline {
	font-size: var(--size-step--2);
	line-height: 1;
	padding: 0.35em 0.6em;
	color: var(--color-fg-muted);
	background-color: var(--color-bg);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	cursor: pointer;
	flex-shrink: 0;
}

.copy-inline:hover {
	color: var(--color-accent);
	border-color: var(--color-accent);
}

.activitypub-reply-warning {
	margin-block-start: 0.7rem;
	font-size: var(--size-step--1);
	color: var(--color-fg-muted);
}

/* ------------------------------------------------- code copy (from JS) */

.code-block {
	position: relative;
}

.code-copy {
	position: absolute;
	inset-block-start: 0.5rem;
	inset-inline-end: 0.5rem;
	font-size: var(--size-step--2);
	line-height: 1;
	padding: 0.4em 0.6em;
	color: var(--color-fg-muted);
	background-color: var(--color-bg);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	cursor: pointer;
	opacity: 0;
	transition: opacity 0.12s ease-in-out;
}

.code-block:hover .code-copy,
.code-copy:focus-visible {
	opacity: 1;
}

/* No hover on touch, so keep it visible there. */
@media (hover: none) {
	.code-copy {
		opacity: 1;
	}
}

/* ---------------------------------------------------------------- search */

.search-form {
	display: flex;
	gap: 0.5rem;
	align-items: stretch;
	margin-block-end: 1.5rem;
	max-width: var(--content-width);
}

.search-form label {
	flex: 1 1 auto;
	margin: 0;
}

.search-field {
	width: 100%;
	max-width: 100%;
	font-size: var(--size-step-0);
	color: var(--color-fg);
	background-color: var(--color-bg);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	padding: 0.55em 0.7em;
}

.search-field:focus {
	border-color: var(--color-accent);
}

.search-submit {
	font-size: var(--size-step-0);
	background-color: var(--color-accent);
	color: var(--color-bg);
	border: 1px solid var(--color-accent);
	border-radius: var(--radius-sm);
	padding: 0.55em 1.2em;
	cursor: pointer;
	white-space: nowrap;
}

.search-submit:hover {
	background-color: var(--color-accent-hover);
	border-color: var(--color-accent-hover);
}

/* ---------------------------------------------------------------- footer */

.site-footer {
	margin-block-start: 4rem;
	padding-block: 2.5rem 2rem;
	border-block-start: 1px solid var(--color-accent-soft);
	color: var(--color-fg-muted);
}

.footer-row {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 0.5rem 1rem;
	font-size: var(--size-step--1);
	margin-bottom: 0.5rem;
	text-align: center;
}

.footer-row a {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	white-space: nowrap;
	color: var(--color-fg-muted);
	text-decoration: none;
}

.footer-row a:hover {
	color: var(--color-accent);
}

.footer-brand {
	color: var(--color-fg);
	font-weight: 700;
}

.footer-sep {
	color: var(--color-border);
}

.footer-nav ul {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.5rem 1rem;
	list-style: none;
	margin: 0 0 0.75rem;
	padding: 0;
	font-size: var(--size-step--1);
}

.footer-nav a {
	color: var(--color-fg-muted);
	text-decoration: none;
}

.footer-nav a:hover {
	color: var(--color-accent);
}

.site-copyright {
	text-align: center;
	font-size: var(--size-step--2);
	margin: 0;
}

.footer-widgets {
	display: flex;
	flex-wrap: wrap;
	gap: 2rem;
	justify-content: center;
	margin-bottom: 1.5rem;
	font-size: var(--size-step--1);
}

.footer-widgets ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.widget-title {
	font-size: var(--size-step-0);
	font-weight: 600;
	margin-block-end: 0.5rem;
	border-bottom: 0;
	padding-bottom: 0;
}

/* ------------------------------------------------------------- utilities */

.no-results {
	max-width: var(--content-width);
	margin-inline: auto;
}

.recent-posts {
	padding-inline-start: 1.2em;
}

.more-link {
	white-space: nowrap;
}
