/* ====================================================
   DIVERGENCE CHART — charts.css
   Colours/fonts reference variables from style.css only.
   ==================================================== */

/* --- Header --- */
.lab-frozen-article .chart-header {
	margin-bottom: 10px;
}
.lab-frozen-article .chart-title {
	margin-top: 5px;
	margin-bottom: 0;
}

/* --- Legend (placed below title, above chart) --- */
.lab-frozen-article .chart-legend-wrapper {
	display: flex;
	gap: 24px;
	margin: 10px 0 16px;
	flex-wrap: wrap;
	align-items: center;
}
.lab-frozen-article .chart-legend-item {
	display: flex;
	align-items: center;
	gap: 8px;
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 500;
	color: var(--white);
}
.lab-frozen-article .chart-legend-line {
	width: 28px;
	height: 2.5px;
	background: var(--white);
	flex-shrink: 0;
	border-radius: 2px;
}
.lab-frozen-article .chart-legend-line.sat {
	background: repeating-linear-gradient(
		90deg,
		var(--grey-25) 0,
		var(--grey-25) 6px,
		transparent 6px,
		transparent 10px
	);
}

/* --- SVG wrapper — enables floating overlays, full width --- */
.lab-frozen-article .chart-svg-wrapper {
	position: relative;
	width: 100%;
}

/* --- Base SVG --- */
.lab-frozen-article .divergence-chart {
	width: 100%;
	display: block;
}

/* --- Grid & axes --- */
.lab-frozen-article .chart-gridline {
	stroke: var(--grey-75);
	stroke-width: 1;
	fill: none;
}
.lab-frozen-article .chart-axis {
	stroke: var(--grey-50);
	stroke-width: 1.5;
	fill: none;
}

/* --- SVG text labels (all white) --- */
.lab-frozen-article .chart-label {
	fill: var(--white);
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 15px;
	font-weight: 500;
}
.lab-frozen-article .chart-label-right  { text-anchor: end; }
.lab-frozen-article .chart-label-center { text-anchor: middle; }
.lab-frozen-article .chart-label-left   { text-anchor: start; }

/* --- Gap fill --- */
.lab-frozen-article .chart-gap-fill {
	fill: rgba(255, 255, 255, 0.07);
	stroke: none;
	animation: chart-fade-in 1.5s ease-out 1.5s both;
}

/* --- Attacker line: draws in --- */
.lab-frozen-article .chart-line-attacker {
	stroke: var(--white);
	stroke-width: 2.5;
	fill: none;
	stroke-linecap: round;
	stroke-linejoin: round;
	stroke-dasharray: 1;
	stroke-dashoffset: 1;
	animation: chart-draw 2s ease-out 0.3s forwards;
}

/* --- SAT line: fades in after attacker finishes --- */
.lab-frozen-article .chart-line-sat {
	stroke: var(--grey-25);
	stroke-width: 2;
	fill: none;
	stroke-dasharray: 6 4;
	stroke-linecap: round;
	opacity: 0;
	animation: chart-fade-in 0.8s ease-out 2.2s forwards;
}

/* --- Dots --- */
.lab-frozen-article .chart-dot,
.lab-frozen-article .chart-dot-sat {
	transform-box: fill-box;
	transform-origin: center;
}
.lab-frozen-article .chart-dot     { fill: var(--white); }
.lab-frozen-article .chart-dot-sat { fill: var(--grey-25); }

/* staggered appearance matching line draw timing */
.lab-frozen-article .chart-dot-d1     { animation: chart-dot-pulse 0.45s ease-out 1.1s both; }
.lab-frozen-article .chart-dot-d2     { animation: chart-dot-pulse 0.45s ease-out 1.55s both; }
.lab-frozen-article .chart-dot-d3     { animation: chart-dot-pulse 0.45s ease-out 2.0s both; }
.lab-frozen-article .chart-dot-sat-d1 { animation: chart-dot-pulse 0.45s ease-out 2.35s both; }

/* --- ChatGPT annotation --- */
.lab-frozen-article .chart-annotation-line {
	stroke: var(--grey-50);
	stroke-width: 1;
	stroke-dasharray: 4 3;
	opacity: 0;
	animation: chart-fade-in 0.5s ease-out 1.1s forwards;
}
.lab-frozen-article .chart-annotation-text {
	fill: var(--white);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 15px;
	font-weight: 700;
	text-anchor: start;
	opacity: 0;
	animation: chart-fade-in 0.5s ease-out 1.1s forwards;
}

/* --- 2023 inline annotation (connector + text in gap area) --- */
.lab-frozen-article .chart-callout-line {
	stroke: var(--grey-50);
	stroke-width: 1;
	fill: none;
	opacity: 0;
	animation: chart-fade-in 0.5s ease-out 1.65s forwards;
}
.lab-frozen-article .chart-inline-annotation {
	fill: var(--white);
	font-family: 'Inter', 'Arial', sans-serif;
	/* Was 10px -- unreadable sitting inline against the chart's own
	   gridlines/gap-fill mesh (Finn, 14 Sep 2026). Bumped toward the chart's
	   other label sizes (11-14px) and to 600 weight for contrast. */
	font-size: 15px;
	font-weight: 600;
	text-anchor: middle;
	opacity: 0;
	animation: chart-fade-in 0.5s ease-out 1.65s forwards;
}

/* --- Floating HTML callout labels (overlaid on SVG) --- */
.lab-frozen-article .chart-float {
	position: absolute;
	pointer-events: none;
	opacity: 0;
	animation: chart-fade-in 0.6s ease-out 2.3s forwards;
	text-align: right;
}
.lab-frozen-article .chart-float-attacker {
	top: 2%;
	right: 2%;
	max-width: 390px;
}
.lab-frozen-article .chart-float-sat {
	top: 70%;
	right: 2%;
	max-width: 390px;
}
.lab-frozen-article .chart-float-title {
	margin: 0 0 4px;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 17px;
	font-weight: 700;
	color: var(--white);
	line-height: 1.2em;
}
/* Body copy was 11px/grey-25 -- too faint sitting over the chart's own
   converging lines on the right-hand side (Finn, 14 Sep 2026). Bumped
   size for legibility; kept grey-25 (rgb 126,126,126) rather than grey-50
   (rgb 78,78,78, noticeably dimmer) -- grey-50 reads fine on light panels
   but is close to invisible against this section's black background, per
   the same calibration already used elsewhere in Threat Context. */
/* Raised again to 15px at 75% white (Frank, 1 Oct 2026): no tiny grey
   text on any chart. */
.lab-frozen-article .chart-float-body {
	margin: 0;
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 15px;
	font-weight: 500;
	color: rgba(255, 255, 255, 0.75);
	line-height: 1.5em;
}

/* --- Mobile: bottom annotation text (in SVG) --- */
.lab-frozen-article .chart-bottom-label {
	fill: var(--white);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 15px;
	font-weight: 700;
	text-anchor: start;
}
.lab-frozen-article .chart-bottom-label-sat {
	fill: rgba(255, 255, 255, 0.75);
}
.lab-frozen-article .chart-bottom-text {
	fill: rgba(255, 255, 255, 0.75);
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 400;
	text-anchor: start;
}

/* --- Source note ---
   14px at 70% white, up from 12px grey-50: at the old size and contrast
   the note was close to unreadable on the black Threat Context panels,
   the only place it's used (Finn, 30 Sep 2026; same fix as VM's
   .vm-footnote). */
/* Ruled footnote, as on the VM charts (Finn, 2 Oct 2026). */
.lab-frozen-article .chart-source-note {
	max-width: 74ch;
	margin-top: 30px;
	padding-top: 20px;
	border-top: 1px solid rgba(255, 255, 255, 0.2);
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 14px;
	line-height: 1.6em;
	color: rgba(255, 255, 255, 0.7);
}

/* Ranked rows: label, a to-scale bar on a 0 to 100% track, and the value.
   The lead row is white and largest; the rest sit back at 75% white
   (Finn, 2 Oct 2026, after the VM coverage chart). Each row sets --v. */
.lab-frozen-article .chart-rows {
	margin: 0;
	padding: 0;
	list-style: none;
}
.lab-frozen-article .chart-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr) 110px;
	align-items: center;
	gap: 12px 40px;
	padding: 28px 0;
	border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.lab-frozen-article .chart-row:first-child {
	padding-top: 0;
	border-top: 0;
}
.lab-frozen-article .chart-row-label h4 {
	margin: 0 0 6px;
	font-size: 1.1em;
	line-height: 1.25;
	color: rgba(255, 255, 255, 0.85);
}
.lab-frozen-article .chart-row-label p {
	margin: 0;
	font-size: 0.8em;
	line-height: 1.55;
	color: rgba(255, 255, 255, 0.75);
}
.lab-frozen-article .chart-row-track {
	height: 14px;
	border-radius: 7px;
	background: rgba(255, 255, 255, 0.08);
	overflow: hidden;
}
.lab-frozen-article .chart-row-fill {
	display: block;
	width: calc(var(--v) * 1%);
	height: 100%;
	border-radius: 7px;
	background: rgba(255, 255, 255, 0.3);
}
.lab-frozen-article .chart-row-val {
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 1.5em;
	font-weight: 800;
	line-height: 1;
	text-align: right;
	color: rgba(255, 255, 255, 0.75);
}
.lab-frozen-article .chart-row.is-hero h4 {
	color: var(--white);
}
.lab-frozen-article .chart-row.is-hero .chart-row-fill {
	background: var(--white);
}
.lab-frozen-article .chart-row.is-hero .chart-row-val {
	font-size: 2.25em;
	color: var(--white);
}
@media (max-width: 768px) {
	.lab-frozen-article .chart-row {
		grid-template-columns: minmax(0, 1fr) 84px;
		gap: 14px 16px;
	}
	.lab-frozen-article .chart-row.is-hero .chart-row-val {
		font-size: 1.75em;
	}
	.lab-frozen-article .chart-row-label {
		grid-column: 1 / -1;
	}
}

/* --- Desktop / Mobile visibility --- */
.lab-frozen-article .chart-desktop { display: block; }
.lab-frozen-article .chart-mobile  { display: none; }

/* --- Keyframe animations --- */
@keyframes chart-draw {
	to { stroke-dashoffset: 0; }
}
@keyframes chart-fade-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}
@keyframes chart-dot-pulse {
	0%   { opacity: 0; transform: scale(0); }
	60%  { opacity: 1; transform: scale(1.7); }
	100% { opacity: 1; transform: scale(1); }
}

/* --- Mobile breakpoint --- */
@media (max-width: 768px) {
	.lab-frozen-article .chart-desktop        { display: none; }
	.lab-frozen-article .chart-mobile         { display: block; }
	.lab-frozen-article .chart-float          { display: none; }
	.lab-frozen-article .chart-legend-wrapper { margin-bottom: 10px; }
}

/* ====================================================
   DISCLOSURE TIMELINE — axis + event nodes
   ==================================================== */

.lab-frozen-article .disclosure-timeline {
	--dt-axis-color: rgba(255, 255, 255, 0.18);
	--dt-axis-accent: rgba(255, 255, 255, 0.4);
	--dt-node-color: var(--white);
	--dt-drop-color: rgba(255, 255, 255, 0.22);
	--dt-label-color: var(--grey-25);
	--dt-title-color: var(--white);
	--dt-body-color: var(--grey-25);
	--dt-caption-w: 240px;
	--dt-drop-h: 32px;
	--dt-caption-gap: 14px;

	position: relative;
	margin: 8px 0 0;
	padding: 0;
	/* Raised from 360px for the audited captions, which run longer (2 Oct 2026). */
	min-height: 500px;
}

/* --- Axis --- */
.lab-frozen-article .disclosure-timeline__axis {
	position: absolute;
	left: 0;
	right: 0;
	top: 50%;
	height: 1px;
	background: linear-gradient(
		to right,
		transparent 0,
		var(--dt-axis-color) 12px,
		var(--dt-axis-color) calc(100% - 12px),
		transparent 100%
	);
}
/* Axis caps: small labels anchored to the very ends of the axis */
.lab-frozen-article .disclosure-timeline__axis-cap {
	position: absolute;
	top: 14px;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.75);
	white-space: nowrap;
	line-height: 1;
}
.lab-frozen-article .disclosure-timeline__axis-cap--start { left: 0; }
.lab-frozen-article .disclosure-timeline__axis-cap--end { right: 0; }

/* "Two patch bypasses" chevron annotation */
.lab-frozen-article .disclosure-timeline__bypass {
	position: absolute;
	top: -16px;
	transform: translateX(-50%);
	display: flex;
	flex-direction: column;
	align-items: center;
	color: rgba(255, 255, 255, 0.55);
	pointer-events: none;
}
.lab-frozen-article .disclosure-timeline__bypass svg {
	display: block;
}
.lab-frozen-article .disclosure-timeline__bypass-label {
	margin-top: 4px;
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 500;
	font-style: italic;
	letter-spacing: 0.01em;
	color: rgba(255, 255, 255, 0.75);
	white-space: nowrap;
	line-height: 1;
}

/* --- Events --- */
.lab-frozen-article .disclosure-timeline__events {
	position: absolute;
	inset: 0;
	list-style: none;
	margin: 0;
	padding: 0;
}
.lab-frozen-article .disclosure-timeline__event {
	position: absolute;
	left: var(--at);
	top: 0;
	bottom: 0;
	width: 0;
}

/* Node: ring + dot — sits on the axis */
.lab-frozen-article .disclosure-timeline__node {
	position: absolute;
	top: 50%;
	left: 0;
	width: 9px;
	height: 9px;
	border-radius: 50%;
	background: var(--dt-node-color);
	transform: translate(-50%, -50%);
	box-shadow: 0 0 0 4px var(--grey-100), 0 0 0 5px rgba(255, 255, 255, 0.35);
	z-index: 2;
}
.lab-frozen-article .disclosure-timeline__node--open {
	background: var(--grey-100);
	box-shadow: 0 0 0 4px var(--grey-100), 0 0 0 5px var(--white);
}

/* Drop hairline from axis to caption */
.lab-frozen-article .disclosure-timeline__event::before {
	content: '';
	position: absolute;
	left: 0;
	width: 1px;
	height: var(--dt-drop-h);
	background: var(--dt-drop-color);
	transform: translateX(-0.5px);
}
.lab-frozen-article .disclosure-timeline__event--above::before {
	bottom: calc(50% + 6px);
}
.lab-frozen-article .disclosure-timeline__event--below::before {
	top: calc(50% + 6px);
}

/* Caption: absolutely anchored to the event x-position; centered by default */
.lab-frozen-article .disclosure-timeline__caption {
	position: absolute;
	left: 0;
	width: var(--dt-caption-w);
	transform: translateX(-50%);
	color: var(--dt-body-color);
}
.lab-frozen-article .disclosure-timeline__event--above .disclosure-timeline__caption {
	bottom: calc(50% + 6px + var(--dt-drop-h) + var(--dt-caption-gap));
	text-align: center;
}
.lab-frozen-article .disclosure-timeline__event--below .disclosure-timeline__caption {
	top: calc(50% + 6px + var(--dt-drop-h) + var(--dt-caption-gap));
	text-align: center;
}

/* Edge alignment so captions don't overflow the panel */
.lab-frozen-article .disclosure-timeline__event[style*="--at: 0%"] .disclosure-timeline__caption {
	transform: translateX(0);
	text-align: left;
}
.lab-frozen-article .disclosure-timeline__event[style*="--at: 100%"] .disclosure-timeline__caption {
	transform: translateX(-100%);
	text-align: right;
}

.lab-frozen-article .disclosure-timeline__date {
	display: block;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 800;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--white);
	line-height: 1;
	margin-bottom: 10px;
}
.lab-frozen-article .disclosure-timeline__vendor {
	display: block;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 16px;
	font-weight: 700;
	letter-spacing: -0.015em;
	color: var(--dt-title-color);
	line-height: 1.2em;
	margin-bottom: 6px;
}
.lab-frozen-article .disclosure-timeline__body {
	margin: 0;
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 15px;
	font-weight: 400;
	color: rgba(255, 255, 255, 0.75);
	line-height: 1.55em;
	letter-spacing: 0.005em;
}

/* --- Mobile: vertical timeline --- */
@media (max-width: 768px) {
	.lab-frozen-article .disclosure-timeline {
		min-height: 0;
		padding: 4px 0 4px 32px;
	}
	.lab-frozen-article .disclosure-timeline__axis {
		position: absolute;
		top: 10px;
		bottom: 10px;
		left: 6px;
		right: auto;
		width: 1px;
		height: auto;
		background: linear-gradient(
			to bottom,
			transparent 0,
			var(--dt-axis-color) 10px,
			var(--dt-axis-color) calc(100% - 10px),
			transparent 100%
		);
	}
	.lab-frozen-article .disclosure-timeline__axis-cap,
	.lab-frozen-article .disclosure-timeline__bypass {
		display: none;
	}
	.lab-frozen-article .disclosure-timeline__events {
		position: static;
		inset: auto;
		display: flex;
		flex-direction: column;
		gap: 26px;
	}
	.lab-frozen-article .disclosure-timeline__event,
	.lab-frozen-article .disclosure-timeline__event--above,
	.lab-frozen-article .disclosure-timeline__event--below {
		position: relative;
		left: 0;
		top: auto;
		bottom: auto;
		width: 100%;
		min-height: 0;
	}
	.lab-frozen-article .disclosure-timeline__event::before {
		display: none;
	}
	.lab-frozen-article .disclosure-timeline__node {
		position: absolute;
		top: 10px;
		left: -26px;
		transform: none;
		width: 9px;
		height: 9px;
		box-shadow: 0 0 0 4px var(--grey-100), 0 0 0 5px rgba(255, 255, 255, 0.35);
	}
	.lab-frozen-article .disclosure-timeline__caption,
	.lab-frozen-article .disclosure-timeline__event--above .disclosure-timeline__caption,
	.lab-frozen-article .disclosure-timeline__event--below .disclosure-timeline__caption,
	.lab-frozen-article .disclosure-timeline__event[style*="--at: 0%"] .disclosure-timeline__caption,
	.lab-frozen-article .disclosure-timeline__event[style*="--at: 100%"] .disclosure-timeline__caption {
		position: relative;
		left: auto;
		right: auto;
		top: auto;
		bottom: auto;
		width: 100%;
		max-width: 100%;
		text-align: left;
		transform: none;
	}
	.lab-frozen-article .disclosure-timeline__date {
		margin-bottom: 8px;
	}
	.lab-frozen-article .disclosure-timeline__vendor {
		font-size: 17px;
		margin-bottom: 4px;
	}
	.lab-frozen-article .disclosure-timeline__body {
		font-size: 15px;
	}
}

/* ====================================================
   REGULATION INFOGRAPHIC
   ==================================================== */

.lab-frozen-article .reg-subtitle {
	margin: 6px 0 24px;
	font-size: 0.9em;
	line-height: 1.4em;
	color: var(--grey-25);
}
.lab-frozen-article .reg-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 10px;
	margin-bottom: 10px;
}
.lab-frozen-article .reg-card {
	background: var(--grey-75);
	border-radius: 20px;
	padding: 30px;
}
.lab-frozen-article .reg-eyebrow {
	display: block;
	margin-bottom: 10px;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 0.7em; /* 14px */
	font-weight: 900;
	letter-spacing: 0.05em;
	line-height: 1em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.75);
}
.lab-frozen-article .reg-stat {
	display: block;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 3em;
	font-weight: 800;
	line-height: 0.95em;
	letter-spacing: -0.04em;
	color: var(--white);
	margin-bottom: 16px;
}
.lab-frozen-article .reg-copy {
	font-size: 0.85em;
	line-height: 1.5em;
	color: var(--white);
	margin: 0 0 10px;
}
.lab-frozen-article .reg-source {
	font-size: 0.65em;
	line-height: 1.4em;
	color: var(--grey-50);
	margin: 0;
}
/* grey-50 above is calibrated for the light outcome panels (same issue as
   .vef-h3-year) -- reg-source only ever actually sits on the dark
   panel-grey-100 reg-card/reg-precedent surfaces, where it was reading as
   near-invisible (Finn, 11 Sep 2026). Override to the same light grey the
   rest of this dark context already uses. */
.lab-frozen-article .reg-card .reg-source,
.lab-frozen-article .reg-precedent .reg-source {
	color: rgba(255, 255, 255, 0.6);
}
.lab-frozen-article .reg-card .reg-source:hover,
.lab-frozen-article .reg-precedent .reg-source:hover {
	color: rgba(255, 255, 255, 0.85);
}

/* Precedent bar */
.lab-frozen-article .reg-precedent {
	background: var(--grey-75);
	border-radius: 20px;
	padding: 30px;
	display: flex;
	align-items: center;
	gap: 30px;
}
.lab-frozen-article .reg-precedent-stat {
	flex-shrink: 0;
	min-width: 120px;
}
.lab-frozen-article .reg-precedent-stat .reg-stat {
	font-size: 3.5em;
	margin-bottom: 0;
}
.lab-frozen-article .reg-precedent-content {
	flex: 1;
}
.lab-frozen-article .reg-precedent-content .reg-copy {
	margin-bottom: 6px;
}

/* 3-column grid at lg and above */
@media (min-width: 992px) {
	.lab-frozen-article .reg-grid {
		grid-template-columns: repeat(3, 1fr);
	}
}

/* Stack precedent bar on smaller screens */
@media (max-width: 991px) {
	.lab-frozen-article .reg-precedent {
		flex-direction: column;
		align-items: flex-start;
		gap: 12px;
	}
	.lab-frozen-article .reg-precedent-stat {
		min-width: unset;
	}
	.lab-frozen-article .reg-precedent-stat .reg-stat {
		font-size: 3em;
	}
}

/* --- Product Landscape intro type-scale + methodology reposition
   (density pass, 11 Sep 2026) ---
   Body text is 500-weight system-wide, not 400 -- semibold (600) promotes
   this above plain body copy without reaching the lede's bold (700); white
   (not a muted grey) matches on-dark surfaces, since a grey token
   calibrated for light panels reads as too low-contrast here. */
.lab-frozen-article .vef-intro-support {
	margin-top: var(--space-30);
	margin-bottom: 0;
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 1em;
	font-weight: 600;
	color: var(--white);
	letter-spacing: normal;
}
/* Sits directly under the h2, which already carries its own pad-b-50 --
   stacking .section-intro's usual space-30 on top would double the gap. */
.lab-frozen-article h2.pad-b-50 + .vef-intro-support {
	margin-top: 0;
}
.lab-frozen-article .vef-intro-support .text-white {
	font-weight: 700;
}
/* Trims a .section-intro down to the same 1.5em weight as the outcome-card
   h4 labels (Efficacy etc.) below it, rather than the default 2em -- used
   where the intro is making a denser, more argumentative point than a
   simple lead-in question. */
.lab-frozen-article .vef-intro-compact {
	font-size: 1.5em;
}

/* Methodology footnote below the continuum -- fine print, not a second
   lede. rgba(255,255,255,0.6) is the existing on-black muted-text value
   this codebase already uses elsewhere, rather than a grey-* token, which
   the rule above already flags as too low-contrast on this dark surface. */
.lab-frozen-article .vef-methodology-note {
	margin: 0;
	font-family: 'Inter', 'Arial', sans-serif;
	font-size: 0.8em;
	font-weight: 400;
	line-height: 1.5;
	color: rgba(255, 255, 255, 0.6);
	letter-spacing: normal;
}
.lab-frozen-article .vef-methodology-note strong {
	color: rgba(255, 255, 255, 0.85);
	font-weight: 600;
}

/* --- Collapsible regulatory cards (SAT density pass, 11 Sep 2026) ---
   Cards collapse to eyebrow + stat by default; expanding reveals the
   subcopy. .reg-eyebrow/.reg-stat are already display:block, so wrapping
   them in <summary> keeps the existing vertical stack; the toggle icon is
   positioned absolutely so it doesn't force them onto one row. */
.lab-frozen-article .reg-card,
.lab-frozen-article .reg-precedent {
	position: relative;
}
.lab-frozen-article .vef-reg-toggle summary {
	cursor: pointer;
	list-style: none;
}
.lab-frozen-article .vef-reg-toggle summary::-webkit-details-marker {
	display: none;
}
.lab-frozen-article .vef-reg-toggle-icon {
	position: absolute;
	top: 25px;
	right: 25px;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 20px;
	font-weight: 400;
	color: var(--grey-25);
}
.lab-frozen-article .vef-reg-toggle-icon::before {
	content: '+';
}
.lab-frozen-article .vef-reg-toggle[open] .vef-reg-toggle-icon::before {
	content: '\2212';
}
.lab-frozen-article .vef-reg-toggle:not([open]) .reg-copy,
.lab-frozen-article .vef-reg-toggle:not([open]) .reg-source,
.lab-frozen-article .vef-reg-toggle:not([open]) .reg-precedent-content {
	display: none;
}

/* Precedent cards: .reg-precedent is a flex row pairing .reg-precedent-stat
   with .reg-precedent-content -- fine when both are always visible, but the
   content is now inside <details> and hidden by default, so the row moves
   onto <summary> (stat + toggle icon) and the content stacks below when
   opened, rather than forcing an empty flex track. Scoped to :has() the
   toggle variant specifically -- the bare selector here previously matched
   EVERY .reg-precedent site-wide, including Email's plain (non-toggle)
   precedent cards, which broke their flex layout entirely and collapsed
   the gap between stat and copy to zero (Finn, 11 Sep 2026). */
.lab-frozen-article .reg-precedent:has(.vef-reg-toggle--precedent) {
	display: block;
}
.lab-frozen-article .vef-reg-toggle--precedent summary {
	display: flex;
	align-items: center;
	gap: 30px;
}
.lab-frozen-article .vef-reg-toggle--precedent .reg-precedent-content {
	margin-top: 16px;
}
/* The site's own CSS gives .reg-grid a margin-bottom but never gave two
   stacked .reg-precedent cards any spacing between each other -- with a
   second precedent card added here (Oxfam), they sat flush together
   (Finn, 11 Sep 2026). Matches the 10px rhythm .reg-grid already uses. */
.lab-frozen-article .reg-precedent + .reg-precedent {
	margin-top: 10px;
}

/* Stat cards unboxed onto top rules, matching the VM charts (Finn, 2 Oct
   2026): grey boxes inside a grey panel read as filler. Each stat now sits
   under a hairline, with the gap doing the separating. */
.lab-frozen-article .reg-grid {
	gap: 40px;
	margin-bottom: 40px;
}
.lab-frozen-article .reg-card,
.lab-frozen-article .reg-precedent {
	padding: 24px 0 0;
	background: none;
	border-radius: 0;
	border-top: 1px solid rgba(255, 255, 255, 0.2);
}
.lab-frozen-article .reg-precedent + .reg-precedent {
	margin-top: 40px;
}
/* A long word stat ("Untested") is wider than a narrow card at 3em, so
   the figure caps at its card width. */
.lab-frozen-article .reg-card {
	container-type: inline-size;
}
.lab-frozen-article .reg-card .reg-stat {
	font-size: min(3em, 22cqi);
}
.lab-frozen-article .vef-reg-toggle-icon {
	top: 22px;
	right: 0;
}

/* Two verdict lines bookending the regulatory grid, pulled out of the
   paragraph flow into a standalone, ruled statement. */
.lab-frozen-article .vef-reg-stamp {
	border-top: 2px solid rgba(255, 255, 255, 0.25);
	border-bottom: 2px solid rgba(255, 255, 255, 0.25);
	padding: 20px 0;
	margin: 0;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 1.3em;
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.3;
}

/* --- Threat Context density pass: two-column editorial prose (Finn, 14 Sep 2026) ---
   The section was prose-dominant: ~12 body paragraphs against 2 infographic
   panels, all sharing the same 800px left edge, so the graphics read as
   slightly-wider text rows rather than set-pieces. Flowing the three pure-prose
   blocks into two columns roughly halves their height and reads as premium
   editorial, while the widened panels below out-dent the text on both edges.
   Applied ONLY to the pure multi-paragraph blocks -- NOT the ruled
   .vef-reg-stamp statements or the stat panels (multi-column would split their
   borders/grids). 30px gap = the design system's space-30.
   Gated at 992px: below it the prose band is already full-width and stacks; a
   2-col split there would collapse to ~150px columns (unreadable). */
@media (min-width: 992px) {
	.lab-frozen-article .threat-prose-2col {
		column-count: 2;
		column-gap: 50px; /* space-50 -- wider gutter so the two columns read as distinct */
		/* space-20 above and below the denser 2-col block. Block padding only:
		   the old shorthand zeroed the column's 12px gutter, so the block sat
		   12px left of the headings around it (Finn, 6 Oct 2026). */
		padding-top: 20px;
		padding-bottom: 20px;
	}
	.lab-frozen-article .threat-prose-2col > h3 {
		column-span: all; /* sub-head spans both columns, prose flows beneath */
		/* 20px read as too tight under a 60px h3 -- the heading's own weight
		   needs more breathing room before the lighter 17px column text
		   starts (Finn, 14 Sep 2026). */
		margin-bottom: 50px; /* space-50 */
	}
	.lab-frozen-article .threat-prose-2col > p:not(.section-quote):not(.section-intro) {
		break-inside: avoid; /* never split a paragraph across the column gap */
		/* Drop to the infographic body-copy size (17px, matching .bar-content /
		   .reg-copy) so the two-column editorial prose reads lighter than the
		   20px single-column body. Scoped to > p so the em-based h3 keeps 60px. */
		font-size: 0.85em; /* 17px */
		line-height: 1.6em; /* 27.2px -- comfortable measure in a ~375px column */
	}
	.lab-frozen-article .threat-prose-2col > p:first-of-type {
		margin-top: 0;
	}
}

/* The two-column prose outside Threat Context (SAT Foreword and Conclusion
   first, Finn, 6 Oct 2026): the section heading and the Foreword's author
   line span both columns, like the h3. */
@media (min-width: 992px) {
	.lab-frozen-article .threat-prose-2col > h2,
	.lab-frozen-article .threat-prose-2col > .section-quote,
	.lab-frozen-article .threat-prose-2col > .section-intro,
	.lab-frozen-article .threat-prose-2col > .author-details {
		column-span: all;
	}
	.lab-frozen-article .threat-prose-2col > .section-quote,
	.lab-frozen-article .threat-prose-2col > .section-intro {
		margin-bottom: 50px; /* space-50, as under the h3 */
	}
	.lab-frozen-article .threat-prose-2col > ul,
	.lab-frozen-article .threat-prose-2col > ol {
		break-inside: avoid;
	}
	.lab-frozen-article .threat-prose-2col > h2 {
		margin-bottom: 30px; /* space-30 */
	}
}

/* Threat Context's closing summary, set in the stamp statements' type
   (.vef-reg-stamp: Inter Tight, 22px, bold) without their rules, so the
   section ends on a statement rather than a footnote-sized line (Finn,
   6 Oct 2026). */
.lab-frozen-article .threat-summary p {
	margin: 0;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 1.3em;
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.3;
}

/* Hero'd infographic panels break wider than the 800px prose band (markup:
   col-xxl-10 offset-xxl-1, ~1333px, out-denting the text both sides). Give the
   larger footprint room to breathe: 50px pad = space-50, up from the base 30px.
   Panel's own responsive padding at narrow widths is left to the base rules. */
@media (min-width: 992px) {
	.lab-frozen-article .threat-hero-panel .panel {
		padding: 50px; /* space-50 */
	}
}

/* Single-column Threat Context prose, sized to match the infographic body
   copy (.bar-content / .reg-copy, both 17px) rather than the 20px article
   default -- keeps the whole dense Threat Context section reading as one
   consistent voice instead of jumping between 20px and 17px block to block.
   Unconditional (not gated to >=992px): the infographics themselves are 17px
   at every width, so this stays consistent on mobile too (Finn, 14 Sep 2026). */
.lab-frozen-article .threat-prose-tight p {
	font-size: 0.85em; /* 17px */
	line-height: 1.6em; /* 27.2px */
}

/* Wide Threat Context (SAT first, Finn, 6 Oct 2026). The section's text
   column now matches the embedded videos and the lead-gen close
   (col-xl-10 col-xxl-8), so headings and the two-column prose get room.
   A lone paragraph would run past a comfortable measure at that width,
   so single-column prose keeps one; the two-column blocks need no cap.
   Since 21 Oct 2026 every article's prose is one column (Finn), held to the
   Foreword's ~800px measure (47em at Body 17px). */
.lab-frozen-article #section-threat .col-xl-10:not(.threat-prose-2col) > p:not(.section-intro),
.lab-frozen-article #section-threat .threat-prose-tight p {
	max-width: 47em;
}

/* .threat-split (an explicit flex 2-column pairing) was tried here for
   "Where legacy filters fall short" and reverted (14 Sep 2026): its
   align-items:center floated the shorter column mid-way down, unaligned
   with the top of its partner, which read as a layout bug rather than an
   intentional pairing. CSS multi-column (.threat-prose-2col, used
   throughout this section) is the right tool instead -- its columns are
   always top-aligned by construction (there is no way to centre one), and
   it auto-balances by rendered height regardless of paragraph count, so it
   scales to any domain's Threat Context copy without per-block manual
   authoring. Rolled out on that basis: every 2+ paragraph prose block in
   Threat Context uses .threat-prose-2col; a lone paragraph uses
   .threat-prose-tight (nothing to split). See email/browser/SAT Threat
   Context for the applied pattern. */

/* Small-source-size year, sat inline in an h3 rather than as a sup. grey-25,
   not grey-50 -- grey-50 is calibrated for text on the light outcome panels
   and is nearly invisible against this section's black background; grey-25
   matches .text-grey already used elsewhere in this dark section. */
.lab-frozen-article .vef-h3-year {
	font-size: 0.4em;
	font-weight: 400;
	color: var(--grey-25);
	letter-spacing: normal;
}

/* --- Fixed-footprint expand: Security Outcomes, and email's four patterns
   (Frank, 14 Oct; AR1). The site's v79 expand grid (ExpandGrid.astro) in
   plain HTML: four tiles over one detail area. Every panel sits in the
   area's one grid cell, so the area holds the longest one and choosing a
   tile never moves the page. The first is open by default; the tiles are
   tabs (core.js wires clicks and arrow keys, vendor-enquiry.js tracks).
   Replaces the 11 Sep collapsible cards, which pushed the page down. */
.lab-frozen-article .lab-xgrid__tiles {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 10px;
}
@media (min-width: 1200px) {
	.lab-frozen-article .lab-xgrid__tiles {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}
.lab-frozen-article .lab-xgrid__tile {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	min-height: 84px;
	padding: 20px;
	border: 0;
	border-radius: 20px;
	background: var(--white);
	box-shadow: inset 0 0 0 1px rgba(20, 20, 20, 0.08), 0 1px 2px rgba(20, 20, 20, 0.04), 0 10px 28px rgba(20, 20, 20, 0.05);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 20px;
	font-weight: 700;
	letter-spacing: -0.02em;
	line-height: 1.15;
	text-align: left;
	color: var(--black);
	cursor: pointer;
	transition: box-shadow 0.2s ease;
}
.lab-frozen-article .lab-xgrid__tile:hover {
	box-shadow: inset 0 0 0 1px rgba(20, 20, 20, 0.16), 0 1px 2px rgba(20, 20, 20, 0.05), 0 14px 34px rgba(20, 20, 20, 0.09);
}
.lab-frozen-article .lab-xgrid__tile[aria-selected='true'] {
	box-shadow: inset 0 0 0 2px var(--black), 0 1px 2px rgba(20, 20, 20, 0.04), 0 10px 28px rgba(20, 20, 20, 0.05);
}
.lab-frozen-article .lab-xgrid__tile:focus-visible {
	outline: 2px solid var(--black);
	outline-offset: 3px;
}
.lab-frozen-article .lab-xgrid__tile .outcome-number {
	flex: 0 0 25px;
	float: none;
	margin-top: -1px;
	letter-spacing: normal;
}
.lab-frozen-article .lab-xgrid__area {
	display: grid;
	margin-top: 10px;
	/* The CTA card's padding (Finn, 21 Oct 2026), so the copy breathes on
	   the right as well. */
	padding: 50px;
	border-radius: 30px;
	/* The card rule's open-featured corner: the area is always the open one. */
	background:
		radial-gradient(85% 75% at 0% 0%, #E0ECFF, transparent 75%),
		var(--white);
	box-shadow: inset 0 0 0 1px rgba(20, 20, 20, 0.08), 0 1px 2px rgba(20, 20, 20, 0.04), 0 10px 28px rgba(20, 20, 20, 0.05);
}
.lab-frozen-article .lab-xgrid__panel {
	grid-area: 1 / 1;
	visibility: hidden;
	opacity: 0;
	transition: opacity 0.25s ease, visibility 0s linear 0.25s;
}
.lab-frozen-article .lab-xgrid__panel.is-open {
	visibility: visible;
	opacity: 1;
	transition: opacity 0.25s ease, visibility 0s;
}
.lab-frozen-article .lab-xgrid__name {
	margin-bottom: 0;
}
.lab-frozen-article .lab-xgrid__panel > p {
	margin: 12px 0 0;
}
/* On black (email's four patterns): the dark panel grey, white ring. */
.lab-frozen-article .lab-xgrid--dark .lab-xgrid__tile,
.lab-frozen-article .lab-xgrid--dark .lab-xgrid__area {
	background: var(--grey-100);
	color: var(--white);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
}
.lab-frozen-article .lab-xgrid--dark .lab-xgrid__tile:hover {
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28);
}
.lab-frozen-article .lab-xgrid--dark .lab-xgrid__tile[aria-selected='true'] {
	box-shadow: inset 0 0 0 2px var(--white);
}
.lab-frozen-article .lab-xgrid--dark .lab-xgrid__tile:focus-visible {
	outline-color: var(--white);
}
@media (max-width: 767px) {
	.lab-frozen-article .lab-xgrid__tile {
		min-height: 72px;
		padding: 16px;
		font-size: 17px;
	}
	.lab-frozen-article .lab-xgrid__area {
		padding: 30px;
		border-radius: 20px;
	}
}
@media (prefers-reduced-motion: reduce) {
	.lab-frozen-article .lab-xgrid__panel,
	.lab-frozen-article .lab-xgrid__panel.is-open {
		transition: none;
	}
}
.lab-frozen-article .vef-outcome-toggle summary {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 10px;
	cursor: pointer;
	list-style: none;
}
.lab-frozen-article .vef-outcome-toggle summary::-webkit-details-marker {
	display: none;
}
.lab-frozen-article .vef-outcome-toggle summary h4 {
	margin-bottom: 0;
}
/* The base h4 margin-bottom fix doesn't reach here: this h4 sits inside
   <summary> (margin-bottom zeroed above so the toggle icon aligns cleanly on
   the flex row), and the revealed content in the "Where legacy filters fall
   short" pattern cards is a plain <p>, not a .vef-outcome-list <ul> -- so it
   never picked up that list's own margin-top: 12px. Without this, expanding
   one of those cards (e.g. "Mid-Campaign Defence Response") left the
   paragraph sitting flush under the heading (Finn, 14 Sep 2026). */
.lab-frozen-article .vef-outcome-toggle summary + p {
	margin-top: 12px;
}
/* Same author-origin override that breaks native details-closed hiding for
   .vef-outcome-list (see below) also hides the plain-<p> reveal case here --
   confirmed live on the already-shipped four-pattern cards, the paragraph
   stayed visible even with the details closed. Force it explicitly, same as
   the list case. */
.lab-frozen-article .vef-outcome-toggle:not([open]) summary + p {
	display: none;
}
.lab-frozen-article .vef-outcome-toggle[open] summary + p {
	display: block;
}
/* The Addendum FAQ reuses .vef-outcome-toggle bare (no card grid, no
   .panel gutter around it), so its items had no spacing of their own --
   sat flush against each other and against "Disclaimers" below (Finn,
   14 Sep 2026). Grid-based uses (Security Outcomes, four-patterns) don't
   need this: Bootstrap's row/col gutters already separate those.
   20px, the site's --space-20 step, not an arbitrary value. */
.lab-frozen-article #section-addendum .vef-outcome-toggle {
	margin-bottom: 20px;
}
/* Design-system review (14 Sep 2026): h4 (30px/700, the base rule above)
   is the site's only sub-heading size, so reusing it unchanged for each
   FAQ question collapsed two hierarchy levels: "Further questions" (a
   section label, peer of Scope/Feature Granularity Model/Disclaimers)
   read identically to the individual questions nested under it. Demotes
   the question text to body size (20px, still bold) so it reads as
   content within "Further questions" rather than another section label.
   (Note: the sibling body paragraphs were 20px when this was written; they
   were subsequently dropped to 17px below -- the question text stays at
   20px so it still outranks its own 17px answer.) Card-grid uses of
   .vef-outcome-toggle (Security Outcomes, four-patterns) keep the full h4
   size -- those really are card headings, not nested list items. */
.lab-frozen-article #section-addendum .vef-outcome-toggle summary h4 {
	font-size: 20px;
}

/* Addendum density pass (Finn, 14 Sep 2026): the "Email Security category"
   block (Scope / Feature Granularity Model / Further questions / Disclaimers)
   had no separation between one sub-section's closing paragraph and the next
   h4 label -- both relied on the paragraph's own 16px margin-bottom (h4's own
   margin-top is 0), so it read as one continuous flow with no sub-section
   boundary. margin-top on the h4 itself gives each sub-section a clean break
   from the one above, on the space-50 step. */
.lab-frozen-article #section-addendum .addendum-category > h4 {
	margin-top: 50px;
}
/* Same pass: body copy (Scope/FGM/Disclaimers paragraphs, and especially the
   FAQ answers) drops from the 20px article default to 17px, matching the
   infographic body-copy size used elsewhere (.bar-content/.reg-copy) and the
   Threat Context prose. The FAQ question h4 above stays at 20px, so it still
   outranks its own answer -- same "label out-ranks its content" principle as
   the h3/h4 nest one level up. */
.lab-frozen-article #section-addendum .addendum-category p {
	font-size: 0.85em; /* 17px */
	line-height: 1.6em;
}
.lab-frozen-article .vef-outcome-toggle-icon {
	flex-shrink: 0;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 20px;
	font-weight: 400;
	color: var(--grey-50);
}
/* grey-50 above is calibrated for the light outcome panels -- this same icon
   is reused bare in the Addendum FAQ, which sits directly on bkg-black,
   where it drops under WCAG's 3:1 non-text contrast floor. Same fix as the
   reg-source override above: translucent white for the dark context. */
.lab-frozen-article #section-addendum .vef-outcome-toggle-icon {
	color: rgba(255, 255, 255, 0.6);
}
.lab-frozen-article .vef-outcome-toggle-icon::before {
	content: '+';
}
.lab-frozen-article .vef-outcome-toggle[open] .vef-outcome-toggle-icon::before {
	content: '\2212';
}
.lab-frozen-article .vef-outcome-list {
	margin: 12px 0 0;
	padding-left: 18px;
}
/* Body size, not fine print: the expanded points are the content of the
   card (Frank, 1 Oct 2026). */
.lab-frozen-article .vef-outcome-list li {
	font-size: 1em;
	line-height: 1.6;
	color: var(--black);
	margin-bottom: 6px;
}
.lab-frozen-article .vef-outcome-list li:last-child {
	margin-bottom: 0;
}
/* Something upstream overrides the browser's native details-closed hiding
   (an author-origin rule always beats the UA stylesheet's
   details:not([open]) > * rule, regardless of specificity), so the
   closed/open state is forced explicitly here instead of relying on the
   native behaviour. */
.lab-frozen-article .vef-outcome-toggle:not([open]) .vef-outcome-list {
	display: none;
}
.lab-frozen-article .vef-outcome-toggle[open] .vef-outcome-list {
	display: block;
}

/* ====================================================
   VENDOR ENQUIRY FEATURE — ported from the proven prototype
   (live-article-proof-sat.html, confirmed working against the real
   HubSpot form 4 Sep 2026) into production for SAT, 14 Sep 2026.
   Only the genuinely new rules from that prototype are here -- it also
   contained an inline <style> block re-listing several .vef-* rules
   (.vef-reg-stamp, .vef-outcome-toggle, .vef-intro-support,
   .vef-methodology-note, .vef-h3-year, .vef-reg-toggle) that ALREADY exist
   above, refined further since the prototype was frozen -- skipped
   deliberately, not overwritten.
   ==================================================== */

/* Vendor selection affordance -- desktop/tablet rows (.prod-list li) and
   mobile tiles (the liquidGlass continuum icons), both toggled by the same
   JS (see the vendor-enquiry <script> block at the end of this article's
   own HTML). Vendor identity is read from a li's own text content / the
   matching tile's icon src -- no data-vendor attribute needed, so no
   markup change to the vendor list itself. */
.lab-frozen-article .prod-list li {
	cursor: pointer;
	transition: opacity 0.12s ease;
}
.lab-frozen-article .prod-list li:hover {
	opacity: 0.75;
}
.lab-frozen-article .prod-list li.vef-selected {
	background: var(--grey-10);
	color: var(--black);
	border-radius: 9999px;
	padding: 0 14px;
}
/* One line for the vendor, one for the product: a long product name trails
   off rather than growing its row, so every row (and every selected pill)
   stays the same height. The full string shows on hover or focus, and for
   a few seconds after a tap on touch screens (.vef-show-full), from
   data-full, which vendor-enquiry.js sets only on rows it actually cut.
   Hover is limited to devices that really hover, so a phone's sticky
   tap-hover doesn't leave a label stranded. */
.lab-frozen-article .prod-list li {
	position: relative;
}
.lab-frozen-article .prod-list-name {
	white-space: nowrap;
	overflow: hidden;
}
.lab-frozen-article .prod-list-name small,
.lab-frozen-article .prod-list-vendor {
	display: block;
	overflow: hidden;
	text-overflow: ellipsis;
}
@media (hover: hover) {
	.lab-frozen-article .prod-list li.vef-truncated:hover {
		opacity: 1;
	}
	.lab-frozen-article .prod-list li.vef-truncated:hover > * {
		opacity: 0.75;
	}
	.lab-frozen-article .prod-list li.vef-truncated:hover::after {
		display: block;
	}
}
.lab-frozen-article .prod-list li.vef-truncated:focus-visible::after,
.lab-frozen-article .prod-list li.vef-truncated.vef-show-full::after {
	display: block;
}
.lab-frozen-article .prod-list li.vef-truncated::after {
	display: none;
	content: attr(data-full);
	position: absolute;
	left: 0;
	bottom: calc(100% + 8px);
	z-index: 5;
	width: max-content;
	max-width: min(320px, 90vw);
	padding: 8px 12px;
	border-radius: 8px;
	background: var(--white);
	color: var(--black);
	font-size: 13px;
	font-weight: 500;
	line-height: 1.35;
	white-space: normal;
	box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
	pointer-events: none;
}
/* The lists are two columns: the right-hand column's label grows leftwards
   so it never runs off the screen. */
.lab-frozen-article .prod-list li.vef-truncated:nth-child(2n)::after {
	left: auto;
	right: 0;
}
/* A shortlisted vendor in the lists: the mono tile turns white, its mark
   black, so the choice reads at a glance. */
.lab-frozen-article .prod-list li.vef-selected .prod-list-icon {
	background: var(--white);
}
.lab-frozen-article .prod-list li.vef-selected .prod-list-icon img {
	filter: invert(1);
}
/* Hover reads as "add to cart" (Finn, 21 Oct 2026): the diamond stays fully
   opaque in its glass, with no ring at rest. On hover a white ring fades
   slowly up around it while it dips down and a little right, as if about to
   fly up to the shortlist; a shortlisted vendor keeps the ring. `translate`
   moves it without touching its rotate. */
.lab-frozen-article .liquidGlass-wrapper.prod-icon {
	cursor: pointer;
	outline: 2px solid rgba(255, 255, 255, 0);
	outline-offset: 2px;
	transition: translate 0.25s ease, outline-color 0.45s ease;
}
.lab-frozen-article .liquidGlass-wrapper.prod-icon:hover,
.lab-frozen-article .liquidGlass-wrapper.prod-icon:focus-visible {
	translate: 2px 3px;
	outline-color: var(--white);
}
.lab-frozen-article .liquidGlass-wrapper.prod-icon.vef-selected {
	outline-color: var(--white);
}
/* Frosted over the 2x2 block of lattice cells it covers, so the cells read
   as a soft glow through the glass rather than a sharp cross. */
.lab-frozen-article .prod-icon .liquidGlass-effect {
	backdrop-filter: blur(8px);
}
@media (prefers-reduced-motion: reduce) {
	.lab-frozen-article .liquidGlass-wrapper.prod-icon:hover,
	.lab-frozen-article .liquidGlass-wrapper.prod-icon:focus-visible {
		translate: none;
	}
}
/* The ring alone marks a shortlisted vendor in the continuum; its logo, on
   its white square, never changes (Finn, 16 Oct: no inverting). */

/* "Make an Enquiry" capture modal -- dark palette regardless of the
   article's own section theming, since it's a fixed overlay above
   everything. Not scoped to .lab-frozen-article: it's a fixed-position
   scrim that sits above the whole page, same reasoning as not scoping
   any other fixed/overlay component in this codebase. */
.vef-modal-scrim {
	position: fixed;
	inset: 0;
	z-index: 2000;
	background: rgba(0, 0, 0, 0.55);
	backdrop-filter: blur(4px);
	display: none;
	align-items: center;
	justify-content: center;
	padding: 20px;
}
.vef-modal-scrim.vef-modal-open {
	display: flex;
}
.vef-modal {
	position: relative;
	width: 100%;
	max-width: 420px;
	max-height: calc(100vh - 40px);
	max-height: calc(100dvh - 40px);
	overflow-y: auto;
	overscroll-behavior: contain;
	background: #141414;
	border-radius: 20px;
	padding: 28px 26px;
	box-shadow: 0 30px 60px rgba(0, 0, 0, 0.45);
}
.vef-modal-close {
	position: absolute;
	top: 16px;
	right: 16px;
	width: 26px;
	height: 26px;
	border-radius: 9999px;
	background: var(--black);
	color: var(--white);
	border: none;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 14px;
	font-weight: 700;
	cursor: pointer;
	padding: 0;
	transition: opacity 0.12s ease;
}
.vef-modal-close:hover {
	opacity: 0.65;
}
/* The right padding keeps the pills clear of the close button. */
.vef-modal-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin: 0 0 18px;
	padding-right: 34px;
}
.vef-modal-pills .vef-sl-pill {
	background: var(--grey-10);
	color: var(--black);
}
/* Scoped under .vef-modal because the modal sits inside
   .lab-frozen-article, whose h3 rule (60px, 40px on mobile) otherwise
   outranks a bare class and sets these headings at article size. */
.vef-modal .vef-modal-heading {
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-weight: 700;
	font-size: 32px;
	line-height: 1.05;
	letter-spacing: -0.03em;
	text-wrap: balance;
	color: var(--white);
	margin: 0 0 12px;
}
.vef-modal #vef-modal-confirm-heading {
	font-size: 28px;
}
@media (max-width: 575px) {
	.vef-modal .vef-modal-heading {
		font-size: 28px;
	}
	.vef-modal #vef-modal-confirm-heading {
		font-size: 26px;
	}
}
.vef-modal-copy {
	color: #d0d2d5;
	font-size: 14px;
	line-height: 1.55;
	margin: 0 0 16px;
}
.vef-modal-copy strong {
	color: var(--white);
}
.vef-modal-form {
	display: flex;
	gap: 8px;
	flex-wrap: wrap;
}
.vef-modal-input {
	flex: 1 1 150px;
	background: #2a2a2a;
	border: 1px solid transparent;
	border-radius: 9999px;
	padding: 12px 16px;
	color: var(--white);
	font-size: 14px;
	line-height: 20px;
	font-family: 'Inter', 'Arial', sans-serif;
	min-width: 0;
}
.vef-modal-input::placeholder {
	color: var(--grey-25);
}
.vef-modal-input.vef-input-error {
	border-color: var(--white);
	border-width: 2px;
}
.vef-modal-input:disabled {
	opacity: 0.6;
}
/* Number of employees. A native select, styled as the other pill inputs,
   with its own chevron. Until a band is chosen the required select is
   :invalid and reads in the placeholder grey. */
.vef-modal-select {
	appearance: none;
	-webkit-appearance: none;
	padding-right: 40px;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 16px center;
	cursor: pointer;
}
.vef-modal-select:invalid {
	color: var(--grey-25);
}
.vef-modal-select option {
	background: #2a2a2a;
	color: var(--white);
}
.vef-modal-submit {
	flex: 1 1 150px;
	background: var(--white);
	color: var(--black);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-weight: 700;
	font-size: 14px;
	line-height: 20px;
	border: none;
	border-radius: 9999px;
	padding: 12px 18px;
	cursor: pointer;
}
.vef-modal-submit:disabled {
	background: #3a3a3a;
	color: #8a8a8a;
	cursor: default;
}
.vef-modal-error {
	display: flex;
	align-items: center;
	gap: 10px;
	color: var(--white);
	font-size: 12.5px;
	margin: 10px 0 0;
}
.vef-modal-error-icon {
	flex: 0 0 auto;
}
.vef-modal-error[hidden] {
	/* The class above sets display:flex, which outranks the user agent's
	   [hidden] { display: none } on specificity. Without this the empty
	   error row, and its icon, sit under every form all the time. */
	display: none;
}
.vef-modal .vef-modal-reassure,
.vef-modal .vef-modal-notice {
	color: #d0d2d5;
	font-size: 13px;
	line-height: 1.5;
	margin: 12px 0 0;
}
/* The consent notice for research emails (2 Oct 2026). It must stay
   readable and next to the button, so it is not fine print. */
.vef-modal .vef-modal-notice {
	margin-top: 6px;
}
.vef-modal .vef-modal-notice a {
	color: var(--white);
	text-decoration: underline;
	text-underline-offset: 2px;
}
/* Research blue and confirmation green, the same values and meanings as the
   v79 system (src/styles/v79-system.css): blue = Tekspace Research and what
   is being considered, green = confirmed or approved. Graphics only (dots,
   ticks), never on words or buttons, and always repeating what the text
   already says. */
:root {
	--v79-blue-dot: #8EAADD;
	--v79-green-mid: #C6DBD2;
	--v79-green-ink: #2E5444;
}
/* The thank-you tick is the confirmation, so it takes the green tick badge
   (the Guarantee card's colours). */
.vef-modal-success-icon {
	width: 36px;
	height: 36px;
	border-radius: 9999px;
	background: var(--v79-green-mid);
	color: var(--v79-green-ink);
	display: flex;
	align-items: center;
	justify-content: center;
	font-weight: 800;
	font-size: 16px;
	margin: 0 0 14px;
}
/* Make an enquiry: a spinner while sending, then white with a check and
   "Enquiry sent" once Form 1 is accepted. The sent state overrides the
   grey :disabled look, since the button stays disabled until the window
   moves on. Motion is only added for readers who have not asked for less
   of it; for everyone else the states simply swap. */
.vef-modal-submit.vef-submit-sending,
.vef-modal-submit.vef-submit-sent {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
}
.vef-modal-submit.vef-submit-sent,
.vef-modal-submit.vef-submit-sent:disabled {
	background: var(--white);
	color: var(--black);
}
.vef-submit-spinner {
	width: 14px;
	height: 14px;
	border-radius: 9999px;
	border: 2px solid currentColor;
	border-top-color: transparent;
	flex: 0 0 auto;
}
.vef-submit-check {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 20px;
	height: 20px;
	border-radius: 9999px;
	background: var(--black);
	color: var(--white);
	flex: 0 0 auto;
}
@media (prefers-reduced-motion: reduce) {
	.vef-submit-spinner {
		display: none;
	}
}
@media (prefers-reduced-motion: no-preference) {
	.vef-modal-submit {
		transition: background-color 0.2s ease, color 0.2s ease;
	}
	.vef-submit-spinner {
		animation: vef-spin 0.8s linear infinite;
	}
	.vef-submit-check,
	.vef-modal-step .vef-modal-success-icon {
		animation: vef-pop 0.28s cubic-bezier(0.2, 0.9, 0.3, 1.3) both;
	}
	.vef-modal-step:not([hidden]) {
		animation: vef-step-in 0.2s ease both;
	}
}
@keyframes vef-spin {
	to { transform: rotate(360deg); }
}
@keyframes vef-pop {
	from { transform: scale(0.6); opacity: 0; }
	to { transform: scale(1); opacity: 1; }
}
@keyframes vef-step-in {
	from { opacity: 0; }
	to { opacity: 1; }
}
/* Each view takes focus when it appears so a screen reader reads it
   from the top. The view itself is not interactive, so it draws no ring. */
.vef-modal-step:focus {
	outline: none;
}
/* Findings / Build-a-shortlist toggle -- two DOM copies exist on the page
   (above the Cyber Continuum, and inside the Consultation CTA card
   further down); both stay in sync via the shared [data-vef-seg]
   attribute the JS selects on, not a shared id. */
.vef-split-pill {
	display: flex;
	align-items: stretch;
	justify-content: center;
	background: rgba(0, 0, 0, 0.06);
	border-radius: 9999px;
	padding: 6px;
	gap: 6px;
	max-width: 480px;
	margin: 0 auto 20px;
}
.vef-split-seg {
	-webkit-appearance: none;
	appearance: none;
	flex: 1;
	border: none;
	background: transparent;
	color: var(--black);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-weight: 700;
	font-size: 15px;
	border-radius: 9999px;
	padding: 14px 18px;
	line-height: 1.1;
	cursor: pointer;
	text-align: center;
	transition: background 0.15s ease, color 0.15s ease;
}
.vef-split-seg.vef-split-active {
	background: var(--black);
	color: var(--white);
}
/* A shortlist is built from the research tiers, so "Build a shortlist"
   carries the research blue dot, on both copies of the toggle. */
.vef-split-seg[data-vef-seg="shortlist"]::before {
	content: '';
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 9999px;
	background: var(--v79-blue-dot);
	margin-right: 8px;
	vertical-align: 0.1em;
}
/* The dot pulses slowly, a live status (Finn, 21 Oct 2026): it dims and
   brightens while a ring breathes out from it, as the site's in-progress
   marks do, only slower, at rest, on hover and when selected. */
@media (prefers-reduced-motion: no-preference) {
	.vef-split-seg[data-vef-seg="shortlist"]::before {
		animation: vef-seg-dot-pulse 2.8s ease-out infinite;
	}
}
@keyframes vef-seg-dot-pulse {
	0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--v79-blue-dot) 80%, transparent); opacity: 1; }
	45% { opacity: 0.55; }
	75%, 100% { box-shadow: 0 0 0 9px color-mix(in srgb, var(--v79-blue-dot) 0%, transparent); opacity: 1; }
}
/* Dark-mode variant, for the copy of this toggle sitting on a bkg-black
   section (the base rule's rgba(0,0,0,0.06) fill and black text are built
   for a light/bkg-grey ground and disappear on black). */
.vef-split-pill--dark {
	background: rgba(255, 255, 255, 0.12);
}
.vef-split-pill--dark .vef-split-seg {
	color: var(--white);
}
.vef-split-pill--dark .vef-split-seg.vef-split-active {
	background: var(--white);
	color: var(--black);
}
/* Sits inline in the Product Landscape intro column, left-aligned with the
   paragraphs above it, not centred like the base component's own margin. */
#vef-split-pill-top {
	margin: 30px 0 0; /* space-30 */
	max-width: 360px;
}
/* Consultation CTA's own copy of the toggle: moved above the heading and
   left-aligned to the card, same reasoning as #vef-split-pill-top above --
   the base .vef-split-pill's centred margin read as floating, disconnected
   from the card's own left-aligned heading/copy/button (Finn, 14 Sep 2026). */
.vef-split-cta .vef-split-pill {
	margin: 0 0 20px;
	max-width: 360px;
}

/* Shortlist bar content -- replaces the sticky-cta's usual subscribe form
   while a shortlist is active, same flex rhythm and pill dimensions as
   the rest of the sticky bar. */
.lab-frozen-article .vef-shortlist-content {
	display: none;
	padding: 6px 6px 6px 16px;
	align-items: center;
	gap: 6px;
	justify-content: flex-end;
}
/* Production's own @media (max-width: 992px) switches .sticky-cta to
   full-width/flush-left with no centering transform -- matching that exact
   breakpoint avoids fighting it; below 992px the bar just inherits
   width:100%/left:0, which is the right call anyway (more room for the
   pill row on tablet/mobile). */
@media (min-width: 993px) {
	.lab-frozen-article .sticky-cta.vef-shortlist-mode {
		max-width: 480px;
	}
}
.lab-frozen-article .sticky-cta.vef-shortlist-mode .sticky-cta-content {
	display: none;
}
.lab-frozen-article .sticky-cta.vef-shortlist-mode .vef-shortlist-content {
	display: flex;
}
.vef-sl-clear {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 22px;
	height: 22px;
	background: var(--black);
	border: none;
	border-radius: 9999px;
	color: var(--white);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 13px;
	font-weight: 700;
	line-height: 1;
	cursor: pointer;
	padding: 0;
	transition: opacity 0.12s ease;
}
.vef-sl-clear:hover {
	opacity: 0.65;
}
.vef-sl-names {
	flex: 1;
	min-width: 0;
	display: flex;
	align-items: center;
	gap: 6px;
	overflow-x: auto;
	scrollbar-width: none;
	-ms-overflow-style: none;
	cursor: grab;
}
.vef-sl-names::-webkit-scrollbar {
	display: none;
}
.vef-sl-names.vef-dragging {
	cursor: grabbing;
}
.vef-sl-pill {
	flex: 0 0 auto;
	background: var(--grey-10);
	color: var(--black);
	border-radius: 9999px;
	padding: 0 12px;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 13px;
	font-weight: 600;
	line-height: 28px;
	white-space: nowrap;
}
/* Removable shortlist pill. There is no removable-chip pattern in the
   Tekspace design system, so this is a small extension, not a settled
   component. Deliberately minimal: a bare x in the pill's own text colour,
   quieter at rest and full strength on hover, in a 20px box to sit with
   the 22px Clear (x) on the same bar. Clear stays as the fallback for
   emptying the shortlist in one go. */
.vef-sl-pill-removable {
	display: inline-flex;
	align-items: center;
	gap: 2px;
	padding: 0 4px 0 12px;
}
.vef-sl-pill-remove {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 20px;
	height: 20px;
	padding: 0;
	border: none;
	border-radius: 9999px;
	background: transparent;
	color: inherit;
	cursor: pointer;
	opacity: 0.45;
	transition: opacity 0.12s ease;
}
.vef-sl-pill-x {
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 15px;
	font-weight: 500;
	line-height: 1;
}
.vef-sl-pill-remove:hover,
.vef-sl-pill-remove:focus-visible {
	opacity: 1;
}
.vef-sl-pill-remove:focus-visible {
	outline: 2px solid var(--black);
	outline-offset: 0;
}
/* Limit reached: a one-second ring on each pill, pointing at the remove
   buttons. Inset, because .vef-sl-names scrolls and would clip an outer
   ring, and an inset shadow cannot shift layout. No animation at all under
   reduced motion; the limit message carries it alone. */
@media (prefers-reduced-motion: no-preference) {
	.vef-sl-names.vef-sl-pulse .vef-sl-pill {
		animation: vef-sl-pill-pulse 1s ease-out;
	}
}
@keyframes vef-sl-pill-pulse {
	0% { box-shadow: inset 0 0 0 0 transparent; }
	25% { box-shadow: inset 0 0 0 2px var(--black); }
	100% { box-shadow: inset 0 0 0 2px transparent; }
}
/* Screen-reader-only text, for the shortlist live regions. */
.vef-sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}
.vef-sl-empty {
	flex: 0 0 auto;
	color: var(--grey-50);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 600;
	white-space: nowrap;
}
.vef-sl-send {
	flex: 0 0 auto;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 700;
	line-height: 40px;
	padding: 0 18px;
	color: var(--white);
	background: var(--black);
	border: none;
	border-radius: 9999px;
	text-decoration: none;
	display: inline-block;
	transition: opacity 0.12s ease;
}
.vef-sl-send.vef-disabled {
	opacity: 0.4;
	pointer-events: none;
}

/* ---------- ONE-SCROLL TYPE SCALE (SAT preview, Finn, 6 Oct 2026) ----------
   One set of type steps for the whole article, so the Foreword, Threat
   Context, Outcomes, Landscape, Conclusion and Addendum read as one scroll
   instead of each module carrying its own sizes. Opt-in per article with
   .lab-type-scale on the wrapper; SAT first.

   Step        desktop   mobile   used for
   Display     170px     64px     section titles (h2), unchanged
   Heading     60px      40px     h3, h2.small, .section-quote, unchanged
   Intro       40px      30px     .section-intro
   Title       30px      24px     h4, chart titles
   Statement   22px      22px     stamps, the Threat Context summary, the
                                  Outcomes framing line: the size of the
                                  headings inside the infographics (chart
                                  row labels; Finn, 14 Oct 2026)
   Lead        20px      19px     the Landscape intro paragraph
   Body        17px      17px     all article prose
   Small       15px      15px     lists, notes, chart call-outs
   Micro       14px      14px     source notes, card labels, unchanged */
.lab-frozen-article.lab-type-scale section[id^="section-"] p:not([class]),
.lab-frozen-article.lab-type-scale .threat-prose-tight p,
.lab-frozen-article.lab-type-scale .threat-prose-2col > p:not(.section-quote):not(.section-intro) {
	font-size: 0.85em; /* Body 17px */
	line-height: 1.6em;
}
.lab-frozen-article.lab-type-scale .col-xl-10 > ul:not([class]) > li,
.lab-frozen-article.lab-type-scale .col-xl-10 > ol:not([class]) > li {
	font-size: 0.85em; /* Body 17px, as the prose around the list */
	line-height: 1.6em;
}
.lab-frozen-article.lab-type-scale .vef-intro-support {
	font-size: 1em; /* Lead 20px */
	font-weight: 500;
	line-height: 1.6em;
}
.lab-frozen-article.lab-type-scale .vef-reg-stamp,
.lab-frozen-article.lab-type-scale section[id^="section-"] .threat-summary p,
.lab-frozen-article.lab-type-scale .section-intro.vef-intro-compact {
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 1.1em; /* Statement 22px, as .chart-row-label h4 */
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.3;
}
.lab-frozen-article.lab-type-scale #section-addendum .small-ul,
.lab-frozen-article.lab-type-scale #section-addendum .small-ol,
.lab-frozen-article.lab-type-scale .vef-methodology-note {
	font-size: 0.75em; /* Small 15px */
	font-weight: 500;
	line-height: 1.6em;
}
.lab-frozen-article.lab-type-scale #section-addendum .small-ul li,
.lab-frozen-article.lab-type-scale #section-addendum .small-ol li {
	font-size: 1em;
	line-height: 1.6em;
}
/* One text column for every section: the wide column Threat Context, the
   videos and the lead-gen close use, with single-column prose and lists held
   to a reading measure of about 800px. */
.lab-frozen-article.lab-type-scale .col-xl-10:not(.threat-prose-2col) > p:not([class]) {
	max-width: 47em; /* ~800px at Body 17px */
}
.lab-frozen-article.lab-type-scale .col-xl-10 > p.vef-intro-support {
	max-width: 40em; /* ~800px at Lead 20px */
}
.lab-frozen-article.lab-type-scale #section-addendum .small-ul,
.lab-frozen-article.lab-type-scale #section-addendum .small-ol {
	max-width: 53em;
}
@media (max-width: 991.98px) {
	.lab-frozen-article.lab-type-scale .section-intro:not(.vef-intro-compact) {
		font-size: 1.5em; /* Intro 30px, under the 40px heading */
	}
	/* Chart row headings keep their 22px, the Statement size (Finn, 14 Oct
	   2026). */
	.lab-frozen-article.lab-type-scale h4:not(#section-addendum details h4, .chart-row-label h4) {
		font-size: 1.2em; /* Title 24px */
	}
	.lab-frozen-article.lab-type-scale .vef-intro-support {
		font-size: 0.95em; /* Lead 19px */
	}
}

/* ---------- LAB ARTICLE FOUNDATIONS (Finn, 16 Oct 2026) ----------
   _plan/lab-article-foundations.md. Infographics and Threat Context use five
   steps of the one-scroll scale above, nothing between:
     Heading 60 (display stats) . Title 30 (infographic titles, bar values)
     Statement 22 (row headings, stamps) . Body 17 . Micro 14 (eyebrows,
     source lines)
   Plus the pieces that hold them: a source line under every infographic,
   hairline lists in place of cards that hide text, pills for annotations,
   and pink (attack side) / green (defended) dots. */
.lab-frozen-article.lab-type-scale sup {
	font-size: 0.6em;
	line-height: 0;
}
/* Eyebrows inside infographics and above lists: Micro. */
.lab-frozen-article.lab-type-scale .chart-header .eyebrow,
.lab-frozen-article.lab-type-scale .col-xl-10 > .eyebrow,
.lab-frozen-article.lab-type-scale .reg-eyebrow,
.lab-frozen-article.lab-type-scale .ig-eyebrow {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 0 0 10px;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 800;
	letter-spacing: 0.06em;
	line-height: 1.3;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.7);
}
.lab-frozen-article.lab-type-scale .chart-title {
	font-size: 30px;
	line-height: 1.15;
}
/* Bars: every value at Title; the lead row is white, the rest grey. */
.lab-frozen-article.lab-type-scale .chart-row-val,
.lab-frozen-article.lab-type-scale .chart-row.is-hero .chart-row-val {
	font-size: 30px;
}
.lab-frozen-article.lab-type-scale .chart-row-label h4 {
	font-size: 22px;
}
.lab-frozen-article.lab-type-scale .chart-row-label p {
	font-size: 17px;
}
/* Stat trio: label, Heading value, Body line. */
.lab-frozen-article.lab-type-scale .reg-stat {
	font-size: 60px;
}
.lab-frozen-article.lab-type-scale .reg-copy {
	font-size: 17px;
	line-height: 1.6;
}
/* The source line: under every infographic, above a hairline, Micro. */
.lab-frozen-article.lab-type-scale .chart-source-note,
.lab-frozen-article.lab-type-scale .ig-source {
	max-width: none;
	margin: 30px 0 0;
	padding-top: 20px;
	border-top: 1px solid rgba(255, 255, 255, 0.15);
	font-size: 14px;
	font-weight: 500;
	line-height: 1.5;
	color: rgba(255, 255, 255, 0.6);
}
.lab-frozen-article.lab-type-scale .col-xl-10 > .ig-source {
	margin-top: 20px;
}
/* Dots: pink is the attack side, green is defended. */
.lab-frozen-article .ig-dot {
	flex: 0 0 auto;
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: #FF9AA7;
}
.lab-frozen-article .ig-dot--defended {
	background: #89CF9B;
}
/* Pill: a short annotation held in white on the dark panels. */
.lab-frozen-article .ig-pill {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 5px 12px;
	border-radius: 999px;
	background: var(--white);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 700;
	line-height: 1.3;
	letter-spacing: 0;
	text-transform: none;
	color: var(--black);
	white-space: nowrap;
	vertical-align: middle;
}
.lab-frozen-article .chart-row-label .ig-pill {
	margin-top: 10px;
}
/* Hairline list: what used to sit in cards behind a click, shown in full. */
.lab-frozen-article .ig-list {
	margin: 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid rgba(255, 255, 255, 0.15);
}
.lab-frozen-article .ig-item {
	display: grid;
	gap: 10px;
	padding: 30px 0;
	border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}
@media (min-width: 992px) {
	.lab-frozen-article .ig-item {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		gap: 50px;
	}
}
.lab-frozen-article .ig-item__head {
	display: flex;
	align-items: baseline;
	gap: 12px;
	margin: 0;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 22px;
	font-weight: 700;
	line-height: 1.25;
	letter-spacing: -0.01em;
}
.lab-frozen-article .ig-item__head .ig-dot {
	transform: translateY(-3px);
}
.lab-frozen-article.lab-type-scale .ig-item__body {
	margin: 0;
	font-size: 17px;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.85);
}
/* Security Outcomes' detail area (AR1): the points at Body, the name at
   Statement. */
.lab-frozen-article.lab-type-scale .lab-xgrid__name {
	font-size: 22px;
}
.lab-frozen-article.lab-type-scale .lab-xgrid__panel .vef-outcome-list li,
.lab-frozen-article.lab-type-scale .lab-xgrid__panel > p {
	font-size: 17px;
	line-height: 1.6;
}
@media (max-width: 767.98px) {
	.lab-frozen-article.lab-type-scale .reg-stat {
		font-size: 44px;
	}
	.lab-frozen-article.lab-type-scale .chart-title {
		font-size: 24px;
	}
	.lab-frozen-article.lab-type-scale .chart-row-val,
	.lab-frozen-article.lab-type-scale .chart-row.is-hero .chart-row-val {
		font-size: 24px;
	}
}
/* Callouts under a chart, not floating over it (SAT's adoption gap, 16 Oct:
   the floats collided with the plot's own marks). A row of eyebrow + Body
   line pairs; the numbers in white. */
.lab-frozen-article .ig-dot--neutral {
	background: rgba(255, 255, 255, 0.45);
}
.lab-frozen-article .ig-callouts {
	display: grid;
	gap: 20px 50px;
	margin-top: 30px;
}
@media (min-width: 768px) {
	.lab-frozen-article .ig-callouts {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
.lab-frozen-article.lab-type-scale .ig-callout p {
	margin: 0;
	font-size: 17px;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.75);
}
.lab-frozen-article .ig-callout strong {
	color: var(--white);
}
/* Glass pill (Finn, 16 Oct): white type on a clear holding shape over the
   dark panel, the dot carrying the meaning. The figure is white, the words
   around it grey, so the small type still draws the eye to the number. */
.lab-frozen-article .ig-pill--glass {
	background: rgba(255, 255, 255, 0.1);
	backdrop-filter: blur(10px) saturate(1.4);
	box-shadow:
		inset 0 0 0 1px rgba(255, 255, 255, 0.2),
		inset 0 1px 0 rgba(255, 255, 255, 0.25);
	font-weight: 600;
	color: rgba(255, 255, 255, 0.7);
}
.lab-frozen-article .ig-pill--glass strong {
	font-weight: 800;
	color: var(--white);
}
/* The outcome detail opens on a one-line summary of its points (Finn,
   16 Oct): Statement, bold, as Threat Context's row headings. The tile keeps
   the outcome's name. */
.lab-frozen-article.lab-type-scale .lab-xgrid__name {
	/* Held to about the measure of the points under it, so the heading
	   doesn't run wider than the body (Finn, 16 Oct). */
	max-width: 24em;
	margin-bottom: 10px;
	font-weight: 700;
	line-height: 1.25;
	letter-spacing: -0.01em;
	text-wrap: balance;
}
/* Browser's disclosure timeline on the scale (16 Oct): dates and axis caps
   at Micro, each vendor at Statement, the finding at Body. */
.lab-frozen-article.lab-type-scale .disclosure-timeline__axis-cap,
.lab-frozen-article.lab-type-scale .disclosure-timeline__date {
	font-size: 14px;
}
.lab-frozen-article.lab-type-scale .disclosure-timeline__vendor {
	font-size: 22px;
	line-height: 1.25;
}
.lab-frozen-article.lab-type-scale .disclosure-timeline__body {
	font-size: 17px;
	line-height: 1.5;
}
/* The outcome detail as a hairline list (Finn, 16 Oct): the summary heading
   in its own column, the points beside it as ruled rows rather than
   bullets, the same shape as Threat Context's lists. Two columns from
   992px (the heading about a third); stacked below, heading first. */
.lab-frozen-article.lab-type-scale .lab-xgrid__panel .vef-outcome-list {
	margin: 0;
	padding: 0;
	list-style: none;
}
.lab-frozen-article.lab-type-scale .lab-xgrid__panel .vef-outcome-list li {
	margin: 0;
	padding: 12px 0;
	border-top: 1px solid rgba(20, 24, 28, 0.1);
}
.lab-frozen-article.lab-type-scale .lab-xgrid__panel .vef-outcome-list li:last-child {
	padding-bottom: 0;
}
.lab-frozen-article.lab-type-scale .lab-xgrid__name {
	margin-bottom: 20px;
}
@media (min-width: 992px) {
	.lab-frozen-article.lab-type-scale .lab-xgrid__panel {
		grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
		column-gap: 50px;
		align-items: start;
	}
	.lab-frozen-article.lab-type-scale .lab-xgrid__panel.is-open,
	.lab-frozen-article.lab-type-scale .lab-xgrid__panel {
		display: grid;
	}
	.lab-frozen-article.lab-type-scale .lab-xgrid__name {
		max-width: none;
		margin-bottom: 0;
	}
	/* The first row starts level with the heading, no rule above it. */
	.lab-frozen-article.lab-type-scale .lab-xgrid__panel .vef-outcome-list li:first-child {
		padding-top: 0;
		border-top: 0;
	}
}

/* ---------- ARTICLE LIST PATTERNS + DEFINITION (Finn, 21 Oct 2026) ----------
   VM staging edits 1, 2, 9 and 10; for every article to reuse. No rules or
   boxes between items: spacing only.
   .lab-steps  numbered list: the design system's outcome list (a black
               number badge, bold text beside it on one line), sized to
               the .lab-terms labels so the two read as one system.
   .lab-terms  labelled list (<dl>): a bold label, its description under
               it, one column at every width.
   .lab-definition  the hero's definition: the quietest text in the hero,
               at the section cards' description size and grey, with a
               bold "Definition:" label. */
.lab-frozen-article .lab-steps {
	--lab-step-gap: 14px; /* the outcome list's badge-to-text pairing */
	display: flex;
	flex-direction: column;
	gap: var(--lab-step-gap);
	margin: 30px 0;
	padding: 0;
	list-style: none;
	counter-reset: lab-step;
}
.lab-frozen-article .lab-steps > li {
	display: flex;
	align-items: center;
	gap: var(--lab-step-gap);
	margin: 0;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 17px;
	font-weight: 700;
	line-height: 1.4;
	counter-increment: lab-step;
	break-inside: avoid;
}
.lab-frozen-article .lab-steps > li::before {
	content: counter(lab-step);
	flex: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	border-radius: 9999px;
	background: var(--black);
	color: var(--white);
	font-size: 14px;
	font-weight: 700;
	line-height: 1;
	font-variant-numeric: tabular-nums;
}
/* --plain: the same list for full sentences (VO foreword and conclusion),
   in body weight, the badge level with the first line. */
.lab-frozen-article .lab-steps--plain > li {
	align-items: flex-start;
	font-family: inherit;
	font-weight: 500;
	line-height: 1.6;
}
.lab-frozen-article .lab-steps--plain > li::before {
	margin-top: 1px;
}
.lab-frozen-article .lab-terms {
	display: flex;
	flex-direction: column;
	gap: 20px;
	margin: 30px 0;
}
.lab-frozen-article .lab-terms > div {
	break-inside: avoid;
}
.lab-frozen-article .lab-terms dt {
	margin: 0 0 4px;
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 17px;
	font-weight: 700;
	line-height: 1.4;
}
.lab-frozen-article .lab-terms dd {
	margin: 0;
	font-size: 17px;
	line-height: 1.6;
}
.lab-frozen-article :is(.lab-steps, .lab-terms) + h3 {
	margin-top: 50px;
}
.lab-frozen-article .lab-definition {
	max-width: 47em;
	margin: 30px 0 0;
	color: var(--grey-50);
	font-size: 17px;
	font-weight: 500;
	line-height: 1.6;
}
.lab-frozen-article .lab-definition strong {
	font-weight: 700;
}

/* ---------- ONE STYLE PER INFOGRAPHIC TYPE (Finn, 21 Oct 2026) ----------
   Every article's Threat Context uses the same pieces at the same sizes:
   a panel opens on an eyebrow and a title; a stat card is a dot eyebrow,
   the figure and its copy, under a hairline; a lone stat after a chart
   sits on its own hairline, clear of the rows above; sources sit in one
   note at the foot of the panel; a worked example sits in an "In practice"
   panel; there are no callout stamps. */
.lab-frozen-article .chart-rows + .reg-precedent,
.lab-frozen-article .reg-grid + .reg-precedent {
	margin-top: 40px;
}
.lab-frozen-article .reg-precedent-stat .reg-stat {
	font-size: 3em; /* the stat cards' figure */
}
.lab-frozen-article .chart-source-note a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 2px;
}
/* SVG chart labels match the HTML charts' axis labels (VM's day scale) on
   screen: core.js sets --svg-k to the viewBox-to-pixel ratio, so a label
   draws at 14px however wide the chart renders. */
.lab-frozen-article .chart-label {
	fill: rgba(255, 255, 255, 0.85);
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: calc(14px * var(--svg-k, 1));
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}
.lab-frozen-article .chart-annotation-text {
	font-size: calc(14px * var(--svg-k, 1));
}
/* Legends read as the chart micro labels (VM's "To exploit"). */
.lab-frozen-article .chart-legend-item {
	font-family: 'Inter Tight', 'Arial', sans-serif;
	font-size: 14px;
	font-weight: 800;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}
/* "In practice": the case, in Body on the dark panel (from VO). */
.lab-frozen-article :is(.lab-practice, .vo-practice) p {
	max-width: 47em;
	font-size: 17px;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.85);
}
.lab-frozen-article :is(.lab-practice, .vo-practice) p:last-child {
	margin-bottom: 0;
}

/* Labelled lists run on one line: "Library: the answer" (Finn, 21 Oct). */
.lab-frozen-article .lab-terms > div {
	font-size: 17px;
	line-height: 1.6;
}
.lab-frozen-article .lab-terms dt,
.lab-frozen-article .lab-terms dd {
	display: inline;
	margin: 0;
	font-size: inherit;
	line-height: inherit;
}
.lab-frozen-article .lab-terms dd::before {
	content: ' ';
}

/* Capability gaps: a callout after Category Findings, before the Addendum,
   for a reader who is assessing the market now (Finn, 21 Oct 2026). */
.lab-frozen-article .lab-gaps {
	margin-top: 50px;
}
.lab-frozen-article .lab-gaps .lab-terms {
	margin-bottom: 0;
}

/* Section headings sit on a shorter measure than the column, balanced over
   their lines, so each reads as a tidy left-aligned block (Finn, 21 Oct). */
.lab-frozen-article :is(#section-foreword, #section-threat, #section-conclusion) .col-xl-10 > h3 {
	max-width: 12em;
	text-wrap: balance;
}
/* Panel eyebrows are Micro on every panel, "In practice" included. */
.lab-frozen-article :is(.lab-practice, .vo-practice) > .eyebrow {
	font-size: 14px;
	font-weight: 800;
	letter-spacing: 0.06em;
}
/* Timeline copy is Body, like every other line of infographic prose. */
.lab-frozen-article.lab-type-scale .disclosure-timeline__body {
	font-weight: 500;
	line-height: 1.6;
}
/* A heading that follows copy in the same column gets the 50px step above
   it, as the Foreword already does, so each heading opens its own block. */
.lab-frozen-article :is(#section-foreword, #section-threat, #section-conclusion) .col-xl-10 > :is(p, ol, ul, dl, div) + h3 {
	margin-top: 50px;
}

/* Lists and the closing line keep the paragraphs' measure (47em at 17px), so
   every body block in a section ends on the same line (Finn, 21 Oct). */
.lab-frozen-article :is(#section-foreword, #section-threat, #section-conclusion) .col-xl-10 > :is(ol, ul, dl) {
	max-width: 47em;
	font-size: 17px;
}
.lab-frozen-article.lab-type-scale section#section-threat .col-xl-10.threat-summary > p:not([class]) {
	max-width: 799px;
}
/* Links in Threat Context prose read white on the black section. */
.lab-frozen-article #section-threat .col-xl-10 > p a {
	color: var(--white);
	text-decoration: underline;
	text-underline-offset: 3px;
}
/* A lone precedent stat sits in its own darker holding shape inside the
   panel, so it reads apart from the bars or cards above it (Finn, 21 Oct). */
.lab-frozen-article .panel .reg-precedent {
	padding: 30px;
	border-top: 0;
	border-radius: 20px;
	background: var(--black);
}
.lab-frozen-article .panel .reg-precedent + .reg-precedent {
	margin-top: 10px;
}
@media (max-width: 767.98px) {
	.lab-frozen-article .panel .reg-precedent {
		padding: 24px;
	}
}

/* ---------- REPORT BASELINE (Finn, 22 Oct 2026) ----------
   One left edge and two right edges, so an article reads as one report:
   words (paragraphs, lists, intros, quotes, subheadings, notes) end at the
   799px measure; boxes (panels, cards, the CTA, the gaps aside) and display
   type end on the 8-column line. Subheadings inside a section drop to the
   Title size (30px) and every two-tone sentence shares one size (40px), so
   the only display type left is the section heading. */
.lab-frozen-article.lab-type-scale :is(.section-intro, .section-quote, .vef-methodology-note, .video-credits) {
	max-width: 799px;
}
.lab-frozen-article.lab-type-scale .section-quote {
	font-size: 2em; /* 40px, the two-tone sentence size */
}
.lab-frozen-article.lab-type-scale #section-threat .col-xl-10 > p.section-quote {
	max-width: 799px; /* the Threat prose measure is set in em, too wide at 40px */
}
.lab-frozen-article.lab-type-scale :is(#section-foreword, #section-threat, #section-conclusion) .col-xl-10 > h3 {
	max-width: 799px;
	margin-bottom: 20px;
	font-size: 30px;
	line-height: 1.15;
	letter-spacing: -0.03em;
}
.lab-frozen-article.lab-type-scale :is(.vef-split-cta, .lab-gaps) h3 {
	font-size: 2em; /* 40px */
}
.lab-frozen-article.lab-type-scale #section-addendum h3 {
	max-width: 799px;
	font-size: 30px;
	letter-spacing: -0.03em;
}
.lab-frozen-article.lab-type-scale #section-addendum h4:not(details h4) {
	font-size: 22px;
}
/* The Addendum runs full width, so its column would sit left of the inset
   sections above; give its container the same 30px inset they have. */
@media (min-width: 577px) {
	.lab-frozen-article #section-addendum > .section-outer > .container {
		width: auto;
		max-width: none;
		margin-left: 30px;
		margin-right: 30px;
	}
}
@media (max-width: 991.98px) {
	.lab-frozen-article.lab-type-scale :is(.section-quote, .vef-split-cta h3, .lab-gaps h3) {
		font-size: 1.5em; /* 30px, with the intros */
	}
	.lab-frozen-article.lab-type-scale :is(#section-foreword, #section-threat, #section-conclusion) .col-xl-10 > h3,
	.lab-frozen-article.lab-type-scale #section-addendum h3 {
		font-size: 24px;
	}
	.lab-frozen-article.lab-type-scale #section-addendum h4:not(details h4) {
		font-size: 20px;
	}
}
/* 16px side gutter on phones. */
@media (max-width: 576px) {
	.lab-frozen-article .section-outer > .container {
		padding-left: 16px;
		padding-right: 16px;
	}
}
/* Figure numbers in each infographic's eyebrow, in the section's text colour
   so they read ahead of the grey label. */
.lab-frozen-article.lab-type-scale .eyebrow:has(.lab-fig-no) {
	display: block;
}
.lab-frozen-article .lab-fig-no {
	margin-right: 10px;
	white-space: nowrap;
	color: var(--black);
}
.lab-frozen-article .lab-fig-no::after {
	content: "\00B7";
	margin-left: 10px;
	color: var(--grey-25);
}
.lab-frozen-article #section-threat .lab-fig-no {
	color: var(--white);
}

/* Continuum field (Finn, 22 Oct 2026): the lattice fades into the black at
   its top and bottom, and in two columns at its right edge too, where it meets
   the tier lists, so the diamonds never stop on a hard line. The vendor logos
   sit outside the drawing, so they stay at full strength. The field keeps
   full strength around the vendors and eases back where nothing needs focus
   (core.js FOCUS; Finn, 9 Nov 2026). */
.lab-frozen-article .vef-field-svg {
	-webkit-mask-image: linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 160px), transparent);
	mask-image: linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 160px), transparent);
}
@media (min-width: 992px) {
	.lab-frozen-article .vef-field-svg {
		-webkit-mask-image:
			linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 160px), transparent),
			linear-gradient(to right, #000 calc(100% - 160px), transparent);
		-webkit-mask-composite: source-in;
		mask-image:
			linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 160px), transparent),
			linear-gradient(to right, #000 calc(100% - 160px), transparent);
		mask-composite: intersect;
	}
}

/* ---------- THREAT CONTEXT CREDENTIALS (Frank, 9 Nov 2026) ----------
   The Parabellum logo sits inline at the intro's cap height, and the CREST
   and OffSec badges shrink to one 48px row (from 80) tucked under it, so the
   chapter reaches its first finding about 250px sooner. */
.lab-frozen-article #section-threat .section-intro img {
	height: 0.72em;
	width: auto;
	margin: 0 0 0 0.12em;
	vertical-align: baseline;
}
.lab-frozen-article #section-threat .row:has(+ .row .cert-badge) {
	padding-bottom: 20px;
}
.lab-frozen-article #section-threat .row:has(.cert-badge) {
	padding-bottom: 40px;
}
.lab-frozen-article #section-threat .cert-badge {
	display: inline-block;
	height: 48px;
	width: auto;
	margin: 0 6px 6px 0;
}
.lab-frozen-article #section-threat .cert-badge:first-child {
	margin-right: 16px;
}
@media (max-width: 575.98px) {
	/* One row of the eight OffSec badges on a phone, under CREST. */
	.lab-frozen-article #section-threat .cert-badge {
		height: 36px;
		margin-right: 4px;
	}
}

/* ---------- FINE PRINT BELOW THE CLOSE (Frank, 9 Nov 2026) ----------
   Further questions, Disclaimers and References leave the Addendum and sit
   under the page-end subscribe ask, inside the dark footer: the close's own
   7 + 4 column split, a rule above, 14px type, quiet labels. The block keeps
   the article's classes so the accordions and lists style as they do in it. */
.lab-frozen-article.lab-fineprint {
	background: transparent;
	margin-top: 100px;
	padding-top: 100px;
	border-top: 1px solid var(--rule-on-dark, rgba(255, 255, 255, 0.15));
	color: var(--grey-25);
	font-size: 14px;
	line-height: 1.6;
}
.lab-frozen-article.lab-fineprint .lab-fineprint__label {
	margin: 0 0 20px;
	font-size: 14px;
	line-height: 1.4;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--white);
}
.lab-frozen-article.lab-fineprint p,
.lab-frozen-article.lab-fineprint li {
	font-size: 14px;
	line-height: 1.6;
	color: var(--grey-25);
}
.lab-frozen-article.lab-fineprint a {
	color: var(--white);
}
.lab-frozen-article.lab-fineprint .vef-outcome-toggle summary h4 {
	font-size: 17px;
	color: var(--white);
}
.lab-frozen-article.lab-fineprint .lab-fineprint__disclaimers,
.lab-frozen-article.lab-fineprint .lab-fineprint__refs {
	margin-top: 50px;
}
@media (min-width: 992px) {
	.lab-frozen-article.lab-fineprint .lab-fineprint__disclaimers {
		margin-top: 0;
	}
	.lab-frozen-article.lab-fineprint .lab-fineprint__refs .small-ol {
		columns: 2;
		column-gap: 60px;
	}
	.lab-frozen-article.lab-fineprint .lab-fineprint__refs li {
		break-inside: avoid;
	}
}

/* Parabellum photo (Frank, 9 Nov 2026): it frames the chapter opening rather
   than running the length of the chapter. On a wide screen it sits beside the
   title at no more than 58% of the panel, fading into the black under the
   credentials. Below 1200px it no longer pushes the title down 400-500px:
   it shows as a 260px band above the title instead. */
/* A black-to-clear wash over the photo's left edge hides where it starts. */
.lab-frozen-article #section-threat .section-outer {
	background:
		linear-gradient(to right, var(--black) 0, rgba(0, 0, 0, 0) 40%) right top / min(58%, 900px) 100% no-repeat,
		url('/research/lab-images/bkg-parabellum.png') right top / min(58%, 900px) auto no-repeat,
		var(--black);
}
@media (max-width: 1200px) {
	.lab-frozen-article #section-threat .section-outer {
		padding-top: 260px;
		background:
			url('/research/lab-images/bkg-parabellum.png') right top / min(115%, 720px) auto no-repeat,
			var(--black);
	}
}

/* ---------- THREAT CONTEXT DENSITY (Frank, 9 Nov 2026) ----------
   Figures keep their design but lose some air: 40px panel padding (was 50),
   30px under chart titles (was 50), tighter bar rows and hairline rows. */
@media (min-width: 992px) {
	.lab-frozen-article #section-threat .panel {
		padding: 40px;
	}
}
.lab-frozen-article #section-threat .chart-title.pad-b-50 {
	padding-bottom: 30px;
}
.lab-frozen-article #section-threat .chart-row {
	padding-bottom: 18px;
}
.lab-frozen-article #section-threat .chart-source-note {
	margin-top: 20px;
}
.lab-frozen-article #section-threat .reg-precedent {
	margin-top: 30px;
}
.lab-frozen-article #section-threat .ig-item {
	padding: 20px 0;
}

/* Hairline rows that open for the detail (Frank, 9 Nov 2026): the name and
   a plus on the row, the paragraph underneath once opened. */
.lab-frozen-article .ig-item.ig-item--more {
	display: block;
}
.lab-frozen-article .ig-item--more summary {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 20px;
	cursor: pointer;
	list-style: none;
}
.lab-frozen-article .ig-item--more summary::-webkit-details-marker {
	display: none;
}
.lab-frozen-article .ig-item__icon {
	position: relative;
	flex: 0 0 14px;
	width: 14px;
	height: 14px;
	align-self: center;
}
.lab-frozen-article .ig-item__icon::before,
.lab-frozen-article .ig-item__icon::after {
	content: "";
	position: absolute;
	left: 0;
	top: 6px;
	width: 14px;
	height: 2px;
	background: currentColor;
	transition: transform 0.2s ease;
}
.lab-frozen-article .ig-item__icon::after {
	transform: rotate(90deg);
}
.lab-frozen-article .ig-item--more details[open] .ig-item__icon::after {
	transform: rotate(0deg);
}
.lab-frozen-article .ig-item--more summary:focus-visible {
	outline: 2px solid var(--white);
	outline-offset: 4px;
}
.lab-frozen-article .ig-item--more .ig-item__body {
	margin-top: 12px;
	max-width: 760px;
}
.lab-frozen-article .ig-item--more details:not([open]) .ig-item__body {
	display: none;
}
@media (prefers-reduced-motion: reduce) {
	.lab-frozen-article .ig-item__icon::before,
	.lab-frozen-article .ig-item__icon::after {
		transition: none;
	}
}

/* The fine print's questions keep the gap they had in the Addendum. */
.lab-frozen-article.lab-fineprint .vef-outcome-toggle {
	margin-bottom: 14px;
}

/* Precedents and "In practice" accounts that open for the detail (Frank,
   9 Nov 2026): the figure, label and a plus on the closed row. */
.lab-frozen-article details.reg-precedent--more,
.lab-frozen-article details.lab-practice--more {
	display: block;
}
.lab-frozen-article .reg-precedent--more summary,
.lab-frozen-article .lab-practice--more summary {
	display: flex;
	align-items: center;
	gap: 30px;
	cursor: pointer;
	list-style: none;
}
.lab-frozen-article .reg-precedent--more summary::-webkit-details-marker,
.lab-frozen-article .lab-practice--more summary::-webkit-details-marker {
	display: none;
}
.lab-frozen-article .reg-precedent--more summary .reg-eyebrow {
	flex: 1;
	margin: 0;
}
.lab-frozen-article .reg-precedent--more summary .ig-item__icon,
.lab-frozen-article .lab-practice--more summary .ig-item__icon {
	margin-left: auto;
	color: var(--white);
}
.lab-frozen-article .reg-precedent--more[open] .ig-item__icon::after,
.lab-frozen-article .lab-practice--more[open] .ig-item__icon::after {
	transform: rotate(0deg);
}
.lab-frozen-article .reg-precedent--more > .reg-copy {
	margin: 16px 0 0;
}
@media (min-width: 992px) {
	/* The case text lines up under its label, past the 120px figure. */
	.lab-frozen-article .reg-precedent--more > .reg-copy {
		padding-left: 150px;
	}
}
.lab-frozen-article .lab-practice--more summary {
	gap: 16px;
}
.lab-frozen-article .lab-practice--more .eyebrow {
	margin: 0;
}
.lab-frozen-article .lab-practice__title {
	flex: 1;
	font-weight: 700;
	color: var(--white);
}
.lab-frozen-article .lab-practice--more > p {
	margin: 16px 0 0;
}
.lab-frozen-article .reg-precedent--more summary:focus-visible,
.lab-frozen-article .lab-practice--more summary:focus-visible {
	outline: 2px solid var(--white);
	outline-offset: 4px;
}
.lab-frozen-article .reg-precedent--more:not([open]) > .reg-copy,
.lab-frozen-article .lab-practice--more:not([open]) > p {
	display: none;
}
@media (max-width: 991.98px) {
	.lab-frozen-article .reg-precedent--more summary {
		flex-wrap: wrap;
		gap: 8px 16px;
	}
	.lab-frozen-article .reg-precedent--more summary .reg-precedent-stat {
		flex-basis: 100%;
	}
	.lab-frozen-article .reg-precedent--more summary .ig-item__icon {
		margin-left: 0;
	}
}


/* Brighter glass (Finn, 9 Nov 2026): each vendor diamond is a lit glass
   tile, a dark hairline gap keeping it apart from the white cells around
   it, a soft glow and a stronger highlight on its upper edges. */
.lab-frozen-article .prod-icon .liquidGlass-tint {
	background: rgba(255, 255, 255, 0.32);
}
.lab-frozen-article .prod-icon .liquidGlass-content {
	background: transparent;
}
.lab-frozen-article .liquidGlass-wrapper.prod-icon {
	box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.55), 0 0 32px rgba(255, 255, 255, 0.3), 0 10px 28px rgba(0, 0, 0, 0.7);
}
.lab-frozen-article .prod-icon .liquidGlass-shine {
	box-shadow: inset 2px 2px 3px 0 rgba(255, 255, 255, 0.95), inset -1px -1px 2px 0 rgba(255, 255, 255, 0.35);
}

/* ---------- THREAT CONTEXT RHYTHM (Finn, 9 Nov 2026, pre-release) ----------
   One spacing rule for the chapter: 50px between blocks (the row padding),
   so no block adds its own trailing margin on top; 20px from a heading to
   its text; the opening quote sits 30px above the prose like a heading. */
.lab-frozen-article #section-threat .container > .row > [class*="col-"] > :last-child {
	margin-bottom: 0;
}
.lab-frozen-article #section-threat .container > .row:has(> [class*="col-"] > .section-quote:only-child) {
	padding-bottom: 30px;
}

/* Smaller figures: bar rows at Statement/Body/Micro (22/17/14 were
   Title/Statement/Body), tighter rows; stat cards' copy at Micro. */
.lab-frozen-article.lab-type-scale #section-threat .chart-row {
	padding: 14px 0;
	gap: 8px 32px;
}
.lab-frozen-article.lab-type-scale #section-threat .chart-row:first-child {
	padding-top: 0;
}
.lab-frozen-article.lab-type-scale #section-threat .chart-row-label h4 {
	font-size: 17px;
	margin-bottom: 4px;
}
.lab-frozen-article.lab-type-scale #section-threat .chart-row-label p {
	font-size: 14px;
}
.lab-frozen-article.lab-type-scale #section-threat .chart-row-val,
.lab-frozen-article.lab-type-scale #section-threat .chart-row.is-hero .chart-row-val {
	font-size: 22px;
}
.lab-frozen-article.lab-type-scale #section-threat .reg-copy {
	font-size: 14px;
}

/* A figure that opens for its detail (Finn, 9 Nov 2026): the figure's
   title shows, with a row underneath to open the graphic itself. */
.lab-frozen-article .lab-fig-more > summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	padding: 16px 0 0;
	border-top: 1px solid rgba(255, 255, 255, 0.15);
	cursor: pointer;
	list-style: none;
	font-size: 17px;
	font-weight: 600;
	color: var(--white);
}
.lab-frozen-article .lab-fig-more > summary::-webkit-details-marker {
	display: none;
}
.lab-frozen-article .lab-fig-more[open] > summary {
	margin-bottom: 30px;
}
.lab-frozen-article .lab-fig-more[open] > summary .ig-item__icon::after {
	transform: rotate(0deg);
}
.lab-frozen-article .lab-fig-more > summary:focus-visible {
	outline: 2px solid var(--white);
	outline-offset: 4px;
}

/* Disclosure timeline, compact: on a screen that can hover, each step shows
   its date and name on the line, and its detail as a card on hover or
   keyboard focus. Touch screens keep every caption in full. */
@media (hover: hover) and (min-width: 769px) {
	.lab-frozen-article .lab-fig-more .disclosure-timeline {
		min-height: 260px;
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__caption {
		cursor: default;
		border-radius: 10px;
		outline: none;
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__body {
		position: absolute;
		left: 50%;
		width: 260px;
		margin: 0;
		padding: 14px 16px;
		transform: translateX(-50%);
		background: var(--grey-75);
		border-radius: 12px;
		box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);
		color: var(--white);
		text-align: left;
		/* Opacity, not visibility, so screen readers still read every step. */
		opacity: 0;
		pointer-events: none;
		transition: opacity 0.15s ease;
		z-index: 5;
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__event--above .disclosure-timeline__body {
		bottom: calc(100% + 10px);
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__event--below .disclosure-timeline__body {
		top: calc(100% + 10px);
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__event[style*="--at: 0%"] .disclosure-timeline__body {
		left: 0;
		transform: none;
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__event[style*="--at: 100%"] .disclosure-timeline__body {
		left: auto;
		right: 0;
		transform: none;
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__caption:is(:hover, :focus-visible) .disclosure-timeline__body {
		opacity: 1;
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__caption:is(:hover, :focus-visible) .disclosure-timeline__vendor {
		text-decoration: underline;
		text-underline-offset: 4px;
	}
	.lab-frozen-article .lab-fig-more .disclosure-timeline__event:has(.disclosure-timeline__caption:is(:hover, :focus-visible)) {
		z-index: 4;
	}
	.lab-frozen-article .lab-fig-more .lab-fig-more__hint {
		display: block;
	}
}
.lab-frozen-article .lab-fig-more__hint {
	display: none;
	margin: 12px 0 0;
	font-size: 14px;
	color: var(--grey-25);
}
@media (prefers-reduced-motion: reduce) {
	.lab-frozen-article .lab-fig-more .disclosure-timeline__body {
		transition: none;
	}
}

