/**
 * custom.css — project component styles.
 *
 * Empty in the starter. Add component CSS here (or per-section files in
 * assets/css/) as patterns are built. Remember the hard-constraints:
 * no font-size, no margin-for-spacing, no gap — those live in theme.json
 * tokens and block attributes.
 */

/* ==========================================================================
   Quote + pull-quote citations. theme.json styles the FRAMES (core/quote = a red
   accent left rule; core/pullquote = red accent rules top + bottom, display
   serif); the <cite> is core sub-markup with no block attribute of its own, so
   its editorial label treatment — sans, uppercase, muted, on the shared eyebrow
   tracking — lives here. custom.css is an editor style too, so the canvas
   preview matches the front end.
   ========================================================================== */
.wp-block-quote cite,
.wp-block-pullquote cite {
	display: block;
	margin-top: 0.75rem; /* lint-allow: <cite> is core sub-markup, no block attr; not a layout child, so blockGap can't reach it */
	font-family: var(--wp--preset--font-family--sans);
	font-style: normal;
	font-size: var(--wp--preset--font-size--xs); /* lint-allow: preset slug via var; core sub-markup, no fontSize attribute */
	font-weight: 700;
	letter-spacing: 0.08rem; /* match the shared eyebrow / all-caps tracking */
	text-transform: uppercase;
	color: var(--wp--preset--color--stone);
}

/* ==========================================================================
   About page (1863) — image hero + intro card that breaks up over the hero.
   ========================================================================== */

/* Hero: school photo under a green veil. Content aligns to the site column via
   the cover's root-padding gutter (set on the block), not CSS. */
.wulr-page-image-hero {
	min-height: 540px;
}

/* Off-white section carrying the card. `flow-root` establishes a BFC so the
   card's negative top margin lifts ONLY the card over the hero — without it the
   margin collapses through and drags this section's off-white background up over
   the photo, killing the overlap. overflow stays visible so nothing clips. */
.wulr-about-intro {
	display: flow-root;
	overflow: visible;
}

/* White card lifted up over the hero. The lift itself is a block-attr negative
   margin (inline, editor-owned); CSS handles stacking + the elevation so it
   reads as a panel floating over the photo. */
.wulr-about-card {
	position: relative;
	z-index: 1;
	box-shadow: var(--wulr-shadow-lift);
}

/* Short accent rule between the statement and the body copy. */
.wulr-about-rule {
	width: 64px;
	height: 4px;
	border: 0;
	background-color: var(--wp--preset--color--accent);
	margin-inline: 0; /* flush-left; defeats separator auto-centering */
}

/* Big serif lead statement (size comes from the block's xxl fontSize attr). */
.wulr-about-statement {
	font-family: var(--wp--preset--font-family--display);
	line-height: 1.15;
}

/* Right column: editorial-board image (natural display). */
.wulr-board-image img {
	width: 100%;
	height: auto;
	display: block;
}

/* Hero parallax — the large cover photo scrubs vertically on scroll (Osmo
   global-parallax, GSAP/ScrollTrigger via assets/js/gsap/osmo-parallax.js).
   Oversize the cover's background image so the yPercent travel stays inside the
   frame; the cover already clips (overflow: clip). */
.wulr-page-image-hero .wp-block-cover__image-background {
	height: 120%;
	top: -10%; /* centered — room for the symmetric ±6% drift without revealing an edge */
	will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
	.wulr-page-image-hero .wp-block-cover__image-background { transform: none !important; }
}

/* Brand double-rule detail at the TOP of the image hero (right under the green
   section) — thick + thin green lines sitting on the photo, with the photo
   showing through the gap between. Geometry from the shared rule tokens (see
   global.css → brand double-rule mark). */
.wulr-page-image-hero::before,
.wulr-page-image-hero::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	z-index: 2; /* above the (parallaxing) photo + overlay */
	background-color: var(--wp--preset--color--primary);
	pointer-events: none;
}
.wulr-board-label {
	font-family: var(--wp--preset--font-family--primary);
	font-style: italic;
	font-weight: 400;
	letter-spacing: 0;
	text-transform: none;
	color: var(--wp--preset--color--stone);
}

/* ==========================================================================
   Block style: "Double Rule (bottom)" on core/group — the brand thick + thin
   mark (matches the header / archive mark). Registered in functions.php via
   register_block_style().

   Drawn just BELOW the group's bottom edge so it overlaps the following
   section: the two lines carry the group's OWN background colour and the
   transparent gap between them (plus the offset above the thick line) lets the
   NEXT section's colour bleed through — the same geometry as the archive mark,
   only anchored to the bottom of this section instead of the top of the next.
   `z-index` lifts the overflowing mark above the next section; `overflow` must
   stay visible. No bottom padding needed — the mark lives in the next section.
   ========================================================================== */
.wp-block-group.is-style-double-rule {
	position: relative;
	z-index: 1;
	overflow: visible;
}
.wp-block-group.is-style-double-rule::before,
.wp-block-group.is-style-double-rule::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	/* Default = green brand rule (primary sections); overridden per bg below. */
	background-color: var(--wp--preset--color--primary);
	pointer-events: none;
}
/* Thick line sits `offset` below the section edge; the thin line follows a gap
   further down. Both are in the next section's space; the gap + offset are
   transparent, so that section shows through. Weights/offsets are the shared
   rule tokens. */
.wp-block-group.is-style-double-rule::before { top: calc(100% + var(--wulr-rule-offset)); height: var(--wulr-rule-thick); } /* thick */
.wp-block-group.is-style-double-rule::after { top: calc(100% + var(--wulr-rule-thin-offset)); height: var(--wulr-rule-thin); } /* thin */
/* Line colour = the group's own background, so the rule reads as this section
   bleeding a mark down into the next one. */
.wp-block-group.is-style-double-rule.has-muted-background-color::before,
.wp-block-group.is-style-double-rule.has-muted-background-color::after { background-color: var(--wp--preset--color--muted); }
.wp-block-group.is-style-double-rule.has-white-background-color::before,
.wp-block-group.is-style-double-rule.has-white-background-color::after { background-color: var(--wp--preset--color--white); }
.wp-block-group.is-style-double-rule.has-secondary-background-color::before,
.wp-block-group.is-style-double-rule.has-secondary-background-color::after { background-color: var(--wp--preset--color--secondary); }

/* ==========================================================================
   Group extension: shield watermark. The panel (assets/js/editor/group-shield.js)
   sets the `wulr-has-shield is-shield-{pos}` class + inline vars (--wulr-shield-
   color/size/opacity); here the detailed shield is painted as a masked ::before
   behind the group's content. Same CSS runs in the editor (custom.css is loaded
   into the canvas), so the preview matches the frontend.
   ========================================================================== */
.wulr-has-shield {
	position: relative;
	isolation: isolate;
	overflow: hidden;
}
/* Raise real content above a decorative watermark/shield — shared by the
   archive hero, the homepage Explore band, and any shield-extension group. */
.wulr-archive-hero > *:not(.wulr-archive-watermark),
.wulr-explore > *,
.wulr-has-shield > * {
	position: relative;
	z-index: 1; /* lift real content above the watermark */
}
.wulr-has-shield::before {
	content: "";
	position: absolute;
	z-index: 0;
	width: var(--wulr-shield-size, 340px);
	aspect-ratio: 332 / 378;
	background-color: var(--wulr-shield-color, var(--wp--preset--color--primary));
	opacity: var(--wulr-shield-opacity, 0.1);
	-webkit-mask: url(../images/shield-detail.svg) no-repeat center / contain;
	        mask: url(../images/shield-detail.svg) no-repeat center / contain;
	pointer-events: none;
}
.wulr-has-shield.is-shield-center::before { top: 50%; left: 50%; transform: translate(-50%, -50%); }
.wulr-has-shield.is-shield-top-left::before { top: 6%; left: 4%; }
.wulr-has-shield.is-shield-top-right::before { top: 6%; right: 4%; }
.wulr-has-shield.is-shield-bottom-left::before { bottom: 6%; left: 4%; }
.wulr-has-shield.is-shield-bottom-right::before { bottom: 6%; right: 4%; }
.wulr-has-shield.is-shield-left::before { top: 50%; left: 4%; transform: translateY(-50%); }
.wulr-has-shield.is-shield-right::before { top: 50%; right: 4%; transform: translateY(-50%); }

/* ==========================================================================
   Stat row (green hero) — red left rule, big serif figure, muted uppercase
   label. Markup is a Columns block of `.wulr-stat` groups.
   ========================================================================== */
.wulr-stat {
	border-left: 3px solid var(--wp--preset--color--accent);
	padding-left: clamp(0.875rem, 1.6vw, 1.25rem);
}
.wulr-stat-num {
	font-family: var(--wp--preset--font-family--display);
	line-height: 1;
}
.wulr-stat-label {
	font-family: var(--wp--preset--font-family--sans);
	font-weight: 700;
	letter-spacing: 0.08rem; /* match the post-card eyebrow tracking */
	text-transform: uppercase;
}

/* ==========================================================================
   Editing process — "Rigorous by design" (About page).

   Two-column section: eyebrow + heading left, intro + a 2×2 grid of items
   right. Each item title carries an `is-icon-{name}` modifier that paints a
   small accent line icon (assets/images/ep-*.svg) as a CSS-masked ::before —
   same mechanism as the shield watermark, so the editor canvas previews it.
   Icons are pure decoration (CSS backgrounds are invisible to AT); the titles
   carry the meaning. No modifier class = no icon, cleanly.
   ========================================================================== */
.wulr-ep-intro {
	line-height: 1.75;
}
/* Item titles — the same treatment as the timeline era names, so the two
   About sections read as siblings (colour comes from the block's textColor). */
.wulr-ep-title {
	font-family: var(--wp--preset--font-family--primary);
	font-weight: 400;
}
/* Gated to the icon modifiers — a bare .wulr-ep-title::before with no
   mask-image would paint a solid accent square. */
.wulr-ep-title.is-icon-pen::before,
.wulr-ep-title.is-icon-magnifier::before,
.wulr-ep-title.is-icon-book::before,
.wulr-ep-title.is-icon-quotes::before {
	content: "";
	display: block;
	width: 20px;
	height: 20px;
	background-color: var(--wp--preset--color--accent);
	-webkit-mask-repeat: no-repeat;
	        mask-repeat: no-repeat;
	-webkit-mask-position: left center;
	        mask-position: left center;
	-webkit-mask-size: contain;
	        mask-size: contain;
	/* Pseudo-element decoration — blockGap can't reach a ::before, so the
	   icon→title gap has to live here. */
	margin-bottom: 10px;
}
/* ?v=2 = cache-bust: the SVGs were redrawn (thinner 1.5 stroke) at the same
   URLs, and mask images cache hard. */
.wulr-ep-title.is-icon-pen::before {
	-webkit-mask-image: url(../images/ep-pen.svg?v=2);
	        mask-image: url(../images/ep-pen.svg?v=2);
}
.wulr-ep-title.is-icon-magnifier::before {
	-webkit-mask-image: url(../images/ep-magnifier.svg?v=2);
	        mask-image: url(../images/ep-magnifier.svg?v=2);
}
.wulr-ep-title.is-icon-book::before {
	-webkit-mask-image: url(../images/ep-book.svg?v=2);
	        mask-image: url(../images/ep-book.svg?v=2);
}
.wulr-ep-title.is-icon-quotes::before {
	-webkit-mask-image: url(../images/ep-quotes.svg?v=2);
	        mask-image: url(../images/ep-quotes.svg?v=2);
}

/* ==========================================================================
   Timeline — "One journal, four names" (About page).

   A tab set: the rail of years is the tablist, each era is a panel. Progressive
   enhancement — assets/js/timeline.js adds `is-armed` to the section, and ONLY
   the armed state hides inactive panels. With JS off (or before it runs) all
   panels render stacked and readable, so no copy is ever CSS-hidden.

   Geometry note: the rail's dots sit ON the line, so the line is drawn as a
   ::before on the rail and the dots are ::before on each year.
   ========================================================================== */
.wulr-timeline-rail {
	/* Declared on the rail, not the year — the rail's ::before line reads it too,
	   and custom properties only inherit downward. */
	--wulr-timeline-dot: 11px;
	position: relative;
	align-items: flex-start;
}
/* The horizontal line behind the dots. It spans the full rail and the LAST dot
   is pinned to the rail's right edge (see :last-child below), so the line ends
   underneath that final dot — no measuring required, and it holds at any era
   count and any width. */
.wulr-timeline-rail::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: var(--wulr-timeline-dot);
	height: 1px;
	background-color: var(--wp--preset--color--primary);
	transform: translateY(-50%);
}
.wulr-timeline-year {
	position: relative;
	flex: 1 1 0;
	padding-top: calc(var(--wulr-timeline-dot) * 2.4);
	font-family: var(--wp--preset--font-family--sans);
	font-weight: 700;
	letter-spacing: 0.08rem; /* match the shared eyebrow/all-caps tracking */
	line-height: 1;
	cursor: pointer;
	transition: color 0.18s;
}
/* The dot itself. */
.wulr-timeline-year::before {
	content: "";
	position: absolute;
	left: 0;
	top: var(--wulr-timeline-dot);
	width: var(--wulr-timeline-dot);
	height: var(--wulr-timeline-dot);
	border-radius: 50%;
	background-color: var(--wp--preset--color--primary);
	transform: translate(-1px, -50%);
	transition: background-color 0.18s, box-shadow 0.18s;
}
/* `!important` is required, not sloppiness: the year carries WP's `has-stone-color`
   preset class, which sets `color` with !important. Without it these two rules
   silently do nothing and the active year is indistinguishable from the rest.
   Same trap as the has-*-font-size presets. */
.wulr-timeline-year:hover {
	color: var(--wp--preset--color--body) !important;
}
.wulr-timeline-year[aria-selected="true"] {
	color: var(--wp--preset--color--accent) !important;
}
/* Active state is deliberately signalled THREE ways — colour, dot size, and an
   underline — so it doesn't depend on hue alone (WCAG 1.4.1 Use of Color). */
.wulr-timeline-year[aria-selected="true"]::before {
	background-color: var(--wp--preset--color--accent);
	/* Grow the dot from its own centre; the translate keeps it on the rail. */
	transform: translate(-1px, -50%) scale(1.4);
	/* Selection ring, not elevation — so it's derived from the accent token via
	   color-mix rather than a hardcoded rgba or a --wulr-shadow-* level. */
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--wp--preset--color--accent) 22%, transparent);
}
/* Accent underline beneath the active year. Uses ::after, which is free on this
   element — the dot is ::before. */
.wulr-timeline-year::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: -6px;
	width: 1.75rem;
	height: 2px;
	background-color: var(--wp--preset--color--accent);
	opacity: 0;
	transform: scaleX(0.3);
	transform-origin: left center;
	transition: opacity 0.18s, transform 0.18s;
}
.wulr-timeline-year[aria-selected="true"]::after {
	opacity: 1;
	transform: none;
}
.wulr-timeline-year:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 4px;
}

/* Pin the final era to the rail's right edge so the timeline spans the full
   width. Taking it out of flow leaves the remaining years to split the width
   evenly (with blockGap 0 on the rail, the intervals come out equal), and its
   dot flips to the right edge so the line terminates under it. Its label
   shrink-wraps and hangs to the LEFT of that edge, which is why the longer
   "2017 – Now" string doesn't push the layout around. */
.wulr-timeline-year:last-child {
	position: absolute;
	right: 0;
	top: 0;
	text-align: right;
}
.wulr-timeline-year:last-child::before {
	left: auto;
	right: 0;
	transform: translate(0, -50%);
}
.wulr-timeline-year:last-child[aria-selected="true"]::before {
	transform: translate(0, -50%) scale(1.4);
}
/* Underline follows the label to the right edge. */
.wulr-timeline-year:last-child::after {
	left: auto;
	right: 0;
	transform-origin: right center;
}

/* ---- Panels ---- */
/* Arrow row — injected by timeline.js (controls, not content, so it stays out of
   the editor), right-aligned within whatever box it lands in. */
.wulr-timeline-arrows {
	justify-content: flex-end;
	/* Stacked under the heading on mobile: the JS-made wrapper isn't a WP layout
	   child, so it gets no blockGap of its own. Padding, not margin. */
	padding-top: var(--wp--preset--spacing--40);
}

/* UA reset, scoped to the JS-made head wrapper — when timeline.js moves the h2
   inside it, the heading is no longer a direct child of the WP layout container,
   so WP's zeroed layout margins stop reaching it and the browser's default
   h2 margins (±0.83em ≈ 40px at this size) come back, opening a hole between
   the eyebrow and the headline. Mirror WP's reset for whatever lands in here. */
.wulr-timeline-head > * {
	margin-block: 0;
}
/* Breathing room between the headline/arrows row and the rail (client). Padding
   on the wrapper, not blockGap — the wrapper is JS-made, so the editor's
   spacing controls can't reach this interval, and raising the section blockGap
   would reopen the eyebrow→headline gap we just closed. Mirrors the clamp the
   panel uses below the rail, so the rail sits centred in its band. */
.wulr-timeline-head {
	padding-bottom: clamp(1.5rem, 3vw, 2.5rem);
}

/* Desktop: put the arrows on the headline's line. Below this the wrapper stays a
   plain block, so the heading and arrows stack in source order. */
@media (min-width: 782px) {
	.wulr-timeline-head {
		display: flex;
		align-items: center;
		justify-content: space-between;
	}
	.wulr-timeline-arrows {
		padding-top: 0;
	}
}

.wulr-timeline-panel {
	display: flex;
	flex-wrap: wrap;
	/* Top-aligned with the numeral (client). Not baseline: on a 176px figure a
	   baseline match drops the copy to the numeral's feet and pushes the
	   description below it entirely, leaving a large hole top-right. The
	   numeral's 0.82 line-height puts its box top at the glyph top, so
	   flex-start reads as cap-to-cap alignment. */
	align-items: flex-start;
	padding-top: clamp(1.5rem, 3vw, 2.5rem);
}
/* The panel is authored as a flow group but rendered as a flex row, so WP's
   flow blockGap (margin-block-start on the second child) just pushes the copy
   column 24px below the numeral's top. Zero it — layout-container reset; the
   horizontal gap is the numeral's padding-right. */
.wulr-timeline-panel > * {
	margin-block: 0;
}
/* Armed (JS running): one panel at a time, crossfading in. */
.wulr-timeline.is-armed .wulr-timeline-panel { display: none; }
.wulr-timeline.is-armed .wulr-timeline-panel.is-active {
	display: flex;
	animation: wulr-timeline-in 0.32s ease both;
}
@keyframes wulr-timeline-in {
	from { opacity: 0; transform: translateY(8px); }
	to   { opacity: 1; transform: none; }
}
/* The giant numeral. Size comes from the `mega` theme.json preset on the block. */
.wulr-timeline-num {
	font-family: var(--wp--preset--font-family--display);
	line-height: 0.82;
	color: var(--wp--preset--color--primary);
	flex: 0 0 auto;
	padding-right: clamp(1.5rem, 4vw, 3.5rem);
}
.wulr-timeline-copy {
	flex: 1 1 18rem;
	max-width: 34rem;
}
.wulr-timeline-era {
	font-family: var(--wp--preset--font-family--primary);
	font-weight: 400;
	color: var(--wp--preset--color--accent);
}

/* Stack the numeral above the copy once they can't sit side by side. */
@media (max-width: 781px) {
	.wulr-timeline-panel { display: block; }
	.wulr-timeline.is-armed .wulr-timeline-panel.is-active { display: block; }
	.wulr-timeline-num { padding-right: 0; }
}

/* ==========================================================================
   Shared interactive-state treatments.
   Consolidated from per-component rules that carried identical declaration
   bodies (the no-duplicate-rule-bodies gate). Merging is visually inert —
   :hover/:focus-visible win by specificity regardless of source order.
   ========================================================================== */
/* Accent fill + border — icon buttons (article share/stickybar/cite toggles,
   homepage rotator controls, sidenote toggle). */
.wulr-stickybar-btn:hover,
.wulr-stickybar-btn:focus-visible,
.wulr-share-btn:hover,
.wulr-share-btn:focus-visible,
.wulr-cite:not(.is-expanded) .wulr-cite-toggle:hover,
.wulr-featured-playpause:hover,
.wulr-featured-playpause:focus-visible,
.wulr-featured-arrow:hover,
.wulr-featured-arrow:focus-visible,
.wulr-sidenote:not(.is-expanded) .wulr-sn-toggle:hover {
	background: var(--wp--preset--color--accent);
	border-color: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--white);
}
/* Accent fill, no border — action link, primary button, drawer subscribe. */
.wulr-action-link:hover,
.wulr-action-link:focus-visible,
.wulr-btn-primary,
.wulr-drawer-subscribe:hover {
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--white);
}
/* Accent text + bottom rule — inline links / active rotator number. */
.wulr-am-link:hover,
.wulr-am-link:focus-visible,
.wulr-featured-number.is-active,
.wulr-viewall a:hover {
	color: var(--wp--preset--color--accent);
	border-bottom-color: var(--wp--preset--color--accent);
}
/* Accent text + border — pill / thumbnail hovers. */
.wulr-search-grid .wulr-topic-chip:hover,
.wulr-mh-thumb:hover,
.wulr-mh-thumb:focus-visible,
.wulr-count-pill:hover,
.wulr-count-pill:focus-visible {
	color: var(--wp--preset--color--accent);
	border-color: var(--wp--preset--color--accent);
}
