/* Block: Feature (acf/feature)
   ---------------------------------------------------------------------------
   Media beside copy. Phone first: the media and the copy stack (a panel puts
   its copy first, centred); from 992px they sit side by side. Notes:
   docs/feature-block.md.

   Comp references (Figma file 9eBn6GzkM1aHMg59Ck62cP):
     desktop 1512  Amenities rows 71:619 / 71:647 / 71:622, Penthouse 256:483,
                   site plan 384:1087, Keane's 95:216, Home Overview 71:350,
                   neighborhood teaser 375:791
     phone 402     Overview 127:573, teaser 127:605–609, Keane's 127:617

   Vertical spacing is the comp's ink-to-ink distances converted to CSS line
   boxes with the fonts' real metrics (Richmond Display: ascent .91, descent
   .25; Rig Sans: ascent .94/.96, descent .27), not its text-frame gaps
   (figma-comps.md). Each gap is a custom property at the top so the rhythm
   can be retuned in one place.

   Block stylesheets print BEFORE reset.min.css and style.css (header.md, "CSS
   order trap"), so every rule here wins on specificity, never on order.
--------------------------------------------------------------------------- */

.feature--section {
	/* --- Phone (402) --- */
	--feature-pad-top: 60px;      /* teaser: band bottom → media 59 */
	--feature-pad-bottom: 60px;   /* teaser: button → next section 63 */
	/* .theme-container's 15px phone gutter, plus this, is the comps' 43px. */
	--feature-inset: 28px;
	--feature-media-ratio: 1 / 1;
	--feature-media-radius: var(--lwh-media-radius, 60px);
	--feature-panel-radius: var(--lwh-panel-radius, 60px);
	/* How far a panel rides up over the section above it. */
	--feature-panel-overlap: var(--feature-panel-radius);

	/* Copy rhythm (phone). "lead" = the first child's offset from the top of
	   the copy column; the rest are margins between neighbours. */
	--feature-gap-media: 58px;    /* media bottom → copy (teaser heading ink 65 below) */
	--feature-lead-eyebrow: -6px; /* puts the eyebrow's cap line level with the media top */
	--feature-lead-heading: 0px;
	--feature-lead-logo: 0px;
	--feature-gap-eyebrow: 21px;  /* eyebrow → heading */
	--feature-gap-eyebrow-xl: 5px;/* eyebrow → a 124px heading */
	--feature-gap-heading: 36px;  /* heading → body (teaser 127:607 → 608) */
	--feature-gap-heading-xl: 15px; /* 124px heading → 48px subhead */
	--feature-gap-subhead: 36px;  /* 48px subhead → list */
	--feature-gap-logo: 47px;     /* logo → body (Keane's 127:628) */
	--feature-gap: 41px;          /* anything else: body → list, list → body … */
	--feature-gap-cta: 47px;      /* last copy → buttons (58 teaser, 37 Keane's) */
	--feature-gap-copy: 55px;     /* panel: copy → media below it */

	position: relative;
	padding-top: var(--feature-pad-top);
	padding-bottom: var(--feature-pad-bottom);
}

.feature--container.theme-container {
	padding-left: calc(var(--theme-content-padding) + var(--feature-inset));
	padding-right: calc(var(--theme-content-padding) + var(--feature-inset));
}

/* --- Backgrounds -----------------------------------------------------------
   Each background sets the colours its copy, accents, buttons and focus rings
   use, so an editor never has to pick text colours. "None" leaves the page's
   own Deep Sea, Linen text and the Sunset buttons.

   Linen (2026-10-16, Phase 7 audit AV-1) is the plain ground with the Linen
   pinstripe's colours and no pattern: the Availability page's Overview
   (335:161), whose ground samples 215, 208, 199, the Linen token exactly. */

.feature--section.bg-linen-mod,
.feature--section.bg-linen-pinstripe-mod,
.feature--section.bg-linen-arches-mod {
	--feature-fg: var(--wp--preset--color--chocolate, #1e0e0b);
	--feature-heading: var(--wp--preset--color--black, #000);
	/* Text in the AA shade of Ember (2026-10-17, DR-5; style.css): the
	   eyebrows, the tags lists (--lwh-tags-color follows the accent) and the
	   button's label, outline and hover fill, whose Linen label then reads
	   4.62:1 too. The pill's chevrons are marks, not text, and keep the
	   palette Ember (3.6:1, over the 3:1 they need). */
	--feature-accent: var(--lwh-ember-on-linen, #8a4530);
	--feature-btn: var(--lwh-ember-on-linen, #8a4530);
	--feature-btn-hover-fg: var(--wp--preset--color--linen, #d7d0c7);
	--feature-ring: var(--wp--preset--color--chocolate, #1e0e0b);
	--feature-pill-below: var(--wp--preset--color--ember, #a35139);

	background-color: var(--wp--preset--color--linen, #d7d0c7);
}

.feature--section.bg-chocolate-mod {
	--feature-fg: var(--wp--preset--color--white, #fff);
	--feature-heading: var(--wp--preset--color--white, #fff);
	--feature-accent: var(--wp--preset--color--linen, #d7d0c7);
	--feature-btn: var(--wp--preset--color--linen, #d7d0c7);
	--feature-btn-hover-fg: var(--wp--preset--color--chocolate, #1e0e0b);
	--feature-ring: var(--wp--preset--color--linen, #d7d0c7);
	--feature-pill-below: var(--wp--preset--color--linen, #d7d0c7);

	background-color: var(--wp--preset--color--chocolate, #1e0e0b);
}

/* The pinstripe is a tile cut from the comp's own raster ("Seattleite_
   WebPattern", 17 stripe periods, noise averaged out), not redrawn. 500px of
   raster is 17 periods; it is drawn at the comp's pitch, 10.9px a stripe on
   the 1512 board and 14.1 on the 402 one. */
.feature--section.bg-keanes-mod {
	--feature-fg: var(--wp--preset--color--white, #fff);
	--feature-heading: var(--wp--preset--color--linen, #d7d0c7);
	/* The AA shade of Slate on Keane's Green, LIGHTER than the palette's
	   (2026-10-17, DR-5): the "View Website" label and outline 3.15 ->
	   4.64:1, and the green label on its hover fill the same. */
	--feature-accent: var(--lwh-slate-on-keanes, #adc5c3);
	--feature-btn: var(--lwh-slate-on-keanes, #adc5c3);
	--feature-btn-hover-fg: var(--wp--preset--color--keanes-green, #34534d);
	--feature-ring: var(--wp--preset--color--linen, #d7d0c7);
	--feature-pill-below: var(--wp--preset--color--linen, #d7d0c7);

	background-color: var(--wp--preset--color--keanes-green, #34534d);
	background-image: url(../../images/pattern-keanes-pinstripe.webp);
	background-repeat: repeat;
	background-size: 240px 4px;
	background-position: left top;
}

/* Linen arches: the Amenities pattern (Figma 45:99), from 992 (Desktop,
   below). Below 992 the ground is plain light Linen (2026-10-16, Phase 7
   audit AM-3): a stacked row is far taller than the pattern's arches, so a
   phone showed only its flat centre, and the bottom cap's edge cut through
   Wellness's "Make Reservation" 16px below the button's top. One raster in
   the comp behind all three rows; here every Feature block paints its own
   slice, and consecutive arches blocks join up:
     - the top cap (the inverted band with the arch tops) only on the FIRST
       block of a run
     - the bottom cap only on the LAST, which needs :has(); where :has() is
       unsupported the run simply ends without its bottom arches
     - the vertical bands on every block, repeat-y, so the columns run on
       unbroken through the run
   The slices are drawn at the comp's scale (the raster is 4308px wide on the
   1512 board) and with its 62px offset right of centre, at every desktop
   width. */
.feature--section.bg-linen-arches-mod {
	background-color: var(--lwh-linen-light, #ded7cf);
}

/* Colours follow the background. */
.feature--section[class*="bg-"]:not(.bg-none-mod) {
	color: var(--feature-fg);
	--lwh-tags-color: var(--feature-accent);
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-heading,
.feature--section:not(.bg-none-mod) :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > :is(.has-h-1-font-size, .has-h-2-font-size, .has-h-3-font-size) {
	color: var(--feature-heading, inherit);
}

.feature--section:not(.bg-none-mod) :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .is-style-eyebrow {
	color: var(--feature-accent);
}

/* --- Panel shape ------------------------------------------------------------
   Rounded top, and the block rides up over the bottom of the section above by
   --feature-panel-overlap, so that section shows in the corners the way the
   comp draws the Penthouse over the hero and Keane's over the rows. z-index 1
   paints it over that section (the bands and panels are z-index 1 too, and a
   later sibling wins a tie). */

.feature--section.panel-mod {
	--feature-pad-top: 72px;      /* Keane's phone: panel top → logo ink */
	z-index: 1;
	border-radius: var(--feature-panel-radius) var(--feature-panel-radius) 0 0;
}

/* (0,3,0), not (0,2,0): style.css's margin-cancel list is
   `:root .wp-block-acf-feature`, and :root counts as a class, so it ties
   (0,2,0) — and style.css prints after this file, so it would win the tie and
   zero the lift. Same fix as the leasing footer's overlap. */
:root .feature--section.panel-mod {
	margin-top: calc(-1 * var(--feature-panel-overlap));
}

/* A Feature that a panel is about to cover keeps its content clear of it. */
.feature--section:has(+ .panel-mod) {
	padding-bottom: calc(var(--feature-pad-bottom) + var(--feature-panel-overlap));
}

/* --- Layout (phone) --------------------------------------------------------- */

.feature--main {
	display: flex;
	flex-direction: column;
}

.feature--media-col {
	position: relative;
	min-width: 0;
}

.feature--media-frame {
	position: relative;
	z-index: 1;
}

.feature--copy {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	min-width: 0;
	margin-top: var(--feature-gap-media);
}

/* No media yet (the editor placeholder aside): nothing to sit below. */
.feature--media-col:empty + .feature--copy {
	margin-top: 0;
}

/* A panel on a phone: copy first, centred, then the media (Keane's 127:617). */
.feature--section.panel-mod .feature--copy {
	order: -1;
	margin-top: 0;
	text-align: center;
	align-items: center;
}

.feature--section.panel-mod .feature--media-col {
	margin-top: var(--feature-gap-copy);
}

.feature--section.panel-mod .feature--media-col:empty {
	margin-top: 0;
}

/* --- Media ------------------------------------------------------------------ */

.feature--section.shape-portrait-mod {
	--feature-media-ratio: 414 / 537;
}

.feature--media {
	position: relative;
	overflow: hidden;
	/* width: 100% is NOT optional with aspect-ratio — without a definite
	   inline size Chrome can run the ratio backwards (image-band-block.md). */
	width: 100%;
	aspect-ratio: var(--feature-media-ratio);
	background-color: rgba(0, 0, 0, 0.08);
}

.feature--section.corner-top-left-mod .feature--media {
	border-top-left-radius: var(--feature-media-radius);
}

.feature--section.corner-top-right-mod .feature--media {
	border-top-right-radius: var(--feature-media-radius);
}

.feature--media-item {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

video.feature--media-item {
	pointer-events: none;
}

/* --- Carousel ---------------------------------------------------------------
   Only for 2+ slides. A plain scroll-snap track, so it swipes with JS off;
   js/carousel.js (shared with acf/image-band) adds the arrows, ←/→, the
   wrap-around and the live region. */

.feature--track {
	display: flex;
	height: 100%;
	/* So the inset focus ring follows the media's rounded corner. */
	border-radius: inherit;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	-ms-overflow-style: none;
}

.feature--track::-webkit-scrollbar {
	display: none;
}

.feature--slide {
	flex: 0 0 100%;
	height: 100%;
	scroll-snap-align: start;
}

/* Keyboard focus only: clear Chrome's ring on a click first, then re-add the
   theme's on :focus-visible (equal specificity, so the order matters). */
.feature--track:focus {
	outline: none;
}

.feature--track:focus-visible {
	outline: 2px solid var(--wp--preset--color--linen, #d7d0c7);
	outline-offset: -4px;
}

/* The arrow pill. Same geometry as the image band's (100.4 x 48, the small
   clipped corner); the CSS is repeated here rather than shared because
   image-band.css only loads with a band — see docs/feature-block.md.

   Phone: below the media, centred (Keane's 127:617, 33px under the photo),
   in the background's own colour, since it sits on the panel, not a photo.
   992px+: over the photo's bottom-right corner, in white (see below). */
.feature--nav {
	--feature-pill-fg: var(--feature-pill-below, var(--wp--preset--color--linen, #d7d0c7));
	/* The chevron's colour on hover, over the filled half: the ground the pill
	   sits on (Deep Sea over a photo, from 992). */
	--feature-pill-hover-fg: var(--feature-btn-hover-fg, var(--wp--preset--color--deep-sea, #1b2632));

	display: flex;
	align-items: center;
	gap: 17.6px;
	width: max-content;
	margin: 33px auto 0;
	padding: 9.8px 14px;
	border: 1px solid var(--feature-pill-fg);
	border-radius: var(--lwh-clip-corner-sm, 10px) var(--lwh-clip-corner-sm, 10px) 0 var(--lwh-clip-corner-sm, 10px);
	background-color: rgba(215, 208, 199, 0.2);
	color: var(--feature-pill-fg);
}

.feature--arrow {
	position: relative;
	display: block;
	width: 26.4px;
	height: 26.4px;
	padding: 0;
	border: 0;
	background: none;
	color: inherit;
	cursor: pointer;
}

/* The tap target (2026-10-15, Phase 7 audit F1): the chevron is 26.4px, so an
   invisible box takes each arrow out to its half of the pill, 50.2 x 48:
   over the pill's 14px padding and 1px border on the outside, half the 17.6px
   gap on the inside, the 9.8px padding and border above and below. Nothing
   changes on screen; the ring stays on the button's own box. Same geometry
   in image-band.css, availability.css and news.css. */
.feature--arrow::before {
	content: "";
	position: absolute;
	top: -10.8px;
	bottom: -10.8px;
	left: -15px;
	right: -8.8px;
}

.feature--arrow.is-next::before {
	left: -8.8px;
	right: -15px;
}

/* The pause toggle (2026-10-21), as the band's: the middle third of the pill
   (144.4 wide with it), only with JS. */
.feature--arrow.is-pause {
	display: none;
}

html.lwh-js .feature--arrow.is-pause {
	display: block;
}

.feature--arrow.is-pause::before {
	left: -8.8px;
	right: -8.8px;
}

.feature--arrow[disabled] {
	opacity: 0.35;
	cursor: default;
}

.feature--arrow:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 4px;
	border-radius: 2px;
}

/* Hover (2026-10-16, Phase 7 audit AM-10; ours, the comps draw none): the
   arrow's half of the pill fills in the pill's colour and the chevron takes
   the colour under it, the way the buttons fill. The fill sits inside the
   pill's 1px border, with its rounded corners (10px less the border), and
   the two halves meet in the middle of the gap. Pointer devices only, so a
   tap on a phone doesn't leave it filled (as batch 1 did for the lightbox
   buttons). The image band's pill does the same (image-band.css). */
@media (hover: hover) {
	.feature--arrow::after {
		content: "";
		position: absolute;
		z-index: -1;
		top: -9.8px;
		bottom: -9.8px;
		left: -14px;
		right: -8.8px;
		border-radius: 9px 0 0 9px;
		background-color: var(--feature-pill-fg);
		opacity: 0;
		pointer-events: none;
	}

	.feature--arrow.is-next::after {
		left: -8.8px;
		right: -14px;
		border-radius: 0 9px 0 0;
	}

	.feature--arrow.is-pause::after {
		left: -8.8px;
		right: -8.8px;
		border-radius: 0;
	}

	.feature--arrow:not([disabled]):hover {
		color: var(--feature-pill-hover-fg);
	}

	.feature--arrow:not([disabled]):hover::after {
		opacity: 1;
	}

	/* The ::after sits behind the chevron: the button needs its own stacking
	   context for z-index -1 to stay above the pill's backing. */
	.feature--arrow {
		z-index: 0;
	}
}

.feature--chevron {
	display: block;
	width: 100%;
	height: 100%;
}

.feature--arrow.is-prev .feature--chevron {
	transform: rotate(180deg);
}

/* Pause bars while the slides rotate, the play triangle once paused. */
.feature--toggle {
	display: block;
	width: 100%;
	height: 100%;
}

.feature--toggle-play,
.feature--arrow.is-paused-mod .feature--toggle-pause {
	display: none;
}

.feature--arrow.is-paused-mod .feature--toggle-play {
	display: inline;
}

/* A panel with a carousel ends 32px under its pill (127:617). */
.feature--section.panel-mod:has(.feature--nav) {
	--feature-pad-bottom: 32px;
}

/* --- Copy --------------------------------------------------------------------
   Both DOM shapes: the front end prints the InnerBlocks straight into
   .feature--copy (the ACF wrapper is opted out so [data-reveal-group] staggers
   the real children); the editor still wraps them in
   .acf-innerblocks-container, which is display: contents here. */

.feature--copy > .acf-innerblocks-container {
	display: contents;
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > * {
	margin-top: 0;
	margin-bottom: 0;
	max-width: 100%;
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > * + * {
	margin-top: var(--feature-gap);
}

/* Leads: where the first thing in the column sits against the media top. */
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .is-style-eyebrow:first-child {
	margin-top: var(--feature-lead-eyebrow);
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-heading:first-child {
	margin-top: var(--feature-lead-heading);
}

/* A figure at the H2 size that opens the column (Availability's Overview,
   335:161, which has no eyebrow): the comp puts its ink 46px under the media
   top, as Home's eyebrow-led Overview does, so the subhead and list land
   where both comps draw them. Its cap line sits 19.3px into the 124px line
   box (2026-10-16, Phase 7 audit AV-1). */
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .has-h-2-font-size:first-child {
	margin-top: var(--feature-lead-heading-xl, var(--feature-lead-heading));
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-image:first-child,
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .screen-reader-text:first-child + .wp-block-image {
	margin-top: var(--feature-lead-logo);
}

/* Line breaks (2026-10-15, Phase 7 audit F3): headings balance their lines,
   paragraphs avoid a lone last word ("there.", "soul.", "function.",
   "sunbreaks."). Progressive enhancement: browsers without text-wrap keep
   the old breaks. */
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-heading {
	text-wrap: balance;
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) p {
	text-wrap: pretty;
}

/* The Overview's subhead ("Trophy Office Tower", a paragraph at the H3 size
   after the H2-size figure) is 34px below 992 (2026-10-16, Phase 7 audit
   AV-8): on a phone the figure is the fluid H2's 54.5px and a 48px subhead
   read as its equal. 48 from 992, as drawn. WordPress sets the size from the
   preset variable with !important, so the variable is redefined on the
   paragraph (the H2 cap below does the same), and restored from 992 from
   the root's value captured on the column (a variable can't refer to itself). */
.feature--copy {
	--feature-h3-root: var(--wp--preset--font-size--h-3, 48px);
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .has-h-2-font-size + p.has-h-3-font-size {
	--wp--preset--font-size--h-3: 34px;
}

/* Neighbours. */
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .is-style-eyebrow + * {
	margin-top: var(--feature-gap-eyebrow);
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .is-style-eyebrow + .has-h-2-font-size {
	margin-top: var(--feature-gap-eyebrow-xl);
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-heading + * {
	margin-top: var(--feature-gap-heading);
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .has-h-2-font-size + * {
	margin-top: var(--feature-gap-heading-xl);
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > p.has-h-3-font-size + * {
	margin-top: var(--feature-gap-subhead);
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-image + * {
	margin-top: var(--feature-gap-logo);
}

/* A visually hidden heading (the logo stands in for it on screen) takes no
   part in the rhythm: the logo after it leads as if it were first. */
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .screen-reader-text + * {
	margin-top: 0;
}

/* The buttons drop to the foot of the column, level with the bottom of the
   media (every desktop comp), with at least --feature-gap-cta above them when
   the copy runs longer than the media (the teaser). Flex margins don't
   collapse, so the gap lives on the element before. */
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > :is(.wp-block-buttons, .feature--alt-open-wrap):last-child {
	margin-top: auto;
}

:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > :has(+ :is(.wp-block-buttons, .feature--alt-open-wrap):last-child) {
	margin-bottom: var(--feature-gap-cta);
}

/* Logos standing in for a heading: sized by the image block's own width, never
   wider than the column. */
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-image img {
	display: block;
	max-width: 100%;
	height: auto;
}

.feature--section.panel-mod :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-image {
	margin-left: auto;
	margin-right: auto;
}

.feature--section.panel-mod :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-buttons {
	justify-content: center;
}

/* Everywhere else the buttons follow the copy, which is left-aligned until
   992 (2026-10-12). An editor's Justification (Amenities sets Multi-Purpose
   and Wellness to Right, for the desktop comps) would otherwise strand the
   CTA at the right edge under left-aligned copy on phones and tablets. This
   out-specifies core's `.wp-block-buttons.is-content-justification-*` (0,2,0)
   and the layout's generated `.wp-container-core-buttons-is-layout-*`; the
   editor's setting is handed back from 992 (Desktop, below). */
.feature--section:not(.panel-mod) :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-buttons {
	justify-content: flex-start;
}

/* core/columns (the teaser's body-beside-list run) stacks at core's 781px;
   from the ladder's 768 it holds its row. Core sets both rules !important, so
   these must be too (third-party override).

   Except 992-1199 (2026-10-09, Home's teaser): there the copy sits beside a
   portrait photo in a column only 388-625px wide, which left two 175px
   columns at 992, three words a line. So the run stacks again, as on
   phones, until 1200, where each column is 279px or more (the comp's are
   355 and 474 at 1512; ours 326.5). */
:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-columns {
	gap: 38px;
}

@media (min-width: 768px) and (max-width: 991px), (min-width: 1200px) {
	:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-columns:not(.is-not-stacked-on-mobile) {
		flex-wrap: nowrap !important;
	}

	:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-columns:not(.is-not-stacked-on-mobile) > .wp-block-column {
		flex-basis: 0 !important;
		flex-grow: 1;
	}
}

@media (min-width: 992px) and (max-width: 1199px) {
	/* The Overview's figure (2026-10-15, Phase 7 audit H-3): beside a portrait
	   photo the copy column is 100vw - 589px wide (403 at 992), and
	   "464,404 SF" at the fluid H2 size (101-109px) broke as "464,404 / SF"
	   from 992 to 1093. Its ink is 4.615x the font size, so the size is capped
	   at (100vw - 620px) / 4.65 (81px at 992, 15px of a classic scrollbar
	   allowed for); the fluid size takes over again from about 1150.
	   WordPress's .has-h-2-font-size sets font-size from the preset variable
	   with !important, so the cap redefines the variable on the heading
	   instead, from the root's value captured one level up (a variable can't
	   refer to itself). */
	.feature--section.shape-portrait-mod .feature--copy {
		--feature-h2-root: var(--wp--preset--font-size--h-2, 124px);
	}

	.feature--section.shape-portrait-mod :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .has-h-2-font-size {
		--wp--preset--font-size--h-2: min(var(--feature-h2-root), calc((100vw - 620px) / 4.65));
	}

	:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-columns:not(.is-not-stacked-on-mobile) {
		flex-wrap: wrap !important;
	}

	:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-columns:not(.is-not-stacked-on-mobile) > .wp-block-column {
		flex-basis: 100% !important;
	}
}

/* --- Buttons -----------------------------------------------------------------
   On a coloured background the CTA is a flat outline in the background's
   button colour (Ember on Linen, Linen on Chocolate, Slate on Keane's), not
   the Sunset gradient label. Hover fills it with that colour — our call; the
   comps show no hover state. */

.feature--section:not(.bg-none-mod) .wp-block-button__link {
	border-color: var(--feature-btn);
	background-color: transparent;
	background-image: none;
	color: var(--feature-btn);
	-webkit-background-clip: border-box;
	background-clip: border-box;
}

.feature--section:not(.bg-none-mod) .wp-block-button__link:hover,
.feature--section:not(.bg-none-mod) .wp-block-button__link:focus-visible {
	background-color: var(--feature-btn);
	background-image: none;
	color: var(--feature-btn-hover-fg);
}

.feature--section:not(.bg-none-mod) .wp-block-button__link:focus-visible {
	outline-color: var(--feature-ring);
}

/* --- Alternate view: the lightbox ---------------------------------------------
   Dmitriy, 2026-10-08: "a traditional lightbox", zoomable so the site plan
   reads on a phone, with a blurred backdrop, at every screen size. The comp
   (384:958) swapped the plan in place instead.

   The open control prints as a link to the full-size image (JS off, the
   editor) and js/lightbox.js swaps it for a <button>; both carry the same
   classes, so it looks the same either way. Keyboard focus only: the reset's
   `button:focus` ring went on 2026-10-07, so no :focus reset is needed. */
.feature--section .feature--alt-open:focus-visible {
	outline: 2px solid var(--feature-ring, var(--wp--preset--color--linen, #d7d0c7));
	outline-offset: 3px;
}

.feature--alt-open {
	font: inherit;
}

/* The lightbox itself (the dialog, its backdrop, zoom controls and the page
   scroll lock) moved to the shared css/lightbox.css on 2026-10-14, when
   acf/availability's floor plans started using it too. feature.php enqueues
   it (and js/lightbox.js) only when a block has an alternate view. */

/* --- Editor -------------------------------------------------------------- */

.feature--placeholder {
	margin: 0;
	padding: 60px 30px;
	border: 1px dashed currentColor;
	text-align: center;
	opacity: 0.7;
}

/* --- Tablet (768-991) -------------------------------------------------------
   Still stacked, but the full-width media made 682 x 682 photos at 768 and
   rows 1,230-1,346px tall (2026-10-16, Phase 7 audit AM-8). The media is
   capped at the desktop square's 560px: under left-aligned copy it starts at
   the copy's edge; a panel (copy centred) centres it. feature.php's media
   slot has the same tier, so the srcset is picked for 560. */
@media (min-width: 768px) {
	.feature--media-col {
		width: 100%;
		max-width: 560px;
	}

	.feature--section.panel-mod .feature--media-col {
		margin-left: auto;
		margin-right: auto;
	}
}

/* --- Desktop -----------------------------------------------------------------
   Media and copy side by side in .theme-container, the same gutter decision
   as the band and the amenities panel (figma-comps.md): content runs
   146 → 1366 on the 1512 board, where the comps put the media anywhere from
   x=88 to x=131. Square: a 560 media column and a 530 copy column pushed to
   the far sides (copy at x=836; comp 813–832). Portrait: 414 media, then the
   copy 115px on (the Home overview). */

@media (min-width: 992px) {
	.feature--section {
		--feature-pad-top: 90px;
		--feature-pad-bottom: 90px;
		--feature-inset: 0px;
		--feature-media-w: 560px;
		--feature-copy-w: 530px;
		/* 130px at 1512 (560 + 130 + 530 = 1220), yielding as the window
		   narrows before either column does. */
		--feature-col-gap: clamp(40px, 8.6vw, 130px);
		--feature-justify: space-between;
		/* Desktop panels lift by their top padding, not the full radius: the
		   media's top edge then lands exactly where the section above ends
		   (Penthouse over the Amenities hero, Keane's over the rows: 73px). */
		--feature-panel-overlap: 73px;

		/* Copy rhythm (desktop, Amenities rows 71:619 / 71:647 / 71:622). */
		--feature-lead-heading: 35px;  /* teaser: heading ink 42 below the media top */
		--feature-lead-heading-xl: 27px; /* Availability's figure: ink 46 below the media top */
		--feature-lead-logo: 57px;     /* Penthouse lockup 64, Keane's script 51 */
		--feature-gap-eyebrow: 21px;   /* eyebrow → heading ink, 46 (41–51) */
		--feature-gap-heading: 69px;   /* heading → body ink, 117 (113–120) */
		--feature-gap-logo: 71px;      /* logo → body: Penthouse 60, Keane's 83 */
		--feature-gap: 29px;
		--feature-gap-cta: 47px;       /* teaser: body → button */
	}

	.feature--section.shape-portrait-mod {
		--feature-media-w: 414px;
		--feature-copy-w: 1fr;
		--feature-col-gap: 115px;
		--feature-justify: start;
	}

	.feature--section.panel-mod {
		--feature-pad-top: 73px;
		--feature-pad-bottom: 73px;
	}

	/* The Amenities rows: 60/60 inside a run of arches blocks (123 and 107
	   between rows in the comp), 140 above the first (1503 → 1641) and 137
	   below the last (what shows above Keane's panel). */
	.feature--section.bg-linen-arches-mod {
		--feature-pad-top: 60px;
		--feature-pad-bottom: 60px;
	}

	.feature--section.bg-linen-arches-mod:not(.bg-linen-arches-mod + .bg-linen-arches-mod) {
		--feature-pad-top: 140px;
	}

	.feature--section.bg-linen-arches-mod:not(:has(+ .bg-linen-arches-mod)) {
		--feature-pad-bottom: 137px;
	}

	.feature--section.bg-keanes-mod {
		background-size: 185px 4px;
	}

	:is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .has-h-2-font-size + p.has-h-3-font-size {
		--wp--preset--font-size--h-3: var(--feature-h3-root, 48px);
	}

	.feature--media-col {
		max-width: none;
	}

	.feature--section.panel-mod .feature--media-col {
		margin-left: 0;
		margin-right: 0;
	}

	/* The arches pattern (see "Linen arches" above), from 992 only. */
	.feature--section.bg-linen-arches-mod {
		--feature-arches-x: calc(50% + 62px);
		--feature-arches-w: 4308px;

		background-color: var(--lwh-linen-light, #ded7cf);
		background-image:
			url(../../images/pattern-linen-arches-top.webp),
			url(../../images/pattern-linen-arches-band.webp);
		background-repeat: no-repeat, repeat-y;
		background-size: var(--feature-arches-w) auto, var(--feature-arches-w) 2px;
		background-position: var(--feature-arches-x) top, var(--feature-arches-x) top;
	}

	.feature--section.bg-linen-arches-mod + .feature--section.bg-linen-arches-mod {
		background-image: url(../../images/pattern-linen-arches-band.webp);
		background-repeat: repeat-y;
		background-size: var(--feature-arches-w) 2px;
		background-position: var(--feature-arches-x) top;
	}

	.feature--section.bg-linen-arches-mod:not(.bg-linen-arches-mod + .bg-linen-arches-mod):not(:has(+ .bg-linen-arches-mod)) {
		background-image:
			url(../../images/pattern-linen-arches-top.webp),
			url(../../images/pattern-linen-arches-bottom.webp),
			url(../../images/pattern-linen-arches-band.webp);
		background-repeat: no-repeat, no-repeat, repeat-y;
		background-size: var(--feature-arches-w) auto, var(--feature-arches-w) auto, var(--feature-arches-w) 2px;
		background-position: var(--feature-arches-x) top, var(--feature-arches-x) bottom, var(--feature-arches-x) top;
	}

	.feature--section.bg-linen-arches-mod + .feature--section.bg-linen-arches-mod:not(:has(+ .bg-linen-arches-mod)) {
		background-image:
			url(../../images/pattern-linen-arches-bottom.webp),
			url(../../images/pattern-linen-arches-band.webp);
		background-repeat: no-repeat, repeat-y;
		background-size: var(--feature-arches-w) auto, var(--feature-arches-w) 2px;
		background-position: var(--feature-arches-x) bottom, var(--feature-arches-x) top;
	}

	.feature--main {
		display: grid;
		grid-template-columns: minmax(0, var(--feature-media-w)) minmax(0, var(--feature-copy-w));
		column-gap: var(--feature-col-gap);
		justify-content: var(--feature-justify);
		align-items: stretch;
	}

	.feature--section.media-right-mod .feature--main {
		grid-template-columns: minmax(0, var(--feature-copy-w)) minmax(0, var(--feature-media-w));
	}

	.feature--section.media-right-mod .feature--media-col {
		grid-column: 2;
		grid-row: 1;
	}

	.feature--section.media-right-mod .feature--copy {
		grid-column: 1;
		grid-row: 1;
	}

	.feature--copy,
	.feature--section.panel-mod .feature--copy {
		order: 0;
		margin-top: 0;
		text-align: left;
		align-items: stretch;
	}

	.feature--section.panel-mod .feature--media-col {
		margin-top: 0;
	}

	.feature--section.panel-mod :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-image {
		margin-left: 0;
		margin-right: 0;
	}

	.feature--section.panel-mod :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-buttons {
		justify-content: flex-start;
	}

	/* The editor's Justification applies again beside the media: core's own
	   values, restated above the phone rule's specificity. Left is the phone
	   rule's flex-start already. */
	.feature--section:not(.panel-mod) :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-buttons.is-content-justification-center {
		justify-content: center;
	}

	.feature--section:not(.panel-mod) :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-buttons.is-content-justification-right {
		justify-content: flex-end;
	}

	.feature--section:not(.panel-mod) :is(.feature--copy, .feature--copy > .acf-innerblocks-container) > .wp-block-buttons.is-content-justification-space-between {
		justify-content: space-between;
	}

	/* The pill moves onto the photo's bottom-right corner (71:556, 71:601:
	   30px in, 25px up), and turns white. The comp draws it Linen, but the
	   client asked for white over photos on the image band (2026-09-01) as
	   Linen read too dim; this follows that ruling (turnover.md). */
	.feature--nav {
		--feature-pill-fg: #fff;
		--feature-pill-hover-fg: var(--wp--preset--color--deep-sea, #1b2632);

		position: absolute;
		right: 30px;
		bottom: 25px;
		z-index: 2;
		margin: 0;
		/* Deep Sea at 45% under the white chevrons and ring (2026-10-15, Phase
		   7 audit AM-1). The comp's Linen at 20% lightened the photo: on the
		   bright floor of Keane's 465 the white read 1.06-1.33:1 against WCAG's
		   3:1. At 45% the brightest pixel under any pill on the site comes out
		   3.1:1 or better. Our call, for Dapper: turnover.md. */
		background-color: rgba(27, 38, 50, 0.45);
	}

	.feature--section.panel-mod:has(.feature--nav) {
		--feature-pad-bottom: 73px;
	}

	/* Linen pinstripe: the stripes cover the media side only, from the page
	   edge to 80px past the media (Home overview 0 → 582, media 88 → 502;
	   teaser 923 → 1512, media 1010 → 1424). The tile is one stripe period
	   cut from the comp's raster, drawn at its 14.54px pitch. Phones get
	   plain Linen, as the phone comps draw it. The section clips the
	   overhang. */
	.feature--section.bg-linen-pinstripe-mod {
		overflow: hidden;
		overflow: clip;
	}

	.feature--section.bg-linen-pinstripe-mod .feature--media-col::before {
		content: "";
		position: absolute;
		top: -2000px;
		bottom: -2000px;
		left: -100vw;
		right: -80px;
		z-index: 0;
		background-image: url(../../images/pattern-linen-pinstripe.webp);
		background-repeat: repeat;
		background-size: 14.54px 4px;
		/* The comp's first stripe sits 13px in from the page edge. */
		background-position: right -1px top;
		pointer-events: none;
	}

	.feature--section.bg-linen-pinstripe-mod.media-right-mod .feature--media-col::before {
		left: -80px;
		right: -100vw;
		background-position: left -1px top;
	}
}
