/* ============================================================================
   EUX Blocks — Good-Fit Matrix
   ----------------------------------------------------------------------------
   Cream qualifier section ("Is this service a good fit?"). Two-column
   layout: editable copy + 2x2 trait cards on the left, an animated SVG
   complexity-vs-systems matrix on the right.

   Defensive scoping — every selector starts with `.eux-block--good-fit`,
   both to beat Salient's blanket column / paragraph / heading defaults
   on specificity, and to stop our rules leaking onto other parts of
   the page.

   Layout note — !important on a handful of layout-critical properties
   (display, flex, grid) defends against Salient's high-specificity
   column-system CSS, which otherwise turns flex/grid contexts into
   block layouts. Same defensive pattern used elsewhere in eux-blocks.
   ============================================================================ */

.eux-block--good-fit { display: block; }

/* ==========================================================================
   Section padding + cream backdrop
   --------------------------------------------------------------------------
   Background is set as a class default. Editors who change it from the
   sidebar produce an inline `style="background:..."` on the wrapper,
   which wins over this rule via inline-style specificity — so the
   default doesn't need !important and won't fight editor choices.
   ========================================================================== */
.eux-block--good-fit {
	padding: 96px 0;
	background: var(--eux-cream-50);
}
@media (max-width: 720px) {
	.eux-block--good-fit {
		padding: 64px 0;
	}
}

/* ==========================================================================
   Two-column grid wrap
   --------------------------------------------------------------------------
   Source design uses 1.05fr / 1fr — left column slightly wider so the
   2x2 trait grid + heading sit comfortably. At <980px we stack.

   v0.17.0 note — TWO layout structures in play:
     - Legacy (pre-v0.17.0): .eux-fit__wrap > .eux-fit__left + .eux-fit__right
     - New (v0.17.0+):       .wp-block-columns.eux-fit__cols >
                              .eux-fit__col-copy + .eux-fit__col-mockup
   Both are styled below so the section keeps rendering correctly through
   the migration window.
   ========================================================================== */

/* --- LEGACY layout (pre-v0.17.0) --- */
.eux-block--good-fit .eux-fit__wrap {
	display: grid !important;
	grid-template-columns: 1.05fr 1fr;
	gap: 56px;
	align-items: start;
}
@media (max-width: 980px) {
	.eux-block--good-fit .eux-fit__wrap {
		grid-template-columns: 1fr;
		gap: 40px;
	}
}

/* --- NEW layout (v0.17.0+): core/columns reshape --- */
.eux-block--good-fit .wp-block-columns.eux-fit__cols {
	gap: 56px;
	align-items: flex-start;
	margin: 0;
}
.eux-block--good-fit .wp-block-columns.eux-fit__cols > .wp-block-column.eux-fit__col-copy {
	flex: 0 0 calc(51.2% - 28px); /* 1.05 / (1.05 + 1) ≈ 51.2% */
}
.eux-block--good-fit .wp-block-columns.eux-fit__cols > .wp-block-column.eux-fit__col-mockup {
	flex: 0 0 calc(48.8% - 28px); /* 1 / (1.05 + 1) ≈ 48.8% */
}
@media (max-width: 980px) {
	.eux-block--good-fit .wp-block-columns.eux-fit__cols {
		flex-direction: column;
		gap: 40px;
	}
	.eux-block--good-fit .wp-block-columns.eux-fit__cols > .wp-block-column.eux-fit__col-copy,
	.eux-block--good-fit .wp-block-columns.eux-fit__cols > .wp-block-column.eux-fit__col-mockup {
		flex: 1 1 auto;
		width: 100%;
	}
}

/* The new copy column needs the same vertical-stack treatment the
   legacy .eux-fit__left had. */
.eux-block--good-fit .wp-block-column.eux-fit__col-copy {
	display: flex !important;
	flex-direction: column !important;
}

/* ==========================================================================
   LEFT column — eyebrow / h2 / copy / meta / 2x2 trait grid
   ========================================================================== */
.eux-block--good-fit .eux-fit__left {
	display: flex !important;
	flex-direction: column !important;
}

/* Eyebrow — small purple uppercase. */
.eux-block--good-fit .eux-fit__eyebrow,
.eux-block--good-fit p.eux-fit__eyebrow {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	font-family: var(--eux-font-display);
	font-size: 12px;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--eux-woo-purple);
	margin: 0 0 18px;
	background: transparent !important; /* override Salient paragraph backgrounds */
}
/* v0.36.12 — Section-label dash. */
.eux-block--good-fit .eux-fit__eyebrow::before {
	content: '';
	display: inline-block;
	width: 28px;
	height: 1px;
	background: var(--eux-woo-500);
	flex: 0 0 28px;
}

/* H2 — large display weight 400 with negative tracking and a purple
   <em> accent. Same word-break + overflow-wrap reset as daas-slack so
   long compound words ("WooCommerce" etc.) stay intact regardless of
   Salient's `word-break: break-word` on columns. */
.eux-block--good-fit .wp-block-heading.eux-fit__title,
.eux-block--good-fit .eux-fit__title {
	font-family: var(--eux-font-display);
	font-weight: 400;
	font-size: clamp(32px, 4vw, 52px);
	line-height: 1.04;
	letter-spacing: -0.024em;
	margin: 0 0 18px;
	color: var(--eux-ink-900);
	text-wrap: balance;
	word-break: normal !important;
	overflow-wrap: normal !important;
	hyphens: none !important;
}
.eux-block--good-fit .eux-fit__title em {
	color: var(--eux-woo-purple);
	font-style: normal;
}

/* Body paragraphs. */
.eux-block--good-fit .eux-fit__copy,
.eux-block--good-fit p.eux-fit__copy {
	font-family: var(--eux-font-body);
	font-size: 16px;
	line-height: 1.6;
	color: var(--eux-ink-700);
	max-width: 60ch;
	margin: 0 0 14px;
}

/* Meta line — monospace, faint, small print. */
.eux-block--good-fit .eux-fit__meta,
.eux-block--good-fit p.eux-fit__meta {
	margin-top: 18px;
	font-family: var(--eux-font-mono);
	font-size: 11px;
	color: var(--eux-ink-500);
	background: transparent !important;
}

/* ==========================================================================
   TRAITS — 2x2 grid of trait cards
   --------------------------------------------------------------------------
   The grid wrapper is a core/group with class `eux-fit__traits`. Each
   card is a `core/group` with class `eux-fit__trait` and four core-block
   children: number paragraph, h4 heading, body paragraph, "Applies to
   you" paragraph (the purple ✓ is added via ::before so editors don't
   need to type it).

   Using compound selectors (.eux-fit__traits.wp-block-group) so we
   override the default `wp-block-group is-layout-flow` from core.
   ========================================================================== */
.eux-block--good-fit .eux-fit__traits.wp-block-group,
.eux-block--good-fit .eux-fit__traits {
	margin-top: 28px;
	display: grid !important;
	grid-template-columns: 1fr 1fr;
	gap: 14px;
	max-width: none;

	/* Grid items default to `align-items: stretch`, which makes each
	   card fill the height of the tallest card in its row. That was
	   the right default for the original design — the `.eux-fit__trait-chk`
	   footer carried `margin-top: auto` and pinned itself to the bottom
	   of the stretched card, so cards looked equal-height with no
	   visible empty space. Without the footer (when an editor removes
	   it), the stretch produces visible empty space at the bottom of
	   shorter cards. Setting `align-items: start` at the grid level
	   flips the default: cards size to their own content. The
	   `:has()` override below opts cards back into stretching when
	   they still carry the footer, so any existing pages using the
	   default template look unchanged. */
	align-items: start;
}
@media (max-width: 540px) {
	.eux-block--good-fit .eux-fit__traits.wp-block-group,
	.eux-block--good-fit .eux-fit__traits {
		grid-template-columns: 1fr;
	}
}

/* Individual trait card. The purple `::before` bar is the design
   accent — a 3px tall, 32px wide strip in the top-left corner that
   gives each card a small visual anchor. */
.eux-block--good-fit .eux-fit__trait.wp-block-group,
.eux-block--good-fit .eux-fit__trait {
	background: var(--eux-cream-50);
	border: 1px solid var(--eux-ink-100);
	border-radius: var(--eux-r-md);
	padding: 20px 22px 22px;
	display: flex !important;
	flex-direction: column !important;
	gap: 8px;
	position: relative;
	margin: 0 !important; /* core/group adds default vertical margins; reset */
}
.eux-block--good-fit .eux-fit__trait::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	height: 3px;
	width: 32px;
	background: var(--eux-woo-purple);
	border-radius: 0 0 4px 0;
}

/* --------------------------------------------------------------------------
   When the "Applies to you" footer IS present, restore the original
   stretch + pin-to-bottom behaviour.
   --------------------------------------------------------------------------
   The grid itself now defaults to `align-items: start` (see the
   .eux-fit__traits rule above), so cards size to their own content
   out of the box. That handles the "footer-less" case at the grid
   level — no per-card selector evaluation needed.

   The original design intent was: when every card carries the chk
   footer, all cards in a row stretch to equal heights and the
   footer's `margin-top: auto` pins itself to the bottom of each
   card — giving the grid a clean baseline along the chk line. This
   rule reinstates that behaviour only for cards that still carry
   the footer, so existing pages using the default template look
   unchanged.

   Why this shape and not the inverse (:not(:has()) → start):
   the previous version did the latter, which relied on the grid's
   default stretch and overrode it per-card for footer-less cards.
   That depended on `:has()` matching correctly to make the visible
   fix happen. This version inverts the dependency: the grid
   default itself is `start`, so the compact behaviour applies even
   if `:has()` fails to evaluate for any reason. The worst case
   when `:has()` doesn't resolve is footer-ed cards stay
   content-sized rather than stretching (a mild aesthetic
   regression for that specific case), instead of the much worse
   "fix didn't apply at all" outcome the inverse shape risked.

   :has() is supported in all major browsers since 2022-2023.
   Older browsers that don't recognise the selector fall through
   to the grid default (`align-items: start`), so footer-less
   cards still get the compact behaviour — the bug we shipped
   to fix.
   -------------------------------------------------------------------------- */
.eux-block--good-fit .eux-fit__trait:has(.eux-fit__trait-chk) {
	align-self: stretch;
}

/* Card number — large light-weight purple display digits. */
.eux-block--good-fit .eux-fit__trait-num,
.eux-block--good-fit p.eux-fit__trait-num {
	font-family: var(--eux-font-display);
	font-weight: 300;
	font-size: 36px;
	line-height: 1;
	letter-spacing: -0.04em;
	color: var(--eux-woo-purple);
	font-variant-numeric: tabular-nums;
	margin: 0;
	background: transparent !important;
}

/* Card heading — display, 500 weight, tight tracking. */
.eux-block--good-fit .wp-block-heading.eux-fit__trait-hd,
.eux-block--good-fit .eux-fit__trait-hd {
	font-family: var(--eux-font-display);
	font-weight: 500;
	font-size: 15px;
	line-height: 1.3;
	letter-spacing: -0.01em;
	color: var(--eux-ink-900);
	margin: 0;
}

/* Card body — body font, smaller and slightly muted. */
.eux-block--good-fit .eux-fit__trait-bd,
.eux-block--good-fit p.eux-fit__trait-bd {
	font-family: var(--eux-font-body);
	font-size: 12.5px;
	line-height: 1.55;
	color: var(--eux-ink-600);
	margin: 0;
	background: transparent !important;
}

/* "Applies to you" footer — mono, faint, with a purple ✓ added via
   ::before so the icon stays consistent across cards even if editors
   change the text. `margin-top: auto` pins it to the bottom of the
   card so cards align cleanly on a 2x2 grid even when card bodies
   differ in length. */
.eux-block--good-fit .eux-fit__trait-chk,
.eux-block--good-fit p.eux-fit__trait-chk {
	margin: auto 0 0 0 !important;
	font-family: var(--eux-font-mono);
	font-size: 11px;
	color: var(--eux-ink-500);
	display: inline-flex !important;
	align-items: center;
	gap: 6px;
	background: transparent !important;
}
.eux-block--good-fit .eux-fit__trait-chk::before {
	content: "\2713"; /* ✓ */
	color: var(--eux-woo-purple);
	font-family: var(--eux-font-display);
	font-size: 13px;
	font-weight: 700;
}

/* ==========================================================================
   RIGHT column — wrapper + matrix card
   ========================================================================== */
.eux-block--good-fit .eux-fit__right {
	display: flex !important;
	flex-direction: column !important;
}

.eux-block--good-fit .eux-fit__matrix {
	background: var(--eux-white);
	border: 1px solid var(--eux-ink-100);
	border-radius: var(--eux-r-lg);
	padding: 28px 32px 16px;
	box-shadow: 0 8px 32px rgba(0, 0, 0, 0.04);
}

.eux-block--good-fit .eux-fit__matrix-hd {
	display: flex !important;
	justify-content: space-between;
	align-items: baseline;
	margin-bottom: 16px;
	gap: 12px;
	flex-wrap: wrap;
}
.eux-block--good-fit .eux-fit__matrix-lbl {
	font-family: var(--eux-font-display);
	font-size: 11px;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--eux-ink-500);
}
.eux-block--good-fit .eux-fit__matrix-lbl--accent {
	color: var(--eux-woo-purple);
}

/* ==========================================================================
   SVG MATRIX — grid, axes, zone, "You" marker
   --------------------------------------------------------------------------
   The viewBox is 400x320 and the SVG scales fluidly with the container
   width. `overflow: visible` lets the "You" radiating ring spill outside
   the viewBox edge without being clipped (it scales up past r:14 during
   the f8Ring keyframe). All SVG element classes are namespaced
   `.eux-fit__svg-*` so they don't collide with anything else in the
   plugin.
   ========================================================================== */
.eux-block--good-fit .eux-fit__grid {
	position: relative;
	padding: 16px 0 24px 4px;
}
.eux-block--good-fit .eux-fit__grid svg {
	display: block;
	width: 100%;
	height: auto;
	overflow: visible;
}

/* Static visual properties (colour + stroke width). The drawing
   keyframes below use stroke-dashoffset + opacity to animate these
   into view. */
.eux-block--good-fit .eux-fit__svg-axis {
	stroke: var(--eux-ink-200);
	stroke-width: 1;
}
.eux-block--good-fit .eux-fit__svg-grid {
	stroke: var(--eux-ink-100);
	stroke-width: 1;
	stroke-dasharray: 3 3; /* dotted look once drawn */
}
.eux-block--good-fit .eux-fit__svg-label-x,
.eux-block--good-fit .eux-fit__svg-label-y {
	font-family: var(--eux-font-display);
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	fill: var(--eux-ink-500);
}
.eux-block--good-fit .eux-fit__svg-zone {
	fill: var(--eux-woo-50);
	fill-opacity: 0.85;
}
.eux-block--good-fit .eux-fit__svg-zone-stroke {
	fill: none;
	stroke: var(--eux-woo-purple);
	stroke-width: 1.2;
	stroke-dasharray: 4 3;
}
.eux-block--good-fit .eux-fit__svg-you {
	fill: var(--eux-woo-purple);
}
.eux-block--good-fit .eux-fit__svg-you-ring {
	fill: none;
	stroke: var(--eux-woo-purple);
	stroke-width: 1.5;
}
.eux-block--good-fit .eux-fit__svg-ann {
	font-family: var(--eux-font-display);
	font-size: 11px;
	font-weight: 600;
	fill: var(--eux-woo-purple);
}

/* ==========================================================================
   MATRIX ANIMATIONS — staggered drawing on first in-view, then a
   persistent pulse on the "You" dot.
   --------------------------------------------------------------------------
   The grid lines have a long `stroke-dasharray` and start with the same
   `stroke-dashoffset`, so they're invisible until the keyframe animates
   the offset back to 0 — classic "line draws itself" effect. The zone
   rectangle and "EUX zone" annotation fade in on top once the grid is
   established. Then the "You" dot pops in and starts its infinite
   pulse, with a radiating ring expanding outward from it.

   PAUSE GATING — the wrapper carries .eux-reveal which becomes
   .eux-is-in-view when the section scrolls into the viewport. We don't
   want the elaborate draw-in sequence to play silently before the user
   has scrolled to the section, and we don't want the looping pulse +
   ring to keep firing GPU work when the section is off-screen. Both
   are handled by `animation-play-state: paused` while the wrapper
   lacks `.eux-is-in-view` (see PAUSE block at the bottom).

   Same pause-rule trap documented in motion-and-reveal: the pause
   selector must check the same element the IntersectionObserver tags.
   .eux-reveal is on the section wrapper, so the pause check is on the
   wrapper too.
   ========================================================================== */

/* Initial (off-screen) state.
   --------------------------------------------------------------------------
   The matrix wrapper itself fades in at ~380ms delay over ~900ms (set up
   in animations.css via `.eux-block--good-fit.eux-is-in-view .eux-fit__matrix`),
   so the wrapper isn't fully visible until ~1.28s after `.eux-is-in-view`
   lands. The grid-draw choreography needs to START AFTER the wrapper is
   visible — otherwise the lines draw themselves behind an opacity:0 card
   and the user never sees the reveal. We anchor every grid/axis/zone/
   marker animation off a 1.3s base delay for that reason.

   Why opacity instead of stroke-dashoffset for the grid lines:
   the base `.eux-fit__svg-grid` rule on line 358 sets
   `stroke-dasharray: 3 3` to give a dotted look. The original draw-on
   technique overrode that to `stroke-dasharray: 600` so the dash could
   hide the full line length — but with `forwards` fill-mode and only
   `stroke-dashoffset` animated, the dasharray stayed at 600 after
   completion, producing a solid line, not the intended dotted finish.
   Switching the lines to an opacity fade-in (with a small stagger)
   preserves the `stroke-dasharray: 3 3` final state AND gives a clear
   visible reveal once the card is on-screen. Axes still use the
   stroke-dashoffset draw-on (no dotted final state desired on the
   solid axis lines). */
.eux-block--good-fit .eux-fit__svg-grid {
	opacity: 0;
	animation: euxFitFade 0.7s var(--eux-ease-out) 1.3s forwards;
}
.eux-block--good-fit .eux-fit__svg-grid:nth-of-type(2)  { animation-delay: 1.35s; }
.eux-block--good-fit .eux-fit__svg-grid:nth-of-type(3)  { animation-delay: 1.40s; }
.eux-block--good-fit .eux-fit__svg-grid:nth-of-type(4)  { animation-delay: 1.45s; }
.eux-block--good-fit .eux-fit__svg-grid:nth-of-type(5)  { animation-delay: 1.50s; }
.eux-block--good-fit .eux-fit__svg-grid:nth-of-type(6)  { animation-delay: 1.55s; }
.eux-block--good-fit .eux-fit__svg-grid:nth-of-type(7)  { animation-delay: 1.60s; }
.eux-block--good-fit .eux-fit__svg-axis {
	stroke-dasharray: 800;
	stroke-dashoffset: 800;
	animation: euxFitDraw 0.9s var(--eux-ease-out) 1.3s forwards;
}

/* Zone rectangle — fades in and scales up from 85% once the grid is laid down. */
.eux-block--good-fit .eux-fit__svg-zone {
	opacity: 0;
	transform-origin: 320px 95px;
	transform: scale(0.85);
	animation: euxFitZone 0.7s var(--eux-ease-out) 2.0s forwards;
}
.eux-block--good-fit .eux-fit__svg-zone-stroke {
	opacity: 0;
	stroke-dasharray: 520;
	stroke-dashoffset: 520;
	animation: euxFitStroke 1.2s var(--eux-ease-out) 2.1s forwards;
}

/* Labels + annotations — fade in. */
.eux-block--good-fit .eux-fit__svg-label-x,
.eux-block--good-fit .eux-fit__svg-label-y {
	opacity: 0;
	animation: euxFitFade 0.5s var(--eux-ease-out) 1.8s forwards;
}
.eux-block--good-fit .eux-fit__svg-ann {
	opacity: 0;
	animation: euxFitFade 0.5s var(--eux-ease-out) 2.5s forwards;
}

/* "You" dot — pops in with a slight bounce, then settles into an
   infinite pulse. We chain two animations: f8Pop (one-shot, forwards)
   then f8Pulse (infinite). The forwards fill-mode on Pop holds the
   final transform between the end of Pop and the start of Pulse so
   the dot doesn't snap. */
.eux-block--good-fit .eux-fit__svg-you {
	opacity: 0;
	transform-origin: 320px 80px;
	animation:
		euxFitPop   0.5s var(--eux-ease-out) 2.9s forwards,
		euxFitPulse 2.2s var(--eux-ease-in-out) 3.5s infinite;
}
.eux-block--good-fit .eux-fit__svg-you-ring {
	opacity: 0;
	transform-origin: 320px 80px;
	animation: euxFitRing 1.8s var(--eux-ease-out) 3.1s infinite;
}

@keyframes euxFitDraw   { to { stroke-dashoffset: 0; } }
@keyframes euxFitFade   { to { opacity: 1; } }
@keyframes euxFitZone   { to { opacity: 1; transform: scale(1); } }
@keyframes euxFitStroke { to { opacity: 1; stroke-dashoffset: 0; } }
@keyframes euxFitPop {
	0%   { opacity: 0; transform: scale(0); }
	70%  { opacity: 1; transform: scale(1.4); }
	100% { opacity: 1; transform: scale(1); }
}
@keyframes euxFitPulse {
	0%, 100% { transform: scale(1); }
	50%      { transform: scale(1.25); }
}
@keyframes euxFitRing {
	0%   { opacity: 0.8; transform: scale(0.7); }
	100% { opacity: 0;   transform: scale(2.4); }
}

/* ==========================================================================
   PAUSE-ON-OFFSCREEN
   --------------------------------------------------------------------------
   Pause every animation inside the matrix when the section wrapper
   isn't in view. The drawing animations start at frame 0 (invisible)
   and only run to completion once .eux-is-in-view lands — so the
   "matrix draws itself" reveal happens AT the user's scroll, not
   silently before. The infinite pulse + ring on the "You" marker stop
   chewing GPU when the section is scrolled away.

   The selector targets the wrapper that IntersectionObserver actually
   adds `.eux-is-in-view` to — i.e. the element carrying `.eux-reveal`,
   which in render.php is the section itself. If you ever move
   `.eux-reveal` onto a different element, update this rule to match —
   otherwise the matrix will stay paused forever (the v0.6.6 / v0.8.0
   bug pattern documented in motion-and-reveal).
   ========================================================================== */
.eux-block--good-fit:not(.eux-is-in-view) .eux-fit__grid * {
	animation-play-state: paused !important;
}

/* ==========================================================================
   Reduced-motion — kill the keyframes entirely so the matrix shows as
   a finished diagram. We collapse every animated property to its
   end-state by hand: stroke-dashoffset:0 makes lines fully drawn,
   opacity:1 makes everything visible, transform:none cancels the
   pulse/ring/zone-scale.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
	.eux-block--good-fit .eux-fit__grid * {
		animation: none !important;
		opacity: 1 !important;
		stroke-dashoffset: 0 !important;
		transform: none !important;
	}
}

/* ==========================================================================
   Editor preview tweaks
   --------------------------------------------------------------------------
   Inside Gutenberg the matrix renders at rest — we don't want the
   drawing sequence playing inside the canvas while authors are editing
   text. The `.eux-fit__matrix--editor` modifier on the wrapper kills
   every animation inside and snaps every element to its end state.
   ========================================================================== */
.editor-styles-wrapper .eux-block--good-fit {
	padding: 56px 0;
}
.editor-styles-wrapper .eux-block--good-fit[data-align="full"] {
	margin-left: 0;
	margin-right: 0;
}
/* Make focus outlines visible on the cream backdrop while editing. */
.editor-styles-wrapper .eux-block--good-fit .wp-block-heading:focus,
.editor-styles-wrapper .eux-block--good-fit .wp-block-paragraph:focus {
	outline: 1px dashed rgba(0, 0, 0, 0.18);
	outline-offset: 4px;
}
/* In-editor preview matrix: lines/zone/dot all rendered at rest. */
.editor-styles-wrapper .eux-block--good-fit .eux-fit__matrix--editor .eux-fit__grid * {
	animation: none !important;
	opacity: 1 !important;
	stroke-dashoffset: 0 !important;
	transform: none !important;
}
