/*
Theme Name: ProperTies Living
Theme URI: https://propertiesliving.co.uk
Author: ProperTies Living
Author URI: https://propertiesliving.co.uk
Description: Classic PHP theme for the ProperTies Living portfolio site, built with ACF Blocks for editable page content. Header logo is hardcoded per brand template (header.php for ProperTies Living; duplicate as header-{brand}.php for Virtua, Roding Mill, etc.). Footer / contact CTA band is shared site-wide and driven by the "Site Settings" ACF options page, not a per-page block.
Version: 1.0.0
Requires at least: 6.0
Tested up to: 6.6
Requires PHP: 7.4
Text Domain: properties-living
*/

/*
 * Grid, confirmed from Zeplin's own grid overlay on 3a_HOME (Zeplin >
 * toggle Grid in the screen view): Total Width 1340px, 12 columns,
 * ~84.7px column / 27px gutter. .container is the one source of truth
 * for that width — every full-bleed section (header, hero, contact
 * band, footer) centers its content inside .container rather than its
 * own one-off max-width.
 */
:root {
	--pl-container: 1340px;
	--pl-grid-columns: 12;
	--pl-gutter: 27px;
	--pl-column: 84.7px;
	--pl-container-padding: 48px;

	/* "marine" — confirmed brand navy, #043156 */
	--pl-navy: #043156;
	--pl-navy-dark: #021f37;
}

/* ---------- Reset-ish basics ---------- */
* {
	box-sizing: border-box;
}

body {
	margin: 0;
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-size: 1rem;
	line-height: 1.7;
	color: #4a5062;
	background: #ffffff;
}

img {
	max-width: 100%;
	height: auto;
	display: block;
}

a {
	color: var(--pl-navy);
	text-decoration: none;
}

/*
 * Underlined links in body copy.
 *
 * Scoped to the containers whose contents come from a WYSIWYG editor,
 * NOT to something like `p a`. A `p a` rule would also underline the
 * footer address and nav columns, the hero subtext, the Find Your Place
 * card descriptions and the PEX portal copy — all of which use <p> and
 * none of which should gain underlines.
 *
 * These four are every rich-text field an editor can put a link into:
 *   .feature-split__wysiwyg      Feature Split → Text
 *   .callout__body               Callout → Body text
 *   .faqs__answer                FAQs → Answer
 *   .apartment-detail__description   Apartment CPT → Description
 *
 * Add to this list when a new rich-text container appears, rather than
 * widening the selector. :is() keeps it to one rule and is forgiving —
 * an unrecognised entry is ignored instead of invalidating the whole
 * thing, which a plain comma-separated list would not be.
 *
 * a:not(.btn) so a button dropped into rich text stays a button.
 */
:is(
	.feature-split__wysiwyg,
	.callout__body,
	.faqs__answer,
	.apartment-detail__description
) a:not(.btn) {
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
}

:is(
	.feature-split__wysiwyg,
	.callout__body,
	.faqs__answer,
	.apartment-detail__description
) a:not(.btn):hover {
	text-decoration-thickness: 2px;
}

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

h1, h2, h3, h4, h5, h6 {
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
	font-weight: 400;
	color: var(--pl-navy);
	margin: 0 0 0.5em;
}

/*
 * h1 was missing from this scale, so every h1 fell back to the browser
 * default of 2em (32px) — smaller than an h2. That gap is why section
 * templates kept inventing their own clamp() sizes instead of using the
 * scale. Sizes belong here; section rules set colour and spacing only.
 *
 * The hero sizes its own .line-1/.line-2 spans, so it is unaffected.
 */
h1 {
	font-size: 3rem;
}

h2 {
	font-size: 2.5rem;
}

h3 {
	font-size: 1.875rem;
}

h4 {
	font-size: 1.5rem;
}

h5 {
	font-size: 1.25rem;
}

.font-display {
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
}

.quicksand {font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;}

/*
 * Visible to screen readers, not on screen. The theme didn't carry this
 * (WordPress only ships it in its own bundled themes), so any markup
 * using the conventional class name was rendering the text on the page.
 *
 * clip-path plus the legacy clip: the latter is the only version older
 * Safari honours, and dropping it makes the text reappear there.
 */
.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.container {
	max-width: var(--pl-container);
	margin: 0 auto;
	padding: 0 var(--pl-container-padding);
}

.container-narrow {
	max-width: 900px;
	margin: 0 auto;
	padding: 0 24px;
}

.btn {
	display: inline-block;
	font-size:1rem;
	font-weight: 500;
	/*letter-spacing: 0.06em;*/
	padding: 0.3rem 0.8rem;
	white-space: nowrap;
	border: 1px solid transparent;
	cursor: pointer;
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
}
.wide {padding: 0.3rem 2.8rem;}

.btn-navy {
	background: var(--pl-navy);
	color: #ffffff;
	border-color: var(--pl-navy);
}
.btn-navy:hover {
	background: #ffffff;
	color: var(--pl-navy);
	border-color: var(--pl-navy);
}

.btn-white {
	background: #ffffff;
	color: var(--pl-navy)!important;
	border-color: #ffffff;
}
.btn-white:hover {
	background: var(--pl-navy);
	color: #ffffff!important;
	border-color: #ffffff;
}

/*
 * Outline variant for use ON the navy — white keyline, navy fill, white
 * label, inverting to a solid white fill with a navy label on hover.
 * Effectively .btn-white's two states swapped, so the pair stay visually
 * consistent wherever they sit next to each other.
 *
 * Any icon inside should be a .mask-icon rather than an <img>: the mask
 * is painted with currentColor, so it flips white→navy with the label.
 * A white PNG can't follow the text colour and would vanish on hover.
 */
/* True outline button for use ON the navy — no fill, white keyline and
   label, filling to solid white with a navy label on hover. */
.btn-outline-white {
	background: transparent;
	color: #ffffff!important;
	border-color: #ffffff;
}
.btn-outline-white:hover {
	background: #ffffff;
	color: var(--pl-navy)!important;
	border-color: #ffffff;
}

/* The same outline treatment for light backgrounds — a secondary action
   sitting next to a solid .btn-navy. */
.btn-navy-outline {
	background: transparent;
	color: var(--pl-navy)!important;
	border-color: var(--pl-navy);
}
.btn-navy-outline:hover {
	background: var(--pl-navy);
	color: #ffffff!important;
	border-color: var(--pl-navy);
}

/*
 * ---------- Scroll reveal ----------
 * Generic "fade up into place the first time it scrolls into view"
 * treatment (matches the designer's animation reference). Applied via
 * assets/js/site-animations.js, which observes every `.reveal` element
 * with an IntersectionObserver and adds `.is-visible` once, then stops
 * watching it — sections don't re-hide if scrolled back past.
 *
 * Stagger a group by adding `.reveal-delay-1` / `.reveal-delay-2` to
 * successive children (e.g. the two contact-band buttons).
 *
 * Falls back to fully visible, no motion, if JS doesn't run or the
 * visitor has requested reduced motion.
 */
.reveal {
	opacity: 0;
	transform: translateY(32px);
	transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1), transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.reveal.is-visible {
	opacity: 1;
	transform: translateY(0);
}

.reveal-delay-1.is-visible {
	transition-delay: 0.2s;
}

.reveal-delay-2.is-visible {
	transition-delay: 0.4s;
}

.no-js .reveal {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	.reveal {
		opacity: 1;
		transform: none;
		transition: none;
	}

	.hero-block__heading .line-1,
	.hero-block__heading .line-2,
	.hero-block__subtext,
	.hero-block__buttons,
	.site-header {
		animation: none;
		opacity: 1;
		transform: none;
	}

	.find-your-place-card__photo-bg,
	.find-your-place-card__photo::after {
		transition: none;
	}
}

/* ---------- Header ---------- */
/*
 * Header colour + position behaviour (matches the designer's load/
 * animation reference) — the same on every page, not just the home page:
 * - Fixed to the viewport at all times — it stays visible while
 *   scrolling, and shrinks slightly (via `.is-scrolled`, toggled by
 *   assets/js/site-animations.js) once the page has scrolled past 40px.
 * - Transparent by default (white logo/icons/text), overlaying whatever
 *   sits at the top of the page. Turns into a solid white bar (navy
 *   logo/icons) once ANY of the following is true: scrolled past 40px,
 *   hovered, keyboard focus has landed inside it, or the Locations
 *   dropdown is open.
 * - Fades/slides down into place shortly after the page loads.
 *
 * Because the header always overlays the top of the page rather than
 * pushing it down, page content isn't given reserved top padding for it
 * (no `body { padding-top: ... }` — every page's own hero/top section is
 * expected to sit under the transparent header, same as the home page).
 *
 * The logo is a real white/navy SVG pair (see `.site-header__logo-img`
 * below); every small nav icon is a single-colour PNG rendered as a CSS
 * mask (`.mask-icon`) filled with `currentColor`. Flipping
 * `.site-header`'s `color` between white and navy recolours the icons,
 * nav text, and "Register interest" button together, in one place.
 */
:root {
	--site-header-height: 96px;
}

.site-header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 50;
	background-color: transparent;
	color: #ffffff;
	padding: 20px 0;
	transition: background-color 0.25s ease, color 0.25s ease, padding 0.25s ease, box-shadow 0.25s ease;
	animation: site-header-in 0.7s ease both;
	animation-delay: 0.05s;
}

.site-header.is-scrolled {
	padding: 12px 0;
	box-shadow: 0 2px 12px rgba(4, 49, 86, 0.08);
}

@keyframes site-header-in {
	from { opacity: 0; transform: translateY(-20px); }
	to { opacity: 1; transform: translateY(0); }
}

/* `body.has-solid-header` (apartment detail pages — see
   properties_living_solid_header_body_class() in functions.php) joins
   each of these solid-state groups so the header starts white instead of
   transparent. It has to be added to every one of them — background,
   both logo crossfade halves, and the button flip — or the header ends
   up white with a white logo on it. */
.site-header.is-scrolled,
.site-header:hover,
.site-header:focus-within,
.site-header:has(.site-header__dropdown.is-open),
body.has-solid-header .site-header {
	background-color: #ffffff;
	color: var(--pl-navy);
	box-shadow: 0 2px 12px rgba(4, 49, 86, 0.08);
}

.site-header .container {
	display: flex;
	align-items: center;
	justify-content: space-between;
}

/* Generic single-colour icon rendered via CSS mask + currentColor —
   `--mask` (a mask-image url) is set inline per icon in header.php. */
.mask-icon {
	display: inline-block;
	background-color: currentColor;
	-webkit-mask-image: var(--mask);
	mask-image: var(--mask);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-size: contain;
	mask-size: contain;
}

/*
 * Logo: real white + navy SVGs (not a mask) stacked in the same spot and
 * crossfaded with opacity. White shows while the header is transparent;
 * navy shows once the header turns white (scrolled/hovered/focused).
 */
.site-header__logo {
	position: relative;
	width: 240px;
	height: 48px;
	transition: all 0.5s;
}

.site-header__logo a {
	display: block;
	width: 100%;
	height: 100%;
}

.site-header__logo-img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	transition: opacity 0.25s ease;
}

.site-header__logo-img--white {
	opacity: 1;
}

.site-header__logo-img--blue {
	opacity: 0;
}

.site-header.is-scrolled .site-header__logo-img--white,
.site-header:hover .site-header__logo-img--white,
.site-header:focus-within .site-header__logo-img--white,
.site-header:has(.site-header__dropdown.is-open) .site-header__logo-img--white,
body.has-solid-header .site-header__logo-img--white {
	opacity: 0;
}

.site-header.is-scrolled .site-header__logo-img--blue,
.site-header:hover .site-header__logo-img--blue,
.site-header:focus-within .site-header__logo-img--blue,
.site-header:has(.site-header__dropdown.is-open) .site-header__logo-img--blue,
body.has-solid-header .site-header__logo-img--blue {
	opacity: 1;
}

.site-header__right {
	display: flex;
	align-items: center;
	gap: 24px;
	flex-shrink: 0;
}

/* Burger toggle — hidden at desktop widths, shown below 992px (see the
   @media block near the end of this file). Draws its own icon from
   three spans so it recolours via currentColor like everything else in
   the header, and morphs into an "X" while the mobile panel is open. */
.site-header__burger {
	display: none;
	flex-direction: column;
	justify-content: center;
	gap: 5px;
	width: 32px;
	height: 32px;
	padding: 0;
	background: none;
	border: none;
	cursor: pointer;
	flex-shrink: 0;
}

.site-header__burger span {
	display: block;
	width: 100%;
	height: 2px;
	background: currentColor;
	transition: transform 0.25s ease, opacity 0.25s ease;
	color: var(--pl-navy);
}

.site-header__burger.is-open span:nth-child(1) {
	transform: translateY(7px) rotate(45deg);
}

.site-header__burger.is-open span:nth-child(2) {
	opacity: 0;
}

.site-header__burger.is-open span:nth-child(3) {
	transform: translateY(-7px) rotate(-45deg);
}

.site-header__icon-link {
	display: flex;
	align-items: center;
	gap: 8px;
	color: inherit;
	font-size: 1rem;
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
}

.site-header__icon-link .tel {font-size: 1.125rem; font-weight: 500;}

.site-header__icon-link .mask-icon,
.site-header__search .mask-icon {
	width: 18px;
	height: 18px;
}

.site-header a {
	color: inherit;
}

.site-header__nav {
	/* Deliberately NOT position:relative — .site-header__dropdown needs
	   its containing block to be the full-width .site-header (already
	   position:fixed, spanning left:0/right:0), not this small nav
	   element, so the mega panel's centering math below resolves against
	   the viewport instead of the button's own tiny box. That mismatch
	   was the previous bug: the panel rendered far from the "Locations"
	   button, so the mouse crossed a dead zone and lost :hover before
	   reaching it. */
}

.site-header__nav-toggle {
	background: none;
	border: none;
	color: inherit;
	font-size: 1rem;
	font-family: inherit;
	cursor: pointer;
	display: flex;
	align-items: center;
	gap: 6px;
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
}

.site-header__nav-toggle .mask-icon {
	width: 12px;
	height: 8px;
}

/*
 * Locations dropdown — a full-viewport-width "mega menu" on desktop
 * (opens on hover, covering the top of the hero/page below the header),
 * a plain compact accordion list on mobile (see the max-width:991px
 * override further down). `.site-header__dropdown` is `position:absolute`
 * with its containing block being `.site-header` itself (fixed,
 * left:0/right:0 — see the note on `.site-header__nav` just above for why
 * that ancestor is deliberately NOT position:relative). That gives us
 * `top:100%` tracking the header's real height/offset for free (scrolled
 * padding, the location-page top bar, etc.) and `left:50% + width:100vw +
 * translateX(-50%)` resolving correctly against the full viewport instead
 * of the small "Locations" button's own box.
 *
 * Opening on mouse hover is driven by JS (`.mega-open`, set via
 * mouseenter/mouseleave with a grace timer in header-dropdown.js), not a
 * plain CSS `:hover` selector — the panel is visually far from the
 * button it's triggered by, and relying on the browser to keep treating
 * the button as "hovered" purely because the panel is its DOM
 * descendant (regardless of where it's actually painted) proved
 * unreliable in testing. `:focus-within` is kept for keyboard users,
 * since focus-based ancestry doesn't have the same issue.
 */
.site-header__dropdown {
	display: none;
	position: absolute;
	top: 100%;
	left: 50%;
	right: auto;
	width: 100vw;
	max-width: 100vw;
	transform: translateX(-50%);
	background: #ffffff;
	min-width: 0;
	box-shadow: 0 20px 40px rgba(4, 49, 86, 0.15);
	padding: 40px 0;
	margin-top: 0;
	color: var(--pl-navy);
}

.site-header__dropdown.is-open {
	display: block;
}

.site-header__dropdown .container-narrow h3 {text-align: center; font-size: 1.875rem; font-weight: 500;}


.site-header__dropdown .site-header__mega.container {justify-content: space-evenly;}

@media (min-width: 992px) {
	.site-header__nav.mega-open .site-header__dropdown,
	.site-header__nav:focus-within .site-header__dropdown {
		display: block;
		min-height: 500px;
		height: 60vh;
	}
}

.site-header__dropdown a {
	display: block;
	padding: 10px 20px;
	color: var(--pl-navy);
	font-size: 0.875rem;
}

.site-header__dropdown a:hover {
	background: #f7f7f5;
}

/* Mega menu cards — image (the linked page's own featured image) +
   page title, same tint/hover treatment as .find-your-place-card. */
.site-header__mega {
	display: flex;
	flex-wrap: wrap;
	gap: 32px;
}

.site-header__mega-card {
	display: block;
	/*
	 * Share the row rather than taking a fixed third of it. At a fixed
	 * 33.33% three cards plus two 32px gaps come to more than the full
	 * width, so the third wrapped onto its own line — which is what
	 * happened as soon as a location had three apartments.
	 *
	 * flex-basis 0 with grow lets any number of cards divide the space
	 * that is actually free; max-width keeps two cards at the proportion
	 * they have always had on the Locations panel instead of stretching
	 * to half the viewport each.
	 */
	flex: 1 1 0;
	min-width: 0;
	max-width: 33.33%;
	padding: 0;
	text-align: center;
	background-color: #ffffff;
}

.site-header__mega-card:hover {
	background: none;
}

.site-header__mega-card-photo {
	position: relative;
	display: block;
	height: 260px;
	background-color: #e3e4e8;
	background-size: cover;
	background-position: center;
}

.site-header__mega-card-photo::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--pl-navy);
	opacity: 0;
	transition: opacity 0.3s ease;
}

.site-header__mega-card:hover .site-header__mega-card-photo::after {
	opacity: 0.15;
}

.site-header__mega-card-name {
	display: block;
	margin-top: 14px;
	padding: 0;
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
	font-size: 1.85rem;
	font-weight: 500;
	color: var(--pl-navy);
}

/*
 * Custom navigation menu — a location can swap the whole "Locations"
 * dropdown for a plain WordPress menu instead (Location Header →
 * "Custom navigation menu", see properties_living_get_location_context()
 * in functions.php). Sits in the same `.site-header__right` flex row, so
 * it inherits that row's gap/spacing and the mobile burger behaviour for
 * free — only the link list itself needs styling here.
 */
.site-header__custom-nav-list {
	display: flex;
	align-items: center;
	gap: 24px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.site-header__custom-nav-list a {
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
	font-size: 1rem;
	color: inherit;
}

/*
 * The dropdown toggle is a <button>, and a button inherits neither the
 * line-height nor the padding its sibling links have: the browser gives
 * it line-height: normal (about 20px here against the links' 27.2px) and
 * a default padding of 1px 6px. That made its box 22px tall against the
 * links' 31.2px, so its text sat lower than the rest of the row.
 *
 * Matching both to the link rule above lines the baselines up. Scoped to
 * the custom nav: the parent site's Locations toggle sits outside this
 * list and is positioned by its own rules.
 */
.site-header__custom-nav-list .site-header__nav-toggle {
	line-height: inherit;
	padding: 0 0 4px;
}

/*
 * NOTE: the padding above is the DESKTOP value. At (0,2,0) this selector
 * outranks the mobile `.site-header__nav-toggle { padding: 12px 0 }`
 * rule, so the burger menu needs its own override further down — see the
 * matching rule in the max-width: 991px block.
 */

/* Top-level items only (not sub-menu links) get the same hover/active
   underline as .feature-split__menu — 2px solid border, left-to-right
   reveal. `currentColor` rather than a fixed navy so it still reads on
   the header's white-on-transparent (home) state. */
.site-header__custom-nav-list > li > a {
	position: relative;
	display: inline-block;
	padding-bottom: 4px;
	text-decoration: none;
	width: 100%;
}

.site-header__custom-nav-list > li > a::before {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 2px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.site-header__custom-nav-list > li > a:hover::before,
.site-header__custom-nav-list > li.current-menu-item > a::before {
	transform: scaleX(1);
}

/* Chevron on any top-level item with children (WP adds
   .menu-item-has-children to the <li> automatically) — signals the
   hover-reveal sub-menu below it. Drawn with CSS (no image asset) so it
   always matches currentColor across the header's light/dark states. */
.site-header__custom-nav-list > li.menu-item-has-children > a {
	display: inline-flex;
	align-items: center;
	gap: 6px;
}

.site-header__custom-nav-list > li.menu-item-has-children > a::after {
	content: "";
	width: 7px;
	height: 7px;
	margin-top: -3px;
	border-right: 1.5px solid currentColor;
	border-bottom: 1.5px solid currentColor;
	transform: rotate(45deg);
}

/*
 * Sub-menus (any item given children in Appearance → Menus) reveal on
 * hover — a full-width bar spanning the whole header, positioned below
 * it, mirroring the Locations mega-menu (`.site-header__dropdown`)
 * below. Its items are laid out horizontally and right-aligned.
 *
 * Breakout note: `.sub-menu` uses left:50%/width:100vw/translateX(-50%)
 * to span the viewport, same trick as `.site-header__dropdown`. That
 * only works if its nearest positioned ancestor is `.site-header`
 * (position:fixed) — so `.site-header__custom-nav-list li` deliberately
 * stays position:static here (no position:relative), same reasoning as
 * `.site-header__nav` above.
 *
 * `:focus-within` mirrors the hover state for keyboard users. Plain CSS
 * :hover is used rather than the mega-menu's JS hover-intent handling —
 * unlike the mega-menu's separate toggle button, this sub-menu's trigger
 * is the parent link itself, which sits inside the same
 * `.site-header__right` row the bar drops from, so there's no dead zone
 * the cursor has to cross to reach it.
 */
.site-header__custom-nav-list li {
	/* Deliberately position:static — see breakout note above. */
}

.site-header__custom-nav-list .sub-menu {
	position: absolute;
	top: 100%;
	left: 50%;
	z-index: 60;
	width: 100vw;
	max-width: 100%;
	box-sizing: border-box;
	transform: translateX(-50%);
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 28px;
	list-style: none;
	margin: 0;
	/* Outer box is full viewport width (the white bar); this padding
	   keeps the actual link row inset to match .container's max-width
	   (--pl-container) and centered, same as the mega-menu's inner
	   .site-header__mega.container wrapper achieves with a real element —
	   done via calc/max here since wp_nav_menu's <ul> can't be wrapped. */
	padding: 24px max(var(--pl-container-padding), calc((100vw - var(--pl-container)) / 2 + var(--pl-container-padding)));
	background: #ffffff;
	box-shadow: 0 20px 40px rgba(4, 49, 86, 0.15);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.25s ease, visibility 0.25s;
}

.site-header__custom-nav-list li:hover > .sub-menu,
.site-header__custom-nav-list li:focus-within > .sub-menu {
	opacity: 1;
	visibility: visible;
}

.site-header__custom-nav-list .sub-menu a {
	position: relative;
	display: inline-block;
	padding-bottom: 4px;
	color: var(--pl-navy);
	text-decoration: none;
}

.site-header__custom-nav-list .sub-menu a::before {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 2px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.site-header__custom-nav-list .sub-menu a:hover::before,
.site-header__custom-nav-list .sub-menu li.current-menu-item a::before {
	transform: scaleX(1);
}

/* "Register interest" is styled `.btn-white` for the dark/transparent
   header (default state); flip it to a solid navy button whenever the
   header background is white so it doesn't disappear. */
.site-header.is-scrolled .btn-white,
.site-header:hover .btn-white,
.site-header:focus-within .btn-white,
.site-header:has(.site-header__dropdown.is-open) .btn-white,
body.has-solid-header .site-header .btn-white {
	background: var(--pl-navy);
	color: #ffffff!important;
	border-color: var(--pl-navy);
}

.site-header .btn-white:hover {
	background: var(--pl-navy-dark);
	border-color: var(--pl-navy-dark);
}

/*
 * ---------- Location pages — two-row header ----------
 * Pages with the "Location Header" ACF field switched on (and every page
 * beneath them — see properties_living_get_location_context() in
 * functions.php) get a slim ProperTies Living bar above the normal
 * header, with the header row's logo swapped for the location's own.
 * Reference: berkeleyliving.co.uk vs. berkeleyliving.co.uk/the-watermint/.
 */
:root {
	--location-bar-height: 40px;
}

.site-header-location-bar {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 51;
	height: var(--location-bar-height);
	background-color: var(--pl-navy);
	display: flex;
	align-items: center;
	justify-content: start;
	padding: 0 var(--pl-container-padding) 0;
}

.site-header-location-bar__back {
	display: flex;
	align-items: baseline;
	gap: 8px;
	color: #ffffff;
	text-decoration: none;
	font-family: Quicksand;
	font-size: 0.8125rem;
	font-weight: 500;
}

.site-header-location-bar__back:hover {
	/*opacity: 0.8;*/
	color: #ffffff;
}

.site-header-location-bar__arrow {
	font-size: 1rem;
	line-height: 1;
}

.site-header-location-bar__logo {
	height: 16px;
	width: auto;
}

body.has-location-header .site-header {
	top: var(--location-bar-height);
}

/* The location bar itself is always solid (not part of the transparent
   header overlay), so it's the only piece of header space page content
   still needs reserved — the site-header height isn't, since it now
   overlays every page the same way the home page's hero does. */
body.has-location-header {
	padding-top: var(--location-bar-height);
}

/*
 * Solid-header pages reserve the header's own height as well, so the
 * gallery starts below it rather than behind it. Only needed at ≥992px:
 * below that .site-header is already position: relative and in the flow,
 * so it takes its own space.
 */
body.has-solid-header {
	padding-top: var(--site-header-height);
}

body.has-solid-header.has-location-header {
	padding-top: calc(var(--location-bar-height) + var(--site-header-height));
}


/* Single full-colour location logo (not a white/blue crossfade pair) —
   sized to the same logo box as the default logo, letterboxed to fit. */
.site-header__logo-img--location {
	object-fit: contain;
	object-position: left center;
}

/* ---------- Hero (ACF block) ---------- */
.hero-block {
	position: relative;
	min-height: 620px;
	display: flex;
	align-items: center;
	background-size: cover;
	background-position: center;
	background-color: var(--pl-navy-dark);
	overflow: hidden;
}

/*
 * Background video — a looping, muted Vimeo embed (see hero/render.php),
 * matching the designer's reference. The hero's own background-image
 * (the "Background photo" ACF field) sits behind it and shows through
 * as a poster while the video loads, or as the full fallback if no
 * video ID is set.
 */
.hero-block__video {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
}

/*
 * An iframe's own box can be sized to 100%/100%, but object-fit doesn't
 * reach inside it to cover-fit the video playing within — so a straight
 * 100%/100% iframe leaves the Vimeo video letterboxed/pillarboxed
 * whenever the hero's aspect ratio doesn't match the video's 16:9.
 * Oversizing the iframe itself (classic background-video technique) and
 * centering it is what actually makes the video fill the hero edge to
 * edge, cropping instead of letterboxing.
 */
.hero-block__video iframe {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 100vw;
	height: 56.25vw; /* 100vw * 9/16 — keeps the 16:9 video uncropped horizontally... */
	min-height: 100%;
	min-width: 177.78vh; /* ...or vertically, whichever the container needs to stay covered */
	transform: translate(-50%, -50%);
	border: 0;
	pointer-events: none;
}

.hero-block::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: var(--pl-navy);
	opacity: 0.3;
}

.hero-block__inner {
	position: relative;
	z-index: 2;
	width: 850px;
	margin: 0 auto;
	padding: 160px var(--pl-container-padding) 60px;
}

/*
 * Compact hero — the "Height" field on the Hero block. For text pages
 * (Privacy policy, Terms) where the hero is a title bar rather than a
 * full-height opener.
 *
 * Both the min-height AND the inner padding have to come down: the 160px
 * top padding is what clears the fixed transparent site header, so
 * halving the height alone would leave the heading pinned near the
 * bottom. The replacement is derived from --site-header-height rather
 * than a magic number, so it keeps clearing the header if that changes.
 *
 * Only defined at ≥992px because .hero-block's min-height is — below
 * that the hero is already sized by its content.
 */
.hero-block--compact {
	min-height: 380px;
}

.hero-block--compact .hero-block__inner {
	padding-top: calc(var(--site-header-height) + 40px);
	padding-bottom: 40px;
}

/*
 * Sizes taken directly from the Sketch source (3a_HOME > Modern / Living
 * text layers): both lines are Quicksand SemiBold, but "Living" is set
 * dramatically larger (130px vs 80px) with tight kerning — not a uniform
 * heading size with a "thin" first line as originally guessed.
 *
 * Each line/subtext cascades in on page load (matching the designer's
 * reference: Modern at 150ms, Living at 300ms, subtext at 450ms) via the
 * shared `hero-line-in` keyframe below.
 */
@keyframes hero-line-in {
	from { opacity: 0; transform: translateY(24px); }
	to { opacity: 1; transform: translateY(0); }
}

.hero-block__heading {
	font-weight: 600;
	line-height: 1;
	max-width: 720px;
	margin-bottom: 24px;
	position: relative;
}

.hero-block__heading .line-1,
.hero-block__heading .line-2 {
	display: block;
	color: #ffffff;
	opacity: 0;
	animation: hero-line-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.hero-block__heading .line-1 {
	font-size: clamp(2.5rem, 6vw, 5rem);
	animation-delay: 0.15s;
	font-weight: 400;
}

.hero-block__heading .line-2 {
	font-size: clamp(3.25rem, 9vw, 8.125rem);
	letter-spacing: -1px;
	margin-top: -0.1em;
	animation-delay: 0.3s;
}

.hero-block__subtext {
	color: #ffffff;
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-weight: 500;
	font-size: 1.875rem;
	line-height: 1.33;
	/*max-width: 640px;*/
	margin: 0;
	opacity: 0;
	animation: hero-line-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
	animation-delay: 0.45s;
}

/* Up to two optional CTA buttons — "Button 1"/"Button 2" ACF fields.
   Button 1 uses .btn-white, Button 2 uses .btn-navy (matches the "Make
   an enquiry" / "Contact us" pairing used elsewhere on the page). */
.hero-block__buttons {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
	margin-top: 32px;
	opacity: 0;
	animation: hero-line-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
	animation-delay: 0.6s;
}

/* ---------- Intro text (ACF block) ---------- */
.intro-text-block {
	padding: 70px 0;
	text-align: center;
}

.intro-text-block p {
	color: var(--pl-navy);
	font-size: 1.875rem;
	line-height: 1.47;
	max-width: 900px;
	margin: 0 auto 1em;
}
.intro-text-block p.para-two { font-size:1.125rem; }

/*
 * ---------- Find Your Place cards (ACF block) ----------
 * One block instance renders every row of the "Locations" repeater as a
 * card in this wrapping row — see blocks/find-your-place-card/render.php.
 * Wraps to a single centred column at narrow widths since each card has
 * a minimum comfortable width (flex-basis below).
 */
.find-your-place {padding: 70px 0; background-color: #f7f7f5;}

/*
 * Hidden by default, at every width — the dots only mean anything once
 * find-your-place-carousel.js has added .is-carousel. Putting this
 * inside the mobile media query (as .photo-grid__dots still does) leaves
 * them visible on desktop, where there is no carousel to page through.
 */
.find-your-place-dots {
	display: none;
}
.find-your-place-cards {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 30px;
	margin: 0 auto 30px;
}

.find-your-place-card {
	flex: 1 1 320px;
	max-width: 420px;
	border: 1px solid #e3e4e8;
	box-shadow: 0 10px 30px rgba(4, 49, 86, 0.12);
}

.find-your-place-card__photo {
	position: relative;
	min-height: 260px;
	overflow: hidden;
	background-size: cover;
	background-position: center;
	display: flex;
	align-items: center;
	justify-content: center;
}

/* The photo itself is the card's own background-image (set inline), so
   it can be scaled independently of the tint/logo layers on hover. */
.find-your-place-card__photo-bg {
	position: absolute;
	inset: 0;
	background-size: cover;
	background-position: center;
	transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

.find-your-place-card:hover .find-your-place-card__photo-bg {
	transform: scale(1.06);
}

/* Base tint — confirmed pure black at ~40% opacity in the Sketch source
   (Watford_thumb_tint / Barking_thumb_tint layers), always present for
   logo legibility. A second navy wash fades in on hover as an
   interaction cue (matching the designer's animation reference). */
.find-your-place-card__photo::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: #000000;
	opacity: 0.4;
}

.find-your-place-card__photo::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: var(--pl-navy);
	opacity: 0;
	transition: opacity 0.6s ease;
}

.find-your-place-card:hover .find-your-place-card__photo::after {
	opacity: 0.15;
}

.find-your-place-card__photo img {
	position: relative;
	z-index: 2;
	width: 150px;
}

.find-your-place-card__body {
	padding: 24px 24px 32px;
	text-align: center;
}

/*
 * No font-size: 1.875rem is exactly the global h3, so pinning it here
 * changed nothing on desktop while blocking the mobile scale — the card
 * title stayed at 30px inside a 225px card while every other h3 stepped
 * down. Colour comes from the global rule too; only weight and leading
 * are specific to the card.
 */
.find-your-place-card__body h3 {
	font-weight: 500;
	line-height: 1.47;
}

.find-your-place-card__body p {
	color: var(--pl-navy);
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-size: 1.125rem;
	line-height: 1.44;
}

.find-your-place-card__cta {
	margin-top: 12px;
}

/*
 * Shown when a location has no Button URL set. Keeps the button's shape
 * and position so the row of cards stays aligned, but reads as a status
 * label rather than something to click — muted, no pointer, and no hover
 * change (the .btn-navy hover would otherwise still fire on a span).
 */
.find-your-place-card__cta--coming-soon,
.find-your-place-card__cta--coming-soon:hover {
	background: #e7eaee;
	border-color: #e7eaee;
	color: #5c6b7a;
	cursor: default;
}

/* ---------- Shared standard list (ACF block) ---------- */
.shared-standard-block {
	padding: 70px 0;
	text-align: center;
}

.shared-standard-block__heading {
	color: var(--pl-navy);
	font-size: 1.875rem;
	line-height: 1.47;
	margin-bottom: 20px;
}

.shared-standard-block__intro {
	color: var(--pl-navy);
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-size: 1.125rem;
	line-height: 1.44;
	max-width: 620px;
	margin: 0 auto 40px;
}

.shared-standard-list {
	list-style: none;
	margin: 0 auto;
	padding: 0;
	max-width: 740px;
	column-count: 2;
	column-gap: 48px;
	text-align: left;
}

.shared-standard-list li {
	color: var(--pl-navy);
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-size: 1.125rem;
	line-height: 1.44;
	padding-left: 1.75em;
	position: relative;
	margin-bottom: 1em;
	break-inside: avoid;
	background-image: url('assets/icons/arrow-line-icon.png');
	background-repeat: no-repeat;
	background-position: 0 0.35em;
	background-size: 16px 15px;
}

/*
 * ---------- Feature Split (ACF block) ----------
 * Two-column section — logo/heading/rich-text one side, image or video
 * the other, optional menu row on top and a background image/colour
 * (set inline per instance — see render.php). `--fs-text-width` (also
 * inline, from the "Text column width" field) sizes the text side;
 * .feature-split__media flexes to fill whatever's left. Swap
 * `.feature-split__row--media-left`/`--media-right` (from the "Media
 * position" field) to flip which side the media sits on.
 */
.feature-split {
	padding: 70px 0;
}

.feature-split__menu {
	margin-bottom: 40px;
}

.feature-split__menu ul {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 28px;
	margin: 0;
	padding: 0;
}

/* .menu-item-no-link is the <span> that replaces the <a> on menu items
   carrying the `no-link` CSS class — see
   properties_living_nav_menu_no_link() in functions.php. It shares the
   link's typography so the row still reads as one set, but deliberately
   gets none of the hover/underline rules below. */
.feature-split__menu a,
.feature-split__menu .menu-item-no-link {
	position: relative;
	display: inline-block;
	padding-bottom: 4px;
	color: var(--pl-navy);
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
	font-size: 1rem;
	text-decoration: none;
}

.feature-split__menu .menu-item-no-link {
	cursor: default;
}

/* Hover/active underline — 2px solid border that reveals left-to-right.
   Uses ::before (not ::after) since li:first-child's ::after is already
   the arrow glyph. Active state (WP's .current-menu-item on the <li>)
   shows the same border, already expanded, no animation needed there. */
.feature-split__menu a::before {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 2px;
	background: var(--pl-navy);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}

.feature-split__menu a:hover::before,
.feature-split__menu li.current-menu-item a::before {
	transform: scaleX(1);
}

/* First item reads as the section's "eyebrow" label — bold, uppercase,
   with an arrow — the rest (e.g. "1 Bedroom / 2 Bedroom / 3 Bedroom")
   sit alongside it at normal weight. */
.feature-split__menu li:first-child a,
.feature-split__menu li:first-child .menu-item-no-link {
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	font-size: 0.875rem;
}

.feature-split__menu li:first-child a::after,
.feature-split__menu li:first-child .menu-item-no-link::after {
	content: "\2192";
	margin-left: 10px;
	font-weight: 400;
	text-transform: none;
}

.feature-split__row {
	display: flex;
	align-items: center;
	gap: 60px;
	flex-wrap: wrap;
}

.feature-split__row--media-left {
	flex-direction: row-reverse;
}

/* flex-grow:0 is deliberate — .feature-split__text should sit at
   exactly --fs-text-width, not compete for leftover space against
   .feature-split__media below (which is what made the media column
   render smaller than intended: with both sides set to grow:1, any
   spare row width got split evenly between them regardless of the
   text-width setting). */
.feature-split__text {
	flex: 0 1 var(--fs-text-width, 50%);
	min-width: 280px;
}

.feature-split__logo {
	margin-bottom: 24px;
}

.feature-split__logo img {
	width: 180px;
	height: auto;
}

.feature-split__heading {
	color: var(--pl-navy);
	font-size: clamp(1.75rem, 3vw, 2.5rem);
	line-height: 1.2;
	margin-bottom: 20px;
}

.feature-split__wysiwyg {
	color: var(--pl-navy);
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-size: 1.125rem;
	line-height: 1.6;
}

.feature-split__wysiwyg p {
	margin: 0 0 1em;
}

.feature-split__wysiwyg ul,
.feature-split__wysiwyg ol {
	margin: 0 0 1em;
	padding-left: 1.25em;
}

.feature-split__wysiwyg li {
	margin-bottom: 0.5em;
}

.feature-split__button {
	margin-top: 24px;
}

/* Takes all the row width .feature-split__text doesn't use — see the
   note on flex-grow above. */
.feature-split__media {
	flex: 1 1 0;
	min-width: 280px;
}

.feature-split__media img {
	width: 100%;
	height: auto;
	display: block;
}

/* Responsive 16:9 wrapper for the raw embed HTML ACF's oEmbed field
   returns — that markup carries its own fixed width/height attributes,
   which this overrides so the video scales with the column instead. */
.feature-split__video {
	position: relative;
	padding-top: 56.25%;
	overflow: hidden;
}

.feature-split__video iframe,
.feature-split__video embed,
.feature-split__video object {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

@media (max-width: 782px) {
	.feature-split {
		padding: 60px 0;
	}

	.feature-split__text {
		flex-basis: 100%;
	}
}

/*
 * ---------- Gallery Carousel (ACF block) ----------
 * Full-bleed image carousel — no .container wrapper, so it always spans
 * the full viewport width. Built on Embla Carousel (see
 * assets/js/gallery-carousel.js); the .embla/.embla__viewport/
 * .embla__container/.embla__slide class names are Embla's own required
 * structure (embla-carousel.com/docs/v8/get-started/cdn), everything
 * else (.embla__prev/__next/__dots/__dot) is this theme's own styling
 * hung off Embla's plain HTML buttons.
 */
.gallery-carousel .embla {
	position: relative;
}

.gallery-carousel .embla__viewport {
	overflow: hidden;
}

.gallery-carousel .embla__container {
	display: flex;
	touch-action: pan-y pinch-zoom;
}

.gallery-carousel .embla__slide {
	position: relative;
	flex: 0 0 100%;
	min-width: 0;
	height: clamp(360px, 55vw, 720px);
}

.gallery-carousel .embla__slide img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.gallery-carousel .embla__prev,
.gallery-carousel .embla__next {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 2;
	width: 56px;
	height: 56px;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--pl-navy);
	border: none;
	cursor: pointer;
	padding: 0;
	transition: background-color 0.2s ease;
}

.gallery-carousel .embla__prev:hover,
.gallery-carousel .embla__next:hover {
	background: var(--pl-navy-dark);
}

.gallery-carousel .embla__prev {
	left: 24px;
}

.gallery-carousel .embla__next {
	right: 24px;
}

.gallery-carousel .embla__prev img,
.gallery-carousel .embla__next img {
	width: 16px;
	height: 16px;
}

.gallery-carousel .embla__dots {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 24px;
	z-index: 2;
	display: flex;
	justify-content: center;
	align-items: center;
	gap: 14px;
}

.gallery-carousel .embla__dot {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	border: none;
	padding: 0;
	background: rgba(255, 255, 255, 0.5);
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.gallery-carousel .embla__dot.is-active {
	background: #ffffff;
}

@media (max-width: 782px) {
	.gallery-carousel .embla__prev,
	.gallery-carousel .embla__next {
		width: 44px;
		height: 44px;
	}

	.gallery-carousel .embla__prev {
		left: 12px;
	}

	.gallery-carousel .embla__next {
		right: 12px;
	}

	.gallery-carousel .embla__dots {
		bottom: 16px;
	}
}

/*
 * ---------- Icon Grid (ACF block) ----------
 * Brand icon + centred intro line, then a row of circular amenity icons
 * — up to 5 per row, spaced evenly via flexbox, wrapping to further
 * centred rows beyond that (see blocks/icon-grid/render.php). The
 * supplied icons already bake in their own navy circle + white glyph
 * (90x90 SVGs), so .icon-grid__item-icon is just sized, no separate
 * circle background needed.
 */
.icon-grid {
	padding: 70px 0;
	text-align: center;
}

.icon-grid__brand-icon {
	display: block;
	margin: 0 auto 24px;
	max-height: 40px;
	width: auto;
}

.icon-grid__intro {
	color: var(--pl-navy);
	font-size: clamp(1.375rem, 2.4vw, 1.75rem);
	font-weight: 500;
	line-height: 1.4;
	max-width: 900px;
	margin: 0 auto 60px;
}

.icon-grid__items {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 48px 40px;
	max-width: 1100px;
	margin: 0 auto;
}

.icon-grid__item {
	flex: 0 1 160px;
}

.icon-grid__item-icon {
	display: block;
	width: 94px;
	height: 94px;
	margin: 0 auto 20px;
}

.icon-grid__item-label {
	color: var(--pl-navy);
	font-size: 1.125rem;
	line-height: 1.3;
	margin: 0;
}

@media (max-width: 782px) {
	.icon-grid {
		padding: 60px 0;
	}

	.icon-grid__items {
		gap: 32px 24px;
	}

	.icon-grid__item {
		flex-basis: 120px;
	}

	.icon-grid__item-icon {
		width: 72px;
		height: 72px;
	}
}

/*
 * ---------- Apartments Grid (ACF block) ----------
 * Bento-style card grid — see blocks/apartments-grid/render.php, which
 * finds this page's child pages linked to an Apartment automatically (no
 * manual selection). The bento pattern (two stacked cards + one taller
 * card, spanning both rows) repeats every 3 cards via nth-child, using
 * `grid-auto-flow: column dense` so the browser handles the stacking —
 * this works for any number of apartments, not just multiples of 3
 * (leftover 1-2 cards at the end just render as normal single cards).
 */
.apartments-grid {
	padding: 70px 0;
}

.apartments-grid__heading {
	color: var(--pl-navy);
	margin-bottom: 30px;
}

/*
 * One arrangement per card count, set by a modifier from the block (see
 * blocks/apartments-grid/render.php). The previous single grid assumed
 * the three-card mosaic: with two cards they stacked into one column and
 * stretched the full width, and with four the :nth-child(3n) span broke
 * the rows.
 *
 * Heights use clamp() rather than fixed rows so the cards keep their
 * proportions as the container narrows, instead of the images being
 * cropped harder and harder.
 */
.apartments-grid__cards {
	display: grid;
	gap: 24px;
}

/* One: full width, shallow enough not to dominate the page. */
.apartments-grid__cards--1 {
	grid-template-columns: 1fr;
	grid-template-rows: clamp(300px, 32vw, 440px);
}

/* Two: side by side and roughly square, matching the tall card's shape
   in the three-card layout rather than two stretched bands. */
.apartments-grid__cards--2 {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	grid-template-rows: clamp(340px, 40vw, 544px);
}

/* Three: the original mosaic — two shallow stacked, one tall beside. */
.apartments-grid__cards--3 {
	grid-auto-flow: column dense;
	grid-auto-columns: minmax(240px, 1fr);
	grid-template-rows: repeat(2, minmax(260px, 1fr));
}

/* Four: an even 2x2 of the shallow card. */
.apartments-grid__cards--4 {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	grid-template-rows: repeat(2, clamp(240px, 26vw, 300px));
}

.apartments-grid__card {
	position: relative;
	display: block;
	overflow: hidden;
	background-color: #e3e4e8;
}

/*
 * Scoped to the three-card layout. Unscoped it also caught the third
 * card of the 2x2, which then spanned both rows and collapsed the grid.
 */
.apartments-grid__cards--3 .apartments-grid__card:nth-child(3n) {
	grid-row: span 2;
}

.apartments-grid__card-photo {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

.apartments-grid__card-photo img {height: 100%; width: 100%; max-width: none;}

.apartments-grid__card:hover .apartments-grid__card-photo {
	transform: scale(1.06);
}

.apartments-grid__card::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: #000000;
	opacity: 0.35;
}

.apartments-grid__card::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: var(--pl-navy);
	opacity: 0;
	transition: opacity 0.6s ease;
}

.apartments-grid__card:hover::after {
	opacity: 0.15;
}

.apartments-grid__card-info {
	position: absolute;
	z-index: 2;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	text-align: center;
	color: #ffffff;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 6px;
	width: 100%;
	padding: 0 16px;
}

.apartments-grid__card-type {
	font-size: 1.5rem;
	font-weight: 500;
}

.apartments-grid__card-price {
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-size: 1rem;
}

.apartments-grid__card-cta {
	margin-top: 10px;
	opacity: 0;
	visibility: hidden;
	transform: translateY(6px);
	transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s;
}

.apartments-grid__card:hover .apartments-grid__card-cta {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.apartments-grid__actions {
	margin-top: 32px;
	text-align: center;
}

@media (max-width: 782px) {
	/*
	 * One column at every count — the modifier grids above are all
	 * overridden here deliberately, so a new count never needs a
	 * matching mobile rule.
	 */
	.apartments-grid__cards,
	.apartments-grid__cards--1,
	.apartments-grid__cards--2,
	.apartments-grid__cards--3,
	.apartments-grid__cards--4 {
		display: flex;
		flex-direction: column;
		gap: 20px;
	}

	.apartments-grid__card {
		min-height: 300px;
	}

	.apartments-grid__card-cta {
		opacity: 1;
		visibility: visible;
		transform: none;
	}
}

/*
 * ---------- Apartment Detail (template-parts/apartment-detail.php) ----------
 * Shown on a Page with an Apartment linked (see page.php) instead of that
 * page's normal block content.
 *
 * Structure, after the layout review: full-bleed gallery, a full-width
 * key-facts strip, then a two-column body with a sticky enquiry rail.
 *
 * The single-column version before this left the right two thirds of a
 * 1340px container empty the whole way down — the body was capped at
 * 900px — and put the one enquiry button above the gallery, where it
 * scrolled away and never came back.
 */

/* ---------- Key facts strip ---------- */
/*
 * --facts-count comes from the template: the strip holds only the fields
 * that are filled in, so the columns have to follow the count rather than
 * a fixed five, or three facts would sit squeezed into the left third.
 */
.apartment-facts {
	display: grid;
	grid-template-columns: repeat(var(--facts-count, 5), minmax(0, 1fr));
	/*
	 * The dividing lines are the 1px gaps letting the container's
	 * background through, not borders on the items. That way the rules
	 * stay correct at any column count and at any wrap point — the
	 * border-on-each-item version needed an :nth-child rule per
	 * breakpoint, and got one wrong every time the count changed.
	 */
	gap: 1px;
	margin: 0 0 30px;
	border: 1px solid #e3e6eb;
	border-radius: 6px;
	background-color: #e3e6eb;
	overflow: hidden;
}

.apartment-facts__item {
	padding: 14px 16px;
	background-color: #ffffff;
}

.apartment-facts dt {
	margin-bottom: 4px;
	color: #5a6672;
	font-size: 0.72rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.apartment-facts dd {
	margin: 0;
	color: var(--pl-navy);
	font-size: 1.02rem;
	font-weight: 600;
}

/* ---------- Two-column body ---------- */
/*
 * No overflow on this element or its ancestors. `overflow` of anything
 * other than `visible` on an ancestor silently kills position: sticky in
 * the rail — the commonest reason a sticky sidebar "doesn't work", and
 * it fails without any error.
 *
 * align-items: start matters too: the default `stretch` makes the rail
 * full height, and a full-height box has nothing left to scroll past, so
 * sticky never engages.
 */
.apartment-detail__layout {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 348px;
	gap: 54px;
	align-items: start;
	/*
	 * 70px 0 is the theme's standard section rhythm (see .find-your-place
	 * and the blocks around it). This rule had the bottom half only, so
	 * the eyebrow and the sticky enquiry card both sat hard against the
	 * bottom edge of the full-bleed gallery.
	 */
	padding-top: 35px;
	padding-bottom:70px;
}

.apartment-detail__main {
	min-width: 0;
}

.apartment-detail__eyebrow {
	margin-bottom: 7px;
	color: #5a6672;
	font-size: 0.78rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	margin-top: 0;
}

.apartment-detail__heading {
	margin: 0 0 6px;
}

/*
 * 1.5rem is the h4 step on the global scale — this is the only price on
 * the page now that the enquiry card leads with its CTA line instead, so
 * it sits one step under the h1 rather than matching anything else.
 */
.apartment-detail__price {
	margin: 0 0 26px;
	color: var(--pl-navy);
	font-size: 1.5rem;
	font-weight: 600;
}

.apartment-detail__description p {
	margin-bottom: 14px;
	line-height: 1.7;
}

.apartment-detail__section {
	margin-top: 30px;
	padding-top: 26px;
	border-top: 1px solid #e3e6eb;
}

.apartment-detail__section h3 {
	margin: 0 0 14px;
}

/* Two columns of features, since they're short lines and often numerous. */
.apartment-detail__features ul {
	list-style: none;
	margin: 0;
	padding: 0;
	columns: 2;
	column-gap: 34px;
}

.apartment-detail__features li {
	position: relative;
	padding: 6px 0 6px 25px;
	font-size: 0.95rem;
	/* Or a feature can be split down the middle across the column break. */
	break-inside: avoid;
}

.apartment-detail__features li::before {
	content: "";
	position: absolute;
	top: 14px;
	left: 0;
	width: 9px;
	height: 9px;
	border-radius: 50%;
	background-color: var(--pl-navy);
	opacity: 0.3;
}

/* ---------- Letting details ---------- */
.apartment-detail__pairs {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 14px 34px;
	margin: 0;
}

.apartment-detail__pairs dt {
	color: #5a6672;
	font-size: 0.78rem;
	letter-spacing: 0.05em;
	text-transform: uppercase;
}

.apartment-detail__pairs dd {
	margin: 3px 0 0;
	color: var(--pl-navy);
	font-weight: 600;
}

/* ---------- Downloads ---------- */
.apartment-download {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	margin-bottom: 9px;
	padding: 13px 16px;
	border: 1px solid #e3e6eb;
	border-radius: 5px;
	color: var(--pl-navy);
	font-size: 0.95rem;
	text-decoration: none;
	transition: border-color 0.2s ease, background-color 0.2s ease;
}

.apartment-download:hover,
.apartment-download:focus-visible {
	border-color: var(--pl-navy);
	background-color: #f7f9fb;
	text-decoration: none;
}

.apartment-download__meta {
	display: flex;
	align-items: center;
	gap: 10px;
	color: #5a6672;
	font-size: 0.82rem;
	white-space: nowrap;
}

.apartment-download__arrow {
	color: var(--pl-navy);
	font-weight: 700;
}

/* ---------- Sticky enquiry rail ---------- */
.apartment-detail__rail {
	position: sticky;
	/*
	 * Clears the sticky site header rather than sliding under it.
	 * --site-header-height is declared on :root at the top of this file.
	 */
	top: calc(var(--site-header-height, 96px) + 40px);
}

.apartment-cta {
	padding: 22px;
	border: 1px solid #e3e6eb;
	border-radius: 8px;
	background-color: #ffffff;
	box-shadow: 0 2px 14px rgba( 4, 49, 86, 0.07 );
}

/*
 * Spacing only — the global h1..h6 rule supplies Quicksand and navy, and
 * h4 is already 1.5rem, which is the size this was hard-coding.
 */
.apartment-cta__heading {
	margin: 0 0 10px;
	font-weight: 500;
}

/*
 * Supporting line under the CTA heading. #5a6672 is the same muted grey
 * the eyebrow and the facts-strip labels use; size comes from the body
 * default.
 */
.apartment-cta__text {
	margin: 0 0 18px;
	color: #5a6672;
}

.apartment-cta__status {
	display: flex;
	align-items: center;
	gap: 9px;
	margin: 0 0 18px;
	padding: 9px 12px;
	border-radius: 4px;
	background-color: #eef6f0;
	color: #2c6b39;
	font-size: 0.85rem;
	font-weight: 600;
}

.apartment-cta__status--muted {
	background-color: #eef0f4;
	color: #4a5764;
}

.apartment-cta__dot {
	width: 8px;
	height: 8px;
	flex: 0 0 8px;
	border-radius: 50%;
	background-color: #49a05e;
}

.apartment-cta__dot--muted {
	background-color: #8a96a3;
}

.apartment-cta__btn {
	display: block;
	width: 100%;
	margin-bottom: 9px;
	text-align: center;
}

/* ---------- Share ---------- */
/*
 * Deliberately quieter than the two buttons above it: a third full
 * strength button would compete with the enquiry CTA, which is the one
 * the page exists for.
 */
.apartment-share {
	margin-top: 14px;
	padding-top: 14px;
	border-top: 1px solid #e3e6eb;
}

.apartment-share__toggle {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	width: 100%;
	padding: 6px 0;
	border: 0;
	background: none;
	color: var(--pl-navy);
	font-family: inherit;
	font-size: 0.9rem;
	font-weight: 600;
	cursor: pointer;
}

.apartment-share__toggle:hover,
.apartment-share__toggle:focus-visible {
	text-decoration: underline;
}

.apartment-share__icon {
	width: 17px;
	height: 17px;
	flex: 0 0 auto;
}

.apartment-share__panel {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 12px;
}

/*
 * The panel is display:flex, which beats the browser's own
 * [hidden] { display: none } on specificity.
 */
.apartment-share__panel[hidden] {
	display: none;
}

.apartment-share__url {
	flex: 1 1 140px;
	min-width: 0;
	padding: 9px 11px;
	border: 1px solid #c7d0da;
	border-radius: 4px;
	color: #5a6672;
	font-family: inherit;
	font-size: 0.82rem;
}

.apartment-share__copy {
	flex: 0 0 auto;
	padding: 9px 18px;
	font-size: 0.85rem;
}

.apartment-share__status {
	flex: 1 0 100%;
	margin: 0;
	min-height: 1.2em;
	color: #2c6b39;
	font-size: 0.8rem;
	font-weight: 600;
}

.apartment-cta__phone {
	margin: 15px 0 0;
	text-align: center;
	font-weight: 600;
}

.apartment-cta__phone a {
	color: var(--pl-navy);
}

.apartment-cta__ref {
	margin: 10px 0 0;
	text-align: center;
	color: #5a6672;
	font-size: 0.78rem;
}

/* ---------- Narrow screens ---------- */
@media (max-width: 991px) {
	/*
	 * One column, and the rail stops being sticky — pinning a card in a
	 * single-column flow just parks it over the content below.
	 */
	.apartment-detail__layout {
		grid-template-columns: minmax(0, 1fr);
		gap: 34px;
		padding-top: 40px;
		padding-bottom:50px;
	}

	.apartment-detail__rail {
		position: static;
	}

	.apartment-facts {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	/*
	 * An odd number of facts leaves the second half of the last row
	 * empty, and because the dividing lines are the container's
	 * background showing through 1px gaps, that empty cell reads as a
	 * grey block rather than as nothing.
	 *
	 * :last-child:nth-child(odd) is true only when the final item sits
	 * in an odd position — i.e. when it is alone on its row in a
	 * two-column grid. Stated that way it stays correct at three, five
	 * or seven facts, with no count baked in.
	 */
	.apartment-facts__item:last-child:nth-child(odd) {
		grid-column: 1 / -1;
	}

	.apartment-detail__features ul {
		columns: 1;
	}
}

@media (max-width: 600px) {
	.apartment-detail__pairs {
		grid-template-columns: minmax(0, 1fr);
	}
}

/*
 * ---------- Apartment gallery (slider + thumbnails + lightbox) ----------
 * Markup in template-parts/apartment-detail.php, behaviour in
 * assets/js/apartment-gallery.js. Replaces the old static 4-up grid.
 *
 * Embla moves .__container by transform; the viewport is what clips. So
 * overflow belongs on the viewport and nowhere else — putting it on an
 * ancestor instead is what makes a carousel show all its slides at once
 * for a frame before the script runs.
 */
.apartment-gallery {
	position: relative;
}

/*
 * Mosaic: one large tile spanning two rows on the left, two stacked on
 * the right. Explicit rows rather than aspect-ratio on the tiles, so the
 * two small tiles always add up to exactly the height of the large one —
 * with aspect-ratio they drift apart as the column width changes and the
 * right-hand edge stops lining up.
 */
.apartment-gallery__mosaic {
	position: relative;
	display: grid;
	grid-template-columns: 2fr 1fr;
	/*
	 * Height on the grid, rows as fractions — NOT clamp() on each row.
	 * Sizing the rows individually lets each one round on its own, and
	 * the large tile ends up a pixel short of the two stacked beside it,
	 * leaving a hairline along the bottom edge. One total, divided, keeps
	 * both columns exactly equal at every width. Measured: 397px vs 398px
	 * before, identical after.
	 */
	grid-template-rows: repeat(2, 1fr);
	height: clamp(268px, 38vw, 468px);
	gap: 8px;
}

.apartment-gallery__mosaic > .apartment-gallery__tile:first-child {
	grid-row: span 2;
}

/* One or two images: no stack to build, so the large tile takes it all. */
.apartment-gallery__mosaic--1 {
	grid-template-columns: 1fr;
}

.apartment-gallery__mosaic--2 {
	grid-template-columns: 2fr 1fr;
	grid-template-rows: 1fr;
}

.apartment-gallery__mosaic--2 > .apartment-gallery__tile:first-child {
	grid-row: span 1;
}

.apartment-gallery__tile {
	position: relative;
	display: block;
	overflow: hidden;
	padding: 0;
	border: 0;
	background-color: #e7eaee;
	cursor: pointer;
}

.apartment-gallery__tile img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.4s ease;
}

.apartment-gallery__tile:hover img,
.apartment-gallery__tile:focus-visible img {
	transform: scale(1.03);
}

.apartment-gallery__tile:focus-visible {
	outline: 3px solid var(--pl-navy);
	outline-offset: -3px;
}

/* ---------- Video tile ---------- */
.apartment-gallery__play {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 72px;
	height: 72px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background-color: rgba(4, 49, 86, 0.82);
	color: #ffffff;
	pointer-events: none;
}

.apartment-gallery__play svg {
	width: 34px;
	height: 34px;
	margin-left: 3px; /* optical centring: the triangle's mass sits left */
}

/*
 * The play badge is display:flex, which beats the browser's own
 * [hidden] { display: none } on specificity — so JS toggling `hidden`
 * would do nothing without this. Same trap as .apartment-lightbox[hidden].
 */
.apartment-gallery__play[hidden],
.apartment-gallery__tile[hidden],
.apartment-gallery__nav[hidden] {
	display: none;
}

/* ---------- Mosaic navigation ---------- */
/*
 * Positioned against the large tile's column rather than the grid, so the
 * arrows never float over the two previews on the right. 66% matches the
 * 2fr of 2fr+1fr; the 8px is half the grid gap.
 */
.apartment-gallery__nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 2;
	width: 44px;
	height: 44px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: 0;
	border-radius: 50%;
	background-color: rgba(255, 255, 255, 0.92);
	color: var(--pl-navy);
	font-size: 26px;
	line-height: 1;
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.apartment-gallery__nav:hover,
.apartment-gallery__nav:focus-visible {
	background-color: #ffffff;
}

.apartment-gallery__nav--prev {
	left: 14px;
}

.apartment-gallery__nav--next {
	left: calc(66.666% - 58px);
}

/*
 * Tiles crossfade on index change rather than cutting. Short enough not
 * to lag a held-down arrow key.
 */
.apartment-gallery__tile img {
	transition: transform 0.4s ease, opacity 0.18s ease;
}

/* ---------- Count badge ---------- */
.apartment-gallery__badge {
	position: absolute;
	right: 16px;
	bottom: 16px;
	z-index: 2;
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 14px;
	border: 0;
	border-radius: 8px;
	background-color: #ffffff;
	box-shadow: 0 2px 10px rgba(4, 49, 86, 0.22);
	color: var(--pl-navy);
	font-size: 0.9375rem;
	font-weight: 600;
	line-height: 1;
	cursor: pointer;
}

.apartment-gallery__badge-group {
	display: flex;
	align-items: center;
	gap: 6px;
}

.apartment-gallery__badge-icon {
	width: 19px;
	height: 19px;
}

.apartment-gallery__badge-divider {
	width: 1px;
	height: 18px;
	background-color: #d4dae1;
}

/* ---------- Lightbox ---------- */
.apartment-lightbox {
	position: fixed;
	inset: 0;
	z-index: 2000;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	background-color: rgba(2, 16, 28, 0.94);
}

/*
 * [hidden] needs the explicit display:none because the rule above sets
 * display:flex, and a plain attribute selector loses to a class selector
 * on specificity.
 */
.apartment-lightbox[hidden] {
	display: none;
}

/*
 * Scroll lock. Without this the page behind the overlay scrolls under
 * the visitor's finger on touch, and they close the lightbox to find
 * themselves somewhere else entirely.
 */
body.has-lightbox-open {
	overflow: hidden;
}

.apartment-lightbox__stage {
	position: relative;
	width: 100%;
	max-width: 1200px;
	padding: 0 16px;
}

.apartment-lightbox__viewport {
	overflow: hidden;
}

.apartment-lightbox__container {
	display: flex;
	touch-action: pan-y pinch-zoom;
}

.apartment-lightbox__slide {
	flex: 0 0 100%;
	min-width: 0;
	display: flex;
	align-items: center;
	justify-content: center;
}

.apartment-lightbox__slide img {
	display: block;
	max-width: 100%;
	/*
	 * Leaves room for the close button above and the counter below, so a
	 * portrait photograph can't push either off screen.
	 */
	max-height: 78vh;
	object-fit: contain;
}

.apartment-lightbox__close {
	position: absolute;
	top: 16px;
	right: 20px;
	width: 44px;
	height: 44px;
	border: 0;
	border-radius: 50%;
	background-color: rgba(255, 255, 255, 0.14);
	color: #ffffff;
	font-size: 28px;
	line-height: 1;
	cursor: pointer;
}

.apartment-lightbox__close:hover,
.apartment-lightbox__close:focus-visible {
	background-color: rgba(255, 255, 255, 0.28);
}

.apartment-lightbox__arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 2;
	width: 52px;
	height: 52px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: 0;
	border-radius: 50%;
	background-color: rgba(255, 255, 255, 0.92);
	color: var(--pl-navy);
	font-size: 30px;
	line-height: 1;
	cursor: pointer;
}

.apartment-lightbox__arrow--prev {
	left: 24px;
}

.apartment-lightbox__arrow--next {
	right: 24px;
}

.apartment-lightbox__counter {
	margin: 20px 0 0;
	color: #ffffff;
	font-size: 0.875rem;
}

/* ---------- Lightbox video slide ---------- */
.apartment-lightbox__slide--video {
	position: relative;
	width: 100%;
}

.apartment-lightbox__play {
	position: relative;
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	background-color: #0b2237;
	cursor: pointer;
}

.apartment-lightbox__play img {
	display: block;
	width: 100%;
	max-height: 78vh;
	object-fit: contain;
}

.apartment-lightbox__play-icon {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 84px;
	height: 84px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background-color: rgba(4, 49, 86, 0.86);
	color: #ffffff;
}

.apartment-lightbox__play-icon svg {
	width: 40px;
	height: 40px;
	margin-left: 4px;
}

/*
 * Once playing, the iframe replaces the poster visually. 16:9 is fixed
 * here rather than left to the embed: the iframe ACF returns carries
 * hardcoded width/height attributes, and without a ratio box the player
 * renders at whatever those say instead of filling the slide.
 */
.apartment-lightbox__slide--video.is-playing .apartment-lightbox__play {
	display: none;
}

.apartment-lightbox__slide--video iframe {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	max-height: 78vh;
	border: 0;
}

@media (max-width: 782px) {

	/*
	 * Mosaic becomes a single hero on a phone. Three tiles across a
	 * 375px screen makes the two small ones about 50px wide — too small
	 * to read, and they only push the detail further down the page. The
	 * badge still says how many more there are.
	 */
	.apartment-gallery__mosaic,
	.apartment-gallery__mosaic--2 {
		grid-template-columns: 1fr;
		grid-template-rows: 1fr;
		height: clamp(220px, 58vw, 300px);
	}

	.apartment-gallery__mosaic > .apartment-gallery__tile:first-child {
		grid-row: span 1;
	}

	.apartment-gallery__mosaic > .apartment-gallery__tile:not(:first-child) {
		display: none;
	}

	/*
	 * One column on a phone, so the next arrow goes back to the right
	 * edge — the 66% offset it uses on desktop would put it in the middle
	 * of the image.
	 */
	.apartment-gallery__nav--next {
		left: auto;
		right: 14px;
	}

	.apartment-gallery__nav {
		width: 38px;
		height: 38px;
		font-size: 22px;
	}

	.apartment-gallery__play {
		width: 58px;
		height: 58px;
	}

	.apartment-gallery__play svg {
		width: 26px;
		height: 26px;
	}

	.apartment-gallery__badge {
		right: 10px;
		bottom: 10px;
		padding: 7px 11px;
		font-size: 0.875rem;
	}

	.apartment-lightbox__arrow {
		width: 42px;
		height: 42px;
		font-size: 24px;
	}

	.apartment-lightbox__arrow--prev {
		left: 6px;
	}

	.apartment-lightbox__arrow--next {
		right: 6px;
	}

	.apartment-lightbox__play-icon {
		width: 64px;
		height: 64px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.apartment-gallery__tile img {
		transition: none;
	}

	.apartment-gallery__tile:hover img,
	.apartment-gallery__tile:focus-visible img {
		transform: none;
	}
}

/*
 * ---------- Callout (ACF block) ----------
 * Mobile: a plain stacked layout — full image, then the card in normal
 * flow below it, no overlap.
 *
 * Desktop (≥992px): the card overlaps the image on the right or left.
 * .callout__image switches to an absolutely-positioned background layer
 * (inset:0) behind .callout__container, so the SECTION's height is
 * driven by the card's own content — .callout__container sets a
 * comfortable min-height and vertical padding, and if the card's text
 * ever needs more room than that, the container (and the image behind
 * it) simply grows to fit, instead of the card overflowing past a
 * shorter, fixed-height image.
 */
.callout {
	position: relative;
}

.callout__image {
	width: 100%;
	height: clamp(280px, 60vw, 420px);
	overflow: hidden;
}

.callout__image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.callout__card-wrap {
	width: 100%;
}

.callout__card {
	background: var(--pl-navy);
	color: #ffffff;
	padding: 40px 24px;
}

/* Font-size set explicitly so the "Heading tag" field (h2/h3/h4) only
   changes the semantic level, never the visual size. */
.callout__heading {
	color: #ffffff;
	/*font-size: 2.5rem;*/
	font-weight: 500;
	margin-bottom: 20px;
}

.callout__intro {
	font-size: 1.125rem;
	line-height: 1.5;
	margin-bottom: 20px;
}

.callout__body {
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-size: 0.875rem;
	line-height: 1.6;
}

.callout__body p {
	margin: 0 0 14px;
}

.callout__body p:last-child {
	margin-bottom: 0;
}

@media (min-width: 992px) {
	.callout__image {
		position: absolute;
		inset: 0;
		height: 100%;
	}

	.callout__container {
		position: relative;
		z-index: 1;
		display: flex;
		align-items: center;
		min-height: clamp(400px, 48vw, 620px);
		padding-top: 60px;
		padding-bottom: 60px;
	}

	.callout__card-wrap {
		width: auto;
	}

	.callout__card-wrap--right {
		margin-left: auto;
	}

	.callout__card-wrap--left {
		margin-right: auto;
	}

	.callout__card {
		width: 100%;
		max-width: 420px;
		padding: 48px 40px;
		box-shadow: 0 20px 50px rgba(4, 49, 86, 0.25);
	}
}

/*
 * ---------- FAQs (ACF block) ----------
 * Native <details>/<summary> accordion — no JS required. The +/- glyph
 * is pure CSS, swapping off the [open] attribute; the first item is
 * open by default (set in render.php).
 */
.faqs {
	padding: 70px 0;
}

.faqs__heading {
	color: var(--pl-navy);
	margin-bottom: 30px;
}

.faqs__list {
	border-top: 1px solid var(--pl-navy);
}

.faqs__item {
	border-bottom: 1px solid var(--pl-navy);
}

.faqs__question {
	position: relative;
	list-style: none;
	cursor: pointer;
	padding: 18px 40px 18px 0;
	color: var(--pl-navy);
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-weight: 600;
	font-size: 0.9375rem;
}

.faqs__question::-webkit-details-marker {
	display: none;
}

.faqs__question::after {
	content: "+";
	position: absolute;
	right: 4px;
	top: 50%;
	transform: translateY(-50%);
	color: var(--pl-navy);
	font-size: 1.25rem;
	line-height: 1;
}

.faqs__item[open] .faqs__question::after {
	content: "\2212";
}

.faqs__answer {
	padding: 0 40px 18px 0;
	color: var(--pl-navy);
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-size: 0.9375rem;
	line-height: 1.6;
}

.faqs__answer p {
	margin: 0;
}

/*
 * ---------- Photo Grid (ACF block) ----------
 * 3-column grid of photo cards with a centred label — see
 * blocks/photo-grid/render.php. Cards render as <a> when a Link is set,
 * plain <div> otherwise, so both share the same visual treatment.
 */
.photo-grid {
	padding: 70px 0;
}

.photo-grid__heading {
	text-align: center;
	color: var(--pl-navy);
	margin-bottom: 30px;
}

.photo-grid__items {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 24px;
}

.photo-grid__item {
	position: relative;
	display: block;
	overflow: hidden;
	aspect-ratio: 1 / 1;
	color: inherit;
	text-decoration: none;
}

.photo-grid__item-photo {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

.photo-grid__item:hover .photo-grid__item-photo {
	transform: scale(1.06);
}

.photo-grid__item::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: #000000;
	opacity: 0.35;
}

.photo-grid__item::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: var(--pl-navy);
	opacity: 0;
	transition: opacity 0.6s ease;
}

.photo-grid__item:hover::after {
	opacity: 0.15;
}

/*
 * Hidden at every width — the dots only mean anything once
 * photo-grid-carousel.js has added .is-carousel. This rule sat inside
 * the mobile media query, so nothing hid them on desktop and they
 * rendered unstyled under the grid.
 */
.photo-grid__dots {
	display: none;
}

.photo-grid__item-caption {
	position: absolute;
	z-index: 2;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	width: 100%;
	padding: 0 16px;
	text-align: center;
	color: #ffffff;
}

/*
 * Positioning moved to .photo-grid__item-caption above, so a label and
 * its description centre as a pair. Centring the label alone left it
 * sitting high on the photograph as soon as a description was added.
 */
.photo-grid__item-label {
	display: block;
	font-size: 1.5rem;
	font-weight: 500;
	line-height: 1.3;
}

/* No font-size: it takes the body size, one clear step below the label. */
.photo-grid__item-description {
	display: block;
	margin-top: 8px;
	line-height: 1.5;
}

@media (max-width: 782px) {
	.photo-grid__items {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 560px) {
	.photo-grid__items {
		grid-template-columns: 1fr;
	}
}

/* ---------- Feature split: space below ---------- */
/* The "Space below block" field — see blocks/feature-split/render.php. */
.feature-split--space-reduced {
	padding-bottom: 24px;
}

.feature-split--space-none {
	padding-bottom: 0;
}

/* ---------- Back to top ---------- */
/*
 * Mobile and tablet only. Fixed bottom-right, revealed once the visitor
 * is about a screen down (see assets/js/site-animations.js). Hidden with
 * no JS, where it would do nothing at all.
 *
 * Not shown on desktop: a mouse has a scroll wheel and the keyboard has
 * Home, so the button is just an overlay sitting on top of the content.
 * It earns its place on touch devices, where the page is far longer in
 * screens and there's no equivalent shortcut.
 */
.back-to-top {
	position: fixed;
	right: 24px;
	bottom: 24px;
	z-index: 60;
	width: 46px;
	height: 46px;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	border: 1px solid #ffffff;
	border-radius: 50%;
	background: var(--pl-navy);
	cursor: pointer;
	opacity: 0;
	visibility: hidden;
	transform: translateY(10px);
	transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s,
		background-color 0.2s ease;
}

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

.back-to-top:hover,
.back-to-top:focus-visible {
	background: #ffffff;
}

/* Chevron drawn in CSS rather than shipping an icon for one arrow. */
.back-to-top__arrow {
	display: block;
	width: 10px;
	height: 10px;
	margin-top: 3px;
	border-left: 2px solid #ffffff;
	border-top: 2px solid #ffffff;
	transform: rotate(45deg);
	transition: border-color 0.2s ease;
}

.back-to-top:hover .back-to-top__arrow,
.back-to-top:focus-visible .back-to-top__arrow {
	border-color: var(--pl-navy);
}

.no-js .back-to-top {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.back-to-top {
		transition: opacity 0.25s ease, visibility 0.25s;
		transform: none;
	}
	.back-to-top.is-visible {
		transform: none;
	}
}

/*
 * Desktop: gone entirely. Must stay AFTER the rules above — a media
 * query carries no extra specificity, so with both at (0,1,0) it's
 * source order that decides, and placed earlier this would lose to
 * `.back-to-top.is-visible` the moment the page scrolled.
 */
@media (min-width: 992px) {
	.back-to-top,
	.back-to-top.is-visible {
		display: none;
	}
}

/* ---------- 404 ---------- */
/*
 * Header is solid here (has-solid-header body class — see
 * properties_living_solid_header_body_class() in functions.php), which
 * also reserves the header's height, so this needs no top offset of its
 * own.
 */
.error-404 {
	padding: 70px 0 80px;
	text-align: center;
}

.error-404__code {
	margin: 0 0 8px;
	font-size: clamp(3.5rem, 12vw, 6rem);
	font-weight: 600;
	line-height: 1;
	color: var(--pl-navy);
	opacity: 0.15;
}

.error-404__heading {
	margin: 0 0 16px;
}

.error-404__text {
	max-width: 46ch;
	margin: 0 auto 32px;
	font-size: 1.0625rem;
	line-height: 1.6;
}

.error-404__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 14px;
}

.error-404__locations {
	margin-top: 56px;
	padding-top: 32px;
	border-top: 1px solid #e3e6eb;
}

.error-404__locations-heading {
	font-size: 1.25rem;
	font-weight: 500;
	margin-bottom: 14px;
	color: var(--pl-navy);
}

.error-404__locations ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 10px 28px;
}

.error-404__locations a {
	color: var(--pl-navy);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

@media (max-width: 991px) {
	.error-404 {
		padding: 40px 0 50px;
	}

	.error-404__locations {
		margin-top: 36px;
	}
}

/* ---------- Hero subtext on narrow phones ---------- */
/*
 * The only other .hero-block__subtext rule is inside min-width: 992px
 * (1.875rem), so between 428px and 991px the subtext just inherits the
 * body's 1rem. This lifts it on the narrowest screens.
 */
@media (max-width: 428px) {
	.hero-block__subtext {
		font-size: 1.6rem;
	}
}

/* ---------- Mobile: callout + photo grid ---------- */
@media (max-width: 991px) {
	/*
	 * The navy card runs edge to edge rather than sitting inside the
	 * container's gutters. On a phone those gutters cost ~96px of an
	 * ~390px screen, which is what was forcing the heading to wrap after
	 * three words.
	 */
	.callout__container {
		max-width: none;
		padding-left: 0;
		padding-right: 0;
	}

	.callout__card {
		padding: 32px 24px;
	}

	/*
	 * Photo grid becomes a swipeable carousel.
	 *
	 * Everything that styles this block — the grid, the 1:1 crop, the
	 * scrim and the centred label — lives in the min-width: 992px block
	 * above, so below that the items were unstyled full-width images
	 * stacked end to end. (The max-width 782/560 grid-template-columns
	 * rules never applied: the element isn't display:grid down here.)
	 * So these rules are both the mobile styling and the carousel.
	 *
	 * .is-carousel is added by assets/js/photo-grid-carousel.js once
	 * Embla initialises. Without JS the slides stay stacked and
	 * everything is still reachable.
	 */
	.photo-grid__viewport {
		overflow: hidden;
	}

	.photo-grid__item {
		position: relative;
		display: block;
		overflow: hidden;
		aspect-ratio: 4 / 3;
		color: inherit;
		text-decoration: none;
		margin-bottom: 12px;
	}

	.photo-grid__item-photo {
		position: absolute;
		inset: 0;
		width: 100%;
		height: 100%;
		object-fit: cover;
	}

	.photo-grid__item::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 1;
		background: #000000;
		opacity: 0.35;
	}

	.photo-grid__item-caption {
		position: absolute;
		z-index: 2;
		left: 50%;
		top: 50%;
		transform: translate(-50%, -50%);
		width: 100%;
		padding: 0 16px;
		text-align: center;
		color: #ffffff;
	}

	.photo-grid__item-label {
		display: block;
		font-size: 1.25rem;
		font-weight: 500;
	}

	.photo-grid__item-description {
		display: block;
		margin-top: 6px;
		font-size: 0.9rem;
		line-height: 1.45;
	}

	.photo-grid.is-carousel .photo-grid__items {
		display: flex;
		gap: 12px;
		touch-action: pan-y pinch-zoom;
	}

	/* Slightly under full width so the next card peeks in — the cue that
	   tells people it's swipeable without needing an instruction. */
	.photo-grid.is-carousel .photo-grid__item {
		flex: 0 0 84%;
		min-width: 0;
		margin-bottom: 0;
	}

	.photo-grid.is-carousel .photo-grid__dots {
		display: flex;
		justify-content: center;
		align-items: center;
		gap: 10px;
		margin-top: 18px;
	}

	.photo-grid__dot {
		width: 8px;
		height: 8px;
		padding: 0;
		border: 0;
		border-radius: 50%;
		background: rgba(4, 49, 86, 0.25);
		cursor: pointer;
		transition: background 0.2s ease, transform 0.2s ease;
	}

	.photo-grid__dot.is-active {
		background: var(--pl-navy);
		transform: scale(1.25);
	}

	/* ---------- Find Your Place — mobile carousel ----------
	 * Same pattern as the photo grid above: .is-carousel is added by
	 * assets/js/find-your-place-carousel.js once Embla initialises, so
	 * without JS the cards simply stack as before.
	 *
	 * Used by the block and by "Other apartments here" on apartment
	 * pages, which renders the same markup.
	 */
	.find-your-place-viewport {
		overflow: hidden;
	}

	.find-your-place.is-carousel .find-your-place-cards {
		flex-wrap: nowrap;
		justify-content: flex-start;
		gap: 16px;
		margin-bottom: 0;
		touch-action: pan-y pinch-zoom;
	}

	/* Slightly under full width so the next card peeks in — the cue that
	   tells people it's swipeable without needing an instruction. */
	.find-your-place.is-carousel .find-your-place-card {
		flex: 0 0 84%;
		max-width: 84%;
		min-width: 0;
		margin-bottom: 35px;
	}

	.find-your-place.is-carousel .find-your-place-dots {
		display: flex;
		justify-content: center;
		align-items: center;
		gap: 10px;
		margin-top: 18px;
	}

	.find-your-place-dot {
		width: 8px;
		height: 8px;
		padding: 0;
		border: 0;
		border-radius: 50%;
		background: rgba(4, 49, 86, 0.25);
		cursor: pointer;
		transition: background 0.2s ease, transform 0.2s ease;
	}

	.find-your-place-dot.is-active {
		background: var(--pl-navy);
		transform: scale(1.25);
	}

	/* ---------- Mobile rhythm ----------
	 *
	 * Every block ships `padding: 70px 0`, which was set for desktop. On a
	 * phone that's 140px of empty space between each one — the gaps above
	 * "Is Virtua right for you?", "Where to find Virtua" and the FAQs.
	 * One rule covers all of them rather than nine separate overrides, so
	 * a new block picks up the same rhythm automatically.
	 */
	.intro-text-block,
	.find-your-place,
	.shared-standard-block,
	.feature-split,
	.icon-grid,
	.apartments-grid,
	.faqs,
	.photo-grid,
	.location-map,
	.hubspot-form-block,
	.hubspot-meeting-block {
		padding-top: 40px;
		padding-bottom: 40px;
	}

	/* The editor's own choice still wins over the blanket rule above. */
	.feature-split--space-reduced {
		padding-bottom: 16px;
	}

	.feature-split--space-none {
		padding-bottom: 0;
	}

	/*
	 * Headings inherit a line-height tuned for single-line desktop
	 * display. Once they wrap to three or four lines on a narrow screen
	 * the leading reads as a gap between lines rather than a heading.
	 */
	h1, h2, h3, h4,
	.feature-split__heading,
	.photo-grid__heading,
	.faqs__heading,
	.apartments-grid__heading,
	.callout__heading {
		line-height: 1.15;
	}

	/*
	 * Mobile heading scale. The desktop sizes are tuned for a 1340px
	 * column and are simply too large on a phone — 3rem is 48px, which
	 * on a 375px screen takes most of the width for a two-word title.
	 *
	 * Each step moves down roughly one place on the same scale rather
	 * than being picked individually, so the relationship between the
	 * levels is the one the desktop sizes already establish. Sizes stay
	 * here with the rest of the heading typography; section rules carry
	 * colour and spacing only.
	 *
	 * The hero is unaffected: it sizes its own .line-1/.line-2 spans.
	 */
	h1 {
		font-size: 2.25rem;
	}

	h2 {
		font-size: 1.875rem;
	}

	h3 {
		font-size: 1.5rem;
	}

	h4 {
		font-size: 1.25rem;
	}

	h5 {
		font-size: 1.125rem;
	}

	.back-to-top {
		right: 16px;
		bottom: 16px;
		width: 42px;
		height: 42px;
	}
}

/* ---------- Location Map (ACF block) ---------- */
/*
 * Single-pin, custom-styled map — MapLibre GL JS against a self-hosted
 * style (assets/data/pl-map-style.json), not Google Maps — see
 * blocks/location-map/render.php and assets/js/location-map.js. The pin
 * and its info card are one element (`.location-map__marker`) so hover
 * never crosses a dead zone; `.is-open` (toggled on click/tap) covers
 * touch devices, where hover doesn't apply.
 */
.location-map {
	padding: 70px 0;
}

.location-map__heading {
	text-align: center;
	color: var(--pl-navy);
	margin-bottom: 30px;
}

/*
 * Used by the block and by the apartment detail page, which reads the
 * same field off the location page — see
 * properties_living_get_location_map_data() in functions.php.
 *
 * The heading's 30px margin would double up against this, so it is
 * pulled back when a description follows.
 */
.location-map__heading + .location-map__description {
	margin-top: -18px;
}

.location-map__description {
	max-width: 70ch;
	margin: 0 auto 30px;
	text-align: center;
}

.location-map__description p:last-child {
	margin-bottom: 0;
}

.location-map__canvas {
	position: relative;
	height: clamp(360px, 45vw, 520px);
	border-radius: 4px;
	overflow: hidden;
}

/* MapLibre injects its own canvas/control markup as children of the
   container above — this just keeps our own <template> (inert, never
   rendered) from affecting layout. */
.location-map__canvas template {
	display: none;
}

.location-map__marker {
	position: relative;
	cursor: pointer;
}

.location-map__pin {
	display: block;
	max-width: 70px;
	max-height: 45px;
	width: auto;
	height: auto;
	filter: drop-shadow(0 3px 6px rgba(4, 49, 86, 0.35));
}

.location-map__card {
	position: absolute;
	bottom: calc(100% + 10px);
	left: 50%;
	/* No translateY offset: that was the pre-reveal position. */
	transform: translateX(-50%);
	width: max-content;
	max-width: 260px;
	background: var(--pl-navy);
	color: #ffffff;
	padding: 16px 18px;
	border-radius: 4px;
	box-shadow: 0 12px 30px rgba(4, 49, 86, 0.3);
	/*
	 * Open by default — the card is the point of the map, and hiding it
	 * behind a hover meant it was invisible on touch until tapped and
	 * invisible in a screenshot. The hover/focus/.is-open rules below are
	 * kept so the card still re-asserts itself if anything ever sets the
	 * hidden state again, but nothing hides it now.
	 */
	opacity: 1;
	visibility: visible;
	transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}

/* Small triangle pointing down to the pin. */
.location-map__card::after {
	content: "";
	position: absolute;
	top: 100%;
	left: 50%;
	transform: translateX(-50%);
	border: 7px solid transparent;
	border-top-color: var(--pl-navy);
}

.location-map__marker:hover .location-map__card,
.location-map__marker:focus-within .location-map__card,
.location-map__marker.is-open .location-map__card {
	opacity: 1;
	visibility: visible;
	transform: translateX(-50%) translateY(0);
}

.location-map__card-label {
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
	font-weight: 600;
	font-size: 0.9375rem;
	margin: 0 0 4px;
}

.location-map__card-address {
	font-size: 0.8125rem;
	line-height: 1.5;
	margin: 0 0 10px;
	color: rgba(255, 255, 255, 0.85);
}

.location-map__card-directions {
	display: inline-block;
	font-size: 0.8125rem;
	font-weight: 600;
	color: #ffffff;
	text-decoration: underline;
	text-underline-offset: 2px;
}

.location-map__card-directions:hover {
	color: rgba(255, 255, 255, 0.8);
}

/* MapLibre's own controls (zoom buttons, attribution) — restyled lightly
   so they sit comfortably on the custom map style rather than the
   library's default black-on-white look. */
.location-map .maplibregl-ctrl-group {
	border-radius: 4px;
	box-shadow: 0 4px 12px rgba(4, 49, 86, 0.15);
}

.location-map .maplibregl-ctrl-attrib {
	font-size: 0.6875rem;
	background: rgba(238, 231, 210, 0.85);
}

/* ---------- Location Map: wp-admin editor-only static preview ---------- */
/*
 * Shown instead of the live MapLibre canvas while editing (see render.php's
 * $is_preview branch) — a stylised placeholder graphic plus the pin/card
 * always visible (no hover in the editor), so the block never looks like
 * an empty box. Never appears on the published page.
 */
.location-map__canvas--preview {
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: rgb(238, 231, 210);
	background-size: cover;
	background-position: center;
}

.location-map__marker--preview {
	position: relative;
	pointer-events: none;
}

.location-map__card--preview {
	position: absolute;
	bottom: calc(100% + 10px);
	left: 50%;
	transform: translateX(-50%);
	opacity: 1;
	visibility: visible;
}

.location-map__preview-note {
	position: absolute;
	left: 12px;
	bottom: 12px;
	margin: 0;
	padding: 4px 10px;
	font-size: 0.75rem;
	color: var(--pl-navy);
	background: rgba(255, 255, 255, 0.85);
	border-radius: 3px;
}

@media (max-width: 768px) {
	.location-map__canvas {
		height: clamp(280px, 70vw, 380px);
	}

	.location-map__card {
		max-width: 220px;
	}
}

/* ---------- Footer / contact CTA band ---------- */
.contact-band {
	position: relative;
	min-height: 420px;
	display: flex;
	align-items: center;
	/* Both images come from footer.php as custom properties so the mobile
	   swap can happen in the media query below — see .contact-band there. */
	background-image: var(--contact-band-photo);
	background-size: cover;
	background-position: center;
	background-color: var(--pl-navy-dark);
}

/*
 * Optional mobile crop — the contact_band_photo_mobile field in Site
 * Settings, falling back to the desktop image when it's empty.
 *
 * This has to come AFTER the base rule above, not with the other mobile
 * overrides earlier in the file: a media query adds no specificity, so
 * two .contact-band rules both score (0,1,0) and source order decides.
 * Placed earlier, the base rule would win and the mobile image would
 * silently never load.
 *
 * 768px matches the breakpoint the rest of the contact band already
 * switches on, below.
 */
@media (max-width: 768px) {
	.contact-band {
		background-image: var(--contact-band-photo-mobile, var(--contact-band-photo));
	}
}

/*.contact-band::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--pl-navy);
	opacity: 0.3;
}*/

.contact-band__inner {
	position: relative;
	z-index: 2;
	width: var(--pl-container);
	margin: 0 auto;
	padding: 0 var(--pl-container-padding);
}

/*
 * "contact us" in the Sketch source runs as two distinct sizes on one
 * heading — "contact" at 80px, "us" at 48px, both Quicksand SemiBold.
 * footer.php splits the ACF heading text on the first space so any
 * editor-entered heading gets the same big-word/small-word treatment.
 */
.contact-band__heading {
	font-weight: 600;
	line-height: 1.1;
	margin-bottom: 50px;
	position: relative;
}

.contact-band__heading-big,
.contact-band__heading-small {
	color: #ffffff;
}

.contact-band__heading-big {
	font-size: clamp(2.5rem, 6vw, 5rem);
}

.contact-band__heading-small {
	font-size: clamp(1.75rem, 3.5vw, 3rem);
}

.contact-band__buttons {
	display: flex;
	gap: 16px;
	flex-wrap: wrap;
}

/* "Make an enquiry" / "Contact us" CTAs: NotoSans-Medium 24px, sentence
   case — confirmed from the Sketch source (distinct from the smaller
   uppercase .btn treatment used elsewhere, e.g. header). */
.contact-band__buttons .btn {
	font-size: 1.5rem;
	font-weight: 500;
	text-transform: none;
	letter-spacing: normal;
	padding: 0.6rem 1.5rem;
}

/*
 * The footer's navy panel is INSET, not full-bleed — confirmed from the
 * Sketch source (FTRv1_LANDING symbol sits inset within its artboard,
 * white showing around it). .site-footer is just a plain white-page
 * wrapper that gives the panel room to breathe; .site-footer__inner is
 * the actual navy card, capped at the site's normal container width.
 */
.site-footer {
	background: #ffffff;
	padding: 40px 0;
}

.site-footer__inner {
	max-width: var(--pl-container);
	margin: 0 auto;
	background: var(--pl-navy);
	color: #ffffff;
	padding: 56px var(--pl-container-padding) 32px;
}

.site-footer a {
	color: #ffffff;
}

.site-footer__top {
	display: flex;
	justify-content: space-between;
	flex-wrap: nowrap;
	gap: 1.5rem;
	margin-bottom: 40px;
}

/*
 * "Let's discuss your requirements" runs as 3 distinct sizes in the
 * Sketch source (FTRv1_LANDING symbol) — "Let's" ~44px, "discuss"
 * emphasised at ~90px, "your requirements" ~60px, all Quicksand —
 * matching the same big/small-word treatment used for .contact-band__heading.
 * footer.php splits the heading text into 3 parts to apply this.
 */
.site-footer__discuss h2 {
	font-weight: 500;
	line-height: 0.8;
	margin-bottom: 30px;
}

.site-footer__discuss-word1,
.site-footer__discuss-word2,
.site-footer__discuss-rest {
	color: #ffffff;
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
}

.site-footer__discuss-word1 {
	font-size: clamp(1.75rem, 3.5vw, 2.75rem);
	font-weight: 400;
}

.site-footer__discuss-word2 {
	font-size: clamp(3.5rem, 8vw, 5.625rem);
}

.site-footer__discuss-rest {
	font-size: clamp(2.25rem, 5vw, 3.75rem);
	font-weight: 400;
	margin-left: 65px;
}

.site-footer__contact {
	display: flex;
  justify-content: space-between;
  align-items: end;
  flex-direction: column;
}

.site-footer__contact img {
	width: 280px;
	margin-left: auto;
	margin-bottom: 16px;
}

/* "From [ProperTies Living logo]" lockup shown under a location's own
   footer logo. Overrides the generic .site-footer__contact img rule
   above (which is meant for the main, full-width logo) so the mark
   here stays small and reads as a subordinate line, not a second logo. */
.footer-logo {
	margin-bottom: 16px;
}

.footer-logo img {
	margin-bottom: 0;
}

.footer-logo__from {
	display: flex;
	align-items: baseline;
	justify-content: flex-end;
	gap: 8px;
	margin-top: 12px;
}

.footer-logo__from-text {
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
	font-size: 0.75rem;
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: #ffffff;
}

.footer-logo__from img {
	width: 195px !important;
	margin-bottom: 0;
	margin-left: 0;
}

.site-footer__phone {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 8px;
	font-size: 1.5rem;
	margin: 0 0 4px;
}

.site-footer__contact .site-footer__phone-icon {
	width: 20px;
	height: 20px;
	margin-bottom: 0;
}

.site-footer__address {
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	font-weight: 400;
	margin: 0;
}

.site-footer__separator {
	border: none;
	border-top: 1px solid rgba(255, 255, 255, 1);
	margin-top: 0;
	margin-bottom: 24px;
}

/*
 * Two real columns (5 links, then 4 — matches the Sketch source exactly,
 * not 3 even columns). Columns take only the width their content needs
 * rather than stretching to fill the row, with a gutter-width gap
 * between them; the icons group is pinned to the far right of the same
 * row via margin-left:auto rather than being a 3rd flex-grow column.
 */
.site-footer__columns {
	display: flex;
	align-items: flex-start;
	flex-wrap: wrap;
	gap: var(--pl-gutter);
	margin-bottom: 15px;
}

.site-footer__col {
	flex: 0 1 260px;
}

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

.site-footer__col li {
	font-size: 0.9375rem;
}

/*
 * Right-hand stack: Login/social, then the accreditation logos, then the
 * copyright, each right-aligned under the one above. margin-left: auto
 * moves the whole group to the right edge of the flex row, which is what
 * .site-footer__icons used to do on its own.
 */
.site-footer__end {
	margin-left: auto;
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 20px;
	text-align: right;
	justify-content: space-between;
  	min-height: 102px;
  	max-width: 670px;
}

/* Own row above the nav columns, left-aligned under the separator. */
.site-footer__icons {
	display: flex;
	align-items: center;
	gap: 16px;
	margin-bottom: 24px;
}

/* Footer Login button — .btn base needs flex to centre the mask icon. */
/*
 * Footer Login — solid white with a navy label, emptying to a white
 * outline on hover. The reverse of .btn-outline-white above, so the two
 * footer buttons trade states rather than both filling on hover.
 *
 * Styled here rather than as a shared variant because it's the only
 * button using this pairing. The icon needs no colour rules of its own:
 * it's a .mask-icon painted with currentColor, so it follows the label
 * navy -> white automatically.
 */
.site-footer__login {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	align-self: flex-end;
	padding: 0.4rem 1rem;
	margin-bottom: 16px;
	background: #ffffff;
	color: var(--pl-navy)!important;
	border-color: #ffffff;
}

.site-footer__login:hover,
.site-footer__login:focus {
	background: transparent;
	color: #ffffff!important;
	border-color: #ffffff;
}

.site-footer__login .mask-icon {
	width: 18px;
	height: 18px;
	flex: none;
}

.site-footer__icon {display: flex; gap: 10px;}

.site-footer__icon img {
	width: 20px;
	height: 20px;
	display: block;
}

/*
 * Accreditation logos (Site Settings → Accreditations). Their own
 * full-width row so the strip still reads properly if more memberships
 * are added, with the copyright tucked in close underneath rather than
 * sitting on a line of its own further down.
 *
 * Heights are normalised rather than widths: the supplied logos are a
 * mix of wide wordmarks and tall stacked marks, so matching width would
 * leave them looking wildly different sizes.
 */
.site-footer__accreditations {
	list-style: none;
	/* Separates the logo row from the Login button above it. The parent
	   .site-footer__end is a flex column with its own gap, so this is
	   additional to that rather than instead of it. Applies on every
	   footer — the markup is shared between the main site and the
	   location sub-brands. */
	margin: 24px 0 0;
	padding: 0;
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 20px 40px;
}

.site-footer__accreditation img {
	display: block;
	width: auto;
	height: 46px;
	max-width: 110px;
	/* object-fit matters for raster logos that aren't tightly cropped. */
	object-fit: contain;
}

.site-footer__accreditation a {
	display: block;
	transition: opacity 0.2s ease;
}

.site-footer__accreditation a:hover,
.site-footer__accreditation a:focus {
	opacity: 0.75;
}

.site-footer__copyright {
	margin: 0;
	text-align: right;
	font-size: 0.8rem
}

.placeholder-note {
	font-size: 0.75rem;
	color: #b91c1c;
	background: #fff1f0;
	border: 1px dashed #f2b8b5;
	padding: 0.5rem 0.75rem;
	display: inline-block;
}

/*Media Queries*/

@media (min-width: 1340px) {
	/* --hero-line1-left is set inline per hero block instance from the
	   "Heading — thin line position (desktop)" ACF field, since this
	   differs per page — falls back to -240px if that field is empty. */
	.hero-block__heading .line-1 {position: absolute; left: var(--hero-line1-left, -240px); top: -45px;}
	.contact-band__heading-small {position: absolute; bottom: -20px; left: 280px;}
}

@media (min-width: 1200px) {
	.site-header__logo { width: 352px;}
	.site-header.is-scrolled .site-header__logo { width: 300px;}
}

/*
 * Mobile header (below 992px): the desktop's fixed, transparent-then-
 * white-on-scroll header is replaced with a plain white bar that
 * scrolls away with the page — not position:fixed, so it's never
 * pinned/sticky while scrolling — plus a burger menu replacing the
 * inline search/phone/login/Locations/register row, which becomes a
 * toggled dropdown panel.
 */
@media (max-width: 991px) {

	:root {
		/*--pl-container: 1340px;
		--pl-grid-columns: 12;
		--pl-gutter: 27px;
		--pl-column: 84.7px;*/
		--pl-container-padding: 24px;
	}
	/* Forced solid white on every page at mobile widths — the transparent-
	   overlay/scroll-hover behaviour is a desktop-only treatment. */
	.site-header {
		position: relative;
		background-color: #ffffff !important;
		color: var(--pl-navy) !important;
		animation: none;
		box-shadow: none;
	}

	/* Header no longer overlays content (it's in normal flow, not
	   fixed), so no page needs top padding reserved for it. */
	body {
		padding-top: 0;
	}

	/* Location bar also drops out of fixed positioning at mobile widths,
	   stacking in normal flow above the (also non-fixed) header — same
	   treatment as .site-header just above. */
	.site-header-location-bar {
		position: relative;
		height: auto;
		padding: 8px 24px;
	}

	body.has-location-header .site-header {
		top: 0;
	}

	body.has-location-header {
		padding-top: 0;
	}

	body.has-solid-header.has-location-header {
		padding-top: 0;
	}

	.hero-block__inner {
		padding-top: 60px;
	}

	.site-header__burger {
		display: flex;
	}

	/* The desktop white/blue logo crossfade is keyed to scroll/hover/
	   dropdown-open state, none of which apply once the header is
	   forced solid white here — so force the blue logo unconditionally
	   too, on every page including home. */
	.site-header__logo-img--white {
		opacity: 0 !important;
	}

	.site-header__logo-img--blue {
		opacity: 1 !important;
	}

	.site-header__right {
		display: none;
		position: absolute;
		z-index: 40;
		top: 100%;
		left: 0;
		right: 0;
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		background: #ffffff;
		color: var(--pl-navy);
		box-shadow: 0 10px 30px rgba(4, 49, 86, 0.15);
		padding: 8px 24px 24px;
	}

	.site-header__right.is-open {
		display: flex;
	}

	.site-header__search,
	.site-header__icon-link {
		padding: 12px 0;
		border-bottom: 1px solid #eceef0;
	}

	.site-header__nav {
		border-bottom: 1px solid #eceef0;
	}

	.site-header__custom-nav-list {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
	}

	.site-header__custom-nav-list a {
		display: block;
		padding: 12px 0;
		border-bottom: 1px solid #eceef0;
	}

	/*
	 * Same padding as the links above, so a row with a dropdown is the
	 * same height as one without. The desktop rule for this selector is
	 * more specific than the generic .site-header__nav-toggle mobile
	 * padding, so without this the toggle lost its 12px top inset and
	 * sat tight against the divider.
	 *
	 * 4px at the bottom rather than 12px because `> li > a` gives the
	 * links a 4px bottom inset for their hover underline; matching it
	 * keeps the two baselines level.
	 */
	.site-header__custom-nav-list .site-header__nav-toggle {
		padding: 12px 0 4px;
	}

	/* Sub-menus sit inline and always open on mobile (no hover-reveal),
	   so the desktop "has children" chevron isn't needed here. */
	.site-header__custom-nav-list > li.menu-item-has-children > a::after {
		display: none;
	}

	/* No hover on touch — sub-menus sit inline, always open, indented
	   under their parent, instead of a hover-revealed card. */
	.site-header__custom-nav-list .sub-menu {
		position: static;
		width: auto;
		max-width: none;
		opacity: 1;
		visibility: visible;
		transform: none;
		flex-direction: column;
		justify-content: flex-start;
		gap: 0;
		padding: 0 0 0 16px;
		box-shadow: none;
	}

	.site-header__custom-nav-list .sub-menu a {
		display: block;
		padding: 12px 0;
		border-bottom: 1px solid #eceef0;
	}

	.site-header__custom-nav-list .sub-menu a::before {
		display: none;
	}

	.site-header__nav-toggle {
		width: 100%;
		justify-content: space-between;
		padding: 12px 0;
	}

	.site-header__dropdown {
		display: none;
		position: static;
		left: auto;
		width: auto;
		max-width: none;
		transform: none;
		box-shadow: none;
		min-width: 0;
		margin: 0 0 8px;
		padding: 0 0 8px 12px;
	}

	.site-header__dropdown.is-open {
		display: block;
	}


	/* Mega-menu cards collapse to a plain thumbnail list inside the
	   existing mobile accordion — no hover state to design for here. */
	.site-header__mega {
		flex-direction: column;
		gap: 0;
	}

	/* The panel's own "Locations" heading duplicates the toggle button
	   directly above it in the accordion. */
	.site-header__dropdown .container-narrow {
		display: none;
	}

	/* A centred card rather than the old 56x44 thumbnail row — with only
	   one or two locations a small left-aligned thumbnail read as an
	   afterthought rather than the main navigation choice. */
	.site-header__dropdown .site-header__mega.container .site-header__mega-card {border-bottom: none;}

	.site-header__mega-card {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 10px;
		/* Undoes the desktop flex sizing — full width in the accordion. */
		flex: 0 0 auto;
		width: 100%;
		max-width: 100%;
		padding: 4px 8px 16px;
		text-align: center;
	}

	.site-header__mega-card-photo {
		width: 100%;
		max-width: 280px;
		height: 160px;
		flex: 0 0 auto;
		margin: 0 auto;
	}

	.site-header__mega-card-name {
		margin-top: 0;
		font-size: 1.25rem;
	}

	/* The register button always sits on the panel's white background
	   here, regardless of home/scrolled state, so force the solid-navy
	   treatment rather than leaving it keyed to desktop-only states. */
	.site-header__right .btn.btn-white {
		background: var(--pl-navy) !important;
		color: #ffffff !important;
		border-color: var(--pl-navy) !important;
		width: 100%;
		text-align: center;
		margin-top: 12px;
	}

	.site-footer {
		padding: 0 0;
	}
}

@media (max-width: 782px) {
	.site-header__right {
		gap: 12px;
	}
	/*.site-header__icon-link span {
		padding-top: 120px;
	}*/
	.shared-standard-list {
		column-count: 1;
	}

	.site-footer__top {
	flex-wrap: wrap;
	}

	.site-footer__contact {
		text-align: left;
		align-items: start;
	}
	.site-footer__contact img {
		margin-left: 0;
	}
	.site-footer__phone {
		justify-content: flex-start;
	}

	.site-footer__discuss-rest {
		margin-left: 0;
	}

	.site-footer__columns { gap: 0;}
	.site-footer__icons {margin-left: 0; margin-top: 0; margin-bottom: 18px;}
	.site-footer__copyright {text-align: left;}

	/* The right-hand stack goes back to the left edge with everything else. */
	.site-footer__end {
		margin-left: 0;
		align-items: flex-start;
		text-align: left;
		gap: 16px;
	}

	/* Tighter gaps and smaller marks so four logos don't dominate the footer. */
	.site-footer__accreditations {
		justify-content: flex-start;
		gap: 18px 28px;
		margin-top: 4px;
	}
	.site-footer__accreditation img {
		height: 36px;
		max-width: 120px;
	}
}

/* ---------- PEX Customer App pages (App dashboard template) ---------- */
/*
 * PEX widget pages skip the site's header/nav and the full footer (see
 * header.php / footer.php `$is_pex_app_page`) so PEX's own UI isn't
 * competing with our site chrome — this cuts the footer down to a bare
 * copyright line.
 */
.site-footer--pex-app {
	padding: 24px 0;
}
.site-footer--pex-app .site-footer__copyright {
	text-align: center;
}

/* ---------- HubSpot Form (ACF block) ---------- */
/*
 * Styles HubSpot's "raw HTML form" markup (rendered by the
 * developer/{portalId}.js script into the .hs-form-html target div —
 * see blocks/hubspot-form/render.php). As of the account's current
 * HubSpot version this renders via their newer "Forms Component"
 * system, whose class names use an "hsfc-" prefix (.hsfc-Form,
 * .hsfc-TextInput, .hsfc-Button, etc.) rather than the older
 * .hs-form/.hs-input naming — these selectors target that markup as
 * observed on the live Watford register-interest form. If HubSpot
 * changes these class names again the form will still work, just fall
 * back to their default styling until this is updated.
 */
.hubspot-form-block {
	padding: 70px 0;
}

.hubspot-form-block__heading {
	text-align: center;
	color: var(--pl-navy);
	margin-bottom: 30px;
}

.hubspot-form-block__preview {
	text-align: center;
	color: #8a8f9c;
	padding: 24px;
	border: 1px dashed #c9cdd6;
	border-radius: 4px;
}

.hubspot-form .hsfc-Form {
	font-family: "Noto Sans", "Helvetica Neue", Arial, sans-serif;
	color: var(--pl-navy);
}

.hsfc-FormWrapper .hsfc-Form .hsfc-Step {border-radius: 0;}

/* HubSpot's default single-step progress bar reads oddly on a
   one-step form — hide it rather than leave their brand-yellow fill. */
.hubspot-form .hsfc-ProgressBar {
	display: none;
}

.hubspot-form .hsfc-Row {
	margin-bottom: 20px;
}

.hubspot-form .hsfc-FieldLabel {
	display: block;
	font-weight: 500;
	font-size: 0.9375rem;
	margin-bottom: 6px;
	color: var(--pl-navy);
}

.hubspot-form .hsfc-FieldLabel__RequiredIndicator {
	color: #b3261e;
}

/*
 * !important throughout this rule: HubSpot injects its own stylesheet
 * for these fields (selector "[data-hsfc-id=\"Renderer\"] .hsfc-*")
 * after ours, at matching specificity, so ties go to theirs unless we
 * force it — same reasoning as the .btn-white:hover override elsewhere
 * in this file.
 */
.hubspot-form .hsfc-TextInput,
.hubspot-form .hsfc-TextareaInput,
.hubspot-form .hsfc-DropdownInput,
.hubspot-form .hsfc-PhoneInput {
	width: 100% !important;
	font-family: inherit !important;
	font-size: 1rem !important;
	/*padding: 0.65rem 0.9rem !important;*/
	border-color: #c9cdd6!important;
	border-radius: 0 !important;
	background: #ffffff !important;
	color: var(--pl-navy) !important;
	transition: border-color 0.2s ease;
}

.hubspot-form .hsfc-TextInput:focus,
.hubspot-form .hsfc-TextareaInput:focus,
.hubspot-form .hsfc-DropdownInput:focus,
.hubspot-form .hsfc-PhoneInput:focus {
	outline: none;
	border-color: var(--pl-navy) !important;
}

.hubspot-form .hsfc-DropdownOptions {
	border: 1px solid #c9cdd6 !important;
	border-radius: 0 !important;
	background: #ffffff !important;
}

/*
 * The dropdown and phone fields each nest a second bordered/rounded
 * element inside the outer box already styled above (a hidden
 * "hsfc-TextInput--button" search input inside the dropdown; a
 * "FlagAndCaret" capsule inside the phone field) — left alone these
 * read as a double border / stray rounded corner. Strip the inner
 * one so only the single outer box shows, with a thin divider line
 * where the phone flag meets the number input.
 */
.hubspot-form .hsfc-DropdownInput .hsfc-TextInput,
.hubspot-form .hsfc-PhoneInput .hsfc-TextInput {
	/*border: none !important;*/
	background: transparent !important;
}

.hubspot-form .hsfc-PhoneInput__FlagAndCaret {
	border: none !important;
	border-radius: 0 !important;
	background: transparent !important;
	border-right: 1px solid #c9cdd6 !important;
}

.hubspot-form .hsfc-DropdownOptions__List__ListItem--selected {
	color: var(--pl-navy);
	font-weight: 500;
}

.hubspot-form .hsfc-CheckboxField {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	font-size: 0.875rem;
	font-weight: 400;
}

.hubspot-form .hsfc-DataPrivacyField,
.hubspot-form .hsfc-RichText {
	font-size: 0.8125rem;
	color: #6b7280;
}

.hubspot-form .hsfc-NavigationRow {
	margin-top: 10px;
}

/* Matches .btn.btn-navy exactly (see the base button styles near the
   top of this file) so the submit button reads as the same button used
   everywhere else on the site, not a HubSpot-styled one-off. HubSpot
   renders this as a real <button>, not an <input type="submit">. */
.hubspot-form button.hsfc-Button {
	display: inline-block;
	font-family: "Quicksand", "Helvetica Neue", Arial, sans-serif;
	font-size: 1rem;
	font-weight: 500;
	line-height: 1.7 !important;
	padding: 0.3rem 0.8rem !important;
	white-space: nowrap;
	background: var(--pl-navy) !important;
	color: #ffffff !important;
	border: 1px solid var(--pl-navy) !important;
	border-radius: 0 !important;
	cursor: pointer;
	transition: background 0.2s ease, color 0.2s ease;
}

.hubspot-form button.hsfc-Button:hover {
	background: #ffffff !important;
	color: var(--pl-navy) !important;
	border-color: var(--pl-navy) !important;
}

.hubspot-form .submitted-message {
	text-align: center;
	color: var(--pl-navy);
	font-size: 1.125rem;
}

/* ---------- HubSpot Meeting (ACF block) ---------- */
/*
 * HubSpot's Meetings embed always renders inside a cross-origin
 * iframe — there's no "raw HTML" equivalent like the Forms embed, so
 * only the wrapper/spacing below is ours to style; the scheduler's own
 * look is set inside HubSpot (Meetings → Style/branding).
 */
.hubspot-meeting-block {
	padding: 70px 0;
}

.hubspot-meeting-block__heading {
	text-align: center;
	color: var(--pl-navy);
	margin-bottom: 30px;
}

.hubspot-meeting-block__preview {
	text-align: center;
	color: #8a8f9c;
	padding: 24px;
	border: 1px dashed #c9cdd6;
	border-radius: 4px;
}

.hubspot-meeting {
	width: 100%;
	min-height: 600px;
}

/*
 * ---------- Apartment page: map + sibling apartments ----------
 * Both sit below the two-column body — see template-parts/apartment-detail.php.
 *
 * The map canvas and card markup are shared with the Location Map and
 * Apartments Grid blocks, so .location-map__* and .apartments-grid__*
 * styling applies untouched. Only the wrappers are new.
 */
.apartment-map {
	padding-top: 10px;
}


/*
 * The map canvas is full-bleed inside the Location Map block because that
 * block sits outside .container. Here it inherits whatever height the
 * block's own .location-map__canvas rule sets, so nothing is restated —
 * only the breathing room below it.
 */
.apartment-map .location-map__canvas {
	margin-bottom: 0;
}

/*
 * The section carries .find-your-place as well, so padding, background
 * and every card rule come from that block — the two rows are then the
 * same row, not two that have to be kept in step.
 *
 * Nothing is overridden here on purpose. The previous version set its own
 * padding, a slightly different background tint and flex: 0 1 340px on
 * the cards, which is exactly why the widths stopped matching the home
 * page.
 */

