@charset "UTF-8";
/*!
 * Pressline — core stylesheet
 * ---------------------------------------------------------------------------
 * Original work. No third-party CSS is included or derived from.
 *
 * Two rules govern this file:
 *
 * 1. No literal colour values. Every colour resolves through a `--pl-color-*`
 *    custom property emitted by inc/branding.php. That indirection is the
 *    product: a network of sites retints from one profile file without this
 *    stylesheet ever being regenerated, so it stays static and cacheable.
 *    A single hard-coded hex breaks that promise for every site downstream.
 *
 * 2. Class names come from docs/markup-contract.md. Anything invented here is
 *    listed under "Additions" below so the contract can absorb it.
 *
 * Additions beyond the contract (all state classes unless noted):
 *   .is-stuck      — header has left the top of the page
 *   .is-hidden     — header retracted on downward scroll
 *   .is-open       — drawer / submenu / search panel open
 *   .is-visible    — back-to-top button revealed
 *   .is-loading    — infinite scroll request in flight
 *   .is-lazy       — already emitted by inc/ads.php
 *   .pl-load-more  — button element, infinite-scroll fallback (real class)
 *   .pl-nav__expand — submenu disclosure button main.js injects inside the
 *                     drawer, so the parent link stays followable (real class)
 *   .pl-drawer-open — body class while the drawer holds the scroll lock
 *   .pl-container--wide — optional wide variant of the container (real class)
 *   .pl-thumb--thumbnail — not invented: pressline_post_card('compact') asks
 *                     for WordPress's square `thumbnail` size, and
 *                     pressline_post_thumbnail() derives the modifier from the
 *                     size name, so this modifier is already being emitted.
 * Breadcrumbs are styled under both `.pl-breadcrumbs` (the contract's name) and
 * `.pl-breadcrumb` (what inc/schema.php actually prints) until the two agree.
 * Screen-reader-only text uses WordPress core's `.screen-reader-text`, which
 * the pagination markup already relies on, rather than a new utility.
 *
 * Written mobile-first: unqualified rules are the small-screen case and every
 * media query is `min-width`.
 */

/* ==========================================================================
   1. DERIVED TOKENS
   Everything here is computed from the branding variables. Nothing in this
   block introduces a new colour — it only recombines the contract's palette.
   ========================================================================== */

:root {
	/* Spacing. One knob (`--pl-space-unit`) drives the whole rhythm, which is
	   how the compact density profile works without a parallel rule set. */
	--pl-space-3xs: calc(var(--pl-space-unit, 1rem) * 0.25);
	--pl-space-2xs: calc(var(--pl-space-unit, 1rem) * 0.5);
	--pl-space-xs: calc(var(--pl-space-unit, 1rem) * 0.75);
	--pl-space-sm: var(--pl-space-unit, 1rem);
	--pl-space-md: calc(var(--pl-space-unit, 1rem) * 1.5);
	--pl-space-lg: calc(var(--pl-space-unit, 1rem) * 2.25);
	--pl-space-xl: calc(var(--pl-space-unit, 1rem) * 3.25);
	--pl-space-2xl: calc(var(--pl-space-unit, 1rem) * 4.5);

	/* Fluid type scale, roughly a 1.22 ratio at the small end opening to about
	   1.28 at the large. clamp() means no heading needs a breakpoint, which
	   matters here because headline length varies far more than viewport does
	   on a news site. */
	--pl-text-sm: clamp(0.82rem, 0.8rem + 0.1vw, 0.88rem);
	--pl-text-xs: clamp(0.72rem, 0.7rem + 0.08vw, 0.78rem);
	--pl-text-base: 1rem;
	--pl-text-md: clamp(1.06rem, 1.02rem + 0.2vw, 1.16rem);
	--pl-text-lg: clamp(1.22rem, 1.14rem + 0.4vw, 1.42rem);
	--pl-text-xl: clamp(1.42rem, 1.28rem + 0.68vw, 1.78rem);
	--pl-text-2xl: clamp(1.66rem, 1.42rem + 1.15vw, 2.24rem);
	--pl-text-3xl: clamp(1.95rem, 1.56rem + 1.9vw, 2.85rem);
	--pl-text-4xl: clamp(2.3rem, 1.68rem + 2.95vw, 3.6rem);

	/* Prose measure. 68ch lands around 75–80 characters at the default stack,
	   which is the top of the comfortable range for continuous reading. */
	--pl-measure: 68ch;

	--pl-container-pad: clamp(1rem, 0.6rem + 1.6vw, 2rem);
	--pl-sidebar-width: 320px;
	--pl-gutter: clamp(1.25rem, 0.9rem + 1.4vw, 2.5rem);

	--pl-radius-sm: calc(var(--pl-radius, 10px) * 0.5);
	--pl-radius-pill: 999px;

	--pl-header-height: 64px;
	--pl-transition: 180ms;
	--pl-easing: cubic-bezier(0.32, 0.72, 0.32, 1);

	--pl-ticker-duration: 34s;

	/* Scheme-sensitive tokens.
	   These are the ones that do NOT come out right from a palette swap alone:
	   a shadow is "the background colour, darker", and in dark mode there is no
	   darker. A scrim built from `--pl-color-heading` is near-black in light and
	   near-WHITE in dark, which would bleach the photo it sits on instead of
	   darkening it. The values below are the light-scheme fallbacks; the
	   @supports block immediately after swaps them per scheme. */
	--pl-shadow-color: var(--pl-color-heading);
	--pl-shadow-alpha: 12%;
	--pl-shadow-alpha-lift: 20%;
	--pl-scrim-color: var(--pl-color-heading);
	--pl-scrim-alpha: 76%;
	--pl-overlay-color: var(--pl-color-heading);
	--pl-overlay-alpha: 45%;
	/* Placeholder fill behind an image that has not decoded yet. */
	--pl-media-bg: var(--pl-color-surface-alt);

	color-scheme: light;
}

/* `light-dark()` reads the computed `color-scheme`, which inc/branding.php
   already sets correctly for all four states it can emit (light-only site,
   explicit toggle either way, and OS preference). Keying off it means the
   scrim/shadow COLOURS need no duplicated media queries here and cannot
   desynchronise from the palette when a site turns dark_mode off entirely.

   The ALPHAS cannot use it. `light-dark()` is defined in CSS Color 5 for
   <color> values only, so `light-dark(76%, 88%)` is not a valid <percentage>.
   Feeding it to color-mix() invalidated the mix, which invalidated the
   gradient, which made `background-image` compute to `none` — the hero scrim
   silently disappeared and left white headline text sitting on a bare
   photograph. Invisible against a dark image, unreadable against a light one,
   and completely invisible in code review.

   So: colours via light-dark(), alphas via explicit scheme selectors that
   mirror the three states branding.php emits. */
@supports (color: light-dark(white, black)) {
	:root {
		--pl-shadow-color: light-dark(var(--pl-color-heading), var(--pl-color-bg));
		--pl-scrim-color: light-dark(var(--pl-color-heading), var(--pl-color-bg));
		--pl-overlay-color: light-dark(var(--pl-color-heading), var(--pl-color-bg));
	}
}

/* Dark-scheme alphas. A scrim over a photo needs to be heavier in dark mode:
   the surrounding page is dark, so a light-mode alpha reads as a grey haze
   rather than a deliberate gradient. */
[data-scheme="dark"] {
	--pl-shadow-alpha: 52%;
	--pl-shadow-alpha-lift: 68%;
	--pl-scrim-alpha: 88%;
	--pl-overlay-alpha: 74%;
}

@media (prefers-color-scheme: dark) {
	:root:not([data-scheme="light"]) {
		--pl-shadow-alpha: 52%;
		--pl-shadow-alpha-lift: 68%;
		--pl-scrim-alpha: 88%;
		--pl-overlay-alpha: 74%;
	}
}

:root {
	--pl-shadow-tint: color-mix(in srgb, var(--pl-shadow-color) var(--pl-shadow-alpha), transparent);
	--pl-shadow-tint-lift: color-mix(in srgb, var(--pl-shadow-color) var(--pl-shadow-alpha-lift), transparent);
	--pl-shadow-1: 0 1px 2px var(--pl-shadow-tint);
	--pl-shadow-2: 0 2px 6px var(--pl-shadow-tint), 0 1px 2px var(--pl-shadow-tint);
	--pl-shadow-3: 0 10px 30px var(--pl-shadow-tint-lift), 0 2px 6px var(--pl-shadow-tint);

	/* Image scrim. Transparent at the top so the photograph is still legible,
	   opaque at the bottom where the headline sits. */
	--pl-scrim: linear-gradient(
		to bottom,
		transparent 0%,
		color-mix(in srgb, var(--pl-scrim-color) calc(var(--pl-scrim-alpha) * 0.18), transparent) 42%,
		color-mix(in srgb, var(--pl-scrim-color) var(--pl-scrim-alpha), transparent) 100%
	);
	--pl-overlay: color-mix(in srgb, var(--pl-overlay-color) var(--pl-overlay-alpha), transparent);

	/* Text that sits on top of a scrim is always the light-scheme heading
	   colour — the scrim is dark in BOTH schemes, so this must not invert. */
	--pl-on-scrim: var(--pl-color-accent-contrast);
	--pl-hairline: color-mix(in srgb, var(--pl-color-border) 100%, transparent);
	--pl-tint-accent: color-mix(in srgb, var(--pl-color-accent) 12%, transparent);
	--pl-tint-surface: color-mix(in srgb, var(--pl-color-text) 6%, transparent);
}

/* ==========================================================================
   2. RESET
   Trimmed to what actually bites in WordPress output. A kitchen-sink reset
   costs bytes and then gets undone element by element.
   ========================================================================== */

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

html {
	/* iOS inflates text in landscape unless this is pinned, which silently
	   breaks every carefully chosen clamp() below. */
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
	-moz-tab-size: 4;
	tab-size: 4;
	scroll-behavior: smooth;
	/* Anchor links and JS scrolls must clear the sticky masthead. */
	scroll-padding-top: calc(var(--pl-header-height) + var(--pl-space-sm));
}

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd, ol, ul, pre, fieldset, hr {
	margin: 0;
}

ol[class],
ul[class] {
	padding-inline-start: 0;
	list-style: none;
}

body {
	min-height: 100vh;
	margin: 0;
	background-color: var(--pl-color-bg);
	color: var(--pl-color-text);
	font-family: var(--pl-font-body);
	font-size: var(--pl-font-size-base, 17px);
	line-height: var(--pl-line-body, 1.65);
	/* `clip` rather than `hidden`: it kills sideways overflow from a full-bleed
	   block without turning the body into a scroll container, which would break
	   position: sticky on the header. */
	overflow-x: clip;
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

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

img,
video {
	height: auto;
}

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

button {
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
}

a {
	color: var(--pl-color-link);
	text-decoration-thickness: from-font;
	text-underline-offset: 0.16em;
}

a:hover {
	color: var(--pl-color-accent-hover);
}

hr {
	border: 0;
	border-top: 1px solid var(--pl-color-border);
}

table {
	border-collapse: collapse;
	width: 100%;
}

:where(h1, h2, h3, h4, h5, h6) {
	color: var(--pl-color-heading);
	font-family: var(--pl-font-heading);
	font-weight: var(--pl-weight-heading, 700);
	line-height: var(--pl-line-heading, 1.2);
	text-wrap: balance;
	overflow-wrap: break-word;
}

p {
	text-wrap: pretty;
}

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

/* ==========================================================================
   3. TYPOGRAPHY SCALE
   ========================================================================== */

h1 { font-size: var(--pl-text-3xl); }
h2 { font-size: var(--pl-text-2xl); }
h3 { font-size: var(--pl-text-xl); }
h4 { font-size: var(--pl-text-lg); }
h5 { font-size: var(--pl-text-md); }
h6 {
	font-size: var(--pl-text-base);
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

small { font-size: var(--pl-text-sm); }

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

/* ==========================================================================
   4. ACCESSIBILITY BASELINE
   ========================================================================== */

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

/* One ring, everywhere, from a single rule. `:focus-visible` keeps it off
   mouse clicks, so there is no reason left to ever write `outline: none`. */
:focus-visible {
	outline: 2px solid var(--pl-color-accent);
	outline-offset: 2px;
	border-radius: var(--pl-radius-sm);
}

/* On an accent-filled control the accent ring would vanish into the fill. */
.pl-badge:focus-visible,
.pl-load-more:focus-visible,
.pl-back-to-top:focus-visible,
.pl-pagination .page-numbers.current:focus-visible,
[type="submit"]:focus-visible {
	outline-color: var(--pl-color-accent-contrast);
	outline-offset: -4px;
}

.pl-skip-link {
	position: absolute;
	inset-inline-start: var(--pl-space-sm);
	inset-block-start: 0;
	z-index: 1000;
	padding: var(--pl-space-2xs) var(--pl-space-sm);
	background-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
	font-size: var(--pl-text-sm);
	font-weight: 600;
	text-decoration: none;
	border-radius: 0 0 var(--pl-radius) var(--pl-radius);
	/* Translated out of view rather than display:none — a hidden element is not
	   focusable, and this one has to be the first thing a keyboard user hits. */
	transform: translateY(-120%);
	transition: transform var(--pl-transition) var(--pl-easing);
}

.pl-skip-link:focus {
	transform: translateY(0);
	color: var(--pl-color-accent-contrast);
}

[hidden] {
	display: none !important;
}

/* ==========================================================================
   5. LAYOUT
   ========================================================================== */

.pl-container {
	width: 100%;
	max-width: var(--pl-content-width, 1200px);
	margin-inline: auto;
	padding-inline: var(--pl-container-pad);
}

.pl-container--wide {
	max-width: var(--pl-wide-width, 1400px);
}

/*
 * The main grid.
 *
 * Named areas rather than column placement, because the sidebar must be able to
 * sit AFTER the content in the DOM — that is the order a screen reader and a
 * narrow viewport both want, and it puts the article ahead of the widgets for a
 * crawler — while still painting on the left when a profile asks for it. Grid
 * areas decouple those two orders completely; `order` would not, because it
 * only shuffles within a line.
 *
 * `:has()` lets the same rules apply whether the template puts the grid on
 * <main> directly or on a .pl-container inside it. Without :has() support the
 * grid simply never engages and both columns stack — a correct, readable
 * degradation rather than a broken one.
 */
.pl-main {
	padding-block: var(--pl-space-lg);
}

:is(.pl-main, .pl-main > .pl-container):has(> .pl-content) {
	display: grid;
	gap: var(--pl-gutter);
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas:
		"content"
		"sidebar";
	align-items: start;
}

.pl-content {
	grid-area: content;
	min-width: 0; /* Without this a wide table or <pre> blows the column out. */
}

.pl-sidebar {
	grid-area: sidebar;
	min-width: 0;
}

@media (min-width: 62rem) {
	body.pl-sidebar-right :is(.pl-main, .pl-main > .pl-container):has(> .pl-content) {
		grid-template-columns: minmax(0, 1fr) var(--pl-sidebar-width);
		grid-template-areas: "content sidebar";
	}

	body.pl-sidebar-left :is(.pl-main, .pl-main > .pl-container):has(> .pl-content) {
		grid-template-columns: var(--pl-sidebar-width) minmax(0, 1fr);
		grid-template-areas: "sidebar content";
	}
}

body.pl-sidebar-none :is(.pl-main, .pl-main > .pl-container):has(> .pl-content) {
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas: "content";
}

body.pl-sidebar-none .pl-sidebar {
	display: none;
}

/* --- Card grid ----------------------------------------------------------- */

.pl-grid {
	display: grid;
	gap: var(--pl-gutter);
	grid-template-columns: minmax(0, 1fr);
}

/*
 * auto-fit + minmax collapses these without a single breakpoint. The `min()`
 * guard is the part people leave out: a bare `minmax(280px, 1fr)` overflows any
 * container narrower than 280px, which is exactly what a 3-column grid inside a
 * sidebar or a 320px phone produces.
 */
@media (min-width: 34rem) {
	.pl-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
	.pl-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }
	.pl-grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }
}

/* Above four columns auto-fit would keep adding them; cap it. */
@media (min-width: 75rem) {
	.pl-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.pl-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
	.pl-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- Section title ------------------------------------------------------- */

.pl-section-title {
	display: flex;
	align-items: center;
	gap: var(--pl-space-2xs);
	margin-block-end: var(--pl-space-md);
	padding-block-end: var(--pl-space-2xs);
	border-block-end: 2px solid var(--pl-color-border);
	font-size: var(--pl-text-lg);
	letter-spacing: -0.01em;
}

.pl-section-title::before {
	content: "";
	inline-size: 0.28em;
	block-size: 1em;
	background-color: var(--pl-color-accent);
	border-radius: 1px;
	flex: none;
}

/* ==========================================================================
   6. MEDIA — the CLS lever
   ========================================================================== */

/*
 * `.pl-thumb` reserves the crop before the image byte one arrives. Every card
 * on an archive would otherwise start at zero height and shove the grid down as
 * each photo decodes; on a 12-card archive that is most of the page's layout
 * shift, and it is fixed here rather than per-template so it cannot be
 * forgotten.
 *
 * Ratios match the registered crops in inc/setup.php exactly — a mismatch means
 * either letterboxing or a re-crop on paint.
 */
.pl-thumb {
	position: relative;
	display: block;
	overflow: hidden;
	aspect-ratio: 3 / 2;
	background-color: var(--pl-media-bg);
	border-radius: var(--pl-radius);
	isolation: isolate;
}

.pl-thumb__img,
.pl-thumb img {
	inline-size: 100%;
	block-size: 100%;
	/* The reserved box and the intrinsic crop can still disagree by a pixel of
	   rounding; cover absorbs it without distorting faces. */
	object-fit: cover;
	object-position: center;
}

.pl-thumb--card,
.pl-thumb--card-lg { aspect-ratio: 3 / 2; }

.pl-thumb--hero,
.pl-thumb--wide { aspect-ratio: 16 / 9; }

/* `compact` cards request WordPress's square `thumbnail` size. */
.pl-thumb--thumbnail { aspect-ratio: 1 / 1; }

@media (min-width: 48rem) {
	.pl-thumb--hero { aspect-ratio: 21 / 9; }
}

/* Images are deliberately NOT dimmed or filtered in dark mode. News
   photography is evidence; a brightness filter misrepresents it, and readers
   notice on skin tones long before they notice the glare. */

/* ==========================================================================
   7. CARDS
   ========================================================================== */

.pl-card {
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-2xs);
	min-width: 0;
}

.pl-card__media {
	display: block;
	border-radius: var(--pl-radius);
	overflow: hidden;
	/* The media link is aria-hidden with tabindex=-1 (see the contract), so it
	   never takes focus — but a mouse user still expects the hover affordance. */
	transition: transform var(--pl-transition) var(--pl-easing);
}

.pl-card__media .pl-thumb__img {
	transition: transform 320ms var(--pl-easing);
}

.pl-card:hover .pl-card__media .pl-thumb__img,
.pl-card:focus-within .pl-card__media .pl-thumb__img {
	transform: scale(1.04);
}

.pl-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-3xs);
	min-width: 0;
}

.pl-card__cat {
	display: flex;
	flex-wrap: wrap;
	gap: var(--pl-space-3xs);
}

.pl-card__title {
	font-size: var(--pl-text-md);
	line-height: 1.28;
	letter-spacing: -0.011em;
	margin: 0;
}

.pl-card__title a {
	color: var(--pl-color-heading);
	text-decoration: none;
	background-image: linear-gradient(var(--pl-color-accent), var(--pl-color-accent));
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0 1px;
	transition: background-size 220ms var(--pl-easing), color var(--pl-transition) linear;
}

.pl-card__title a:hover,
.pl-card__title a:focus-visible {
	color: var(--pl-color-accent);
	background-size: 100% 1px;
}

.pl-card__excerpt {
	color: var(--pl-color-text-muted);
	font-size: var(--pl-text-sm);
	line-height: 1.55;
}

.pl-card__excerpt p {
	margin: 0;
}

.pl-card__excerpt p + p {
	margin-block-start: var(--pl-space-2xs);
}

/* --- Variant: hero ------------------------------------------------------- */

/*
 * The lead story. On a phone it is a stacked card with the headline under the
 * photo; from tablet up the headline moves onto the image over a scrim, which
 * is why `--pl-on-scrim` exists as a fixed light colour rather than inheriting
 * the palette's text colour.
 */
.pl-card--hero .pl-card__title {
	font-size: var(--pl-text-2xl);
	letter-spacing: -0.02em;
}

.pl-card--hero .pl-card__excerpt {
	font-size: var(--pl-text-base);
}

@media (min-width: 48rem) {
	.pl-card--hero {
		position: relative;
		gap: 0;
	}

	.pl-card--hero .pl-card__media {
		border-radius: var(--pl-radius);
	}

	.pl-card--hero:not(.pl-card--no-media) .pl-card__body {
		position: absolute;
		inset-inline: 0;
		inset-block-end: 0;
		z-index: 1;
		gap: var(--pl-space-2xs);
		padding: var(--pl-space-md);
		border-radius: 0 0 var(--pl-radius) var(--pl-radius);
		/* Scrim, not opacity: opacity on the image would wash out the whole
		   photo, and in dark mode a heading-derived gradient would go white and
		   blow the picture out. See --pl-scrim in the token block. */
		background-image: var(--pl-scrim);
	}

	.pl-card--hero:not(.pl-card--no-media) .pl-card__title a,
	.pl-card--hero:not(.pl-card--no-media) .pl-card__excerpt,
	.pl-card--hero:not(.pl-card--no-media) .pl-meta,
	.pl-card--hero:not(.pl-card--no-media) .pl-meta a {
		color: var(--pl-on-scrim);
	}

	.pl-card--hero:not(.pl-card--no-media) .pl-card__title a {
		background-image: linear-gradient(var(--pl-on-scrim), var(--pl-on-scrim));
	}

	.pl-card--hero .pl-card__title {
		font-size: var(--pl-text-3xl);
	}
}

/* --- Variant: feature ---------------------------------------------------- */

.pl-card--feature .pl-card__title {
	font-size: var(--pl-text-xl);
	letter-spacing: -0.015em;
}

/* --- Variant: grid ------------------------------------------------------- */

.pl-card--grid .pl-card__title {
	font-size: var(--pl-text-md);
}

/* --- Variant: list ------------------------------------------------------- */

.pl-card--list {
	gap: var(--pl-space-sm);
	padding-block-end: var(--pl-space-sm);
	border-block-end: 1px solid var(--pl-color-border);
}

.pl-card--list:last-child {
	border-block-end: 0;
	padding-block-end: 0;
}

@media (min-width: 34rem) {
	.pl-card--list {
		display: grid;
		grid-template-columns: minmax(9rem, 15rem) minmax(0, 1fr);
		align-items: start;
	}

	.pl-card--list.pl-card--no-media {
		grid-template-columns: minmax(0, 1fr);
	}
}

.pl-card--list .pl-card__title {
	font-size: var(--pl-text-lg);
}

/* --- Variant: compact ---------------------------------------------------- */

.pl-card--compact {
	display: grid;
	grid-template-columns: 4.75rem minmax(0, 1fr);
	gap: var(--pl-space-2xs);
	align-items: start;
}

.pl-card--compact.pl-card--no-media {
	grid-template-columns: minmax(0, 1fr);
}

.pl-card--compact .pl-card__title {
	font-size: var(--pl-text-base);
	line-height: 1.34;
}

.pl-card--compact .pl-meta {
	font-size: var(--pl-text-xs);
}

/* --- Variant: no media --------------------------------------------------- */

/*
 * A card with no photograph next to cards that have one reads as an error
 * unless it is given some visual weight of its own. A tinted panel and an
 * accent rule do that without pretending an image exists.
 */
.pl-card--no-media .pl-card__body {
	padding: var(--pl-space-sm);
	background-color: var(--pl-color-surface);
	border-radius: var(--pl-radius);
	border-inline-start: 3px solid var(--pl-color-accent);
}

.pl-card--compact.pl-card--no-media .pl-card__body,
.pl-card--list.pl-card--no-media .pl-card__body {
	padding: 0;
	background: none;
	border-inline-start: 0;
}

/* ==========================================================================
   8. BADGES — per-section tinting
   ========================================================================== */

.pl-badge {
	display: inline-flex;
	align-items: center;
	gap: 0.35em;
	padding: 0.24em 0.6em;
	background-color: var(--pl-badge-bg, var(--pl-color-surface-alt));
	color: var(--pl-badge-fg, var(--pl-color-heading));
	border-radius: var(--pl-radius-sm);
	font-family: var(--pl-font-heading);
	font-size: var(--pl-text-xs);
	font-weight: 700;
	line-height: 1.35;
	letter-spacing: 0.055em;
	text-transform: uppercase;
	text-decoration: none;
	white-space: nowrap;
}

.pl-badge--cat {
	--pl-badge-bg: var(--pl-color-accent);
	--pl-badge-fg: var(--pl-color-accent-contrast);
	transition: background-color var(--pl-transition) linear;
}

.pl-badge--cat:hover,
.pl-badge--cat:focus-visible {
	--pl-badge-bg: var(--pl-color-accent-hover);
	color: var(--pl-badge-fg);
}

/*
 * Per-section tinting.
 *
 * The badge reads its fill from `--pl-badge-bg`, so a section colour is one
 * declaration. Each example below points at a `--pl-cat-{slug}` variable first
 * and falls back to a palette token, which gives three levels of control
 * without touching this file:
 *
 *   1. A profile (or the Customizer) emits `--pl-cat-sport: <colour>` in the
 *      inline token block and the badge picks it up.
 *   2. A child theme adds its own `[data-cat="..."]` rule.
 *   3. Nothing is set and the badge falls back to a semantic token, which is
 *      always in-palette and always contrast-checked.
 *
 * To add a section, copy one line and change the slug — the slug is the
 * category's WordPress slug, emitted as data-cat by pressline_category_badge().
 * Keep the fallback pointing at a `--pl-color-*` token so the site still
 * retints from one profile file.
 */
.pl-badge--cat[data-cat="politics"] { --pl-badge-bg: var(--pl-cat-politics, var(--pl-color-accent)); }
.pl-badge--cat[data-cat="business"] { --pl-badge-bg: var(--pl-cat-business, var(--pl-color-success)); }
.pl-badge--cat[data-cat="sport"],
.pl-badge--cat[data-cat="sports"] { --pl-badge-bg: var(--pl-cat-sport, var(--pl-color-success)); }
.pl-badge--cat[data-cat="technology"],
.pl-badge--cat[data-cat="tech"] { --pl-badge-bg: var(--pl-cat-technology, var(--pl-color-link)); }
.pl-badge--cat[data-cat="health"] { --pl-badge-bg: var(--pl-cat-health, var(--pl-color-success)); }
.pl-badge--cat[data-cat="world"] { --pl-badge-bg: var(--pl-cat-world, var(--pl-color-heading)); }
.pl-badge--cat[data-cat="opinion"] { --pl-badge-bg: var(--pl-cat-opinion, var(--pl-color-warning)); }
.pl-badge--cat[data-cat="entertainment"] { --pl-badge-bg: var(--pl-cat-entertainment, var(--pl-color-warning)); }

/* Sections whose fill is a light-ish semantic token need the dark foreground
   or they fail contrast; `heading` needs the opposite. */
.pl-badge--cat[data-cat="world"] { --pl-badge-fg: var(--pl-color-bg); }

/* ==========================================================================
   9. META
   ========================================================================== */

.pl-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--pl-space-3xs) var(--pl-space-2xs);
	color: var(--pl-color-text-muted);
	font-size: var(--pl-text-sm);
	line-height: 1.4;
}

.pl-meta__item {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
}

/* A separator between items, but never a leading one. */
.pl-meta__item + .pl-meta__item::before {
	content: "";
	inline-size: 3px;
	block-size: 3px;
	margin-inline-end: 0.15em;
	background-color: currentColor;
	border-radius: 50%;
	opacity: 0.6;
	flex: none;
}

.pl-meta a {
	color: inherit;
	text-decoration: none;
	font-weight: 600;
}

.pl-meta a:hover,
.pl-meta a:focus-visible {
	color: var(--pl-color-accent);
	text-decoration: underline;
}

.pl-meta__avatar {
	inline-size: 1.55em;
	block-size: 1.55em;
	border-radius: 50%;
	flex: none;
}

.pl-meta__updated {
	color: var(--pl-color-accent);
	font-weight: 600;
}

.pl-meta__read::after {
	content: "";
}

/* ==========================================================================
   10. TOPBAR
   ========================================================================== */

.pl-topbar {
	background-color: var(--pl-color-surface-alt);
	border-block-end: 1px solid var(--pl-color-border);
	font-size: var(--pl-text-xs);
}

.pl-topbar__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--pl-space-2xs);
	min-block-size: 2.35rem;
	padding-block: var(--pl-space-3xs);
}

.pl-topbar a {
	color: var(--pl-color-text-muted);
	text-decoration: none;
}

.pl-topbar a:hover,
.pl-topbar a:focus-visible {
	color: var(--pl-color-accent);
}

.pl-topbar .pl-nav__list {
	gap: var(--pl-space-sm);
}

@media (max-width: 47.99rem) {
	.pl-topbar__inner {
		justify-content: center;
	}
}

/* ==========================================================================
   11. HEADER
   ========================================================================== */

.pl-site-header {
	position: relative;
	z-index: 100;
	background-color: var(--pl-color-bg);
	border-block-end: 1px solid var(--pl-color-border);
}

/*
 * Sticky only when the profile asks for it. `position: sticky` on <header> is
 * cheap — no scroll listener, no reflow — so the JS in main.js only adds the
 * retract-on-scroll-down behaviour on top of it.
 */
body.pl-has-sticky-header .pl-site-header {
	position: sticky;
	inset-block-start: 0;
	transition: transform 260ms var(--pl-easing), box-shadow var(--pl-transition) linear;
	will-change: transform;
}

body.pl-has-sticky-header .pl-site-header.is-stuck {
	box-shadow: var(--pl-shadow-2);
}

body.pl-has-sticky-header .pl-site-header.is-hidden {
	transform: translateY(-100%);
}

.pl-site-header__inner {
	min-block-size: var(--pl-header-height);
	padding-block: var(--pl-space-2xs);
}

/*
 * __bar is the header row itself - the template nests the logo, the primary
 * nav, and the actions cluster inside it. It was previously styled as though
 * it were only the right-hand actions group, which right-aligned the entire
 * header and left a dead column where the logo should sit.
 *
 * An auto margin on the logo does the separating rather than
 * `justify-content: space-between`, because that keeps the logo hard left
 * even when the nav is missing - which is the state of every fresh install
 * until a menu is assigned to the `primary` location.
 */
.pl-site-header__bar {
	display: flex;
	align-items: center;
	gap: var(--pl-space-md);
	min-block-size: var(--pl-header-height);
}

.pl-site-header__bar > .pl-logo {
	margin-inline-end: auto;
}

/* --- Logo ---------------------------------------------------------------- */

.pl-logo {
	display: inline-flex;
	align-items: center;
	grid-column: 1;
	color: var(--pl-color-heading);
	text-decoration: none;
}

.pl-logo--text {
	font-family: var(--pl-font-heading);
	font-size: var(--pl-text-xl);
	font-weight: 800;
	letter-spacing: -0.035em;
	line-height: 1;
}

.pl-logo__img {
	inline-size: auto;
	max-block-size: 2.6rem;
}

/*
 * Logo swap.
 *
 * Both files are in the markup and CSS chooses — doing this in JS means the
 * wrong mark is painted first and then swapped, which is visible on every load.
 * The three selectors mirror inc/branding.php's own scheme resolution: explicit
 * attribute wins, OS preference applies only when no attribute contradicts it.
 */
.pl-logo__img--dark {
	display: none;
}

[data-scheme="dark"] .pl-logo__img--light { display: none; }
[data-scheme="dark"] .pl-logo__img--dark { display: block; }

@media (prefers-color-scheme: dark) {
	:root:not([data-scheme="light"]) .pl-logo__img--light { display: none; }
	:root:not([data-scheme="light"]) .pl-logo__img--dark { display: block; }
}

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

.pl-nav__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--pl-space-xs);
	margin: 0;
	padding: 0;
	list-style: none;
}

.pl-nav__item {
	position: relative;
}

.pl-nav__link {
	display: flex;
	align-items: center;
	gap: 0.35em;
	padding: var(--pl-space-3xs) 0;
	color: var(--pl-color-heading);
	font-family: var(--pl-font-heading);
	font-size: var(--pl-text-sm);
	font-weight: 600;
	letter-spacing: 0.01em;
	text-decoration: none;
	text-transform: uppercase;
	white-space: nowrap;
}

.pl-nav__link:hover,
.pl-nav__link:focus-visible,
.pl-nav__item.current-menu-item > .pl-nav__link,
.pl-nav__item.current-menu-ancestor > .pl-nav__link {
	color: var(--pl-color-accent);
}

/* Caret, drawn with a rotated border so there is no icon font and no request. */
.pl-nav__item--has-children > .pl-nav__link::after {
	content: "";
	inline-size: 0.42em;
	block-size: 0.42em;
	margin-block-start: -0.22em;
	border-inline-end: 2px solid currentColor;
	border-block-end: 2px solid currentColor;
	transform: rotate(45deg);
	transition: transform var(--pl-transition) var(--pl-easing);
	flex: none;
}

.pl-nav__item--has-children:hover > .pl-nav__link::after,
.pl-nav__item--has-children.is-open > .pl-nav__link::after {
	transform: rotate(-135deg);
	margin-block-start: 0.12em;
}

.pl-nav--primary {
	display: none;
	grid-column: 2;
	min-width: 0;
}

@media (min-width: 62rem) {
	.pl-nav--primary {
		display: block;
	}

	.pl-nav--primary > .pl-nav__list {
		gap: var(--pl-space-sm);
		flex-wrap: nowrap;
		overflow: visible;
	}
}

/* --- Dropdowns ----------------------------------------------------------- */

.pl-nav__submenu {
	position: absolute;
	inset-block-start: 100%;
	inset-inline-start: 0;
	z-index: 20;
	display: flex;
	flex-direction: column;
	gap: 0;
	min-inline-size: 13rem;
	margin: 0;
	padding: var(--pl-space-3xs) 0;
	background-color: var(--pl-color-bg);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius);
	box-shadow: var(--pl-shadow-3);
	list-style: none;
	/* Kept in the accessibility tree and focusable-adjacent: opacity + visibility
	   rather than display, so the open transition can run and so the dropdown
	   does not pop out of the layout mid-keyboard-traversal. */
	opacity: 0;
	visibility: hidden;
	transform: translateY(-0.4rem);
	transition:
		opacity var(--pl-transition) linear,
		transform var(--pl-transition) var(--pl-easing),
		visibility 0s linear var(--pl-transition);
}

.pl-nav__item:hover > .pl-nav__submenu,
.pl-nav__item:focus-within > .pl-nav__submenu,
.pl-nav__item.is-open > .pl-nav__submenu {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
	transition-delay: 0s;
}

.pl-nav__submenu .pl-nav__link {
	padding: var(--pl-space-3xs) var(--pl-space-sm);
	font-size: var(--pl-text-xs);
	text-transform: none;
	letter-spacing: 0;
	white-space: normal;
}

.pl-nav__submenu .pl-nav__link:hover,
.pl-nav__submenu .pl-nav__link:focus-visible {
	background-color: var(--pl-color-surface);
}

/* Third level opens sideways. */
.pl-nav__submenu .pl-nav__submenu {
	inset-block-start: calc(var(--pl-space-3xs) * -1);
	inset-inline-start: 100%;
}

.pl-nav__submenu .pl-nav__item--has-children > .pl-nav__link::after {
	margin-inline-start: auto;
	transform: rotate(-45deg);
}

/* Off the right edge of the viewport the last dropdown flips its anchor. */
@media (min-width: 62rem) {
	.pl-nav--primary > .pl-nav__list > .pl-nav__item:nth-last-child(-n + 2) > .pl-nav__submenu {
		inset-inline-start: auto;
		inset-inline-end: 0;
	}
}

/* --- Header buttons ------------------------------------------------------ */

.pl-menu-toggle,
.pl-search-toggle,
.pl-scheme-toggle,
.pl-drawer__close {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 2.5rem;
	block-size: 2.5rem;
	color: var(--pl-color-heading);
	background-color: transparent;
	border-radius: var(--pl-radius-sm);
	transition: background-color var(--pl-transition) linear, color var(--pl-transition) linear;
}

.pl-menu-toggle:hover,
.pl-search-toggle:hover,
.pl-scheme-toggle:hover,
.pl-drawer__close:hover {
	background-color: var(--pl-color-surface);
	color: var(--pl-color-accent);
}

@media (min-width: 62rem) {
	.pl-menu-toggle {
		display: none;
	}
}

/* Hamburger: three bars from one element plus its two pseudo-elements. */
.pl-menu-toggle::before,
.pl-menu-toggle::after {
	content: "";
	position: absolute;
	inline-size: 1.15rem;
	block-size: 2px;
	background-color: currentColor;
	border-radius: 2px;
	transition: transform var(--pl-transition) var(--pl-easing);
}

.pl-menu-toggle {
	position: relative;
}

.pl-menu-toggle::before { transform: translateY(-0.32rem); }
.pl-menu-toggle::after { transform: translateY(0.32rem); }

.pl-menu-toggle > span {
	inline-size: 1.15rem;
	block-size: 2px;
	background-color: currentColor;
	border-radius: 2px;
}

.pl-menu-toggle[aria-expanded="true"]::before { transform: rotate(45deg); }
.pl-menu-toggle[aria-expanded="true"]::after { transform: rotate(-45deg); }
.pl-menu-toggle[aria-expanded="true"] > span { opacity: 0; }

/* Magnifier: a circle plus a rotated bar. No icon font, no SVG request. */
.pl-search-toggle {
	position: relative;
}

.pl-search-toggle::before {
	content: "";
	inline-size: 0.85rem;
	block-size: 0.85rem;
	border: 2px solid currentColor;
	border-radius: 50%;
	transform: translate(-0.08rem, -0.08rem);
}

.pl-search-toggle::after {
	content: "";
	position: absolute;
	inline-size: 2px;
	block-size: 0.42rem;
	background-color: currentColor;
	border-radius: 2px;
	transform: translate(0.36rem, 0.36rem) rotate(-45deg);
}

/* --- Scheme toggle ------------------------------------------------------- */

/*
 * Sun and moon, both drawn in CSS.
 *
 * The moon is a disc with an inset shadow eating a bite out of it; the sun is a
 * smaller disc with eight box-shadow rays. Two shapes, one element, zero
 * requests — which matters because this button is in the header of every page
 * and an icon font would be a render-blocking round trip for one glyph.
 *
 * The icon shows the scheme you would switch TO, matching the button's label.
 */
.pl-scheme-toggle {
	position: relative;
}

.pl-scheme-toggle__icon {
	position: relative;
	display: block;
	inline-size: 1.05rem;
	block-size: 1.05rem;
	border-radius: 50%;
	/* Light scheme: offer the moon. */
	background-color: transparent;
	box-shadow: inset -0.34rem -0.14rem 0 0 currentColor;
	transform: rotate(-24deg);
	transition: box-shadow 240ms var(--pl-easing), transform 320ms var(--pl-easing);
}

/* Dark scheme: offer the sun. */
[data-scheme="dark"] .pl-scheme-toggle__icon {
	inline-size: 0.62rem;
	block-size: 0.62rem;
	background-color: currentColor;
	transform: rotate(0deg);
	box-shadow:
		0 -0.62rem 0 -0.145rem currentColor,
		0 0.62rem 0 -0.145rem currentColor,
		-0.62rem 0 0 -0.145rem currentColor,
		0.62rem 0 0 -0.145rem currentColor,
		-0.44rem -0.44rem 0 -0.2rem currentColor,
		0.44rem -0.44rem 0 -0.2rem currentColor,
		-0.44rem 0.44rem 0 -0.2rem currentColor,
		0.44rem 0.44rem 0 -0.2rem currentColor;
}

@media (prefers-color-scheme: dark) {
	:root:not([data-scheme="light"]) .pl-scheme-toggle__icon {
		inline-size: 0.62rem;
		block-size: 0.62rem;
		background-color: currentColor;
		transform: rotate(0deg);
		box-shadow:
			0 -0.62rem 0 -0.145rem currentColor,
			0 0.62rem 0 -0.145rem currentColor,
			-0.62rem 0 0 -0.145rem currentColor,
			0.62rem 0 0 -0.145rem currentColor,
			-0.44rem -0.44rem 0 -0.2rem currentColor,
			0.44rem -0.44rem 0 -0.2rem currentColor,
			-0.44rem 0.44rem 0 -0.2rem currentColor,
			0.44rem 0.44rem 0 -0.2rem currentColor;
	}
}

/* --- Search form / overlay ----------------------------------------------- */

.pl-search-form {
	display: flex;
	align-items: center;
	gap: var(--pl-space-3xs);
	inline-size: 100%;
}

.pl-search-form input[type="search"],
.pl-search-form input[type="text"] {
	inline-size: 100%;
	padding: var(--pl-space-2xs) var(--pl-space-xs);
	background-color: var(--pl-color-bg);
	color: var(--pl-color-text);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius-sm);
}

.pl-search-form input[type="search"]::placeholder {
	color: var(--pl-color-text-muted);
}

.pl-search-form button,
.pl-search-form input[type="submit"] {
	padding: var(--pl-space-2xs) var(--pl-space-sm);
	background-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
	border-radius: var(--pl-radius-sm);
	font-size: var(--pl-text-sm);
	font-weight: 700;
	white-space: nowrap;
}

.pl-search-form button:hover,
.pl-search-form input[type="submit"]:hover {
	background-color: var(--pl-color-accent-hover);
}

/*
 * Inside the header the form becomes a drop-down overlay pinned under the
 * masthead rather than a permanent field, because the masthead is already
 * three columns wide on a phone.
 */
.pl-site-header .pl-search-form {
	position: absolute;
	inset-inline: 0;
	inset-block-start: 100%;
	z-index: 30;
	padding: var(--pl-space-sm) var(--pl-container-pad);
	background-color: var(--pl-color-bg);
	border-block-end: 1px solid var(--pl-color-border);
	box-shadow: var(--pl-shadow-2);
	opacity: 0;
	visibility: hidden;
	transform: translateY(-0.5rem);
	transition:
		opacity var(--pl-transition) linear,
		transform var(--pl-transition) var(--pl-easing),
		visibility 0s linear var(--pl-transition);
}

.pl-site-header .pl-search-form.is-open {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
	transition-delay: 0s;
}

/* ==========================================================================
   12. MOBILE DRAWER
   ========================================================================== */

/*
 * Off-canvas panel. Animated with `transform` only — animating `inset-inline-
 * start` or `width` relayouts the whole document on every frame of the slide,
 * which is exactly the wrong thing to do on the low-end phones this pattern
 * exists for.
 *
 * The contract says the drawer carries [hidden] when closed. main.js therefore
 * un-hides first, forces a reflow, then adds .is-open so the transition has a
 * from-state to run from.
 */
.pl-drawer {
	position: fixed;
	inset: 0;
	z-index: 200;
	display: block;
	background-color: var(--pl-overlay);
	opacity: 0;
	transition: opacity 240ms linear;
}

.pl-drawer.is-open {
	opacity: 1;
}

.pl-drawer__panel {
	position: absolute;
	inset-block: 0;
	inset-inline-start: 0;
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-sm);
	inline-size: min(20rem, 86vw);
	max-block-size: 100%;
	padding: var(--pl-space-sm);
	background-color: var(--pl-color-bg);
	box-shadow: var(--pl-shadow-3);
	overflow-y: auto;
	overscroll-behavior: contain;
	transform: translateX(-100%);
	transition: transform 260ms var(--pl-easing);
}

/* Logical property equivalent for RTL, where the drawer comes from the right. */
[dir="rtl"] .pl-drawer__panel {
	transform: translateX(100%);
}

.pl-drawer.is-open .pl-drawer__panel {
	transform: translateX(0);
}

.pl-drawer__close {
	position: relative;
	align-self: flex-end;
	flex: none;
}

.pl-drawer__close::before,
.pl-drawer__close::after {
	content: "";
	position: absolute;
	inline-size: 1.1rem;
	block-size: 2px;
	background-color: currentColor;
	border-radius: 2px;
}

.pl-drawer__close::before { transform: rotate(45deg); }
.pl-drawer__close::after { transform: rotate(-45deg); }

.pl-drawer .pl-nav__list {
	flex-direction: column;
	align-items: stretch;
	gap: 0;
}

.pl-drawer .pl-nav__item {
	border-block-end: 1px solid var(--pl-color-border);
}

.pl-drawer .pl-nav__link {
	padding: var(--pl-space-2xs) 0;
	font-size: var(--pl-text-base);
}

/* Inside the drawer a submenu is a disclosure, not a floating layer. */
.pl-drawer .pl-nav__submenu {
	position: static;
	min-inline-size: 0;
	padding: 0 0 var(--pl-space-2xs) var(--pl-space-sm);
	border: 0;
	box-shadow: none;
	background: none;
	opacity: 1;
	visibility: visible;
	transform: none;
	display: none;
}

.pl-drawer .pl-nav__item.is-open > .pl-nav__submenu {
	display: flex;
}

.pl-drawer .pl-nav__submenu .pl-nav__item {
	border-block-end: 0;
}

/*
 * Submenu disclosure, injected by main.js.
 *
 * The parent list item becomes a row: the link keeps its own hit area and stays
 * followable (section landing pages are real destinations), and the caret next
 * to it is a separate button that only expands. Merging the two — the "first
 * tap opens, second tap navigates" pattern — is fine on a hover-less desktop
 * dropdown but hostile in a drawer, where the reader can see both affordances.
 */
.pl-drawer .pl-nav__item {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
}

.pl-drawer .pl-nav__link {
	flex: 1 1 auto;
}

.pl-nav__expand {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	inline-size: 2.25rem;
	block-size: 2.25rem;
	color: var(--pl-color-text-muted);
	border-radius: var(--pl-radius-sm);
}

.pl-nav__expand::before {
	content: "";
	inline-size: 0.45em;
	block-size: 0.45em;
	margin-block-start: -0.2em;
	border-inline-end: 2px solid currentColor;
	border-block-end: 2px solid currentColor;
	transform: rotate(45deg);
	transition: transform var(--pl-transition) var(--pl-easing);
}

.pl-nav__expand[aria-expanded="true"] {
	color: var(--pl-color-accent);
}

.pl-nav__expand[aria-expanded="true"]::before {
	margin-block-start: 0.12em;
	transform: rotate(-135deg);
}

/* The injected button is drawer-only; if a template ever renders one in the
   desktop bar it inherits the same look without extra rules. */
.pl-drawer .pl-nav__submenu {
	flex-basis: 100%;
}

/* Body scroll lock while the drawer is open. Set by main.js. */
body.pl-drawer-open {
	overflow: hidden;
	/* Compensating for the removed scrollbar stops the page jogging sideways
	   on desktop when the drawer opens. */
	padding-inline-end: var(--pl-scrollbar-width, 0px);
}

/* ==========================================================================
   13. BREAKING TICKER
   ========================================================================== */

.pl-ticker {
	display: flex;
	align-items: stretch;
	gap: var(--pl-space-2xs);
	overflow: hidden;
	background-color: var(--pl-color-surface);
	border-block-end: 1px solid var(--pl-color-border);
	font-size: var(--pl-text-sm);
}

.pl-ticker__label {
	display: inline-flex;
	align-items: center;
	flex: none;
	padding: var(--pl-space-3xs) var(--pl-space-xs);
	background-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
	font-family: var(--pl-font-heading);
	font-size: var(--pl-text-xs);
	font-weight: 800;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	white-space: nowrap;
}

.pl-ticker__items {
	display: flex;
	align-items: center;
	gap: var(--pl-space-lg);
	min-inline-size: max-content;
	margin: 0;
	padding-block: var(--pl-space-3xs);
	list-style: none;
	white-space: nowrap;
	/* Composited transform, so the marquee never triggers layout. */
	animation: pl-ticker-scroll var(--pl-ticker-duration) linear infinite;
	will-change: transform;
}

.pl-ticker__items > * {
	flex: none;
}

.pl-ticker__items a {
	color: var(--pl-color-text);
	font-weight: 600;
	text-decoration: none;
}

.pl-ticker__items a:hover,
.pl-ticker__items a:focus-visible {
	color: var(--pl-color-accent);
	text-decoration: underline;
}

/* Pause on hover AND on focus-within — a keyboard user tabbing into a moving
   strip cannot read or click a link that is sliding away from them. */
.pl-ticker:hover .pl-ticker__items,
.pl-ticker:focus-within .pl-ticker__items {
	animation-play-state: paused;
}

@keyframes pl-ticker-scroll {
	from { transform: translateX(100%); }
	to { transform: translateX(-100%); }
}

/* ==========================================================================
   14. READING PROGRESS / BACK TO TOP
   ========================================================================== */

.pl-progress {
	position: fixed;
	inset-block-start: 0;
	inset-inline: 0;
	z-index: 300;
	block-size: 3px;
	background-color: var(--pl-color-accent);
	/* scaleX is the only property here that can be updated every frame without
	   layout or paint; setting `width` would invalidate layout on each scroll
	   tick, which is precisely the INP problem this bar is famous for. */
	transform: scaleX(var(--pl-progress, 0));
	transform-origin: left center;
	pointer-events: none;
}

/* Stays above the masthead on purpose. Tucking it under a sticky header means
   the bar disappears for the whole time the reader is actually reading, which
   is the only time it has anything to say. */

.pl-back-to-top {
	position: fixed;
	inset-block-end: var(--pl-space-md);
	inset-inline-end: var(--pl-space-md);
	z-index: 90;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 2.75rem;
	block-size: 2.75rem;
	background-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
	border-radius: 50%;
	box-shadow: var(--pl-shadow-3);
	opacity: 0;
	visibility: hidden;
	transform: translateY(0.75rem);
	transition:
		opacity var(--pl-transition) linear,
		transform var(--pl-transition) var(--pl-easing),
		visibility 0s linear var(--pl-transition);
}

.pl-back-to-top.is-visible {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
	transition-delay: 0s;
}

.pl-back-to-top:hover {
	background-color: var(--pl-color-accent-hover);
	color: var(--pl-color-accent-contrast);
}

/* Chevron from two borders. */
.pl-back-to-top::before {
	content: "";
	inline-size: 0.6rem;
	block-size: 0.6rem;
	margin-block-start: 0.22rem;
	border-block-start: 2px solid currentColor;
	border-inline-start: 2px solid currentColor;
	transform: rotate(45deg);
}

/* ==========================================================================
   15. BREADCRUMBS
   ========================================================================== */

.pl-breadcrumbs,
.pl-breadcrumb {
	margin-block-end: var(--pl-space-sm);
	color: var(--pl-color-text-muted);
	font-size: var(--pl-text-xs);
}

.pl-breadcrumb__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--pl-space-3xs);
	margin: 0;
	padding: 0;
	list-style: none;
}

.pl-breadcrumb__item {
	display: inline-flex;
	align-items: center;
	gap: var(--pl-space-3xs);
}

.pl-breadcrumb__item + .pl-breadcrumb__item::before {
	content: "";
	inline-size: 0.34em;
	block-size: 0.34em;
	border-inline-end: 1.5px solid currentColor;
	border-block-start: 1.5px solid currentColor;
	/* Rotated caret: flips automatically in RTL because the border edges are
	   logical properties. */
	transform: rotate(45deg);
	opacity: 0.7;
}

.pl-breadcrumb__link {
	color: inherit;
	text-decoration: none;
}

.pl-breadcrumb__link:hover,
.pl-breadcrumb__link:focus-visible {
	color: var(--pl-color-accent);
	text-decoration: underline;
}

.pl-breadcrumb__current {
	color: var(--pl-color-text);
	font-weight: 600;
}

/* ==========================================================================
   16. ENTRY
   ========================================================================== */

.pl-entry {
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-md);
}

.pl-entry__hero {
	margin-block-end: var(--pl-space-2xs);
}

.pl-entry__hero .pl-thumb {
	aspect-ratio: 16 / 9;
}

.pl-entry__hero figcaption,
.pl-entry__hero .wp-caption-text {
	margin-block-start: var(--pl-space-3xs);
	color: var(--pl-color-text-muted);
	font-size: var(--pl-text-xs);
	line-height: 1.45;
}

.pl-entry__header {
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-2xs);
	max-inline-size: var(--pl-measure);
}

.pl-entry__title {
	font-size: var(--pl-text-4xl);
	letter-spacing: -0.028em;
	line-height: 1.1;
}

/* An article with no featured image needs the headline to carry the top of the
   page on its own, so it gets a little more room. */
body.pl-no-thumb .pl-entry__header {
	padding-block-start: var(--pl-space-sm);
}

.pl-entry__footer {
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-sm);
	padding-block-start: var(--pl-space-sm);
	border-block-start: 1px solid var(--pl-color-border);
}

.pl-entry__tags {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--pl-space-3xs);
	font-size: var(--pl-text-xs);
}

.pl-entry__tags a {
	display: inline-flex;
	padding: 0.24em 0.7em;
	background-color: var(--pl-color-surface);
	color: var(--pl-color-text-muted);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius-pill);
	text-decoration: none;
}

.pl-entry__tags a:hover,
.pl-entry__tags a:focus-visible {
	background-color: var(--pl-color-accent);
	border-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
}

/* ==========================================================================
   17. PROSE — .pl-entry__content
   ========================================================================== */

/*
 * Measure is applied to the children, not the container, so that a wide or full
 * aligned block can opt out by overriding its own max-width. Constraining the
 * container instead would make `.alignwide` impossible without negative margins
 * that break inside the sidebar grid.
 */
.pl-entry__content {
	font-size: var(--pl-text-md);
	line-height: var(--pl-line-body, 1.65);
}

.pl-entry__content > * {
	max-inline-size: var(--pl-measure);
	margin-inline: auto;
}

.pl-entry__content > * + * {
	margin-block-start: var(--pl-space-sm);
}

.pl-entry__content > :is(h2, h3, h4, h5, h6) {
	margin-block-start: var(--pl-space-lg);
	margin-block-end: calc(var(--pl-space-2xs) * -1 + var(--pl-space-sm));
}

.pl-entry__content > h2 { font-size: var(--pl-text-xl); }
.pl-entry__content > h3 { font-size: var(--pl-text-lg); }
.pl-entry__content > h4 { font-size: var(--pl-text-md); }

.pl-entry__content a {
	color: var(--pl-color-link);
	text-decoration: underline;
	text-decoration-thickness: 1px;
}

.pl-entry__content a:hover,
.pl-entry__content a:focus-visible {
	color: var(--pl-color-accent-hover);
	text-decoration-thickness: 2px;
}

.pl-entry__content :is(ul, ol) {
	padding-inline-start: 1.4em;
}

.pl-entry__content li + li {
	margin-block-start: var(--pl-space-3xs);
}

.pl-entry__content li > :is(ul, ol) {
	margin-block-start: var(--pl-space-3xs);
}

.pl-entry__content dt {
	font-weight: 700;
	color: var(--pl-color-heading);
}

.pl-entry__content dd {
	margin-inline-start: 1.2em;
	color: var(--pl-color-text-muted);
}

/* --- Blockquote ---------------------------------------------------------- */

.pl-entry__content blockquote,
.pl-entry__content .wp-block-quote {
	padding: var(--pl-space-2xs) 0 var(--pl-space-2xs) var(--pl-space-sm);
	border-inline-start: 3px solid var(--pl-color-accent);
	color: var(--pl-color-heading);
	font-family: var(--pl-font-heading);
	font-size: var(--pl-text-lg);
	font-style: normal;
	line-height: 1.4;
}

.pl-entry__content blockquote p + p {
	margin-block-start: var(--pl-space-2xs);
}

.pl-entry__content blockquote cite,
.pl-entry__content .wp-block-quote cite {
	display: block;
	margin-block-start: var(--pl-space-2xs);
	color: var(--pl-color-text-muted);
	font-family: var(--pl-font-body);
	font-size: var(--pl-text-sm);
	font-style: normal;
	font-weight: 600;
}

.pl-entry__content .wp-block-pullquote {
	padding-block: var(--pl-space-md);
	border-block: 3px solid var(--pl-color-accent);
	border-inline: 0;
	text-align: center;
}

.pl-entry__content .wp-block-pullquote blockquote {
	padding: 0;
	border: 0;
	font-size: var(--pl-text-xl);
}

/* --- Figures and captions ------------------------------------------------ */

.pl-entry__content :is(figure, .wp-block-image, .wp-caption) {
	margin-block: var(--pl-space-md);
}

.pl-entry__content :is(figure, .wp-block-image) img {
	border-radius: var(--pl-radius);
	margin-inline: auto;
}

.pl-entry__content :is(figcaption, .wp-caption-text) {
	margin-block-start: var(--pl-space-3xs);
	color: var(--pl-color-text-muted);
	font-size: var(--pl-text-xs);
	line-height: 1.45;
	text-align: start;
}

.pl-entry__content .wp-block-gallery figcaption {
	text-align: center;
}

/* --- Tables -------------------------------------------------------------- */

/*
 * A wide table must scroll inside its own box. The alternative — letting it set
 * the width of the column — silently breaks the grid on every phone, and it is
 * always a pasted results table or fixture list that does it.
 *
 * `display: block` on the bare <table> is what makes overflow-x work at all;
 * <table> is not a block container and ignores overflow otherwise.
 */
.pl-entry__content .wp-block-table,
.pl-entry__content figure.wp-block-table {
	overflow-x: auto;
	overscroll-behavior-x: contain;
	-webkit-overflow-scrolling: touch;
}

.pl-entry__content > table {
	display: block;
	overflow-x: auto;
	overscroll-behavior-x: contain;
	max-inline-size: var(--pl-measure);
}

.pl-entry__content table {
	inline-size: 100%;
	border-collapse: collapse;
	font-size: var(--pl-text-sm);
}

.pl-entry__content :is(th, td) {
	padding: var(--pl-space-2xs) var(--pl-space-xs);
	border: 1px solid var(--pl-color-border);
	text-align: start;
	vertical-align: top;
}

.pl-entry__content th {
	background-color: var(--pl-color-surface-alt);
	color: var(--pl-color-heading);
	font-weight: 700;
	white-space: nowrap;
}

.pl-entry__content tbody tr:nth-child(even) td {
	background-color: var(--pl-color-surface);
}

/* --- Code ---------------------------------------------------------------- */

.pl-entry__content :is(pre, .wp-block-code, .wp-block-preformatted) {
	padding: var(--pl-space-sm);
	background-color: var(--pl-color-surface-alt);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius);
	overflow-x: auto;
	font-size: var(--pl-text-sm);
	line-height: 1.55;
	tab-size: 2;
}

.pl-entry__content :not(pre) > code {
	padding: 0.14em 0.38em;
	background-color: var(--pl-color-surface-alt);
	border-radius: var(--pl-radius-sm);
	color: var(--pl-color-heading);
	word-break: break-word;
}

.pl-entry__content kbd {
	padding: 0.1em 0.4em;
	background-color: var(--pl-color-surface);
	border: 1px solid var(--pl-color-border);
	border-block-end-width: 2px;
	border-radius: var(--pl-radius-sm);
}

.pl-entry__content mark,
.pl-entry__content .has-inline-color {
	background-color: var(--pl-tint-accent);
	color: inherit;
	padding: 0 0.2em;
}

.pl-entry__content hr,
.pl-entry__content .wp-block-separator {
	margin-block: var(--pl-space-lg);
	border: 0;
	border-block-start: 1px solid var(--pl-color-border);
}

.pl-entry__content .wp-block-separator.is-style-wide {
	max-inline-size: var(--pl-wide-width, 1400px);
}

/* --- WordPress core alignments ------------------------------------------- */

/*
 * `.alignfull` bleeds to the container's padding edge rather than to the
 * viewport. A true 100vw bleed needs `margin-inline: calc(50% - 50vw)`, which
 * (a) includes the scrollbar width and produces a horizontal scrollbar, and
 * (b) escapes the grid column entirely when there is a sidebar — dragging the
 * image across the widgets. Bleeding to the container is the version that
 * survives all three sidebar settings.
 */
.pl-entry__content > .alignwide {
	max-inline-size: min(var(--pl-wide-width, 1400px), 100%);
}

.pl-entry__content > .alignfull {
	max-inline-size: none;
	inline-size: auto;
	margin-inline: calc(var(--pl-container-pad) * -1);
}

.pl-entry__content > .alignfull img {
	inline-size: 100%;
	border-radius: 0;
}

.pl-entry__content > .aligncenter {
	margin-inline: auto;
	text-align: center;
}

@media (min-width: 48rem) {
	.pl-entry__content > .alignleft {
		float: left;
		max-inline-size: 50%;
		margin-inline: 0 var(--pl-space-sm);
		margin-block: var(--pl-space-3xs) var(--pl-space-2xs);
	}

	.pl-entry__content > .alignright {
		float: right;
		max-inline-size: 50%;
		margin-inline: var(--pl-space-sm) 0;
		margin-block: var(--pl-space-3xs) var(--pl-space-2xs);
	}
}

.pl-entry__content::after {
	content: "";
	display: table;
	clear: both;
}

/* Core colour/background utility classes still have to resolve to palette
   tokens, so the editor's presets are wired to the same variables. */
.has-accent-color { color: var(--pl-color-accent); }
.has-accent-background-color { background-color: var(--pl-color-accent); }
.has-heading-color { color: var(--pl-color-heading); }
.has-surface-background-color { background-color: var(--pl-color-surface); }
.has-surface-alt-background-color { background-color: var(--pl-color-surface-alt); }
.has-muted-color { color: var(--pl-color-text-muted); }

.pl-entry__content .wp-block-button__link {
	display: inline-block;
	padding: var(--pl-space-2xs) var(--pl-space-md);
	background-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
	border-radius: var(--pl-radius-pill);
	font-weight: 700;
	text-decoration: none;
}

.pl-entry__content .wp-block-button__link:hover {
	background-color: var(--pl-color-accent-hover);
	color: var(--pl-color-accent-contrast);
}

.pl-entry__content .wp-block-embed,
.pl-entry__content .wp-block-embed__wrapper {
	max-inline-size: 100%;
}

/* Reserve the ratio for embeds too — a YouTube iframe is as big a shift as a
   photograph. */
.pl-entry__content .wp-block-embed.wp-has-aspect-ratio .wp-block-embed__wrapper {
	position: relative;
	aspect-ratio: 16 / 9;
}

.pl-entry__content .wp-block-embed.wp-has-aspect-ratio iframe {
	position: absolute;
	inset: 0;
	inline-size: 100%;
	block-size: 100%;
}

/* ==========================================================================
   18. SHARE
   ========================================================================== */

/*
 * Deliberately palette-coloured rather than brand-coloured. Vendor brand hexes
 * would be hard-coded colours (rule 1) and third-party trade dress in a theme
 * that gets resold; the label text carries the identification instead.
 */
.pl-share {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--pl-space-3xs);
}

.pl-share__label {
	margin-inline-end: var(--pl-space-3xs);
	color: var(--pl-color-text-muted);
	font-family: var(--pl-font-heading);
	font-size: var(--pl-text-xs);
	font-weight: 700;
	letter-spacing: 0.07em;
	text-transform: uppercase;
}

.pl-share__link {
	display: inline-flex;
	align-items: center;
	gap: 0.35em;
	padding: 0.34em 0.85em;
	background-color: var(--pl-color-surface);
	color: var(--pl-color-heading);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius-pill);
	font-size: var(--pl-text-xs);
	font-weight: 700;
	line-height: 1.5;
	text-decoration: none;
	transition: background-color var(--pl-transition) linear, color var(--pl-transition) linear;
}

.pl-share__link:hover,
.pl-share__link:focus-visible {
	background-color: var(--pl-color-accent);
	border-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
}

/* Small mark before each label so the row scans as buttons rather than text. */
.pl-share__link::before {
	content: "";
	inline-size: 0.55em;
	block-size: 0.55em;
	background-color: currentColor;
	flex: none;
}

.pl-share__link--whatsapp::before { border-radius: 50% 50% 50% 2px; }
.pl-share__link--facebook::before { border-radius: 2px; }
.pl-share__link--twitter::before { clip-path: polygon(0 0, 100% 0, 50% 100%); }
.pl-share__link--telegram::before { clip-path: polygon(0 50%, 100% 0, 60% 100%); }
.pl-share__link--email::before { border-radius: 1px; block-size: 0.42em; }
.pl-share__link--native::before { border-radius: 50%; }

/* ==========================================================================
   19. AUTHOR BOX / RELATED
   ========================================================================== */

.pl-author-box {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	gap: var(--pl-space-sm);
	align-items: start;
	padding: var(--pl-space-sm);
	background-color: var(--pl-color-surface);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius);
}

.pl-author-box__avatar img,
.pl-author-box__avatar .avatar {
	inline-size: 3.6rem;
	block-size: 3.6rem;
	border-radius: 50%;
}

.pl-author-box__body {
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-3xs);
	min-width: 0;
}

.pl-author-box__name {
	font-size: var(--pl-text-md);
	margin: 0;
}

.pl-author-box__name a {
	color: var(--pl-color-heading);
	text-decoration: none;
}

.pl-author-box__name a:hover,
.pl-author-box__name a:focus-visible {
	color: var(--pl-color-accent);
}

.pl-author-box__bio {
	margin: 0;
	color: var(--pl-color-text-muted);
	font-size: var(--pl-text-sm);
	line-height: 1.55;
	max-inline-size: var(--pl-measure);
}

.pl-related {
	margin-block-start: var(--pl-space-lg);
}

/* ==========================================================================
   20. PAGINATION
   ========================================================================== */

.pl-pagination {
	margin-block-start: var(--pl-space-lg);
}

.pl-pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: var(--pl-space-3xs);
}

.pl-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-inline-size: 2.35rem;
	block-size: 2.35rem;
	padding-inline: var(--pl-space-2xs);
	background-color: var(--pl-color-surface);
	color: var(--pl-color-heading);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius-sm);
	font-family: var(--pl-font-heading);
	font-size: var(--pl-text-sm);
	font-weight: 700;
	text-decoration: none;
	transition: background-color var(--pl-transition) linear;
}

.pl-pagination a.page-numbers:hover,
.pl-pagination a.page-numbers:focus-visible {
	background-color: var(--pl-color-surface-alt);
	color: var(--pl-color-accent);
}

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

.pl-pagination .page-numbers.dots {
	background: none;
	border-color: transparent;
	color: var(--pl-color-text-muted);
}

.pl-load-more {
	display: block;
	inline-size: fit-content;
	margin: var(--pl-space-lg) auto 0;
	padding: var(--pl-space-2xs) var(--pl-space-lg);
	background-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
	border-radius: var(--pl-radius-pill);
	font-family: var(--pl-font-heading);
	font-size: var(--pl-text-sm);
	font-weight: 700;
	letter-spacing: 0.03em;
}

.pl-load-more:hover {
	background-color: var(--pl-color-accent-hover);
}

.pl-load-more[disabled],
.pl-load-more.is-loading {
	opacity: 0.65;
	cursor: default;
}

/* ==========================================================================
   21. WIDGETS / SIDEBAR
   ========================================================================== */

.pl-sidebar {
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-md);
}

.widget {
	font-size: var(--pl-text-sm);
}

/*
 * Both heading shapes are styled, and this is not belt-and-braces.
 *
 * `.widget__title` is what register_sidebar()'s before_title produces - i.e.
 * classic widgets. Since WordPress 5.8 the default is BLOCK widgets, which
 * ignore before_title entirely and emit `<h2 class="wp-block-heading">`. On a
 * fresh install every sidebar heading takes the block path, so styling only
 * `.widget__title` leaves them at the browser's default h2 size - larger than
 * the article headlines beside them, with the hierarchy inverted.
 *
 * Scoped under .widget so headings inside post content are untouched.
 */
.widget__title,
.widget .wp-block-heading,
.widget .wp-block-search__label {
	display: flex;
	align-items: center;
	margin-block-end: var(--pl-space-2xs);
	padding-block-end: var(--pl-space-3xs);
	border-block-end: 2px solid var(--pl-color-border);
	color: var(--pl-color-heading);
	font-size: var(--pl-text-md);
	font-weight: var(--pl-weight-heading);
	line-height: var(--pl-line-heading);
	letter-spacing: -0.01em;
}

.widget__title > span {
	position: relative;
	padding-block-end: var(--pl-space-3xs);
	margin-block-end: calc(var(--pl-space-3xs) * -1 - 2px);
	border-block-end: 2px solid var(--pl-color-accent);
}

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

.widget li {
	padding-block: var(--pl-space-3xs);
	border-block-end: 1px solid var(--pl-color-border);
}

.widget li:last-child {
	border-block-end: 0;
}

.widget li a {
	color: var(--pl-color-text);
	text-decoration: none;
	font-weight: 600;
}

.widget li a:hover,
.widget li a:focus-visible {
	color: var(--pl-color-accent);
}

.widget .children,
.widget .sub-menu {
	padding-inline-start: var(--pl-space-sm);
}

.widget select {
	inline-size: 100%;
	padding: var(--pl-space-2xs);
	background-color: var(--pl-color-bg);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius-sm);
}

/* The sticky widget area and the sticky ad slot share this behaviour. */
#sidebar-sticky .widget:last-child,
.pl-ad--sidebar-sticky {
	position: sticky;
	inset-block-start: calc(var(--pl-header-height) + var(--pl-space-sm));
}

/* ==========================================================================
   22. SOCIAL
   ========================================================================== */

.pl-social {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--pl-space-3xs);
}

.pl-social__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 2.15rem;
	block-size: 2.15rem;
	background-color: var(--pl-color-surface-alt);
	color: var(--pl-color-heading);
	border-radius: 50%;
	font-size: var(--pl-text-xs);
	font-weight: 700;
	text-decoration: none;
	transition: background-color var(--pl-transition) linear, color var(--pl-transition) linear;
}

.pl-social__link:hover,
.pl-social__link:focus-visible {
	background-color: var(--pl-color-accent);
	color: var(--pl-color-accent-contrast);
}

/* ==========================================================================
   23. FOOTER
   ========================================================================== */

.pl-site-footer {
	margin-block-start: var(--pl-space-xl);
	background-color: var(--pl-color-surface);
	border-block-start: 1px solid var(--pl-color-border);
	color: var(--pl-color-text-muted);
	font-size: var(--pl-text-sm);
}

.pl-site-footer__widgets {
	display: grid;
	gap: var(--pl-gutter);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
	padding-block: var(--pl-space-lg);
}

.pl-site-footer__bottom {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--pl-space-2xs);
	padding-block: var(--pl-space-sm);
	border-block-start: 1px solid var(--pl-color-border);
	font-size: var(--pl-text-xs);
}

.pl-site-footer a {
	color: var(--pl-color-text);
	text-decoration: none;
}

.pl-site-footer a:hover,
.pl-site-footer a:focus-visible {
	color: var(--pl-color-accent);
	text-decoration: underline;
}

.pl-nav--footer .pl-nav__list {
	gap: var(--pl-space-sm);
}

.pl-nav--footer .pl-nav__link {
	font-size: var(--pl-text-xs);
	text-transform: none;
	letter-spacing: 0;
	color: var(--pl-color-text-muted);
}

/* ==========================================================================
   24. ADS
   ========================================================================== */

/*
 * The reserved height arrives as an inline `min-height` from inc/ads.php, so
 * nothing here may set `height`, `max-height`, or `overflow: hidden` on the
 * wrapper — any of those would either fight the reservation or clip a creative
 * that came back taller than expected.
 */
.pl-ad {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--pl-space-3xs);
	margin-block: var(--pl-space-md);
	padding: var(--pl-space-2xs);
	background-color: var(--pl-color-surface);
	border-radius: var(--pl-radius);
	text-align: center;
}

/*
 * Disclosure label. Paid placement has to be identifiable as paid placement —
 * this is a legal requirement in the US, EU and India and an exchange policy
 * requirement everywhere else. It is styled quiet, never hidden, and must not
 * be given display:none by a child theme.
 */
.pl-ad__label {
	display: block;
	color: var(--pl-color-text-muted);
	font-size: var(--pl-text-xs);
	font-weight: 600;
	letter-spacing: 0.14em;
	line-height: 1.2;
	text-transform: uppercase;
	opacity: 0.8;
}

.pl-ad__inner {
	display: flex;
	align-items: center;
	justify-content: center;
	inline-size: 100%;
	/* Height comes from the inline style; this only stops a creative narrower
	   than the slot from sitting off to one side. */
	overflow-x: auto;
}

.pl-ad__inner > * {
	max-inline-size: 100%;
	margin-inline: auto;
}

/* A reserved-but-unfilled slot shows a faint frame so an editor can see the
   space is real; a live creative covers it. */
.pl-ad--reserved .pl-ad__inner {
	border-radius: var(--pl-radius-sm);
}

.pl-ad--reserved.is-lazy .pl-ad__inner {
	background-color: var(--pl-tint-surface);
}

.pl-ad--header,
.pl-ad--below-header {
	margin-block-start: 0;
}

.pl-ad--in-article {
	margin-block: var(--pl-space-lg);
	max-inline-size: none;
}

.pl-ad--sidebar-top,
.pl-ad--sidebar-sticky {
	margin-block: 0;
}

.pl-ad--footer {
	margin-block-end: 0;
}

/* ==========================================================================
   25. FORMS (search page, blocks, comment form lives in comments.css)
   ========================================================================== */

input[type="text"],
input[type="email"],
input[type="url"],
input[type="search"],
input[type="number"],
input[type="tel"],
input[type="password"],
textarea,
select {
	inline-size: 100%;
	padding: var(--pl-space-2xs) var(--pl-space-xs);
	background-color: var(--pl-color-bg);
	color: var(--pl-color-text);
	border: 1px solid var(--pl-color-border);
	border-radius: var(--pl-radius-sm);
	transition: border-color var(--pl-transition) linear;
}

input:focus,
textarea:focus,
select:focus {
	border-color: var(--pl-color-accent);
}

textarea {
	min-block-size: 8rem;
	resize: vertical;
}

/* ==========================================================================
   26. REDUCED MOTION
   Honoured globally rather than per-component: anything added later inherits
   the behaviour instead of having to remember it.
   ========================================================================== */

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

	/* The ticker must genuinely stop, not run once very fast — a single frantic
	   pass is worse for a vestibular-sensitive reader than the loop. Stopping it
	   leaves content clipped, so the strip becomes manually scrollable. */
	.pl-ticker__items {
		animation: none !important;
		transform: none !important;
		will-change: auto;
	}

	.pl-ticker {
		overflow-x: auto;
		overscroll-behavior-x: contain;
	}

	.pl-card:hover .pl-card__media .pl-thumb__img,
	.pl-card:focus-within .pl-card__media .pl-thumb__img {
		transform: none;
	}
}

/* ==========================================================================
   27. PRINT
   ========================================================================== */

@media print {
	/* The one documented exception to "no literal colours".
	   Print is ink on paper regardless of the reader's chosen scheme — a
	   dark-mode article printed as-is is a solid black page, and a brand accent
	   printed on a mono office laser is unreadable grey. Rather than restyle
	   every component, the palette itself is reassigned for the print context,
	   so every rule in the file above keeps working unchanged. */
	:root {
		--pl-color-bg: #fff;
		--pl-color-surface: #fff;
		--pl-color-surface-alt: #fff;
		--pl-color-text: #000;
		--pl-color-text-muted: #333;
		--pl-color-heading: #000;
		--pl-color-border: #999;
		--pl-color-link: #000;
		--pl-color-accent: #000;
		--pl-color-accent-hover: #000;
		--pl-color-accent-contrast: #fff;
		color-scheme: light;
	}

	body {
		background: #fff;
		color: #000;
		font-size: 11pt;
	}

	.pl-topbar,
	.pl-site-header__bar,
	.pl-nav,
	.pl-menu-toggle,
	.pl-search-toggle,
	.pl-search-form,
	.pl-scheme-toggle,
	.pl-drawer,
	.pl-ticker,
	.pl-progress,
	.pl-back-to-top,
	.pl-share,
	.pl-sidebar,
	.pl-related,
	.pl-pagination,
	.pl-load-more,
	.pl-ad,
	.pl-site-footer__widgets,
	.comment-respond,
	#respond {
		display: none !important;
	}

	:is(.pl-main, .pl-main > .pl-container):has(> .pl-content) {
		display: block;
	}

	.pl-entry__content > * {
		max-inline-size: none;
	}

	/* Expand hrefs — a printed article with invisible links loses its sourcing,
	   which for news is the part that matters most. */
	.pl-entry__content a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 9pt;
		word-break: break-all;
	}

	.pl-entry__content a[href^="#"]::after,
	.pl-entry__content a[href^="mailto"]::after {
		content: "";
	}

	.pl-entry__content :is(h2, h3, h4) {
		break-after: avoid;
	}

	.pl-entry__content :is(figure, blockquote, table, pre) {
		break-inside: avoid;
	}

	.pl-thumb {
		border: 1px solid #999;
	}

	a {
		text-decoration: underline;
	}
}
