/**
 * Finewerk Services
 *
 * Scoped, BEM-style styles for the service-card grid with a CSS-only,
 * per-card hover interaction. All custom properties use the --fw-sv- namespace.
 *
 * Card surface
 * ------------
 * Every card carries the theme-level `fw-bg-gradient`
 * utilities, added in the markup — the same contract the FAQ and Steps cards
 * follow. That gradient IS the card surface, so this file paints no gradient,
 * no grain and no flat background of its own, and the whole surface stays
 * controllable centrally from the site styling. Because that surface is dark,
 * card text is white.
 *
 * The optional background panel (`.finewerk-services__bg`, one per widget,
 * around the whole grid) follows the very same contract — see its own section
 * below. It is only in the DOM when the toggle is on.
 *
 * That utility is a BACKGROUND detail and nothing more. Its grain
 * paints on `.fw-bg-gradient::after` at `z-index: -1` under an `isolation:
 * isolate` stacking context, i.e. above the card's own background and below
 * every child. The two content layers below therefore carry explicit positive
 * z-indexes (media 1, content 2) so the icon, title, description and hover
 * image always sit ABOVE any background layer, whatever the utilities paint.
 * Nothing here removes, duplicates or reorders those layers.
 *
 * Layout model
 * ------------
 * The card is a fixed-height positioning context. `.finewerk-services__content`
 * is an absolute box inset by the card padding; inside it, the movable
 * `.finewerk-services__content-group` is placed with `top` + `translateY`
 * driven by two custom properties (--fw-sv-cy / --fw-sv-cty). Because the
 * group is absolute and anchored by its TOP edge, the icon and title sit at an
 * identical vertical position on every card regardless of how much description
 * each one carries, and the description simply flows underneath the title:
 *
 *   default : cy 0%  + translateY(0)              — icon, title, description
 *                                                   aligned to the top padding
 *   hover   : cy 0%  + translateY(-1 * lift)      — the copy slides up by
 *                                                   exactly the icon block it
 *                                                   replaces, as the icon fades
 *
 * The lift is derived from the icon box size + its spacing (both Elementor
 * controls), so the title lands precisely where the icon was, at any icon size.
 *
 * Hover sequence (CSS-only, no front-end JavaScript):
 *   1. the icon fades out            — opacity, --fw-sv-duration
 *   2. title + description slide up  — transform, --fw-sv-duration
 *   3. the hover image slides in     — transform + opacity, --fw-sv-img-duration
 * The description travels WITH the title and stays fully visible throughout.
 *
 * The card is deliberately tall enough for the whole sequence: the normal
 * icon/title/description block, the upward travel, and the image arriving
 * below it without crowding the copy.
 *
 * The has/no-image and has-icon states are decided in PHP and expressed as
 * modifier classes, so no front-end JavaScript is involved.
 *
 * Column count is fixed here (max 3 on desktop, 2 tablet, 1 mobile) and is
 * intentionally not user-configurable so it can never exceed three per row.
 */

/* ------------------------------------------------------------------
 * Typography defaults (see assets/css/fonts.css)
 *
 * Hubot Sans for headings/titles/stat numbers, Archivo for everything
 * else. Declared at single-class specificity — the tag group through a
 * zero-specificity :where() — so an explicit Elementor Typography
 * control (which Elementor writes at element-id specificity) always
 * overrides it. No !important anywhere.
 * ---------------------------------------------------------------- */

.finewerk-services {
	font-family: var(--fw-font-body);
}

.finewerk-services :where(h1, h2, h3, h4, h5, h6) {
	font-family: var(--fw-font-title);
}

/* Form controls do not inherit the document font: the UA sheet gives
   button/input/select/textarea their own `font: 400 13.33px Arial`.
   Opt them back into the component's face. */
.finewerk-services :where(button, input, select, textarea, optgroup) {
	font-family: inherit;
}

.finewerk-services {
	--fw-sv-duration: 350ms;
	--fw-sv-ease: ease;
	--fw-sv-img-duration: 450ms;
	display: block;
	width: 100%;
}

/* ==========================================================================
   Optional background panel  (Style -> Cards Background -> Enable)
   ==========================================================================
   ONE panel around the WHOLE grid — never per card. It only exists in the DOM
   when the toggle is on; with it off nothing below applies and the element is
   unchanged.

   Surface: the markup adds the site-wide `fw-bg-gradient`
   utilities to this element, exactly as the cards do, and this file paints no
   gradient, no grain and no flat background of its own — neither effect is
   recreated here.

   Clipping is already correct without any extra work:
     - the gradient is a `background`, which the element's own border-radius
       clips by definition;
     - `fw-bg-gradient` paints its grain on `.fw-bg-gradient::after` with `border-radius:
       inherit`, so the grain follows this panel's ACTUAL radius, per corner.
   `overflow: hidden` is therefore deliberately NOT set: it would buy nothing
   for the two background layers and would clip card box-shadows and focus
   outlines at the panel edge.

   Stacking: the grain utility gives this element `isolation: isolate` and
   paints at `z-index: -1` — above its own background, below every child. The
   cards are in-flow children, so the whole surface sits behind all of them,
   and each card keeps its own independent gradient/grain layer untouched.

   Sizing: a plain block wrapping the flex grid. Its height comes from however
   many cards wrap into however many rows at the current breakpoint, plus the
   padding below — so it resizes naturally with the card count and the
   responsive column count, with no fixed dimensions anywhere.

   The values here mirror the Elementor control defaults, so the panel is
   correct even before any value is saved. */
.finewerk-services__bg {
	position: relative;
	box-sizing: border-box;
	padding: 48px;
	border-radius: 32px;
}

@media (max-width: 1024px) {
	.finewerk-services__bg {
		padding: 32px;
	}
}

@media (max-width: 767px) {
	.finewerk-services__bg {
		padding: 20px;
	}
}

.finewerk-services__list {
	--fw-sv-columns: 3;
	--fw-sv-col-gap: 24px;
	--fw-sv-row-gap: 24px;
	display: flex;
	flex-wrap: wrap;
	align-items: stretch;
	justify-content: center;
	column-gap: var(--fw-sv-col-gap);
	row-gap: var(--fw-sv-row-gap);
	width: 100%;
}

/* Cards keep a fixed one-third basis so full rows fill the width and any
   incomplete final row is centered by the list's justify-content.

   No background is declared here — see the file header: `fw-bg-gradient`
   owns the surface. */
.finewerk-services__card {
	--fw-sv-pad-top: 28px;
	--fw-sv-pad-right: 28px;
	--fw-sv-pad-bottom: 28px;
	--fw-sv-pad-left: 28px;
	--fw-sv-img-offset: 100%;
	--fw-sv-img-justify: center;
	/* Mirrors of the icon controls, so the lift below tracks the icon's real
	   size instead of a hardcoded guess. */
	--fw-sv-icon-box: 88px;
	--fw-sv-icon-gap: 24px;
	/* How far the copy travels on hover: exactly the icon block it replaces. */
	--fw-sv-lift: calc(var(--fw-sv-icon-box) + var(--fw-sv-icon-gap));
	/* Default vertical placement: top-aligned within the padded area. */
	--fw-sv-cy: 0%;
	--fw-sv-cty: 0px;
	/* `relative` + `overflow: hidden` give the absolute layers their containing
	   block and clip the hover image while it waits below the card edge. */
	position: relative;
	overflow: hidden;
	box-sizing: border-box;
	flex: 0 1 calc(
		(100% - (var(--fw-sv-columns) - 1) * var(--fw-sv-col-gap)) / var(--fw-sv-columns)
	);
	display: block;
	/* Room for the full sequence: content block + upward travel + the image
	   arriving underneath it. Deliberately roomier than the copy alone needs. */
	min-height: 420px;
	border-radius: 16px;
	text-decoration: none;
	/* Default state: every piece of text on the card is white. */
	color: #fff;
	transition: border-color var(--fw-sv-duration) var(--fw-sv-ease),
		box-shadow var(--fw-sv-duration) var(--fw-sv-ease);
}

/* Keyboard focus must be clearly identifiable. */
.finewerk-services__card:focus-visible {
	outline: 2px solid #fff;
	outline-offset: 3px;
}

/* ---------- Content layers ---------- */

/* Inset box: exactly the card's padded area. Does not move. z-index keeps the
   copy above the hover image AND above any background layer. */
.finewerk-services__content {
	position: absolute;
	top: var(--fw-sv-pad-top, 28px);
	right: var(--fw-sv-pad-right, 28px);
	bottom: var(--fw-sv-pad-bottom, 28px);
	left: var(--fw-sv-pad-left, 28px);
	z-index: 2;
}

/* Movable group: placed by the per-state variables and animated. Anchored by
   its top edge, so description length can never shift the icon or title. */
.finewerk-services__content-group {
	position: absolute;
	left: 0;
	right: 0;
	top: var(--fw-sv-cy, 0%);
	transform: translateY(var(--fw-sv-cty, 0px));
	transition: top var(--fw-sv-duration) var(--fw-sv-ease),
		transform var(--fw-sv-duration) var(--fw-sv-ease);
	will-change: top, transform;
}

/* ---------- Icon ---------- */

/* Fades out on hover while the group slides up behind it. It is the group's
   travel — not a collapsing wrapper — that frees the space, so the fade eases
   evenly over the whole duration instead of jumping partway through. */
.finewerk-services__icon-wrap {
	display: block;
	opacity: 1;
	transition: opacity var(--fw-sv-duration) var(--fw-sv-ease);
}

.finewerk-services__icon-box {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 88px;
	height: 88px;
	margin-bottom: 24px;
	border-radius: 14px;
	background-color: #fff;
	transition: background-color var(--fw-sv-duration) var(--fw-sv-ease);
}

.finewerk-services__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-size: 36px;
	line-height: 1;
	color: #123f3a;
	transition: color var(--fw-sv-duration) var(--fw-sv-ease);
}

.finewerk-services__icon svg {
	width: 36px;
	height: 36px;
	fill: currentColor;
}

/* ---------- Text ---------- */

.finewerk-services__title {
	display: block;
	margin: 0 0 12px;
	font-family: var(--fw-font-title);
	font-size: 1.25rem;
	font-weight: 700;
	line-height: 1.25;
	color: #fff;
	/* Guard against overflow from very long, unbroken titles. */
	overflow-wrap: anywhere;
	transition: color var(--fw-sv-duration) var(--fw-sv-ease);
}

/* Flows underneath the title and uses the space below it. It rides along with
   the title on hover and is never faded, collapsed, clipped or moved out of
   the card. */
.finewerk-services__description {
	display: block;
	margin: 0;
	font-size: 0.9rem;
	line-height: 1.5;
	color: #fff;
	overflow-wrap: anywhere;
	transition: color var(--fw-sv-duration) var(--fw-sv-ease);
}

/* ---------- Hover image ---------- */

/* Only rendered on cards that have an image. Definite-height layer anchored to
   the bottom of the card; carries the slide-up + fade and never intercepts
   pointer events. Sits behind the text so, in worst-case long content, the
   text stays readable — and above every background layer. */
.finewerk-services__hover-media {
	position: absolute;
	left: var(--fw-sv-pad-left, 28px);
	right: var(--fw-sv-pad-right, 28px);
	bottom: 0;
	height: 170px;
	max-height: 60%;
	z-index: 1;
	display: flex;
	align-items: flex-end;
	justify-content: var(--fw-sv-img-justify, center);
	opacity: 0;
	transform: translateY(var(--fw-sv-img-offset, 100%));
	pointer-events: none;
	transition: transform var(--fw-sv-img-duration) var(--fw-sv-ease),
		opacity var(--fw-sv-img-duration) var(--fw-sv-ease);
}

.finewerk-services__hover-image {
	display: block;
	width: 88%;
	height: 100%;
	max-width: 100%;
	object-fit: cover;
	object-position: top center;
	border-radius: 8px;
	box-shadow: 0 18px 40px rgba(0, 0, 0, 0.25);
}

/* ==========================================================================
   Expanded state
   ==========================================================================
   Icon fade, copy lift and image reveal, all triggered by the same states.
   Keyboard focus applies on every device; hover only on true hover devices.
   ========================================================================== */

/* --- Via focus (all devices) --- */

/* The lift is scoped to cards that actually render an icon: with no icon there
   is no gap to close, so their copy stays put. */
.finewerk-services__card--has-icon:focus-visible,
.finewerk-services__card--has-icon:focus-within {
	--fw-sv-cty: calc(-1 * var(--fw-sv-lift));
}

.finewerk-services__card:focus-visible .finewerk-services__icon-wrap,
.finewerk-services__card:focus-within .finewerk-services__icon-wrap {
	opacity: 0;
}

.finewerk-services__card--has-hover-image:focus-visible .finewerk-services__hover-media,
.finewerk-services__card--has-hover-image:focus-within .finewerk-services__hover-media {
	opacity: 1;
	transform: translateY(0);
}

/* --- Hover: only on true hover devices --- */

@media (hover: hover) and (pointer: fine) {
	.finewerk-services__card--has-icon:hover {
		--fw-sv-cty: calc(-1 * var(--fw-sv-lift));
	}

	.finewerk-services__card:hover .finewerk-services__icon-wrap {
		opacity: 0;
	}

	.finewerk-services__card--has-hover-image:hover .finewerk-services__hover-media {
		opacity: 1;
		transform: translateY(0);
	}
}

/* ---------- Reduced motion: keep the final positioning, drop the slide ---------- */

@media (prefers-reduced-motion: reduce) {
	.finewerk-services__content-group,
	.finewerk-services__icon-wrap,
	.finewerk-services__hover-media,
	.finewerk-services__card,
	.finewerk-services__icon,
	.finewerk-services__title,
	.finewerk-services__description,
	.finewerk-services__icon-box {
		transition: none;
	}
}

/* ---------- Responsive ---------- */

/* Tablet: max two per row. */
@media (max-width: 1024px) {
	.finewerk-services__list {
		--fw-sv-columns: 2;
	}
}

/* Mobile: one per row, no horizontal page overflow. */
@media (max-width: 767px) {
	.finewerk-services__list {
		--fw-sv-columns: 1;
	}

	.finewerk-services__card {
		flex-basis: 100%;
		max-width: 100%;
	}
}

/* ==========================================================================
   Version 2  (services-card-version2.png)
   ==========================================================================
   Same icon/title/description, restacked as a normal-flow flex column on a
   liquid-glass card, with a button pinned to the bottom. Everything V2 is
   scoped under the root's `is-fw-sv-v2` class; nothing above changes.

   Surface: the card carries the site-wide `.finewerk-liquid-glass` class in
   the markup (instead of gradient + grain) and this file paints no glass of
   its own — the same "background is not ours" contract V1 follows.

   Hover: V2 has no lift/fade/slide. The PHP omits the V1 state classes, so
   the variable-driven lift never engages, and the icon-fade rules (which key
   off :hover/:focus-within alone) are overridden below at higher specificity.
   The only V2 interaction is the button (next section).

   Button (service-card-btn-version2.png): a badge-plus-label whose geometry
   was measured from the two references — 48px tall, 14px corner radius in
   BOTH states. The arrow badge and the label never move; the ::before
   background layer simply widens from badge-size to the full button width,
   which reproduces the reference pill exactly (arrow stays centered in the
   first 48px, label gap and right padding already in place). One animated
   property, so the transition stays smooth on every frame.
   ========================================================================== */

.is-fw-sv-v2 {
	--fw-sv-btn-size: 48px;
	--fw-sv-btn-radius: 14px;
	--fw-sv-btn-bg: #c8f8a9;
	--fw-sv-btn-color: #000000;
}

/* Flex column so the content layer can stretch and pin its button bottom. */
.is-fw-sv-v2 .finewerk-services__card {
	display: flex;
	flex-direction: column;
	min-height: 380px;
	border-radius: 20px;
	/* Reference proportions; the (V2-scoped) Elementor controls override. */
	--fw-sv-pad-top: 40px;
	--fw-sv-pad-right: 40px;
	--fw-sv-pad-bottom: 40px;
	--fw-sv-pad-left: 40px;
}

/* The content layer leaves V1's absolute model: it becomes the card's normal
   padded column. The same --fw-sv-pad-* variables drive real padding here. */
.is-fw-sv-v2 .finewerk-services__content {
	position: static;
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-width: 0;
	padding: var(--fw-sv-pad-top, 40px) var(--fw-sv-pad-right, 40px) var(--fw-sv-pad-bottom, 40px) var(--fw-sv-pad-left, 40px);
}

.is-fw-sv-v2 .finewerk-services__content-group {
	position: static;
	transform: none;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	flex: 1 1 auto;
	transition: none;
	will-change: auto;
}

/* V1's icon fade keys off :hover / :focus-within alone — neutralized here so
   hovering a V2 card (or focusing its button) never touches the icon. */
.is-fw-sv-v2 .finewerk-services__card:hover .finewerk-services__icon-wrap,
.is-fw-sv-v2 .finewerk-services__card:focus-visible .finewerk-services__icon-wrap,
.is-fw-sv-v2 .finewerk-services__card:focus-within .finewerk-services__icon-wrap {
	opacity: 1;
}

/* Guaranteed breathing room between the copy and the bottom button even when
   the card is at its minimum height. */
.is-fw-sv-v2 .finewerk-services__description {
	margin-bottom: 32px;
}

/* ---------- V2 button ---------- */

.is-fw-sv-v2 .finewerk-services__btn {
	position: relative;
	display: inline-flex;
	align-items: center;
	align-self: flex-start;
	/* Pinned to the card bottom by the stretching group above it. */
	margin-top: auto;
	min-height: var(--fw-sv-btn-size);
	/* The expanded pill's right padding — present from the start, so nothing
	   has to reflow when the background reaches it. */
	padding-right: 26px;
	border: 0;
	background: none;
	text-decoration: none;
	color: var(--fw-sv-btn-color);
	font-size: 1rem;
	font-weight: 600;
	line-height: 1.2;
	cursor: pointer;
}

/* The expanding background layer: badge-sized at rest, full-width on hover.
   Radius is identical in both states (measured ~14px in both references). */
.is-fw-sv-v2 .finewerk-services__btn::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	width: var(--fw-sv-btn-size);
	border-radius: var(--fw-sv-btn-radius);
	background: var(--fw-sv-btn-bg);
	transition: width var(--fw-sv-duration, 350ms) cubic-bezier(0.33, 1, 0.36, 1);
	will-change: width;
}

/* Badge column: the arrow stays centered in it in both states. */
.is-fw-sv-v2 .finewerk-services__btn-icon {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 var(--fw-sv-btn-size);
	width: var(--fw-sv-btn-size);
	height: var(--fw-sv-btn-size);
}

.is-fw-sv-v2 .finewerk-services__btn-icon svg {
	width: 18px;
	height: 18px;
}

.is-fw-sv-v2 .finewerk-services__btn-label {
	position: relative;
	margin-left: 12px;
	white-space: nowrap;
}

/* Expanded via keyboard focus (all devices). */
.is-fw-sv-v2 .finewerk-services__btn:focus-visible::before {
	width: 100%;
}

/* Expanded via hover — card or button — only on true hover devices, the same
   gate V1's hover sequence uses, so touch taps never leave a stuck pill. */
@media (hover: hover) and (pointer: fine) {
	.is-fw-sv-v2 .finewerk-services__card:hover .finewerk-services__btn::before,
	.is-fw-sv-v2 .finewerk-services__btn:hover::before {
		width: 100%;
	}
}

.is-fw-sv-v2 .finewerk-services__btn:focus-visible {
	outline: 2px solid #fff;
	outline-offset: 3px;
}

/* Reduced motion: the pill still expands, just without the animation. */
@media (prefers-reduced-motion: reduce) {
	.is-fw-sv-v2 .finewerk-services__btn::before {
		transition: none;
	}
}
