/* ==========================================================================
   Step 1 — the landing page.

   Three objects: a video, two buttons, and a band of figures below the fold.
   Every proportion in section 1 is measured off the reference the client
   approved rather than designed, and the comments record what was measured so
   nobody has to re-derive it from a screenshot.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Stage — the clip and the two buttons

   Measured off the reference (khalidrealty.com) at a 1280 viewport rather
   than guessed:

     container   1120px, which is 87.5% of the viewport
     video       1120 x 630 — exactly 16:9, the full container width
     gap         35px above the video, 20px below it, 20px between buttons
     buttons     full container width, 44 tall, 3px radius,
                 20px/600 capitalize, 12px 24px padding, line-height 1

   Everything above is matched. Two things are not:

   1. The reference page is white with a black logo band; ours is black
      throughout. That is the client's instruction — the palette follows
      mohammedzohaib.com, which is black, white and grey. So the buttons are
      inverted too: theirs are black on white, ours white on black.

   2. The reference does not fit one screen. At 1280x900 its second button
      ends at 952 and the document is 1185 tall. Fitting one screen is a
      standing requirement here, so the video carries a second cap based on
      the height the screen has left. Ours ends at 841.
   -------------------------------------------------------------------------- */

/* No min-height and no centring here, which is a change from every previous
   version of this page.

   Both existed to hold a tall stack — headline, subheading, video, buttons,
   badges — vertically centred in the viewport. With everything but the video
   and the buttons gone, centring only had one effect left: it split the
   leftover space above and below, which pushed the video 75px below the logo
   where the reference has it 35px below. Letting the block sit at its natural
   height puts it back, and the fit-one-screen guarantee moves entirely to the
   height cap on the player — which is where it actually belongs.

   35px top is the reference's own gap, measured. */
.stage {
	/* Everything on the page that is not the video: the logo band, the gap
	   above it, both buttons, their gaps, and the padding below. Every rem
	   removed here becomes 16px of height and 28px of width on the video. */
	--stage-chrome: 19rem;

	position: relative;
	padding-block: clamp(18px, 2.7vw, 35px) clamp(24px, 4vw, 44px);
	overflow: clip;
}

/* 87.5vw is the reference's own container ratio: 1120 of 1280. Below about
   700px that leaves too little side margin to read as deliberate, so it opens
   up to 92vw — the reference does the same thing at its mobile breakpoint. */
.stage__inner {
	position: relative;
	z-index: 1;
	width: min(1120px, 87.5vw);
	margin-inline: auto;
}

@media (max-width: 700px) {
	.stage__inner { width: 92vw; }
}

/* ---- The video ----------------------------------------------------------
   16:9 at the full container width, exactly as the reference.

   The second cap is ours. "Everything on one screen, on every device" is a
   hard requirement on this project; the reference page is 1177px tall at a
   1280x900 viewport and simply scrolls. So the player takes whichever is
   smaller — the reference width, or the width that keeps its 16:9 frame
   inside the height this screen actually has.

   max() floors it: on a very short screen the subtraction goes negative,
   which clamped the player to zero width and made the video vanish. A
   too-small video is a compromise; an absent one is a bug.
   ------------------------------------------------------------------------- */
.stage .player {
	width: 100%;
	max-width: min(1120px, max(280px, (100svh - var(--stage-chrome)) * 16 / 9));
	margin-inline: auto;
}

/* ---- The two bars -------------------------------------------------------
   Side by side from 860px up, stacked below it.

   The reference stacks them, and this page did too until the client asked for
   a row. The reason is arithmetic: stacked, the pair costs 44 + 20 + 44 =
   108px of height; in a row they cost 44. Those 64px come off --stage-chrome
   and go straight into the video, which is the whole point — at 1280x900 the
   player reaches the full 1120px the reference uses, where stacked it was
   capped at 1060.

   Both stay identical and equal-width. This is one decision with two answers,
   not a primary and a secondary.

   860px is where they stop fitting. "Schedule a Face-to-face Meeting" is the
   long one: at that width each button is about 366px and the label needs
   roughly 340px including padding. Below it, the label wraps to two lines and
   the row is worse than the stack, so it stacks.
   ------------------------------------------------------------------------- */
.stage__cta {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 20px;
	margin-top: 20px;
	margin-inline: auto;
	width: 100%;
	max-width: min(1120px, max(280px, (100svh - var(--stage-chrome)) * 16 / 9));
}

/* Re-measured on the settled page: the reference button is 20px/600 with
   12px 24px padding and line-height 1, giving 20 + 24 = 44px tall, radius 3px.
   (An earlier pass read 16px/40px — that was the page before its webfont had
   loaded. 44px is also exactly the minimum touch target, so nothing has to be
   traded here at all.)

   line-height: 1 is load-bearing. The body sets 1.6, which at 20px would make
   the content box 32px and the button 56px — visibly taller than the
   reference, and enough to break the one-screen fit on short laptops.

   The size scales down on narrow screens because "Schedule a Face-to-face
   Meeting" at a flat 20px wraps to two lines on a phone. 20px is the ceiling,
   reached by about 1280 — which is where the reference was measured. */
.stage__cta .btn--bar {
	width: 100%;
	min-height: 44px;
	padding: 12px 24px;
	border: 0;
	border-radius: 3px;
	background: var(--ink);
	color: var(--bg);
	font-size: clamp(15px, .55vw + 13px, 20px);
	font-weight: 600;
	line-height: 1;
	letter-spacing: 0;
	text-transform: capitalize;
	box-shadow: none;
}

@media (hover: hover) {
	.stage__cta .btn--bar:hover {
		background: var(--ink);
		color: var(--bg);
		transform: translateY(-1px);
		box-shadow: var(--lift-2);
	}
}

.stage__cta .btn--bar:active { transform: scale(.995); }

/* Short screens — a small laptop, or a phone turned sideways. */
@media (max-height: 560px) {
	.stage { --stage-chrome: 13rem; }
}

/* A phone held sideways has about 390px of viewport, and the logo band alone
   was taking 82 of it — enough to push the second booking button off the
   bottom. Shrinking the band buys back 40px, which is the difference between
   both buttons being on screen here and only one of them being.

   The video ends up small. That is the honest trade at this size, and it is
   the one orientation where the reference does not fit either. */
@media (max-height: 480px) {
	.site-head { padding-block: 10px 0; }
	.brand--lg .brand__logo { height: 30px; }

	.stage {
		--stage-chrome: 12.5rem;
		padding-block: 10px 14px;
	}
}

/* ---- Side by side -------------------------------------------------------
   Declared after the short-screen blocks above so it can lower their chrome
   budgets too: every one of those numbers was measured with the buttons
   stacked, and a row is 64px shorter in each case.

   Slightly tighter horizontal padding than the reference's 24px. In a row the
   constraint is width, not height, and 18px buys 12px of label room per
   button — the difference between the long label fitting on one line at 860px
   and not.
   ------------------------------------------------------------------------- */
@media (min-width: 860px) {
	.stage { --stage-chrome: 15rem; }

	/* The container is established only here, in row mode. Stacked, a button
	   is the full row width and the @container rule below would fire on every
	   phone — shrinking type that has no width problem. Declaring the
	   container inside this query means the rule can only ever match when the
	   buttons are actually side by side. */
	.stage__cta {
		flex-direction: row;
		container-type: inline-size;
	}

	.stage__cta .btn--bar {
		flex: 1 1 0;
		min-width: 0;
		padding: 12px 18px;
	}
}

@media (min-width: 860px) and (max-height: 560px) {
	.stage { --stage-chrome: 9rem; }
}

@media (min-width: 860px) and (max-height: 480px) {
	.stage { --stage-chrome: 8.5rem; }
}

/* ---- Narrow row, smaller label ------------------------------------------
   The buttons take their width from the video, and the video is capped by
   available height — so on a short, wide screen (1280x600, say) the player
   comes out 640px wide and each button only ~310px. "Schedule a Face-to-face
   Meeting" at 20px needs about 340px and wraps to two lines.

   A viewport media query cannot see that: the viewport is wide, it is the row
   that is narrow. A container query can, so the type steps down only in the
   case that actually has the problem, and stays at the reference's 20px
   everywhere else.

   Degrades exactly to the current behaviour without container query support —
   the label simply wraps, as it does today. Nothing breaks. */
/* Two steps rather than one. A single drop to 15px also caught the 860px
   breakpoint, where the row is 753px wide and 17px fits comfortably — the
   buttons went visibly smaller than the stacked layout one pixel narrower. */
@container (max-width: 780px) {
	.stage__cta .btn--bar { font-size: 17px; padding: 12px 16px; }
}

@container (max-width: 700px) {
	.stage__cta .btn--bar { font-size: 15px; padding: 12px 14px; }
}

/* --------------------------------------------------------------------------
   2. Arrival

   Far quieter than it was. The page is now three objects; a staged sequence
   across three objects reads as a slideshow, not as craft. The video settles,
   the buttons follow it. That is the whole animation.

   The player never animates opacity from 0: Chrome will not record an
   opacity:0 element as the largest contentful paint, so fading it in cost
   roughly 400ms of LCP on the one page where that matters.
   -------------------------------------------------------------------------- */

/* Both are movement-only. Neither animates opacity from 0, and that is a
   correctness rule here rather than a taste one.

   `animation-fill-mode: both` holds the from-keyframe before the delay
   elapses. In any renderer that does not actually run animations — headless
   screenshotters, link-preview crawlers, embedded webviews that never
   composite — "before the delay" is forever, so a from-state of opacity:0
   means the element is permanently invisible. The two booking buttons are the
   only things on this page worth having; they must never depend on an
   animation completing in order to be seen.

   Movement fails safe: worst case the block sits 14px low, which nobody can
   detect without a ruler. (The player has a second reason — Chrome will not
   record an opacity:0 element as the largest contentful paint, so fading it
   in cost about 400ms of LCP.) */
.js .stage .player   { animation: mzc-lift 900ms var(--ease) 60ms both; }
.js .stage__cta      { animation: mzc-nudge 620ms var(--ease) 320ms both; }

.js .stage .player__bar--t { animation: mzc-aperture-t 940ms var(--ease) 100ms both; }
.js .stage .player__bar--b { animation: mzc-aperture-b 940ms var(--ease) 100ms both; }

.js .stage .player__tick     { animation: mzc-tick 420ms var(--ease) both; }
.js .stage .player__tick--tl { animation-delay: 760ms; }
.js .stage .player__tick--tr { animation-delay: 800ms; }
.js .stage .player__tick--bl { animation-delay: 840ms; }
.js .stage .player__tick--br { animation-delay: 880ms; }

@keyframes mzc-nudge {
	from { transform: translateY(var(--travel)); }
	to   { transform: none; }
}

@keyframes mzc-lift {
	from { transform: translateY(var(--travel-lg)); }
	to   { transform: none; }
}

@keyframes mzc-tick {
	from { opacity: 0; transform: scale(.4); }
	to   { opacity: .75; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
	.js .stage .player,
	.js .stage__cta,
	.js .stage .player__tick {
		animation: none;
		opacity: 1;
		transform: none;
	}
	/* The aperture's end state is retracted. Hold it there. */
	.js .stage .player__bar--t { animation: none; transform: translateY(-100%); }
	.js .stage .player__bar--b { animation: none; transform: translateY(100%); }
}

/* --------------------------------------------------------------------------
   3. Track record

   The one block on this page the reference does not have. It is here because
   the client named these three figures and supplied them; it sits below the
   fold so that nothing comes between the video and the buttons, which is the
   part being replicated.

   A credentials strip and a numbered how-it-works sequence used to live here.
   Both were cut in v2.0.0 for the same reason.
   -------------------------------------------------------------------------- */

.stats {
	padding-block: clamp(38px, 5.5vw, 72px);
	border-top: 1px solid var(--line);
	background: linear-gradient(180deg, rgba(255, 255, 255, .018), transparent);
}

.stats__inner {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: clamp(24px, 4vw, 56px);
	text-align: center;
}

.stat {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	position: relative;
	padding-top: clamp(18px, 2.2vw, 26px);
	--step: 110ms;
}

/* The rule is a pseudo-element rather than a border because a border cannot be
   animated, and this one draws itself from the centre out as the band arrives.

   Drawn is the DEFAULT state, and it is only hidden under `.reveal-live` — the
   handshake main.js sets once the observer has actually fired. The failsafe in
   main.css restores opacity and transform on the [data-reveal] element itself,
   which a pseudo-element never sees; scoping it the other way round meant that
   in any environment where IntersectionObserver exists but never fires (headless
   renderers and some embedded webviews do exactly this) all three rules stayed
   at scaleX(0) permanently. Verified: without the handshake the rule is simply
   painted, no animation, nothing missing. */
.stat::before {
	content: "";
	position: absolute;
	top: 0;
	left: 50%;
	width: 34px;
	height: 2px;
	margin-left: -17px;
	/* --ink-3, not --accent. The figure below it is white; a white rule above a
	   white figure gives the mark and the number equal voice, and the number
	   should win. This was the one place where swapping red for white flattened
	   a hierarchy that the red had been carrying. */
	background: var(--ink-3);
	transform-origin: center;
}

.js.reveal-live .stat::before {
	transform: scaleX(0);
	transition: transform var(--dur) var(--ease) calc(260ms + var(--i, 0) * 110ms);
}

.js.reveal-live .stat.is-in::before { transform: scaleX(1); }

/* Tabular figures: "17+", "6,500+" and "$2B+" have very different digit counts,
   and proportional numerals make the three columns look mismeasured. */
.stat__figure {
	color: var(--ink);
	font-family: var(--display);
	font-size: clamp(30px, 4.4vw, 54px);
	font-variant-numeric: tabular-nums;
	line-height: 1;
	letter-spacing: .01em;
}

.stat__label {
	max-width: 14em;
	color: var(--ink-3);
	font-size: var(--t-small);
	line-height: 1.5;
	letter-spacing: .02em;
}

/* Two columns, not one. A single column turns three short figures into a tall
   scroll; the third simply centres itself across the row below. */
@media (max-width: 620px) {
	.stats__inner { grid-template-columns: repeat(2, 1fr); gap: 28px 20px; }
	.stat:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* --------------------------------------------------------------------------
   4. The Calendly popup

   Both booking buttons open Calendly's own modal (see assets/js/front.js).

   ONE RULE ONLY, AND THAT IS DELIBERATE.

   Earlier versions dressed this modal to match the reference: a white panel
   with a measured 10/10/42/42 frame, the popup resized to 1020x784 so the
   iframe kept its native 1000x700, and the close button moved inside the
   panel. It worked, and it is all gone, on the client's instruction to leave
   Calendly alone.

   Worth keeping the reason it was fragile, in case anyone is tempted again:

   - Padding the popup does not add a margin, it shrinks the widget.
     .calendly-popup-content is border-box with height:100%, so 42px of
     padding took the iframe from 1000x700 to 980x616. Calendly reads 616px
     as a short viewport, drops its two-column layout for a stacked one, and
     the stacked one scrolls. The frame cost a scrollbar.

   - Growing the panel instead requires !important on width, height,
     max-width and max-height, because Calendly ships all four with
     !important to defend the widget from host CSS. It also requires
     restating the transform, since theirs is a fixed pixel translate of half
     the default size and is wrong the moment the size changes.

   That is four !important declarations and two calc() expressions duplicating
   a magic size, all riding on a third-party embed that can change without
   notice. The backdrop below is the one override that touches nothing inside
   the iframe and so cannot break the booking flow.
   -------------------------------------------------------------------------- */

/* Doubled class on purpose: inc/enqueue.php registers Calendly's widget.css
   after this file, so a single .calendly-overlay would tie on specificity and
   lose on source order — which is exactly what happened between v2.0.0 and
   v2.6.0, where this override was written but never actually in effect.
   (0,2,0) settles it without depending on enqueue order. */
.calendly-overlay.calendly-overlay {
	background-color: rgba(5, 5, 5, .93);
	-webkit-backdrop-filter: saturate(120%) blur(4px);
	        backdrop-filter: saturate(120%) blur(4px);
}

/* ---- A 14px white edge, and why it is 14px --------------------------------
   Calendly's own "Privacy Policy" link sits hard in the bottom-left corner of
   its booking card. It lives inside their iframe, so it cannot be restyled
   from here; the only lever is to inset the iframe from the modal's edge.

   This was tried once and removed. In v2.6.1 the padding was added to
   Calendly's default 1000x700 popup, which shrank the iframe to 980x616 —
   Calendly reads that as a short viewport, drops its two-column layout for a
   stacked one, and the result is a narrow card floating in white with a
   scrollbar. That is the "extra column" that got it reverted, and the padding
   was the cause rather than the fix.

   So the panel grows by exactly the padding it gains. 1000 + 28 by 700 + 28
   leaves the iframe at its native 1000x700, the two-column layout intact and
   no scrollbar — the same arrangement that is on screen today, moved 14px in
   from the edge.

   14, not 42. The earlier attempt used 42px top and bottom copied from the
   reference's own modal, and that much white does read as a gutter. 14px is
   the smallest inset that stops the link touching the corner, which is the
   whole of what was asked for.

   !important is unavoidable: Calendly ships width, height, max-width and
   max-height on this element with !important, and the transform has to be
   restated because theirs is a fixed pixel translate of half the default size,
   which is wrong the moment the size changes.
   ------------------------------------------------------------------------- */
/* Horizontal only by default, and that is the important half: the link sits
   bottom-LEFT, so 14px of left inset is what lifts it off the edge. Width
   costs nothing — the modal is never width-constrained on a real screen. */
.calendly-overlay .calendly-popup {
	background: #ffffff;
	padding: 0 14px;
	border-radius: 10px;
	box-shadow: 0 40px 120px -28px rgba(0, 0, 0, .92);
	overflow: hidden;
}

.calendly-overlay.calendly-overlay .calendly-popup {
	width:      min(1028px, 96vw) !important;
	height:     min(700px, 94svh) !important;
	max-width:  min(1028px, 96vw) !important;
	max-height: min(700px, 94svh) !important;
	transform:  translate(-50%, -50%) !important;
}

/* Vertical inset only when the screen can spare it.
 *
 * Height is the constrained axis, not width, and it is the axis Calendly
 * switches layout on: at roughly 620px of iframe height it abandons the
 * two-column booking view for a stacked one that scrolls. Adding 28px of
 * vertical padding unconditionally would take a 720p laptop from 677px of
 * iframe to 649 and walk straight back toward that cliff — which is exactly
 * how the first attempt at this went wrong.
 *
 * So the panel only grows taller where there is room to grow into. Below
 * 780px the modal keeps every pixel of height it has today and gains the
 * horizontal breathing room alone, which still fixes the corner.
 */
@media (min-height: 780px) {
	.calendly-overlay .calendly-popup { padding: 14px; }

	.calendly-overlay.calendly-overlay .calendly-popup {
		height:     min(728px, 94svh) !important;
		max-height: min(728px, 94svh) !important;
	}
}
