/**
 * PropFirmGrade base layer.
 *
 * Everything theme.json cannot express: the world-accent indirection
 * (data-world / data-accent scopes), hairline borders, the focus ring,
 * selection, the page glow field, and the decorative crosshatch.
 *
 * Source of truth: the resolved "PropFirm Deals Dashboard (World Accent)"
 * document plus tokens/{colors,typography,spacing}.css.
 *
 * Rulings applied:
 *   R-C  --focus-ring is defined here and re-declared in every accent scope,
 *        because a custom property substitutes var() where it is DECLARED,
 *        not where it is used. Re-declaring is what makes the ring follow the
 *        active vertical.
 *   R-D  --grade / --grade-a..f are deliberately absent. Graded firms use
 *        --acc-bright; NR uses --grade-nr.
 *   R-E  --neg is the only red. #F0554E never appears.
 *   R-AA The muted rungs of the text ladder are NOT the design's dark hexes.
 *        --text-3 #8B90A3, --text-4 #5A6072 and --text-label #57607A measured
 *        5.89/2.98/2.99:1 on this canvas; the disclosure inside the grade
 *        tooltip measured 2.26:1. The design's own LIGHT theme tunes the same
 *        three rungs to 5.68/4.52/4.76:1, so the dark side was untuned rather
 *        than deliberate, and these values mirror the light theme's targets:
 *        hue and saturation held, lightness raised until each clears AA. AA
 *        cannot support seven distinct greys on #101219, so the bottom of the
 *        ladder compresses — the design's old --text-4 #5A6072 is now
 *        --text-disabled, where the 4.5:1 bar does not apply. Pinned by
 *        computed ratio in tests/test-blocks.php.
 */

:root {
	/* ---- World accents (STYLE-GUIDE v0.1 trio) ---- */
	--v-crypto: #00F0D0;
	--v-crypto-rgb: 0, 240, 208;
	--v-crypto-ink: #042F28;
	--v-crypto-text: #00F0D0;
	--v-crypto-hover: #33F5DB;
	--v-crypto-glow: 43, 200, 168;
	--v-futures: #E6FF00;
	--v-futures-rgb: 230, 255, 0;
	--v-futures-ink: #141414;
	--v-futures-text: #E6FF00;
	--v-futures-hover: #EFFF4D;
	--v-futures-glow: 240, 185, 11;
	--v-forex: #B14BFF;
	--v-forex-rgb: 177, 75, 255;
	/* WAS #FFFFFF, which the design specifies and which fails AA on its own
	   fill: white on #B14BFF is 3.95:1, and every accent-filled forex surface
	   is body-sized text (the switcher pill, the coupon and affiliate CTAs,
	   the applied filter chips, the grade-tooltip rung, the consent Accept).
	   Futures and crypto already use a dark ink and already pass; forex was
	   the odd one out. Owner's decision, 2026-08-26, on a measurement made
	   while giving the consent bar the CTA treatment.

	   The value is DERIVED, not picked: crypto's ink is its own accent's hue
	   held at S 84% / L 10% (#00F0D0 is hsl(172,100,47), #042F28 is
	   hsl(170,84,10)). The same construction on the forex hue —
	   hsl(274,84,10) — is this. So the trio now shares one rule rather than
	   three unrelated hexes, and the brand colour #B14BFF is untouched.
	   #1C042F on #B14BFF is 4.80:1. Pinned by computed ratio in
	   tests/test-blocks.php, not by hex. */
	--v-forex-ink: #1C042F;
	/* WAS #B14BFF, the brand fill reused as text, which fails AA as text on
	   the dark surfaces it sits on: 4.36:1 on --surface-3 #171B26 (prices,
	   kickers, links) and 3.58:1 on the 14% forex tint behind the hub's
	   percent-off chip (#2F254A composited over the row). Hue 274 and saturation 100%
	   held, lightness raised to the first step that clears 4.5:1 on EVERY
	   measured forex text surface, the tint chips included: #BE6AFF is
	   4.51:1 on #2F254A, 4.83:1 on the AI summary chip #292140 and 5.48:1 on
	   #171B26. #BB60FF, the first value proposed, is 4.4955:1 on the chip and
	   4.22:1 on the hub chip, so it does not pass. Still below --v-forex-hover
	   #C374FF, so hover still brightens. The brand fill --v-forex is
	   unchanged. */
	--v-forex-text: #BE6AFF;
	--v-forex-hover: #C374FF;
	--v-forex-glow: 154, 92, 245;

	/* Active world. The server stamps data-world on <html>, so this is only
	   reached when it did not — and it must agree with what the server would
	   have stamped. pfg_default_vertical() and RouteRegistry::DEFAULT_WORLD both
	   say futures, and every page but /forex/ stamps futures, so this said the
	   wrong thing from the day the default moved. */
	--world: var(--v-futures);
	--world-rgb: var(--v-futures-rgb);
	--world-ink: var(--v-futures-ink);
	--world-text: var(--v-futures-text);
	--world-hover: var(--v-futures-hover);
	--world-glow: var(--v-futures-glow);

	/* ---- Brand accent family (periwinkle base) ---- */
	--acc: #A79FFF;
	--acc-rgb: 167, 159, 255;
	--acc-bright: #C1BDFF;
	--acc-soft: #C9C4FF;
	--acc-fill: #BDB6FF;
	--acc-fill-hover: #CBC5FF;
	--acc-deep: #8F86E8;
	--on-acc: #14161F;
	--on-acc-solid: #14161F;
	--acc-tint-08: rgba(167, 159, 255, 0.08);
	--acc-tint-16: rgba(167, 159, 255, 0.16);
	--acc-border: rgba(167, 159, 255, 0.40);
	--acc-grad: linear-gradient(90deg, #8F6FFF, #5A7CFF);

	/* ---- Surfaces theme.json cannot alpha-blend ---- */
	--header-bg: rgba(16, 18, 25, 0.92);
	--seg-active: #10131A;
	--recess: rgba(13, 15, 22, 0.60);
	--scrim: rgba(6, 8, 14, 0.72);
	--hero-grad: linear-gradient(135deg, #1B2030 0%, #171B26 55%, #1A1830 100%);

	/* ---- Evidence tiers: a brightness ladder, never a hue ramp ---- */
	--tier-verified: var(--world);
	--tier-reported: #979CAD;
	--tier-claimed: #838A9D;
	--tier-refused: #5A6072;

	/* ---- Grades. R-B: NR renders at --text-3, which is what ships. ---- */
	--grade-nr: #979CAD;

	/* ---- Semantic. R-E: one red. ---- */
	--pos: #40D69A;
	--pos-alt: #2BC8A8;
	--warn: #F0B90B;
	--warn-soft: #E8A13C;
	--neg: #EB4749;
	--cold: #5B9DFF;
	--info: #6C9EF8;
	--star: #F6C453;
	--star-empty: rgba(255, 255, 255, 0.15);

	/* ---- Hairlines / interaction ---- */
	--border-1: rgba(255, 255, 255, 0.06);
	--border-2: rgba(255, 255, 255, 0.08);
	--border-3: rgba(255, 255, 255, 0.10);
	--border-strong: rgba(255, 255, 255, 0.14);
	--hover-wash: rgba(255, 255, 255, 0.04);
	--hover-wash-strong: rgba(255, 255, 255, 0.06);

	/* R-C */
	--focus-ring: 0 0 0 1px var(--acc), 0 0 0 4px rgba(var(--acc-rgb), 0.18);

	/* ---- Chrome geometry, published so sticky offsets cannot drift ---- */
	--hdr-h: 73px;
	--gutter: var(--wp--preset--spacing--60, clamp(20px, 2.6vw, 34px));
	--content-max: 1760px;

	/* WCAG 2.2 SC 2.4.11 FOCUS NOT OBSCURED, which was failing in BOTH
	   directions because both of these were `auto`.

	   Every fixed piece of chrome on this site is welded to one of the two
	   edges the browser scrolls a focused element to. `scroll-padding` is the
	   one property that tells it those edges are not where they look: without
	   it, Tab into a row below the fold and `elementFromPoint` at the row's
	   own centre returns HEADER.pfg-header going down and DIV.pfg-cookiebar
	   coming up. The row has focus and cannot be seen.

	   EVERY TERM IS A PUBLISHED VARIABLE, NOT A NUMBER. --hdr-h lives here,
	   --pfg-subnav-h beside the subnav, --pfg-tabbar-h beside the tab bar and
	   --pfg-cookiebar-h beside the cookie notice. Each is zero or absent when
	   its chrome is not on the page — the tab bar is withheld for the MVP and
	   the cookie notice zeroes itself once accepted — so the sum is self-
	   correcting and no rule here needs to know which page it is on. Hard-code
	   any one of them and it drifts the first time that bar changes height,
	   which is exactly the failure --hdr-h was published to prevent.

	   The 8px is a margin of comfort, not a measurement: an element flush
	   against the header's bottom edge is technically unobscured and still
	   reads as jammed under it. */
	scroll-padding-top: calc(var(--hdr-h, 73px) + 8px);
	scroll-padding-bottom: calc(var(--pfg-tabbar-h, 0px) + var(--pfg-cookiebar-h, 0px) + 8px);
}

/* The subnav sticks BELOW the header, so where it exists the top obstruction
   is both bars. Split into its own rule rather than folded into the calc
   above so that a page without a subnav does not reserve 53px it does not
   have — the same reason --pfg-tabbar-h is 0px until the bar is in the DOM. */
:root:has(.pfg-subnav-bar) {
	scroll-padding-top: calc(var(--hdr-h, 73px) + var(--pfg-subnav-h, 53px) + 8px);
}

/* ---- World scopes ----
   A section inside a page can re-scope the world (the homepage stacks all
   three verticals), so every scope re-derives the accent family below. */
[data-world="crypto"] {
	--world: var(--v-crypto);
	--world-rgb: var(--v-crypto-rgb);
	--world-ink: var(--v-crypto-ink);
	--world-text: var(--v-crypto-text);
	--world-hover: var(--v-crypto-hover);
	--world-glow: var(--v-crypto-glow);
}

[data-world="futures"] {
	--world: var(--v-futures);
	--world-rgb: var(--v-futures-rgb);
	--world-ink: var(--v-futures-ink);
	--world-text: var(--v-futures-text);
	--world-hover: var(--v-futures-hover);
	--world-glow: var(--v-futures-glow);
}

[data-world="forex"] {
	--world: var(--v-forex);
	--world-rgb: var(--v-forex-rgb);
	--world-ink: var(--v-forex-ink);
	--world-text: var(--v-forex-text);
	--world-hover: var(--v-forex-hover);
	--world-glow: var(--v-forex-glow);
}

/* ---- Accent model: world-coloured chrome. The design ships
   data-accent="world" ON, so the whole accent family, including grade
   visuals, follows the active vertical. Custom properties do not re-derive
   on nested scopes automatically, so the derivation is repeated for every
   [data-world] element under the world model. --focus-ring is re-declared
   here for the same reason (R-C). */
[data-accent="world"],
[data-accent="world"] [data-world] {
	--acc: var(--world-text);
	--acc-rgb: var(--world-rgb);
	--acc-bright: var(--world-hover);
	--acc-soft: var(--world-text);
	--acc-fill: var(--world);
	--acc-fill-hover: var(--world-hover);
	--acc-deep: var(--world-text);
	--on-acc: var(--world-ink);
	--on-acc-solid: var(--world-ink);
	--acc-tint-08: rgba(var(--world-rgb), 0.08);
	--acc-tint-16: rgba(var(--world-rgb), 0.16);
	--acc-border: rgba(var(--world-rgb), 0.40);
	--acc-grad: linear-gradient(90deg, var(--world), var(--world));
	--focus-ring: 0 0 0 1px var(--acc), 0 0 0 4px rgba(var(--acc-rgb), 0.18);
}

/* =========================================================================
   Document
   ========================================================================= */

html {
	scroll-behavior: smooth;
	overflow-x: clip;
}

body {
	-webkit-font-smoothing: antialiased;
	/* Nothing may push the page sideways. Wide content scrolls in its own box. */
	overflow-x: clip;
}

/* Long unbroken strings (codes, URLs) never widen the page. */
p,
li,
td,
th,
h1,
h2,
h3,
h4 {
	overflow-wrap: break-word;
}

/* Any table or pre is allowed to be wider than the page, inside its own box. */
.wp-block-table,
figure.wp-block-table,
pre.wp-block-code {
	max-width: 100%;
	overflow-x: auto;
}

img,
svg,
video,
canvas {
	max-width: 100%;
}

::selection {
	background: rgba(var(--acc-rgb), 0.35);
}

/* =========================================================================
   R-C: every interactive element shows the ring on :focus-visible.
   ========================================================================= */

:focus {
	outline: none;
}

:focus-visible,
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[contenteditable]:focus-visible,
.wp-block-navigation-item__content:focus-visible,
.wp-element-button:focus-visible,
.wp-block-button__link:focus-visible {
	outline: 2px solid transparent;
	outline-offset: 2px;
	box-shadow: var(--focus-ring);
	border-radius: 4px;
}

/* Windows high contrast keeps a real outline. */
@media (forced-colors: active) {
	:focus-visible {
		outline: 2px solid Highlight;
	}
}

/* =========================================================================
   Numerals and micro-labels
   ========================================================================= */

.pfg-num,
table td,
table th {
	font-variant-numeric: tabular-nums;
}

.pfg-label {
	font-size: var(--wp--preset--font-size--label, clamp(10.5px, 0.6vw, 12.5px));
	font-weight: 800;
	letter-spacing: var(--wp--custom--label--tracking, 0.08em);
	text-transform: uppercase;
	color: var(--wp--preset--color--text-label, #828BA6);
	margin: 0;
}

/* =========================================================================
   Decorative background.
   copper-hatch.js does not ship (JS-DEPENDENCY-CLASSIFICATION). This is the
   ruling's preferred reimplementation: a three-angle repeating-linear-gradient
   crosshatch tinted with var(--acc), the page radial glow field, and the
   "quiet zone" reproduced as a radial gradient painted in --bg-page so
   foreground copy keeps its contrast.
   Zero JS, zero canvas, no LCP cost, decorative to assistive tech.
   ========================================================================= */

/* The page glow field: one world-tinted radial from the top edge.
   Values measured from the resolved document's three stacked spans. */
.pfg-glow {
	position: relative;
	isolation: isolate;
}

.pfg-glow::before {
	content: "";
	position: fixed;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background: radial-gradient(
		100% 64% at 50% -12%,
		rgba(var(--world-glow), 0.17),
		rgba(var(--world-glow), 0.05) 40%,
		transparent 64%
	);
	transition: background 850ms ease;
}

/* The crosshatch plate. Full-bleed, sits behind the hero, fades out toward
   the right and bottom so it never ends on a hard edge (the design's own
   102deg mask). The quiet zone is the first layer in the stack, so it paints
   on top of the strokes, over the lower-left where the copy sits. */
.pfg-hatch {
	position: absolute;
	top: calc(-1 * var(--gutter));
	left: calc(50% - 50vw);
	width: 100vw;
	bottom: -10px;
	/* The plate is decoration in an is-layout-flow group, so WordPress's
	   `:root :where(.is-layout-flow) > *` block gap lands on it. On an
	   absolutely positioned box with top AND bottom pinned, that margin is not
	   ignored: it shortens the plate and pushes its top edge down by one gap,
	   which is what left a bare strip of panel wash above the hatch and cut the
	   animation off on a hard horizontal line. Layout gap has no business on a
	   box that is out of flow. */
	margin: 0;
	z-index: -1;
	pointer-events: none;
	overflow: clip;
	background-image:
		radial-gradient(74% 96% at 20% 66%, var(--wp--preset--color--bg-page, #101219) 0%, rgba(16, 18, 25, 0.88) 40%, rgba(16, 18, 25, 0) 76%),
		repeating-linear-gradient(32deg, rgba(var(--acc-rgb), 0.30) 0 1.6px, transparent 1.6px 34px),
		repeating-linear-gradient(-32deg, rgba(var(--acc-rgb), 0.30) 0 1.6px, transparent 1.6px 34px),
		repeating-linear-gradient(90deg, rgba(var(--acc-rgb), 0.20) 0 1.6px, transparent 1.6px 34px),
		radial-gradient(64% 80% at 76% 20%, rgba(var(--acc-rgb), 0.10), transparent 70%);
	-webkit-mask-image: linear-gradient(102deg, #000 40%, rgba(0, 0, 0, 0.5) 72%, transparent 97%);
	mask-image: linear-gradient(102deg, #000 40%, rgba(0, 0, 0, 0.5) 72%, transparent 97%);
}

/* ---- Jelly variant ----
   The alternative plate: no strokes, no canvas — a huge, softly-blurred
   accent bloom rotated across the hero's upper half over the dark page, with
   a faint counter-bloom for depth. Same wrapper and positioning as the hatch;
   the crosshatch background and its 102deg mask are simply replaced. Colour
   is rgba(var(--acc-rgb)) throughout, so the bloom is violet on forex,
   yellow on futures, teal on crypto — never a hardcoded hue. */
.pfg-hatch--jelly {
	background-image: linear-gradient(to bottom, rgba(var(--acc-rgb), 0.05), transparent 34%);
	-webkit-mask-image: none;
	mask-image: none;
}

.pfg-jelly__blob {
	position: absolute;
	pointer-events: none;
	border-radius: 50%;
	filter: blur(64px);
	will-change: transform;
}

.pfg-jelly__blob--a {
	top: 2%;
	left: 4%;
	width: 56%;
	height: 46%;
	border-radius: 9999px;
	transform: rotate(-30deg);
	opacity: 0.8;
	background: radial-gradient(closest-side, rgba(var(--acc-rgb), 0.7), rgba(var(--acc-rgb), 0.28) 55%, transparent 78%);
	filter: blur(48px);
}

.pfg-jelly__blob--b {
	top: 26%;
	right: 8%;
	width: 38%;
	height: 44%;
	transform: rotate(18deg);
	opacity: 0.55;
	background: radial-gradient(closest-side, rgba(242, 243, 248, 0.14), rgba(var(--acc-rgb), 0.12) 48%, transparent 72%);
}

/* A deep third layer: soft accent, low opacity, slow pulse. Where it crosses
   the white counter-bloom the mixture shifts, which is what reads as the
   colour itself moving. */
.pfg-jelly__blob--c {
	bottom: -6%;
	left: 24%;
	width: 44%;
	height: 52%;
	transform: rotate(-8deg);
	opacity: 0.4;
	background: radial-gradient(closest-side, rgba(var(--acc-rgb), 0.4), rgba(var(--acc-rgb), 0.14) 52%, transparent 74%);
}

/* ---- Shader variant ----
   The WebGL plate sits ON TOP of the jelly blobs, which stay as the fallback
   ground (and as what shows if WebGL is unavailable — the element sets
   [data-fallback] and we simply never reveal the canvas). Masked with the same
   102deg falloff as the hatch so the hero copy keeps its contrast. */
.pfg-hatch--shader pfg-shader {
	position: absolute;
	inset: 0;
	display: block;
	opacity: 0;
	transition: opacity 600ms ease;
	/* MIRRORED from the hatch's mask on purpose. The hatch fades toward the
	   RIGHT because its strokes live on the right; the shader radiates from
	   the right, so it must fade toward the LEFT — where the headline, the
	   paragraph and the stat row all sit. Getting this backwards puts the
	   densest arcs directly under the copy. */
	-webkit-mask-image:
		linear-gradient(100deg, transparent 4%, rgba(0, 0, 0, 0.28) 26%, rgba(0, 0, 0, 0.8) 52%, #000 78%),
		radial-gradient(58% 78% at 16% 62%, transparent 0%, rgba(0, 0, 0, 0.55) 46%, #000 74%);
	mask-image:
		linear-gradient(100deg, transparent 4%, rgba(0, 0, 0, 0.28) 26%, rgba(0, 0, 0, 0.8) 52%, #000 78%),
		radial-gradient(58% 78% at 16% 62%, transparent 0%, rgba(0, 0, 0, 0.55) 46%, #000 74%);
	-webkit-mask-composite: source-in;
	mask-composite: intersect;
}

/* Revealed only once a canvas actually exists — no flash of an empty box, and
   nothing to undo when the element falls back. */
.pfg-hatch--shader pfg-shader:has(canvas):not([data-fallback]) {
	opacity: 1;
}

.pfg-hatch--shader pfg-shader canvas {
	display: block;
	width: 100%;
	height: 100%;
}

/* With the shader carrying the motion, the CSS blobs drop back to a quiet
   ground rather than competing with it — except on phones, where the shader
   does not run at all (see hero-shader.js) and the blobs are the whole plate,
   so they keep their full jelly strength. */
@media (min-width: 760px) {
	.pfg-hatch--shader .pfg-jelly__blob--a { opacity: 0.42; }
	.pfg-hatch--shader .pfg-jelly__blob--b { opacity: 0.3; }
}

@media (max-width: 759px) {
	.pfg-hatch--shader pfg-shader { display: none; }
}

/* The lava-lamp motion. Every keyframe animates TRANSFORM and OPACITY only —
   compositor work, no repaints of the blurred layers — and the asymmetric
   scale() is the jelly squish. The three periods share no small multiple, so
   the composition never visibly repeats; where the accent blobs cross the
   white one, the mixed colour travels. Under reduced motion the plate is
   simply still, like the hatch — the site's global motion policy. */
@media (prefers-reduced-motion: no-preference) {
	@keyframes pfgJellyA {
		0%   { transform: rotate(-30deg) translate(0, 0) scale(1, 1); }
		50%  { transform: rotate(-16deg) translate(9%, 7%) scale(1.18, 0.88); }
		100% { transform: rotate(-34deg) translate(-5%, 10%) scale(0.92, 1.12); }
	}

	@keyframes pfgJellyB {
		0%   { transform: rotate(18deg) translate(0, 0) scale(1, 1); }
		50%  { transform: rotate(30deg) translate(-9%, -6%) scale(0.9, 1.15); }
		100% { transform: rotate(10deg) translate(6%, -10%) scale(1.14, 0.9); }
	}

	@keyframes pfgJellyC {
		0%   { transform: rotate(-8deg) translate(0, 0) scale(1, 1); opacity: 0.32; }
		50%  { transform: rotate(4deg) translate(-7%, -8%) scale(1.16, 0.92); opacity: 0.55; }
		100% { transform: rotate(-14deg) translate(8%, -3%) scale(0.9, 1.1); opacity: 0.38; }
	}

	.pfg-jelly__blob--a {
		animation: pfgJellyA 13s ease-in-out infinite alternate;
	}

	.pfg-jelly__blob--b {
		animation: pfgJellyB 17s ease-in-out infinite alternate;
	}

	.pfg-jelly__blob--c {
		animation: pfgJellyC 23s ease-in-out infinite alternate;
	}
}

/* The plate is decoration. In forced colours it disappears entirely, exactly
   as the canvas version did. */
@media (forced-colors: active) {
	.pfg-hatch,
	.pfg-glow::before {
		display: none;
	}
}

/* Phones get a lighter plate: the hatch would otherwise sit under the whole
   headline at 390px, where there is no room for a quiet zone beside it. */
@media (max-width: 760px) {
	.pfg-hatch {
		opacity: 0.5;
	}
}

/* =========================================================================
   Global motion policy
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* =========================================================================
   Hero slide panel
   ========================================================================= */

/*
 * The reference is a BOUNDED PANEL that carries its own contents from one state
 * to the next — it wraps its children and animates inside its own box. An
 * earlier pass made this a full-page cover for navigation, which is a different
 * effect entirely and read as one. The panel is the thing that transitions.
 */
.pfg-hero--panel {
	position: relative;
	isolation: isolate;
	overflow: clip;
	/* A FLOOR, not a stretcher. This used to be clamp(420px, 46vw, 560px), which
	   at every desktop width stood 108-154px taller than the panel's own content;
	   `margin-top: auto` on the head then collected all of that slack into one
	   void between the caption row and the headline. The panel now sizes to its
	   contents and the interval below is stated outright, so this only catches
	   the case where the contents are unusually short. */
	min-height: clamp(300px, 32vw, 470px);
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	padding: clamp(22px, 2.6vw, 40px);
	border-radius: clamp(18px, 1.6vw, 28px);
	border: 1px solid var(--wp--preset--color--grid-line, #2A3040);
	/* The world colour arrives as a wash over the page ground, not as the
	   reference's saturated gradient: this sits on a dark product surface and a
	   rose-to-indigo field would read as a different site. */
	background:
		radial-gradient(120% 120% at 12% 8%, rgba(var(--acc-rgb), 0.20) 0%, rgba(var(--acc-rgb), 0.06) 44%, transparent 76%),
		var(--wp--preset--color--bg-page, #101219);
}

/* The plate is scoped to the panel now, not bled across the viewport. */
.pfg-hero--panel .pfg-hatch {
	top: 0;
	left: 0;
	width: 100%;
	bottom: 0;
}

/*
 * The block renders its furniture in one place, but the panel reads top to
 * bottom: caption, then the claim, then the way in. `order` puts them where the
 * design wants them without the block having to emit markup in three places or
 * the template having to interleave them.
 */
.pfg-hero--panel > * { order: 2; }
.pfg-hero--panel .pfg-heroslide { order: 1; }
/* A stated interval, not `auto`. `auto` meant "however much height the panel has
   left over", which is not a design value at all — it swung 108-154px across the
   breakpoints and read as a hole. This is deliberately looser than the 24px
   rhythm the stats and jump rows use, because a mono caption sitting above a
   58px display headline wants more air than two body rows do. */
.pfg-hero--panel .pfg-hero__head { order: 3; margin-top: clamp(20px, 2.8vw, 44px); }
.pfg-hero--panel .pfg-hero__stats { order: 4; margin-top: clamp(16px, 1.8vw, 24px); }
.pfg-hero--panel .pfg-heroslide__jump { order: 5; margin-top: clamp(16px, 1.8vw, 24px); }

.pfg-heroslide {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	position: relative;
	z-index: 2;
}

.pfg-heroslide__index,
.pfg-heroslide__label {
	margin: 0;
	font-family: var(--wp--preset--font-family--mono, ui-monospace, monospace);
	font-size: clamp(11px, 0.8vw, 13px);
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--text-3, #979CAD);
}

.pfg-heroslide__index {
	font-variant-numeric: tabular-nums;
}

.pfg-heroslide__label {
	color: var(--acc-bright, #C1BDFF);
}

.pfg-heroslide__jump {
	display: flex;
	flex-wrap: wrap;
	gap: clamp(8px, 0.9vw, 14px);
	position: relative;
	z-index: 2;
}

.pfg-heroslide__dot {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 10px 14px;
	border-radius: 12px;
	border: 1px solid var(--wp--preset--color--grid-line, #2A3040);
	background: rgba(255, 255, 255, 0.02);
	text-decoration: none;
	transition: border-color 180ms ease, background 180ms ease;
}

.pfg-heroslide__dot:hover,
.pfg-heroslide__dot:focus-visible {
	border-color: rgba(var(--acc-rgb), 0.55);
	background: rgba(var(--acc-rgb), 0.08);
}

.pfg-heroslide__dot[aria-current="true"] {
	border-color: rgba(var(--acc-rgb), 0.8);
	background: rgba(var(--acc-rgb), 0.12);
}

.pfg-heroslide__dot-label {
	font-size: clamp(13px, 0.95vw, 15px);
	font-weight: 600;
	color: var(--wp--preset--color--text-1, #F2F3F8);
}

.pfg-heroslide__dot-meta {
	font-size: clamp(11px, 0.78vw, 12.5px);
	color: var(--text-3, #979CAD);
	font-variant-numeric: tabular-nums;
}

/* =========================================================================
   Cross-document view transitions
   ========================================================================= */

/*
 * Switching vertical is a real navigation between /forex/, /futures/ and
 * /crypto/, and it stays one. The server already produces the right world tint,
 * title, canonical and switcher state for each; intercepting the click to swap
 * content in place would mean re-implementing all of that by hand in a store —
 * and the Interactivity router notably does NOT update `html[data-world]`, which
 * is the attribute the entire world-tint system hangs off. A router-swapped
 * switch lands you on /crypto/ still tinted forex.
 *
 * So the transition is declarative and costs no JavaScript at all: this works
 * with scripting disabled, which is the baseline the rest of the site holds to.
 *
 * WHAT THIS IS NOT. View transitions animate SNAPSHOTS — `::view-transition-old`
 * and `-new` are images, and the only tools are transform, opacity and clip
 * paths. A shader-driven blob wipe cannot be expressed here, and a live WebGL
 * canvas inside the transition root is captured as a frozen still. If a blob
 * transition is added later it must run as a separate overlay and suppress
 * these animations while it plays, rather than trying to render into them.
 */
@view-transition {
	navigation: auto;
}

/*
 * The global policy above crushes animation duration to 0.01ms, but
 * view-transition pseudo-elements live outside the document tree and `*` does
 * not reach them. Without this, a reduced-motion visitor gets the full
 * cross-fade — the one animation on the site that ignored the preference.
 */
@media (prefers-reduced-motion: reduce) {
	::view-transition-group(*),
	::view-transition-old(*),
	::view-transition-new(*) {
		animation: none !important;
	}
}
