/**
 * ncp runtime — layout, position & scroll layer (STYLES)  ·  "part 2" of the ncp runtime
 * Contract: docs/design-system.md → "Layout, position & scroll layer".
 *
 * Companion to assets/ncp/ncp.css (motion & interaction). Enqueued as handle `ncp-layout`
 * AFTER `ncp-runtime`, so the motion tokens it defines (--ncp-motion-duration-fast,
 * --ncp-motion-easing, --ncp-motion-distance) are already available here.
 *
 * Rules baked in (identical to ncp.css):
 * - Class-driven only (never data-* on saved blocks → keeps block validation clean).
 *   JS reads tunable knobs from custom properties (getComputedStyle), never from attributes.
 * - Runtime-local values (breakpoints, background geometry, header threshold, progress size)
 *   are defined here; governance values (z-index scale, positional offsets) are aliased from
 *   theme.json settings.custom with fallbacks, so theme.json stays their source of truth.
 * - Every family degrades: no JS / no browser support / reduced motion all leave content
 *   fully visible and usable. Nothing here can strand an element at opacity:0 without JS.
 * - No @layer: unlayered so single-class selectors keep normal specificity vs core output.
 *
 * Families:  A Position & anchoring · B Header overlay · C Responsive visibility
 *            D Scroll-driven visibility & effects · E Decorative / animated backgrounds
 *            F Responsive layout modifiers (order / stack / spacing per breakpoint)
 */

/* ============================================================
 * Tokens
 *  Governance values (z-index, offsets) come from theme.json settings.custom and are
 *  aliased here with fallbacks so this file works even if a token is ever removed.
 * ============================================================ */
:root {
	/* z-index scale — mirrors theme.json custom.z (governs collisions AMONG ncp elements) */
	--ncp-z-base:     var(--wp--custom--z--base, 0);
	--ncp-z-sticky:   var(--wp--custom--z--sticky, 10);
	--ncp-z-header:   var(--wp--custom--z--header, 100);
	--ncp-z-floating: var(--wp--custom--z--floating, 200);
	--ncp-z-overlay:  var(--wp--custom--z--overlay, 1000);

	/* positional offsets — mirror theme.json custom.offset (built on the spacing scale) */
	--ncp-offset-edge:     var(--wp--custom--offset--edge, var(--wp--preset--spacing--40, 1.5rem));
	--ncp-offset-sticky:   var(--wp--custom--offset--sticky, var(--wp--preset--spacing--40, 1.5rem));
	--ncp-offset-floating: var(--wp--custom--offset--floating, var(--wp--preset--spacing--50, 2rem));

	/* Fixed top chrome — height of the persistent fixed header. ncp.js (initHeader)
	   measures the header CONTAINER once (so any number of bars stacked inside it are
	   covered) and publishes the live value here on :root. Default 0px: no fixed header,
	   or no JS, collapses every consumer to admin-bar-only behavior with no conditional.
	   A static no-JS fallback can be set via theme.json custom.offset.header. */
	--ncp-fixed-offset: var(--wp--custom--offset--header, 0px);

	/* Total space occupied at the top of the viewport by persistent fixed chrome
	   (admin bar + fixed header). THE single value every top-anchored element must clear:
	   ncp-sticky, ncp-float--top-*, and the anchor scroll-padding-top below all read it.
	   Composed in CSS; JS only ever publishes the measured --ncp-fixed-offset piece. */
	--ncp-inset-top: calc(var(--wp-admin--admin-bar--height, 0px) + var(--ncp-fixed-offset));

	/* In-page anchor (#id) jumps land below the fixed chrome + a breathing gap.
	   0px offset on pages without a fixed header → just the gap (harmless). */
	scroll-padding-top: calc(var(--ncp-inset-top) + var(--ncp-offset-sticky));

	/* sticky anchor offset — override per element to change where a sticky block pins */
	--ncp-sticky-top: var(--ncp-offset-sticky);

	/* header overlay */
	--ncp-header-bg:        var(--wp--preset--color--base);
	--ncp-header-shadow:    var(--wp--preset--shadow--sm);
	--ncp-header-threshold: 24px; /* px past which ncp.js turns the header solid */

	/* Scrim tint = the opposite of the header's own text tone, so it darkens a light-text
	   header and lightens a dark-text one. Correct in every palette: in `dark`, --light
	   paints text with base (near-black), and this pairs it with contrast (near-white). */
	--ncp-header-scrim-strength: 38%;

	/* responsive tiers — the two dividing lines between mobile / tablet / desktop. Family C's
	   @media queries restate these as literals (CSS @media cannot read a custom property); the
	   max-width variants use the value minus 0.02px. Keep both in sync. Declared here as the
	   single documented home for the numbers, and so a future JS matchMedia can read them. */
	--ncp-bp-md: 768px;
	--ncp-bp-lg: 1024px;

	/* decorative backgrounds — brand, not accent: these are graphics, never text.
	   `brand` is the client's hex untouched; `accent` is the darkened ink reserved for text.
	   color-2 is the light companion tone; on a dark band it is reassigned in Family E. */
	--ncp-bg-color-1: var(--wp--preset--color--brand);
	--ncp-bg-color-2: var(--wp--preset--color--surface);
	--ncp-bg-cell:     24px;   /* grid/dots lattice pitch */
	--ncp-bg-duration: 18s;    /* gradient pan / aurora drift */

	/* scroll-driven */
	--ncp-scroll-appear-at: 400px; /* read by ncp.js; scroll depth that reveals ncp-scroll-appear */
	--ncp-progress-size:    3px;
}

/* Central reduced-motion zeroing for this file. Background animations read --ncp-bg-duration,
   so a 0s duration freezes them at their first frame (static). Scroll-timeline effects are
   already gated behind prefers-reduced-motion:no-preference below, so they simply never apply. */
@media (prefers-reduced-motion: reduce) {
	:root { --ncp-bg-duration: 0s; }
	.ncp-scroll-progress { display: none; }
}

/* ============================================================
 * A · Position & anchoring  (CSS only)
 *  ncp-anchor        → containing block for absolute children
 *  ncp-absolute      (+ edge modifier) on a child of ncp-anchor
 *  ncp-sticky        (+ --bottom) pins a nested block within its section/column
 *  ncp-fixed         viewport-fixed
 *  ncp-float         (+ corner modifier) floating button/element
 * Pure CSS — nothing to degrade; unsupported sticky simply falls back to static (visible).
 * ============================================================ */

.ncp-anchor { position: relative; }

.ncp-absolute {
	position: absolute;
	z-index: var(--ncp-z-sticky);
	/* default corner = top-left */
	top: var(--ncp-offset-edge);
	left: var(--ncp-offset-edge);
}
.ncp-absolute--top-left     { inset: var(--ncp-offset-edge) auto auto var(--ncp-offset-edge); }
.ncp-absolute--top-right    { inset: var(--ncp-offset-edge) var(--ncp-offset-edge) auto auto; }
.ncp-absolute--bottom-left  { inset: auto auto var(--ncp-offset-edge) var(--ncp-offset-edge); }
.ncp-absolute--bottom-right { inset: auto var(--ncp-offset-edge) var(--ncp-offset-edge) auto; }
.ncp-absolute--top-center {
	top: var(--ncp-offset-edge); bottom: auto;
	left: 50%; right: auto;
	transform: translateX(-50%);
}
.ncp-absolute--bottom-center {
	bottom: var(--ncp-offset-edge); top: auto;
	left: 50%; right: auto;
	transform: translateX(-50%);
}
.ncp-absolute--center {
	inset: 50% auto auto 50%;
	transform: translate(-50%, -50%);
}

.ncp-sticky {
	position: -webkit-sticky;
	position: sticky;
	/* clear all persistent fixed chrome above (admin bar + fixed header) via the shared
	   --ncp-inset-top, then add this element's breathing gap. --ncp-inset-top is 0-safe:
	   with no admin bar and no fixed header it is 0, so this pins at --ncp-sticky-top as before. */
	top: calc(var(--ncp-inset-top) + var(--ncp-sticky-top));
	z-index: var(--ncp-z-sticky);
	/* Inside a flex/grid column (core/columns), a column stretches to full height, which
	   leaves the sticky child no room to travel. align-self:start lets it move. */
	align-self: start;
}
.ncp-sticky--bottom { top: auto; bottom: var(--ncp-sticky-top); }

.ncp-fixed { position: fixed; z-index: var(--ncp-z-floating); }

.ncp-float {
	position: fixed;
	z-index: var(--ncp-z-floating);
	/* default corner = bottom-right */
	right: var(--ncp-offset-floating);
	bottom: var(--ncp-offset-floating);
}
.ncp-float--bottom-right { inset: auto var(--ncp-offset-floating) var(--ncp-offset-floating) auto; }
.ncp-float--bottom-left  { inset: auto auto var(--ncp-offset-floating) var(--ncp-offset-floating); }
.ncp-float--top-right {
	inset: calc(var(--ncp-offset-floating) + var(--ncp-inset-top)) var(--ncp-offset-floating) auto auto;
}
.ncp-float--top-left {
	inset: calc(var(--ncp-offset-floating) + var(--ncp-inset-top)) auto auto var(--ncp-offset-floating);
}

/* ============================================================
 * B · Header transparent overlay  (CSS + JS enhancer `initHeader`)
 *  ncp-header (JS hook) + --overlay / --fixed / --autohide / --light / --dark / --scrim
 *  JS toggles `is-scrolled` (turns solid past --ncp-header-threshold) and, with --autohide,
 *  `is-hidden` (slides up on scroll-down). Classes go on the header template-part wrapper.
 * No JS → header keeps its resting look; --light/--dark + optional --scrim keep it legible,
 * so it is correct without the solid state. See the recipe in docs/design-system.md.
 * ============================================================ */
.ncp-header--overlay,
.ncp-header--fixed {
	position: absolute;
	inset-inline: 0;
	top: var(--wp-admin--admin-bar--height, 0px);
	z-index: var(--ncp-z-header);
	background: transparent;
	transition:
		background-color var(--ncp-motion-duration-fast, 300ms) var(--ncp-motion-easing, ease),
		box-shadow var(--ncp-motion-duration-fast, 300ms) var(--ncp-motion-easing, ease),
		transform var(--ncp-motion-duration-fast, 300ms) var(--ncp-motion-easing, ease);
}
.ncp-header--fixed { position: fixed; }

/* Legibility over the hero — author picks the tone that contrasts their background. */
.ncp-header--light,
.ncp-header--light a,
.ncp-header--light .wp-block-site-title a,
.ncp-header--light .wp-block-navigation,
.ncp-header--light .wp-block-navigation a { color: var(--wp--preset--color--base); }
.ncp-header--dark,
.ncp-header--dark a,
.ncp-header--dark .wp-block-site-title a,
.ncp-header--dark .wp-block-navigation,
.ncp-header--dark .wp-block-navigation a { color: var(--wp--preset--color--contrast); }

/* Scrim — guarantees legibility over busy heroes; painted behind the header content.
   The scrim's ::before needs a positioned host: --overlay/--fixed already provide one, so
   only add position:relative when the header is NOT overlaid/fixed — otherwise, at equal
   specificity + later source order, it would override those and knock the header back into
   normal flow (defeating the overlay exactly when you reach for the scrim to make it legible). */
.ncp-header--scrim:not(.ncp-header--overlay):not(.ncp-header--fixed) { position: relative; }
.ncp-header--scrim { --ncp-header-scrim-tint: var(--wp--preset--color--contrast); }
.ncp-header--dark.ncp-header--scrim { --ncp-header-scrim-tint: var(--wp--preset--color--base); }
.ncp-header--scrim::before {
	content: "";
	position: absolute;
	inset: 0 0 auto 0;
	height: 220%;
	pointer-events: none;
	z-index: -1;
	background: linear-gradient(
		to bottom,
		color-mix(in srgb, var(--ncp-header-scrim-tint) var(--ncp-header-scrim-strength), transparent),
		transparent);
	opacity: 1;
	transition: opacity var(--ncp-motion-duration-fast, 300ms) var(--ncp-motion-easing, ease);
}
/* The scrim serves only the TRANSPARENT (resting) header over the hero. Once JS turns the
   header solid (is-scrolled), its own background provides the contrast, so fade the scrim
   out — otherwise the fixed header keeps dragging the 220%-tall gradient down the page.
   Three classes + pseudo-element outweigh the base ::before rule, so opacity:0 wins. */
.ncp-header.is-scrolled.ncp-header--scrim::before { opacity: 0; }

/* Solid state (JS adds `is-scrolled`). State change, not motion → applies under reduced
   motion too; only its transition is zeroed. Always uses base/contrast for guaranteed AA.
   The compound selector (.ncp-header.is-scrolled …) outweighs --light/--dark above. */
.ncp-header.is-scrolled {
	background: var(--ncp-header-bg);
	box-shadow: var(--ncp-header-shadow);
}
.ncp-header.is-scrolled,
.ncp-header.is-scrolled a,
.ncp-header.is-scrolled .wp-block-site-title a,
.ncp-header.is-scrolled .wp-block-navigation,
.ncp-header.is-scrolled .wp-block-navigation a { color: var(--wp--preset--color--contrast); }

/* Auto-hide (JS adds `is-hidden` on scroll-down, removes on scroll-up). */
.ncp-header.is-hidden { transform: translateY(-100%); }

/* ============================================================
 * C · Responsive visibility  (CSS only)
 *  ncp-hide-mobile / -tablet / -desktop   → hidden in that tier
 *  ncp-show-mobile / -tablet / -desktop   → shown ONLY in that tier
 * Tiers (must match --ncp-bp-*): mobile < 768 · tablet 768–1023 · desktop ≥ 1024.
 * `show-*` never forces a display value (would guess the block's native flex/grid/flow);
 * it only sets display:none in the OTHER tiers. Pure CSS — no-JS safe.
 * ============================================================ */
@media (max-width: 767.98px)  { .ncp-hide-mobile  { display: none !important; } }
@media (min-width: 768px) and (max-width: 1023.98px) { .ncp-hide-tablet { display: none !important; } }
@media (min-width: 1024px)    { .ncp-hide-desktop { display: none !important; } }

@media (min-width: 768px)     { .ncp-show-mobile  { display: none !important; } }
@media (max-width: 767.98px)  { .ncp-show-tablet  { display: none !important; } }
@media (min-width: 1024px)    { .ncp-show-tablet  { display: none !important; } }
@media (max-width: 1023.98px) { .ncp-show-desktop { display: none !important; } }

/* ============================================================
 * D · Scroll-driven visibility & effects
 *  ncp-scroll-appear / ncp-scroll-hide  → JS toggles state past --ncp-scroll-appear-at
 *  ncp-scroll-fx (+ --fade/--fade-up/--scale/--rotate) → CSS scroll-timeline scrub
 *  ncp-scroll-progress → reading indicator bar
 *
 * Appear/hide are JS because they need a no-JS "always visible" fallback: the hidden state is
 * armed ONLY under html.ncp-scroll-ready (added by ncp.js). No JS → never armed → visible.
 * Reduced motion → duration-fast is 0s (zeroed in ncp.css) → the toggle snaps, no travel.
 * ============================================================ */
.ncp-scroll-ready .ncp-scroll-appear {
	opacity: 0;
	transform: translateY(var(--ncp-motion-distance, 2rem));
	transition:
		opacity var(--ncp-motion-duration-fast, 300ms) var(--ncp-motion-easing, ease),
		transform var(--ncp-motion-duration-fast, 300ms) var(--ncp-motion-easing, ease);
}
.ncp-scroll-ready .ncp-scroll-appear:not(.is-revealed) { pointer-events: none; }
.ncp-scroll-ready .ncp-scroll-appear.is-revealed { opacity: 1; transform: none; }

.ncp-scroll-ready .ncp-scroll-hide {
	transition:
		opacity var(--ncp-motion-duration-fast, 300ms) var(--ncp-motion-easing, ease),
		transform var(--ncp-motion-duration-fast, 300ms) var(--ncp-motion-easing, ease);
}
.ncp-scroll-ready .ncp-scroll-hide.is-hidden {
	opacity: 0;
	transform: translateY(calc(-1 * var(--ncp-motion-distance, 2rem)));
	pointer-events: none;
}

/* Scroll-linked scrub — CSS scroll-driven animation (compositor, off the main thread).
   Why CSS not JS rAF: same rationale as parallax (ncp.css) — decorative, degrades flat.
   Keyframes END at the identity/natural state, so where animation-timeline is unsupported
   (Firefox / older Safari) or motion is reduced, the element simply sits fully visible. */
@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {
		.ncp-scroll-fx {
			animation: ncp-fx-fade-up both;
			animation-timeline: view();
			animation-range: entry 0% cover 35%;
		}
		.ncp-scroll-fx--fade    { animation-name: ncp-fx-fade; }
		.ncp-scroll-fx--fade-up { animation-name: ncp-fx-fade-up; }
		.ncp-scroll-fx--scale   { animation-name: ncp-fx-scale; }
		.ncp-scroll-fx--rotate  { animation-name: ncp-fx-rotate; }
	}
}
@keyframes ncp-fx-fade    { from { opacity: 0; } to { opacity: 1; } }
@keyframes ncp-fx-fade-up { from { opacity: 0; transform: translateY(var(--ncp-motion-distance, 2rem)); } to { opacity: 1; transform: none; } }
@keyframes ncp-fx-scale   { from { opacity: 0; transform: scale(0.9); }  to { opacity: 1; transform: none; } }
@keyframes ncp-fx-rotate  { from { opacity: 0; transform: rotate(-6deg) scale(0.95); } to { opacity: 1; transform: none; } }

/* Reading progress bar. No meaningful flat state → hidden when unsupported or reduced motion
   (the reduced-motion display:none is in the central block near the top of this file). */
.ncp-scroll-progress {
	position: fixed;
	top: var(--wp-admin--admin-bar--height, 0px);
	inset-inline: 0;
	height: var(--ncp-progress-size);
	transform-origin: 0 50%;
	transform: scaleX(0);
	background: var(--wp--preset--color--brand, currentColor);
	z-index: var(--ncp-z-overlay);
	pointer-events: none;
}
@supports (animation-timeline: scroll()) {
	@media (prefers-reduced-motion: no-preference) {
		.ncp-scroll-progress {
			animation: ncp-progress-grow both;
			animation-timeline: scroll(root);
		}
	}
}
@supports not (animation-timeline: scroll()) {
	.ncp-scroll-progress { display: none; }
}
@keyframes ncp-progress-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ============================================================
 * E · Decorative / animated backgrounds  (CSS only, + JS for --spotlight)
 *  ncp-bg (base) + --gradient / --grid / --dots / --noise / --aurora / --spotlight
 *  On a core/group or core/cover. Colors from --ncp-bg-color-1/2 (accent/surface).
 *  Painted on ::before/::after at z-index:-1 inside an isolated stacking context, so the
 *  band's content stays above and readable, and decorations are clipped to the box.
 * Reduced motion → --ncp-bg-duration:0s freezes gradient/aurora (static). Always usable.
 * ============================================================ */
.ncp-bg {
	position: relative;
	isolation: isolate;
	overflow: hidden;
}

/* On a dark band the default companion tone (`surface`, a near-white neutral) reads as a
   grey milky smear rather than a second light. Swap it for the brand ink that is already
   guaranteed legible against `contrast` — a text-grade tint always clears the 3:1 a graphic
   needs, so this direction is safe. Covers the band itself and any nested decorated box. */
.has-contrast-background-color.ncp-bg,
.is-style-section-inverted.ncp-bg,
.has-contrast-background-color .ncp-bg,
.is-style-section-inverted .ncp-bg {
	--ncp-bg-color-2: var(--wp--preset--color--accent-inverted);
}

.ncp-bg--gradient::before {
	content: "";
	position: absolute;
	inset: -25%;
	z-index: -1;
	background: linear-gradient(120deg, var(--ncp-bg-color-1), var(--ncp-bg-color-2), var(--ncp-bg-color-1));
	background-size: 200% 200%;
	animation: ncp-bg-pan var(--ncp-bg-duration) linear infinite;
}
@keyframes ncp-bg-pan { to { background-position: 200% 50%; } }

.ncp-bg--grid::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image:
		linear-gradient(to right, var(--wp--preset--color--hairline) 1px, transparent 1px),
		linear-gradient(to bottom, var(--wp--preset--color--hairline) 1px, transparent 1px);
	background-size: var(--ncp-bg-cell) var(--ncp-bg-cell);
	-webkit-mask-image: radial-gradient(ellipse at center, #000 35%, transparent 78%);
	        mask-image: radial-gradient(ellipse at center, #000 35%, transparent 78%);
}

.ncp-bg--dots::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image: radial-gradient(var(--wp--preset--color--hairline) 1.5px, transparent 1.6px);
	background-size: var(--ncp-bg-cell) var(--ncp-bg-cell);
	-webkit-mask-image: radial-gradient(ellipse at center, #000 35%, transparent 78%);
	        mask-image: radial-gradient(ellipse at center, #000 35%, transparent 78%);
}

/* Noise — inline SVG turbulence (one-off geometry allowance; no token expresses it). */
.ncp-bg--noise::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	opacity: 0.35;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Aurora — two blurred blobs drifting; drift freezes under reduced motion. */
.ncp-bg--aurora::before,
.ncp-bg--aurora::after {
	content: "";
	position: absolute;
	z-index: -1;
	width: 60%;
	aspect-ratio: 1;
	border-radius: 50%;
	filter: blur(60px);
	opacity: 0.5;
}
.ncp-bg--aurora::before {
	top: -15%;
	left: -10%;
	background: var(--ncp-bg-color-1);
	animation: ncp-bg-drift-a var(--ncp-bg-duration) ease-in-out infinite alternate;
}
.ncp-bg--aurora::after {
	right: -10%;
	bottom: -20%;
	background: var(--ncp-bg-color-2);
	animation: ncp-bg-drift-b var(--ncp-bg-duration) ease-in-out infinite alternate;
}
@keyframes ncp-bg-drift-a { to { transform: translate(20%, 15%) scale(1.15); } }
@keyframes ncp-bg-drift-b { to { transform: translate(-15%, -12%) scale(1.1); } }

/* Spotlight — radial glow tracking the pointer; JS (initSpotlight) sets --ncp-spot-x/-y.
   No JS or reduced motion → JS skips the listener → the glow stays centered (static). */
.ncp-bg--spotlight::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	opacity: 0.5;
	background: radial-gradient(
		circle at var(--ncp-spot-x, 50%) var(--ncp-spot-y, 50%),
		var(--ncp-bg-color-1),
		transparent 42%
	);
}

/* Optional explicit layer when both pseudo-elements are already used. */
.ncp-bg__layer {
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
}

/* ============================================================
 * F · Responsive layout modifiers  (CSS only)
 *  Per-breakpoint layout overrides — the values theme.json (which has no breakpoints) cannot
 *  express. Mobile-first: author the base for mobile, then reach for a -tier utility as a
 *  TARGETED override on the Family-C tiers (mobile ≤767.98 · tablet 768–1023.98 · desktop ≥1024).
 *  Authoring standard (grammar, engine, 3-step process): docs/design-system.md →
 *  "Authoring new ncp- utilities & components".
 *
 *  Engine: a value class only SETS a custom property; one media query CONSUMES it — so the
 *  vocabulary grows without a class explosion and stays generable/tree-shakeable. `!important`
 *  appears ONLY where core ships the value as an INLINE block style (padding/gap); order and
 *  stack need none. The three spacing substrings (pad / pad-block / gap) never cross-match.
 *
 *  · Order   ncp-order-mobile-{first,last,1..4}    (element must be a flex/grid item)
 *  · Stack   ncp-stack-mobile / -tablet            (collapse a flex/grid container to one column)
 *  · Padding ncp-pad-mobile-{20..80}               (all sides)
 *            ncp-pad-block-mobile-{20..80}         (top+bottom — band vertical rhythm)
 *  · Gap     ncp-gap-mobile-{20..80}               (flex/grid container gap)
 *  Keep columns side-by-side on mobile = native Columns setting "Stack on mobile: off"
 *  (isStackedOnMobile:false) — don't re-fight core here.
 * ============================================================ */

/* Order — value classes set the knob; consumed only below the mobile breakpoint. */
.ncp-order-mobile-first { --ncp-order: -1; }
.ncp-order-mobile-last  { --ncp-order: 999; }
.ncp-order-mobile-1     { --ncp-order: 1; }
.ncp-order-mobile-2     { --ncp-order: 2; }
.ncp-order-mobile-3     { --ncp-order: 3; }
.ncp-order-mobile-4     { --ncp-order: 4; }

/* Padding (all sides) — from the spacing scale. */
.ncp-pad-mobile-20 { --ncp-pad: var(--wp--preset--spacing--20); }
.ncp-pad-mobile-30 { --ncp-pad: var(--wp--preset--spacing--30); }
.ncp-pad-mobile-40 { --ncp-pad: var(--wp--preset--spacing--40); }
.ncp-pad-mobile-50 { --ncp-pad: var(--wp--preset--spacing--50); }
.ncp-pad-mobile-60 { --ncp-pad: var(--wp--preset--spacing--60); }
.ncp-pad-mobile-70 { --ncp-pad: var(--wp--preset--spacing--70); }
.ncp-pad-mobile-80 { --ncp-pad: var(--wp--preset--spacing--80); }

/* Padding (block axis = top+bottom) — the common "tighten a band on mobile" knob. */
.ncp-pad-block-mobile-20 { --ncp-pad-block: var(--wp--preset--spacing--20); }
.ncp-pad-block-mobile-30 { --ncp-pad-block: var(--wp--preset--spacing--30); }
.ncp-pad-block-mobile-40 { --ncp-pad-block: var(--wp--preset--spacing--40); }
.ncp-pad-block-mobile-50 { --ncp-pad-block: var(--wp--preset--spacing--50); }
.ncp-pad-block-mobile-60 { --ncp-pad-block: var(--wp--preset--spacing--60); }
.ncp-pad-block-mobile-70 { --ncp-pad-block: var(--wp--preset--spacing--70); }
.ncp-pad-block-mobile-80 { --ncp-pad-block: var(--wp--preset--spacing--80); }

/* Gap (flex/grid containers). */
.ncp-gap-mobile-20 { --ncp-gap: var(--wp--preset--spacing--20); }
.ncp-gap-mobile-30 { --ncp-gap: var(--wp--preset--spacing--30); }
.ncp-gap-mobile-40 { --ncp-gap: var(--wp--preset--spacing--40); }
.ncp-gap-mobile-50 { --ncp-gap: var(--wp--preset--spacing--50); }
.ncp-gap-mobile-60 { --ncp-gap: var(--wp--preset--spacing--60); }
.ncp-gap-mobile-70 { --ncp-gap: var(--wp--preset--spacing--70); }
.ncp-gap-mobile-80 { --ncp-gap: var(--wp--preset--spacing--80); }

/* Consumers — one rule per property. `flex-direction` + `grid-template-columns` on one stack
   selector covers both flex and grid containers (the inapplicable one is ignored). */
@media (max-width: 767.98px) {
	[class*="ncp-order-mobile"]     { order: var(--ncp-order); }
	.ncp-stack-mobile               { flex-direction: column !important; grid-template-columns: 1fr !important; }
	[class*="ncp-pad-mobile"]       { padding: var(--ncp-pad) !important; }
	[class*="ncp-pad-block-mobile"] { padding-block: var(--ncp-pad-block) !important; }
	[class*="ncp-gap-mobile"]       { gap: var(--ncp-gap) !important; }
}

@media (min-width: 768px) and (max-width: 1023.98px) {
	.ncp-stack-tablet { flex-direction: column !important; grid-template-columns: 1fr !important; }
}
