/*
Theme Name: Hello Elementor Wykes
Template: hello-elementor
Version: 1.7.0
Description: Wykes Law child theme. Exists for one reason: to register the two Funnel
families the design actually uses, which Elementor's own 1667-family list does not contain.
*/

/* =========================================================== LAYOUT MEASURE
 * One cap and one gutter, stated once, used by the PHP header, the PHP footer,
 * single-service.php and the plugin's single-partner.php. Elementor's own bands
 * do NOT read these: they get the identical pair from the Kit, as
 * `--content-width: min(100%, var(--container-max-width))` on `.e-con`, which is
 * why the two systems line up on the same vertical without either one naming the
 * other's number.
 *
 * The pairing is the point. `max-width: var(--wykes-measure)` on a `width:100%`
 * child of a gutter-padded parent IS `min(100%, cap)`: above the cap the content
 * is 1440 and centred, below it the cap stops binding and the gutter takes over,
 * so there is no second number to drift. Writing the 1440 and the fallback as two
 * separate declarations is how the 326px review block and the 1031px hero-stats
 * numbers got stranded on this site.
 *
 * --wykes-measure mirrors the Kit's container_width (Kit post 6: 1440 / 1366 /
 * 1024 / 768 desktop / laptop / tablet / mobile). It is declared here so the
 * stylesheet is correct on its own, and overridden from the live Kit by
 * wykes_layout_tokens() in functions.php, so the Kit stays the single source.
 * The gutter ladder mirrors the Kit's container_padding and has no laptop rung,
 * because the Kit has none either — the desktop clamp covers 1025..1366.
 */
:root {
	--wykes-measure: 1440px;
	--wykes-gutter: clamp(24px, 2.5vw, 48px);
}

@media ( max-width: 1024px ) {
	:root { --wykes-gutter: clamp(20px, 3vw, 32px); }
}

@media ( max-width: 767px ) {
	:root { --wykes-gutter: clamp(16px, 5vw, 24px); }
}

/*
 * The boxed content line itself. Anything that must sit on the same vertical as
 * an Elementor band's `.e-con-inner` gets these three declarations.
 */
.wykes-header__inner,
.wykes-footer__inner,
.wykes-service__hero-inner,
.wykes-service__columns {
	box-sizing: border-box;
	width: 100%;
	max-width: var( --wykes-measure );
	margin-inline: auto;
}

/*
 * Band 2 service-card scrim.
 *
 * The design's overlay is a three-stop gradient. Elementor's background and
 * background-overlay gradient controls are two-stop only (one color, one
 * color_b, one stop each), and free Elementor has no Custom CSS control: the
 * runtime exposes `custom_css_pro`, a promo, so anything written to `custom_css`
 * is stored and ignored. No control can hold these three stops, so the rule
 * lives here. It is the only site-wide rule band 2 adds, one property on one
 * class that only band 2's overlay containers carry.
 *
 * The containers in that band also carry Elementor's own `e-no-lazyload` class.
 * Without it, modules/lazyload/module.php prints
 *   .e-con.e-parent:nth-of-type(n+2):not(.e-lazyloaded):not(.e-no-lazyload),
 *   .e-con.e-parent:nth-of-type(n+2):not(.e-lazyloaded):not(.e-no-lazyload) *
 *     { background-image: none !important }
 * and the second, descendant half of that selector matches this element through
 * an un-lazyloaded ANCESTOR. It is !important and more specific, so !important
 * here does not beat it; measured, the gradient was absent on all six overlays
 * until the band scrolled into view. The class has to be on every container
 * between the band and the overlay, which is why it appears five levels deep.
 */
.wykes-service-overlay {
	background-image: none;
	isolation: isolate;
}

/*
 * The user's ruling: the dim overlay is the REST state and it FADES OUT on
 * hover, so the photograph shows through clean. (This is deliberately the
 * reverse of the partner carousel, which is colour-at-rest / greyscale-on-
 * hover. Both directions are the user's explicit choice; do not harmonise.)
 *
 * `background-image` is not an animatable property, so the gradient cannot
 * live on the element and be transitioned. It moves to a ::before whose
 * OPACITY is transitioned instead. `isolation: isolate` on the overlay makes
 * it a stacking context, so `z-index: -1` on the pseudo-element puts the
 * gradient above the sibling image widget's photograph but still behind the
 * overlay's own children (the heading and the body copy), which are painted
 * in the same context at z-index auto.
 *
 * On the lazyload rule quoted above: it is `... :not(.e-no-lazyload) *`, and
 * `*` is a type selector for ELEMENTS. It cannot match a pseudo-element, so
 * moving the gradient to ::before puts it out of that rule's reach entirely.
 * That is asserted by paint, not assumed - see the report.
 *
 * The hover is keyed on the card anchor, not on the image widget. The
 * photograph is a sibling of the overlay, so the pointer is never inside the
 * image widget's subtree and Elementor's own `{{WRAPPER}}:hover` CSS-filter
 * control could never fire; that is why `css_filters_saturate` on the Image
 * widget is not the mechanism here even though the control exists and is used
 * elsewhere on this site. `:has()` selects the anchor without needing a new
 * CSS class written into twelve Elementor documents.
 */
.wykes-service-overlay::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	opacity: 1;
	background-image: linear-gradient(
		to bottom,
		rgba(55, 74, 97, 0) 10%,
		rgba(49, 64, 84, 0.5) 60%,
		#212a35 100%
	);
	transition: opacity 200ms ease;
}

/* Desaturated at rest, full colour on hover. The duration sits on the REST
 * declaration so the fade runs both ways. */
.elementor a.e-con:has(> .wykes-service-overlay) .elementor-widget-image img {
	filter: grayscale(1);
	transition: filter 200ms ease;
}
.elementor a.e-con:has(> .wykes-service-overlay):hover .wykes-service-overlay::before {
	opacity: 0;
}
.elementor a.e-con:has(> .wykes-service-overlay):hover .elementor-widget-image img {
	filter: grayscale(0);
}

/*
 * Band 4 partner-card specialism truncation.
 *
 * The design truncates the specialism line with an ellipsis on one line:
 * white-space:nowrap + overflow:hidden + text-overflow:ellipsis. Measured at
 * the rendered metrics, only card 5's string overflows (513px against 464px
 * of room); the contract expected card 3 to be the long one, but card 3
 * measures 405px and does not truncate. None of those three
 * properties has an Elementor control — the container `overflow` select is
 * hidden/auto only and applies to a container, not to the text node, and free
 * Elementor exposes `custom_css_pro`, a promo, so a per-widget rule is not
 * available. The rule therefore lives here, scoped to one class that only the
 * five specialism text widgets carry.
 *
 * It is set on the widget root and on its descendants because the text-editor
 * widget wraps its string in a <p>: text-overflow needs the property on the
 * box that both clips and contains the text.
 */
.wykes-truncate,
.wykes-truncate * {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/*
 * Band 4 chevron button height.
 *
 * `.elementor-icon` is inline-block (Elementor's own frontend.css), so inside
 * the icon widget's block wrapper it sits on the parent's text baseline and
 * the line box keeps the descender space below it. Measured: a 24px chevron
 * in a 8px-padded container rendered 40 wide and 47 tall against the design's
 * 40x40. No Elementor control sets display, line-height or vertical-align on
 * that wrapper — the icon widget has no typography section — and free
 * Elementor has no per-element Custom CSS. Making the wrapper a flex box
 * removes the line box entirely; the glyph's own 24x24 box is untouched.
 *
 * The rule has to land on `.elementor-icon`, not on the widget root: the icon
 * widget renders widget > .elementor-icon-wrapper > .elementor-icon, and
 * flexing only the root leaves the wrapper as a block that still builds a line
 * box around the inline-block (measured: 47px unchanged).
 */
.wykes-icon-flush .elementor-icon,
.wykes-icon-flush .elementor-button {
	display: flex;
}

/*
 * Band 5 adds .elementor-button to the same rule rather than a new one: the
 * cause is identical. The phone rows are button widgets (a real tel: anchor,
 * a 16px leading icon and the 8px gap, all from controls); .elementor-button
 * is inline-block, so the widget's block wrapper builds a line box and keeps
 * the descender space. Measured 35 tall against the design's 32. There is no
 * display, line-height or vertical-align control on the button widget wrapper.
 */

/*
 * Band 5 Contact Form 7 field styling.
 *
 * Contact Form 7 renders its own markup inside a `shortcode` widget, and that
 * widget's ONLY content control is `shortcode` (a textarea). Everything else on
 * it is the common Advanced tab — margin, padding, background, border, radius,
 * shadow, z-index — which styles the widget's own box and cannot reach a single
 * field. `custom_css_pro` is a promo raw_html, so a per-widget rule is not
 * available either. There is therefore NO control path to any of the rules
 * below; all eight exist because CF7's output is unreachable from Elementor.
 *
 * Every selector is scoped to .wykes-callback-form, a class this band puts on
 * the one shortcode widget. Nothing here is site-wide.
 *
 * The <br> rule is not cosmetic. CF7 runs its own autop over the form template,
 * which emits rows 2-4 and the submit as ONE <p> with <br> between them and a
 * <br> between every label's text and its field. Hiding those <br>s is what lets
 * the <p> become the 16px flex column the design specifies. The alternative was
 * to rewrite the form template, which would change a verified, already-created
 * form, so the styling absorbs it instead.
 */
.wykes-callback-form .wpcf7-form {
	display: flex;
	flex-direction: column;
	gap: 16px;
	/* containing block for the spinner, parked out of flow at the foot */
	position: relative;
}

.wykes-callback-form .wpcf7-form br {
	display: none;
}

/* rows 2, 3 and the submit: one 644 column, 16 apart */
.wykes-callback-form .wpcf7-form > p {
	display: flex;
	flex-direction: column;
	gap: 16px;
	margin: 0;
}

/* row 1: First Name + Last Name, 314 + 16 + 314 = 644 */
.wykes-callback-form .wykes-form-row > p {
	display: flex;
	flex-direction: row;
	gap: 16px;
	margin: 0;
}

.wykes-callback-form .wykes-form-row > p > label {
	flex: 1 1 0;
	min-width: 0;
}

/*
 * Label above field, 4 apart. line-height is 18, not the 20 the type spec
 * states: the card is 430 tall and its form stack is 310, which only closes if
 * each label+field block is 62 (18 + 4 + 40). The 20 is the token; 18 is the
 * height Figma's auto-height label node actually had. The measured box wins,
 * and the discrepancy is reported.
 */
.wykes-callback-form label {
	display: flex;
	flex-direction: column;
	gap: 4px;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 500;
	font-size: 14px;
	line-height: 18px;
	color: #6F7782;
}

/*
 * padding 9/13 pairs with the 1px border for a 10/14 total offset, the same
 * inside-stroke arithmetic as the 33 on the office divider. box-sizing is
 * stated because a form control does not inherit it.
 */
.wykes-callback-form input[type="text"],
.wykes-callback-form input[type="tel"],
.wykes-callback-form input[type="email"],
.wykes-callback-form select {
	box-sizing: border-box;
	width: 100%;
	background: #FFFFFF;
	border: 1px solid #E6EAF0;
	border-radius: 2px;
	padding: 9px 13px;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 14px;
	line-height: 20px;
	color: #0F172A;
}

.wykes-callback-form ::placeholder {
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 14px;
	line-height: 20px;
	color: #ACB1B7;
	opacity: 1;
}

/* style C: 644 wide, 40 tall (10 + 20 + 10, no border) */
.wykes-callback-form input[type="submit"] {
	box-sizing: border-box;
	width: 100%;
	background: #002D65;
	color: #FFFEFE;
	border: 0;
	border-radius: 2px;
	padding: 10px 32px;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 500;
	font-size: 14px;
	line-height: 20px;
	box-shadow: 0 2px 5px rgba(15, 23, 42, 0.05);
	cursor: pointer;
}

/*
 * Band 5: CF7's submit spinner out of flow.
 *
 * CF7 renders <span class="wpcf7-spinner"> as the submit's next sibling inside
 * the same autop <p>. Once that <p> is the design's 16px flex column the
 * spinner becomes a flex item: measured 24px tall plus a 16px gap, 40px of dead
 * space under the submit, which pushed the card to 470 against the design's 430.
 * The design has no loading state, but deleting the spinner would remove the
 * only submit feedback the form has, so it is taken out of flow instead and
 * parked over the submit's trailing edge. It stays visibility:hidden until
 * CF7 adds form.submitting.
 */
.wykes-callback-form .wpcf7-spinner {
	position: absolute;
	right: 8px;
	bottom: 8px;
	margin: 0;
}

/*
 * Service details: the fact-sheet form.
 *
 * This is a SECOND CF7 form (id 102, name + email). Its layout is identical to
 * the callback form's - label above field, 16px column, 9/13 field padding, 1px
 * #E6EAF0, radius 2 - so the widget carries BOTH classes and reuses every rule
 * above rather than duplicating them. `input[type="email"]` was added to the
 * shared field selector for the same reason: one more type, not one more rule.
 *
 * Only the submit differs. The callback form's is style C (#002D65). The
 * design's fact-sheet submit is style A: Golden/500 fill, Golden/50 label. The
 * two properties that differ are overridden here and nothing else is restated.
 * It comes after the style C rule and has one more class, so it wins on both
 * order and specificity.
 *
 * The 294 width is not written here: the field rule is already width:100% and
 * the sidebar card's padded content box is 342 - 24 - 24 = 294 by construction,
 * which is a container control, not CSS.
 */
.wykes-factsheet-form input[type="submit"] {
	background: #C5A059;
	color: #F9F6EE;
}

/* =====================================================================
 * SERVICE DETAIL LAYOUT  (single-service.php, post type `service`)
 *
 * This block is hand-written CSS by design, not by concession. The service page
 * stopped being an Elementor document when it became one template for six posts,
 * so there are no controls left to hold these numbers. Every value below is the
 * measured, signed-off geometry of the old /service-details/ document.
 *
 * Every selector is scoped to .wykes-service, a class only single-service.php
 * emits. Nothing here can reach another page.
 *
 * Breakpoints match the Kit's own: tablet <= 1024, mobile <= 767.
 * ===================================================================== */

.wykes-service {
	/* --wykes-gutter is NOT redeclared here. It used to be, as the desktop
	   clamp only, which shadowed the :root ladder at every width and put the
	   service hero 5.1px off the bands at 1024 and 5.25px off at 375. */
	--wykes-cream: #F9F7F2;
	--wykes-hairline: #E6EAF0;
	--wykes-ink: #444D5A;
	--wykes-ink-900: #20242A;
	--wykes-blue: #002D65;
}

/* ---- hero (632 tall, content at top 240) ---- */
.wykes-service__hero {
	position: relative;
	box-sizing: border-box;
	min-height: 632px;
	padding: 240px var(--wykes-gutter) 0;
	background-position: 50% 50%;
	background-size: cover;
	background-repeat: no-repeat;
}
.wykes-service__hero::before {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(35, 35, 35, 0.75);
}
.wykes-service__hero-inner {
	position: relative;
	/* width / max-width / margin-inline: see the shared boxed rule at the top. */
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 36px;
	padding: 0;
}
/*
 * NOT a new type rung. The title is 64px/72 at EVERY width - there is no
 * mobile size for it anywhere in this file - and at 320 the single word
 * "Separation" measures 335px. As a flex item of a column with
 * `align-items: center` and the initial `min-width: auto`, it was allowed to
 * exceed its 288px parent and was then centred on it, landing at left:-7.5
 * and pushing the document to scrollWidth 328.
 *
 * This is a PRE-EXISTING service-template defect, not a header/footer one. It
 * was invisible until now only because the footer's fixed-width legal columns
 * were pushing every page of the site to exactly the same 328.
 *
 * `anywhere`, NOT `break-word`. This was measured, not assumed: with
 * `overflow-wrap: break-word` the h1 stayed exactly 335px wide. The two
 * values differ in one way that matters here - `break-word` breaks a word only
 * AFTER the box has been sized, so it leaves min-content at 335, while
 * `anywhere` is taken into account when computing min-content. The h1 is a
 * flex item in a column container with `align-items: center`, so its width is
 * fit-content on the cross axis = min(max-content, max(min-content, 288)).
 * With min-content stuck at 335 that resolves to 335 and the fix did nothing.
 *
 * This is a CONTAINMENT GUARD, not the design fix. It stops the page
 * overflowing at any width and for any service name; it does not stop a 64px
 * word breaking mid-syllable at 320, which looks wrong. The proper fix is a
 * fluid title size (the rest of this site scales type with clamp()), and that
 * is a design decision about the service hero - flagged for a ruling rather
 * than invented here. `min-width: 0` is kept so the item can also shrink if
 * the container ever becomes a row.
 */
.wykes-service__title {
	min-width: 0;
	overflow-wrap: anywhere;
	margin: 0;
	text-align: center;
	color: #FFFEFE;
	font-family: "Funnel Display", sans-serif;
	font-weight: 500;
	font-size: 64px;
	line-height: 72px;
}
.wykes-service__subtitle {
	margin: 0;
	text-align: center;
	color: #ACB1B7;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 500;
	font-size: 20px;
	line-height: 28px;
}

/* ---- content band ---- */
.wykes-service__content {
	box-sizing: border-box;
	background: #FFFEFE;
	padding: 0 var(--wykes-gutter) 80px;
}
.wykes-service__columns {
	/* width / max-width / margin-inline: see the shared boxed rule at the top. */
	display: flex;
	flex-direction: row;
	align-items: flex-start;
	gap: 64px;
	padding: 0;
}

/* ---- sidebar: 342 fixed, 96 of top padding on the column not the band ---- */
.wykes-service__sidebar {
	box-sizing: border-box;
	flex: 0 0 342px;
	width: 342px;
	padding: 96px 0 0;
}
.wykes-service__card {
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	gap: 24px;
	padding: 24px;
	background: var(--wykes-cream);
	border-radius: 2px;
}
.wykes-service__block {
	display: flex;
	flex-direction: column;
	gap: 24px;
	padding: 0;
}
.wykes-service__side-h {
	margin: 0;
	color: var(--wykes-blue);
	font-family: "Funnel Sans", sans-serif;
	font-weight: 500;
	font-size: 20px;
	line-height: 28px;
}
.wykes-service__rule {
	margin: 0;
	border: 0;
	border-top: 1px solid var(--wykes-hairline);
	width: 100%;
	height: 0;
}
.wykes-service__toc {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 12px;
}
.wykes-service__toc a {
	color: var(--wykes-ink);
	text-decoration: none;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 16px;
	line-height: 24px;
}
.wykes-service__toc a:hover,
.wykes-service__toc a:focus-visible {
	text-decoration: underline;
}
.wykes-service__experts {
	display: flex;
	flex-direction: column;
	gap: 24px;
}
.wykes-service__person {
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: 12px;
}
.wykes-service__avatar {
	flex: 0 0 48px;
	width: 48px;
	height: 48px;
	display: block;
	object-fit: cover;
	object-position: center center;
	background: #D6CFB7;
	border: 1px solid rgba(0, 0, 0, 0.08);
	border-radius: 2px;
}
.wykes-service__person-txt {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	grid-template-rows: repeat(2, 24px);
	align-items: center;
}
.wykes-service__person-name,
.wykes-service__person-role {
	color: var(--wykes-ink);
	font-family: "Funnel Sans", sans-serif;
	font-size: 16px;
	line-height: 24px;
}
.wykes-service__person-name { font-weight: 500; }
.wykes-service__person-role { font-weight: 400; }

/* ---- rich text: 1034 wide, every top-level gap exactly 32 ---- */
.wykes-service__rich {
	box-sizing: border-box;
	flex: 1 1 auto;
	min-width: 0;
	width: 1034px;
	padding: 96px 0 0;
	display: flex;
	flex-direction: column;
	gap: 32px;
}
.wykes-service__crumbs {
	display: grid;
	grid-template-columns: auto 20px auto;
	grid-template-rows: 20px;
	gap: 4px;
	align-items: center;
	justify-items: start;
	justify-content: start;
	width: fit-content;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 14px;
	line-height: 20px;
}
.wykes-service__crumbs a { color: #ACB1B7; text-decoration: underline; }
.wykes-service__crumbs > span { color: #6F7782; }
.wykes-service__crumbs .wykes-service__icon { color: #ACB1B7; }
.wykes-service__lede {
	margin: 0;
	color: var(--wykes-ink);
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 20px;
	line-height: 28px;
}
/* ===================================================== prose (post_content)
 * The body of a service used to be four heading fields and four WYSIWYG fields
 * rendered into .wykes-service__section / .wykes-service__body. It is now
 * WordPress's own content editor, so the style hooks are element selectors, not
 * BEM classes: whatever the client types has to come out looking like the design.
 *
 * VERTICAL RHYTHM. The old geometry was two flex gaps - 32 between sections and 24
 * inside one. A flat prose stream has no sections, so the same two numbers are
 * reproduced with margins, and the reproduction is exact:
 *
 *     * + *      24    everything inside a section
 *     * + h2     32    a new h2 IS a new section
 *     p + p       5    paragraph spacing
 *
 * The one deliberate difference from the old template: paragraph spacing was 5px in
 * the introduction and 0px everywhere else, which is the Figma text block, not a
 * rule anyone could restate for free-form prose. Two paragraphs 0px apart read as
 * one paragraph. 5px now applies throughout; the measured cost is reported.
 *
 * MEASURE. Deliberately uncapped, by the client's decision on 2026-09-19.
 * A 58ch cap was shipped briefly and reverted: it capped the TEXT only, so at 1920
 * paragraphs rendered 522px while the headings, figures and lede beside them stayed
 * 1034px. Text that is half the width of the heading above it reads as a bug, and it
 * did - the client reported it on sight. The arithmetic behind the revert: at the
 * body's 16px, 522px is ~71 characters and 1034px is ~138. There is no width that is
 * both full-bleed and a readable measure at this font size, so the choice was between
 * a narrower column for everything and a long line. The client chose the long line.
 * Do not re-add a cap to the text alone. If the measure is revisited, narrow the
 * COLUMN - text, headings and figures together - or the same defect returns.
 * ========================================================================= */
.wykes-service__prose {
	color: var(--wykes-ink);
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 16px;
	line-height: 24px;
}

/* --- rhythm. Reset first, then state every gap out loud. --- */
.wykes-service__prose > * { margin: 0; }
.wykes-service__prose > * + * { margin-top: 24px; }
.wykes-service__prose > p + p { margin-top: 5px; }
.wykes-service__prose > * + h2 { margin-top: 32px; }

/* --- measure: uncapped on purpose, see the MEASURE note above --- */

/* --- headings --- */
.wykes-service__prose h2,
.wykes-service__prose h3,
.wykes-service__prose h4 {
	color: var(--wykes-ink-900);
	font-family: "Funnel Sans", sans-serif;
	font-weight: 500;
	scroll-margin-top: 24px;
}
.wykes-service__prose h2 { font-size: 24px; line-height: 32px; }
.wykes-service__prose h3 { font-size: 20px; line-height: 28px; }
.wykes-service__prose h4 { font-size: 18px; line-height: 26px; }

/* --- inline --- */
.wykes-service__prose a {
	color: var(--wykes-blue);
	text-decoration: underline;
	text-underline-offset: 2px;
}
.wykes-service__prose a:hover,
.wykes-service__prose a:focus-visible { text-decoration-thickness: 2px; }
.wykes-service__prose strong { font-weight: 600; color: var(--wykes-ink-900); }
.wykes-service__prose em { font-style: italic; }
.wykes-service__prose code {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: 14px;
	background: var(--wykes-cream);
	border-radius: 2px;
	padding: 1px 4px;
}

/* --- lists. An unstyled <ul> in the client's first edit is the failure mode. --- */
.wykes-service__prose ul,
.wykes-service__prose ol {
	padding-left: 24px;
	list-style-position: outside;
}
.wykes-service__prose ul { list-style-type: disc; }
.wykes-service__prose ol { list-style-type: decimal; }
.wykes-service__prose li { margin: 0; }
.wykes-service__prose li + li { margin-top: 5px; }
.wykes-service__prose li > ul,
.wykes-service__prose li > ol { margin-top: 5px; }
.wykes-service__prose ul ul { list-style-type: circle; }

/* --- an editor's blockquote. NOT the pull quote, which is [service_quote]. --- */
.wykes-service__prose > blockquote,
.wykes-service__prose > .wp-block-quote {
	box-sizing: border-box;
	border-left: 2px solid var(--wykes-blue);
	padding: 0 0 0 24px;
	color: var(--wykes-ink-900);
	font-size: 20px;
	line-height: 28px;
	font-style: italic;
}
.wykes-service__prose > blockquote > * { margin: 0; }
.wykes-service__prose > blockquote > * + * { margin-top: 8px; }
.wykes-service__prose > blockquote cite {
	display: block;
	font-size: 14px;
	line-height: 20px;
	font-style: normal;
	color: var(--wykes-ink);
}

/* --- figures: 1034 x 689.33 is aspect-ratio 720/480 at the column width.
   Native WordPress captions now, so the selector is the element, not a BEM class. --- */
/* :not(.wykes-service__quote) is load-bearing. Without it the 720/480 crop below
   matched the 48px avatar inside the pull quote's <figure> and blew it up to
   1026x684, which then pushed 78px of horizontal overflow onto every page at
   375, 768 and 1024. Measured, not theorised. */
.wykes-service__prose figure:not(.wykes-service__quote),
.wykes-service__prose .wp-block-image {
	box-sizing: border-box;
	margin-left: 0;
	margin-right: 0;
	display: flex;
	flex-direction: column;
	gap: 6px;
	width: 100%;
	max-width: 100%;
}
.wykes-service__prose figure:not(.wykes-service__quote) > img,
.wykes-service__prose .wp-block-image > img {
	display: block;
	width: 100%;
	max-width: 100%;
	height: auto;
	aspect-ratio: 720 / 480;
	object-fit: cover;
	object-position: center center;
	border-radius: 2px;
}
/* An inline image the client drops mid-paragraph is not a 720/480 crop. */
.wykes-service__prose p img {
	display: inline-block;
	width: auto;
	max-width: 100%;
	height: auto;
	aspect-ratio: auto;
	border-radius: 2px;
	vertical-align: middle;
}
/* NOT a grid. The old caption was `16px | 1fr` because the template printed the
   icon and exactly ONE <span>. A native caption is free inline content - here a
   text node and an <a> - which is TWO grid items, wraps to a second row and
   measured the caption at 46px instead of 20px on every width. A block with a
   hanging absolute icon takes any number of inline children. */
.wykes-service .wykes-service__prose figcaption:not(.wykes-service__quote-attr) {
	position: relative;
	display: block;
	margin: 0;
	padding-left: 22px; /* 16 icon + 6 gap, the old grid's two tracks */
	text-align: left;
	color: var(--wykes-ink);
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 14px;
	line-height: 20px;
}
/* The 16px link glyph the old wykes_service_figure() printed as inline SVG. A mask,
   not a background image, so it still takes currentColor. top:2px centres a 16px
   box in the 20px line box. */
.wykes-service .wykes-service__prose figcaption:not(.wykes-service__quote-attr)::before {
	content: "";
	position: absolute;
	left: 0;
	top: 2px;
	width: 16px;
	height: 16px;
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M10%2013a5%205%200%200%200%207.54.54l3-3a5%205%200%200%200-7.07-7.07l-1.72%201.71M14%2011a5%205%200%200%200-7.54-.54l-3%203a5%205%200%200%200%207.07%207.07l1.71-1.71%22%2F%3E%3C%2Fsvg%3E") no-repeat center / 16px 16px;
	mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22black%22%20stroke-width%3D%222%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M10%2013a5%205%200%200%200%207.54.54l3-3a5%205%200%200%200-7.07-7.07l-1.72%201.71M14%2011a5%205%200%200%200-7.54-.54l-3%203a5%205%200%200%200%207.07%207.07l1.71-1.71%22%2F%3E%3C%2Fsvg%3E") no-repeat center / 16px 16px;
}
.wykes-service .wykes-service__prose figcaption:not(.wykes-service__quote-attr) a { color: inherit; }
.wykes-service__icon { display: block; flex: none; }

/* ---- pull quote: [service_quote], rendered by wykes_service_quote_html() ---- */
.wykes-service__quote {
	/* No `margin: 0` here. It is the same specificity as the rhythm rule
	   `.wykes-service__prose > * + *` and sits later in the file, so it won it and
	   measured the quote flush against the figure above it - 0px where the design
	   has 24. The reset at the top of the prose block already zeroes it. */
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 24px;
	width: 100%;
}
.wykes-service__quote-text { margin: 0; border: 0; padding: 0; }
.wykes-service__quote-text > p {
	margin: 0;
	max-width: none;
	text-align: center;
	color: var(--wykes-ink-900);
	font-family: "Funnel Sans", sans-serif;
	font-weight: 500;
	font-style: italic;
	font-size: 24px;
	line-height: 32px;
}
.wykes-service .wykes-service__prose .wykes-service__quote-attr {
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: 12px;
	width: fit-content;
	margin: 0;
}
.wykes-service .wykes-service__prose .wykes-service__quote-attr::before { content: none; }
/* The avatar is a 48px square, not a 720/480 crop. Restated at this specificity so
   the prose image rule above can never reach it again. */
.wykes-service .wykes-service__prose img.wykes-service__avatar {
	flex: 0 0 48px;
	width: 48px;
	height: 48px;
	max-width: 48px;
	aspect-ratio: auto;
	object-fit: cover;
}

/* ---- conclusion callout: a Group block carrying the design class ---- */
.wykes-service__callout {
	box-sizing: border-box;
	width: 100%;
	max-width: 100%;
	padding: 24px;
	background: var(--wykes-cream);
	border-radius: 2px;
}
/* The conclusion heading measured 24/32 in the old template, which used the same
   .wykes-service__h as an h2. A general prose h3 is a sub-heading and stays 20/28;
   the callout's h3 keeps the signed-off size. */
.wykes-service__prose .wykes-service__callout h3 { font-size: 24px; line-height: 32px; }
.wykes-service__callout > * { margin: 0; }
.wykes-service__callout > * + * { margin-top: 16px; }
.wykes-service__callout > p + p { margin-top: 5px; }

/* ---- tablet <= 1024: the two columns stack ---- */
@media (max-width: 1024px) {
	.wykes-service__hero {
		min-height: 480px;
		padding: 140px clamp(20px, 3vw, 32px) 0;
	}
	.wykes-service__hero-inner { gap: 28px; }
	.wykes-service__content { padding: 0 clamp(20px, 3vw, 32px) 80px; }
	.wykes-service__columns { flex-direction: column; gap: 48px; }
	.wykes-service__sidebar { flex: 0 0 auto; width: 100%; padding-top: 64px; }
	.wykes-service__rich { width: 100%; padding-top: 48px; gap: 28px; }
}

/* ---- mobile <= 767 ---- */
@media (max-width: 767px) {
	.wykes-service__hero {
		min-height: 400px;
		/* 128, not the 96 this rung carried while the header was a stacked 84-tall
		   band. The header now overlays the hero at 104, and 96 put the h1's box
		   8px INSIDE it (measured at 767 and 375). 128 = 104 + 24, the mobile
		   gutter, so the clearance is a number the spacing scale already holds. */
		padding: 128px clamp(16px, 5vw, 24px) 0;
	}
	.wykes-service__hero-inner { gap: 20px; }
	.wykes-service__content { padding: 0 clamp(16px, 5vw, 24px) 64px; }
	.wykes-service__columns { gap: 32px; }
	.wykes-service__sidebar { padding-top: 48px; }
	.wykes-service__rich { padding-top: 40px; gap: 24px; }
}

/* ==========================================================================
 * HEADER AND FOOTER
 *
 * These replace everything that used to key off UAE/HFE's class names
 * (its dropdown, active-menu, toggle, menu-item and pointer-underline
 * classes - all prefixed with the plugin's own three letters, which is why no
 * such token survives a grep of this file). HFE is gone; the markup is
 * the child theme's own, in inc/header-footer.php.
 *
 * THE COLLAPSE THRESHOLD. It used to be wrong to write a breakpoint here,
 * because UAE owned the number and a hand-written @media would have been a
 * second copy that drifted. We own it now, so it is written once, at 1024,
 * and wykes-menu.js reads the SAME query through matchMedia rather than
 * comparing innerWidth - which would disagree with this file by the width of
 * a classic scrollbar.
 *
 * Every number below was read off the live UAE header and footer with
 * getComputedStyle before it was written here, not taken from the design file.
 * ========================================================================== */

/* -------------------------------------------------------------- header bar */
.wykes-header {
	position: relative;
	z-index: 100;
}

.wykes-header__bar {
	background-color: #00295C;
	box-shadow: 0 4px 2.5px 0 rgba( 0, 0, 0, 0.15 );
	/* The bar itself stays full-bleed - the navy has to reach both screen edges.
	   Only the inner is capped. The gutter is the token, so the header picks up
	   the tablet and mobile rungs it never had: it was pinned to the desktop
	   clamp at every width and sat 5.1px inside the bands at 1024 and 5.25px
	   outside them at 375. */
	padding: 12px var( --wykes-gutter );
}

/*
 * `1fr auto 1fr` and not a flex row with spacers: the nav must be centred on
 * the BAND, not on the space left over after the brand and the buttons, and
 * those two are different widths. The two 1fr tracks are equal by definition,
 * so the centre track is centred whatever the brand or the buttons do.
 *
 * The cap is now on, and lives in the shared boxed rule at the top of this
 * file - the inner is `min(100%, var(--wykes-measure))`, so it is 1440 centred
 * at 1920 and gutter-bound below that. This SETTLES the discrepancy the previous
 * revision flagged here: the user ruled the site boxed, so the logo does move
 * 192px inward at 1920, on purpose, onto the same vertical as every band.
 *
 * The note that revision left behind also mis-stated the cause. Checked against
 * the file rather than restated: in wykes-law.header.ir.json the `header-inner`
 * node already carries `content_width: "boxed"` AND `boxed_width: 1440`, so the
 * control was correctly set and its condition was met. The IR was right.
 *
 * The 1440 never reached a browser for a much duller reason - the header and
 * footer stopped being rendered from those documents. They are PHP now, in
 * inc/header-footer.php, and the PHP shipped no cap. Posts 28 and 81 are still
 * `publish`, but the live page contains zero `elementor-hf` nodes, so nothing
 * in either IR renders. A setting cannot take effect in a document that is no
 * longer on the page; the previous note diagnosed the control when the defect
 * was in the rebuild list.
 *
 * The separate trap is real and worth keeping, because it DID apply to the page
 * bands: `boxed_width` is conditional. container.php declares it with
 * `'condition' => [ 'content_width' => 'boxed' ]` and the runtime schema reports
 * `requires: {content_width: ["boxed"]}`, so on a `full` container the 1440 is
 * stored and silently ignored. qa.lintPlan's `unmet_condition` check catches
 * exactly that - but only when it is handed schemas, and it usually is not.
 */
.wykes-header__inner {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	gap: 24px;
}

.wykes-header__brand { display: flex; align-items: center; }

/*
 * `--wykes-logo-w` is set inline on .wykes-header__inner from the Customizer,
 * so the control needs no dynamic stylesheet and no inline <style> block.
 * height:auto rather than a second number: the source is 235x181 and two
 * independent numbers can disagree and distort the mark.
 */
.wykes-header__brand img,
.wykes-header__brand .custom-logo {
	display: block;
	width: var( --wykes-logo-w, 78px );
	height: auto;
}

.wykes-header__sitename {
	font-family: "Funnel Sans", sans-serif;
	font-weight: 700;
	font-size: 20px;
	line-height: 28px;
	color: #F9F6EE;
	text-decoration: none;
}

/*
 * THE PANEL WRAPPER. `display: contents` above the collapse point makes the
 * nav and the actions behave as direct grid items of .wykes-header__inner, so
 * the desktop layout is exactly the three-track grid above. At and below the
 * collapse point the same element becomes the full-screen overlay, with both
 * of them already inside it.
 *
 * This is why no script moves DOM nodes any more. The old implementation
 * lifted the action buttons into the nav on open and restored them on close,
 * tracked by a comment node, with a resize listener as a second trigger
 * because the first depended on a third-party plugin choosing to rewrite a
 * class attribute. A node that never moves cannot be lost.
 */
.wykes-header__panel { display: contents; }

.wykes-header__nav { grid-column: 2; }

.wykes-menu {
	display: flex;
	align-items: center;
	gap: 40px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.wykes-menu .menu-item { position: relative; margin: 0; }

.wykes-menu .menu-item > a {
	display: block;
	position: relative;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 500;
	font-size: 16px;
	line-height: 24px;
	color: #F9F6EE;
	text-decoration: none;
	transition: color 175ms ease;
}

/*
 * The current-page / hover underline.
 *
 * UAE drew this with its "creative menu" pointer, hard-coded to 3px at
 * bottom:0, which the old stylesheet then overrode to 2px at -6px. There is
 * no plugin to override now, so 2px and -6px are simply the values.
 *
 * A pseudo-element, not text-decoration and not a border: it is absolutely
 * positioned, so moving it 6px clear of the line box does not grow the
 * anchor, the menu item, or the 104px band.
 *
 * Both states share ONE object held at opacity 0, so the current-page line and
 * the hover line cannot get out of step.
 */
.wykes-menu .menu-item > a::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -6px;
	height: 2px;
	background-color: #C5A059;
	opacity: 0;
	transition: opacity 175ms ease;
}

.wykes-menu .menu-item > a:hover,
.wykes-menu .menu-item > a:focus-visible,
.wykes-menu .current-menu-item > a,
.wykes-menu .current_page_item > a,
.wykes-menu .current-menu-ancestor > a { color: #C5A059; }

.wykes-menu .menu-item > a:hover::after,
.wykes-menu .menu-item > a:focus-visible::after,
.wykes-menu .current-menu-item > a::after,
.wykes-menu .current_page_item > a::after,
.wykes-menu .current-menu-ancestor > a::after { opacity: 1; }

/* ------------------------------------------------------------ the two CTAs */
.wykes-header__actions {
	grid-column: 3;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 16px;
}

.wykes-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 500;
	text-decoration: none;
	white-space: nowrap;
	transition: background-color 175ms ease, color 175ms ease, border-color 175ms ease;
}

.wykes-btn--solid {
	font-size: 14px;
	line-height: 20px;
	padding: 10px 32px;
	border-radius: 2px;
	background-color: #C5A059;
	color: #F9F6EE;
	box-shadow: 0 2px 5px 0 rgba( 15, 23, 42, 0.05 );
}
/* #001938 on #A8853F is 5.09:1. */
.wykes-btn--solid:hover,
.wykes-btn--solid:focus-visible { background-color: #A8853F; color: #001938; }

.wykes-btn--ghost {
	gap: 12px;
	font-size: 16px;
	line-height: 24px;
	padding: 8px 20px;
	border-radius: 3px;
	background-color: transparent;
	color: #C5A059;
	border-left: 2px solid #C5A059;
}
.wykes-btn--ghost:hover,
.wykes-btn--ghost:focus-visible { background-color: #C5A059; color: #00295C; }

.wykes-btn__icon { flex: 0 0 auto; }

/* ----------------------------------------------------------- the hamburger */
/*
 * 44x44 is a hard floor, not the icon's size. UAE's toggle measured
 * 40.4 x 44.4 - under the 44px touch target on one axis, which is the kind of
 * miss that only shows up when it is measured. The bars are 24px inside a
 * 44px box; padding, not size, makes up the difference.
 */
.wykes-header__toggle {
	display: none;
	grid-column: 3;
	justify-self: end;
	width: 44px;
	height: 44px;
	padding: 0;
	margin: 0;
	border: 0;
	background: transparent;
	color: #F9F6EE;
	cursor: pointer;
	align-items: center;
	justify-content: center;
	/*
	 * Above the panel, which is z-index 9998. The toggle is the close control
	 * as well as the open control, so it must stay hittable over the overlay.
	 */
	position: relative;
	z-index: 9999;
}

/*
 * The icon is drawn from one element and two pseudo-elements so the X state
 * needs no second glyph and no icon font. currentColor throughout, so the
 * focus and hover colour rules reach it.
 */
.wykes-header__toggle-bars,
.wykes-header__toggle-bars::before,
.wykes-header__toggle-bars::after {
	display: block;
	width: 24px;
	height: 2px;
	background-color: currentColor;
	transition: transform 175ms ease, opacity 175ms ease;
}
.wykes-header__toggle-bars { position: relative; }
.wykes-header__toggle-bars::before,
.wykes-header__toggle-bars::after { content: ""; position: absolute; left: 0; }
.wykes-header__toggle-bars::before { top: -8px; }
.wykes-header__toggle-bars::after { top: 8px; }

/*
 * hello-elementor ships `[type="button"], [type="submit"], button` with
 * `border: 1px solid #c36; color: #c36` and a matching hover/focus state that
 * FILLS the control with #c36. At rest our own rule wins, but nothing here
 * declared a hover or focus background, so the first tap turned the hamburger
 * into a pink pill with a white X - caught in a screenshot of the open panel,
 * not by any computed-style check, because the resting state computes
 * correctly as transparent. Both interactive states are now stated out loud.
 */
.wykes-header__toggle:hover,
.wykes-header__toggle:focus,
.wykes-header__toggle:focus-visible,
.wykes-header__toggle:active {
	background: transparent;
	border: 0;
	color: #C5A059;
}

[aria-expanded="true"] .wykes-header__toggle-bars { background-color: transparent; }
[aria-expanded="true"] .wykes-header__toggle-bars::before { transform: translateY( 8px ) rotate( 45deg ); }
[aria-expanded="true"] .wykes-header__toggle-bars::after { transform: translateY( -8px ) rotate( -45deg ); }

/* ================================================= header over the hero
 * Figma gives the header TWO states. On the frames that open with a hero it
 * sits INSIDE the hero - transparent, no shadow, 104 tall. On Individual
 * Partner, the one frame with no hero, it is its own 84-tall #00295C band with
 * the drop shadow. The template ships the Partner state; this block is the
 * hero state.
 *
 * Driven by the `wykes-has-hero` body class, added in functions.php when the
 * page's own Elementor document carries the marker of the same name (or when
 * it is a single service, whose hero is in single-service.php). Unchanged by
 * the move off UAE - it never depended on the plugin.
 *
 * OVERLAY, not stacked: position:absolute takes the header out of flow, so the
 * hero starts at y=0. #page is position:static, so the containing block is the
 * initial one - document top, full width.
 */
body.wykes-has-hero .wykes-header {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
}

/* 16 + 72 + 16 = 104. The horizontal gutter is unchanged between the states. */
body.wykes-has-hero .wykes-header__bar {
	padding-top: 16px;
	padding-bottom: 16px;
	background-color: transparent;
	box-shadow: none;
}

/*
 * The hero state scales the logo to a fixed HEIGHT rather than to the
 * Customizer's width, because the 104px band height is a design constant and
 * is measured: 16 + 72 + 16. If the logo took its width here, raising the
 * width control would silently grow the band. width:auto keeps the mark
 * undistorted - it renders 93.5 x 72 from the 235x181 source.
 */
body.wykes-has-hero .wykes-header__brand img,
body.wykes-has-hero .wykes-header__brand .custom-logo {
	width: auto;
	height: 72px;
}

/* ====================================== tablet/mobile: the full-screen panel
 * The design has no mobile frame; this is the user's decision, not design
 * fidelity.
 */
@media ( max-width: 1024px ) {
	.wykes-header__inner {
		/* Brand left, hamburger hard right. The nav and the actions leave the
		   grid entirely - the panel stops being display:contents below. */
		grid-template-columns: 1fr auto;
	}

	.wykes-header__toggle { display: flex; grid-column: 2; }

	.wykes-header__panel {
		display: flex;
		position: fixed;
		top: 0;
		right: 0;
		bottom: 0;
		left: 0;
		z-index: 9998;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 32px;
		padding: 104px 24px 40px;
		overflow-y: auto;
		background-color: #00295C;
		/*
		 * Off-canvas rather than display:none, so the panel can animate and so
		 * its contents have a real box to measure. `inert` is applied by
		 * wykes-menu.js in the closed state - an off-canvas link is still
		 * tabbable, which is the classic invisible-focus trap.
		 */
		transform: translateX( 100% );
		visibility: hidden;
		transition: transform 200ms ease, visibility 0s linear 200ms;
	}

	html.wykes-menu-open .wykes-header__panel {
		transform: translateX( 0 );
		visibility: visible;
		transition: transform 200ms ease, visibility 0s;
	}

	.wykes-header__nav,
	.wykes-header__actions { grid-column: auto; width: 100%; }

	.wykes-menu {
		flex-direction: column;
		align-items: stretch;
		gap: 1px;
	}

	/*
	 * 54 tall and 1px apart, matching the geometry the UAE panel was measured
	 * at, so the panel is not silently redesigned by the port. The 1px gap is
	 * the divider.
	 */
	.wykes-menu .menu-item { background-color: #00295C; }
	.wykes-menu .menu-item > a {
		display: flex;
		align-items: center;
		justify-content: center;
		min-height: 54px;
		text-align: center;
	}

	/*
	 * bottom:0, not -6px. The items here are 1px apart and the divider lives in
	 * that 1px; at -6px the gold line sat 6px above it and the two read as a
	 * doubled rule. Screenshot-checked on the UAE build, and the reason is
	 * unchanged, so the value carries over.
	 */
	.wykes-menu .menu-item > a::after { bottom: 0; }

	.wykes-header__actions { justify-content: center; }
}

/*
 * The page behind a full-screen panel must not scroll.
 *
 * On <html> AND <body>: overflow:hidden on html alone is propagated to the
 * viewport and leaves body scrollable in some engines. Note for whoever
 * verifies this - window.scrollTo() STILL WORKS under overflow:hidden, so a
 * probe that uses it is a false pass. Prove the lock with real wheel input.
 */
html.wykes-menu-open,
html.wykes-menu-open body { overflow: hidden; }

/* ------------------------------------------------------------------ footer */
.wykes-footer {
	background-color: #00295C;
	/* Full-bleed navy; only .wykes-footer__inner is capped (shared boxed rule at
	   the top). This is the alignment the user pointed at: the wordmark used to
	   sit on the gutter at x=48 while the band above it started at x=240. */
	padding: 80px var( --wykes-gutter );
}

.wykes-footer__inner {
	display: grid;
	grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	/* One row, stated. An unstated row track lets the grid invent a second one
	   and double the band's height. */
	grid-template-rows: auto;
	gap: 32px;
	align-items: start;
}

.wykes-footer__left { display: flex; flex-direction: column; gap: 16px; }

.wykes-footer__wordmark {
	align-self: flex-start;
	font-family: "Funnel Sans", sans-serif;
	font-weight: 700;
	font-size: 24px;
	line-height: 32px;
	color: #F9F6EE;
	text-decoration: none;
	transition: color 175ms ease;
}
.wykes-footer__wordmark:hover,
.wykes-footer__wordmark:focus-visible { color: #C5A059; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
.wykes-footer__wordmark--image img { display: block; max-width: min( 280px, 100% ); height: auto; }

.wykes-footer__copy {
	margin: 0;
	max-width: min( 448px, 100% );
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 16px;
	line-height: 24px;
	color: #D7CFC3;
}

/*
 * THE LEGAL ROW - the 320px overflow, fixed.
 *
 * It was two fixed-width columns, 120px and 160px, in a `nowrap` flex row:
 * 120 + 32 + 160 = 312px inside a 288px content box at 320, which pushed
 * scrollWidth to 328 on EVERY page of the site, header and footer being global.
 *
 * `flex-wrap: wrap` with no fixed widths. The links are a client-editable
 * WordPress menu now, so the container must tolerate any number of items of
 * any length; a two-row grid with `grid-auto-flow: column` would have looked
 * right today and grown a third column off the side of the page the first time
 * a fifth link was added - the same bug in a new place.
 */
.wykes-footer__legal-list {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	column-gap: 32px;
	/*
	 * 0, not 12. The links below are inline-block with 12px of vertical padding
	 * to reach a 44px touch target, so the padding IS the row gap. Measured at
	 * 375 before this: 99x20 and 160x20 - less than half the 44px minimum, and
	 * slightly worse than the 24px the Elementor buttons gave.
	 */
	row-gap: 0;
	/* Cancel the first and last rows' padding so the list still aligns optically
	   with the wordmark opposite it, rather than sitting 12px low. */
	margin: -12px 0;
	padding: 0;
	list-style: none;
}

.wykes-footer__legal-list .menu-item { margin: 0; min-width: 0; }

.wykes-footer__legal-list a {
	font-family: "Funnel Sans", sans-serif;
	font-weight: 400;
	font-size: 16px;
	line-height: 24px;
	color: #D7CFC3;
	text-decoration: none;
	/* inline-block so the vertical padding creates a real 44px hit area; an
	   inline box's padding does not grow its border box for hit testing. */
	display: inline-block;
	padding: 12px 0;
	/* A single long label must break rather than set the container's floor. */
	overflow-wrap: break-word;
	transition: color 175ms ease;
}
.wykes-footer__legal-list a:hover,
.wykes-footer__legal-list a:focus-visible {
	color: #F9F6EE;
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}

@media ( max-width: 767px ) {
	/* Horizontal padding comes from --wykes-gutter; only the vertical differs. */
	.wykes-footer { padding-top: 64px; padding-bottom: 64px; }
	.wykes-footer__inner { grid-template-columns: minmax( 0, 1fr ); }
	.wykes-footer__legal-list { justify-content: flex-start; }
}


/*
 * Service-card anchor: remove the inherited link underline.
 *
 * Each card in the "How We Can Help" band (homepage band 3 and the Services
 * page) is a whole container wrapped in a link, so the element is an
 * `a.e-con`. hello-elementor's `.comments-area a, .page-content a` rule
 * (specificity 0,1,1) sets `text-decoration: underline` on it, and because
 * `text-decoration-color` resolves to `currentColor` and the anchor's own
 * colour is hello-elementor's `#c36`, the underline paints pink across the
 * card's heading and description. Measured on the live page before this rule:
 * text-decoration-line `underline`, text-decoration-color `rgb(204, 51, 102)`
 * on all six anchors. Elementor's own `.elementor a { text-decoration: none }`
 * is also 0,1,1 and loses on order.
 *
 * `.elementor a.e-con` is 0,2,1, so it wins on specificity and does not
 * depend on sheet order. The `*` half is belt-and-braces: text-decoration is
 * painted by the decorating box rather than inherited as a computed value, so
 * descendants already compute `none`; the extra selector only matters if a
 * descendant ever grows its own decoration.
 *
 * Scope: `a.e-con` is an anchor that is ALSO an Elementor container. Measured
 * across all five pages, the only twelve elements it matches are the six
 * service cards on the homepage and the six on the Services page. It cannot
 * reach an inline link — the footer legal links, the partner-card CTAs, the
 * tel:/mailto: links on Contact and the service-detail breadcrumbs are all
 * plain anchors and keep their underline.
 *
 * Only the decoration is removed. The href, the :focus-visible outline and
 * the card's hover behaviour are untouched.
 */
.elementor a.e-con,
.elementor a.e-con * {
	text-decoration: none;
}

/* =====================================================================
 * HOVER AND FOCUS SYSTEM
 *
 * The Elementor Button widget has a real hover tab (hover_color,
 * button_background_hover_*, button_hover_border_color,
 * button_hover_transition_duration) and every button's hover COLOUR is set
 * there, in the document, not here.  What is left for CSS is the three
 * things no control can express:
 *
 *   1. a hover text-decoration          (the hover tab has no such control)
 *   2. a :focus-visible ring            (no control at all, any widget)
 *   3. anything on a non-Elementor control - Contact Form 7's two submits,
 *      the plain <a> tel:/mailto: links, the service-detail template
 *
 * plus the reduced-motion guard, which has to cover both.
 *
 * Nothing below changes a padding, a border-width, a font or a dimension:
 * outline is out-of-flow by definition and text-decoration does not reflow,
 * so no hover moves a box.
 */

/* --- the ring -------------------------------------------------------------
 * hello-elementor ships `a:focus-visible, button:focus-visible { box-shadow:
 * 0 0 0 4px #fff; outline: 2px solid #000; outline-offset: 2px }` (0,1,1).
 * Measured on the service-card anchor that computed `outline: 2px solid
 * rgb(0,0,0)` - a black ring on a dark photograph, effectively invisible.
 *
 * One ring for the whole site: the gold the carousel already uses, 2px at
 * 2px offset, inside a #001938 halo.  The halo is not decoration - the gold
 * alone is 2.4:1 against the cream #FAF9F4 band behind "Protect your future",
 * short of the 3:1 that WCAG 1.4.11 asks of a focus indicator.  Painted with
 * box-shadow, which like outline takes no space: navy 0-2px, gold 2-4px,
 * navy 4-6px, whatever the surface.
 */
.elementor .elementor-button:focus-visible,
.elementor a.e-con:focus-visible,
/* QA: the header nav ring was hello-elementor's `outline: 2px solid #000` on
 * the #00295C bar - measured 1.56:1, effectively invisible. These five put
 * the header and footer on the site's single gold ring. Gold on #00295C is
 * 5.77:1 on its own; the #001938 halo carries it over the hero photograph,
 * where the backdrop is an image and no single figure can be quoted. */
.wykes-menu .menu-item > a:focus-visible,
.wykes-btn:focus-visible,
.wykes-header__toggle:focus-visible,
.wykes-header__brand a:focus-visible,
.wykes-footer a:focus-visible,
.wykes-callback-form input[type="submit"]:focus-visible,
.wykes-factsheet-form input[type="submit"]:focus-visible,
.elementor a[href^="tel:"]:not(.elementor-button):focus-visible,
.elementor a[href^="mailto:"]:not(.elementor-button):focus-visible,
.wykes-service__toc a:focus-visible,
.wykes-service__crumbs a:focus-visible {
	outline: 2px solid #C5A059;
	outline-offset: 2px;
	box-shadow: 0 0 0 6px #001938;
}

/* --- text CTAs: underline on hover ---------------------------------------
 * `wykes-cta-text` is written by the buttons' own _css_classes control onto
 * the seven text CTAs (footer wordmark, the four legal links, the two office
 * phone numbers).  Their hover COLOUR is a control; only the underline is
 * here.  Scoping to the class rather than to "any button in the footer"
 * keeps the next button added to that template out of it.
 */
.elementor .wykes-cta-text .elementor-button:hover,
.elementor .wykes-cta-text .elementor-button:focus-visible {
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}

/* --- the two Contact Form 7 submits --------------------------------------
 * CF7 renders its own <input type="submit">, so there is no widget and no
 * hover tab.  The rest styling is already above; these are the hover pairs.
 *
 * Both have to out-rank hello-elementor's reset, which is the reason the
 * carousel's chevrons were turning pink: `[type="submit"]:hover` is (0,2,0)
 * - the ATTRIBUTE selector counts as a class - not the (0,1,1) it reads
 * like, so it ties with a two-class selector and wins on being later.
 * These are (0,2,1) and (0,3,1) and win outright.
 */
/* hello-elementor's reset gives every [type=submit] `transition: all .3s`;
 * these two are the site's own buttons and take the site's 175ms. */
.wykes-callback-form input[type="submit"],
.wykes-factsheet-form input[type="submit"] {
	transition: background-color 175ms ease, color 175ms ease;
}
.wykes-callback-form input[type="submit"]:hover,
.wykes-callback-form input[type="submit"]:focus-visible {
	background: #001938;           /* Primary-blue/800; #FFFEFE on it = 17.44:1 */
	color: #FFFEFE;
}
.wykes-factsheet-form input[type="submit"]:hover,
.wykes-factsheet-form input[type="submit"]:focus-visible {
	background: #A8853F;           /* darker gold; #001938 on it = 5.09:1 */
	color: #001938;
}

/* --- service-card anchors -------------------------------------------------
 * The whole card is one `a.e-con`.  It had no hover state of its own: the
 * only thing that changed was hello-elementor's `a:hover { color: #336 }`,
 * invisible because every child sets its own colour.  The card's gradient is
 * NOT touched (it is blocked on a user ruling), so the affordance is the same
 * one the carousel card uses - the heading underlines.
 *
 * (0,4,1) against the (0,2,1) of the existing `.elementor a.e-con *
 * { text-decoration: none }` two blocks up, so it wins on specificity rather
 * than on being written later.
 */
.elementor a.e-con:hover .elementor-heading-title,
.elementor a.e-con:focus-visible .elementor-heading-title {
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}

/* --- plain tel:/mailto: links (Contact page) -----------------------------
 * Underlined at rest already; the hover is a colour.  Gold would be 2.44:1
 * on the white card these sit on, so on light surfaces the text CTAs move to
 * #00295C (14.17:1) instead.
 *
 * Selected by href rather than by widget: measured, these six links are inside
 * HEADING widgets on the Contact page, not the text-editor widgets the first
 * draft of this rule assumed, and the rule silently matched nothing.  The
 * :not() keeps it off the header's "Call Now", which is an .elementor-button
 * with a tel: href and is styled as a ghost button by its own hover controls.
 */
.elementor a[href^="tel:"]:not(.elementor-button):hover,
.elementor a[href^="mailto:"]:not(.elementor-button):hover,
.elementor a[href^="tel:"]:not(.elementor-button):focus-visible,
.elementor a[href^="mailto:"]:not(.elementor-button):focus-visible {
	color: #00295C;
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}
/* The duration belongs on the REST state, not inside the :hover block: a
 * transition is read from the state being entered, so declaring it only on
 * :hover animates the way in and snaps the way out. */
.elementor a[href^="tel:"]:not(.elementor-button),
.elementor a[href^="mailto:"]:not(.elementor-button) {
	transition: color 175ms ease;
}

/* --- service-detail template links ---------------------------------------
 * The TOC already underlined on hover and the breadcrumb already underlines
 * at rest; both only gain the colour, so the whole template speaks the same
 * language as the rest of the site.  Both surfaces are light, so both take
 * #00295C.
 */
.wykes-service__toc a:hover,
.wykes-service__toc a:focus-visible {
	color: #00295C;
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}
.wykes-service__toc a,
.wykes-service__crumbs a {
	transition: color 175ms ease;
}
.wykes-service__crumbs a:hover,
.wykes-service__crumbs a:focus-visible {
	color: #00295C;
}

/* --- reduced motion -------------------------------------------------------
 * `button_hover_transition_duration` puts `transition-duration: 175ms` on
 * `.elementor-NNN .elementor-button` - (0,2,0), from post-N.css, which loads
 * BEFORE this file but out-ranks a one-class selector - so the guard needs
 * !important to reach it.  That is the whole reason for the flag; it is not
 * used anywhere else in this stylesheet.
 *
 * Note for whoever checks this: `transition: none` does not compute to the
 * string "none".  getComputedStyle reports `all 0s ease 0s`; assert on
 * transitionDuration === '0s'.
 */
@media (prefers-reduced-motion: reduce) {
	.elementor .elementor-button,
	.elementor a.e-con,
	.elementor a.e-con *,
	.wykes-service-overlay::before,
	.elementor a[href^="tel:"]:not(.elementor-button),
	.elementor a[href^="mailto:"]:not(.elementor-button),
	.wykes-callback-form input[type="submit"],
	.wykes-factsheet-form input[type="submit"],
	.wykes-service__toc a,
	.wykes-service__crumbs a,
	.wykes-menu .menu-item > a,
	.wykes-menu .menu-item > a::after,
	.wykes-btn,
	.wykes-header__toggle-bars,
	.wykes-header__toggle-bars::before,
	.wykes-header__toggle-bars::after,
	.wykes-header__panel,
	.wykes-footer__wordmark,
	.wykes-footer__legal-list a {
		transition: none !important;
	}
}
