/**
 * Pattern: Hero — Campaign  (patterns/hero-campaign.php)
 *
 * Figma home hero (10:277…10:348, frame 1:2, y0–899 @1440). One pattern =
 * one CSS partial (auto-enqueued by inc/enqueue.php's glob) — every rule for
 * this pattern, including its responsive media queries, lives here.
 *
 * ── DL-A (2026-09-11 design-sign-off delta, Sara's original file
 * rUGBn1NQQxBTR6vHwW3MMv, see design-deltas-2026-09-11.md rows DL1–DL8) ────
 * Band grew 846→899 (+53px); the copy block (h1/display/sub) moved up 25px
 * and the button row an *additional* 15px on top of that (40px total) — see
 * the padding-top/button-margin comments below for the exact math. **Scoped
 * to `@media (min-width: 1024px)`** — no comp exists below that width, so
 * mobile/tablet keep the pre-DL-A padding (round-1 gate finding: the
 * unscoped 290px padding-bottom left a dead pink slab under the stacked
 * bars column at 375/768). The H1 and the "Win $10,000!" display line both
 * gained a white outline (Figma's text stroke isn't exposed via the Dev
 * Mode API — no width value ships with the node — so `--dfd-hero-outline`
 * is a live-calibrated estimate, not a read spec value; see the property's
 * own comment for the two-round measurement history). Round 1 removed a
 * redundant text-shadow "fallback ring" that wasn't actually hidden under
 * the stroke (`-webkit-text-stroke` paints CENTRED on the glyph outline,
 * and `paint-order: stroke fill` only keeps the outer half visible) and
 * roughly doubled the intended weight. Round 2 (D24, 2026-09-11): Alain
 * reviewed and approved the *combined* stroke+ring render live, before
 * the ring was removed — so the single stroke was re-calibrated to
 * reproduce that same approved visual weight, measured empirically on both
 * renders (not derived from theory alone).
 * The raster background needed NO change: `cover` +
 * `background-position:center bottom` (existing, S1) already re-derives
 * "more image visible" purely from the container getting taller — that is
 * the whole point of the technique documented below, confirmed by
 * comparing the live 1440 render against the Figma screenshot of node
 * 10:277 post-change.
 *
 * ── Background — D21 (orchestrator decision, 2026-09-10) ─────────────────
 * A CSS `background-image` + `image-set()` on this plain full-bleed group —
 * NOT a `wp:cover` block — is the accepted technique for this pattern's
 * raster band background: the asset is a fixed theme file, not a
 * media-library upload (the P5 gate's portability rule — fixed brand photos
 * ship as theme assets, never attachment IDs/localhost URLs), and a cover
 * block pointed at a theme-path URL gets no srcset/webp/DPR handling from
 * core at all, only a single flat `<img src>`. CSS `image-set()` is what
 * gets the 1x/2x + WEBP/JPG resolution switching this band actually needs.
 *
 * The gradient/skyline PNG bleeds full-width behind BOTH the header and this
 * band (Figma bg rect 10:277 is 899px tall starting at y0, DL-A). DL-E gave
 * the header a transparent background and this pattern a negative top
 * margin equal to the header's height (see the file-header comment), so
 * the band's own DOM box now genuinely starts at y0 too — the header
 * really does sit on top of this same background image, not a visual
 * approximation of it. `background-position:bottom` on the raster (needed
 * regardless, for the "more sky shows as the band grows taller" behaviour
 * at every breakpoint) still does the right thing unchanged by that.
 *
 * ── Real fallback (round-1 gate fix — a later `background-image` value
 * does NOT catch a 404 on an earlier one; only a genuinely separate paint
 * source does) ─────────────────────────────────────────────────────────
 * `background-color` is the first line of defence (paints solid before
 * anything else resolves). The gradient is a SECOND, LOWER background-image
 * LAYER in the same comma-separated list as the raster (raster listed
 * first = on top; gradient listed second = underneath) — multiple
 * background-image layers load independently, so if the raster URL 404s
 * that layer simply paints nothing and the gradient layer beneath shows
 * through, with no `@supports`/cascade trickery needed. The `@supports`
 * block below only upgrades WHICH raster candidate is requested
 * (WEBP/2x via `image-set()`) for browsers that understand that syntax —
 * it is not what supplies the failure fallback. Verified live by renaming
 * the asset files so both requests 404 (see the S1 handoff for the
 * computed-style readback of the gradient showing through).
 */
.dfd-hero-campaign {
	/* DL-A round-2: --dfd-hero-outline is the CSS `-webkit-text-stroke` WIDTH,
	   not the visible ring width — see the file header note. Shared by both
	   .heading and .display below (Figma uses one flat stroke weight, not one
	   scaled per font size), hoisted here instead of duplicated. Calibrated
	   empirically (pixel-measured the "." of "Duck." at 1440, not the
	   half-the-stroke theory alone) against the combined stroke+fallback-ring
	   render Alain reviewed and approved live (D24, 2026-09-11) BEFORE the
	   ring was removed: that render's visible white fringe measured ~1.4px.
	   A stroke-only 6px (round-1's guess, measured off the static Figma
	   export instead of the live approved render) produced a ~2.7-3px
	   fringe live — too heavy. 3px reproduces the ~1.4px approved fringe
	   (measured live, same period, same technique). */
	--dfd-hero-outline: 0.1875rem; /* 3px stroke-width → ~1.4px visible fringe, matches D24 */
	/* ── DL-E (2026-09-12, Alain: "the hero should bleed into the nav") ──────
	   The header (parts/header.html) is now transparent and non-sticky
	   (global.css) and this band supplies the overlay: a negative top
	   margin equal to the header's OWN rendered height (--kd-mainbar-height,
	   tokens.css — single source of truth, responsive at ≤1024px) pulls the
	   band up to start at the page top (y0, behind the now-transparent
	   header), and the padding-top values below are grown by that same
	   amount so every copy element keeps its EXACT pre-DL-E absolute
	   position — the two changes cancel algebraically (box-top moves up by
	   the header's height while padding-top grows by the same amount, so
	   content measured from the box's own top lands at the same
	   page-absolute y). The band's total height grows by the header's
	   height while its BOTTOM edge is unchanged — the next section starts
	   at the same absolute y as before, untouched by this item. */
	--dfd-header-h: var(--kd-mainbar-height);
	/* margin-top itself lives on the scoped `.entry-content >
	   .dfd-hero-campaign:first-child` rule below, not here — see that
	   rule's own comment (gate round 1: an unconditional negative margin
	   on this class alone would still fire if the pattern were ever placed
	   somewhere other than the page's first section). */
	/* DL-F (2026-09-11, round-2 gate finding): zero out the WP global-padding
	   this alignfull group otherwise inherits (theme.json's root padding
	   clamp, capped at 144px @1920) — moved to .dfd-hero-campaign__inner
	   below via --kd-edge-pad instead. Doing it HERE would still be wrong:
	   this element is nested one level inside .entry-content, which ALSO
	   carries has-global-padding, so a percentage in --kd-edge-pad's own
	   `calc((100% - 1216px)/2)` term would resolve against entry-content's
	   already-shrunk content box (1617px @1920), not the true viewport width
	   (1905px @1920 post-scrollbar) — giving 200.5px instead of 344.5px
	   (confirmed live). Applying it one level down instead, on .inner (whose
	   containing block is THIS now-zero-padded, full-width alignfull box),
	   resolves the percentage against the right width — same non-nested
	   position the header/mainbar's own --kd-edge-pad usage is in. */
	padding-left: 0;
	padding-right: 0;
	position: relative;
	background-color: var(
		--kd-color-pink
	); /* solid paint before any layer resolves */
	background-repeat: no-repeat;
	background-size: cover, cover;
	background-position:
		center bottom,
		center bottom; /* crops the header-covered top slice, see above */
	background-image:
		url("../../images/hero-bg-1440.jpg"),
		linear-gradient(
			180deg,
			var(--kd-color-pink) 0%,
			var(--kd-color-surface) 100%
		);
}

/* Scoped rather than an unconditional `.dfd-hero-campaign { margin-top:
   ... }` (gate round 1 finding): this pattern is inserter-available, and
   an unconditional negative margin would still fire if it were ever
   placed somewhere other than the very top of the page, yanking the band
   up over whatever precedes it there instead of the header.
   `.entry-content > .dfd-hero-campaign:first-child` wins (0,3,0) over
   core's (0,2,0) on specificity alone (gate round 2) — no `!important`
   needed. */
.entry-content > .dfd-hero-campaign:first-child {
	margin-top: calc(-1 * var(--dfd-header-h));
}

/* Resolution/format upgrade only — NOT the failure fallback (see above).
   Still two layers, same order, so the mobile-crop override below (which
   only touches background-size) applies to either. */
@supports (background-image: image-set(url("a.jpg") 1x)) {
	.dfd-hero-campaign {
		background-image:
			image-set(
				url("../../images/hero-bg-1440.webp") 1x type("image/webp"),
				url("../../images/hero-bg.webp") 2x type("image/webp"),
				url("../../images/hero-bg-1440.jpg") 1x type("image/jpeg"),
				url("../../images/hero-bg.jpg") 2x type("image/jpeg")
			),
			linear-gradient(
				180deg,
				var(--kd-color-pink) 0%,
				var(--kd-color-surface) 100%
			);
	}
}

/* Mobile/tablet crop fix (round-1 gate finding #2, corrected round 2 — the
   round-1 fix introduced a real defect, not a designer question): the
   stacked band is far taller than it is wide (e.g. ~1195×375 at mobile), so
   `cover` scales the 1440:846 raster up until its HEIGHT matches the
   container, cropping most of its WIDTH — confirmed live the checkered
   tower (left edge) and the ferris wheel (right edge, the design's other
   signature silhouette besides the palms) both fall outside the centred
   crop window at 375 and 768, leaving only the centre mountain.
   Round 1 fixed this with `100% auto` (full width, no crop) but that left
   the raster shorter than the band, exposing a hard seam where the
   full-height fallback gradient (a different lavender/pink than the
   raster's own top edge at that exact size) showed above it — a real visual
   defect, confirmed in the round-1 375 screenshot.
   Round 2: `auto 100%` instead — the raster fills the band's full HEIGHT
   (same height as the gradient layer beneath it, so there is no exposed
   gradient strip and no seam), and is allowed to crop horizontally instead.
   Position tuned to **80%**, not the 68% first suggested: the exported
   asset's own aspect ratio (3375×2625 source ⇒ 1440×1120 / 2880×2240,
   ≈1.286) is narrower than the design band's own 1440×846 (≈1.702), so at
   `auto 100%` the rendered image is proportionally WIDER relative to a
   375–768px window than a hand-computation off the band's own aspect would
   predict — 68% landed short and still cropped the ferris wheel out.
   Confirmed empirically (live `background-position` override + screenshot
   at both 375 and 768, not computed blind): 80% keeps the ferris wheel
   fully on-screen at both widths, with the mountains and several palms
   still visible alongside it at 768 (375's narrower window loses most of
   the mountain, keeping the wheel + nearer palms — the wheel is the
   priority, per the gate). The checkered tower (far left) crops off at
   both — acceptable, per the gate. Scoped to the same ≤1023.98px range
   this pattern already stacks the copy/bars columns at. */
@media (max-width: 1023.98px) {
	.dfd-hero-campaign {
		background-size:
			auto 100%,
			cover;
		background-position:
			80% bottom,
			center bottom;
	}
}

/* Figma-derived, not the generic --dfd-section-pad clamp (104px @1440
   would overshoot the comp's own 42px top inset — this hero is pixel-match
   at 1440, so its own one-off band geometry wins over the shared token).
   Pre-DL-A values, unscoped — this is what mobile/tablet (<1024px, no comp)
   still use; see the @media(min-width:1024px) block below for the DL-A
   desktop numbers. 67px = old h1 top (263) − header height (196,
   --kd-mainbar-height). 197px = hand-summed content height under-measured
   the real rendered flow by ~7px vs the 846px band; bumped to close the gap
   after live measurement (verify note, S1).
   DL-E: padding-top grown by --dfd-header-h (96px in this mobile/tablet
   range) — see the overlay comment above; padding-bottom is untouched
   (the band's bottom edge, and everything after it, doesn't move). */
.dfd-hero-campaign {
	padding-top: calc(var(--dfd-header-h) + 4.1875rem); /* 96px + 67px */
	padding-bottom: 12.3125rem; /* 197px */
}

/* DL-A (2026-09-11), desktop only — round-1 gate finding: the new padding
   is NOT a global change. No comp exists below 1024px, and applying the
   290px padding-bottom there left a dead pink slab under the
   mobile/tablet-stacked bars column (confirmed live at 375: band 967px
   tall, ~290px of empty band below the bars). Scoped to the same
   min-width:1024px breakpoint the bars-column grid already switches at.
   h1 top moved 263→238, band 846→899.
   42px = h1 top (238) − header height (196, --kd-mainbar-height).
   283px = band bottom (899−196=703 local) − buttons bottom (616−196=420
	local; button row top 542 + height 74 = 616) — formulaic base, then
	live-verified/adjusted the same way the pre-DL-A 197px value was
	   (see git history): hand-summed flow vs the real rendered box model.
   DL-E: padding-top grown by --dfd-header-h (196px in this >=1024 range).
   padding-bottom untouched -- the band's bottom edge doesn't move, so 899
   total (196 reclaimed from the header + the pre-DL-E 703 band) falls out
   automatically: (196+42) + content + 290. */
@media (min-width: 1024px) {
	.dfd-hero-campaign {
		padding-top: calc(var(--dfd-header-h) + 2.625rem); /* 196px + 42px */
		padding-bottom: 18.125rem; /* 290px — round-1 live check (1440, getBoundingClientRect):
			the 283px formulaic value under-measured the real rendered flow by ~7px vs
			the 899px target, same DynaPuff-leading-vs-Figma-box-height drift the
			pre-DL-A 197px value already documented (h1/win/sub each render a few px
			shorter than their Figma text-box height) — bumped to close the gap,
			verified live. */
	}
}

/* Neutralise WP's default block-gap margin on this pattern's own nested
   groups (same footgun documented in every sibling pattern's handoff) —
   every gap here is explicit, not WP's blockGap. */
.dfd-hero-campaign__inner,
.dfd-hero-campaign__copy > * {
	margin-top: 0;
}

/* ── Row: copy column + bars column ──────────────────────────────────────
   `layout:{"type":"default"}` on the wp:group (not WP's native flex/grid
   support) so this stays a plain CSS grid — no blockGap to neutralise.
   WP's constrained-layout support still forces `margin-inline:auto
   !important` on any direct child of an `.is-layout-constrained` parent
   narrower than the content column (P4/P8 precedent) — this row (1010px
   at the desktop lock) IS narrower than the 1216px column, so it needs the
   matched-specificity override below to stay flush at the column's left
   edge instead of being auto-centred. */
.dfd-hero-campaign__inner {
	display: block;
	margin-left: 0 !important;
	/* DL-F: the site's shared content-column gutter, moved here from the
	   alignfull parent (see the note on .dfd-hero-campaign above) so its
	   percentage term resolves against the right containing-block width. */
	padding-left: var(--kd-edge-pad);
	padding-right: var(--kd-edge-pad);
	/* Core's constrained layout caps this box at --wp--style--global--content-size
	   (1216px). With the gutter now INSIDE the box, that cap would shrink the
	   content box to 1216 − 2·edge-pad (527px @1920) and the fixed tracks would
	   only land by overflow; lifting it makes the content box the real site
	   column (gate finding, 2026-09-11). Nothing moves at 1440 or ≥1920. */
	max-width: none;
}

.dfd-hero-campaign__copy {
	min-width: 0;
}

.dfd-hero-campaign__bars {
	display: flex;
	flex-direction: column;
	gap: 2.5625rem; /* 41px — Figma 10:340 top (435) − 10:336/339 label-row bottom (394) */
	margin-top: 2.5rem; /* mobile/tablet-stacked: space below the copy column */
	width: min(
		24.5rem,
		100%
	); /* 392px cap, matches --kd-card-w / the block's own --kd-bu-width default */
}

.dfd-hero-campaign__bars > * {
	margin: 0;
}

/* ── Copy column typography ──────────────────────────────────────────────
   h1 (level 1) already matches the comp with ZERO overrides: theme.json's
   `h1` element style is DynaPuff 700 / `huge` (--dfd-size-h2-section, the
   same 32→50px clamp) / 0.03em tracking / contrast navy, and global.css's
   shared heading rule already applies --dfd-shadow-heading + the DynaPuff
   `wdth` axis — theme-conventions' "one spec, don't redeclare per partial". */
/* DL-A: white outline on the H1 and the "Win $10,000!" display line
   (Figma screenshot-confirmed on both; no stroke-width value ships from the
   Dev Mode API for a text stroke, see file header note + --dfd-hero-outline
   above). `-webkit-text-stroke` + `paint-order:stroke fill` is the sole
   technique — every evergreen engine, including Firefox, supports the
   -webkit- prefix, so a text-shadow "fallback ring" has no real target and
   was dropped (round-1 gate finding: it wasn't hidden under the stroke and
   roughly doubled the visible outline weight). The drop-shadow stays
   global.css's --dfd-shadow-heading on h1–h6 — not redeclared here (a rule
   can't override a property it doesn't declare; gate round 2). Grouped instead
   of duplicated per element — only the size/colour/margin differ below. */
.dfd-hero-campaign__heading,
.dfd-hero-campaign__display {
	-webkit-text-stroke: var(--dfd-hero-outline) var(--kd-color-base);
	paint-order: stroke fill;
}

.dfd-hero-campaign__heading {
	margin: 0;
}

/* "Win $10,000!" — same DynaPuff/0.03em-tracking/shadow heading base as h1
   (global.css), only the size + colour differ from the default h2 (huge/
   contrast): --dfd-size-display is the Figma-verified 40→70px clamp, and at
   its own 0.03em tracking that resolves to exactly 2.1px @70px — the Figma
   spec's literal tracking value — with no separate letter-spacing override
   needed. */
.dfd-hero-campaign__display {
	font-size: var(--dfd-size-display);
	color: var(--kd-color-secondary);
	margin: 0;
	margin-top: 0.9375rem; /* 15px — Figma 10:332 bottom (379) to 10:333 top (394);
		unchanged by DL-A — the whole copy block shifted up together, this
		internal gap didn't move (verified against the new node metadata). */
}

.dfd-hero-campaign__sub {
	font-family: var(--kd-font-body);
	font-weight: 500; /* Helvetica Neue Medium */
	font-size: 1.25rem; /* 20px */
	line-height: 1.3; /* 26px */
	color: var(--kd-color-body);
	margin: 0;
	margin-top: 0.6875rem; /* 11px — Figma 10:333 bottom (479) to 10:342 top (490) */
}

/* No !important on either property below (round-1 gate finding #3 — checked,
   not assumed): the only WP-generated rule in play is the zero-specificity
   `:where(.is-layout-flex){gap:24px}` (confirmed live in the page's inline
   style block), and margin-top only fights this file's own earlier
   `.dfd-hero-campaign__copy > *{margin-top:0}` reset — both same-or-lower
   specificity than a single class selector, so normal cascade order wins
   cleanly. */
.dfd-hero-campaign__buttons {
	/* DL-A: 25px, not the old 40px. New sub bottom (465 top + 52 height = 517)
	   to new buttons top (542) = 25px — the buttons row moved up 40px total
	   (582→542) but only 25 of that comes from the copy block's shared
	   padding-top shift; the other 15px is this margin shrinking 40→25. */
	margin-top: 1.5625rem; /* 25px */
	gap: 1.6875rem; /* 27px — Figma 10:334 x355 − (10:347 x112 + w216); unchanged by DL-A */
}

/* ── Bars column layout — position/size ONLY. Never style the plugin's own
   internals (labels, track, fill, marker) — it reads --kd-* org tokens and
   theme-conventions.md forbids editing them from a consuming pattern. ──── */
@media (min-width: 1024px) {
	.dfd-hero-campaign__inner {
		display: grid;
		grid-template-columns: 1fr 20rem; /* 320px — "narrower" bars column, no 1024/1440 comp exists to pixel-match */
		column-gap: 2rem;
		align-items: start;
	}

	.dfd-hero-campaign__bars {
		margin-top: 0;
		width: auto;
	}
}

/* Desktop lock — exact Figma pixels (pixel-match fidelity applies at 1440;
   this also holds the same exact geometry ≥1920 rather than stretching,
   same "never verify at 1440 only" caution every sibling pattern documents). */
@media (min-width: 81.25rem) {
	/* 1300px */
	.dfd-hero-campaign__inner {
		grid-template-columns: 38.625rem 24.5rem; /* 618px / 392px — Figma 10:340/341 x730 minus the content column's x112 left edge */
		column-gap: 0;
	}

	.dfd-hero-campaign__bars {
		/* DL-A: 49px, not the old 24px. The bars column itself did NOT move
		   (10:341 is still y287, confirmed against the new node metadata —
		   nothing in the delta note touches the bars' own position), but the
		   h1 moved up 25px (263→238) via the padding-top change above, and
		   `align-items:start` on the row measures this margin from the row's
		   (= h1's) top edge — so the gap that keeps the bars column visually
		   anchored at its unchanged absolute position grows by that same
		   25px: 287−238=49px (was 287−263=24px). */
		margin-top: 3.0625rem;
	}
}
