/*
 * pm-contact — the contact page (WO-38, frame 90:4211).
 *
 * Compiled to assets/css/components/contact.css by src/build-tokens.mjs,
 * which substitutes the breakpoint markers (a comment holding `@bp <name>`)
 * with the pixel value from tokens/tokens.json. Custom properties cannot
 * resolve inside @media conditions and a bare integer is invalid CSS, so the
 * build appends the unit. Never type a breakpoint width here.
 *
 * Every colour is a --pm-color-* token; spacing, type sizes, leading and
 * tracking come from tokens/tokens.json. No hex value and no literal
 * breakpoint width may appear in this file. Values the token file does not
 * hold (the 612px panel, the 80px header term, the 40px nav-inset term) are
 * typed with a comment citing the extract key they come from — the same
 * technique as the button's 14px label and the header's 80px bar.
 *
 * The full-bleed technique is the header's own (header.css): the scaffold
 * body constrains content to a centred 72rem column with --pm-space-8
 * padding; the section escapes that box horizontally.
 */

.pm-contact {
	position: relative;
	box-sizing: border-box;
	/*
	 * WO-99 AC 13 — `clip`, and `hidden` must not come back.
	 *
	 * Both clip the same rectangle (the padding box; `overflow-clip-margin`
	 * defaults to zero), so the photo and the scrim are contained exactly as
	 * before. The difference is invisible until something animates:
	 * `overflow: hidden` makes this element a SCROLL CONTAINER, `overflow:
	 * clip` does not. A `view()` timeline resolves against its subject's
	 * nearest ancestor scroll container, and reveal.js's SELECTOR_MAP stamps
	 * `[data-pm-reveal]` on blocks INSIDE this one — so with `hidden` their
	 * timeline resolved against this element, which never scrolls, froze at a
	 * fixed progress, and the reveal simply never ran. Measured before the
	 * fix: 108 frozen instances across nine pages and four viewports, stuck
	 * between 0.91 and 1.0 progress. Visible, and never animating.
	 *
	 * If you are here because a block does not animate: this is the thing to
	 * check first, on this element and on every ancestor of the block.
	 */
	overflow: clip;
	width: 100vw;
	margin-inline: calc(50% - 50vw);
	/*
	 * 38-contact.json#measured.layout.padding — 24 top / 96 sides / 96
	 * bottom. The top term carries the overlay header band, so the panels'
	 * top edge lands at the frame's y 144: 80 (the built header's height,
	 * header.css) + 40 + 24 (this frame's own top padding) = 144. The 80
	 * and 40 are typed; 24 is --pm-space-6.
	 *
	 * WO-93 — the 40 here is the RESERVATION: the band the overlay header's
	 * own inset occupies (header.css's `top: 40px` on
	 * body.pm-header--overlay .pm-header,
	 * 93-contact-spacing.json#measured.header_block.padding_top). It is NOT
	 * a duplicate of that inset and it does not come out: delete it and the
	 * content row moves from 144 to 104, which is AC 1's second half
	 * (counter-review objection 9). Two numbers, two jobs, one page.
	 */
	padding: calc(80px + 40px + var(--pm-space-6)) var(--pm-space-24) var(--pm-space-24);
	font-family: var(--pm-font-family-base), system-ui, sans-serif;
}

/*
 * WO-38 — under the overlay header the bar is out of flow (header.css), so
 * the scaffold body's --pm-space-8 padding-top would show above the photo.
 * The section pulls itself up by that same token with the header's own
 * technique (header.css's margin-top), so it — not the scaffold padding —
 * starts at y 0. The homepage's in-flow negative header never matches this
 * rule and stays untouched.
 */
body.pm-header--overlay .pm-contact {
	margin-top: calc(-1 * var(--pm-space-8));
}

/*
 * The background layer: cover, behind the header and both panels,
 * decorative (alt="", WO-38 AC 2). The two-class selector beats Elementor's
 * `.elementor img { height: auto; max-width: 100% }` (MISTAKES.md §C15).
 *
 * WO-93 — element-agnostic: the layer is an <img> when only a poster/still
 * is set and a <video> when the client's background video is (counter-review
 * objection 10). Both branches are written out rather than collapsed to a
 * bare `.pm-contact .pm-contact__media`, because the img branch must keep
 * its (0,2,1) weight to beat `.elementor img`; a single (0,2,0) selector
 * would lose the img case again.
 */
.pm-contact img.pm-contact__media,
.pm-contact video.pm-contact__media {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The two panels (38-contact.json#measured.layout.columns): left 612px dark
 * panel + right flex-1 light panel, equal height — align-items: stretch is
 * what equalises them. The gap is --pm-space-10 (the frame's 40).
 */
.pm-contact__panels {
	position: relative; /* paints above the absolute media layer */
	display: flex;
	align-items: stretch;
	gap: var(--pm-space-10);
}

/*
 * The left panel — 38-contact.json#measured.left_panel: #000000, i.e. the
 * Texte palette entry via the surface-ink role (recorded as a contradiction
 * against Volcanic Ink; built as drawn), padding 48, gap 32.
 */
.pm-contact__panel--ink {
	display: flex;
	flex-direction: column;
	gap: var(--pm-space-8);
	flex: 0 0 612px;
	width: 612px; /* frame measurement, typed like the hero sidebar's 382px */
	padding: var(--pm-space-12);
	background-color: var(--pm-color-surface-ink);
	color: var(--pm-color-surface);
}

/*
 * The right panel — 38-contact.json#measured.right_panel: Blush Linen,
 * padding 48, gap 28 (--pm-space-7).
 */
.pm-contact__panel--form {
	display: flex;
	flex-direction: column;
	gap: var(--pm-space-7);
	flex: 1 1 auto;
	min-width: 0;
	padding: var(--pm-space-12);
	background-color: var(--pm-color-surface);
	color: var(--pm-color-ink);
}

/*
 * The section header inside the ink panel: eyebrow (rule + Caption Meta
 * accent — the pm-section-header pattern, 28-intro.json#measured.eyebrow),
 * the H1 and the intro.
 *
 * WO-93 — the gap is the frame's 16, not the 24 the build guessed:
 * 93-contact-spacing.json#measured.left_panel.blocks.section_header.gap
 * (node 90:4584, mapped to this class by the extract's dom_mapping). 16 is
 * --pm-space-4. The three children carry no margins, so the rendered
 * distance IS the gap (AC 3 measures the rendered distance).
 */
.pm-contact__header {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--pm-space-4);
}

.pm-contact__eyebrow {
	display: inline-flex;
	align-items: center;
	gap: var(--pm-space-4);
}

.pm-contact__eyebrow-rule {
	flex: none;
	width: 40px; /* the section-header pattern's rule (28-intro.json#measured.eyebrow.line) */
	height: 1px;
	background-color: var(--pm-color-accent);
}

.pm-contact__eyebrow-text {
	font-size: var(--pm-font-size-caption);
	font-weight: var(--pm-font-weight-400);
	line-height: var(--pm-leading-normal);
	letter-spacing: var(--pm-tracking-caption);
	text-transform: uppercase;
	color: var(--pm-color-accent);
}

/*
 * The page heading (WO-38 AC 3): Roboto Light 56 / 1 / -3 in White —
 * sentence case here on purpose: the frame is sentence case, so unlike the
 * hero no uppercase is applied. Below the design width the size scales
 * fluidly to the hero's 40px floor — at 375px a fixed 56px cannot fit the
 * viewport minus padding (the hero's clamp, resolving to exactly the token's
 * 56px at 1440px).
 */
.pm-contact__title {
	margin: 0;
	max-width: 510px; /* the hero H1's measure — the same 56px style */
	font-size: clamp(2.5rem, 7.5vw, var(--pm-font-size-h1));
	line-height: var(--pm-leading-tight);
	letter-spacing: var(--pm-tracking-h1);
	font-weight: var(--pm-font-weight-300);
	color: var(--pm-color-on-accent);
	overflow-wrap: break-word;
}

/* The intro: Body 16 / 1.6 in on-ink-muted (38-contact.json#measured
   .left_panel.section_header.body). 16px is typed like every recorded 16px
   before a size token exists. */
.pm-contact__intro {
	margin: 0;
	font-size: 1rem;
	font-weight: var(--pm-font-weight-300);
	line-height: var(--pm-leading-body);
	color: var(--pm-color-on-ink-muted);
}

/*
 * The company block (38-contact.json#measured.left_panel.company_block):
 * gap 8, the details read from Site::get() — nothing typed (WO-38 Result).
 */
.pm-contact__company {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--pm-space-2);
}

/* H4 Label 18 in Blush Linen (the extract's name style). */
.pm-contact__company-name {
	margin: 0;
	font-size: var(--pm-font-size-h4);
	font-weight: var(--pm-font-weight-400);
	line-height: var(--pm-leading-tight);
	color: var(--pm-color-surface);
}

/* VAT: Caption Meta uppercase in on-ink-muted. */
.pm-contact__company-vat {
	margin: 0;
	font-size: var(--pm-font-size-caption);
	font-weight: var(--pm-font-weight-400);
	line-height: var(--pm-leading-normal);
	letter-spacing: var(--pm-tracking-caption);
	text-transform: uppercase;
	color: var(--pm-color-on-ink-muted);
}

/* The three detail lines: 16px in Blush Linen; the mailto/tel links read as
   part of the line (the frame shows no link colour), so they inherit and
   gain an underline only on hover — developer judgement (MISTAKES.md §C7). */
.pm-contact__company-line {
	margin: 0;
	font-size: 1rem;
	font-weight: var(--pm-font-weight-400);
	line-height: var(--pm-leading-body);
	color: var(--pm-color-surface);
}

.pm-contact__company-line a {
	color: inherit;
	text-decoration: none;
	transition: color var(--pm-motion-duration-fast) var(--pm-motion-ease-standard);
}

.pm-contact__company-line a:hover,
.pm-contact__company-line a:focus-visible {
	color: var(--pm-color-accent-hover);
	text-decoration: underline;
}

/* The 1px rule between the company and talk blocks: White at 20%, the
   extract's rule-line.svg value (the divider-on-ink role). The selector is
   raised to (0,2,1) per MISTAKES.md §C15: Elementor's own
   `.elementor hr { background-color: transparent }` is (0,1,1) and beat the
   bare class, leaving the rule invisible on every Elementor-rendered page. */
.pm-contact hr.pm-contact__rule-line {
	flex: none;
	width: 100%;
	height: 1px;
	margin: 0;
	border: 0;
	background-color: var(--pm-color-divider-on-ink);
}

/*
 * The talk block — the title, its intro and the points list.
 *
 * WO-93 — the gap is the frame's 32, one uniform flex gap:
 * 93-contact-spacing.json#measured.left_panel.blocks.contact_details.gap
 * (node 90:4649, mapped to this class by the extract's dom_mapping). 32 is
 * --pm-space-8. The list's own 8px top margin goes with this change (see
 * .pm-contact__talk-points below): left in place it would render 40 where
 * the frame reads 32, and an acceptance criterion reading the `gap`
 * property alone would have passed that wrong page (counter-review
 * objection 6). Both rendered distances in this block are now 32.
 */
.pm-contact__talk {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--pm-space-8);
}

/* H3 Subtitle 24 White (the extract's title style). */
.pm-contact__talk-title {
	margin: 0;
	font-size: var(--pm-font-size-h3);
	font-weight: var(--pm-font-weight-300);
	line-height: var(--pm-leading-tight);
	letter-spacing: var(--pm-tracking-h3);
	color: var(--pm-color-on-accent);
}

.pm-contact__talk-intro {
	margin: 0;
	font-size: 1rem;
	font-weight: var(--pm-font-weight-300);
	line-height: var(--pm-leading-body);
	color: var(--pm-color-on-ink-muted);
}

/* The list's own row gap is the frame's 16
   (93-contact-spacing.json#measured.left_panel.blocks.discussion_points
   .gap, node 90:4631 — already correct in the build).

   WO-93 — the top margin is gone. It was --pm-space-2 (8), which added to
   the parent's old 24 gap to make 32 by accident; with the parent now
   carrying the frame's 32 as a real gap, the margin would make 40
   (counter-review objection 6). The block's spacing is the parent's gap
   alone. */
.pm-contact__talk-points {
	display: flex;
	flex-direction: column;
	gap: var(--pm-space-4);
	margin: 0;
	padding: 0;
	list-style: none;
}

/* Each point: 16px icon + 8px + H4 Label 18 in Powder Blush
   (38-contact.json#measured.left_panel.talk_block.point_style). */
.pm-contact__talk-points li {
	display: flex;
	align-items: flex-start;
	gap: var(--pm-space-2);
	font-size: var(--pm-font-size-h4);
	font-weight: var(--pm-font-weight-400);
	line-height: var(--pm-leading-tight);
	color: var(--pm-color-surface-alt);
}

/* The icon at its designed 16px; the descendant selector beats Elementor's
   `.elementor img` (MISTAKES.md §C15). The 2px top offset aligns the 16px
   box optically with the 18px first line — developer judgement. */
.pm-contact__talk-points .pm-contact__talk-icon {
	flex: none;
	width: 16px;
	height: 16px;
	margin-top: 2px;
}

/*
 * The form panel's heading: H3 Subtitle 24 in Volcanic Ink
 * (38-contact.json#measured.right_panel.title). The panel's --pm-space-7
 * gap separates it from the form below.
 */
.pm-contact__form-title {
	margin: 0;
	font-size: var(--pm-font-size-h3);
	font-weight: var(--pm-font-weight-300);
	line-height: var(--pm-leading-tight);
	letter-spacing: var(--pm-tracking-h3);
	color: var(--pm-color-ink);
}

/*
 * WO-38 AC 2 — below the laptop breakpoint (developer judgement, MISTAKES.md
 * §C7): one column, left panel first (DOM order), padding 24 sides. The
 * panels keep their own padding; only the section's side padding tightens.
 */
@media (max-width: 1024px) {
	.pm-contact {
		padding-inline: var(--pm-space-6);
	}

	.pm-contact__panels {
		flex-direction: column;
	}

	.pm-contact__panel--ink {
		flex: 0 1 auto;
		width: 100%;
	}
}

/*
 * Ticket 54 — the mailto/tel link's colour transition (line 218 above) had
 * no reduced-motion guard anywhere in this file. Colour is the one
 * accepted non-transform/opacity property (ticket 54 AC 3); reduced motion
 * still drops it so the link snaps instead of fading, like every other
 * colour transition in the theme.
 */
@media (prefers-reduced-motion: reduce) {
	.pm-contact__company-line a {
		transition: none;
	}

	/*
	 * WO-93 AC 6 — the background layer STAYS VISIBLE under reduced motion;
	 * what stops is the playing, and video.js already never calls play()
	 * for this visitor. A paused <video poster> shows its poster, which is
	 * exactly what the criterion asks the visitor to see.
	 *
	 * This rule exists because the media element borrows pm-video__video
	 * for its behaviour (Contact.php), and video.css's own reduced-motion
	 * block sets `.pm-video__video { display: none }` — right for WO-36's
	 * block, where a separate <img> poster layer sits underneath, and fatal
	 * here, where the video IS the layer and hiding it empties the page's
	 * whole background. video.css is not enqueued on this page today
	 * (Contact::get_style_depends()), so that collision is latent rather
	 * than live — and AC 6 must not rest on a sibling widget's absence
	 * (counter-review objection 1). (0,2,1) beats video.css's (0,1,0).
	 */
	.pm-contact video.pm-contact__media {
		display: block;
	}
}
