/*
 * HOME PAGE
 *
 * The one page whose visual design has had a second pass. Everything in
 * this block is scoped to the home template's own classes -- .hero,
 * .programs, .process, .deals -- so the pages still awaiting review are
 * untouched by it.
 *
 * What the pass is answering: the first version was a correct page that
 * read as a text document. Same content, same order, same links; the
 * difference is scale, photography, and a dark/light rhythm instead of one
 * long pale column.
 */

/*
 * Section rhythm.
 *
 * --space-section is 144px at desktop, which is right for a page that is
 * nothing but prose and too much everywhere else: with photography carrying
 * the breaks, the same gap reads as the page having run out of things to
 * say. The token itself is untouched -- the footer still uses it.
 */
.section { padding-block: clamp(72px, 7.6vw, 116px); }

/* ---------- Motion ----------
 *
 * One system, two shapes: `.reveal` for a single element, `.reveal-group`
 * for a container whose children arrive one after another.
 *
 * Every rule here is gated behind `.js-anim` on <html>, which only script
 * sets, and only when IntersectionObserver exists and the visitor has not
 * asked for reduced motion (see apollonia_print_motion_flag). Without that
 * class nothing is hidden and nothing moves -- the page is simply the page.
 *
 * The distances are deliberately small. 14px and a slow ease is a settle,
 * not an entrance; anything larger starts to look like a template.
 */
.js-anim .reveal,
.js-anim .reveal-group > * {
	opacity: 0;
	transform: translateY(14px);
}

.js-anim .reveal,
.js-anim .reveal-group > * {
	transition: opacity 0.9s cubic-bezier(0.22, 0.61, 0.36, 1),
		transform 0.9s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.js-anim .reveal.is-in,
.js-anim .reveal-group.is-in > * {
	opacity: 1;
	transform: none;
}

/* The stagger. Capped at eight because the longest group on the page is the
   eight transactions, and a ninth child arriving 0.72s late would read as a
   fault rather than as rhythm. */
.js-anim .reveal-group.is-in > *:nth-child(2) { transition-delay: 0.07s; }
.js-anim .reveal-group.is-in > *:nth-child(3) { transition-delay: 0.14s; }
.js-anim .reveal-group.is-in > *:nth-child(4) { transition-delay: 0.21s; }
.js-anim .reveal-group.is-in > *:nth-child(5) { transition-delay: 0.28s; }
.js-anim .reveal-group.is-in > *:nth-child(6) { transition-delay: 0.35s; }
.js-anim .reveal-group.is-in > *:nth-child(7) { transition-delay: 0.42s; }
.js-anim .reveal-group.is-in > *:nth-child(n + 8) { transition-delay: 0.49s; }

/* A belt-and-braces stop. The flag script already refuses to set .js-anim
   for a visitor who asked for reduced motion, so this only ever matters if
   the preference changes after the page has loaded. */
@media (prefers-reduced-motion: reduce) {
	.js-anim .reveal,
	.js-anim .reveal-group > * {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* ---------- Hero ---------- */

/*
 * The opening is a photograph, not a white page: Lower Manhattan at sunset
 * from the client's own library. It is the first thing that says what kind
 * of lender this is, and it carries the whole top of the page together with
 * the figure band directly beneath it -- one dark mass, then light.
 */
.hero {
	position: relative;
	/* Own stacking context, so the negative-z layers below stay inside the
	   hero and can never paint under the sticky header. */
	isolation: isolate;
	display: flex;
	align-items: flex-end;
	min-height: min(88vh, 900px);
	/* The top padding clears the fixed header on this page (88px) with room
	   to spare; the bottom one sets the headline off the figure band. */
	padding-block: clamp(150px, 22vh, 240px) clamp(48px, 5vw, 84px);
	background: var(--ink);
	color: var(--paper);
	overflow: hidden;
}

.hero__media {
	position: absolute;
	inset: 0;
	z-index: -2;
}

.hero__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Below centre: it keeps the skyline and the bridge in frame while the
	   scrim and the headline take the water at the bottom. */
	object-position: 50% 52%;
}

/* The scrim. Two gradients, not one flat wash: the vertical one buys the
   headline its contrast at the foot of the frame, the horizontal one keeps
   the left column readable without dimming the sunset on the right. A flat
   overlay dark enough for the text would have thrown the photograph away. */
.hero--photo::after,
.pagehead--photo::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background:
		/* Under the header bar. The sky in this photograph is a bright
		   sunset, and the transparent header's white type sits directly on
		   it: without this the nav measures around 4.7:1 in the best part
		   of the frame and less in the worst. Under it, nothing in the bar
		   is below 9:1. */
		linear-gradient(to bottom, rgba(6, 8, 10, 0.6) 0, rgba(6, 8, 10, 0) 200px),
		linear-gradient(to top, rgba(6, 8, 10, 0.82) 0%, rgba(6, 8, 10, 0.58) 30%, rgba(6, 8, 10, 0.16) 68%, rgba(6, 8, 10, 0.3) 100%),
		linear-gradient(to right, rgba(6, 8, 10, 0.5) 0%, rgba(6, 8, 10, 0) 58%);
}

.hero__inner { width: 100%; }

.hero__rule {
	display: block;
	width: 64px;
	height: 1px;
	margin-bottom: clamp(28px, 3vw, 44px);
	background: var(--green-on-ink);
}

.hero__title {
	font-family: var(--font-display);
	font-weight: 300;
	font-size: clamp(46px, 7.4vw, 116px);
	line-height: 1.02;
	letter-spacing: -0.02em;
	max-width: 15ch;
	margin: 0;
}

/*
 * Not .u-muted. A muted grey belongs on a paper ground; over a photograph
 * the opening line is the second thing read after the headline, and it is
 * set in white held slightly back rather than in grey. 0.82 of white on the
 * scrim measures far above the 4.5:1 minimum.
 */
.hero__sub {
	font-size: clamp(17px, 1.4vw, 21px);
	line-height: 1.55;
	max-width: 44ch;
	margin: clamp(22px, 2.4vw, 32px) 0 0;
	color: rgba(255, 255, 255, 0.82);
}

@media (max-width: 860px) {
	.hero { min-height: min(84vh, 720px); }
	.hero__media img { object-position: 60% 46%; }
}

/* ---------- Loan programs ----------
 *
 * List on the left, a single picture frame on the right that changes to
 * whatever row the reader is pointing at. It replaces a bare list of five
 * links, and it is the reason the five program photographs -- which the
 * client already owns, one per program -- appear anywhere on this page.
 */
.programs__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 0.68fr);
	gap: clamp(40px, 5vw, 96px);
	align-items: start;
}

.programs__media {
	position: sticky;
	top: 128px;
	aspect-ratio: 3 / 4;
	overflow: hidden;
	background: var(--wash);
}

.programs__shot {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	opacity: 0;
	transform: scale(1.05);
	/* The cross-fade is slow on purpose. At 200ms it flickers as the
	   pointer crosses the list; at 600ms it reads as one picture settling
	   into another. */
	transition: opacity 0.6s ease, transform 1.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.programs__shot.is-active {
	opacity: 1;
	transform: scale(1);
}

/* Programs list */
.proglist { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }

.proglist__link {
	position: relative;
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 24px;
	padding: clamp(22px, 2.6vw, 36px) 0;
	border-bottom: 1px solid var(--rule);
	text-decoration: none;
}

.proglist__name {
	font-family: var(--font-display);
	font-size: clamp(26px, 3.2vw, 46px);
	font-weight: 300;
	letter-spacing: -0.015em;
	line-height: 1.1;
	transition: transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* The green hairline draws itself along the row's own bottom border, so the
   hover is a line being ruled rather than a box lighting up. */
.proglist__link::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: -1px;
	width: 0;
	height: 1px;
	background: var(--green);
	transition: width 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.proglist__link:hover::after,
.proglist__link:focus-visible::after { width: 100%; }

.proglist__link:hover .proglist__name,
.proglist__link:focus-visible .proglist__name { transform: translateX(12px); }

.proglist__mark {
	font-size: 20px;
	line-height: 1;
	color: var(--muted);
	transition: transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1), color 0.3s ease;
}

.proglist__link:hover .proglist__mark,
.proglist__link:focus-visible .proglist__mark {
	transform: translateX(10px);
	color: var(--green);
}

@media (prefers-reduced-motion: reduce) {
	.proglist__name,
	.proglist__mark,
	.proglist__link::after,
	.programs__shot { transition: none; }
}

/* Below the two-column breakpoint the frame is dropped rather than stacked.
   A phone gets a clean list and does not download five photographs to show
   none of them: a lazy image inside display:none is never fetched. */
@media (max-width: 860px) {
	.programs__grid { grid-template-columns: minmax(0, 1fr); }
	.programs__media { display: none; }
}

/* ---------- How it works ----------
 *
 * The three steps used to be three equal columns of small type on a pale
 * ground -- the same shape as every other block on the page. They are now
 * a dark band with the photograph running off the left edge of the screen,
 * and the steps ruled underneath one another beside it.
 */
.process { padding-block: 0; }

.process__grid {
	display: grid;
	grid-template-columns: minmax(0, 0.42fr) minmax(0, 0.58fr);
}

/* No vw arithmetic anywhere in this block. The picture reaches the edge of
   the screen because its column starts there -- the section is full width
   and is not inside .wrap -- rather than by being pulled out of a centred
   container with a negative margin, which is the version of this effect
   that adds a scrollbar's worth of horizontal overflow on a phone. */
.process__media { position: relative; min-height: 100%; }

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

.process__body {
	padding-block: clamp(72px, 8vw, 128px);
	padding-left: clamp(32px, 5vw, 88px);
	/*
	 * The right edge lines up with the page grid: on a viewport wider than
	 * --wrap-max the centred .wrap leaves a margin, and this reproduces it.
	 * max() rather than a bare calc so narrower viewports fall back to the
	 * ordinary page padding, and padding rather than margin so a scrollbar
	 * can only make the column narrower -- never wider than the screen.
	 */
	padding-right: max(var(--wrap-pad), calc((100vw - var(--wrap-max)) / 2 + var(--wrap-pad)));
}

.process__inner { max-width: 720px; }

/* Steps */
.steps { list-style: none; margin: 0; padding: 0; }

.steps__item {
	display: grid;
	grid-template-columns: 84px minmax(0, 1fr);
	gap: clamp(16px, 2vw, 32px);
	align-items: start;
	padding-block: clamp(24px, 2.6vw, 34px);
	border-top: 1px solid var(--rule-on-ink);
}

.steps__item:last-child { border-bottom: 1px solid var(--rule-on-ink); }

.steps__num {
	display: block;
	color: var(--green-on-ink);
	font-size: clamp(20px, 1.7vw, 26px);
	font-weight: 200;
	letter-spacing: 0.04em;
	line-height: 1;
	padding-top: 6px;
}

.steps__text h3 {
	font-family: var(--font-display);
	font-weight: 300;
	font-size: clamp(21px, 1.9vw, 28px);
	letter-spacing: -0.005em;
	margin: 0 0 0.4em;
}

.steps__text p {
	margin: 0;
	color: var(--muted-on-ink);
	max-width: 54ch;
}

@media (max-width: 860px) {
	.process__grid { grid-template-columns: minmax(0, 1fr); }
	.process__media { min-height: 0; aspect-ratio: 16 / 10; }
	.process__body {
		padding-inline: var(--wrap-pad);
		padding-block: clamp(56px, 9vw, 88px);
	}
	.steps__item { grid-template-columns: 58px minmax(0, 1fr); }
}

/* ---------- Transactions ----------
 *
 * Eight tombstones. As a four-across grid of small type they read as a
 * table of contents; as two columns of ruled rows with the amount set
 * large, they read as a track record, which is what they are.
 *
 * No photographs here, deliberately. The deals on the page today are demo
 * records awaiting the client's own list, and giving invented transactions
 * a picture apiece would dress them as evidence.
 */
.dealgrid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: clamp(40px, 6vw, 104px);
	row-gap: 0;
}

.dealcard {
	display: grid;
	/*
	 * The figure takes its own width and the description takes the rest.
	 *
	 * Not the other way round, which is what this was: with the description
	 * in an `auto` track it claimed its max-content width -- one unbroken
	 * uppercase line -- and at 1024px that was wider than the row, so it
	 * overflowed back across the amount and the two printed on top of each
	 * other. Given a 1fr track it wraps instead, and the amounts are short
	 * enough that their own track never needs to.
	 */
	grid-template-columns: auto minmax(0, 1fr);
	align-items: baseline;
	gap: 8px 24px;
	padding-block: clamp(20px, 2.2vw, 30px);
	border-top: 1px solid var(--rule);
}

/* Every card in the last row also closes with a rule, so each column ends
   on a line rather than in mid-air. Two columns, so that is the last two. */
.dealcard:nth-last-child(-n + 2) { border-bottom: 1px solid var(--rule); }

/* Kept for the day the client sends photographs of their own closings: the
   frame spans both columns above the figure instead of sitting inside one. */
.dealcard__img {
	grid-column: 1 / -1;
	margin-bottom: 20px;
	filter: grayscale(1);
}

.dealcard__img img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }

.dealcard__amount {
	font-size: clamp(24px, 2.5vw, 36px);
	font-weight: 300;
	letter-spacing: -0.02em;
	line-height: 1.1;
	margin: 0;
}

/* Uppercase and letterspaced, against the large figure on the left: the
   pair reads as a tombstone entry rather than as a caption under a card.
   --muted is 4.93:1 on --wash, so the smaller size still clears AA. */
.dealcard__meta {
	font-size: 12px;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	text-align: right;
	margin: 0;
}

/*
 * Between the two breakpoints the row keeps its two columns but the entry
 * stacks: a description beside the figure has to wrap here, and it wraps in
 * the middle of a term -- "TOWNHOUSE · NEW CONSTRUCTION · / STAMFORD, CT".
 * Under the figure it has the whole row and needs no second line at all.
 */
@media (max-width: 1200px) and (min-width: 761px) {
	.dealcard {
		grid-template-columns: minmax(0, 1fr);
		gap: 6px;
	}
	.dealcard__meta { text-align: left; }
}

@media (max-width: 760px) {
	.dealgrid { grid-template-columns: minmax(0, 1fr); }
	.dealcard {
		grid-template-columns: minmax(0, 1fr);
		gap: 6px;
	}
	.dealcard__meta { text-align: left; }
	.dealcard:nth-last-child(-n + 2) { border-bottom: 0; }
	.dealcard:last-child { border-bottom: 1px solid var(--rule); }
}

/* Long-form text */

/* Heading rhythm, shared by every prose page. */
.prose h2 { margin-top: 1.6em; }

/*
 * A reading measure for stored copy, set on the children rather than on the
 * block -- the same reason as .loanpage__intro above: the tab groups and any
 * full-width figure inside the copy want the whole column, and capping the
 * container would take them down with it.
 *
 * .textpage (legal, broker, 404) is excluded because it caps its own whole
 * column already, at --measure.
 */
.prose:not(.textpage) > p,
.prose:not(.textpage) > h2,
.prose:not(.textpage) > h3,
.prose:not(.textpage) > h4,
.prose:not(.textpage) > ul,
.prose:not(.textpage) > ol,
.prose:not(.textpage) > details { max-width: 78ch; }

/*
 * A picture that arrives inside stored copy is sized, not stretched.
 *
 * `width: 100%` was the first attempt and it was wrong: the two founder
 * portraits on About are 2048px originals, and filling the column blew them
 * up to 748px tall slabs that pushed the rest of the page off the screen.
 * A cap leaves a small picture at its own size and brings a large one down
 * to an inset the copy can sit beside.
 *
 * Tab panels are excluded below -- their pictures fill the grid column the
 * panel gives them, which is the whole point of that layout.
 */
.prose > p img,
.prose > figure img,
.loanpage__intro > p img,
.loanpage__intro > figure img {
	width: auto;
	max-width: min(100%, 380px);
}

/* The two founder portraits on About arrive as bare <figure> elements with
   the name and role as the two elements after them, so the figure is left
   flush with the copy and the pair reads as a portrait with its caption. */
.prose > figure { margin: 0 0 20px; }
.prose > figure + h4 { margin-top: 0; }

.tabs__panel img { width: 100%; }

/* Legal, Broker and 404 copy caps the whole column at the reading measure.
   The padding has to be added OUTSIDE that measure: .wrap puts
   2 x --wrap-pad inside the box and max-width caps the border box, so a
   bare var(--measure) spent 96px of the measure on its own padding and set
   59 characters to the line where the token asks for 68.

   About deliberately does NOT take this cap. It is the company page rather
   than legal copy, its body follows the page grid like every other section,
   and the global `p { max-width: var(--measure) }` in base.css keeps its
   lines to the same 68 characters without narrowing the column around
   them. */
.textpage { max-width: calc(var(--measure) + 2 * var(--wrap-pad)); }

/* FAQ */
.faq__item { border-bottom: 1px solid var(--rule); }
.faq__item:first-child { border-top: 1px solid var(--rule); }

.faq__q {
	cursor: pointer;
	list-style: none;
	padding: 28px 0;
	/* A <summary>, not a heading, so the heading rule in base.css does not
	   reach it -- but it reads as one and is set like one. */
	font-family: var(--font-display);
	font-size: clamp(20px, 1.9vw, 27px);
	font-weight: 400;
	display: flex;
	justify-content: space-between;
	gap: 24px;
}

/* Every one of the 42 stored questions ends with a <br> that Elementor
   left behind. In a flex container it becomes a flex item of its own, so
   the 24px gap is applied twice and the question sits pushed away from the
   +/- marker. The content in the database is not edited to fix it. */
.faq__q br { display: none; }

.faq__q::-webkit-details-marker { display: none; }
.faq__q::after { content: "+"; color: var(--green); }
.faq__item[open] .faq__q::after { content: "\2212"; }
.faq__a { padding-bottom: 28px; max-width: var(--measure); }

/* The opening paragraphs of the FAQ page, above the accordion. */
.faq > p { max-width: 78ch; }

/*
 * The group markers -- "About Apollonia Equities", "Private Lending
 * Basics", ten of them -- are <h4> in the client's copy, and every one of
 * them sits between accordion rows.
 *
 * With the site-wide heading rule they came out at 21px serif, in a column
 * where the questions they are meant to head are 27px serif: a divider set
 * smaller than the things it divides, in the same face, with the same
 * spacing above and below. It read as one more question.
 *
 * So it stops competing on size and becomes what it is -- a label. The rule
 * above it is what does the dividing, the same 2px the section markers use,
 * and the space around it is what makes the group a group. Every h4 inside
 * .faq is one of these ten; the page's other headings are h2 and h3.
 */
.faq h4 {
	font-family: var(--font);
	font-size: var(--step-label);
	font-weight: 500;
	letter-spacing: 0.14em;
	line-height: 1.4;
	text-transform: uppercase;
	color: var(--ink);
	margin: clamp(56px, 6vw, 96px) 0 0;
	padding-top: clamp(20px, 2vw, 28px);
	border-top: 2px solid var(--ink);
}

/* The first marker opens the accordion, so it needs no gap of its own on
   top of the paragraph spacing already above it. */
.faq h4:first-of-type { margin-top: clamp(32px, 3.5vw, 56px); }

/* A question directly under a marker would otherwise draw its own hairline
   a few pixels below the marker's rule. */
.faq h4 + .faq__item { border-top: 0; }

/* Contact */

/* One column, not two. The body of this page is an Elementor document that
   lays out a row of its own -- the form beside the map -- and that row sizes
   itself against whatever track it lands in. Held in a 1.4fr track it got
   747px of a 1344px page and split it into two 311px columns: fields
   narrower than their own labels, and a map too small to read a street off.
   Given the page's own width the same row comes out at 580px a side, which
   is the size the builder drew it for.

   Our contact details follow underneath as a strip instead of taking a third
   column, where four lines of text left a tall empty gap beside the form. */
.contact { display: grid; grid-template-columns: 1fr; gap: 64px; }

/* Contact is the one page still rendered by Elementor, and the builder's
   containers size themselves against the grid track they land in. A grid
   item's automatic minimum size is its content's minimum, so the track grew
   to the width the builder wanted — 1000px — and the whole document
   scrolled sideways on a phone. min-width: 0 lets the track shrink to the
   viewport again, and the builder's 100%-wide containers follow it. Still
   needed with a single track: the minimum applies per item, not per
   column count. */
.contact__form { min-width: 0; }

/* auto-fit rather than two fixed tracks, so the pairs fall onto one column
   on a narrow screen without a media query of their own. */
.contact__meta {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: 8px 64px;
	border-top: 1px solid var(--rule);
	padding-top: 40px;
}

@media (max-width: 900px) {
	.contact { gap: 40px; }
}


/* ---------- Loan program pages and the hub ----------
 *
 * The body of these pages is the client's own stored copy, so what can be
 * designed here is its measure and the way its pictures sit in it -- not
 * its structure.
 */

/*
 * A reading measure for the prose, applied to the block's own children
 * rather than to the block.
 *
 * The line was running the full 1344px of the page -- about 120 characters,
 * against a typographic norm of 45 to 75 -- because the container is wide
 * and nothing said otherwise. Capping the container itself would have taken
 * the tab groups down with it, and those want the whole width: their
 * pictures sit in the margin the prose leaves.
 */
.loanpage__intro > p,
.loanpage__intro > h2,
.loanpage__intro > h3,
.loanpage__intro > h4,
.loanpage__intro > ul,
.loanpage__intro > ol,
.loanpage__intro > details { max-width: 78ch; }

.loanpage__intro > h2,
.loanpage__intro > h3 { margin-top: 1.4em; }

/*
 * Inside a tab panel the picture goes into the column beside the copy.
 *
 * A float was the first attempt and it cannot work here: the picture is the
 * LAST thing in the panel, and a float never rises above the block boxes
 * that precede it, so it landed under the text instead of beside it. The
 * panels are stored content and their order is not ours to change.
 *
 * Grid places it regardless of where it appears in the source. The whole
 * rule is behind :has(), so a panel that carries no picture is left as an
 * ordinary column of text rather than a two-column grid with an empty half.
 */
.tabs__panel:has(p img) {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 0.52fr);
	column-gap: clamp(32px, 4vw, 72px);
	align-items: start;
}

.tabs__panel:has(p img) > * { grid-column: 1; }

/* `span 30`, not `1 / -1`: -1 addresses the last EXPLICIT row line, and
   these rows are all implicit -- there is one per paragraph the client
   wrote. Thirty is past any panel they will write; the extra rows are
   zero-height and cost nothing. */
.tabs__panel:has(p img) > p:has(img) {
	grid-column: 2;
	grid-row: 1 / span 30;
	margin: 0;
}

/* One ratio for all four panels. The pictures arrive at whatever shape the
   client uploaded, and an unconstrained portrait next to a landscape means
   the panel changes height as the reader switches tabs -- the page jumps
   under the pointer that just clicked. */
.tabs__panel:has(p img) > p:has(img) img {
	aspect-ratio: 4 / 5;
	object-fit: cover;
}

@media (max-width: 860px) {
	.tabs__panel:has(p img) { display: block; }
	.tabs__panel:has(p img) > p:has(img) { margin: 0 0 24px; }
}


/* ---------- Contact ----------
 *
 * The one page still rendered by Elementor, so its body is the builder's
 * markup and only its surface can be designed. These rules do not touch the
 * layout the builder draws -- they put its type and its form controls into
 * the design system, which is the difference between a page that keeps its
 * form and a page that looks like a different site.
 *
 * Every selector carries .contact as well as .contact__form, and that is
 * not padding: the kit's own rules are two classes deep and its stylesheet
 * is printed after this one on this page, so a tie goes to the builder. The
 * third class is what settles it.
 */

/* The builder's headings, in the site's display face. Elementor prints its
   own font stack per widget, so this has to name the elements it uses. */
.contact .contact__form .elementor-heading-title {
	font-family: var(--font-display);
	font-weight: 300;
	letter-spacing: -0.015em;
}

/* Form controls. The kit draws them with rounded corners, a grey rule and
   the browser's own type; everything else on this site is a hairline box
   with the body face in it. */
.contact .contact__form .elementor-field-textual {
	border: 1px solid var(--rule);
	border-radius: 0;
	background: var(--paper);
	color: var(--ink);
	font-family: var(--font);
	font-size: var(--step-body);
	padding: 14px 16px;
	min-height: 52px;
	box-shadow: none;
	transition: border-color 0.3s ease;
}

.contact .contact__form .elementor-field-textual:focus {
	border-color: var(--ink);
	box-shadow: none;
	outline: none;
}

.contact .contact__form .elementor-field-textual:focus-visible {
	outline: 2px solid var(--green);
	outline-offset: 2px;
}

.contact .contact__form .elementor-field-label {
	font-family: var(--font);
	font-size: var(--step-label);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--muted);
	margin-bottom: 10px;
}

/*
 * The submit button, as the header's Apply button is drawn.
 *
 * The two colours carry !important and nothing else here does. Elementor
 * generates per-widget CSS keyed to the widget's own id --
 * `.elementor-590 .elementor-element.elementor-element-a4212f0
 * .elementor-button[type="submit"]`, five components deep -- and no class
 * selector can outrank it. Matching that id here would be worse than
 * !important: it changes whenever the client re-saves the widget, and the
 * button would quietly go back to being blue with nothing to say why.
 * Everything else in this block wins on specificity alone.
 */
.contact .contact__form .elementor-button {
	/* !important on the radius too: it is set per widget --
	   `.elementor-590 .elementor-element.elementor-element-367f809f
	   .elementor-button { border-radius: 8px }` -- four components deep,
	   past anything a class selector can reach. Every box on this site is
	   square. */
	border-radius: 0 !important;
	background: var(--ink) !important;
	color: var(--paper) !important;
	font-family: var(--font);
	font-size: var(--step-label);
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	padding: 18px 40px;
	border: 1px solid var(--ink);
	transition: background-color 0.3s ease, color 0.3s ease;
}

.contact .contact__form .elementor-button:hover,
.contact .contact__form .elementor-button:focus {
	background: var(--paper) !important;
	color: var(--ink) !important;
}


/* ---------- Calls to action inside stored copy ----------
 *
 * The row near the top of About and of every loan page -- "Request Investor
 * Information" beside "Speak With Our Team". The paragraph is marked server
 * side (apollonia_mark_cta_rows), which is also where the note on what does
 * and does not qualify lives.
 *
 * Drawn as the header's Apply button is drawn, because it is the same kind
 * of thing: the first link filled, the rest outlined. One strong action per
 * row, and the second reads as the alternative rather than as a rival.
 */
.ctarow {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	margin: clamp(26px, 3vw, 38px) 0 clamp(34px, 4vw, 52px);
}

.ctarow__btn {
	display: inline-flex;
	align-items: center;
	padding: 16px 34px;
	border: 1px solid var(--ink);
	background: var(--ink);
	color: var(--paper);
	font-size: var(--step-label);
	font-weight: 500;
	letter-spacing: 0.08em;
	line-height: 1.2;
	text-transform: uppercase;
	text-decoration: none;
	transition: background-color 0.35s ease, color 0.35s ease;
}

/* Beats the site-wide `a:hover { color: var(--green) }` on specificity: a
   button that turns green on hover would be the only one on the site. */
.ctarow__btn:hover {
	background: transparent;
	color: var(--ink);
}

.ctarow__btn--ghost {
	background: transparent;
	color: var(--ink);
}

.ctarow__btn--ghost:hover {
	background: var(--ink);
	color: var(--paper);
}

@media (max-width: 480px) {
	/* Full width rather than a cramped wrap: "Request Investor Information"
	   is 28 characters and does not fit beside anything on a phone. */
	.ctarow { display: grid; gap: 12px; }
	.ctarow__btn { justify-content: center; text-align: center; }
}


/* ---------- Accreditation strip ----------
 *
 * The MPA award seal, its caption and its buttons, gathered into one block
 * server side (apollonia_group_credentials, where the note on what qualifies
 * lives). It arrives as figure + heading + .ctarow and is laid out as a
 * credential: the mark small on the left, everything it says beside it,
 * hairlines above and below.
 *
 * The seal keeps its own colours. It is a third party's mark; size and
 * position are ours to choose, its brand is not.
 */
.credential {
	display: grid;
	grid-template-columns: 96px minmax(0, 1fr);
	column-gap: clamp(24px, 3vw, 44px);
	align-items: center;
	border-block: 1px solid var(--rule);
	padding-block: clamp(28px, 3vw, 40px);
	margin-block: clamp(36px, 4vw, 56px);
}

/* Spanning both rows so the mark is centred against the caption and the
   buttons together rather than against the caption alone. */
.credential > figure {
	grid-column: 1;
	grid-row: 1 / span 2;
	margin: 0;
}

.credential > figure img { width: 96px; height: auto; }

.credential > :not(figure) { grid-column: 2; }

.credential > h2,
.credential > h3,
.credential > h4 {
	font-size: clamp(19px, 1.7vw, 25px);
	margin: 0 0 clamp(14px, 1.6vw, 20px);
}

/* The row already sits inside a strip with its own rhythm. */
.credential > .ctarow { margin: 0; }

@media (max-width: 600px) {
	.credential {
		grid-template-columns: minmax(0, 1fr);
		row-gap: 20px;
	}
	.credential > figure { grid-column: 1; grid-row: auto; }
	.credential > :not(figure) { grid-column: 1; }
}


/* ---------- Contact: the builder's photographic band ----------
 *
 * "Speak With an Apollonia Equities Specialist" -- a heading, a paragraph and
 * two links over a photograph, all of it the client's stored content and all
 * of it drawn by Elementor. It arrived as a rounded card inset 27px from the
 * page grid, its heading set 60px in Cal Sans, its text sitting straight on
 * a sunlit skyline. Next to the rest of the site it read as a widget from a
 * different website.
 *
 * Nothing here removes or moves any of it. Square corners, the page's own
 * grid, the display serif, and a scrim so the type has a ground -- the same
 * treatment every other photographic band on this site gets.
 *
 * WHY :has() RATHER THAN THE ELEMENT IDS. Elementor names each widget with a
 * generated id (.elementor-element-73670a8), and those change whenever the
 * client re-saves the widget. "The container that holds the background
 * slideshow" and "the heading inside it" are the same things tomorrow.
 *
 * WHY !important. The per-widget CSS Elementor generates is five components
 * deep (`.elementor-590 .elementor-element.elementor-element-213792f8
 * .elementor-heading-title`) and no class selector can outrank it. Matching
 * that id here would be worse: it would break silently on the next save,
 * with nothing to say why.
 */

/* The band takes the page grid: the builder's own container insets it by
   27px a side, which left it not quite aligned with anything above or
   below it. */
.contact .contact__form .e-con:has(> .e-con > .elementor-background-slideshow) {
	padding-inline: 0 !important;
}

.contact .contact__form .e-con:has(> .elementor-background-slideshow) {
	border-radius: 0 !important;
	padding: clamp(48px, 6vw, 96px) clamp(28px, 4vw, 72px) !important;
}

.contact .contact__form .elementor-background-slideshow {
	border-radius: 0 !important;
}

/* The scrim, inside the slideshow wrapper so it covers the photograph and
   nothing else: the wrapper is z-index 0 and every text widget sits above
   it, so a layer added here lands between the picture and the type. */
.contact .contact__form .elementor-background-slideshow::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 2;
	background:
		linear-gradient(to right, rgba(6, 8, 10, 0.85) 0%, rgba(6, 8, 10, 0.5) 48%, rgba(6, 8, 10, 0.15) 100%),
		linear-gradient(to top, rgba(6, 8, 10, 0.5) 0%, rgba(6, 8, 10, 0) 55%);
}

/*
 * On a narrow screen the copy runs the full width of the band, so it reaches
 * the right-hand side where the horizontal scrim has faded out -- white type
 * on a sunlit skyline. Measured there before this rule: the last lines of
 * the paragraph were around 2:1.
 *
 * The gradient goes vertical instead. There is no "away from the text" side
 * to fade towards when the text is the full width.
 */
@media (max-width: 860px) {
	.contact .contact__form .elementor-background-slideshow::after {
		background: linear-gradient(to top, rgba(6, 8, 10, 0.9) 0%, rgba(6, 8, 10, 0.72) 55%, rgba(6, 8, 10, 0.5) 100%);
	}
}

/*
 * The buttons inside the band invert.
 *
 * They take the page's ink fill everywhere else, which on this band is a
 * near-black box on a near-black photograph -- the two calls to action were
 * the least visible thing in the frame. On a dark ground the fill is paper,
 * exactly as the header's Apply button inverts over the hero.
 *
 * Both outlined, not one filled and one outlined. On the pages where the
 * .ctarow appears the first link is the page's primary action; here it is
 * not -- the primary action on Contact is the form directly below, and these
 * two are peers ("explore the programmes" beside "speak to someone"). A
 * filled button on top of the largest photograph on the page would also be
 * claiming a hierarchy the page does not have.
 *
 * It is the simpler rule as well: the filled-first version had to address
 * `> .e-con > *:first-child`, which is a position in the builder's tree and
 * is one drag away from meaning something else.
 */
.contact .contact__form .e-con:has(> .elementor-background-slideshow) .elementor-button {
	background: transparent !important;
	color: var(--paper) !important;
	border: 1px solid rgba(255, 255, 255, 0.6) !important;
}

.contact .contact__form .e-con:has(> .elementor-background-slideshow) .elementor-button:hover,
.contact .contact__form .e-con:has(> .elementor-background-slideshow) .elementor-button:focus {
	background: var(--paper) !important;
	color: var(--ink) !important;
	border-color: var(--paper) !important;
}

/*
 * Scoped to the band, and that scope is load-bearing rather than tidiness.
 * Without it these two rules reach every heading widget on the page -- and
 * the one above the form ("Explore Our Programs") sits on white paper, so it
 * was being painted white on white and disappeared entirely.
 */
/*
 * The client's own "animated button" snippet, and the reason the two links
 * in the band still went green on hover.
 *
 * `.mortgage-animated-btn a.elementor-button` paints a green gradient, and a
 * SECOND green gradient slides across it from the left on hover, drawn by a
 * ::before. Two things follow:
 *
 * - a gradient is a background-IMAGE. The `background` shorthand above did
 *   clear it, but a background-COLOUR rule alone never would have.
 * - the hover colour is a separate element sliding over the button, which no
 *   rule about the button's own colours can reach at all. That is what was
 *   still turning them green.
 *
 * The snippet is site-wide but Contact is the only page it lands on -- the
 * one page still rendered by Elementor. Checked: zero occurrences on the
 * other six.
 *
 * The slide is dropped rather than recoloured. Every other button on this
 * site changes by swapping two colours; a wipe would be the only one of its
 * kind, and this band already has the strongest thing on the page in it.
 */
.contact .contact__form .mortgage-animated-btn .elementor-button {
	background-image: none !important;
}

.contact .contact__form .mortgage-animated-btn .elementor-button::before {
	content: none !important;
}

.contact .contact__form .e-con:has(> .elementor-background-slideshow) h2.elementor-heading-title {
	font-family: var(--font-display) !important;
	font-size: clamp(30px, 3.4vw, 50px) !important;
	font-weight: 300 !important;
	line-height: 1.06 !important;
	letter-spacing: -0.02em !important;
	color: var(--paper) !important;
}

.contact .contact__form .e-con:has(> .elementor-background-slideshow) p.elementor-heading-title {
	font-family: var(--font) !important;
	font-size: clamp(16px, 1.25vw, 19px) !important;
	line-height: 1.55 !important;
	color: rgba(255, 255, 255, 0.82) !important;
}

/* Every other heading the builder prints on this page keeps the site's
   display face and the page's own ink. */
.contact .contact__form .elementor-heading-title {
	font-family: var(--font-display);
	font-weight: 300;
	letter-spacing: -0.015em;
}
