/**
 * Option A2, Brick and granite (lehane-172.1).
 *
 * The Customizer carries the palette, type, buttons, header and footer. This file
 * carries what it cannot: three textured materials, the eyebrow label, the ghost
 * button, the cover shadow, and a colour remap inside the dark materials.
 *
 * Two rules keep it honest:
 *   1. Colour comes from var(--ast-global-color-N), or color-mix() over those.
 *      No literal hex, rgb() or named colour except black and transparent inside
 *      color-mix(). A palette change in the Customizer therefore still reaches
 *      every rule here, and the magenta probe can see it.
 *   2. Hooks are className values (is-style-*, lehane-*), never a Kadence
 *      uniqueID class. Kadence rewrites uniqueIDs on "Attempt recovery".
 *
 * Sizes are px. The mockup's rem assumed a 16px root; this site's root is 18px.
 */

/* ---------------------------------------------------------------------------
   Tokens
   Captured at :root so a region can redefine the Astra slot variables without
   referring to itself. A custom property inherits its computed value, so these
   hold the palette colours even inside a region that has remapped the slots.
   ------------------------------------------------------------------------- */
:root {
	--lehane-font-display: 'Oswald', 'Arial Narrow', sans-serif;

	/* The site's content column, border-box: Astra's own
	   `@media (min-width:922px){.ast-container{max-width:1240px}}` — 1200px of
	   content plus the container's 20px gutters. Named here so the one rule that
	   has to restate it (the post-single container, below) does not inline the
	   number, and so a reader can see that 1240 is Astra's figure and not ours.
	   The Task 6 comparator asserts the post single's container against a live
	   non-post single rather than against this constant, so if the Customizer's
	   container width ever moves, the gate goes red instead of this value
	   quietly disagreeing with the rest of the site. */
	--lehane-container: 1240px;

	/* THE PROSE MEASURE, pinned as its own value. §0.6, owner's call 2026-09-23:
	   a post single's prose matches a book or Film & TV single's, so all four
	   single types agree.

	   DERIVATION, stated rather than computed in CSS. On those singles the text is
	   not capped at all: it is the `1fr` track of the .lehane-page-lead grid, i.e.
	   what is LEFT of the 1200px column after the cover and the gutters. Measured
	   live 2026-09-23, the track list is `280px 785px`, and:

	     1200 (column) - 45 - 45 (lead padding) - 45 (gap) - 280 (cover) = 785px

	   WHY THIS IS A LITERAL AND NOT THAT calc(). It was written as the calc() first
	   and that was wrong twice over.

	   1. A custom property substitutes as a TOKEN STREAM, not a computed length, so
	      an `em` inside it resolves at the point of USE. The lead's padding is
	      2.5em, and this value is also assigned to
	      --wp--custom--ast-content-width-size below, which Astra applies to EVERY
	      block child of .entry-content — at that element's own font-size. Measured
	      on a news single: h2 is 44px, so the cap came out
	      calc(1200px - 2*110px - 45px - 280px) = 655px, auto-centred with 65px
	      either side; h3 gave 735px and blockquote 776px, inside 785px paragraphs.
	      Three different measures on one page. Latent only because all five
	      block-mode news posts currently contain nothing but <p>.
	   2. A post single has NO COVER, so the cover's width has no causal bearing on
	      its prose. The equality with the siblings is a consequence of the owner's
	      "match at the design width" decision, not of a shared mechanism. Deriving
	      from --lehane-lead-media inverted that: raising the book cover to 320px
	      silently narrowed prose on all 19 news pages and the derived check stayed
	      green, so the drift read as correct.

	   The relationship is therefore enforced by the Task 6 comparator, which reads
	   the sibling's #primary, lead padding, gap and cover track LIVE and requires
	   the leftover to equal this measure. Divergence turns that red. A px literal
	   here cannot vary per consumer, and the gate — not the cascade — is what
	   notices if the siblings move. */
	--lehane-measure: 785px;

	--lehane-granite: var(--ast-global-color-1);
	--lehane-stone: var(--ast-global-color-5);
	--lehane-brick: var(--ast-global-color-6);
	--lehane-ground: var(--ast-global-color-4);
	--lehane-ink: var(--ast-global-color-2);

	/* On-dark colours. Ratios measured 2026-09-18 against the lightest pixel of
	   a2-granite.jpg, #375066. apply-astra-design.sh points the Customizer's
	   menu hover and copyright colours at the label and muted tokens by name,
	   because Astra's colour sanitizer empties a color-mix() on save. */
	--lehane-on-dark-text: color-mix(in srgb, var(--ast-global-color-4) 88%, var(--ast-global-color-1)); /* 6.32:1 */
	--lehane-on-dark-muted: color-mix(in srgb, var(--ast-global-color-4) 75%, var(--ast-global-color-1)); /* 4.89:1 */
	--lehane-on-dark-label: color-mix(in srgb, var(--ast-global-color-4) 70%, var(--ast-global-color-6)); /* 4.80:1 */

	--lehane-shadow-cover:
		drop-shadow(0 1px 1px color-mix(in srgb, var(--ast-global-color-2) 20%, transparent))
		drop-shadow(0 10px 16px color-mix(in srgb, var(--ast-global-color-2) 18%, transparent));
	--lehane-shadow-on-dark: drop-shadow(0 12px 20px color-mix(in srgb, black 45%, transparent));
}

/* ---------------------------------------------------------------------------
   Materials. Each serves a Kadence row style and a plain class for templates.
   ------------------------------------------------------------------------- */
.lehane-stone,
.wp-block-kadence-rowlayout.is-style-stone {
	background: var(--lehane-stone) url('../textures/a2-stone.jpg') repeat left top / 768px auto;
}

.lehane-granite,
.wp-block-kadence-rowlayout.is-style-granite {
	background: var(--lehane-granite) url('../textures/a2-granite.jpg') repeat left top / 768px auto;
}

.lehane-brick,
.wp-block-kadence-rowlayout.is-style-brick {
	background-color: var(--lehane-brick);
	background-image:
		linear-gradient(
			color-mix(in srgb, color-mix(in srgb, var(--lehane-brick), black 58%) 38%, transparent),
			color-mix(in srgb, color-mix(in srgb, var(--lehane-brick), black 58%) 38%, transparent)
		),
		url('../textures/a2-brick.jpg');
	background-repeat: repeat;
	background-position: left top;
	background-size: auto, 512px auto;
}

/* The remap. Astra colours headings, links and buttons through the slot
   variables at the element, so redefining the slots here turns everything
   inside a dark material light, including the featured-filmtv block, whose
   stylesheet uses nothing but slot variables. Body text is inherited as an
   already-resolved colour, so it needs `color` set here as well. */
.lehane-granite,
.wp-block-kadence-rowlayout.is-style-granite {
	--ast-global-color-0: var(--lehane-ground);          /* links */
	--ast-global-color-1: var(--lehane-on-dark-label);   /* link hover */
	--ast-global-color-2: var(--lehane-ground);          /* headings */
	--ast-global-color-3: var(--lehane-on-dark-text);    /* text */
	--ast-global-color-6: var(--lehane-on-dark-label);   /* labels */
	--ast-global-color-7: color-mix(in srgb, var(--lehane-ground) 22%, var(--lehane-granite)); /* rules */
	--ast-global-color-8: var(--lehane-on-dark-muted);   /* muted */
	color: var(--ast-global-color-3);
}

.lehane-brick,
.wp-block-kadence-rowlayout.is-style-brick {
	--ast-global-color-0: var(--lehane-ground);
	--ast-global-color-1: color-mix(in srgb, var(--lehane-ground) 80%, var(--lehane-brick));
	--ast-global-color-2: var(--lehane-ground);
	--ast-global-color-3: color-mix(in srgb, var(--lehane-ground) 92%, var(--lehane-brick));
	--ast-global-color-6: color-mix(in srgb, var(--lehane-ground) 80%, var(--lehane-brick));
	--ast-global-color-8: color-mix(in srgb, var(--lehane-ground) 80%, var(--lehane-brick));
	color: var(--ast-global-color-3);
}

/* A filled button on brick is granite, as in the mockup. A filled button on
   granite would be ground on ground after the remap, so it gets the same. */
:is(.lehane-brick, .is-style-brick, .lehane-granite, .is-style-granite)
	.wp-block-button__link:not(.is-style-ghost):not(.is-style-ghost *) {
	background-color: var(--lehane-granite);
	color: var(--lehane-ground);
}
:is(.lehane-brick, .is-style-brick, .lehane-granite, .is-style-granite)
	.wp-block-button__link:not(.is-style-ghost):not(.is-style-ghost *):is(:hover, :focus-visible) {
	background-color: color-mix(in srgb, var(--lehane-granite), black 45%);
	color: var(--lehane-ground);
}

/* ---------------------------------------------------------------------------
   The page lead: a media column beside an eyebrow, an H1 and an intro, sitting
   on a material. Extracted from the child theme's css/filmtv.css in Plan 3
   Task 2 (§0.8, §0.9) so the Film & TV title and the book single consume ONE
   component instead of two copies of it. The BEM classes stay on the markup
   beside the generic ones, because the poster shadow, the trailer frame and
   the watch link still key on them.

   SIZES HERE ARE em AND rem, against this file's px rule, and deliberately.
   Every inset below is Astra's OWN computed card padding at that band, read
   from the rendered page on Astra 4.13.2: 1rem from 768px up, 2.5em between
   545 and 767, 1em at 544 and below. The host gives up its padding and the
   lead takes it back, so the two have to be the same number in the same unit.
   A px conversion would freeze that agreement at one root size.

   THE HOST RESET NEEDS AN ID SELECTOR, and a class rule will not do. Astra
   pads this article from three places and the one that wins above 768px is
   `.site .site-content #primary .ast-article-single { padding: 1rem }` at
   (1,3,0) -- the same trap the book-card reset further down documents. A
   (0,3,0) class rule was written first in filmtv.css and lost silently: 390px
   obeyed it, every width from 768px up kept Astra's 18px, and the page looked
   plausible. Matching Astra's shape and adding one class gives (1,4,0), which
   wins on specificity and therefore does not care that this file loads AFTER
   filmtv.css where the rule used to live.

   NOT negative margins. `margin: -2.5em` on the lead made the panel 5em wider
   than its container, and measure-layout.mjs reported overflow at 1200, 1000,
   900 and 768 while 1400 had slack and passed. Nothing here is ever wider
   than its parent.

   The host keeps its BOTTOM padding, because the last child varies: a title
   with no trailer and no watch link ends at .entry-content.

   No colour is declared here. The material is a plain class on the markup.
   ------------------------------------------------------------------------- */
.site .site-content #primary .lehane-page-lead-host.ast-article-single {
	padding: 0 0 2.5em;
}

.lehane-page-lead {
	display: grid;
	grid-template-columns: 1fr;
	gap: 2.5rem;
	margin-bottom: 2.5rem;
	padding: 2.5em;
}

@media (min-width: 768px) {
	.site .site-content #primary .lehane-page-lead-host.ast-article-single {
		padding: 0 0 1rem;
	}

	.lehane-page-lead {
		/* align-items: start matches the mockup's .title .wrap. A centred
		   media column would float against a short intro. */
		grid-template-columns: minmax(200px, 280px) 1fr;
		align-items: start;
	}

	/*
	 * A lead with no image renders no media div at all, so the body becomes
	 * the FIRST grid item and lands in the fixed media track. Measured on the
	 * Film & TV lead with its image suppressed by a filter: the body and the
	 * h1 both sat at 280px inside a 1200px panel at 1400, 900 and 768, with
	 * the 1fr track empty beside them.
	 *
	 * :has() rather than a PHP modifier class, because the book grid below
	 * already keys on `.writing_covers:has(> .book-card)` and a second idiom
	 * for the same job would be the worse choice. Specificity is (0,2,0),
	 * since :not() and :has() each take their argument's, so it beats the
	 * two-column rule above on specificity and not on source order.
	 */
	.lehane-page-lead:not(:has(.lehane-page-lead__media)) {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 544px) {
	.site .site-content #primary .lehane-page-lead-host.ast-article-single {
		padding: 0 0 1.5em;
	}

	.lehane-page-lead {
		margin-bottom: 2rem;
		padding: 1.5em 1em;
	}
}

/* The eyebrow sits above the H1, so the H1 loses the top margin Astra gives a
   first heading and the pair reads as one unit.

   BOTH OF THESE RULES ARE INERT ON THE FILM & TV LEAD TODAY. Measured with
   CSS.getMatchedStylesForNode, not assumed: Astra's
   `header.entry-header > :not(:last-child) { margin-bottom: 10px }` is (0,2,1)
   and beats the eyebrow rule at (0,1,0), and the theme's own element reset
   already zeroes h1 margin-top, so the title rule changes nothing either.
   They are moved verbatim rather than dropped because §0.9 lists them and a
   lead whose markup puts the eyebrow outside header.entry-header will need
   them.

   THE EYEBROW RULE SITS BEFORE .lehane-eyebrow BELOW ON PURPOSE. Those two are
   both (0,1,0) and source order decided between them before this move, with
   .lehane-eyebrow's 12px winning because filmtv.css loaded first. Putting this
   rule after it would hand the 0.5rem back and change a page this task is
   supposed to leave identical. */
.lehane-page-lead__eyebrow {
	margin: 0 0 0.5rem;
}

.lehane-page-lead .entry-title {
	margin-top: 0;
}

/* ---------------------------------------------------------------------------
   Section headings inside a Kadence row keep the mockup's rhythm.
   ------------------------------------------------------------------------- */
.wp-block-kadence-advancedheading.is-style-eyebrow,
.lehane-eyebrow {
	font-family: var(--lehane-font-display);
	font-size: 14px;
	font-weight: 500;
	font-style: normal;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	line-height: 1.3;
	color: var(--ast-global-color-6);
	margin: 0 0 12px;
}

/* ---------------------------------------------------------------------------
   Kadence buttons that inherit theme styles.
   Kadence adds .wp-block-button__link and .button, but Astra styles those only
   under a .wp-block-button parent, which Kadence does not render. Core's
   `:root :where(.wp-element-button, .wp-block-button__link)` then wins with
   #32373c and inherited body type. These values MIRROR the Customizer button
   settings in ~/lehane-migration/apply-astra-design.sh. Change them together.
   The front end renders a.kb-button.kt-button; the editor renders span.kt-button
   with no .kb-button. The shared classes below match both.
   ------------------------------------------------------------------------- */
.kt-button.kb-btn-global-inherit.wp-block-button__link {
	font-family: var(--lehane-font-display);
	font-size: 15px;
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	line-height: 1.2;
	padding: 13px 24px;
	border: 0;
	border-radius: 0;
	background-color: var(--ast-global-color-0);
	color: var(--ast-global-color-4);
	text-decoration: none;
}
.kt-button.kb-btn-global-inherit.wp-block-button__link:is(:hover, :focus-visible) {
	background-color: var(--ast-global-color-1);
	color: var(--ast-global-color-4);
}
.wp-block-kadence-advancedbtn.kb-buttons-wrap {
	gap: 12px;
}

/* ---------------------------------------------------------------------------
   Ghost button. On the front end Kadence puts the block's className on the
   link itself; in the editor it sits on the block wrapper. currentColor
   carries the region's link colour into the border, so on granite it turns
   light with no extra rule.
   ------------------------------------------------------------------------- */
.kt-button.wp-block-button__link.is-style-ghost,
.is-style-ghost .kt-button.wp-block-button__link {
	background-color: transparent;
	color: var(--ast-global-color-0);
	border: 0;
	box-shadow: inset 0 0 0 2px currentColor;
}
.kt-button.wp-block-button__link.is-style-ghost:is(:hover, :focus-visible),
.is-style-ghost .kt-button.wp-block-button__link:is(:hover, :focus-visible) {
	background-color: transparent;
	color: var(--ast-global-color-1);
}

/* ---------------------------------------------------------------------------
   Cover and poster art: a soft two-layer shadow on light grounds, one deeper
   shadow on granite. Astra's own 30px image shadow stays off in the Customizer.
   ------------------------------------------------------------------------- */
.wp-block-kadence-image.is-style-cover img,
.book-card__cover img {
	filter: var(--lehane-shadow-cover);
}
:is(.lehane-granite, .is-style-granite) .book-card__cover img {
	filter: var(--lehane-shadow-on-dark);
}
/* filmtv.css clips the poster img with overflow:hidden on its frame, which
   would clip a shadow on the img. The frame's own filter is not clipped by
   its own overflow, and object-fit:cover fills the frame, so the shadow goes
   on the frame. */
:is(.lehane-granite, .is-style-granite) .filmtv-card__poster {
	filter: var(--lehane-shadow-on-dark);
}

/* ---------------------------------------------------------------------------
   Book card grid, for the theme's covers layouts. The wrapper's classes come
   from the theme and carry flex rules from _writing.css, so the grid is set
   here and those rules are neutralised.
   The theme's blocks accept column_count-1 to -6, and writing-by-taxonomy-series
   can emit -0. Every count sets --lehane-book-cols. No count, or 0, gets six.
   ------------------------------------------------------------------------- */
.writing_covers:has(> .book-card) {
	--lehane-book-cols: 6;
	display: grid;
	grid-template-columns: repeat(var(--lehane-book-cols), minmax(0, 1fr));
	gap: 48px;
	margin: 0;
	align-items: start;
	justify-content: stretch;
}
.writing_covers.column_count-1 { --lehane-book-cols: 1; }
.writing_covers.column_count-2 { --lehane-book-cols: 2; }
.writing_covers.column_count-3 { --lehane-book-cols: 3; }
.writing_covers.column_count-4 { --lehane-book-cols: 4; }
.writing_covers.column_count-5 { --lehane-book-cols: 5; }
/* Two classes on the card to outrank _writing.css's
   .writing_covers.column_count-N .writing_cover_excerpt max-width rules. */
.writing_covers > .writing_cover_excerpt.book-card {
	flex: none;
	max-width: none;
	width: auto;
	padding: 0;
	margin: 0;
	text-align: left;
}
/* Fixed 2:3 box, contain, never cover: a jacket is never cropped.
   Scoped under .writing_covers to outrank _writing.css's image margin. */
.writing_covers .book-card__cover img,
.book-card__cover img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 2 / 3;
	object-fit: contain;
	object-position: left bottom;
	margin: 0;
}
/* A book with no cover of its own, and no parent_writing cover to borrow. */
.book-card__placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	aspect-ratio: 2 / 3;
	background-color: var(--ast-global-color-7);
	color: var(--ast-global-color-8);
	font-family: var(--lehane-font-display);
	font-size: 15px;
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	text-align: center;
}
.book-card__link {
	display: block;
	text-decoration: none;
	color: inherit;
}
.book-card__title {
	font-size: 22px;
	font-weight: 500;
	margin: 12px 0 0;
	color: var(--ast-global-color-2);
}
.book-card__link:is(:hover, :focus-visible) .book-card__title {
	color: var(--ast-global-color-0);
}

/* Narrower screens never widen a grid. Source order decides between these
   rules, which all share specificity (0,2,0). */
@media (max-width: 1024px) {
	.writing_covers:has(> .book-card) { --lehane-book-cols: 3; }
	.writing_covers.column_count-1 { --lehane-book-cols: 1; }
	.writing_covers:is(.column_count-2, .column_count-3, .column_count-4) { --lehane-book-cols: 2; }
}
@media (max-width: 640px) {
	.writing_covers:has(> .book-card) { --lehane-book-cols: 2; gap: 24px; }
	.writing_covers.column_count-1 { --lehane-book-cols: 1; }
}

/* ---------------------------------------------------------------------------
   The books index's sections: Novels, Anthologies & Collections, Dennis Lehane
   Books. Each is the landing point for one item in the Books submenu, which has
   linked /books/#novels, #anthologies and #imprint since the menu was built.
   templates/archive-writing.php emits them; lehane_books_sections() in
   inc/design.php maps each anchor to its `writing_type` term.

   THE HEADING IS A SIBLING OF THE GRID, NOT INSIDE IT. The grid rules above key
   on `.writing_covers:has(> .book-card)` and on a direct-child card selector, so
   an <h2> inside the wrapper would become a grid item in the first cell and push
   the first cover out of line.

   scroll-margin-top is what stops an anchored heading landing flush against the
   top of the window. The masthead does not stick, so this is breathing room
   rather than clearance for a fixed bar -- 40px, about the heading's own line.
   The logged-in admin bar IS fixed at 32px, so this doubles as clearance there.
   ------------------------------------------------------------------------- */
.lehane-books-section {
	scroll-margin-top: 40px;
}

/* Between sections, not above the first: the archive header already sets the
   distance from the H1 down to the first heading. :first-child rather than a
   margin on every section and a reset on one, so there is a single source for
   the gap. */
.lehane-books-section + .lehane-books-section {
	margin-top: 72px;
}

.lehane-books-section__title {
	font-size: 30px;
	margin: 0 0 28px;
	color: var(--ast-global-color-2);
}

@media (max-width: 640px) {
	.lehane-books-section + .lehane-books-section {
		margin-top: 48px;
	}
	.lehane-books-section__title {
		font-size: 24px;
		margin-bottom: 20px;
	}
}

/* ---------------------------------------------------------------------------
   Masthead and footer: what the Customizer cannot set.
   Astra's "image" background type emits no colour, so the slot-1 colour sits
   under the texture here, for the moment before it loads.
   ------------------------------------------------------------------------- */
.ast-primary-header-bar,
.site-below-footer-wrap[data-section="section-below-footer-builder"] {
	background-color: var(--lehane-granite);
}
.ast-site-identity .site-title,
.ast-site-identity .site-title a {
	text-transform: uppercase;
	letter-spacing: 0.04em;
	font-weight: 600;
}
/* The Books submenu. Astra would paint it with the menu's own background
   option, which would also lay a flat colour over the granite behind the
   top-level items. */
.ast-builder-menu-1 .main-header-menu .sub-menu {
	background-color: var(--lehane-granite);
	border-color: var(--lehane-brick);
}

/* ---------------------------------------------------------------------------
   Page sections built from Kadence rows.
   ------------------------------------------------------------------------- */

/* Astra's full-width page template sets max-width:none on every child of an
   alignfull block, at specificity (0,4,0). That erases a Kadence row's own
   maxWidth, which is only (0,2,0), and row content ran edge to edge. Put
   Astra's container width back, so row content lines up with the masthead.
   This sets 1240px on EVERY full-width row, whatever maxWidth the row itself
   carries, and the editor still honours the row's own value. Every row in
   patterns/ is 1240. A row that needs another width needs its own rule here. */
.ast-page-builder-template .entry-content[data-ast-blocks-layout] > .wp-block-kadence-rowlayout.alignfull > .kt-row-column-wrap {
	max-width: calc(var(--wp--custom--ast-container-width, 1200px) + 40px);
}

/* Astra underlines every link in a single entry's content. Cards are not prose. */
.ast-single-post .entry-content :is(a.book-card__link, .filmtv-card a, .lehane-news-list .entry-title a) {
	text-decoration: none;
}

/* A section's closing button sits a full step below its grid. */
:is(.lehane-books, .lehane-filmtv-band) .wp-block-kadence-advancedbtn {
	margin-top: 48px;
}

/* The poster strip stays narrower than the container, as in the mockup. */
.lehane-filmtv-band .filmtv-featured {
	max-width: 840px;
}

/* post_class() gives every card Astra's ast-article-single, and Astra pads it
   with `.site .site-content #primary .ast-article-single`, an ID selector no
   class rule can outrank. Match its shape and add one class. */
.site .site-content #primary :is(.book-card, .lehane-news-list .loop-entry) {
	padding: 0;
}

/* News: Kadence's posts block, reduced to headline and date. */
.lehane-news-list .entry-content-wrap {
	padding: 0;
}
/* Three classes to outrank Astra's `header.entry-header .entry-title`. */
.lehane-news-list .entry-header .entry-title {
	font-size: 22px;
	font-weight: 500;
	line-height: 1.2;
	margin: 0 0 6px;
}
.lehane-news-list .entry-title a {
	color: var(--ast-global-color-2);
}
.lehane-news-list .entry-title a:is(:hover, :focus-visible) {
	color: var(--ast-global-color-0);
}
.lehane-news-list .entry-meta {
	font-size: 16px;
	font-weight: 400;
	color: var(--ast-global-color-8);
	text-transform: none;
	letter-spacing: normal;
}

/* The brick band's heading is a band title, not a section heading. It carries
   no eyebrow: the label colour on brick is 3.88:1 on the lightest texture pixel.
   The paragraph keeps the band's text colour, slot 3 after the remap, for the
   same reason: 4.72:1 there, where slot 8 was 3.88:1. */
.lehane-contact-band .lehane-contact-band__title {
	font-size: 28px;
	margin: 0 0 12px;
}
.lehane-contact-band p {
	margin: 0;
}

/* -------------------------------------------------------------------------
 * ONE PAGE HEADER FOR THE WHOLE SITE.
 *
 * Six top-level URLs rendered six different title treatments. Measured at
 * 1689px on 2026-09-24, before this block existed:
 *
 *   /about-dennis/, /contact/   32px    600  lh 1.2   pad 0      mb 27
 *   /books/, /category/*        32px    600  lh 1.4   pad 54     mb 36
 *   /events/                    51.43px 300  lh 1.4   pad 90/60  mb 36
 *   /film-and-tv/               64px    400  lh 1.4   pad 0      h1 mb 64
 *   /news/                      64px    600  lh 1.1   pad 0      mb 45
 *
 * The About page was the oracle for the SHAPE and all six were brought to it:
 * Oswald 600, line-height 1.2, 0.01em tracking, 0.6em under the title, 1.5em
 * under the block, no panel and no padding. Those numbers are Astra's, not
 * ours -- `.ast-single-post .entry-title` in main.min.css gives the 1.2, the
 * h1..h6 dynamic rule gives Oswald and 0.01em, `.entry-title{margin-bottom:
 * 0.6em}` gives the space under the title, and the entry header's own 1.5em
 * gives the 27px under the block. The two bottom margins are adjoining and
 * collapse to the larger of the pair, which is why this block sets both
 * rather than one combined number.
 *
 * THE SIZE IS A CHOICE AND NOT ASTRA'S. 42px, set here rather than inherited,
 * because About's own 32px is only 2px clear of the 30px
 * `.lehane-books-section__title` and the two read as peers on /books/ once the
 * archive header's 54px of padding stopped separating them. 42px restores the
 * step without touching the section titles, which stay at 30px. The About
 * page's own h1 is in this rule's selector list for that reason: it moves WITH
 * the set instead of being the thing the set is pinned to.
 *
 * SINGLES ARE DELIBERATELY NOT IN THIS RULE. A book, Film & TV or event
 * single puts its h1 inside `.lehane-page-lead` -- a stone panel beside a
 * 280px cover and under its own eyebrow -- which is a different composition
 * from a bare page header, and it stays at Astra's 32px. `body.page` is what
 * keeps them out, and not the `>` combinator, which is there for a different
 * job -- see below.
 *
 * THE `>` KEEPS THE HOMEPAGE NEWS CARDS OUT. The front page is a `body.page`
 * too, and its Kadence posts grid renders three
 * `.entry-header > .entry-title` card titles inside `.entry-content`. Without
 * the combinator this rule is (1,3,1) against `.lehane-news-list .entry-header
 * .entry-title` at (0,3,0), so it wins and the three card titles jump from
 * 20px to 42px. A page's OWN header is `article.ast-article-single >
 * header.entry-header` and a card's never is, so the direct child is the line
 * between them. If Astra ever wraps a page header the way it wraps a single's
 * this rule goes inert and every page title drops to 32px while the archives
 * stay at 42px -- loud, not silent, which is why the structural selector is
 * tolerable here and was not for the singles.
 *
 * WHY THE SPREAD EXISTED -- three sources, none of them wrong on its own.
 * Astra's Customizer emits a PER-POST-TYPE archive banner block, and `writing`
 * has one configured while `event` does not: /books/ got
 * `body.archive .ast-archive-description .ast-archive-title{font-weight:600;
 * font-size:32px}` and /events/ fell through to main.min.css's 40px/300. Film
 * & TV has its own header markup and no rule of any kind, so its h1 took the
 * generic `h1{font-size:3.5556rem;line-height:1.4em}`. News had a rule that
 * chased the A2 spec's 64px display size, which reads as a display title on a
 * page whose siblings do not have one.
 *
 * SPECIFICITY. `#primary` plus one class is (1,1,0) on the container and
 * (1,2,0) on the archive title. The tallest thing either has to beat is
 * Astra's (0,3,0) `body.archive .ast-archive-description .ast-archive-title`,
 * and one id outranks any number of classes. The page-title half is (1,3,1)
 * against Astra's (0,2,1) `header.entry-header .entry-title`. So no
 * !important and no media query is needed at any width, and neither Astra
 * source is responsive on this site.
 *
 * REM AGAIN: 2.3333333333rem is 42px at this site's 18px root.
 *
 * EVERY `.ast-archive-description` ON THE SITE, deliberately, which is the
 * opposite of the rule this replaces. That one was scoped to /books/ and
 * /events/ because Plan 4 §0.11 declined to build the taxonomy archives. The
 * taxonomy archives are still not being built -- they are only being kept from
 * disagreeing with the pages that were. It reaches the seven /category/, seven
 * /tag/, three /series/ and three /writing-type/ archives plus the author and
 * date archives, all of which were on /books/'s 54px-padded treatment.
 *
 * `background: none` drops the `.ast-separate-container` panel colour, which
 * is #FAF7F2 -- the same value as `body`, with no image on either -- so it is
 * a no-op to look at and makes the header genuinely match About's unpanelled
 * one instead of matching it by coincidence.
 *
 * `:is()` is safe here because all three arguments are single classes, so the
 * group carries the same specificity as each member. Do not add a compound
 * selector to either list without re-checking that -- :is() takes its
 * argument's specificity, and that trap already cost this codebase a day on
 * the motion layer.
 * ---------------------------------------------------------------------- */
#primary :is(.ast-archive-description, .filmtv-header, .lehane-news-header) {
	max-width: none;
	margin: 0 0 1.5em;
	padding: 0;
	background: none;
	border-bottom: 0;
}

#primary :is(.ast-archive-description, .filmtv-header, .lehane-news-header) .page-title,
body.page #primary .ast-article-single > .entry-header .entry-title {
	font-family: var(--lehane-font-display);
	font-size: 2.3333333333rem;
	font-weight: 600;
	line-height: 1.2;
	letter-spacing: 0.01em;
	color: var(--ast-global-color-2);
	text-transform: none;
	margin: 0 0 0.6em;
}

/* -------------------------------------------------------------------------
 * Pin the event card's typography across Task 2's heading-level change.
 *
 * Step 3b re-tagged the card title h4 -> h2 and the venue line h5 -> p, so
 * the archive's outline stops skipping two levels under its single h1. That
 * is a SEMANTIC change only. No new look was designed for this card and Plan
 * 4 does not restyle it, so the card must render exactly as it did before.
 *
 * Class names alone do not carry that, because the properties that moved are
 * the ones derived from the tag. `.event_title` (css/_events.css:89-93) sets
 * margin, border and font-weight but NO font-size, and `.excerpt_location`
 * has no base rule at all — only `.excerpt_location a` (:125-128), which
 * never applies, because the archive venue is plain esc_html() text with no
 * link. The tag was carrying the typography. Measured on the live cascade:
 *
 *   .event_title       h4 22px/26.4px  ->  h2 44px/57.2px      (size doubles)
 *   .excerpt_location  h5 18px/21.6px Oswald 600
 *                       ->  p 18px/28.8px Source Sans 3 400
 *
 * These rules restore the pre-change computed values. Astra's h4/h5 sizes are
 * not responsive on this site — measured constant across 1400, 1200, 1000,
 * 900, 768 and 390 — so fixed values are exact here, not an approximation.
 *
 * Only the properties that actually moved are pinned. `.event_title`'s weight
 * (500) and family (Oswald) measured identical as h2 and as h4, because
 * _events.css at (0,1,0) already beats Astra's element-level heading rules
 * for the weight and both tags take Oswald from the same h1..h6 rule.
 *
 * SCOPED TO THE CARD, which makes it a no-op everywhere it is not needed.
 * `.event_excerpt` is emitted only by this plugin's excerpt-event part and by
 * the theme's excerpt-event and widget-event parts. The first is the file
 * this task changed; the second is shadowed by it; the third still uses h4
 * and has no venue line, so these values are already what it computes.
 *
 * (0,2,0) beats every element-level heading rule Astra sets, and nothing in
 * the cascade uses !important on these. Colour is deliberately untouched.
 *
 * THE CARD RENDERS ZERO TIMES TODAY. The archive query is filtered to
 * upcoming events and all 19 of this site's events are historical (Plan 4
 * §0.1, Ruling 1). This pin is what keeps the card right on the day one
 * becomes upcoming, with no comparator able to watch it in the meantime.
 * ---------------------------------------------------------------------- */
.event_excerpt .event_title {
	font-size: 22px;
	line-height: 26.4px;
}

.event_excerpt .excerpt_location {
	font-family: Oswald, "Arial Narrow", sans-serif;
	font-size: 18px;
	font-weight: 600;
	line-height: 21.6px;
}

/* -------------------------------------------------------------------------
 * Keep the event single's header a two-up row across Task 3's heading change.
 *
 * Task 3 re-tagged the date line <h4 class="date_time"> -> <p class="date_time
 * lehane-eyebrow">, so the single's outline stops skipping two levels under its
 * h1. The NEW TYPE IS DELIBERATE and is not pinned: the date is meant to read
 * as an eyebrow label, and it now does -- 32.4px Oswald 500 at 1400 and 22px at
 * 390 become the eyebrow's 14px, uppercase, 0.14em tracked, at both widths.
 *
 * WHAT IS NOT DELIBERATE is the LAYOUT that went with the tag. `.event_header
 * h4` (css/_events.css:32-44) is tag-scoped, and above 1080px it set
 * `flex: 0 0 50%; max-width: 50%` on the date. It was OVERRIDING `.date_time`'s
 * own `flex: 0 0 66.6666%` (css/_events.css:99-113) on specificity, (0,1,1)
 * beating (0,1,0). Losing the h4 does not remove that column rule, it hands the
 * column to the 66.6666% one that had been dead since it was written -- and
 * 66.7% + the 50% `.event_header .location` keeps no longer fit on one line, so
 * the venue wraps to a row of its own. Measured on
 * /events/west-virginia-book-festival/ at 1400px: date x=103 w=597 and location
 * x=700 w=597 became date w=796 with the location dropped to x=103 below it.
 *
 * This rule hands the 50% column back, and that is all it does. Font size,
 * line-height, letter-spacing, transform and colour are left to
 * `.lehane-eyebrow`, which is the restyle Plan 4 §0.9 chose. The 30px
 * margin-bottom `.date_time` set above 1080px is likewise left to the
 * eyebrow's 12px: the date and the venue sit in the same flex row, so the
 * date's own bottom margin no longer sets the gap under the header.
 *
 * (0,2,0) beats `.date_time` at (0,1,0), and the media query matches the one it
 * is correcting. Scoped under `.event_header`, so it cannot reach the archive
 * card or the event widget, neither of which renders a `.date_time` inside an
 * event header.
 *
 * BELOW 1080px NOTHING IS PINNED, because nothing moved: no `.date_time` or
 * `.event_header h4` column rule applies there, and both tags are ordinary
 * full-width flex items. Measured at 390px, the stack is unchanged.
 * ---------------------------------------------------------------------- */
/* The title keeps its own row at EVERY width, which is what it did before.
 *
 * `.event_header` is `display: flex; flex-wrap: wrap` (css/_events.css:14-18)
 * with no order or basis below 1080px, so which items share a row is decided
 * purely by their content widths. The theme's h4 date line was wide enough --
 * 422px of 22px Oswald on the longest of the 19 -- that the h1 was alone on
 * its row at every width measured: 1400, 1200, 1080, 1000, 900, 768 and 390.
 * The eyebrow is 213px, and at 1000 and 900 that fits in the gap beside a
 * content-sized h1, so the date line floated UP and sat to the right of the
 * title. Measured: date y=265 -> y=175 at 1000, y=240 -> y=170 at 900.
 *
 * That is not the eyebrow restyle, it is the h4's width having been load
 * bearing by accident. _events.css:21-29 already asserts this row above
 * 1080px; this says the same thing at the widths below it. Keyed on
 * `.page_title` rather than `h1` so it cannot be undone by a future tag
 * change, which is the mistake being corrected here.
 *
 * `.event_header` is emitted by exactly two files -- the theme's
 * parts/content-event.php and this plugin's, which shadows it -- so both rules
 * in this block reach the event single and nothing else.
 * ---------------------------------------------------------------------- */
.event_header .page_title {
	flex: 0 0 100%;
	max-width: 100%;
}

@media (min-width: 1080px) {
	.event_header .date_time {
		flex: 0 0 50%;
		max-width: 50%;
	}
}

/* Phones. Kadence stacks the columns below 768px; the mockup then caps the
   cover and the portrait at 260px and sets posters two to a row. */
@media (max-width: 767px) {
	:is(.lehane-lead, .lehane-about) .wp-block-kadence-image {
		max-width: 260px;
	}
	.lehane-filmtv-band .filmtv-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 24px;
	}
}

/* -------------------------------------------------------------------------
 * News singles sit in the site's column, not in a narrower one of their own,
 * and their prose matches a book or Film & TV single's. §0.6.
 *
 * Measured 2026-09-22 at 1400px: every page and every other single renders
 * #primary at x=100 w=1200. Post singles alone rendered x=345 w=710, which is
 * Astra's default single-post content width. The jump makes News read as a
 * different site.
 *
 * The source is Astra's "narrow container" setting, which applies to single
 * posts and to nothing else on this site:
 *
 *   @media (min-width:922px){ .ast-container{ max-width:1240px } }
 *   @media (min-width:922px){ .ast-narrow-container .site-content
 *                             > .ast-container{ max-width:750px } }
 *   .ast-narrow-container{ --wp--custom--ast-content-width-size:750px;
 *                          --wp--custom--ast-wide-width-size:750px }
 *   .entry-content[data-ast-blocks-layout] > *{
 *       max-width:var(--wp--custom--ast-content-width-size);
 *       margin-left:auto; margin-right:auto }
 *
 * SPECIFICITY, NOT SOURCE ORDER. Astra's container selector is (0,3,0) and the
 * first version of this rule was (0,3,0) too, so it won only because design.css
 * is enqueued after Astra's inline dynamic CSS. Any critical-CSS inliner,
 * minifier or enqueue-priority change would have silently restored the 710px
 * column. Adding `body` and Astra's own `#content` gives (1,2,1) — the same
 * shape Task 2's archive-header rule uses, and an id beats any number of
 * classes, so this now wins outright without !important.
 * ---------------------------------------------------------------------- */
/* MIRRORING ASTRA'S OWN MEDIA QUERY, not wrapping for the sake of it. Below
 * 922px Astra sets this container to `max-width:100%` for every single on the
 * site, and the narrow 750px override does not exist there at all. An unscoped
 * override was written first and declared 1240px at 390/768/900 too: the
 * RENDERED width was identical, because the viewport is narrower than 1240
 * either way, so every geometry assertion passed — and the comparator's
 * container-max-width check still went red at those three widths, because the
 * post single was configured differently from every other single for no reason.
 * Overriding exactly the rule being fixed, and only where it applies, is what
 * makes that check clean. If Astra ever moves this breakpoint the same check
 * goes red rather than the difference going unnoticed. */
@media (min-width: 922px) {
	body.single-post #content > .ast-container {
		max-width: var(--lehane-container);
	}
}

body.single-post #primary {
	width: 100%;
	max-width: none;
	margin-left: 0;
	margin-right: 0;
}

/* THE MEASURE NEEDS BOTH LEVERS, and the second one is easy to miss.
 *
 * Capping .entry-content alone leaves Astra's block-layout rule above still
 * capping every BLOCK CHILD at --wp--custom--ast-content-width-size, which
 * .ast-narrow-container sets to 750px. Measured: with only the cap in place the
 * container reported 785px while the paragraphs the reader actually sees
 * rendered at 750px and were CENTRED inside it by that rule's auto margins —
 * 750px being, exactly, the counter-example this task's gate exists to reject.
 * So the variable is redefined too, and the comparator asserts the rendered
 * width of `.entry-content > p` and not only of its container.
 *
 * .ast-narrow-container is the body element itself at (0,1,0); `body.single-post`
 * is (0,1,1) and targets the same element, so this wins on specificity.
 *
 * Both --wp--custom--*-width-size values move together because Astra sets them
 * equal on this template; leaving `wide` at 750px would make an .alignwide block
 * NARROWER than an ordinary paragraph. */
body.single-post {
	--wp--custom--ast-content-width-size: var(--lehane-measure);
	--wp--custom--ast-wide-width-size: var(--lehane-measure);
}

/* NOT a direct child of .ast-article-single. Astra wraps both the header and
 * the content in a .single-layout-1 div
 * (astra/template-parts/single/single-layout.php:12, header :18, content :32),
 * so a `>` combinator against the article matches nothing — and the measure is
 * then silently not applied while every other assertion passes.
 *
 * ALIGNMENT MATCHES THE SIBLINGS, which took measuring rather than guessing.
 * A book or Film & TV single's text is neither centred nor indented by an
 * alignment rule: it has margin 0 and sits at the start of the lead grid's 1fr
 * track, and what pushes it right on those pages is a 280px cover plus a 45px
 * gap — a sibling ELEMENT, not a choice about alignment. A post single has no
 * cover, so the faithful match is margin 0 and flush left, which is what the
 * cap below gives once the block children stop being auto-centred at 750px. */
body.single-post #primary .ast-article-single .entry-header,
body.single-post #primary .ast-article-single .entry-content {
	max-width: var(--lehane-measure);
}

/* ---------------------------------------------------------------------------
   About: the author photo beside the eyebrow AND the biography, on stone.
   This is the `lehane/about-teaser` shape from the translation plan (§222):
   "Two columns of 260px and 1fr. Portrait, eyebrow, H2, about 60 words, a
   link" — 260px of portrait against a 1fr track that carries text.

   THE 1fr TRACK MUST HOLD THE COPY, and an earlier draft of this task left it
   empty. The biography sat in a SECOND row below, so at 1200px the body column
   measured 852px wide and contained one 18px eyebrow: roughly 850x450px of
   blank stone beside the portrait, with the copy in the next row at a width
   that did not even align with the eyebrow labelling it. Every geometry
   assertion passed, because geometry measures the column that HAS content and
   nothing measured the one that did not. One container, no content split.

   Kadence lays the two columns out itself via colLayout/columns; this only
   pins the photo track, the stacking breakpoint and the body measure. Do NOT
   reuse .lehane-page-lead here — it is a `minmax(200px, 280px) 1fr` grid
   (above) and a Kadence row emits a SINGLE direct child, .kt-row-column-wrap,
   which would auto-place into that 280px track and squeeze the whole lead
   into it.

   THE SELECTOR CARRIES TWO CLASSES ON PURPOSE, and one would not do.
   Kadence writes its own per-row grid into `kadence_blocks_css-inline-css`,
   which is printed AFTER this stylesheet in the head — measured on the
   rendered page, design.css at position 12 and the Kadence inline block at 14.
   Its rule is `.kb-row-layout-id_<id> > .kt-row-column-wrap`, specificity
   (0,2,0). A single-class `.lehane-about-lead > .kt-row-column-wrap` is also
   (0,2,0), so it would LOSE on source order and the 260px track would never
   apply — while the row still rendered two columns and every count-based
   assertion stayed clean. Adding .kb-row-layout-wrap, which build_html always
   emits on the same element, makes this (0,3,0) and wins on specificity rather
   than on the order two plugins happen to enqueue in.

   THE STACKING BREAKPOINT IS OURS, NOT KADENCE'S. The spec stacks lead
   columns at 900px (translation plan §Spacing). Kadence's own generated rule
   stacks at `max-width: 767px`, so between 768 and 900 the row would still be
   two columns — at exactly 768px, a width the comparator asserts as stacked.
   The second block below moves that boundary to 900 rather than leaving the
   spec and the render disagreeing in a 133px band nobody looks at. */
@media (min-width: 901px) {
	.kb-row-layout-wrap.lehane-about-lead > .kt-row-column-wrap {
		grid-template-columns: 260px 1fr;
	}
}

@media (max-width: 900px) {
	.kb-row-layout-wrap.lehane-about-lead > .kt-row-column-wrap {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* max-width matches the desktop track, so the stacked layout does not blow the
   portrait up to the full content width.

   THE SOURCE IS THE `large` SIZE, 683x1024, not `medium`. The element occupies
   260 CSS px, and with the medium file WordPress emitted
   `sizes="(max-width: 200px) 100vw, 200px"`, so at DPR 1 the browser chose the
   200px file and upscaled it 1.3x. Picking the size that is larger than the
   slot, and letting srcset/sizes narrow it, is what keeps it sharp at 1x as
   well as on retina. */
.lehane-about-lead__media img {
	display: block;
	width: 100%;
	max-width: 260px;
	height: auto;
}

.lehane-about-lead__p {
	margin: 0 0 1.25rem;
	max-width: 70ch;
	line-height: 1.7;
	color: var(--lehane-ink);
}

.lehane-about-lead__p:last-child {
	margin-bottom: 0;
}

/* ---------------------------------------------------------------------------
   Contact: one agent per column. §0.8

   THE STACKING RULE IS NOT REDUNDANT, and it is not in the task brief. Kadence's
   own responsive CSS for this row emits `repeat(3, minmax(0, 1fr))` at BOTH
   desktop and its 1024px tablet breakpoint, and collapses to a single track only
   at `max-width: 767px`. The spec stacks the agents AT 900px, so without this
   rule 900px and 768px would each render three ~130px columns with a full
   postal address wrapped inside every one. This selector carries three classes
   against Kadence's two, so it wins inside the narrower query — the same
   mechanism the About lead above relies on.
   ------------------------------------------------------------------------- */
@media (max-width: 900px) {
	.kb-row-layout-wrap.lehane-agents > .kt-row-column-wrap {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* Inert by specificity and kept deliberately: `is-style-eyebrow` already sets
   `margin: 0 0 12px` from two classes and wins over this one. 0.75rem is the
   same 12px at the root size, so the two agree; this states the intent local to
   the agents row in case the eyebrow style is ever retired. */
.lehane-agents__role {
	margin: 0 0 0.75rem;
}

/* The bare-class `margin: 0` below does NOT win. Astra styles this paragraph
   through `.entry-content ... p` at (0,1,1), which outranks a single class, so
   the computed bottom margin was 28.8px and every column carried 29px of
   trailing stone under its last line, with the row's own 64px bottom padding
   beneath that.

   A declaration that reads `margin: 0` and does not zero the margin is a trap
   for whoever edits this next, so the intent is made true here at Astra's own
   specificity rather than merely documented. Measured: 28.8px -> 0px and 29px of
   slack -> 0px. The comparator asserts the computed value, so this cannot
   silently revert.

   Measured row height: 360px -> 331px at 1400 (the columns are side by side, so
   one column's margin sets the height) and 780px -> 694px at 390, where all
   three stack and all three margins come out.

   The `margin: 0` on the bare class is kept as the statement of intent for any
   context outside .entry-content. */
.entry-content .lehane-agents__body {
	margin-bottom: 0;
}

.lehane-agents__body {
	margin: 0;
	line-height: 1.6;
	color: var(--lehane-ink);
}

/* ---------------------------------------------------------------------------
   Featured Film & TV: the strip lays itself out.

   Before this, the block had no layout of its own. css/filmtv.css in the child
   theme gave it `repeat(auto-fit, minmax(220px, 1fr))`, so the column count was
   whatever the container width happened to allow and the editor had no say.
   Here the count is the editor's choice and the track is explicit.

   THE GRID RULE DOUBLES ITS CLASS ON PURPOSE. filmtv.css already holds
   `.filmtv-featured .filmtv-grid` at (0,2,0), and it is a block-style handle,
   so core enqueues it during render -- after this file, which goes out on
   wp_enqueue_scripts. Source order would hand the win to filmtv.css. Repeating
   .filmtv-grid makes this (0,3,0), which wins whatever the order turns out to
   be. Same trap the host reset above documents.

   minmax(0, 1fr), not minmax(220px, 1fr): a 220px floor makes five tracks
   overflow a 1200px container, and the poster frame's own aspect-ratio already
   stops a card collapsing.
   --------------------------------------------------------------------------- */
.filmtv-featured {
	--lehane-filmtv-cols: 3;
}

.filmtv-featured--cols-2 { --lehane-filmtv-cols: 2; }
.filmtv-featured--cols-3 { --lehane-filmtv-cols: 3; }
.filmtv-featured--cols-4 { --lehane-filmtv-cols: 4; }
.filmtv-featured--cols-5 { --lehane-filmtv-cols: 5; }

.filmtv-featured .filmtv-grid.filmtv-grid {
	grid-template-columns: repeat(var(--lehane-filmtv-cols, 3), minmax(0, 1fr));
}

/* The homepage band caps the strip at 840px, which is right for three posters
   and cramped for five. Widen it to the container once the count goes past
   three, rather than removing a cap the mockup asked for. */
.lehane-filmtv-band :is(.filmtv-featured--cols-4, .filmtv-featured--cols-5) {
	max-width: 100%;
}

/* The cap below full width is deliberate and not editor-adjustable. Five 211px
   posters are fine at 1400; five on a tablet are thumbnails. These rules carry
   the same (0,1,0) weight as the choice rules above and sit after them, so the
   later source order is what makes them win. */
@media (max-width: 1024px) {
	.filmtv-featured--cols-4,
	.filmtv-featured--cols-5 { --lehane-filmtv-cols: 3; }
}

@media (max-width: 640px) {
	.filmtv-featured--cols-3,
	.filmtv-featured--cols-4,
	.filmtv-featured--cols-5 { --lehane-filmtv-cols: 2; }
}
