/* Source Sans 3 — self-hosted.
   Previously loaded from Google Fonts, which cost a third-party DNS/TLS handshake before the
   font could even start downloading, and left a long enough gap for the 73px H1 to paint in
   Arial and then visibly reflow. Serving from our own origin lets the files be preloaded
   from the template head (see tpl-innovation-drop-sep-2026.php), so they arrive with the CSS.

   These are VARIABLE font files: Google returns the same woff2 whatever weight range you ask
   for, so one file per subset covers every weight the page uses. Declared with a font-weight
   RANGE accordingly — do not split these into per-weight faces.

   The range is 200-900: the font's true axis, not the subset the page happens to use today.
   It said 400-700 until 2026-09-08, which silently clamped .idsep-section__heading — set to 800
   from Figma node 80:108 (ExtraBold), it rendered at 700, because a weight outside a variable
   face's declared range is clamped to the nearest end. The CSS said 800, DevTools said 800, the
   glyphs were 700. Measured with canvas: 700, 800 and 900 all came back the same width.

   Verified 2026-09-08 that the Google Fonts CSS API returns the SAME woff2 URL for wght@400..700,
   wght@400..800 and wght@200..900 — one file carrying the whole axis. So this descriptor is
   purely declarative: widening it costs nothing, downloads nothing extra, and the only thing a
   narrow range can do is silently clamp a weight the file already contains. Declare what the
   FILE supports here; let the rules below decide what the page uses.
   Roman only; the page uses no italic. */

@font-face {
	font-family: "Source Sans 3";
	font-style: normal;
	font-weight: 200 900;
	font-display: swap;
	src: url("fonts/source-sans-3-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "Source Sans 3";
	font-style: normal;
	font-weight: 200 900;
	font-display: swap;
	src: url("fonts/source-sans-3-latin-ext.woff2") format("woff2");
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* Design tokens */
:root {
	--idsep-dark: #1f282c;
	--idsep-teal: #00ead0;
	--idsep-cyan: #00ace7;
	--idsep-cyan-mid: #16b1d1;
	--idsep-blue-bright: #0099d5;
	--idsep-blue: #0079a5;
	--idsep-blue-deep: #00689c;
	--idsep-navy: #104864;
	--idsep-orange: #ff9632;
	--idsep-orange-deep: #fa6423;
	/* NOT the Figma "Web-Brand-Blue" despite the name - that is #0099d5, above, as
	   --idsep-blue-bright. This token is still used by .idsep-header__logo; whether that tile
	   should also be #0099d5 is unconfirmed with the designer. */
	--idsep-brand-blue: #00aae5;
	--idsep-light-blue: #80d4f2;
	--idsep-white: #ffffff;

	/* Card heading on hover. Read from the Figma API on 2026-09-07, node 80:131 — the first
	   primary card in the Fulfillment section, which is drawn in its hover state:
	     linear-gradient(52deg, rgba(128,212,242,1) 0%, rgba(0,234,208,1) 95%)
	   Was 87deg with stops at 8.22% / 93.99%, taken from a Dev Mode reading that turned out to
	   be a different node. The angle is the substantive change: at 87deg the ramp ran almost
	   horizontally, where 52deg carries it diagonally across the heading. */
	--idsep-heading-hover: linear-gradient(
		52deg,
		var(--idsep-light-blue) 0%,
		var(--idsep-teal) 95%
	);

	--idsep-icon-shadow: 4.317px 4.317px 8.633px rgba(0, 170, 229, 0.2);

	/* Frost component of Figma's Glass effect on the card icon (Group 75154).
	   Figma reports Light -45deg/80%, Refraction 44, Depth 1.86, Dispersion 31, Frost 32.63,
	   Splay 32. As with the card, only Frost has a CSS analogue — a backdrop blur.
	   Scaled off the one reference point already in this file: the card uses blur(6px) for a
	   Frost of 7, so 32.63 extrapolates to roughly 28px. Kept as a token because that
	   extrapolation assumes a linear Frost scale, which is an assumption, not something Figma
	   documents — and 28px is nearly half the icon's 62px diameter, so it frosts heavily.
	   Tune here if it reads too strong against the real assets.
	   Depth is 1.86 (against the card's 26), so no sheen/inset highlight is applied — the
	   --idsep-card-sheen stand-in would be wrong at this depth. */
	--idsep-icon-frost: 28px;

	/* Darkening half of the glass. Figma's Glass composites its backdrop noticeably darker —
	   Light is 80%, and refraction/dispersion/depth all shade it. A CSS backdrop-filter blur
	   preserves average brightness, so blur alone leaves the disc far too bright and too orange
	   against the design render.
	   0.45 black is not arbitrary: sampling the design render put the visible disc at ~55% of
	   the fully-opaque gradient in every channel (#54E1D1 -> #2C807B is x0.52 / x0.57 / x0.59),
	   and a near-constant ratio across channels is what compositing over near-black looks like.
	   0.45 black over an opaque fill leaves exactly 0.55 of it.
	   This lives on the glass layer, not as a lowered opacity on the disc, because that is where
	   Figma puts it — node 80-55 carries NO opacity, it is fully opaque, and the dimming belongs
	   to the glass above it. Tune here, not on the disc. */
	--idsep-icon-glass-tint: rgba(0, 0, 0, 0.45);

	/* Width of the antialiasing ramp on the icon ring's mask. Must resolve to exactly ONE
	   DEVICE pixel, which is why it tracks the pixel ratio the same way --idsep-ring-width
	   does: 1px at 1x, 0.5px at 2x.
	   A single fixed value cannot work. At 0.5px the ramp is half a device pixel on a standard
	   monitor, so it falls inside one pixel and the browser approximates it differently at
	   different points around the curve — the ring reads rough and broken rather than smooth.
	   At 1px on retina it would be two device pixels, which is soft. One device pixel is the
	   only value that is both smooth and crisp at a given ratio. */
	--idsep-icon-feather: 1px;

	--idsep-wrapper: 1436px;
	/* Expressed as "whatever is left once the 1436px content width is satisfied", not as a
	   fixed 242px. At a true 1920 of usable width this resolves to exactly 242, matching the
	   Figma artboard. It matters when it cannot: a classic scrollbar leaves 1905 of layout
	   width, where a fixed 242 gutter would leave the wrapper at 1421 - 15px short. That is not
	   invisible. It narrows the card text column from 317 to 313.28 and reflows headings away
	   from the design; measured against Figma node 3:506, whose heading frame is 317 x 120 and
	   breaks as "What Top Supply Chain / Teams Look for Before / They Buy". Letting the gutter
	   give up those few pixels keeps every line break as drawn, on every machine.
	   The 60px floor keeps the gutter sane as the viewport approaches 1436, and every
	   breakpoint at 1440 and below overrides this value and is untouched. */
	--idsep-gutter: max(60px, (100% - 1436px) / 2);

	/* Bar height, and therefore the side of the logo square - the square is drawn flush to
	   the bar's full height, so the two are the same number by design. Stepped down below
	   400 (see that block). Nothing else measures off the header: it is not sticky and no JS
	   reads its height, so this is safe to vary per breakpoint. */
	--idsep-header-h: 77px;

	/* Floor for the header's left padding, so the first in-flow child (the wordmark) clears
	   the logo square: the square plus the header's own 24px gap. Overridden to a flush
	   square-width below 768, where the nowrap wordmark is 275.8px wide and
	   375 - 20px right gutter - 275.8 leaves only 79.2px for the left padding: 101 pushes it
	   1.8px off-screen and the page scrolls sideways. Flush is the only value that fits on a
	   phone at 19.5px type. */
	--idsep-header-pad-min: calc(var(--idsep-header-h) + 24px);

	/* Thickness of every gradient ring on the page — pills and both card tiers.
	   Figma specifies 1.5px. A fractional CSS pixel only renders cleanly when it lands on
	   whole device pixels, so this is resolution-dependent:
	     1x  -> 2px. 1.5px would round to 1 or 2 depending on subpixel position and engine,
	            giving edges of uneven weight; and a true 1px stroke around a 15-20px radius
	            antialiases so thinly that the corner arcs read as broken.
	     2x+ -> 1.5px, which is exactly 3 device pixels. Crisp, and matches the design.
	   See the override below. Change both to change every ring together. */
	--idsep-ring-width: 2px;

	/* Stand-in for the Light and Depth parameters of Figma's Glass effect, which CSS cannot
	   express. Tuned for DARK glass — roughly a fifth of the opacity a light-glass recipe
	   would use. Set to `none` to remove it. */
	--idsep-card-sheen: inset 0 1px 0 rgba(255, 255, 255, 0.07);

	--idsep-pill-border: linear-gradient(130deg, #ff9632 0%, #ffffff 25%, #00ead0 50%, #00aae5 100%);
	--idsep-pill-glow: rgba(128, 212, 242, 0.8);

	/* Card border gradients. Read from the stroke editor, not Dev Mode — Dev Mode flattens
	   gradient strokes to their first stop. Both run top-right to bottom-left and share the
	   same 0/17/62/100 stop positions.
	   At rest every card uses the cool default; on pointer hover primary cards cross-fade a
	   warm gradient ring over the rest border (see the hover block below).

	   Stops and angle are Figma's literal values. Two earlier attempts remapped them to
	   compensate for CSS normalising its gradient line to the box corners while Figma uses
	   absolute handle coordinates — but both corrections were derived from pixel-estimates of
	   the handle position and drifted further from the design rather than closer, so they were
	   reverted. If this needs tuning again, tune against a 100% Figma screenshot, not maths on
	   estimated coordinates.
	   Note most of this border is invisible by design: #104864 sits so close to the card
	   background that only the blue (top-right), orange (top-left) and teal (bottom-left)
	   actually read. That is correct, not a bug. */
	/* Stops are composed into linear card borders. Card ramps fade to transparent at the last
	   stop, so a conic ring would be needed to sweep them evenly around a circle — but the icon
	   ring is a separate Figma ramp with no transparent stop, defined below. */
	--idsep-card-border-stops: #1f282c 0%, #104864 17%, #00689c 62%, rgba(0, 104, 156, 0) 100%;
	--idsep-card-border-hover-stops: #00aae5 0%, #104864 17%, #ff9632 62%, #00ead0 100%;
	--idsep-card-border: linear-gradient(225deg, var(--idsep-card-border-stops));
	--idsep-card-border-hover: linear-gradient(225deg, var(--idsep-card-border-hover-stops));
	/* Icon ring — own Figma ramp (Ellipse 943), not inherited from the card border.
	   Linear 180deg to match the disc; stroke angle was not reported in Dev Mode. */
	--idsep-icon-ring: linear-gradient(180deg, var(--idsep-orange) 0%, var(--idsep-teal) 50%, var(--idsep-blue-bright) 100%);


	--idsep-font: "Source Sans 3", "Source Sans Pro", Arial, sans-serif;
}

/* On 2x and above, 1.5px is exactly 3 device pixels — crisp, and the value Figma specifies. */
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
	:root {
		--idsep-ring-width: 1.5px;
		/* One device pixel at 2x. See the token's definition in :root. */
		--idsep-icon-feather: 0.5px;
	}
}

@media (max-width: 1440px) {
	:root {
		--idsep-gutter: 60px;
	}
}

@media (max-width: 1240px) {
	:root {
		--idsep-gutter: 40px;
	}
}

@media (max-width: 1024px) {
	:root {
		--idsep-gutter: 32px;
	}
}

@media (max-width: 1023px) {
	:root {
		--idsep-gutter: 24px;
	}
}

@media (max-width: 767px) {
	:root {
		--idsep-gutter: 20px;
		/* Flush against the logo square - see the token's definition in :root. */
		--idsep-header-pad-min: var(--idsep-header-h);
	}
}

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

body.page-template-tpl-innovation-drop-sep-2026-php {
	background-color: var(--idsep-dark);
	/* The page's two fills, matching the Figma page frame (1920 x 8215), which carries an
	   Image fill above a Linear fill. CSS paints the FIRST layer on top, so the noise is
	   listed first for the same stacking.
	   Gradient is Figma Dev Mode's own CSS, verbatim: 129deg, Deep Blue -29.67%, Slate Grey
	   42.03%. Both stops sit outside 0-100 deliberately - the ramp starts above the page and
	   finishes 42% down, so the lower half is flat Slate Grey.
	   Nothing between here and the content may paint an opaque background, or this is hidden:
	   the hero and every section are deliberately transparent.
	   Tile is 50px, per Figma's CSS. The asset is 100x100 lossless WebP, 8.6KB: 50px at a 2x
	   device ratio is 100 device pixels, so the source maps 1:1 there and nothing is thrown
	   away. Replaced 2026-09-08 with a downscale of the real Figma export (400x400 PNG, kept
	   in the task's assets/ folder). Serving the 400 itself costs 205KB and the browser
	   averages most of that grain away at a 50px tile, so it buys nothing.
	   The version before this was a palette-quantised 200x200 at 7.9KB whose tonal range had
	   been crushed to about a third of the source - RGB 19-53 and alpha 32-42 against the
	   original's 0-151 and 20-57. Means matched, so overall darkness was right, but the grain
	   was visibly flatter. Current file measures RGB 14-71, alpha 30-45.
	   Intensity is baked into the alpha channel and there are NO opaque pixels, so it layers
	   straight over the ramp - do NOT add opacity or mix-blend-mode, that would double-apply
	   it. If a 3x-sharp version is ever wanted, 150x150 lossless is 22.8KB. */
	background-image: url("img/noise-texture.webp"),
		linear-gradient(129deg, var(--idsep-blue) -29.67%, var(--idsep-dark) 42.03%);
	background-repeat: repeat, no-repeat;
	background-size: 50px 50px, 100% 100%;
	color: var(--idsep-white);
	font-family: var(--idsep-font);
	/* Reproduced from the child theme's style.css, which dequeue_divi_assets_on_idsep() drops.
	   Without it this template inherits the browser default, which on macOS is subpixel
	   antialiasing - visibly heavier glyphs than the grayscale rendering Figma uses, so the
	   type read as too thick at every weight even though the weights were correct. The rest of
	   the site gets `antialiased` from style.css; this restores parity rather than inventing a
	   new treatment. */
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* Divi's ePanel injects an inline <style> in wp_head() with
   `h1,h2,h3,h4,h5,h6 { font-family: "Source Sans Pro", ... }`. It has no !important, but a
   direct element selector beats an inherited value, so headings never picked up the family
   set on body — and the page ended up downloading Source Sans Pro as well as Source Sans 3.
   It is inline, so it cannot be dequeued; this outranks it on specificity. */
body.page-template-tpl-innovation-drop-sep-2026-php :is(h1, h2, h3, h4, h5, h6) {
	font-family: var(--idsep-font);
}

/* `footer.php` still emits <span class="et_pb_scroll_top et-pb-icon"> while Divi's
   `divi_back_to_top` option is on, but this template needs no rule to hide it. Measured on
   the rendered page with the hide removed: display inline, box 0x0, `::before` content
   `none`, no background — it paints nothing, because the CSS that gave it `position: fixed`,
   a background and the icon glyph is dequeued along with the rest of Divi's stylesheet.
   So no rule here. If Divi's assets are ever restored for this template, the hide has to come
   back AND it has to carry !important: `divi-custom-script` reveals the button with jQuery
   `.show()`, which writes an inline `display: block`, and only an author !important outranks
   an inline declaration. */

/* `.idsep-shell-bg` itself paints nothing - it is only a markup hook. Sections that do
   carry a fill get it by id below, because each one's values differ.
   WHY BY ID, and why not copy one section's values to the others: Figma stores gradient
   handles in the node's normalised space, and Dev Mode converts them to a CSS angle and
   stop percentages using that node's own box. These sections are 923 to 1389px tall, so the
   SAME gradient in Figma exports as a DIFFERENT `linear-gradient(...)` per section. Take
   each one's CSS from its own node; do not generalise one into a shared rule. */

/* Every section carries the same three stops - Teal, Web/Deep Blue #00689C, Slate Grey -
   with the ramp leaning left or right. The full set, in page order:
     max               328deg   -12.69 / 19.21 / 51.12
     fulfillment        32deg   -12.45 / 12.93 / 38.31
     analytics         334deg    -6.65 / 22.63 / 51.91
     visibility         41deg    -8.21 / 16.20 / 40.61
     revenue-recovery  334deg    -6.65 / 22.63 / 51.91
     manufacturing      26deg    -6.65 / 22.63 / 51.91   <- MIRRORED, Figma says 334
   Figma's own values give leans of L R L R L L - the mirror breaks on the last section only.
   Manufacturing is deviated to 26deg so the page reads L R L R L R; see its rule for the
   reasoning and how to revert. Everything else here is Figma verbatim.
   Do not otherwise "regularise" these into an every-other-one rule - an earlier version of
   this file did alternate them, on the vertical axis (0deg / 180deg) at that, which is the
   wrong axis as well as the wrong pattern, and never matched the design.
   The last three are byte-identical despite being 1358, 948 and 955px tall, so the numbers
   are NOT a per-node conversion artefact - they are the designer's handle placements, and
   sections that differ differ by intent. Take each from its own node; do not derive one from
   another's height.
   Web/Deep Blue #00689C is a different named style from the page ramp's Deep Blue #0079A5;
   both are in the palette, as --idsep-blue-deep and --idsep-blue. Easy to swap by mistake. */

/* MAX. Figma Dev Mode CSS, verbatim. */
#max.idsep-section {
	background-image:
		url("img/noise-texture.webp"),
		linear-gradient(
			328deg,
			var(--idsep-teal) -12.69%,
			var(--idsep-blue-deep) 19.21%,
			var(--idsep-dark) 51.12%
		);
	background-repeat: repeat, no-repeat;
	background-size: 50px 50px, 100% 100%;
}

/* Fulfillment. Figma Dev Mode CSS, verbatim. Mirrored against MAX, and its stops sit at
   different percentages because this section is 1389px tall against MAX's 1269 - see the
   note above on values being per node. */
#fulfillment.idsep-section {
	background-image:
		url("img/noise-texture.webp"),
		linear-gradient(
			32deg,
			var(--idsep-teal) -12.45%,
			var(--idsep-blue-deep) 12.93%,
			var(--idsep-dark) 38.31%
		);
	background-repeat: repeat, no-repeat;
	background-size: 50px 50px, 100% 100%;
}

/* Analytics and Revenue Recovery. Figma Dev Mode CSS, verbatim, and byte-identical across
   both even though the nodes are 1358 and 948px tall. Grouped for that reason rather than
   repeated - if one changes in the design, split it back out rather than editing this rule.
   Manufacturing exports these same values too but is deliberately NOT grouped here; see the
   deviation recorded on its own rule below. */
#analytics.idsep-section,
#revenue-recovery.idsep-section {
	background-image:
		url("img/noise-texture.webp"),
		linear-gradient(
			334deg,
			var(--idsep-teal) -6.65%,
			var(--idsep-blue-deep) 22.63%,
			var(--idsep-dark) 51.91%
		);
	background-repeat: repeat, no-repeat;
	background-size: 50px 50px, 100% 100%;
}

/* Visibility. Figma Dev Mode CSS, verbatim. Leans with Fulfillment. */
#visibility.idsep-section {
	background-image:
		url("img/noise-texture.webp"),
		linear-gradient(
			41deg,
			var(--idsep-teal) -8.21%,
			var(--idsep-blue-deep) 16.2%,
			var(--idsep-dark) 40.61%
		);
	background-repeat: repeat, no-repeat;
	background-size: 50px 50px, 100% 100%;
}

/* Manufacturing. DELIBERATE DEVIATION FROM FIGMA - needs designer confirmation.
   Figma exports this node identical to Analytics and Revenue Recovery, at 334deg, which
   makes the leans read L R L R L L down the page and breaks the mirror on the last section
   only. Radmilo's call is that this is a copy-paste slip in the design rather than intent,
   so the angle is mirrored to give L R L R L R.
   Mirroring a CSS gradient about the vertical axis is 360 - angle, hence 334 -> 26. The stop
   colours and percentages are Figma's, untouched; only the lean changes.
   If the designer confirms 334 was intended, the fix is to delete this rule and add
   #manufacturing back to the grouped selector above. */
#manufacturing.idsep-section {
	background-image:
		url("img/noise-texture.webp"),
		linear-gradient(
			26deg,
			var(--idsep-teal) -6.65%,
			var(--idsep-blue-deep) 22.63%,
			var(--idsep-dark) 51.91%
		);
	background-repeat: repeat, no-repeat;
	background-size: 50px 50px, 100% 100%;
}

.idsep-header {
	position: relative;
	height: var(--idsep-header-h);
	border-bottom: 1px solid #b1c5cf;
	background: transparent;
}

.idsep-header__inner {
	display: flex;
	align-items: center;
	gap: 24px;
	padding: 0 var(--idsep-gutter);
	/* The logo is a square, --idsep-header-h on a side, absolutely pinned to the viewport
	   edge outside the gutter, while the wordmark is the first in-flow child and so starts at
	   this padding edge. Below a 1590px layout width the gutter falls under 77px and the
	   square paints over the first
	   glyphs - "INNOVATION" read as "NOVATION" at 1440. Floor the left padding at the square
	   plus the header's own 24px gap. At 1920 the 242px gutter already wins, so the design
	   width is untouched. Replaces a mobile-only offset that covered only <= 1023.
	   This must live here, not as a margin on the wordmark: --idsep-gutter holds a `100%`
	   term, and custom properties substitute textually, so that percentage resolves against
	   the *using* element's containing block. On the wordmark that is this inner's 1436px
	   content box rather than the viewport, and the token collapses to its 60px floor. */
	padding-left: max(var(--idsep-header-pad-min), var(--idsep-gutter));
	height: 100%;
	width: 100%;
	box-sizing: border-box;
}

/* Solid brand-blue square flush to the viewport edge, outside the gutter, full bar height. */
.idsep-header__logo {
	position: absolute;
	left: 0;
	top: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	width: var(--idsep-header-h);
	height: var(--idsep-header-h);
	background: var(--idsep-brand-blue);
}

.idsep-header__logo svg {
	display: block;
	width: 46px;
	height: auto;
}

.idsep-header__wordmark {
	display: flex;
	align-items: center;
	gap: 6px;
	margin: 0;
	font-size: 19.5px;
	font-weight: 600;
	line-height: 1.07;
	white-space: nowrap;
}

.idsep-header__wordmark-gradient {
	text-transform: uppercase;
	background: linear-gradient(
		90deg,
		var(--idsep-teal) 0%,
		var(--idsep-cyan-mid) 69%,
		var(--idsep-cyan) 100%
	);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}

.idsep-header__wordmark-season {
	color: var(--idsep-orange);
}

.idsep-header__actions {
	display: flex;
	align-items: center;
	gap: 20px;
	margin-left: auto;
}

.idsep-header__lang .wpml-ls-legacy-dropdown,
.idsep-header__lang .wpml-ls-legacy-dropdown a {
	color: var(--idsep-white);
	font-size: 14px;
}

/* Figma spec for .idsep-header__link. Two deliberate deviations from what the panel reported:
   the family is Source Sans 3, not the "Open Sans" Figma listed - this template self-hosts only
   Source Sans 3 and loads no Open Sans face, so that value would have fallen back to a different
   system font on every OS (Radmilo's call, 2026-09-08); and 12.97px is normalised to 13px, the
   same treatment the hero's 1441.42 and 220 already get in this build. */
.idsep-header__link {
	color: var(--idsep-white);
	font-family: var(--idsep-font);
	font-size: 13px; /* Figma 12.97px */
	font-weight: 600;
	line-height: 1.07; /* Figma 107% */
	text-decoration: none;
	transition: color 0.25s ease;
}

/* Only the spscommerce.com link is underlined. Figma reported the underline against
   .idsep-header__link, but Login is deliberately plain - Radmilo's call, 2026-09-08. */
.idsep-header__link--site {
	text-decoration-line: underline;
	text-underline-position: from-font;
}

/* Hover uses --idsep-light-blue rather than a new colour: it is already this page's
   interactive accent, being the opening stop of --idsep-heading-hover and the stat-bar label
   colour. No glow here on purpose - at 13px a text-shadow softens the glyph edges and costs
   more legibility than it buys; the glow language belongs to the icon discs and card borders.
   :focus-visible is paired with :hover throughout this file so keyboard users get the same
   affordance. */
.idsep-header__link:hover,
.idsep-header__link:focus-visible {
	color: var(--idsep-light-blue);
}

/* The underline drops away on hover, matching .idsep-card__link. */
.idsep-header__link--site:hover,
.idsep-header__link--site:focus-visible {
	text-decoration-line: none;
}

.idsep-header__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 9px 20px;
	border: 0;
	/* Figma: 40px. The button computes to 32px tall, so this and the previous 999px both clamp
	   to 16px and render identically - kept at the spec value so it stays right if the button
	   ever grows past 80px tall. */
	border-radius: 40px;
	/* Figma "Web-Brand-Blue" #0099D5, which is --idsep-blue-bright. This was
	   --idsep-brand-blue (#00aae5), a lighter, more cyan blue - the wrong token despite the
	   name. See the note on --idsep-brand-blue in :root. */
	background: var(--idsep-blue-bright);
	color: var(--idsep-white);
	font-family: var(--idsep-font);
	font-size: 14px;
	font-weight: 600;
	line-height: 1;
	text-decoration: none;
	cursor: pointer;
	transition: background-color 0.25s ease;
}

/* Hover darkens to --idsep-blue. Measured, not chosen on looks: the label is 14px/600 white,
   which WCAG treats as normal text needing 4.5:1. White on the rest fill #0099d5 is only
   3.22:1, and lightening to --idsep-cyan would have dropped it to 2.61:1 - a hover state less
   legible than the resting one. #0079a5 gives 4.91:1 and passes.
   NOTE: the Figma hover state for this button has not been read (the Figma API was rate limited
   on 2026-09-08). Replace it if the design specifies something else, but check the contrast of
   whatever it specifies. */
.idsep-header__btn:hover,
.idsep-header__btn:focus-visible {
	background: var(--idsep-blue);
}

/* Paints nothing. The page's gradient and noise are both on the body, which is the only
   element on this template with a background. */
main.idsep {
	display: block;
	font-family: var(--idsep-font);
	line-height: 1.5;
	color: var(--idsep-white);
}

.idsep-wrapper {
	max-width: var(--idsep-wrapper);
	margin-inline: auto;
	width: 100%;
}

/* The hero's Figma fill list is FOUR layers, top to bottom:
     1. Linear  - fade to Slate Grey
     2. Video   - the particle animation, which we build as .idsep-hero__canvas
     3. Image   - the noise tile
     4. Linear  - the 129deg ramp
   Dev Mode's CSS only exports 1, 3 and 4; it silently drops the video, which is why pasting
   that CSS straight in put all three on the element and left the canvas floating above the
   lot. The animation has to sit BETWEEN the noise and the fade, so the stack is split:
     - layers 4 and 3 here, as the element's own background, painting below every child;
     - the canvas at z-index 0;
     - layer 1 on ::after at z-index 1, above the canvas;
     - the content wrapper at z-index 2.
   An element's own background always paints below its children, so there is no ordering of
   background layers alone that can put the fade over the canvas - it has to be an overlay.
   Tile is 50px, matching the body - Radmilo confirmed Figma's CSS for both nodes uses
   50px, and the body was corrected from 100px to match.
   Figma also emits `lightgray` as a placeholder on the image layer; dropped, since only the
   last layer of the shorthand may carry a colour and the tile is transparent by design. */
.idsep-hero {
	position: relative;
	overflow: hidden;
	padding: 80px var(--idsep-gutter);
	display: flex;
	flex-direction: column;
	gap: 60px;
	background-image:
		url("img/noise-texture.webp"),
		linear-gradient(129deg, var(--idsep-blue) -29.67%, var(--idsep-dark) 42.03%);
	background-repeat: repeat, no-repeat;
	background-size: 50px 50px, 100% 100%;
	background-position: 0 0, 0 0;
}

/* Fill layer 1, lifted out of the background so it paints OVER the canvas. Spans the whole
   hero with the ramp starting at 78.67%, exactly as the fill is drawn - not a short fixed
   strip pinned to the bottom, which is what an earlier version of this rule did. */
.idsep-hero::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background-image: linear-gradient(180deg, rgba(31, 40, 44, 0) 78.67%, var(--idsep-dark) 100%);
}

.idsep-hero__canvas {
	position: absolute;
	inset: 0;
	z-index: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
}

/* REMOVED 2026-09-08: `.idsep-hero::after`, a 180px fade from transparent to
   --idsep-dark over the bottom of the hero. It was the only band-level gradient left on the
   page and it read as a dark strip against the new page ramp. The page gradient on
   main.idsep is now the single background gradient on the template, which is the point.
   CONSEQUENCE, not yet addressed: that overlay also sat above the particle canvas so the
   animation dissolved into the hero's bottom edge instead of being cut off square. With it
   gone the canvas ends hard at the hero boundary. If that edge needs softening again, do it
   with a mask on the canvas rather than a painted gradient, so the page ramp stays the only
   gradient. The removed rule was:
     .idsep-hero::after { content:""; position:absolute; right:0; bottom:0; left:0;
       height:180px; z-index:1; pointer-events:none;
       background: linear-gradient(180deg, rgba(31,40,44,0) 0%, var(--idsep-dark) 100%); }
   Figma drew it as a separate rectangle: #1F282C at 0% alpha to the same colour at 100%. */

/* The hero's own gap can't space these: its only in-flow child is this wrapper (the canvas
   is absolute). The 60px between the H1 and the content row belongs here.
   z-index 2 keeps the copy above the fade overlay, which is z-index 1. */
.idsep-hero > .idsep-wrapper {
	position: relative;
	z-index: 2;
	display: flex;
	flex-direction: column;
	gap: 60px;
	/* Makes this the size container the H1 sizes itself against - see .idsep-hero__title.
	   Safe here: `inline-size` containment does not contain block size, and this element is
	   already `position: relative` with a `z-index`, so it was already both a containing
	   block for absolute descendants and a stacking context. The hero canvas and fade are
	   children of .idsep-hero, not of this wrapper, so neither is affected. */
	container-type: inline-size;
}

/* Measured from Figma V8: Source Sans 3 700, 73px, 107% line-height. */
/* The design is one line, and at 73px it fits by 0.62px: the string measures 1126.38px
   against a 1127px max-width taken from the Figma frame. So any width below that wrapped -
   and wrapped badly, orphaning "Here!" on a second line at 934 + 178 rather than breaking
   evenly. Natural width is linear in size at 15.4299 x font-size, so the largest size that
   still fits one line is 100cqw / 15.4299 = 6.4809cqw; 6.47 is used to hold ~2px of slack
   against subpixel rounding. The 73px cap takes over once the wrapper passes ~1128, so the
   design width is untouched.
   Container units, not vw, for two reasons: the wrapper is not a fixed offset from the
   viewport here - the gutter steps 60 / 40 / 32 across three sub-bands, so vw would need
   three formulas - and vw would additionally have to assume a scrollbar width. 100cqw is
   the wrapper's own content box, which is exactly the width the line must fit.
   The 40px and 32px rules below 1024 and 768 override this and are unaffected. */
.idsep-hero__title {
	margin: 0;
	max-width: 1127px;
	font-size: min(73px, 6.47cqw);
	font-weight: 700;
	line-height: 1.07;
	background: linear-gradient(
		90deg,
		var(--idsep-teal) 0.01%,
		var(--idsep-cyan-mid) 69%,
		var(--idsep-cyan) 100%
	);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}

/* Figma row 2 (New Brand 59930:21286) is 1442 wide with a 128 gap: a fixed 688 text frame
   and a 625.71 badge group, since the hero moved from three badges to all six (group
   61778:15056, 2026-09-11). Before that the group was 539.35 and the text column ~775. */
.idsep-hero__row {
	display: grid;
	/* Both tracks shrink together, in the design's own 688:626 ratio. At our 1436 wrapper the
	   128 gap leaves 1308, which that ratio splits ~685 / ~623. It was 768:540 until the
	   six-badge group replaced the three. Before that it was `minmax(0, 1fr) 540px`, which
	   pinned the badge column and made the text column absorb every pixel lost as the
	   viewport narrowed: at a 1105 wrapper the text was down to 437 against its design 768,
	   while the badges still had all 540. */
	grid-template-columns: minmax(0, 688fr) minmax(0, 626fr);
	gap: 128px;
	/* The gap is the second biggest consumer of the row, so it scales on the same basis
	   rather than staying a fixed 128 while everything around it shrinks: 128/1436 = 8.914%
	   of the wrapper, capped at the design value. cqw is the hero wrapper - see
	   .idsep-hero__title for why this element is a size container. Column only: the row gap
	   applies when this collapses to one column below 1024, which has its own 40px rule. */
	column-gap: min(128px, 8.914cqw);
	align-items: start;
}

/* Figma type token "SPS P 16": Source Sans 3 400, 16px, 125%. Container is 688px. */
.idsep-hero__intro {
	margin: 0 0 40px;
	max-width: 688px;
	font-size: 16px;
	font-weight: 400;
	line-height: 1.25;
}

.idsep-hero__pills {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 290px));
	gap: 29px;
	justify-content: start;
	padding: 0;
	margin: 0;
	list-style: none;
}

/* Measured from Figma: 290 x 69, radius 15, no fill, gradient stroke + glow.
   All six pills are identical. Figma's Dev Mode reports this as `1.5px solid #FF9632`
   because it flattens gradient strokes to their first stop — the stroke editor shows the
   real four-stop gradient.
   Stroke is 1.5px in the design; drawn at 2px (--idsep-pill-ring-width). Fractional border
   widths are valid CSS but snap to whole device pixels, so at 1x DPR 1.5px rounds to 1 or 2
   depending on subpixel position and engine, giving uneven edges. A whole value is crisp at
   every DPR. Glow is a drop shadow on hover/focus only — none at rest. */
.idsep-hero__pill {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 69px;
	padding: 0 40px;
	border-radius: 15px;
	background: transparent;
	box-shadow: none;
	color: var(--idsep-white);
	font-size: 20px;
	font-weight: 600;
	text-align: center;
	text-decoration: none;
	transition: box-shadow 0.2s ease;
}

/* Gradient ring via a masked pseudo-element. The padding-box/border-box double-background
   trick can't be used here: it needs an opaque fill and this pill is transparent.
   Uses a real transparent BORDER + a padding-box mask, not `padding` + a content-box mask.
   A content box is a sharp rectangle with no corner radius, so the mask hole cuts straight
   across the curve and visibly thins/breaks the ring at each corner. With a border, the
   browser derives the padding-box radius (outer minus border width) and the hole follows
   the curve correctly. */
.idsep-hero__pill::before {
	content: "";
	position: absolute;
	inset: 0;
	box-sizing: border-box;
	border: var(--idsep-ring-width) solid transparent;
	border-radius: inherit;
	background: var(--idsep-pill-border) border-box;
	-webkit-mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	pointer-events: none;
}

.idsep-hero__pill:hover,
.idsep-hero__pill:focus-visible {
	box-shadow: 0 0 10px 0 var(--idsep-pill-glow);
	outline: none;
}

/* All six badges as a 3 x 2 grid, from New Brand group 61778:15056 (2026-09-11): 625.71 x
   410.18, six 200.33 squares, rows MAX / Fulfillment / Analytics over Visibility / Revenue
   Recovery / Manufacturing, with ~12.4 between columns and ~9.5 between rows, rounded here
   to 12 / 10. The 1fr tracks divide the badge column, so the group scales with it down to
   1241. The stacked bands set fixed tracks instead: 180 at 1024-1240, and the compact 120
   below 1024 settled after the 2026-09-11 review call - see those blocks.
   Until the six-badge design this was a flex row of three, two per row in a 540 column. */
.idsep-hero__badges {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	column-gap: 12px;
	row-gap: 10px;
	max-width: 626px;
}

/* `aspect-ratio` keeps them square without restating the width. */
.idsep-hero__badge {
	width: 100%;
	aspect-ratio: 1;
	height: auto;
}

/* Revenue Recovery's artwork fills 92.4% of its 484 canvas, against 96.5-99.2% for the other
   five (measured opaque bounds), so at the same box size it reads ~6% smaller. Figma
   compensates the same way: its rect is cropped to 0.9366, i.e. the artwork is drawn at
   1 / 0.9366 = 1.068. `transform` leaves the grid track untouched, and the file's own
   transparent margin (~8px a side at 200, ~4.5px at 120) absorbs the growth, so the patch does
   not visibly reach its neighbours at any size the hero uses. */
.idsep-hero__badge--revenue-recovery {
	transform: scale(1.068);
}

.idsep-section {
	padding: 100px var(--idsep-gutter);
}

/* Same shape as the hero: the section's only child is this wrapper, so the 60px between the
   head, the primary row and the secondary row has to live here, not on the section. */
.idsep-section > .idsep-wrapper {
	display: flex;
	flex-direction: column;
	gap: 60px;
}

/* NO per-section gradient, and no alternating direction. A `:nth-child` rule here used to
   flip every other section; both it and the section gradients were removed 2026-09-08 once
   the design was actually read. Figma carries ONE Linear fill on the whole 1920 x 8215 page
   frame, so a gradient composed per section can never match it - each copy restarts the ramp
   at its own top. Whatever the page-level ramp ends up being, it does not belong here. */

/* Figma: 1436 x 202, align-items: center, gap 50. Badge 170 + 50 + copy 1216 = 1436. */
.idsep-section__head {
	display: flex;
	align-items: center;
	gap: 50px;
}

/* Copy column: Figma Frame 1000005104 — column, gap 50, flex: 1 0 0. */
.idsep-section__copy {
	display: flex;
	flex: 1 1 0;
	flex-direction: column;
	align-items: flex-start;
	gap: 50px;
	min-width: 0;
}

.idsep-section__badge {
	width: 170px;
	height: 170px;
	flex-shrink: 0;
}

/* Figma node 80:108 — Source Sans 3 ExtraBold, 55px, line-height 1.07em. */
.idsep-section__heading {
	margin: 0;
	font-size: 55px; /* was 40px */
	font-weight: 800; /* was 700 */
	line-height: 1.07; /* was 1.08 */
}

/* Figma node 80:109 — "SPS H4": SemiBold 600, 25px, line-height 1.25em. */
.idsep-section__intro {
	margin: 0;
	font-size: 25px; /* was 18px */
	font-weight: 600;
	line-height: 1.25; /* was 1.6 */
	/* 30em caps the measure at roughly 66 characters at any size, since Source Sans 3
	   averages 0.452 x font-size per character (measured) and 1em therefore carries ~2.2
	   characters. The previous 52em only bound above a ~1300px column, so it never engaged at
	   any width this page actually renders at - the line length was whatever the wrapper
	   happened to be. */
	max-width: 30em;
}

.idsep-card-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* The two rows are not spaced the same in Figma: the primary row is `space-between` across
   1436 with 694 cards, which works out at 48; the secondary row sets an explicit 60. */
.idsep-card-grid--primary {
	gap: 48px;
}

.idsep-card-grid--secondary {
	gap: 60px;
}

.idsep-card {
	box-sizing: border-box;
}

/* Gradient border via a masked pseudo-element.
   The padding-box/border-box double-background trick does NOT work here: it needs an
   opaque padding-box layer to mask the gradient, and this card's fill is rgba(0,0,0,0.2).
   With a translucent fill the border gradient bleeds through the whole card. */
.idsep-card--primary {
	position: relative;
	display: flex;
	/* Held as custom properties because the mobile full-bleed media rule cancels this exact
	   padding with negative margins. Repeating the numbers there would let the two drift the
	   moment either is touched — this file already has five recorded cases of paired values
	   falling out of step. Change the padding here and the bleed follows. */
	--idsep-card-pad-y: 50px;
	--idsep-card-pad-x: 40px;
	padding: var(--idsep-card-pad-y) var(--idsep-card-pad-x);
	align-items: flex-start;
	gap: 30px;
	border-radius: 20px;
	background: rgba(0, 0, 0, 0.2);
	/* Approximation of Figma's "Glass" effect on this card. Glass is a Figma-only render
	   effect with six parameters — Light -39deg/80%, Refraction 48, Depth 26, Dispersion 28,
	   Frost 7, Splay 29. Only Frost has a CSS analogue (a backdrop blur); refraction,
	   dispersion, depth and splay cannot be expressed in CSS at all. Frost is low (7), so the
	   blur is deliberately slight. The value is a judgement call, not a measured conversion —
	   Figma's Frost scale does not map to pixels.
	   Deliberately NOT reproduced: the white fills, white border, inset highlights and drop
	   shadow from the common glassmorphism recipe. Those assume light glass on a bright
	   background; this card is dark glass on a dark gradient, and they would wash it out.
	   Note this is a real cost: backdrop-filter forces compositing on every card. */
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
	box-shadow: var(--idsep-card-sheen);
}

/* Border + padding-box mask, not `padding` + content-box: a content box has no corner
   radius, so the mask hole cuts straight across the curve and thins the ring at each
   corner. See the same note on .idsep-hero__pill::before. */
.idsep-card--primary::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	box-sizing: border-box;
	border: var(--idsep-ring-width) solid transparent;
	border-radius: inherit;
	background: var(--idsep-card-border) border-box;
	-webkit-mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	pointer-events: none;
}

/* Hover ring — a duplicate of ::before carrying the warm gradient, cross-faded in on hover.
   CSS cannot interpolate between gradient images, so both rings stay present and opacity
   animates instead of swapping ::before's background. */
.idsep-card--primary::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	box-sizing: border-box;
	border: var(--idsep-ring-width) solid transparent;
	border-radius: inherit;
	background: var(--idsep-card-border-hover) border-box;
	-webkit-mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.25s ease;
}

/* Absolutely positioned, so it is not a flex item — but keep content above it. */
.idsep-card--primary > * {
	position: relative;
	z-index: 1;
}

.idsep-card__media {
	flex: 0 1 43.4%;
	max-width: 267px;
	aspect-ratio: 267 / 326;
	/* 15px, not the 8px this carried until 2026-09-10. The design uses ~15px — 14.93px appears
	   six times, one per section — and every asset-board export frame is 15px. The radius is
	   applied HERE and never baked into the file, so it lives in one place: the supplied PNGs
	   are square-cornered (measured, corner alpha 254/255) and `overflow: hidden` above does
	   the rounding. */
	border-radius: 15px;
	overflow: hidden;
	background: rgba(255, 255, 255, 0.06);
}

/* <picture> is an inline wrapper the browser inserts between the slot and the image; without
   this it sizes to the img's intrinsic box and the object-fit below has nothing to fill. */
.idsep-card__media picture {
	display: block;
	width: 100%;
	height: 100%;
}

.idsep-card__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.idsep-card__content {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: 20px;
	min-width: 0;
}

/* Icon and category pill share a row — Figma node 80:119: row, align-items center, gap 15px,
   both axes hugging their content. They were stacked as separate children of the card's flex
   column until 2026-09-07.
   `align-self: flex-start` keeps the row itself hugging rather than stretching to the card
   width, the same reason the CTA needs it: these are flex items in a column, so they are
   blockified and would otherwise fill the cross axis. */
.idsep-card__icon-row {
	display: flex;
	align-self: flex-start;
	align-items: center;
	gap: 15px;
}

/* Card icon — built in CSS, values measured from Figma (Group 75154, 62x62).
   Outer ring is Ellipse 943, inner gradient disc is Ellipse 942, glyph sits on top. */
.idsep-card__icon {
	position: relative;
	display: inline-grid;
	place-items: center;
	/* border-box because Figma's 62px (Ellipse 943) is the OUTER diameter, ring included.
	   Without it the border adds on top and the icon renders 65px at 2x, 66px at 1x — and it
	   would change size between pixel ratios, since --idsep-ring-width differs. */
	box-sizing: border-box;
	width: 62px;
	height: 62px;
	flex-shrink: 0;
	border-radius: 50%;
	/* Same ring width as every other stroke on the page — 2px at 1x, 1.5px at 2x+. See the
	   --idsep-ring-width comment in :root for why a fractional border only works on retina. */
	border: var(--idsep-ring-width) solid var(--idsep-white);
	box-shadow: var(--idsep-icon-shadow);
	/* No backdrop-filter here on purpose, and not merely because the glass is hover-only: it
	   would frost the card BEHIND the icon while leaving the gradient disc sharp on top, which
	   is the opposite of what Figma does. The glass is its own layer above the disc — see
	   .idsep-card__icon-glass. */
	transition: border-color 0.25s ease;
}

/* The inner gradient disc and the gradient ring are both hover-only: at rest the icon is
   just its outline and glyph. Kept in the DOM at opacity 0 rather than toggled with
   display, so nothing reflows and the disc can be faded later if wanted. */
/* Not a fixed 54px. An absolutely positioned pseudo-element resolves against the PADDING box,
   so the inset stays correct when --idsep-ring-width changes between 1x and 2x. Measured off
   the design: the fill runs continuously to the ring (teal at r=30, ring at r=31), with no dark
   rim between them. A fixed 54px inside a 62px icon left ~3px of card background showing.

   The negative inset is a deliberate OVERLAP, not padding. The ring's mask feathers from 0 to
   full alpha over its first --idsep-icon-feather, so a disc ending at the padding box edge
   (inset: 0) stops exactly where the ring is still translucent, leaving a band with neither the
   disc nor a solid ring in it — card background shows through as a hairline seam. Measured at
   2x before this was fixed: disc ended at r29.5, ring only reached full opacity at r30.

   It tracks the feather rather than being a fixed -1px, because the feather itself changes with
   pixel ratio (1px at 1x, 0.5px at 2x). A fixed -1px happened to give 0.5px of overlap at 2x but
   exactly ZERO at 1x once the feather widened — the disc would meet the ring's opaque edge
   precisely, where any rounding reopens the seam. The extra 0.5px keeps a real overlap at both
   ratios: disc edge lands at r30.5 either way, always under the ring's opaque region and always
   inside the icon's r31 outer edge. */
.idsep-card__icon::before {
	content: "";
	position: absolute;
	inset: calc(-1 * var(--idsep-icon-feather) - 0.5px);
	border-radius: 50%;
	background: linear-gradient(
		180deg,
		var(--idsep-orange-deep) 0%,
		var(--idsep-teal) 50%,
		var(--idsep-blue-bright) 100%
	);
	box-shadow: var(--idsep-icon-shadow);
	opacity: 0;
	transition: opacity 0.25s ease;
}

/* Gradient ring, masked so only the border area paints. The negative inset is not a constant:
   an absolute pseudo-element resolves against the PADDING box, so the ring has to be pulled out
   by exactly the icon's own border width to cover it rather than sit inside it. That width is
   --idsep-ring-width (2px at 1x, 1.5px at 2x+), so the inset has to track it — hardcoding -1px
   would leave a half-pixel of white rim showing through on retina and a full pixel at 1x.
   Linear 180deg ramp — unlike the card border, this icon ramp has no transparent stop, so conic
   is not needed here. */
.idsep-card__icon::after {
	content: "";
	position: absolute;
	inset: calc(-1 * var(--idsep-ring-width));
	border-radius: 50%;
	background: var(--idsep-icon-ring);
	/* A radial mask, NOT the padding-box/border-box xor used on the cards and pills.
	   That technique cuts its hole with a hard, unantialiased edge. On a card it does not
	   show: the radius is 20px and most of the outline is straight. On a 62px circle every
	   pixel of the edge is curved, so the hole's staircase is visible all the way round and
	   the ring reads as jagged.
	   Here the hole is a radial-gradient stop instead, with a soft band that gives the
	   antialiasing the mask cannot. The OUTER edge needs no help — border-radius clipping of
	   the background is antialiased by the browser already. `closest-side` makes 100% resolve
	   to the circle's radius, so the band tracks --idsep-ring-width at both pixel ratios.

	   The feather is ONE-SIDED, running outward from the nominal inner edge (100% - W) rather
	   than straddling it. A straddling band (-0.5px to +0.5px) put half its width INSIDE the
	   ring, so the ink spread measured 2.5px at 1x and 2px at 2x against a token of 2px and
	   1.5px — visibly thicker and softer than the card border, which is crisp. Starting the
	   band at exactly 100% - W means the painted ring is never wider than the token: ink runs
	   from (100% - W) at 0 alpha to full opacity 0.5px later, then out to the edge. Measured
	   spread is now 2px at 1x and 1.5px at 2x, matching the card and pill strokes. */
	-webkit-mask: radial-gradient(
		circle closest-side,
		transparent calc(100% - var(--idsep-ring-width)),
		#000 calc(100% - var(--idsep-ring-width) + var(--idsep-icon-feather))
	);
	mask: radial-gradient(
		circle closest-side,
		transparent calc(100% - var(--idsep-ring-width)),
		#000 calc(100% - var(--idsep-ring-width) + var(--idsep-icon-feather))
	);
	opacity: 0;
	transition: opacity 0.25s ease;
	pointer-events: none;
}

/* Glass layer — Figma node 80-56, sitting directly on top of the gradient disc (node 80-55).
   That stacking is the entire point of this element. backdrop-filter blurs whatever is painted
   BEHIND the element, so putting it on .idsep-card__icon frosted the card behind the circle
   while ::before painted the gradient sharp on top — the glass never touched the gradient, which
   is why the disc read as a hard orange-to-blue ramp instead of the diffuse teal glow the design
   shows. Sitting above ::before, the gradient becomes part of this element's backdrop and gets
   frosted, which is what Figma is doing.

   A real element rather than a third pseudo because ::before and ::after are already the disc
   and the ring. Paint order inside the icon is: ::before (disc), this span, the glyph <img>,
   then ::after (ring) — pseudo-before, then DOM children in order, then pseudo-after. So the
   glyph stays sharp above the frost and the ring paints over everything.

   Inset matches the disc exactly so the frost covers the same area, including the disc's
   overhang under the ring. HOVER ONLY: no glass at rest. */
.idsep-card__icon-glass {
	position: absolute;
	inset: calc(-1 * var(--idsep-icon-feather) - 0.5px);
	border-radius: 50%;
	opacity: 0;
	transition: opacity 0.25s ease;
	pointer-events: none;
}

/* backdrop-filter is declared only here, not at rest with opacity 0 — an opacity-0 element
   carrying a backdrop-filter still forces compositing for every icon on the page. Declared on
   hover, the second backdrop root exists for one icon at a time. The fade comes from opacity,
   which composites the filtered backdrop, so the frost still eases in over 0.25s. */


/* Each glyph renders at its OWN intrinsic size — no fixed pair, no normalising cap.
   Held 26x21 until 2026-09-10 (the old placeholder's ratio, which squashed the real icons),
   then briefly a 33x33 cap taken from the first real icon delivered. That was a generalisation
   from one sample: the icons are 33x33, 38x19 and 28x28 so far, drawn at deliberately
   different sizes, and a single cap would have shrunk the widest and normalised away the
   differences. Figma gives no glyph size to copy either — mockup node 80:120 is one flattened
   62x62 image with disc and glyph combined — so each file's own canvas is the intent.
   max-* is a safety rail against a mis-exported oversized file, not a layout value: at 38px it
   is exactly the largest glyph delivered and binds on nothing. */
.idsep-card__icon img {
	position: relative;
	display: block;
	width: auto;
	height: auto;
	max-width: 38px;
	max-height: 38px;
}

/* Icon ladder. Added 2026-09-10 after the real 33x33 glyphs landed and the assembly read
   oversized on a phone. TWO causes, both real: the glyph grew from the placeholder's 26x21,
   AND the 62px disc had never been stepped for width — it was 62px at 1920 and 62px at 320,
   the same unstepped-value pattern found four times in this file on 2026-09-08.
   Figma is a 1920-only frame, so there is no mobile size to read; these follow the type and
   spacing ladders already in this file. Disc and glyph step TOGETHER, holding the design's
   33/62 = 0.53 ratio, so the glyph never crowds or floats inside the ring:
     >=1024  62 / 33   (design)
     <=1023  52 / 28   (52 x 0.53 = 27.7)
     <=767   44 / 24   (44 x 0.53 = 23.4)
   Only width/height are set. The gradient disc, ring and glass are all `inset`-based on
   .idsep-card__icon, so they follow the box on their own and must NOT be resized here. */
@media (max-width: 1023px) {
	.idsep-card__icon {
		width: 52px;
		height: 52px;
	}

	/* Scaled, not capped. A cap is a box, so it shrinks a tall glyph and leaves a small one
	   untouched — the icons stop holding their relative sizes. transform keeps every glyph at
	   the same fraction of its design size, and the disc is a centred grid container so a
	   scale about the centre needs no layout compensation. 52/62 = 0.839. */
	.idsep-card__icon img {
		transform: scale(0.839);
	}
}

@media (max-width: 767px) {
	.idsep-card__icon {
		width: 44px;
		height: 44px;
	}

	/* 44/62 = 0.710. Same reasoning as the 1023 rung above. */
	.idsep-card__icon img {
		transform: scale(0.71);
	}
}

/* Category pill. Spec comes from the New Brand library (file 2HzE41Wkmmw6bx58qbAbCg, node
   59930-21762), not the Innovation Drop mockup — the mockup shows an older orange-bordered
   version and is out of date on this component.
   Blue at rest, orange on CARD hover. The pill is a non-interactive <span>, so it cannot be a
   hover target itself; it follows the card, like the icon and the heading. Only the border
   colour moves — hence a transition scoped to border-color, which is a plain colour and
   therefore genuinely interpolable, unlike the gradient rings elsewhere on this page. */
.idsep-card__pill {
	display: inline-flex;
	/* No align-self. It was flex-start while the pill was a direct child of the card's flex
	   COLUMN, where that stopped it stretching to the full width. Inside .idsep-card__icon-row
	   it is a row item instead, so it hugs horizontally on its own, and flex-start pinned it to
	   the top of the 62px icon rather than centring against it. The row's align-items: center
	   now governs, matching Figma node 80:119. */
	/* Figma nodes 80:127 / 80:151, style_a65e3c16 — composited padding 4px 6px 2px. */
	padding: 4px 6px 2px; /* was 4px 10px */
	border: 1px solid var(--idsep-blue-bright);
	border-radius: 5px;
	color: var(--idsep-white);
	font-size: 14px; /* was 11px */
	font-weight: 600; /* was 700 */
	letter-spacing: 0.05em; /* was 0.08em */
	line-height: 1.2;
	text-transform: uppercase;
	transition: border-color 0.25s ease;
}



/* "SPS H3" text style from Figma. Was 24px/700/1.2 — all three wrong. Colour is declared
   explicitly rather than left to inherit from body: it resolves to the same white either way,
   but Figma states it, and leaving it implicit is what let the earlier cyan heading rule go
   unnoticed until v22. Does not interfere with the gradient-on-card-hover rule, which overrides
   via background-clip and -webkit-text-fill-color rather than via color. */
.idsep-card__heading {
	margin: 0;
	color: var(--idsep-white);
	font-size: 32px;
	font-weight: 600;
	line-height: 125%;
}

/* Figma nodes 80:174 / 80:191 — secondary cards use "SPS H4" (25px), not primary's H3. */
.idsep-card--secondary .idsep-card__heading {
	font-size: 25px;
}

/* "SPS P" from Figma — the same text style as the CTA. Was 16px/1.6; both were wrong.
   Weight is declared explicitly rather than left to inherit: it resolves to 400 either way
   here, but the style is shared with .idsep-card__link, which sits inside a card that also
   carries bold headings, and an inherited weight is the kind of thing that silently changes
   when a parent is restyled. */
/* Manual line breaks in card copy, e.g. `<br class="idsep-br--wide">`.
   They are positioned by eye against the design width, where the wrapper is a full 1436 and a
   primary card's text column is 317px. Below that the wrapper shrinks - the gutter hits its
   60px floor once usable width drops under 1556 - and a hard break starts landing arbitrarily:
   an orphan word on its own line, or a break the natural wrap would have made anyway. So they
   only apply while the layout is still at design width, and the natural wrap takes over below.

   1570 rather than 1556 because media queries measure the viewport INCLUDING the scrollbar,
   while the wrapper maths works on the usable width inside it. 1556 + a typical 15px scrollbar
   = 1571, so hiding at 1570 and under is the first width where the wrapper is no longer 1436.
   On macOS with overlay scrollbars there is no scrollbar to allow for, so between 1556 and 1570
   those users lose the break slightly early - a better failure than keeping a break past the
   point where it stops making sense. */
@media (max-width: 1570px) {
	br.idsep-br--wide {
		display: none;
	}
}

.idsep-card__body {
	margin: 0;
	/* Full white, not the 88% it used to be. Every piece of card text is pure white at rest;
	   the heading is the only one that changes, and only on hover. */
	color: var(--idsep-white);
	font-size: 20px;
	font-weight: 400;
	line-height: 125%;
}

/* CTA carries the underline at rest and drops it when the pointer is on the link itself —
   the reverse of the usual convention, and deliberate. Note this is keyed on the LINK's own
   :hover, not the card's, so hovering anywhere else on the card leaves it underlined. */
/* The hit area is deliberately larger than the text, and deliberately NOT full width.
   As a block-level child of the flex column the link stretched to the full content column:
   measured at 365px wide against 84px of text, so 281px of it was dead space that still
   navigated when clicked. `align-self: flex-start` shrinks it to its text — note
   `display: inline-block` does NOT work here, because flex items are blockified and it would
   compute back to `block`.
   The padding then buys back a comfortable target (a 24px line becomes 34px tall), and the
   matching negative margin pulls the layout box back to the text's own size so nothing moves:
   the 20px column gap and the left alignment with the heading and body are unchanged. Padding
   and margin must stay equal and opposite — changing one without the other shifts the CTA. */
.idsep-card__link,
.idsep-link {
	align-self: flex-start;
	padding: 5px 10px;
	margin: -5px -10px;
	color: var(--idsep-white);
	/* "SPS P" text style from Figma. Was 16px/600 — both were wrong, this is the body-copy
	   weight at 20px, not a small bold link. */
	font-size: 20px;
	font-weight: 400;
	line-height: 125%;
	text-decoration-line: underline;
	/* Figma specifies both of these explicitly rather than leaving them at their defaults.
	   `skip-ink: none` keeps the underline unbroken through descenders (the g in "guide", the
	   y in "story") instead of the browser default of hopping over them; `from-font` takes the
	   underline's position from Source Sans 3's own metrics rather than the browser's guess.
	   Thickness and offset are left `auto`, which is what Figma reported. */
	text-decoration-skip-ink: none;
	text-underline-position: from-font;
}

.idsep-card__link:hover,
.idsep-card__link:focus-visible,
.idsep-link:hover,
.idsep-link:focus-visible {
	text-decoration: none;
}

/* Row 2. No Glass effect and no backdrop blur — those belong to the primary cards only. */
/* No background fill. Figma node 80:160 lists strokes only — unlike the primary card
   (node 80:111), which explicitly carries rgba(0, 0, 0, 0.2). The rgba(0, 0, 0, 0.12) here was
   invented, not measured, and is removed on Radmilo's call to see how it reads without.
   Restore by re-adding `background: rgba(0, 0, 0, 0.12)` if it looks too bare. */
/* Figma EL-e12d2462 (nodes 80:160 / 80:177) — padding 40px, border-radius 20px. */
.idsep-card--secondary {
	position: relative;
	padding: 40px; /* was 32px 28px */
	border-radius: 20px; /* was 16px */
}

.idsep-card--secondary::before {
	content: "";
	position: absolute;
	inset: 0;
	box-sizing: border-box;
	border: var(--idsep-ring-width) solid transparent;
	border-radius: inherit;
	background: var(--idsep-card-border) border-box;
	-webkit-mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	pointer-events: none;
}

/* Hover ring — solid deep blue, cross-faded in on hover (same technique as primary ::after). */
.idsep-card--secondary::after {
	content: "";
	position: absolute;
	inset: 0;
	box-sizing: border-box;
	border: var(--idsep-ring-width) solid transparent;
	border-radius: inherit;
	background: var(--idsep-blue) border-box;
	-webkit-mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	mask:
		linear-gradient(#000 0 0) padding-box,
		linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.25s ease;
}

.idsep-card--secondary > * {
	position: relative;
	z-index: 1;
}

/* Card hover decoration: icon, glass, pill and heading. */
@media (hover: hover) {
	/* Guarded on capability, not width - added 2026-09-08. Only the two ::after border
	   cross-fades were behind `hover: hover`; every other part of the card hover set was
	   unguarded, so a tap on a touch device could leave the icon ring, glass, pill colour
	   and heading gradient stuck on while the border - the one guarded piece - did nothing.
	   Capability is the right test: a 1024px tablet reports `hover: none` and correctly gets
	   none of this, while a 900px-wide desktop window keeps all of it. A width breakpoint
	   would get both of those backwards. */
	.idsep-card:hover .idsep-card__icon-glass {
		opacity: 1;
		/* Blur diffuses the gradient beneath; the tint supplies the darkening the blur cannot.
		   Both belong to this layer — see --idsep-icon-glass-tint. */
		background: var(--idsep-icon-glass-tint);
		backdrop-filter: blur(var(--idsep-icon-frost));
		-webkit-backdrop-filter: blur(var(--idsep-icon-frost));
	}

	.idsep-card:hover .idsep-card__pill {
		border-color: var(--idsep-orange);
	}

	.idsep-card:hover .idsep-card__icon {
		border-color: transparent;
	}

	.idsep-card:hover .idsep-card__icon::before {
		opacity: 1;
	}

	.idsep-card:hover .idsep-card__icon::after {
		opacity: 1;
	}

	.idsep-card:hover .idsep-card__heading {
		background: var(--idsep-heading-hover);
		-webkit-background-clip: text;
		background-clip: text;
		-webkit-text-fill-color: transparent;
	}
}

/* Card hover — primary cards only, pointer devices. Border cross-fades via ::after opacity;
   background and box-shadow do not change. */
@media (hover: hover) {
	.idsep-card--primary:hover::after {
		opacity: 1;
	}
}

@media (hover: hover) and (min-width: 1024px) {
	.idsep-card--secondary:hover::after {
		opacity: 1;
	}
}

/* Icon hover: disc and gradient ring fade in; white rest border fades to transparent so the
   ring replaces it rather than sitting inside it. The ring uses its own --idsep-icon-ring
   token, not the card border. */


/* Both the ring and the disc go fully opaque.
   The disc sat at 0.55 until 2026-09-07. That value was reverse-engineered by sampling the
   design render and finding it at ~55% of our fully-opaque values in every channel — a
   near-constant ratio across channels, which happens when a fill composites over a near-black
   backdrop. It was a stand-in for the dimming Figma's Glass does, derived at a time when
   nothing in this build sat above the disc to dim it.
   Radmilo has since supplied node 80-55's own CSS:
     background: linear-gradient(180deg, #FA6423 0%, #00EAD0 50%, #0099D5 100%);
   with NO opacity property, so the layer itself is fully opaque and the dimming belongs
   entirely to the glass above it. Our glass layer now exists, so the 0.55 was double-counting.
   Note the gradient stops themselves already matched Figma exactly — --idsep-orange-deep is
   #fa6423, --idsep-teal is #00ead0, --idsep-blue-bright is #0099d5. The stops were never wrong. */




/* Heading takes a gradient text fill on CARD hover (not on its own hover — the whole card is
   the target, same as the icon above).
   No transition: `background-clip: text` paints a gradient image, and CSS cannot interpolate
   between a gradient and a plain colour any more than it can between two gradients. The card
   border solves that by cross-fading two stacked layers, but doing the same for text would mean
   duplicating every heading in the DOM, so this one snaps. Same conclusion as v17 reached for
   the icon ring: an easing declaration that silently does nothing is worse than none. */


/* The video card is not a media thumbnail beside a text column — it has no text at all, so
   the preview fills the whole card. Its border is a plain white hairline, NOT the gradient
   ring the other cards use. Figma gives 0.993px / 19.866px; those are scale artefacts, so
   1px / 20px, which also avoids fractional widths snapping unevenly at 1x DPR. */
.idsep-card--video::before {
	background: var(--idsep-white) border-box;
}

/* The video card is media edge-to-edge — it inherits the primary card's 50px/40px padding,
   which is there to give TEXT room and just insets the video. Zero it and let the preview
   fill the card, clipped by the card's own radius. */
.idsep-card--video {
	padding: 0;
	overflow: hidden;
	min-height: 428px;
}

/* The 428px above is a fixed height at every width. That is close enough to 16:9 on desktop,
   where the card is 694 wide and object-fit: cover only crops ~9% of the frame. It stops being
   close as the card narrows: ~28% cropped at 1240, ~41% at 1024, ~56% at 375, where the card is
   335 x 428 and the frame is cut to a narrow vertical slice through the middle - straight
   through the centred text and the logo wall.
   From 1240 down the card takes the video's own proportion instead of matching the height of
   the cards beside it. Same 16/9 the overlay frame already uses. Desktop is left alone: it is
   signed off against Figma at 428. */
@media (max-width: 1240px) {
	.idsep-card--video {
		min-height: 0;
		aspect-ratio: 16 / 9;
	}
}

/* The media now fills the card, and as a child at z-index 1 it paints over the ring, which
   sits at 0. Lift the ring above it. Safe to do: the ring is a masked frame with a
   transparent centre and pointer-events: none, so it obscures nothing and blocks no clicks. */
.idsep-card--video::before {
	z-index: 2;
}

.idsep-card--video::after {
	z-index: 2;
}

.idsep-card--video .idsep-card__video-preview {
	position: absolute;
	inset: 0;
	width: auto;
	max-width: none;
	min-height: 0;
	border-radius: inherit;
	overflow: hidden;
}

.idsep-card__video-loop {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.idsep-card__video-preview img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Still covers the whole card - clicking anywhere on the video opens the popup (Radmilo,
   2026-09-12). What changed is what it SHOWS: a small cue in the bottom-right corner instead
   of a centred triangle, so the button pushes its content to that corner. */
.idsep-card__video-play {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: flex-end;
	justify-content: flex-end;
	width: 100%;
	height: 100%;
	/* 20px, Radmilo 2026-09-12 - 16 sat the cue slightly tight into the corner. This is the
	   icon's whole inset from the card edge, since the icon is the button's only child. */
	padding: 20px;
	border: 0;
	border-radius: inherit;
	background: transparent;
	color: var(--idsep-white);
	cursor: pointer;
}

/* 32px, Radmilo's call on 2026-09-12. The Figma node exports at 57.21 x 57.43, but that is the
   icon's own bounds on an export board, NOT a placement on a card: the glyph is not placed on
   any card anywhere in the file, and the design's own video card exports as an empty SVG, so
   the file cannot settle the size. At 57 it read as a control rather than a cue.
   The inset from the card edge comes from the button's padding (20px). The inline play/mute
   controls below 1240 sit at 16px, so the two overlays are deliberately no longer on the same
   margin - they never appear at the same width.
   `fill: currentColor` in the markup, so the hover colour is one declaration on the parent. */
.idsep-card__video-cue-icon {
	display: block;
	flex-shrink: 0;
	width: 32px;
	height: 32px;
	transition: color 0.25s ease, filter 0.25s ease;
}

/* Hover and keyboard focus share the treatment: the design's #80D4F2 (= --idsep-light-blue)
   plus a glow. The glow works here where the 2026-09-08 attempt failed: that icon was a ~1px
   hairline stroke with no fill, so a drop-shadow had almost no ink to catch and a radial pool
   behind it washed out the video. This glyph is solid, so the shadow lands on the shape
   itself. --idsep-pill-glow is the same rgba(128, 212, 242, 0.8) the hero pills use. */
.idsep-card__video-play:hover .idsep-card__video-cue-icon,
.idsep-card__video-play:focus-visible .idsep-card__video-cue-icon {
	color: var(--idsep-light-blue);
	filter: drop-shadow(0 0 12px var(--idsep-pill-glow));
}

/* Keyboard focus. The button covers the whole card, so the ring lands on the card edge;
   `border-radius: inherit` above keeps it following the card's corners rather than cutting
   square ones. Unlike the previous version this is no longer the control's only state - the
   cue above reacts to hover and focus alike. */
.idsep-card__video-play:focus-visible {
	outline: 2px solid var(--idsep-light-blue);
	outline-offset: -4px;
}

.idsep-card__video-play[hidden] {
	display: none;
}

.idsep-card__video-controls {
	position: absolute;
	bottom: 16px;
	/* Right, not left: the centre play button is gone in inline mode, so the controls are
	   the only overlay on the frame and sit clear of the video's own subject, which is
	   centred and lower-left weighted in this footage. */
	right: 16px;
	z-index: 3;
	display: flex;
	gap: 8px;
}

.idsep-card__video-controls[hidden] {
	display: none;
}

.idsep-card__video-control {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 1px solid rgba(255, 255, 255, 0.35);
	border-radius: 50%;
	background: rgba(31, 40, 44, 0.65);
	color: var(--idsep-white);
	cursor: pointer;
	transition: border-color 0.25s ease, background-color 0.25s ease;
}

.idsep-card__video-control:hover {
	border-color: var(--idsep-white);
	background: rgba(31, 40, 44, 0.85);
}

.idsep-card__video-control:focus-visible {
	border-color: var(--idsep-teal);
	outline: 2px solid var(--idsep-teal);
	outline-offset: 2px;
}

.idsep-card__video-control-icon {
	display: block;
	flex-shrink: 0;
}

.idsep-card__video-control-icon[hidden] {
	display: none;
}

.idsep-card__accordion-toggle {
	display: none;
	width: 100%;
	padding: 0;
	border: 0;
	background: transparent;
	color: inherit;
	font: inherit;
	text-align: left;
	cursor: pointer;
}

.idsep-card__accordion-toggle .idsep-card__heading {
	display: block;
}

.idsep-card__accordion-chevron {
	display: none;
}

.idsep-card__heading--desktop {
	display: block;
}

@media (min-width: 1024px) {
	.idsep-card--secondary .idsep-card__accordion-toggle {
		display: none;
	}

	/* Not qualified on [hidden], and no !important. The accordion JS removes `hidden` when a
	   panel is opened below 1024px, so a panel resized up to desktop arrives WITHOUT the
	   attribute; an [hidden]-qualified rule would miss it and the panel would fall back to the
	   div default of `display: block`, dropping the gap and putting the inline-level icon and
	   pill on one line. Author-origin `display` already beats the UA stylesheet's
	   `[hidden] { display: none }` on cascade origin, so both states resolve to flex here. */
	/* Figma EL-45c4c93b — column gap 15px. */
	.idsep-card--secondary .idsep-card__accordion-panel {
		display: flex;
		flex-direction: column;
		gap: 15px; /* was 20px */
	}
}

@media (max-width: 1023px) {
	.idsep-header__actions {
		display: none;
	}

	/* With the actions hidden the wordmark is the only in-flow item in the bar, leaving the
	   whole right side empty and everything crowded against the logo. Send it to the right
	   gutter instead. The auto margin resolves to 0 when there is no free space (320 and
	   below), where the --idsep-header-pad-min floor still holds it at the logo's edge. */
	.idsep-header__wordmark {
		margin-left: auto;
	}

	.idsep-card__heading--desktop {
		display: none;
	}
	.idsep-hero__title {
		font-size: 40px;
	}

	/* The section heading had NO step here - it held the desktop 55px right down to 768,
	   which made every section heading larger than the page's own H1 (40px above) and wrapped
	   a 30-character heading like "The Future of Revenue Recovery" onto two near-full-width
	   lines at a 720px wrapper. 40px restores the hierarchy and matches the H1.
	   The intro had no step at any width: 25px everywhere gave 86 characters a line at 1023
	   and 30 at 375, against a comfortable 45-75. 20px is the existing "SPS P" token. */
	.idsep-section__heading {
		font-size: 40px;
	}

	.idsep-section__intro {
		font-size: 20px;
	}

	.idsep-hero__row {
		grid-template-columns: 1fr;
		gap: 40px;
	}

	.idsep-section__head {
		flex-direction: column;
		gap: 24px;
	}

	/* The head steps its gap down here but the copy column never did - it held the desktop
	   50px at every width. On desktop that is fine: the head is a ROW, so its 50 is
	   horizontal and the copy's 50 is vertical, two different axes. The moment the head
	   becomes a column both gaps stack, and the sequence read badge -24- heading -50- intro:
	   the space inside the copy block twice the space separating it from the badge, which
	   groups the heading with the badge instead of with its own intro.
	   16 keeps the inner gap clearly tighter than the outer one at both remaining steps,
	   against a 40px heading over a 20px intro. */
	.idsep-section__copy {
		gap: 16px;
	}

	.idsep-card-grid {
		grid-template-columns: 1fr;
	}

	/* 48 -> 30 (2026-09-11 spacing pass). The grid is one column here, so this is the gap
	   BETWEEN stacked cards; 48 was the desktop COLUMN gap and had never been stepped for the
	   stacked layout. The secondary grid keeps its own `gap: 0` further down in this block,
	   where the cards become accordion rows with their own dividers. */
	.idsep-card-grid--primary {
		gap: 30px;
	}

	.idsep-card--primary {
		flex-direction: column;
	}

	/* Mobile keeps the image on top (column layout above). Portrait assets cannot scale into
	   a landscape slot without losing content, so each card carries a separately composed
	   landscape variant, selected by the <picture> source at this same breakpoint. Built and
	   in use since 2026-09-10 — this comment described it as pending until then. */
	.idsep-card--primary .idsep-card__media,
	.idsep-card--video .idsep-card__video-preview {
		max-width: none;
	}

	/* Percentage flex-basis resolves on the main axis; in column layout that is height, so
	   reset basis and width here — desktop row layout uses 43.4% on .idsep-card__media.
	   The slot also turns LANDSCAPE here. Above 1024 the card is a row and the slot is the
	   design's portrait 267 x 326; below it the card stacks and a full-width portrait box is
	   enormously tall. 16/9 matches the video card's own mobile ratio so the two card types
	   read as the same family. Kept in step with the <picture> source in the template, which
	   swaps to the landscape asset at this exact breakpoint - the box and the file must
	   change together or the image gets cropped to fit a box it was not shot for. */
	.idsep-card--primary .idsep-card__media {
		flex-basis: auto;
		width: 100%;
		aspect-ratio: 16 / 9;
	}

	/* No gap between accordion rows. The 60px from the two-column desktop grid is spacing
	   BETWEEN CARDS, and these are no longer cards - each row is `padding: 20px 0` with a 1px
	   bottom rule, so a gap on top of that puts ~100px between rows and makes every border
	   read as an underline with space after it rather than a divider between adjacent items.
	   At 0 the rows close up into a single list and the toggle padding supplies the rhythm. */
	.idsep-card-grid--secondary {
		gap: 0;
	}

	.idsep-card--secondary {
		padding: 0;
		border: 0;
		border-bottom: 1px solid rgba(177, 197, 207, 0.35);
		border-radius: 0;
		background: transparent;
		box-shadow: none;
	}

	/* The gradient ring has to go with the card, not just the border. `border: 0` above
	   removes the card's own border but leaves ::before painting - it is a masked 2px
	   gradient ring at inset 0, independent of `border`. Left on, it drew a rectangle around
	   each accordion row, and because the ring's own gradient ends on a transparent stop and
	   the radius is now 0, only parts of it rendered: no left edge, a stray vertical at the
	   right, a bottom rule not meeting the corners. ::after is the hover ring and goes for
	   the same reason. In accordion mode the only rule is the 1px bottom border above. */
	.idsep-card--secondary::before,
	.idsep-card--secondary::after {
		display: none;
	}

	.idsep-card--secondary .idsep-card__accordion-toggle {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 16px;
		padding: 20px 0;
	}

	.idsep-card--secondary .idsep-card__accordion-chevron {
		display: block;
		flex-shrink: 0;
		width: 12px;
		height: 12px;
		border-right: 2px solid var(--idsep-white);
		border-bottom: 2px solid var(--idsep-white);
		transform: rotate(45deg);
		transition: transform 0.2s ease;
	}

	.idsep-card--secondary.idsep-card--open .idsep-card__accordion-chevron {
		transform: rotate(-135deg);
	}

	/* The heading's gradient fill moves from :hover to the OPEN state here.
	   `.idsep-card:hover .idsep-card__heading` is unscoped - no `hover: hover` guard, no
	   breakpoint - so it was firing on these accordion rows too. Hover is not a state a
	   touch user can reach, and on an accordion it is not the state worth showing: open
	   versus closed is. So the hover fill is reset for secondaries here and the same
	   treatment is attached to `.idsep-card--open`, which is what the toggle actually
	   changes.
	   The reset needs BOTH declarations: clearing the background alone would leave
	   `-webkit-text-fill-color: transparent` in place and the heading would vanish. */
	.idsep-card--secondary:hover .idsep-card__heading {
		background: none;
		-webkit-text-fill-color: currentColor;
	}

	.idsep-card--secondary.idsep-card--open .idsep-card__heading {
		background: var(--idsep-heading-hover);
		-webkit-background-clip: text;
		background-clip: text;
		-webkit-text-fill-color: transparent;
	}

	.idsep-card--secondary .idsep-card__accordion-panel {
		padding-bottom: 24px;
	}

	.idsep-card--secondary .idsep-card__accordion-panel[hidden] {
		display: none;
	}

	.idsep-card--secondary.idsep-card--open .idsep-card__accordion-panel {
		display: flex;
		flex-direction: column;
		gap: 20px;
	}
}

/* NOTE: this block must stay BELOW the `max-width: 1023px` rule above, which sets
   `width: 100%` on the same selector. Identical specificity (0,2,0), so source order is
   the only thing deciding it, and at 375 both queries match. Placed higher in the file it
   silently loses and the image shifts sideways instead of widening. */
/* Full-bleed card image on phones. Radmilo, 2026-09-10: the icon and pill were outweighing
   the artwork. Two paddings stack against the image at this width — the section gutter (20px
   at 375) and the card's own 40px — leaving it 255 wide inside a 335 card while the icon and
   pill beside it are at full size. Cancelling only the card's padding takes the image to
   335 x 188, 31% wider, without touching the gutter that aligns the card with everything
   else on the page.
   Phones only. Between 768 and 1023 the card is wide enough that the image does not read as
   undersized, and bleeding there would fight the roomier layout.
   `width: auto` is required: the <=1023 rule sets `width: 100%`, which would resolve against
   the content box and simply shift the image sideways instead of widening it.
   Top corners take the card's own 20px so the bleed reads as intentional; the bottom two
   stay square where the image meets the copy. The card's ::before gradient ring is positioned
   with z-index 0 and so paints ABOVE this in-flow child, which is what keeps the border
   continuous across the image edge rather than the image covering it. */
@media (max-width: 767px) {
	.idsep-card--primary .idsep-card__media {
		width: auto;
		margin: calc(-1 * var(--idsep-card-pad-y)) calc(-1 * var(--idsep-card-pad-x)) 0;
		border-radius: 20px 20px 0 0;
	}
}

/* Card padding ladder. Radmilo, 2026-09-10: 50px 40px read as too much on a phone. It had
   never been stepped — the design's 1920 value held all the way down to 320, the same
   unstepped-value pattern found six times in this file.
   Ladder matches the shape of the section padding (100/80/70) and gutter ladders already
   here:
     >=1024  50 / 40   (design)
     <=1023  40 / 30
     <=767   30 / 20   — copy column goes 255 -> 295 at 375, a 16% wider measure
   Only the custom properties are set, never `padding` directly. Two reasons that matters:
   the media's full-bleed negative margin reads the same properties, so the bleed retracks
   itself instead of having to be restated per band; and `.idsep-card--video` sets
   `padding: 0` literally further down the file, so a var change cannot leak into the video
   card the way a `padding` declaration here would fight it. */
@media (max-width: 1023px) {
	.idsep-card--primary {
		--idsep-card-pad-y: 40px;
		--idsep-card-pad-x: 30px;
	}
}

@media (max-width: 767px) {
	.idsep-card--primary {
		--idsep-card-pad-y: 30px;
		--idsep-card-pad-x: 20px;
	}
}

/* ---------------------------------------------------------------------------
   Hero, 1024-1240: stacked and centred
   Two columns stop working before the row runs out of room. The CTAs need ~290px
   a piece and the badges will not go below a legible size, so the side-by-side
   arrangement squeezes the copy long before the viewport is actually narrow.
   Instead of shrinking everything, the row unstacks: intro, then badges, then
   CTAs, all centred, using the full width for each in turn.
   `display: contents` on the text column is what makes the order possible - intro
   and pills are its children, not the row's, so without it the badges could only
   sit before or after the pair, never between them. It drops the column from the
   box tree and promotes both to grid items, so all three can be ordered directly
   and no markup changes.
   Upper bound is 1240. It was tried at 1440 and rejected on the render - the
   stacked layout reads as too loose on a laptop, where two columns still have the
   room to work. The trade-off, accepted deliberately: 1241-1440 stays two-column
   and is at its tightest just above the switch, a 591 text column and 180 badges
   at 1241 against 698 and 218 at 1441. That band is narrow and degrades smoothly;
   the stacked layout takes over before it gets worse.
   Scoped with min-width because below 1024 the row already has its own
   single-column rule, which is left exactly as it was.
   --------------------------------------------------------------------------- */
@media (min-width: 1024px) and (max-width: 1240px) {
	.idsep-hero__col--text {
		display: contents;
	}

	.idsep-hero__row {
		grid-template-columns: minmax(0, 1fr);
		justify-items: center;
		gap: 50px;
	}

	/* The 40px was spacing the pills directly below it; the row gap does that now.
	   Up from the base 16px to the "SPS P" token already used for card body and CTAs,
	   rather than a new value - at 16px in a 688 box the copy read as small against the
	   full-width badge row and the CTAs below it. max-width scales by the same 1.25 so
	   the line count holds instead of the block growing two lines taller. */
	.idsep-hero__intro {
		order: 1;
		margin-bottom: 0;
		text-align: center;
		font-size: 20px;
		max-width: 860px;
	}

	.idsep-hero__col--badges {
		order: 2;
	}

	.idsep-hero__pills {
		order: 3;
		/* Full width available now, so six pills read better as 3 x 2 than 2 x 3.
		   minmax(0, 290px) rather than a flat 290 so the tracks shrink instead of
		   overflowing at the narrow end: 3 x 290 + 2 x 29 = 928 against a 930 wrapper
		   at 1025, which fits but with nothing to spare. */
		grid-template-columns: repeat(3, minmax(0, 290px));
		justify-content: center;
	}

	/* Since 2026-09-11: all six, as the same 3 x 2 group the design draws beside the copy,
	   centred on the full width. Fixed 180 tracks rather than the base rule's 1fr,
	   which would size them off the full wrapper here and blow each badge up to ~300.
	   3 x 180 + 2 x 12 = 564, well inside the 930 wrapper at the narrow end of the band.
	   (Before: one row of three, 3 x 180 + 2 x 55 = 650.) */
	.idsep-hero__badges {
		max-width: none;
		grid-template-columns: repeat(3, 180px);
		justify-content: center;
	}

	/* 180 kept from the three-badge layout, where 242 across the full width read as the
	   loudest thing in the hero and pushed the CTAs down. Cost of six: the group is now two
	   rows, 370 tall instead of 180, so the CTAs sit ~190px lower in this band. */
	.idsep-hero__badge {
		width: 180px;
	}

	/* `margin-inline` does the work, not `text-align`: the H1 is capped at max-width 1127
	   and is a flex item in the wrapper's column, so centring its *text* only recentres
	   inside a 1127-wide box that is itself pinned left - at a 1305 wrapper the heading
	   stayed hard left while everything below it was centred. `text-align` is kept for the
	   narrower part of the band, where the box is the full wrapper and the line is shorter
	   than it after the fluid size kicks in. */
	.idsep-hero__title {
		margin-inline: auto;
		text-align: center;
	}
}

/* ---------------------------------------------------------------------------
   Primary cards, 1024-1240: one per row, centred at 80%
   Two columns do not fail here by overflowing - nothing spills, which is why an
   earlier pass recorded 1240 as closed - they fail by reading badly. Measured at
   1240: the card body column is 235px at 20px type, a capacity of 26 characters
   a line against the 45-75 that reads comfortably. That is two or three words a
   line for nine lines.
   One card per row at 80% of the wrapper gives a 539px column, 60 characters -
   the middle of the range. 90% and 100% were measured too and give 72 and 85;
   100% overshoots the upper bound, so the cap is deliberate rather than a
   fallback from full width.
   Secondaries deliberately stay two-up: they carry no image, so the same 542px
   card yields a 462px column at 51 characters, already inside the range. The
   297px an image plus its gap take out of a primary card is the whole reason the
   two tiers behave differently.
   Cost, accepted: the tallest section goes 1359 to 1886 and the page 9159 to
   11193. The video card is in a primary grid, so it widens to 916 and, with the
   16/9 rule already in force below 1240, renders 515 tall instead of a cropped
   428.
   --------------------------------------------------------------------------- */
@media (min-width: 1024px) and (max-width: 1240px) {
	.idsep-card-grid--primary {
		grid-template-columns: minmax(0, 1fr);
		justify-items: center;
	}

	.idsep-card-grid--primary > .idsep-card {
		width: 80%;
	}

	/* A lone secondary card (Analytics) sat in the first of two tracks with an empty half
	   beside it, which reads badly once the primaries above it are single and centred. Span
	   both tracks so the grid area is the full width, take exactly one track's width back and
	   centre it - `(100% - 60px) / 2` is the width it would have had as one of a pair, so it
	   stays the same size as every other secondary card, just centred.
	   BAND-SCOPED ON PURPOSE. Above 1240 the primaries are two-up again and a centred lone
	   card looks out of place against them, so it stays in the first track there. Below 1024
	   the grid is a single `1fr` column and this `calc` would halve the card rather than
	   centre it. Both edges matter; do not widen this rule to `min-width: 1024px` alone. */
	.idsep-card-grid--secondary > .idsep-card:only-child {
		grid-column: 1 / -1;
		justify-self: center;
		width: calc((100% - 60px) / 2);
	}
}

/* ---------------------------------------------------------------------------
   Below 1024: continue the centred orientation from the 1024-1240 band
   Below 1024 the layout used to snap back to left alignment - badges hard left,
   the intro pinned left at 688, the CTAs packed left with dead space beside
   them, and section heads half-centred with a centred badge above a
   left-aligned heading. Coming straight after the centred band above, that read
   as a different page rather than a narrower one.
   This repeats the band's arrangement - intro, badges, CTAs, stacked and
   centred - all the way down. Card interiors are deliberately NOT centred, at
   Radmilo's call: body copy and CTA links keep a straight left edge to read
   down.
   Two values here are phone-hostile and are overridden in the max-width: 767px
   block below: the 3-column CTA grid (~92px columns at 375) and the badge
   shrink formula (~75px badges at 375). Everything else carries down.
   --------------------------------------------------------------------------- */
@media (max-width: 1023px) {
	/* Same reason as the 1024-1240 block: intro and pills are children of the text
	   column, so without this the badges can only sit before or after the pair. */
	.idsep-hero__col--text {
		display: contents;
	}

	/* One 30px step between every item in the stack: copy, badges, CTAs. Radmilo's call on
	   2026-09-11, tightening the hero below 1024 to the 30px rhythm set by the badge gap.
	   (Earlier the same day this was gap 0 with per-item margins, 50 above the badges and 30
	   below, which one gap could not express; with both at 30 it can again.) Below 600 the
	   badge column is hidden and the gap closes up with it. */
	.idsep-hero__row {
		grid-template-columns: minmax(0, 1fr);
		justify-items: center;
		gap: 30px;
	}

	/* The H1-to-copy gap, and the one that was actually too big. The wrapper held 60px at
	   every width below 1024 - a lot of air above a centred paragraph on a narrow screen.
	   The `max-width: 767px` block set `gap: 40px` on `.idsep-hero`, which LOOKS like this
	   rule but is inert: the hero has a single in-flow child (this wrapper - the canvas is
	   absolutely positioned), so there is no gap for it to create. Same shape of dead rule as
	   `.idsep-section { gap: 40px }` in that block. */
	/* 48 -> 30 on 2026-09-11: the same 30px rhythm as the stack below it, held down through
	   phone widths (the <=767 block no longer steps it). */
	.idsep-hero > .idsep-wrapper {
		gap: 30px;
	}

	.idsep-hero__title {
		margin-inline: auto;
		text-align: center;
	}

	.idsep-hero__intro {
		order: 1;
		margin-bottom: 0;
		text-align: center;
	}

	.idsep-hero__col--badges {
		order: 2;
	}

	/* Rows 29 -> 20 (2026-09-11, 30px rhythm pass). Row gap only: the 29 between columns is
	   untouched. The <=767 block changes the column count, not the gap, so this holds there. */
	.idsep-hero__pills {
		order: 3;
		grid-template-columns: repeat(3, minmax(0, 290px));
		row-gap: 20px;
		justify-content: center;
	}

	/* All six, compact, for tablet. The 2026-09-11 review call agreed ~100px badges with a 15px
	   gap; Radmilo settled it at 120px and 30px the same day after seeing that built. The 30px
	   stack rhythm around the group (see .idsep-hero__row) keeps the badges and CTAs within the
	   first screen on a tablet. Same 3 x 2 grouping as desktop. 3 x 120 + 2 x 30 = 420, inside the
	   narrowest wrapper this shows at (544 at 600; below that the column is hidden).
	   Replaces three badges at up to 242px and an interim rule that hid badges 4-6. */
	.idsep-hero__badges {
		max-width: none;
		grid-template-columns: repeat(3, 120px);
		gap: 30px;
		justify-content: center;
	}

	.idsep-hero__badge {
		width: 120px;
	}

	/* The head is already a centred column at this width (see the 1023 block); only
	   the text inside it was still left-aligned, which is what made it read as
	   half-centred.
	   BOTH declarations are needed. `.idsep-section__copy` is a flex column with
	   `align-items: flex-start`, so its children shrink to their content width and pin
	   left - `text-align` then centres the text inside a narrow box that is itself off to
	   the left, which changes nothing visible. Measured at an 885 viewport: the heading box
	   was 443 wide sitting 394px left of centre. The intro looked correct only by accident,
	   because its copy is long enough to fill the full 837 and there was no slack to reveal
	   the problem. `align-items: center` moves the boxes; `text-align` then centres the last
	   line within them. */
	.idsep-section__copy {
		align-items: center;
	}

	.idsep-section__heading,
	.idsep-section__intro {
		text-align: center;
	}

	/* Section padding ladder 100 / 50 / 40 (>=1024 / 768-1023 / <=767). It was 100 / 80 / 70
	   until 2026-09-11, when Radmilo tightened the page below 1024 and chose to keep the
	   sections on the same rhythm as the hero rather than a step above it. Two sections meet
	   at their paddings, so the space between them goes 160 -> 100 here and 140 -> 80 on
	   phones. Desktop is untouched at 100. */
	.idsep-section {
		padding-top: 50px;
		padding-bottom: 50px;
	}

	/* 60 -> 30. This one gap sets both the space under the section head and the space above
	   the secondary row, and like the hero's it was a desktop value that had never been
	   stepped: 60 held from 1920 down to 320. The head's own gaps (badge 24, heading 16) were
	   stepped on 2026-09-08 and stay as they are, so the block still reads as a group. */
	.idsep-section > .idsep-wrapper {
		gap: 30px;
	}

	/* Hero padding ladder 80 / 50 / 40 (>=1024 / 768-1023 / <=767). It was 80 / 70 / 60 until
	   2026-09-11, when Radmilo tightened the hero below 1024 to a 30px rhythm; 70 above a 30px
	   stack read as padding out of proportion to what it holds. This drops the earlier
	   "20px under the section's 100 / 80 / 70" relationship on purpose - the sections keep
	   their own padding. */
	.idsep-hero {
		padding-top: 50px;
		padding-bottom: 50px;
	}
}

@media (max-width: 767px) {
	/* 60 -> 40 on 2026-09-11 with the 30px rhythm pass - see the hero padding note in the
	   1023 block. The wrapper gap (title to copy) is no longer stepped here: it was 60 / 48 /
	   40 and is now 60 / 30, set once in the 1023 block and held down to phone widths. */
	.idsep-hero {
		padding-top: 40px;
		padding-bottom: 40px;
	}

	/* 70 -> 40 on 2026-09-11, matching the hero's phone rung in the same spacing pass.
	   The `gap: 40px` that used to sit here went with it: the section's only in-flow child is
	   its wrapper, so there was never a second item for a gap to separate - the same dead rule
	   the 1023 block's hero note describes. The wrapper's own gap does that work. */
	.idsep-section {
		padding-top: 40px;
		padding-bottom: 40px;
	}

	/* Back to two columns. The band above uses three, which is right from 768 up but
	   resolves to ~92px per column at 375 - narrower than the word "Manufacturing".
	   `justify-content: center` from that block still applies. */
	.idsep-hero__pills {
		grid-template-columns: repeat(2, minmax(0, 290px));
	}


	.idsep-hero__title {
		font-size: 32px;
	}

	.idsep-section__heading {
		font-size: 32px;
	}

	/* Matches the hero intro at this width, which measures 46 characters a line at 375 -
	   inside the comfortable range. At 20px the same column gives 37. */
	.idsep-section__intro {
		font-size: 16px;
	}
}

/* Hero badges are hidden once they can no longer sit in a single row.
   The band above sizes them `min(242px, calc((100% - 110px) / 3))`, which guarantees three
   fit: the two 55px gaps are subtracted before the division, so each badge is at most a
   third of what remains. They shrink with the wrapper - 203px at 768, 200 at 767, 150 at
   600 - and stay one row the whole way. Below 600 three would drop under 150px and stop
   reading as embroidered patches, so the only alternatives were two across (2 + 1, a
   lopsided orphan row) or none. Radmilo's call: none.
   Safe to hide outright. These three are decorative previews of emblems that appear again
   beside their own section headings further down, and they already carry `alt=""` for that
   reason - so nothing is lost to a screen reader, and the sections still show every badge.
   Hiding the COLUMN rather than the flex container also removes its row-gap contribution,
   so the hero closes up cleanly instead of leaving a 40px hole. */
@media (max-width: 599px) {
	.idsep-hero__col--badges {
		display: none;
	}
}

/* ---------------------------------------------------------------------------
   Ported from the child theme's style.css (scss/), which this template dequeues.

   style.css compiles bare tag selectors with !important (h1-h6, p, a, ul, li) that
   override this page's type scale and cannot be beaten without spreading !important
   through a new stylesheet — so the whole sheet is dropped for this template in
   dequeue_divi_assets_on_idsep(). Everything below is the part this page still needs,
   reproduced without !important.

   Only the floating sales tab was affected: its classes were the sole ones this template
   uses that live in style.css rather than css/custom/global/main.css. Rendered by
   footer.php and toggled per page by the ACF `display-sales-tab` field.
   --------------------------------------------------------------------------- */

#sps-sales-tab-float {
	display: none;
	position: fixed;
	top: 300px;
	right: -1px;
	z-index: 100;
	margin: 0;
	overflow: hidden;
	border-radius: 10px 10px 0 0;
	background: var(--idsep-blue);
	box-shadow: 0 0 2px rgba(0, 0, 0, 0.25);
	transform: rotate(-90deg);
	transform-origin: 100% 100%;
}

#sps-sales-tab-float.visible {
	display: block;
}

#sps-sales-tab-float a {
	display: block;
	padding: 7px 14px;
	color: var(--idsep-white);
	font-size: 15px;
	font-weight: 700;
	text-transform: uppercase;
	text-decoration: none;
}

#sps-sales-tab-float a:hover {
	background: var(--idsep-brand-blue);
}

@media (max-width: 766px) {
	#sps-sales-tab-float,
	#sps-sales-tab-float.visible {
		display: none;
	}
}

/* The wordmark is nowrap, and its width is linear in its font size:
   width = 13.53 * font-size + 12, the 12 being the two 6px flex gaps between its three
   spans. Against a 77px logo square and a 20px right gutter, 19.5px stops holding a 24px
   clearance below a 397px viewport, which is where this rung sits. 16px measures 228.46px
   and clears the square by 49.5px at 375 and 14.5px at 340. At 320 it goes flush but still
   fits inside the viewport, which also resolves the sideways scroll that width had at
   19.5px. Re-derive this if the edition string changes length - "Summer '26" is not
   permanent. */
@media (max-width: 400px) {
	:root {
		/* Bar and square step down together - the square is drawn to the bar's full height,
		   so shrinking one without the other would leave it floating in a dark strip. Also
		   lifts the clearance at 320 from flush to 11.5px, since the wordmark is pushed right
		   by an auto margin and the square it has to clear is now 17px narrower. */
		--idsep-header-h: 60px;
	}

	/* Solved, not tuned. Below 768 the wordmark sits between a --idsep-header-h square on
	   the left and a 20px gutter on the right, and its width is 13.526 * font-size + 12, so
	   holding a 24px clearance means
	     font-size = (viewport - 60 - 20 - 24 - 12) / 13.526 = 7.393vw - 8.576px.
	   16px satisfies that down to a 332px viewport, so the cap holds the approved size across
	   every width that can carry it and the expression only takes over below 332 - where a
	   fixed size would start eating into the square instead. vw is safe here: no scrollbar at
	   these widths, so 1vw is a true hundredth of the layout width.
	   The 13px floor is a legibility stop, not a fitting one; it binds below ~265, narrower
	   than any real device. Re-derive both constants if the edition string changes length. */
	.idsep-header__wordmark {
		font-size: clamp(13px, calc(7.393vw - 8.576px), 16px);
	}

	/* Held at the mark's share of the square, 46/77 = 0.597, so the blue border around it
	   keeps the same proportion as at full size. */
	.idsep-header__logo svg {
		width: 36px;
	}
}

/* ---------------------------------------------------------------------------
   Video overlay
   Fixed and layered above the page — it must not push content, so the page never
   reflows when it opens. Width follows the page wrapper but is capped to the viewport
   minus the current gutter, so on smaller screens it stays at the widest that screen
   allows rather than switching to inline playback.
   --------------------------------------------------------------------------- */

.idsep-video-overlay {
	position: fixed;
	inset: 0;
	z-index: 10000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--idsep-gutter);
}

.idsep-video-overlay[hidden] {
	display: none;
}

.idsep-video-overlay__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, 0.8);
}

.idsep-video-overlay__inner {
	position: relative;
	width: 100%;
	max-width: var(--idsep-wrapper);
}

.idsep-video-overlay__close {
	position: absolute;
	right: 0;
	bottom: calc(100% + 12px);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: var(--idsep-white);
	cursor: pointer;
}

.idsep-video-overlay__close:hover,
.idsep-video-overlay__close:focus-visible {
	background: rgba(255, 255, 255, 0.12);
	outline: none;
}

.idsep-video-overlay__frame {
	position: relative;
	aspect-ratio: 16 / 9;
	width: 100%;
	overflow: hidden;
	border-radius: 20px;
	background: #000;
}

.idsep-video-overlay__frame video {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
	object-fit: contain;
	background: #000;
}

/* Unmute control for the video overlay. Revealed by JS ONLY when the browser refused audible
   playback and we fell back to muted — see the open() handler in the page script. It is not a
   permanent control, so it deliberately does not sit alongside the close button: it appears
   over the video, disappears on click, and never returns for that session's playback.
   Positioned against .idsep-video-overlay__inner, which is the positioned ancestor the close
   button already uses. */
.idsep-video-overlay__unmute {
	position: absolute;
	z-index: 2;
	right: 16px;
	bottom: 76px;
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 10px 16px;
	color: var(--idsep-dark);
	background: var(--idsep-white);
	border: 0;
	border-radius: 999px;
	box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
	font-family: var(--idsep-font);
	font-size: 16px;
	font-weight: 600;
	line-height: 1;
	cursor: pointer;
}

/* Required, not optional. `hidden` is only a UA `display: none` at the lowest priority, so the
   `display: inline-flex` above beats it and the button would show permanently — which it did.
   Same pattern as .idsep-card__video-play[hidden] and .idsep-card__video-controls[hidden]. */
.idsep-video-overlay__unmute[hidden] {
	display: none;
}

.idsep-video-overlay__unmute:hover,
.idsep-video-overlay__unmute:focus-visible {
	background: var(--idsep-teal);
}

/* Sits clear of the native controls, which are ~40px tall at the foot of the video. On a phone
   the video is shorter and the controls proportionally larger, so lift it further. */
@media (max-width: 767px) {
	.idsep-video-overlay__unmute {
		right: 12px;
		bottom: 64px;
		padding: 8px 14px;
		font-size: 14px;
	}
}

/* WHOLE CARD CLICKABLE — desktop only. Feedback 2026-09-11: reviewers got a text cursor over
   the card and had to hunt for the link.
   Implemented as `.idsep-card__clickarea`, an empty <a> that is a DIRECT CHILD of the card and
   is stretched over it. It has to be a direct child: `.idsep-card--primary > *` sets
   position:relative on every child to lift them above the ::before/::after gradient rings,
   which makes .idsep-card__content a positioned ancestor. A stretched link on the CTA's own
   ::after therefore anchors to the TEXT COLUMN and never covers the image — that was the first
   attempt, and hovering the image gave no link.
   z-index 2 puts it above the card's children (z-index 1 from that same `> *` rule) and above
   the rings (z-index 0).
   The layer is aria-hidden and tabindex="-1", so the accessibility tree and tab order are
   untouched: the visible CTA remains the only real link. It carries the same target/rel logic,
   so a '#' placeholder does not open an empty tab here either.

   THREE deliberate limits:
   1. `pointer: fine` — a touch device never gets it. Dragging to scroll would otherwise risk
      being read as a tap on the card, which is the scrolling problem raised in review.
   2. `min-width: 1024px` — below this, secondary cards are ACCORDIONS whose toggle owns the
      click. The layer would swallow the toggle and the card could never open. Capability alone
      is not enough: a narrow desktop window still reports `pointer: fine`.
   3. The video card renders no CTA, so no layer is emitted there — and it needs none, since its
      play button is already `position: absolute; inset: 0` across the whole card. */
.idsep-card__clickarea {
	display: none;
}

@media (hover: hover) and (pointer: fine) and (min-width: 1024px) {
	.idsep-card__clickarea {
		position: absolute;
		z-index: 2;
		display: block;
		inset: 0;
		border-radius: inherit;
		cursor: pointer;
	}

	/* The CTA loses its underline on hover. That is driven by `.idsep-card__link:hover`, which
	   STOPS FIRING once the click layer exists — the layer sits above the link, so the pointer
	   never enters the <a> itself. Re-drive it from the card's hover instead, which does still
	   fire because the layer is a descendant of the card.
	   Scoped to this block deliberately: below 1024, and on touch, there is no layer and
	   `.idsep-card__link:hover` works unaided. `:focus-visible` is untouched either way, since
	   the layer is `tabindex="-1"` and keyboard focus still lands on the real link. */
	.idsep-card:hover .idsep-card__link {
		text-decoration: none;
	}
}
