/*
 * Raconteur — design tokens & base system.
 *
 * Palette: "typewriter ribbon" — cool near-black ink ground, warm cream
 * book-paper text, a single spine-orange accent in the tradition of
 * colour-coded paperback spine livery (a real historic convention: mass-
 * market imprints have long colour-coded spines by genre/imprint so a
 * shelf reads at a glance). A muted moss taxonomy tone is used only as a
 * low-saturation utility color for tagging essays vs. novels — never as a
 * second brand accent. Two self-hosted families only (Raconteur Display /
 * Raconteur Text — Alegreya + Merriweather, see fonts.css).
 *
 * Layout archetype: the "reading room" — a persistent left-hand rail of
 * chapter/issue navigation plus a wide central reading column, distinct
 * from this catalogue's other editorial archetypes (Quire's cross-page
 * view-transition index, Dispatch's per-category ticker grid, Patina's
 * catalogue-spread).
 *
 * @package Raconteur
 */

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

/* ---------- Reading modes govern the WHOLE site ----------
 *
 * paper / sepia / night were once a skin for the chapter body only. They now
 * drive every chrome token on the page, so the same control that warms the
 * prose warms the shelf, the header and the footer with it. `paper` is the
 * default: this is a place to read fiction, and every comparable reading
 * platform opens on a light page, not a dark one.
 *
 * The mode lives in `data-read-mode` on <html> — written synchronously by the
 * inline no-flash script in header.php, then persisted by
 * assets/js/raconteur-ui.js. The bare `:root` block below is therefore also
 * the paper palette, so a visitor with no stored preference (or with JS off)
 * still gets the light page rather than a flash of the wrong theme.
 *
 * Token names are identical in all three modes; only values change. Nothing
 * downstream branches on the mode except the handful of places called out in
 * comments (photo scrims, book jackets, on-accent text) where a surface is
 * genuinely mode-independent.
 */
:root,
:root[data-read-mode="paper"] {
	--rc-ink: #f7f3e8;
	--rc-ink-soft: #efe9da;
	--rc-ink-elevated: #fffdf7;
	--rc-paper: #22201b;
	--rc-paper-dim: rgba(34, 32, 27, 0.74);
	--rc-paper-faint: rgba(34, 32, 27, 0.64);
	--rc-accent: #a8451c;
	--rc-accent-bright: #c1592f;
	--rc-moss: #55684d;
	--rc-moss-bright: #46583f;
	--rc-line: rgba(34, 32, 27, 0.13);
	--rc-line-strong: rgba(34, 32, 27, 0.24);
	--rc-glass-bg: rgba(255, 253, 247, 0.74);
	--rc-glass-border: rgba(34, 32, 27, 0.11);
	--rc-shadow: 0 24px 64px rgba(63, 52, 34, 0.13);
	--rc-field-tint: 0.133, 0.125, 0.106;
	--rc-read-bg: #f6f1e4;
	--rc-read-fg: #26221a;
	--rc-read-rule: rgba(38, 34, 26, 0.14);
}

/* Sepia: a warm middle, not a third brand. Surfaces are pulled from the
 * reading triad that already existed (#ecdfc4 / #3a2f1f) and the accent is
 * deepened one step so it still carries 4.5:1 against a tinted page. */
:root[data-read-mode="sepia"] {
	--rc-ink: #f2e6cd;
	--rc-ink-soft: #e9dcc0;
	--rc-ink-elevated: #fbf1dd;
	--rc-paper: #3a2f1f;
	--rc-paper-dim: rgba(58, 47, 31, 0.76);
	--rc-paper-faint: rgba(58, 47, 31, 0.72);
	--rc-accent: #9c3f18;
	--rc-accent-bright: #b8511f;
	--rc-moss: #55684d;
	--rc-moss-bright: #46583f;
	--rc-line: rgba(58, 47, 31, 0.16);
	--rc-line-strong: rgba(58, 47, 31, 0.28);
	--rc-glass-bg: rgba(251, 241, 221, 0.76);
	--rc-glass-border: rgba(58, 47, 31, 0.14);
	--rc-shadow: 0 24px 64px rgba(74, 58, 30, 0.16);
	--rc-field-tint: 0.227, 0.184, 0.122;
	--rc-read-bg: #ecdfc4;
	--rc-read-fg: #3a2f1f;
	--rc-read-rule: rgba(58, 47, 31, 0.16);
}

/* Night: the palette this theme shipped with, unchanged. */
:root[data-read-mode="night"] {
	--rc-ink: #14161a;
	--rc-ink-soft: #1a1d22;
	--rc-ink-elevated: #22262c;
	--rc-paper: #ece4d1;
	--rc-paper-dim: rgba(236, 228, 209, 0.72);
	/* Was 0.46, which measured 3.92:1 on ink — below AA for the 15px meta text
	 * this token is used for. Raised to match the correction applied to the two
	 * light modes; it is an opacity knob on the existing cream, not a repaint.
	 * Everything else in this block is the palette the theme shipped with. */
	--rc-paper-faint: rgba(236, 228, 209, 0.55);
	--rc-accent: #c1592f;
	--rc-accent-bright: #e07949;
	--rc-moss: #6f8368;
	--rc-moss-bright: #8ea287;
	--rc-line: rgba(236, 228, 209, 0.14);
	--rc-line-strong: rgba(236, 228, 209, 0.24);
	--rc-glass-bg: rgba(26, 29, 34, 0.66);
	--rc-glass-border: rgba(236, 228, 209, 0.12);
	--rc-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
	--rc-field-tint: 0.929, 0.894, 0.820;
	--rc-read-bg: #14161a;
	--rc-read-fg: #ece4d1;
	--rc-read-rule: rgba(236, 228, 209, 0.16);
}

:root {
	/* Foreground for anything sitting ON the accent (buttons, active chips,
	 * the active mode pip). The accent is a mid-dark orange in every mode, so
	 * this one value is correct in all three — using --rc-paper here would put
	 * near-black ink on an orange button the moment the site went light. */
	--rc-on-accent: #fff8f0;

	--rc-font-display: 'Raconteur Display', Georgia, 'Times New Roman', serif;
	--rc-font-text: 'Raconteur Text', Georgia, 'Times New Roman', serif;
	--rc-font-mono: ui-monospace, 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;

	/* Type scale: base 17px x 1.25 (major third-ish), 8 sizes, reused everywhere. */
	--rc-size-0: 0.9375rem;  /* 15 */
	--rc-size-1: 1.0625rem;  /* 17 */
	--rc-size-2: 1.3125rem;  /* 21 */
	--rc-size-3: 1.6875rem;  /* 27 */
	--rc-size-4: 2.0625rem;  /* 33 */
	--rc-size-5: 2.625rem;   /* 42 */
	--rc-size-6: 3.25rem;    /* 52 */
	--rc-size-7: 4.0625rem;  /* 65 */

	/* Spacing scale: base 8px. */
	--rc-sp-1: 0.5rem;
	--rc-sp-2: 1rem;
	--rc-sp-3: 1.5rem;
	--rc-sp-4: 2rem;
	--rc-sp-5: 3rem;
	--rc-sp-6: 4rem;
	--rc-sp-7: 6rem;
	--rc-sp-8: 8rem;
	--rc-sp-9: 10rem;

	--rc-radius: 3px;
	--rc-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
	--rc-ease-in: cubic-bezier(0.7, 0, 0.84, 0);
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
}

/* `overflow-x: clip` clips exactly like `hidden` but does NOT turn the box
 * into a scroll container. With `hidden` here, <body> became a scrollport of
 * its own, and a sticky box can only stick inside its own scrollport — which
 * silently disabled `.site-header { position: sticky }` on every template.
 * (assets/css/reader.css previously patched this for the chapter reader
 * alone; that scoped rule is now redundant but harmless, and the reader still
 * un-sticks the site header there so the toolbar keeps the top edge.) */
html, body { overflow-x: clip; }

body {
	margin: 0;
	background: var(--rc-ink);
	color: var(--rc-paper);
	font-family: var(--rc-font-text);
	font-size: var(--rc-size-1);
	line-height: 1.55;
	-webkit-font-smoothing: antialiased;
	/* Neutralised wholesale by the reduced-motion block above. */
	transition: background-color 0.4s var(--rc-ease-out), color 0.4s var(--rc-ease-out);
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
ul, ol { margin: 0; padding: 0; list-style: none; }
h1, h2, h3, h4, p, figure { margin: 0; }

h1, h2, h3, h4 {
	font-family: var(--rc-font-display);
	font-weight: 700;
	line-height: 1.14;
	letter-spacing: -0.008em;
	text-wrap: balance;
}

.h-display { font-size: var(--rc-size-7); }
.h-1 { font-size: var(--rc-size-6); }
.h-2 { font-size: var(--rc-size-5); }
.h-3 { font-size: var(--rc-size-4); }
.h-4 { font-size: var(--rc-size-3); }

@media (max-width: 720px) {
	.h-display { font-size: var(--rc-size-6); }
	.h-1 { font-size: var(--rc-size-5); }
	.h-2 { font-size: var(--rc-size-4); }
}

.eyebrow {
	font-family: var(--rc-font-text);
	font-size: var(--rc-size-0);
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--rc-accent-bright);
}

.lede {
	font-size: var(--rc-size-2);
	color: var(--rc-paper-dim);
	line-height: 1.5;
}

.tag {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	padding: 0.3em 0.75em;
	border-radius: 999px;
	border: 1px solid var(--rc-line-strong);
	font-size: var(--rc-size-0);
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--rc-paper-dim);
}

/* Both borders used to be frozen copies of the night accent/moss. Mixing off
 * the live token instead keeps them in step when the page goes light. */
.tag--novel { border-color: color-mix(in srgb, var(--rc-accent) 42%, transparent); color: var(--rc-accent-bright); }
.tag--essay { border-color: color-mix(in srgb, var(--rc-moss) 52%, transparent); color: var(--rc-moss-bright); }

.container {
	width: 100%;
	max-width: 1240px;
	margin: 0 auto;
	padding: 0 var(--rc-sp-4);
}

.container--narrow { max-width: 800px; }
.container--reading { max-width: 700px; }

section { position: relative; padding: var(--rc-sp-7) 0; }
@media (max-width: 720px) { section { padding: var(--rc-sp-6) 0; } }

.btn {
	display: inline-flex;
	align-items: center;
	gap: 0.6em;
	padding: 0.85em 1.6em;
	border-radius: var(--rc-radius);
	font-size: var(--rc-size-1);
	font-weight: 700;
	letter-spacing: 0.01em;
	transition: transform 0.3s var(--rc-ease-out), background 0.3s var(--rc-ease-out), border-color 0.3s var(--rc-ease-out);
}

.btn--primary {
	background: var(--rc-accent);
	color: var(--rc-on-accent);
}
/*
 * Night's accent (#c1592f) is only 4.43:1 from pure white, so NO foreground
 * clears WCAG AA on it — the primary CTA measured 4.21:1. The button surface
 * is darkened ~8% in night mode only (4.82:1). The accent token itself is
 * untouched, so headings, rules and links keep the exact signature orange;
 * this is scoped to the one element that has text sitting on top of it.
 */
:root[data-read-mode="night"] .btn--primary {
	background: color-mix(in srgb, var(--rc-accent) 92%, #000);
}
.btn--primary:hover { background: var(--rc-accent-bright); transform: translateY(-2px); }

.btn--ghost {
	border: 1px solid var(--rc-line-strong);
	color: var(--rc-paper);
}
.btn--ghost:hover { border-color: var(--rc-accent-bright); color: var(--rc-accent-bright); transform: translateY(-2px); }

.card {
	background: var(--rc-glass-bg);
	border: 1px solid var(--rc-glass-border);
	border-radius: 6px;
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
}

.rule {
	border: none;
	border-top: 1px solid var(--rc-line);
	margin: var(--rc-sp-5) 0;
}

.sr-only {
	position: absolute;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.visually-hidden-focusable:not(:focus) {
	position: absolute;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* GPU word-frequency field host — fixed, full-viewport, sits behind all
 * content. Off by default until raconteur-field.js confirms a capable
 * tier; the Static fallback below covers reduced-motion/no-WebGL.
 *
 * Two direct body children only: the fixed field stage (z-index:0) and
 * .rc-page wrapping everything real (z-index:1) — an explicit two-child
 * stacking order, not a generic `body > *` rule, so nothing real content
 * ever adds as a third direct child can accidentally slip behind the
 * field or in front of it by omission. */
.rc-field-stage {
	position: fixed;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	background: var(--rc-ink);
}
#rc-field-canvas {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
	opacity: 0;
	transition: opacity 1.2s var(--rc-ease-out);
}
.rc-field-stage.is-ready #rc-field-canvas { opacity: 1; }

.rc-page { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
	#rc-field-canvas { display: none; }
}

/* ---------- Skip link ---------- */
.skip-link {
	position: absolute; left: -9999px; top: 0;
	background: var(--rc-accent); color: var(--rc-on-accent);
	padding: var(--rc-sp-2) var(--rc-sp-3); z-index: 200;
}
.skip-link:focus { left: 0; }

/* ---------- Layout ---------- */
.wrap { max-width: 1280px; margin: 0 auto; padding: 0 var(--rc-sp-4); }
@media (max-width: 720px) { .wrap { padding: 0 var(--rc-sp-3); } }

.section { padding: var(--rc-sp-8) 0; }
@media (max-width: 900px) { .section { padding: var(--rc-sp-6) 0; } }
.section-head { max-width: 46rem; margin-bottom: var(--rc-sp-5); }
.section-head + .section-head { margin-top: var(--rc-sp-5); }

/* ---------- Header / nav ---------- */
.site-header {
	position: sticky; top: 0; z-index: 100;
	border-bottom: 1px solid var(--rc-line);
	background: var(--rc-glass-bg);
	backdrop-filter: blur(14px) saturate(1.1);
	-webkit-backdrop-filter: blur(14px) saturate(1.1);
}
.site-header__inner { display: flex; align-items: center; justify-content: space-between; padding: var(--rc-sp-2) 0; }
.brand { display: flex; align-items: center; gap: 0.6rem; font-family: var(--rc-font-display); font-size: var(--rc-size-3); color: var(--rc-paper); }
.brand__mark { color: var(--rc-accent-bright); }
.brand small { display: block; font-family: var(--rc-font-text); font-size: 0.6em; letter-spacing: 0.08em; text-transform: uppercase; color: var(--rc-paper-faint); }

.nav-toggle { display: none; }
.nav__close { display: none; }
/* .nav must refuse to shrink too. Its children already do, so a shrunken .nav
 * simply overflowed to the right and slid underneath the reading-mode toggle
 * (measured 25px of overlap). The brand is the one flexible item in the
 * header — see .brand { min-width: 0 } below. */
.nav { display: flex; align-items: center; gap: var(--rc-sp-4); flex-shrink: 0; }
.nav__links { display: flex; align-items: center; gap: var(--rc-sp-3); }
/*
 * wp_nav_menu() is called with 'container' => false, so the menu arrives as a
 * bare <ul> — a single flex child of .nav__links. Flexing the wrapper
 * therefore did nothing to the items themselves, and the desktop nav rendered
 * as a six-item vertical stack in the top-right corner. The <ul> is the box
 * that has to become the row.
 */
.nav__links > ul { display: flex; align-items: center; gap: var(--rc-sp-2); flex-wrap: wrap; }
/*
 * The menu needs ~494px but flex was shrinking .nav__links to 434px while the
 * header still had ~126px of slack, so the last item wrapped to a second row
 * for no reason. Refusing to shrink lets the menu take its natural width; the
 * brand's long strapline is the flexible thing here, so it yields first.
 */
.nav__links { flex-shrink: 0; }
/* The CTA has to refuse to shrink for the same reason, or reclaiming the
 * menu's width just pushes the wrap onto the button ("Become a / Member").
 * Header budget at 1280: brand 481 + menu 494 + CTA 197 + gaps 64 = 1236. */
.nav__cta { flex-shrink: 0; white-space: nowrap; }
.brand { min-width: 0; }
.nav a:not(.btn) { position: relative; padding: 0.3em 0; font-size: var(--rc-size-0); letter-spacing: 0.03em; }
.nav a:not(.btn)::after {
	content: ''; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
	background: var(--rc-accent-bright); transform: scaleX(0); transform-origin: left;
	transition: transform 0.3s var(--rc-ease-out);
}
.nav a:not(.btn):hover::after, .nav a:not(.btn).is-active::after { transform: scaleX(1); }
.nav__cta { margin-left: 0.3rem; }

@media (max-width: 900px) {
	.nav-toggle { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border: 1px solid var(--rc-line-strong); border-radius: var(--rc-radius); }
	/* `inset: 0 ...` does not reach the bottom of the screen here: the header
	 * carries a backdrop-filter, which makes it the containing block for its
	 * own fixed children, so `bottom: 0` resolved to the bottom of the HEADER
	 * and the drawer was a ~130px stub with its links spilling onto the page
	 * behind it. Giving it an explicit viewport height over-constrains the
	 * box, `bottom` is dropped, and the panel is full height again. (Pre-dates
	 * this change — it only became obvious once the masthead got shorter.) */
	.nav {
		position: fixed; inset: 0 0 0 30%; z-index: 150;
		height: 100vh; height: 100dvh;
		overflow-y: auto;
		flex-direction: column; align-items: flex-start; justify-content: flex-start;
		padding: var(--rc-sp-6) var(--rc-sp-4);
		background: var(--rc-ink-soft); border-left: 1px solid var(--rc-line);
		transform: translateX(100%); transition: transform 0.4s var(--rc-ease-out);
	}
	.nav.is-open { transform: translateX(0); }
	.nav__links { flex-direction: column; align-items: flex-start; gap: var(--rc-sp-3); width: 100%; }
	/* In the drawer the menu goes back to a stack — see the desktop rule above
	 * for why the <ul> has to be targeted rather than its wrapper. */
	.nav__links > ul { flex-direction: column; align-items: flex-start; gap: var(--rc-sp-3); width: 100%; }
	.nav__cta { margin-left: 0; margin-top: var(--rc-sp-3); }
	.nav__close { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; position: absolute; top: var(--rc-sp-3); right: var(--rc-sp-3); }
}

/* ---------- Footer ---------- */
.site-footer { border-top: 1px solid var(--rc-line); padding: var(--rc-sp-7) 0 var(--rc-sp-4); }
.footer-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: var(--rc-sp-5); }
@media (max-width: 900px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-col h4 { font-family: var(--rc-font-text); font-size: var(--rc-size-0); letter-spacing: 0.1em; text-transform: uppercase; color: var(--rc-accent-bright); margin-bottom: var(--rc-sp-2); }
.footer-col ul { display: flex; flex-direction: column; gap: 0.5rem; }
.footer-col a:hover { color: var(--rc-accent-bright); }
.footer-bottom {
	margin-top: var(--rc-sp-6); padding-top: var(--rc-sp-3); border-top: 1px solid var(--rc-line);
	display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--rc-sp-2);
	font-size: var(--rc-size-0); color: var(--rc-paper-faint);
}
.social-row { display: flex; gap: var(--rc-sp-2); }
.social-row a { color: var(--rc-paper-dim); }
.social-row a:hover { color: var(--rc-accent-bright); }

/* ---------- Hero ---------- */
.hero { min-height: 92vh; display: flex; align-items: center; padding: var(--rc-sp-7) 0; }
.hero__inner { max-width: 42rem; }
.hero__panel { padding: var(--rc-sp-5); border-radius: var(--rc-radius); }
.hero__title { margin: var(--rc-sp-2) 0 var(--rc-sp-3); white-space: pre-line; }
.hero__actions { display: flex; gap: var(--rc-sp-2); margin-top: var(--rc-sp-4); flex-wrap: wrap; }

/* ---------- Reveal-on-scroll ---------- */
.reveal { opacity: 0; transform: translateY(24px); transition: opacity 0.7s var(--rc-ease-out), transform 0.7s var(--rc-ease-out); }
.reveal.is-visible { opacity: 1; transform: translateY(0); }
.reveal-stagger > * { transition-delay: calc(var(--i, 0) * 80ms); }

/* ---------- Stat grid ---------- */
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--rc-sp-4); }
@media (max-width: 800px) { .stat-grid { grid-template-columns: repeat(2, 1fr); } }
.stat { padding: var(--rc-sp-3) 0; border-top: 1px solid var(--rc-line); }
.stat__value { font-family: var(--rc-font-display); font-size: var(--rc-size-5); color: var(--rc-accent-bright); }
.stat__label { font-size: var(--rc-size-0); color: var(--rc-paper-faint); margin-top: 0.3rem; }

/* ---------- Reading-room grid (novels/essays) ----------
 * Signature layout archetype: a "shelf" of typographic covers rather than
 * photographic cards — each novel's cover is generated CSS/SVG art driven
 * by its own _rc_hue meta (deterministic from its slug), the way a real
 * indie serial-fiction platform uses typographic covers instead of stock
 * photography for work that doesn't have a physical jacket yet.
 */
.novel-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--rc-sp-5); }
@media (max-width: 980px) { .novel-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .novel-grid { grid-template-columns: 1fr; } }

.novel-card { display: block; }
/* A book jacket is an object photographed on the page, not a surface of the
 * page: it stays dark-tinted and keyed to --cover-hue in all three reading
 * modes. Its typographic layer therefore pins its own light foreground here
 * instead of following --rc-paper, which is near-black ink once the site goes
 * light — the jacket titles would otherwise vanish into their own artwork. */
.novel-cover {
	--rc-paper: #ece4d1;
	position: relative; aspect-ratio: 2 / 3.1; border-radius: 4px; overflow: hidden;
	display: flex; flex-direction: column; justify-content: space-between; padding: var(--rc-sp-3);
	box-shadow: var(--rc-shadow);
	transition: transform 0.4s var(--rc-ease-out);
	background:
		linear-gradient(160deg, hsla(var(--cover-hue), 55%, 22%, 0.9), hsla(var(--cover-hue), 40%, 10%, 0.95)),
		repeating-linear-gradient(115deg, rgba(255,255,255,0.03) 0 2px, transparent 2px 6px);
}
.novel-card:hover .novel-cover { transform: translateY(-6px); }
.novel-cover__photo {
	position: absolute; inset: 0; z-index: 0;
}
.novel-cover__photo img {
	width: 100%; height: 100%; object-fit: cover;
	filter: saturate(0.85) contrast(1.05);
}
.novel-cover__photo::before {
	/* Deterministic per-novel hue (_rc_hue, crc32(slug)%360) as a real colour-grade wash over the
	   photo rather than a flat swatch — the hue signature survives, the card stops being a solid block. */
	content: ''; position: absolute; inset: 0;
	background: linear-gradient(160deg, hsla(var(--cover-hue), 70%, 35%, 0.55), hsla(var(--cover-hue), 60%, 12%, 0.75));
	mix-blend-mode: multiply;
}
.novel-cover__photo::after {
	content: ''; position: absolute; inset: 0;
	background: linear-gradient(190deg, rgba(10,9,14,0.05) 0%, rgba(10,9,14,0.35) 55%, rgba(10,9,14,0.88) 100%);
}
.novel-cover__eyebrow, .novel-cover__title, .novel-cover__byline { position: relative; z-index: 1; }
.novel-cover__eyebrow { font-size: 0.65rem; letter-spacing: 0.14em; text-transform: uppercase; color: hsla(var(--cover-hue), 70%, 78%, 0.85); }
.novel-cover__title { font-family: var(--rc-font-display); font-size: var(--rc-size-3); line-height: 1.1; color: var(--rc-paper); text-wrap: balance; }
.novel-cover__byline { font-size: 0.72rem; letter-spacing: 0.06em; color: hsla(var(--cover-hue), 40%, 85%, 0.7); }
.novel-cover::after {
	content: ''; position: absolute; inset: 0; pointer-events: none;
	background: radial-gradient(ellipse 90% 60% at 50% 0%, hsla(var(--cover-hue), 80%, 60%, 0.16), transparent 60%);
}
.novel-card__meta { margin-top: var(--rc-sp-2); font-size: var(--rc-size-0); color: var(--rc-paper-faint); display: flex; justify-content: space-between; gap: 0.6em; }
.novel-card__dek { margin-top: 0.4rem; font-size: var(--rc-size-0); color: var(--rc-paper-dim); }

/* ---------- Essay list ---------- */
.essay-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--rc-sp-4); }
@media (max-width: 800px) { .essay-grid { grid-template-columns: 1fr; } }
.essay-card { padding: var(--rc-sp-4); border: 1px solid var(--rc-line); border-radius: var(--rc-radius); transition: border-color 0.3s, transform 0.3s var(--rc-ease-out); }
.essay-card:hover { border-color: var(--rc-line-strong); transform: translateY(-3px); }
.essay-card__title { font-family: var(--rc-font-display); font-size: var(--rc-size-3); margin-bottom: 0.5rem; }
.essay-card__dek { color: var(--rc-paper-dim); font-size: var(--rc-size-0); margin-bottom: 0.8rem; }
.essay-card__meta { font-size: var(--rc-size-0); color: var(--rc-paper-faint); }

/* ---------- Filter rail ---------- */
.filter-rail { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-bottom: var(--rc-sp-4); }
.filter-chip { padding: 0.5em 1.1em; font-size: var(--rc-size-0); border: 1px solid var(--rc-line-strong); border-radius: 999px; transition: background 0.3s, border-color 0.3s, color 0.3s; }
.filter-chip.is-active, .filter-chip:hover { background: var(--rc-accent); border-color: var(--rc-accent); color: var(--rc-on-accent); }

/* ---------- Widget shells (signature techniques) ---------- */
.widget-panel { border: 1px solid var(--rc-line); border-radius: var(--rc-radius); padding: var(--rc-sp-4); background: var(--rc-ink-soft); }
.widget-panel h3 { margin-bottom: var(--rc-sp-2); }
.widget-controls { display: flex; flex-wrap: wrap; gap: var(--rc-sp-3); margin: var(--rc-sp-3) 0; }
.widget-field { display: flex; flex-direction: column; gap: 0.35rem; font-size: var(--rc-size-0); color: var(--rc-paper-dim); }
.widget-field textarea, .widget-field input[type="text"] {
	background: var(--rc-ink); border: 1px solid var(--rc-line-strong); color: var(--rc-paper);
	padding: 0.7em 0.9em; border-radius: var(--rc-radius); font-family: var(--rc-font-text);
}

/* ---------- Flesch-Kincaid readability widget ---------- */
.rc-fk { font-size: var(--rc-size-0); }
.rc-fk__row { display: flex; align-items: baseline; gap: 0.6em; margin-bottom: 0.3rem; }
.rc-fk__label { color: var(--rc-paper-faint); min-width: 8em; }
.rc-fk__value { font-family: var(--rc-font-display); font-size: var(--rc-size-3); color: var(--rc-accent-bright); }
.rc-fk__band { color: var(--rc-paper-dim); }
.rc-fk__bar { display: block; height: 6px; border-radius: 999px; background: var(--rc-line); overflow: hidden; margin: 0.4rem 0 0.8rem; }
.rc-fk__bar span { display: block; height: 100%; background: linear-gradient(90deg, var(--rc-accent), var(--rc-accent-bright)); border-radius: inherit; transition: width 0.4s var(--rc-ease-out); }
.rc-fk__row--sub .rc-fk__value { font-size: var(--rc-size-2); }

/* ---------- Reading-pace widget ---------- */
.rc-pace-widget {
	display: inline-flex; align-items: center; gap: 0.5em;
	font-size: var(--rc-size-0); color: var(--rc-paper-dim);
	padding: 0.5em 0.9em; border: 1px solid var(--rc-line-strong); border-radius: 999px;
}
.rc-pace-widget.is-personalized { color: var(--rc-accent-bright); border-color: color-mix(in srgb, var(--rc-accent) 42%, transparent); }

/* ---------- Reading-mode toggle (paper/sepia/night) ----------
 * Lives in the reader toolbar AND in the site header, because the mode now
 * governs the whole site rather than the prose column alone. */
.read-mode-toggle { display: inline-flex; gap: 0.3rem; border: 1px solid var(--rc-line-strong); border-radius: 999px; padding: 0.25rem; }
.read-mode-toggle button {
	width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center;
	border-radius: 999px; color: var(--rc-paper-dim); transition: background 0.25s, color 0.25s;
}
.read-mode-toggle button.is-active { background: var(--rc-accent); color: var(--rc-on-accent); }
.read-mode-toggle button:hover:not(.is-active) { color: var(--rc-paper); }
.read-mode-toggle button:focus-visible { outline: 2px solid var(--rc-accent-bright); outline-offset: 2px; }

/* In the header it sits between the nav and the menu button, and stays put on
 * mobile: the mode control must not be buried inside a drawer the visitor has
 * to open to find out the site can go dark. */
.site-header .read-mode-toggle { flex: none; margin-left: var(--rc-sp-2); }
@media (max-width: 900px) {
	.site-header .read-mode-toggle { margin-left: auto; margin-right: var(--rc-sp-2); }
	.read-mode-toggle button { width: 28px; height: 28px; }
}
@media (max-width: 560px) {
	/* The mode control is a third item in the header row, and on a phone the
	 * masthead line was wrapping to three lines to make room for it — nearly a
	 * third of the viewport spent on a tagline. The name and the control both
	 * earn their place there; the strapline does not. */
	.brand small { display: none; }
}
@media (max-width: 420px) {
	.site-header .read-mode-toggle { padding: 0.15rem; }
	.site-header .read-mode-toggle button { width: 26px; height: 26px; }
}

/* ---------- Reader layout (chapter/essay) ---------- */
.rc-reader { background: var(--rc-read-bg); color: var(--rc-read-fg); transition: background 0.4s, color 0.4s; }
.rc-reader__head { padding: var(--rc-sp-6) 0 var(--rc-sp-4); border-bottom: 1px solid var(--rc-read-rule); }
.rc-reader__kicker { font-size: var(--rc-size-0); letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.65; }
.rc-reader__title { margin: 0.4rem 0 0.6rem; }
.rc-reader__meta { display: flex; flex-wrap: wrap; gap: var(--rc-sp-3); align-items: center; font-size: var(--rc-size-0); opacity: 0.75; }
.rc-reader__body {
	max-width: 700px; margin: 0 auto; padding: var(--rc-sp-6) var(--rc-sp-4) var(--rc-sp-7);
	font-size: 1.15rem; line-height: 1.75;
}
.rc-reader__body p { margin: 0 0 1.3em; }
.rc-reader__note { margin-top: var(--rc-sp-6); padding: var(--rc-sp-3); border-left: 3px solid var(--rc-accent); background: color-mix(in srgb, var(--rc-accent) 9%, transparent); font-size: 0.95rem; opacity: 0.9; }
.rc-reader__nav { display: flex; justify-content: space-between; gap: var(--rc-sp-3); padding: var(--rc-sp-5) 0; border-top: 1px solid var(--rc-read-rule); max-width: 700px; margin: 0 auto; }
.rc-reader__nav a { font-size: var(--rc-size-0); opacity: 0.85; }
.rc-reader__toolbar { position: sticky; top: 0; z-index: 50; display: flex; align-items: center; justify-content: space-between; gap: var(--rc-sp-3); padding: 0.7rem var(--rc-sp-4); background: var(--rc-read-bg); border-bottom: 1px solid var(--rc-read-rule); }
.rc-reader__toolbar .wrap { display: flex; align-items: center; justify-content: space-between; gap: var(--rc-sp-3); flex-wrap: wrap; }

.rc-chapter-list { display: flex; flex-direction: column; gap: 0.4rem; }
.rc-chapter-list a { display: flex; justify-content: space-between; gap: 0.6em; padding: 0.6em 0.8em; border-radius: var(--rc-radius); font-size: var(--rc-size-0); }
.rc-chapter-list a:hover, .rc-chapter-list a.is-current { background: var(--rc-glass-bg); }
.rc-chapter-list .chapter-num { opacity: 0.6; }

/* ---------- Forms ---------- */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--rc-sp-3); }
@media (max-width: 700px) { .form-grid { grid-template-columns: 1fr; } }
.form-field { display: flex; flex-direction: column; gap: 0.4rem; }
.form-field.span-2 { grid-column: 1 / -1; }
.form-field label { font-size: var(--rc-size-0); color: var(--rc-paper-dim); }
.form-field input, .form-field select, .form-field textarea {
	background: var(--rc-ink); border: 1px solid var(--rc-line-strong); color: var(--rc-paper);
	padding: 0.7em 0.9em; border-radius: var(--rc-radius); font-family: var(--rc-font-text); font-size: var(--rc-size-1);
	transition: border-color 0.3s;
}
.form-field input:focus, .form-field select:focus, .form-field textarea:focus { outline: none; border-color: var(--rc-accent); }
.form-honeypot { position: absolute; left: -9999px; }
.form-status { margin-top: var(--rc-sp-2); font-size: var(--rc-size-0); }
/* The old single #e08a8a was a dark-background pink (2.6:1 on cream). Error
 * text is the one message a visitor must not miss, so it gets a real value
 * per surface rather than a compromise that half-works on both. */
.form-status.is-error { color: #a32424; }
[data-read-mode="night"] .form-status.is-error { color: #e08a8a; }
.form-status.is-success { color: var(--rc-accent-bright); }

/* ---------- Inner page hero ---------- */
.page-hero { position: relative; overflow: hidden; padding: var(--rc-sp-7) 0 var(--rc-sp-4); }
/* A photographic hero keeps its dark scrim in every mode — that is what makes
 * the photograph readable — so the copy on top pins its own light palette
 * rather than following the page. Redeclaring the tokens (instead of setting
 * `color` on a handful of elements) means the eyebrow, meta, rules and back
 * link all follow without listing every child. */
.page-hero--photo {
	--rc-paper: #f4eee2;
	--rc-paper-dim: rgba(244, 238, 226, 0.8);
	--rc-paper-faint: rgba(244, 238, 226, 0.62);
	--rc-accent: #e07949;
	--rc-accent-bright: #e8916a;
	--rc-line: rgba(244, 238, 226, 0.16);
	--rc-line-strong: rgba(244, 238, 226, 0.3);
	color: var(--rc-paper);
	padding: var(--rc-sp-9) 0 var(--rc-sp-6);
}
.page-hero__bg { position: absolute; inset: 0; z-index: 0; }
.page-hero__bg img { width: 100%; height: 100%; object-fit: cover; }
/* Light modes: the scrim can no longer fade into --rc-ink (that would run a
 * dark wash into a cream band), so it closes on its own darkest stop and the
 * photograph ends on a clean edge. */
.page-hero__bg::after {
	content: ''; position: absolute; inset: 0;
	background: linear-gradient(180deg, rgba(20,22,26,0.42) 0%, rgba(20,22,26,0.84) 76%, rgba(20,22,26,0.96) 100%);
}
[data-read-mode="night"] .page-hero__bg::after {
	background: linear-gradient(180deg, rgba(20,22,26,0.5) 0%, rgba(20,22,26,0.88) 75%, var(--rc-ink) 100%);
}
.page-hero--photo .wrap { position: relative; z-index: 1; }
.page-hero--photo .back-link { color: var(--rc-paper-dim); }
.back-link { display: inline-flex; align-items: center; gap: 0.4rem; font-size: var(--rc-size-0); color: var(--rc-paper-faint); margin-bottom: var(--rc-sp-3); }
.back-link:hover { color: var(--rc-accent-bright); }
.section--narrow .wrap { max-width: 800px; }
.content-body { font-size: var(--rc-size-1); line-height: 1.7; }
.content-body p { margin-bottom: 1.2em; }
.content-body h2, .content-body h3 { margin: 1.6em 0 0.6em; }
.content-body a { color: var(--rc-accent-bright); text-decoration: underline; text-underline-offset: 3px; }
.content-body img { border-radius: var(--rc-radius); margin: 1.5em 0; }

/* ---------- Post list (index/search) ---------- */
.post-list { display: flex; flex-direction: column; gap: var(--rc-sp-4); }
.post-row { display: grid; grid-template-columns: 1fr; gap: 0.4rem; padding: var(--rc-sp-4) 0; border-top: 1px solid var(--rc-line); }
.post-row__title { font-family: var(--rc-font-display); font-size: var(--rc-size-3); }
.post-row__meta { font-size: var(--rc-size-0); color: var(--rc-paper-faint); }
.pagination { display: flex; gap: var(--rc-sp-2); margin-top: var(--rc-sp-5); }
.pagination a, .pagination span { padding: 0.5em 1em; border: 1px solid var(--rc-line-strong); border-radius: var(--rc-radius); font-size: var(--rc-size-0); }

/* ---------- Search form ---------- */
.search-form { display: flex; gap: 0.6rem; max-width: 30rem; }
.search-form input[type="search"] {
	flex: 1; background: var(--rc-ink); border: 1px solid var(--rc-line-strong); color: var(--rc-paper);
	padding: 0.7em 0.9em; border-radius: var(--rc-radius); font-family: var(--rc-font-text);
}

/* ---------- 404 / search ---------- */
.error-page { min-height: 60vh; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; }

/* ---------- Comments ---------- */
.comment-list { display: flex; flex-direction: column; gap: var(--rc-sp-3); }
.comment-body { padding: var(--rc-sp-3); border: 1px solid var(--rc-line); border-radius: var(--rc-radius); }
.comment-meta { font-size: var(--rc-size-0); color: var(--rc-paper-faint); margin-bottom: 0.4rem; }

/* ---------- Utility ---------- */
.text-center { text-align: center; }
.mt-0 { margin-top: 0; }

/* ---------- Accent step correction on light surfaces ----------
 *
 * --rc-accent-bright is one step lighter than --rc-accent in every mode. On
 * the dark page that is the step that carries (#e07949 on ink = 6.2:1); on a
 * cream page it is the step that does NOT (#c1592f on paper = 4.0:1, below
 * AA for anything under 24px). The token values are unchanged — the small
 * accent *text* simply resolves to the mode's high-contrast step, which is
 * --rc-accent once the surface is light.
 *
 * Written as :not([data-read-mode="night"]) rather than paper+sepia so it
 * also covers the attribute-less first paint. It resolves through the token,
 * so the two scopes that pin their own palette — .page-hero--photo over a
 * dark scrim, .novel-cover on a dark jacket — keep their bright accent
 * automatically. Display-size accent (--rc-size-3 and up) is left alone: it
 * clears the 3:1 large-text bar and the lighter step is the intended
 * colour there.
 */
:root:not([data-read-mode="night"]) .eyebrow,
:root:not([data-read-mode="night"]) .tag--novel,
:root:not([data-read-mode="night"]) .footer-col h4,
:root:not([data-read-mode="night"]) .footer-col a:hover,
:root:not([data-read-mode="night"]) .social-row a:hover,
:root:not([data-read-mode="night"]) .back-link:hover,
:root:not([data-read-mode="night"]) .content-body a,
:root:not([data-read-mode="night"]) .rc-pace-widget.is-personalized,
:root:not([data-read-mode="night"]) .form-status.is-success,
:root:not([data-read-mode="night"]) .home-meta__genre,
:root:not([data-read-mode="night"]) .home-hero__cadence,
:root:not([data-read-mode="night"]) .home-releases__title,
:root:not([data-read-mode="night"]) .home-essays__link a:hover,
:root:not([data-read-mode="night"]) .home-craft__readout,
:root:not([data-read-mode="night"]) .home-craft__foot a,
:root:not([data-read-mode="night"]) .home-genre:hover .home-genre__arrow,
:root:not([data-read-mode="night"]) .rc-byline-link:hover,
:root:not([data-read-mode="night"]) .rc-byline-link:focus-visible,
:root:not([data-read-mode="night"]) .comments-area .comment-reply-link,
:root:not([data-read-mode="night"]) .rc-resume__pct,
:root:not([data-read-mode="night"]) .rc-resume__text svg,
:root:not([data-read-mode="night"]) .rc-library__empty li svg { color: var(--rc-accent); }

:root:not([data-read-mode="night"]) .nav a:not(.btn)::after { background-color: var(--rc-accent); }
:root:not([data-read-mode="night"]) .home-meta__genre:hover,
:root:not([data-read-mode="night"]) .rc-byline-link:hover,
:root:not([data-read-mode="night"]) .rc-byline-link:focus-visible { border-bottom-color: var(--rc-accent); }
:root:not([data-read-mode="night"]) .rc-byline-link:focus-visible,
:root:not([data-read-mode="night"]) .rc-typo__opt:focus-within { outline-color: var(--rc-accent); }
