/* ==========================================================================
   HDL Commerce V3 — content modules
   Every marketing section between the header and the footer.

   Source lines
     styles.css      218-237  cards            (live; sole definition)
                     383-397  logos, marquee, grids
                     374-378  stats
                     410-413  page hero, breadcrumbs
                     418-423  check list
                     427-429  (reveal -> base.css)
                     540-545  legacy forest hero  (still live on 19 pages)
                     718-754  status page
                     686-715  document blocks
                     1489-1491 the glow kill switch
                     1499-1505 hero dotted field  (+ 1633 override)
                     1772-1798 contact pill / contact band
                     1801-1817 V8 surfaces, cards, ticks, controls
                     1819-1842 lava + grain
     base-2026.css   78-347   the whole 2026 module set
                     355-389  animated line illustrations
                     398-427  hero-2026 + rays
                     429-435  mobile hardening
   ========================================================================== */

/* --------------------------------------------------------------------------
   Image slots — the `has-img` contract

   Seven blocks emit `has-img` on an image slot when a real image is present
   (blog, card_grid, case_grid, report_gate, scroll_story, logo_marquee), and
   until now NONE of them had a matching rule. The `<img>` therefore sized
   itself, overrode the slot's own aspect-ratio and stretched — visible on
   every blog card the moment featured images existed.

   Hard rule 12 asks each slot to define its has-img behaviour beside its
   decorative fallback. The slot owns the aspect-ratio (16/10 on `.post
   .cover`, 16/11 on `.feature-post .cover`, and so on, each set in its own
   section below); this block only makes the image obey it, and switches off
   the decorative placeholder the slot draws when empty.

   Deliberately global rather than repeated per block: the contract is the
   same everywhere, and a per-block copy is how the rule got missed in the
   first place.
   -------------------------------------------------------------------------- */

.has-img:not( .logo-word ) > img,
.has-img:not( .logo-word ) > picture,
.has-img:not( .logo-word ) > picture > img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * `.logo-word` is excluded on purpose. It is an inline text span with no
 * dimensions of its own, so height:100% would collapse it, and a customer
 * logo must never be cropped the way a cover image can be. No logo files
 * exist yet (owner gate B3), so its rule belongs with the assets, not here.
 */

/*
 * The placeholder each empty slot draws — an outlined glyph, a gradient
 * wash — must not sit on top of a real image.
 */
.has-img > svg,
.has-img::before,
.has-img::after {
	display: none;
}

/* --------------------------------------------------------------------------
   Per-instance hooks
   The handoff carried these as inline `style` attributes. Hard rule 2 bans
   inline style, so they are custom-property hooks the block layer sets.
   Fallbacks are the design's own default — never zero.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   Cards and grids
   `.card` is the sole definition and it comes from the early styles.css layer;
   the V8 tail only flattens it. Measured: transparent fill, 1px hairline,
   radius 0, 28px padding, no shadow.
   -------------------------------------------------------------------------- */
.card,
.card-dark,
.glass-quote,
.plan,
.compare,
.ctable,
.form-card,
.code-block,
.code-snip,
.app,
.preview,
.lead-box.chat {
	border-radius: 0 !important;
}

.card,
.card-dark,
.glass-quote,
.plan {
	background: transparent !important;
	border: 1px solid var( --line ) !important;
}

.card {
	padding: 28px;
	box-shadow: none;
	transition: transform 0.25s cubic-bezier( 0.2, 0.7, 0.3, 1 ), box-shadow 0.25s, border-color 0.25s;
}

.card-feature {
	padding: 32px;
}

.card-pad-lg {
	padding: 40px;
}

.card-hover:hover,
.card-dark:hover {
	background: rgba( 255, 255, 255, 0.03 ) !important;
	border-color: rgba( 255, 255, 255, 0.2 ) !important;
	transform: none;
	box-shadow: none;
}

.card .ic {
	width: 44px;
	height: 44px;
	display: grid;
	place-items: center;
	margin-bottom: 20px;
}

.card .ic svg {
	width: 22px;
	height: 22px;
}

.card .ic,
.ic-outline,
.dd-link .dd-ic,
.check-list .ck {
	border-radius: 2px;
	border: 1px solid rgba( 255, 255, 255, 0.18 );
	background: transparent;
	color: var( --wp--preset--color--contrast );
}

.card h3 {
	font-size: 1.18rem;
}

.card p {
	color: var( --slate );
	margin-top: 10px;
	font-size: 0.97rem;
}

/* The base grid family really is 20px / 16px floating cards — styles.css
   393-397, measured 20px on b2c.html. The 2px hairline seam the README
   describes belongs to the bespoke per-page variants and to .steps3 /
   .cs-built, not here. See css-port-notes.md. */
.grid-2 {
	display: grid;
	grid-template-columns: repeat( 2, 1fr );
	gap: 20px;
}

.grid-3 {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 20px;
}

.grid-4 {
	display: grid;
	grid-template-columns: repeat( 4, 1fr );
	gap: 16px;
}

@media ( max-width: 920px ) {
	.grid-3,
	.grid-4 {
		grid-template-columns: repeat( 2, 1fr );
	}
}

@media ( max-width: 600px ) {
	.grid-2,
	.grid-3,
	.grid-4 {
		grid-template-columns: 1fr;
	}
}

/* --------------------------------------------------------------------------
   Button rows
   ADDITION — not extracted from the design. The handoff put these in unclassed
   <div>s carrying inline style. The block layer emits class="btn-row" instead.
   -------------------------------------------------------------------------- */
.btn-row {
	display: flex;
	gap: 12px;
	flex-wrap: wrap;
	margin-top: 30px;
}

/*
 * Centred heroes need the CTA row centred too. `.center` is only
 * `text-align: center` (base.css 364), which cannot move flex items — so on a
 * centred hero the heading, eyebrow and lead centred while the buttons stayed
 * hard left. The design never hit this: its one centred hero, priser.html:59,
 * has no buttons at all, so the combination was never specified. Scoped to
 * .page-hero.center so left-aligned heroes and every other .btn-row on the
 * site are untouched.
 */
.page-hero.center .btn-row {
	justify-content: center;
}

/*
 * Two blocks deliberately do NOT emit .btn-row, because the design addresses
 * their button wrapper by position rather than by class: cta_band's docblock
 * ("the stylesheet addresses them as `.cta-band>div>div`") and statement's
 * ("the stylesheet must own `.stmt-dark + div`"). Both say no class is
 * invented here — correct — but the rule the stylesheet was supposed to own
 * was never written, so the wrappers stayed plain block boxes and their
 * buttons sat flush against each other on every page that uses them.
 *
 * In the handoff the layout lives in an inline style on the wrapper, e.g.
 * solaris.html and byta-e-handelsplattform.html both carry
 * `style="display:flex;gap:12px;margin-top:28px;flex-wrap:wrap"`. That is
 * reproduced here verbatim, including the 28px the design uses in these two
 * places (.btn-row's own 30px is a different measure and stays).
 *
 * base-2026.css:180 already centres .cta-band>div>div; it assumed the flex
 * context that this rule now supplies.
 */
.cta-band > div > div,
.stmt-dark + div {
	display: flex;
	gap: 12px;
	flex-wrap: wrap;
	margin-top: 28px;
}

/* --------------------------------------------------------------------------
   Check list — styles.css 418-421, icon chrome from the V7 tail
   -------------------------------------------------------------------------- */
.check-list {
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.check-list li {
	display: flex;
	gap: 11px;
	align-items: flex-start;
	color: var( --ink );
	font-size: 1rem;
}

.check-list .ck {
	width: 22px;
	height: 22px;
	display: grid;
	place-items: center;
	flex: none;
	margin-top: 1px;
}

.check-list .ck svg {
	width: 13px;
	height: 13px;
}

/* Three-class branches that outrank the shared icon rule above, so the check
   icon is filled inside a hero/forest panel and accent-washed on .surface-dark.
   styles.css 1527 and 423. Radius stays 2px from the shared rule. */
.hero-forest .check-list .ck,
.surface-forest .check-list .ck {
	background: rgba( 255, 255, 255, 0.06 );
	border: 1px solid rgba( 255, 255, 255, 0.16 );
	color: var( --ink );
}

.surface-dark .check-list .ck {
	background: rgba( var( --accent-rgb ), 0.16 );
	border-color: rgba( var( --accent-rgb ), 0.34 );
	color: var( --mint );
}

/* --------------------------------------------------------------------------
   Stats — styles.css 374-376 with the V8 tail
   -------------------------------------------------------------------------- */
.stat .num {
	font-family: var( --font-sans );
	font-weight: 300;
	font-size: clamp( 2.2rem, 4vw, 3.2rem );
	letter-spacing: -0.03em;
	line-height: 1;
	color: var( --wp--preset--color--contrast );
}

.stat .num .unit {
	color: var( --wp--preset--color--contrast );
}

.stat .lbl {
	font-family: var( --font-mono );
	font-size: 11px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var( --slate );
	margin-top: 8px;
}

/* --------------------------------------------------------------------------
   Logo marquee — styles.css 383-388. `.band` below is the light variant.
   -------------------------------------------------------------------------- */
.logos {
	display: flex;
	align-items: center;
	gap: clamp( 28px, 5vw, 64px );
	flex-wrap: wrap;
	justify-content: center;
}

.logo-word {
	font-family: var( --font-mono );
	font-size: 13px;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	font-weight: 400;
	color: #3a404c;
	transition: color 0.2s;
}

.logo-word:hover {
	color: var( --ink );
}

.marquee {
	overflow: hidden;
	-webkit-mask-image: linear-gradient( 90deg, transparent, #000 8%, #000 92%, transparent );
	mask-image: linear-gradient( 90deg, transparent, #000 8%, #000 92%, transparent );
}

.marquee-track {
	display: flex;
	gap: clamp( 40px, 6vw, 80px );
	width: max-content;
	animation: marquee 32s linear infinite;
}

@keyframes marquee {
	to {
		transform: translateX( -50% );
	}
}

/* --------------------------------------------------------------------------
   Surfaces — the V8 tail flattens every legacy gradient to one raised black.
   -------------------------------------------------------------------------- */
/* styles.css:1801 raises all three to #0d1017, then base-2026.css:20 pulls
   .surface-2 / .surface-3 back to pure black. Only the dark/forest panels are
   raised — that ordering is load-bearing. */
.surface-dark,
.surface-forest {
	background: var( --wp--custom--surface-raised );
	color: var( --on-dark );
}

.surface-2,
.surface-3 {
	background: var( --wp--preset--color--base );
}

.surface-dark,
.surface-forest,
.cta-band {
	position: relative;
	overflow: hidden;
}

.surface-dark > *,
.surface-forest > *,
.cta-band > * {
	position: relative;
	z-index: 1;
}

.surface-dark .lead,
.surface-dark .muted,
.surface-forest .lead,
.surface-forest .muted {
	color: rgba( 255, 255, 255, 0.72 );
}

.surface-dark .check-list li {
	color: var( --on-dark );
}

.surface-dark .stat .num {
	color: var( --wp--preset--color--contrast );
}

/* styles.css:378 — the unit keeps the accent inside a dark panel */
.surface-dark .stat .num .unit {
	color: var( --mint );
}

.surface-forest h1,
.surface-forest h2,
.surface-forest h3,
.surface-forest h4,
.surface-forest .h-display,
.surface-forest .display-xl,
.hero-forest h1,
.hero-forest h2,
.hero-forest h3,
.hero-forest h4,
.hero-forest .h-display,
.hero-forest .display-xl {
	color: var( --wp--preset--color--contrast );
}

/* every decorative bloom in the legacy layers is switched off — styles.css
   1489-1491, reinforced for .cta-band by base-2026.css 176 */
.hero-forest::before,
.surface-dark::before,
.surface-forest::before,
.cta-band::before,
.cta-band::after,
.surface-grad-olive::before,
.glass-quote::after,
.glass-quote.on-grad::after,
.glow::before {
	display: none !important;
}

/* --------------------------------------------------------------------------
   CTA band — base-2026.css 174-181 unboxes it entirely
   -------------------------------------------------------------------------- */
.cta-band {
	background: none !important;
	border: 0 !important;
	box-shadow: none !important;
	border-radius: 0 !important;
	padding: 0 !important;
	text-align: center;
	overflow: visible;
	color: var( --on-dark );
}

.cta-band > div {
	max-width: 820px !important;
	margin-inline: auto !important;
	text-align: center;
}

.cta-band .sec-title,
.cta-band .h2,
.cta-band .lead,
.cta-band p {
	margin-inline: auto !important;
	text-align: center;
}

.cta-band .sec-chip,
.cta-band .eyebrow {
	justify-content: center;
}

.cta-band > div > div,
.cta-band > div > .btn-row {
	justify-content: center !important;
}

.cta-band h2 {
	color: var( --wp--preset--color--contrast );
}

.cta-band .lead {
	color: rgba( 255, 255, 255, 0.78 );
}

.cta-band .btn-lime-outline {
	border-color: rgba( var( --accent-rgb ), 0.55 );
}

.cta-band .btn-lime-outline:hover {
	color: var( --wp--preset--color--contrast );
	background: rgba( var( --accent-rgb ), 0.14 );
	border-color: var( --mint );
}

.section:has( > .wrap-wide > .cta-band ),
.section:has( > .wrap > .cta-band ) {
	padding-block: clamp( 34px, 4vw, 64px ) clamp( 56px, 7vw, 104px );
}

/* --------------------------------------------------------------------------
   Lava hero — base-2026.css 78-106. `.hx` is the homepage hero.
   -------------------------------------------------------------------------- */
.hx {
	position: relative;
	min-height: 100svh;
	display: grid;
	place-items: center;
	text-align: center;
	overflow: clip;
	background: var( --wp--preset--color--base );
	padding: 190px 0 130px;
}

.lava {
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	filter: contrast( 1.35 ) saturate( 1.08 );
	background: var( --wp--preset--color--base );
}

.blob {
	position: absolute;
	will-change: transform;
}

.grain {
	position: absolute;
	inset: -6%;
	z-index: 1;
	background-image: url( "data:image/svg+xml;utf8,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22300%22 height=%22300%22%3E%3Cfilter id=%22n%22%3E%3CfeTurbulence type=%22fractalNoise%22 baseFrequency=%220.8%22 numOctaves=%222%22 stitchTiles=%22stitch%22/%3E%3CfeColorMatrix type=%22saturate%22 values=%220%22/%3E%3C/filter%3E%3Crect width=%22300%22 height=%22300%22 filter=%22url(%23n)%22/%3E%3C/svg%3E" );
	background-size: 280px;
	opacity: 0.15;
	mix-blend-mode: overlay;
	pointer-events: none;
	will-change: transform;
}

.fx-off .blob,
.fx-off .grain,
.fx-off .ft-bloom,
.fx-off .ft-bloom2 {
	animation-play-state: paused !important;
}

@media ( prefers-reduced-motion: no-preference ) {
	.blob {
		animation-iteration-count: infinite;
		animation-timing-function: ease-in-out;
	}

	.grain {
		animation: grainJitter 1.1s steps( 4 ) infinite;
	}
}

@media ( prefers-reduced-motion: reduce ) {
	.blob,
	.grain {
		animation: none !important;
	}
}

@keyframes lavaA {
	0% {
		transform: translate( 0%, 26% ) scale( 1, 1.05 );
	}

	33% {
		transform: translate( 5%, -8% ) scale( 1.15, 0.95 );
	}

	66% {
		transform: translate( -3%, -34% ) scale( 0.92, 1.18 );
	}

	100% {
		transform: translate( 0%, 26% ) scale( 1, 1.05 );
	}
}

@keyframes lavaB {
	0% {
		transform: translate( 0%, -30% ) scale( 1.1 );
	}

	40% {
		transform: translate( -8%, 10% ) scale( 0.9, 1.2 );
	}

	70% {
		transform: translate( 6%, 32% ) scale( 1.25, 0.9 );
	}

	100% {
		transform: translate( 0%, -30% ) scale( 1.1 );
	}
}

@keyframes lavaPulse {
	0% {
		transform: translate( 0%, 34% ) scale( 1 );
		opacity: 0.55;
	}

	45% {
		transform: translate( -10%, -16% ) scale( 1.3, 1.1 );
		opacity: 1;
	}

	75% {
		transform: translate( 6%, -40% ) scale( 0.9, 1.25 );
		opacity: 0.8;
	}

	100% {
		transform: translate( 0%, 34% ) scale( 1 );
		opacity: 0.55;
	}
}

@keyframes lavaDark {
	0% {
		transform: translate( 0%, 0% ) scale( 1 );
	}

	50% {
		transform: translate( -12%, 14% ) scale( 1.28 );
	}

	100% {
		transform: translate( 0%, 0% ) scale( 1 );
	}
}

@keyframes grainJitter {
	0% {
		transform: translate( 0, 0 );
	}

	25% {
		transform: translate( -1.5%, 1% );
	}

	50% {
		transform: translate( 1%, -1.5% );
	}

	75% {
		transform: translate( -1%, 1.5% );
	}

	100% {
		transform: translate( 1.5%, -1% );
	}
}

.hx-in {
	position: relative;
	max-width: 1180px;
	padding-inline: var( --wp--custom--gutter );
}

.hx-tag {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	font-family: var( --font-mono );
	font-size: 0.7rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var( --wp--preset--color--on-accent );
	background: var( --wp--preset--color--accent );
	padding: 8px 15px;
}

.hx-tag i {
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: var( --wp--preset--color--contrast );
	animation: pulse 2.4s infinite;
}

@keyframes pulse {
	50% {
		opacity: 0.25;
	}
}

h1.hx-t {
	font-family: var( --font-display );
	font-weight: 300;
	letter-spacing: -0.05em;
	line-height: 0.92;
	font-size: clamp( 3.4rem, 11.5vw, 10rem );
	margin: 30px 0 0;
	color: var( --wp--preset--color--contrast );
	text-shadow: 0 0 90px rgba( 0, 0, 0, 0.55 );
	/* per-instance measure hook — was an inline style in the handoff */
	max-width: var( --hero-h-measure, none );
}

.swap {
	display: inline-grid;
	vertical-align: baseline;
	width: var( --sw, 7em );
	transition: width 0.45s cubic-bezier( 0.2, 0.7, 0.2, 1 );
	text-align: left;
}

.swap i {
	grid-area: 1/1;
	justify-self: start;
	font-style: normal;
	white-space: nowrap;
	line-height: 1;
	background: linear-gradient(
		96deg,
		var( --wp--preset--color--accent-bright ),
		var( --wp--preset--color--accent ) 55%,
		#c9f5e4
	);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	transform: translateY( 0.5em );
	opacity: 0;
	transition: transform 0.5s cubic-bezier( 0.2, 0.7, 0.2, 1 ), opacity 0.4s;
}

.swap i.on {
	transform: none;
	opacity: 1;
}

.swap i.out {
	transform: translateY( -0.5em );
	opacity: 0;
}

.hx-sub {
	font-size: clamp( 1.05rem, 1.6vw, 1.34rem );
	font-weight: 300;
	line-height: 1.55;
	color: #dfe6e2;
	max-width: var( --hero-lead-measure, 620px );
	margin: 34px auto 0;
	text-wrap: pretty;
}

/* Same owner change as .h26-cta above — the front page's lava hero used the
   identical 1px abutting treatment, so it is spaced to match rather than
   left as the only button row on the site whose buttons touch. */
.hx-cta {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	justify-content: center;
	margin-top: 40px;
}

.hx-cta .btn {
	border-radius: 0;
}

.hx-scroll {
	position: absolute;
	bottom: 26px;
	left: 50%;
	translate: -50% 0;
	font-family: var( --font-mono );
	font-size: 0.64rem;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: rgba( 238, 242, 239, 0.4 );
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 9px;
}

.hx-scroll::after {
	content: "";
	width: 1px;
	height: 44px;
	background: linear-gradient( rgba( 0, 194, 203, 0.8 ), transparent );
}

@media ( max-height: 820px ) {
	.hx-scroll {
		display: none;
	}

	.hx {
		padding-bottom: 90px;
	}
}

/* --------------------------------------------------------------------------
   Hero 2026 — dotted field with a blue edge glow. base-2026.css 398-427.
   -------------------------------------------------------------------------- */
.h26 {
	position: relative;
	overflow: clip;
	background: var( --wp--preset--color--base );
	min-height: min( 86svh, 780px );
	display: grid;
	place-items: center;
	text-align: center;
	padding: clamp( 90px, 11vw, 150px ) 0;
}

.h26-edge {
	position: absolute;
	inset: 0;
	pointer-events: none;
	background:
		linear-gradient( 90deg, #00c2cb 0%, rgba( 0, 194, 203, 0.55 ) 4%, rgba( 0, 194, 203, 0.14 ) 12%, transparent 24% ),
		linear-gradient( 270deg, #00c2cb 0%, rgba( 0, 194, 203, 0.55 ) 4%, rgba( 0, 194, 203, 0.14 ) 12%, transparent 24% );
	filter: blur( 10px );
}

.h26-dots {
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image: radial-gradient( circle, rgba( 255, 255, 255, 0.16 ) 1px, transparent 1px );
	background-size: 28px 28px;
	mask-image: radial-gradient( 88% 78% at 50% 46%, #000 30%, transparent 88% );
	-webkit-mask-image: radial-gradient( 88% 78% at 50% 46%, #000 30%, transparent 88% );
}

body.flush .h26 {
	padding-top: clamp( 196px, 18vw, 262px );
}

.h26-in {
	position: relative;
	max-width: 1060px;
	padding-inline: var( --wp--custom--gutter );
}

.h26 h1 {
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 2.5rem, 6.6vw, 5.8rem );
	line-height: 1.02;
	letter-spacing: -0.045em;
	color: var( --wp--preset--color--contrast );
	margin: 0;
	text-wrap: balance;
	max-width: var( --hero-h-measure, none );
}

.h26 .h26-sub {
	font-size: clamp( 1rem, 1.4vw, 1.18rem );
	font-weight: 300;
	line-height: 1.55;
	color: var( --wp--preset--color--body-text );
	max-width: var( --hero-lead-measure, 46ch );
	margin: clamp( 26px, 3.4vw, 44px ) auto 0;
	text-wrap: pretty;
}

/* OWNER CHANGE, not the handoff: base-2026.css:417 sets `gap: 1px` here, so
   the hero's buttons abut and read as one segmented control split by a
   hairline. The owner asked for them to be spaced like every other button
   row on the site, so this matches .btn-row's 12px (modules.css:159). The
   square corners below stay — those are the marketing layer's own treatment,
   not a consequence of the buttons touching. */
.h26 .h26-cta {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	justify-content: center;
	margin-top: clamp( 26px, 3vw, 38px );
}

.h26 .h26-cta .btn {
	border-radius: 0;
}

.h26 .breadcrumbs {
	justify-content: center;
	display: flex;
	gap: 6px;
	margin-bottom: 22px;
}

@media ( prefers-reduced-motion: no-preference ) {
	.h26-edge {
		animation: edgeBreathe 12s ease-in-out infinite alternate;
	}
}

@keyframes edgeBreathe {
	0% {
		opacity: 0.75;
		transform: scaleX( 1 );
	}

	100% {
		opacity: 1;
		transform: scaleX( 1.06 );
	}
}

.fx-off .h26-edge {
	animation-play-state: paused !important;
}

/* rays variant — base-2026.css 398-407 */
.h26.rays {
	min-height: min( 92svh, 880px );
}

.rays-field {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: flex-end;
	justify-content: center;
	gap: clamp( 5px, 0.9vw, 13px );
	pointer-events: none;
	filter: blur( 13px ) saturate( 1.08 );
	mask-image: linear-gradient( 180deg, transparent 4%, #000 34%, #000 88%, rgba( 0, 0, 0, 0.55 ) );
	-webkit-mask-image: linear-gradient( 180deg, transparent 4%, #000 34%, #000 88%, rgba( 0, 0, 0, 0.55 ) );
}

.rays-field b {
	display: block;
	width: clamp( 24px, 4.2vw, 72px );
	background: linear-gradient(
		180deg,
		rgba( 0, 194, 203, 0 ) 0%,
		var( --ray, var( --wp--preset--color--accent ) ) 30%,
		rgba( 0, 194, 203, 0.12 ) 100%
	);
	transform-origin: 50% 100%;
	will-change: transform;
}

@media ( prefers-reduced-motion: no-preference ) {
	.rays-field b {
		animation: rayBreathe 7.5s ease-in-out infinite alternate;
	}
}

@keyframes rayBreathe {
	0% {
		transform: scaleY( 0.94 );
		opacity: 0.8;
	}

	100% {
		transform: scaleY( 1.06 );
		opacity: 1;
	}
}

.fx-off .rays-field b {
	animation-play-state: paused !important;
}

/* --------------------------------------------------------------------------
   Rays hero — per-bar height/color/delay (cms.html and the 16 other .rays
   pages). The handoff set these as per-element inline styles; emitted as
   classes so the markup carries no inline style, same precedent as the lava
   blobs below. animation-delay is inert without the animation-name set by
   `.rays-field b` above, which is itself gated on prefers-reduced-motion.
   -------------------------------------------------------------------------- */
.ray-1 {
	height: 34%;
	--ray: rgba( 0, 194, 203, 0.55 );
	animation-delay: 0s;
}

.ray-2 {
	height: 46%;
	--ray: rgba( 0, 194, 203, 0.7 );
	animation-delay: -0.7s;
}

.ray-3 {
	height: 60%;
	--ray: rgba( 0, 208, 143, 0.82 );
	animation-delay: -1.4s;
}

.ray-4 {
	height: 74%;
	--ray: rgba( 95, 233, 189, 0.9 );
	animation-delay: -2.1s;
}

.ray-5 {
	height: 88%;
	--ray: rgba( 95, 233, 189, 0.95 );
	animation-delay: -2.8s;
}

.ray-6 {
	height: 100%;
	--ray: #c9f5e4;
	animation-delay: -3.5s;
}

.ray-7 {
	height: 88%;
	--ray: rgba( 95, 233, 189, 0.95 );
	animation-delay: -4.2s;
}

.ray-8 {
	height: 74%;
	--ray: rgba( 95, 233, 189, 0.9 );
	animation-delay: -4.9s;
}

.ray-9 {
	height: 60%;
	--ray: rgba( 0, 208, 143, 0.82 );
	animation-delay: -5.6s;
}

.ray-10 {
	height: 46%;
	--ray: rgba( 0, 194, 203, 0.7 );
	animation-delay: -6.3s;
}

.ray-11 {
	height: 34%;
	--ray: rgba( 0, 194, 203, 0.55 );
	animation-delay: -7s;
}

.h26.rays h1 {
	font-size: clamp( 2.6rem, 7.4vw, 6.6rem );
	text-shadow: 0 0 80px rgba( 0, 0, 0, 0.5 );
}

.h26.rays .breadcrumbs,
.h26.rays .breadcrumbs a,
.h26.rays .breadcrumbs span,
.h26.rays .vs-word,
.h26.rays .vs .side small,
.h26.rays .vs .side strong {
	color: #eef0f4 !important;
	text-shadow: 0 1px 14px rgba( 0, 0, 0, 0.75 );
}

.h26.rays .h26-sub {
	color: #eef0f4;
	text-shadow: 0 1px 14px rgba( 0, 0, 0, 0.6 );
}

/* --------------------------------------------------------------------------
   Space hero (solaris.html) — planet horizon. Ported from
   content-build/extract/inline-css/solaris.css; previously withheld because
   the hero partial emitted no `.space`/`.stars`/`.halo`/`.disc` DOM to attach
   it to (see the removed "NOT PORTED" note below this block's old location).
   The starfield's 17 twinkle stars carried per-element `style="animation-
   delay"` in the handoff; render.php emits `.tw-1`…`.tw-17` instead, same
   no-inline-style precedent as the lava blobs and the rays bars above.
   -------------------------------------------------------------------------- */
.h26.sol {
	min-height: min( 94svh, 900px );
	background: radial-gradient( 120% 90% at 50% 108%, #06131f 0%, #000 62% );
}

.space {
	position: absolute;
	inset: 0;
	overflow: hidden;
	pointer-events: none;
}

.space .stars {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	opacity: 0.9;
	mask-image: linear-gradient( #000 62%, transparent 88% );
	-webkit-mask-image: linear-gradient( #000 62%, transparent 88% );
}

.space .halo {
	position: absolute;
	left: 50%;
	top: 44%;
	width: min( 190vw, 2500px );
	aspect-ratio: 1;
	translate: -50% 0;
	border-radius: 50%;
	background: radial-gradient( circle, rgba( 0, 194, 203, 0.34 ) 0%, rgba( 0, 194, 203, 0.12 ) 40%, transparent 66% );
	filter: blur( 26px );
}

.space .disc {
	position: absolute;
	left: 50%;
	top: 76%;
	width: min( 280vw, 3600px );
	aspect-ratio: 1;
	translate: -50% 0;
	border-radius: 50%;
	background: #000;
	box-shadow: 0 0 0 1px rgba( 111, 228, 234, 0.5 ), 0 -10px 60px -12px rgba( 111, 228, 234, 0.7 ), 0 -46px 170px 6px rgba( 0, 194, 203, 0.42 );
}

.space .disc::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: radial-gradient( 120% 30% at 50% 0%, rgba( 182, 240, 243, 0.4 ), rgba( 0, 194, 203, 0.12 ) 40%, transparent 62% );
	mask-image: radial-gradient( circle, transparent 98.6%, #000 99% );
}

.h26.sol .h26-dots {
	opacity: 0.5;
}

.h26.sol h1 {
	text-shadow: 0 2px 40px rgba( 0, 0, 0, 0.75 );
}

.h26.sol .h26-sub {
	color: #eef0f4;
	text-shadow: 0 1px 16px rgba( 0, 0, 0, 0.7 );
}

@media ( prefers-reduced-motion: no-preference ) {
	.space .stars .tw {
		animation: solTw 5.5s ease-in-out infinite;
	}

	.space .halo {
		animation: solBreathe 11s ease-in-out infinite;
	}
}

@keyframes solTw {
	0%,
	100% {
		opacity: 0.15;
	}

	50% {
		opacity: 1;
	}
}

@keyframes solBreathe {
	0%,
	100% {
		opacity: 0.78;
		transform: scale( 1 );
	}

	50% {
		opacity: 1;
		transform: scale( 1.035 );
	}
}

@media ( prefers-reduced-motion: reduce ) {
	.space .stars .tw,
	.space .halo {
		animation: none !important;
	}
}

.fx-off .space .stars .tw,
.fx-off .space .halo {
	animation-play-state: paused !important;
}

.tw-1 {
	animation-delay: -1.2s;
}

.tw-2 {
	animation-delay: -4.6s;
}

.tw-3 {
	animation-delay: -3s;
}

.tw-4 {
	animation-delay: -0.5s;
}

.tw-5 {
	animation-delay: -5.8s;
}

.tw-6 {
	animation-delay: -2.4s;
}

.tw-7 {
	animation-delay: -1.4s;
}

.tw-8 {
	animation-delay: -0.6s;
}

.tw-9 {
	animation-delay: -0.6s;
}

.tw-10 {
	animation-delay: -1.5s;
}

.tw-11 {
	animation-delay: -3.7s;
}

.tw-12 {
	animation-delay: -4.7s;
}

.tw-13 {
	animation-delay: -1.4s;
}

.tw-14 {
	animation-delay: -4.6s;
}

.tw-15 {
	animation-delay: -3.7s;
}

.tw-16 {
	animation-delay: -5.2s;
}

.tw-17 {
	animation-delay: -4.2s;
}

/* --------------------------------------------------------------------------
   Legacy interior hero — styles.css 410-413 / 540-545, still live on 19 pages.
   The bloom is switched off above; only the dotted field renders.
   -------------------------------------------------------------------------- */
.page-hero {
	padding-top: clamp( 56px, 8vw, 104px );
	padding-bottom: clamp( 40px, 6vw, 72px );
}

/* Run the hero's field to the very top of the page, behind the fixed header.
   OWNER CHANGE, not the handoff: the design leaves a flat black band between
   the announcement bar and the hero, because non-flush pages clear the fixed
   header with `body { padding-top: --header-height }` and the hero only
   starts below it. Pulling the hero up by exactly that clearance and adding
   the same amount back as padding leaves every child on the same pixel while
   the box — the #0c0d0e field and the .hero-forest dot texture painted over
   it — extends to y=0. Scoped away from body.flush, whose padding-top is
   already 0 and whose .h26 hero does its own clearance. */
body:not( .flush ) .page-hero {
	margin-top: calc( -1 * var( --wp--custom--header-height ) );
	padding-top: calc( clamp( 56px, 8vw, 104px ) + var( --wp--custom--header-height ) );
}

@media ( max-width: 1080px ) {
	body:not( .flush ) .page-hero {
		margin-top: calc( -1 * var( --wp--custom--header-height-compact ) );
		padding-top: calc( clamp( 56px, 8vw, 104px ) + var( --wp--custom--header-height-compact ) );
	}
}

.page-hero .h-display {
	margin-top: 20px;
}

.page-hero .h-display,
.compare-hero .h-display {
	text-transform: none;
}

/* isolation + a z-index:-1 decoration layer, per handoff/hero/HERO-HEADERS.md
   §1. This block used to raise every child with `.hero-forest > * { position:
   relative; z-index: 1 }` so they cleared the ::after dots — the exact rule
   that handover's pitfall table calls out, because it re-anchors absolutely
   positioned hero children (the co-brand lockup, the VS lockup) to the wrong
   box. Isolating the section and dropping the dots to -1 gets the same
   stacking for free and leaves children untouched. */
.hero-forest {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	background: #0c0d0e;
	color: var( --ink );
}

.hero-forest::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background-image: radial-gradient( rgba( 255, 255, 255, 0.13 ) 1px, transparent 1px );
	background-size: 24px 24px;
	mask-image: linear-gradient( 180deg, #000 0%, #000 62%, transparent 92% );
	-webkit-mask-image: linear-gradient( 180deg, #000 0%, #000 62%, transparent 92% );
}

/* --------------------------------------------------------------------------
   Hero backgrounds — data-hero="wave|iso|pulse|rain"
   Ported verbatim from handoff/hero/hero-headers.html (the standalone
   reference), which is the same block that lives at the tail of the design's
   base-2026.css. Only the formatting is expanded to match this stylesheet.

   One deliberate departure from the handoff: it injects the layer markup with
   base-2026.js on DOMContentLoaded. We render it server-side from
   hdl-kit/blocks/hero/partials/hbg-{variant}.php instead — HERO-HEADERS.md §4
   asks for exactly that, and it avoids a frame of empty hero on load.

   The layer is z-index:-1 inside an isolated stacking context on purpose:
   hero content then needs no z-index of its own, and absolutely positioned
   children keep their placement. Do not "fix" this by raising the children.
   -------------------------------------------------------------------------- */
[data-hero] {
	position: relative;
	isolation: isolate;
	overflow: hidden;
}

[data-hero] > .hbg {
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	overflow: hidden;
}

/* Legacy decorations are REPLACED, not layered under, when a page carries a
   background layer. .hero-forest::after in particular is also a z-index:-1
   dot grid, so leaving it on stacks two background systems in one layer —
   the new field reads as a dirty version of the old one rather than itself.
   Every legacy hero decoration therefore switches off wherever data-hero is
   present. Add to this list, do not dampen the new layer to compensate. */
[data-hero] .rays-field,
[data-hero] .h26-edge {
	display: none;
}

[data-hero].hero-forest::after {
	content: none;
}

/* ---- A. Punktvåg ---- */
.hbg-wave {
	background: #000;
}

.hbg-wave .still {
	position: absolute;
	inset: 0;
	background-image: radial-gradient( rgba( 255, 255, 255, 0.1 ) 1px, transparent 1px );
	background-size: 22px 22px;
	mask-image: radial-gradient( 80% 70% at 50% 46%, #000 0%, transparent 82% );
	-webkit-mask-image: radial-gradient( 80% 70% at 50% 46%, #000 0%, transparent 82% );
}

.hbg-wave .matrix {
	position: absolute;
	inset: -10%;
	background-image: radial-gradient( rgba( 111, 228, 234, 0.5 ) 1.5px, transparent 1.6px );
	background-size: 22px 22px;
}

/* The -webkit-mask-* duplicates are load-bearing, here AND in the keyframes:
   without the prefixed properties the sweep silently freezes in Safari. */
.hbg-wave .matrix.m1 {
	-webkit-mask-image: linear-gradient( 115deg, transparent 30%, #000 46%, #000 54%, transparent 70% );
	mask-image: linear-gradient( 115deg, transparent 30%, #000 46%, #000 54%, transparent 70% );
	-webkit-mask-size: 260% 260%;
	mask-size: 260% 260%;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	animation: hbg-sweep-1 11s linear infinite;
}

.hbg-wave .matrix.m2 {
	background-image: radial-gradient( rgba( 0, 194, 203, 0.85 ) 2px, transparent 2.1px );
	-webkit-mask-image: linear-gradient( 70deg, transparent 34%, #000 48%, #000 52%, transparent 66% );
	mask-image: linear-gradient( 70deg, transparent 34%, #000 48%, #000 52%, transparent 66% );
	-webkit-mask-size: 280% 280%;
	mask-size: 280% 280%;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	animation: hbg-sweep-2 17s linear infinite;
}

@keyframes hbg-sweep-1 {
	0% {
		-webkit-mask-position: -90% 120%;
		mask-position: -90% 120%;
	}

	100% {
		-webkit-mask-position: 120% -90%;
		mask-position: 120% -90%;
	}
}

@keyframes hbg-sweep-2 {
	0% {
		-webkit-mask-position: 120% 130%;
		mask-position: 120% 130%;
	}

	100% {
		-webkit-mask-position: -100% -90%;
		mask-position: -100% -90%;
	}
}

/* Never add a `translate:` property beside the transform in these keyframes —
   the two compose and the bloom doubles its shift into the bottom-left. */
.hbg-wave .bloom {
	position: absolute;
	left: 50%;
	bottom: -38%;
	width: min( 140vw, 1700px );
	height: min( 70vw, 850px );
	background: radial-gradient( 50% 100% at 50% 100%, rgba( 0, 194, 203, 0.5 ) 0%, rgba( 0, 194, 203, 0.14 ) 44%, transparent 74% );
	filter: blur( 24px );
	transform: translate( -50%, 0 );
	animation: hbg-bloom 10s ease-in-out infinite;
}

@keyframes hbg-bloom {
	0%,
	100% {
		opacity: 0.6;
		transform: translate( -50%, 0 ) scale( 1 );
	}

	50% {
		opacity: 1;
		transform: translate( -50%, -2% ) scale( 1.06 );
	}
}

.hbg-wave .vig {
	position: absolute;
	inset: 0;
	background: radial-gradient( 58% 46% at 50% 44%, rgba( 0, 0, 0, 0.82 ) 0%, rgba( 0, 0, 0, 0.45 ) 54%, transparent 84% );
}

/* ---- B. Isometriskt fält ---- */
.hbg-iso {
	background: #000;
}

.hbg-iso .glow {
	position: absolute;
	left: 50%;
	top: 50%;
	width: min( 120vw, 1400px );
	aspect-ratio: 1;
	translate: -50% -50%;
	border-radius: 50%;
	background: radial-gradient( circle, rgba( 0, 194, 203, 0.26 ) 0%, transparent 62% );
	filter: blur( 30px );
}

.hbg-iso .iso {
	position: absolute;
	inset: -20%;
	background-image:
		repeating-linear-gradient( 30deg, rgba( 0, 194, 203, 0.22 ) 0 1px, transparent 1px 78px ),
		repeating-linear-gradient( -30deg, rgba( 0, 194, 203, 0.22 ) 0 1px, transparent 1px 78px );
	mask-image: radial-gradient( 70% 62% at 50% 46%, #000 0%, transparent 76% );
	-webkit-mask-image: radial-gradient( 70% 62% at 50% 46%, #000 0%, transparent 76% );
	animation: hbg-drift 26s linear infinite;
}

@keyframes hbg-drift {
	to {
		transform: translate( 78px, 45px );
	}
}

.hbg-iso .cube {
	position: absolute;
	line-height: 0;
	animation: hbg-bob 7s ease-in-out infinite;
}

.hbg-iso .cube svg {
	display: block;
	width: 100%;
	height: auto;
}

@keyframes hbg-bob {
	0%,
	100% {
		transform: translateY( 0 );
	}

	50% {
		transform: translateY( -26px );
	}
}

/* ---- C. Konturvågor ---- */

/* These are horizontal lines, never closed rings. Any axis-aligned rectangle
   centred on the headline eventually frames the text like an accidental box —
   which is what a screenshot, PDF export or slide catches. Do not restore the
   rings this started as. */
.hbg-pulse {
	background: radial-gradient( 100% 80% at 50% 44%, #050f19 0%, #000 62% );
}

.hbg-pulse .dots {
	position: absolute;
	inset: 0;
	background-image: radial-gradient( rgba( 255, 255, 255, 0.1 ) 1px, transparent 1px );
	background-size: 26px 26px;
	mask-image: radial-gradient( 64% 60% at 50% 48%, transparent 18%, #000 80% );
	-webkit-mask-image: radial-gradient( 64% 60% at 50% 48%, transparent 18%, #000 80% );
}

.hbg-pulse .ring {
	position: absolute;
	left: 50%;
	top: 48%;
	width: min( 80vw, 1180px );
	height: 1px;
	background: linear-gradient( 90deg, transparent, rgba( 111, 228, 234, 0.62 ) 18%, #b6f0f3 50%, rgba( 111, 228, 234, 0.62 ) 82%, transparent );
	transform: translate( -50%, -50% );
	animation: hbg-ring-up 9s ease-out infinite;
}

.hbg-pulse .ring.down {
	animation-name: hbg-ring-down;
}

@keyframes hbg-ring-up {
	0% {
		transform: translate( -50%, -50% ) scaleX( 0.24 );
		opacity: 0;
	}

	18% {
		opacity: 0.9;
	}

	100% {
		transform: translate( -50%, calc( -50% - 320px ) ) scaleX( 1.7 );
		opacity: 0;
	}
}

@keyframes hbg-ring-down {
	0% {
		transform: translate( -50%, -50% ) scaleX( 0.24 );
		opacity: 0;
	}

	18% {
		opacity: 0.9;
	}

	100% {
		transform: translate( -50%, calc( -50% + 320px ) ) scaleX( 1.7 );
		opacity: 0;
	}
}

.hbg-pulse .core {
	position: absolute;
	left: 50%;
	top: 48%;
	width: min( 52vw, 700px );
	height: min( 20vw, 240px );
	translate: -50% -50%;
	background: radial-gradient( closest-side, rgba( 0, 194, 203, 0.4 ), transparent 74% );
	animation: hbg-core 9s ease-out infinite;
}

@keyframes hbg-core {
	0%,
	100% {
		opacity: 0.4;
	}

	12% {
		opacity: 1;
	}
}

.hbg-pulse .veil {
	position: absolute;
	inset: 0;
	background: radial-gradient( 34% 22% at 50% 48%, #000 0%, rgba( 0, 0, 0, 0.7 ) 52%, transparent 88% );
}

/* ---- D. Blockregn ---- */
.hbg-rain {
	background: linear-gradient( 180deg, #000 0%, #04101c 78%, #000 100% );
}

.hbg-rain .sweep {
	position: absolute;
	left: 0;
	right: 0;
	top: 0;
	height: 100%;
	background: linear-gradient( 180deg, transparent 40%, rgba( 0, 194, 203, 0.16 ) 52%, transparent 64% );
	animation: hbg-sweep-v 8s ease-in-out infinite;
}

@keyframes hbg-sweep-v {
	0%,
	100% {
		transform: translateY( -30% );
	}

	50% {
		transform: translateY( 30% );
	}
}

/* One div, one gradient — the falling blocks are not individual elements. */
.hbg-rain .col {
	position: absolute;
	top: -120%;
	width: 11px;
	height: 240%;
	background: repeating-linear-gradient( #00c2cb 0 11px, transparent 11px 58px );
	mask-image: linear-gradient( transparent, #000 22%, #000 60%, transparent );
	-webkit-mask-image: linear-gradient( transparent, #000 22%, #000 60%, transparent );
	animation: hbg-fall linear infinite;
}

@keyframes hbg-fall {
	to {
		transform: translateY( 58% );
	}
}

.hbg-rain .veil {
	position: absolute;
	inset: 0;
	background: radial-gradient( 52% 44% at 50% 46%, #000 0%, rgba( 0, 0, 0, 0.82 ) 46%, rgba( 0, 0, 0, 0.35 ) 70%, transparent 88% );
}

/* Reduced motion is a real design state, not a fallback: everything stops and
   the composition still reads as a static field. */
@media ( prefers-reduced-motion: reduce ) {
	.hbg-wave .matrix,
	.hbg-wave .bloom,
	.hbg-iso .iso,
	.hbg-iso .cube,
	.hbg-pulse .ring,
	.hbg-pulse .core,
	.hbg-rain .col,
	.hbg-rain .sweep {
		animation: none;
	}

	.hbg-pulse .ring {
		opacity: 0.35;
	}
}

/* site.js adds .fx-off to sections scrolled out of view. */
.fx-off .hbg-wave .matrix,
.fx-off .hbg-wave .bloom,
.fx-off .hbg-iso .iso,
.fx-off .hbg-iso .cube,
.fx-off .hbg-pulse .ring,
.fx-off .hbg-pulse .core,
.fx-off .hbg-rain .col,
.fx-off .hbg-rain .sweep {
	animation-play-state: paused !important;
}

.hero-forest .lead,
.hero-forest .muted {
	color: var( --slate );
}

.hero-forest .check-list li,
.surface-forest .check-list li {
	color: var( --ink );
}

.hero-forest .btn-ghost {
	background: transparent;
	border-color: rgba( 255, 255, 255, 0.35 );
}

.hero-forest .pill,
.hero .pill {
	box-shadow: none;
}

.breadcrumbs {
	font-family: var( --font-mono );
	font-size: var( --wp--preset--font-size--small );
	display: flex;
	gap: 8px;
	align-items: center;
	color: var( --slate-2 );
}

.breadcrumbs a:hover {
	color: var( --emerald );
}

.hero-forest .breadcrumbs,
.page-hero.hero-forest .breadcrumbs {
	color: var( --slate-2 );
}

.hero-forest .breadcrumbs a:hover {
	color: var( --mint-bright );
}

/* --------------------------------------------------------------------------
   Promo strip — base-2026.css 109-117
   -------------------------------------------------------------------------- */
.promo {
	position: relative;
	margin: 0 auto;
	max-width: 1600px;
	padding-inline: var( --wp--custom--gutter );
}

.promo a {
	display: grid;
	grid-template-columns: auto 1fr auto;
	gap: clamp( 18px, 3vw, 40px );
	align-items: center;
	text-decoration: none;
	border: 1px solid rgba( 255, 255, 255, 0.1 );
	border-radius: 0;
	padding: 26px clamp( 22px, 3vw, 38px );
	background: linear-gradient(
		120deg,
		rgba( 0, 194, 203, 0.16 ),
		rgba( 255, 255, 255, 0.02 ) 45%,
		rgba( 0, 194, 203, 0.08 )
	);
	transition: border-color 0.25s, transform 0.25s;
}

.promo a:hover {
	border-color: rgba( 0, 194, 203, 0.55 );
	transform: translateY( -2px );
}

.promo .lbl {
	font-family: var( --font-mono );
	font-size: 0.66rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var( --wp--preset--color--accent-bright );
	border-right: 1px solid rgba( 255, 255, 255, 0.14 );
	padding-right: clamp( 18px, 3vw, 36px );
}

.promo b {
	display: block;
	font-weight: 400;
	font-size: clamp( 1.05rem, 1.7vw, 1.4rem );
	color: var( --wp--preset--color--contrast );
}

.promo span {
	display: block;
	font-size: 0.92rem;
	color: var( --on-dark-mut );
	margin-top: 4px;
}

.promo .arw {
	width: 42px;
	height: 42px;
	border-radius: 50%;
	border: 1px solid rgba( 255, 255, 255, 0.18 );
	display: grid;
	place-items: center;
	color: var( --wp--preset--color--contrast );
	flex: none;
}

@media ( max-width: 760px ) {
	.promo a {
		grid-template-columns: 1fr;
	}

	.promo .lbl {
		border: 0;
		padding: 0;
	}
}

/* --------------------------------------------------------------------------
   Logo band — INTENTIONALLY LIGHT. base-2026.css 119-123.
   One of two light areas in the whole site; do not retint.
   -------------------------------------------------------------------------- */
.band {
	padding: clamp( 52px, 7vw, 90px ) 0;
	background: var( --wp--preset--color--light-band );
	color: var( --wp--preset--color--base );
}

.band-h {
	text-align: center;
	font-family: var( --font-mono );
	font-size: 0.68rem;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: #6b7280;
	margin-bottom: 34px;
}

.band .logo-word {
	font-size: clamp( 1.05rem, 1.7vw, 1.5rem );
	font-weight: 400;
	color: #8d949c;
	white-space: nowrap;
}

.band .logo-word:hover {
	color: var( --wp--preset--color--base );
}

/* --------------------------------------------------------------------------
   Statement + claims — light. base-2026.css 125-143.
   -------------------------------------------------------------------------- */
.st {
	background: #f7f8fa;
	color: var( --wp--preset--color--base );
	padding: clamp( 56px, 8vw, 120px ) 0 0;
}

.st-chip {
	display: inline-block;
	font-family: var( --font-mono );
	font-size: var( --wp--preset--font-size--mono-eyebrow );
	letter-spacing: 0.06em;
	color: var( --wp--preset--color--base );
	background: #e4e7ec;
	padding: 6px 12px;
}

.stmt {
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 2.1rem, 5.4vw, 5.6rem );
	line-height: 1.02;
	letter-spacing: -0.04em;
	color: var( --wp--preset--color--base );
	margin: 18px 0 0;
	max-width: 22em;
	text-wrap: pretty;
}

.st-hl {
	background: var( --wp--preset--color--base );
	color: var( --wp--preset--color--contrast );
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
	padding: 0 0.12em 0.06em;
}

.st-ic {
	display: inline-grid;
	place-items: center;
	width: 0.86em;
	height: 0.86em;
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	vertical-align: -0.06em;
	margin-right: 0.1em;
}

.st-ic svg {
	width: 62%;
	height: 62%;
}

.st-foot {
	display: grid;
	grid-template-columns: minmax( 0, 180px ) 1fr;
	gap: clamp( 16px, 3vw, 48px );
	align-items: center;
	margin-top: clamp( 34px, 5vw, 64px );
	padding-bottom: clamp( 26px, 4vw, 46px );
}

.st-foot .arw {
	font-family: var( --font-mono );
	font-size: 0.8rem;
	color: #6b7280;
}

.st-foot .st-chip {
	justify-self: start;
}

.claims {
	background: #eef1f5;
	color: var( --wp--preset--color--base );
	padding: clamp( 10px, 2vw, 26px ) 0 clamp( 34px, 5vw, 60px );
}

.claims ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.claims li {
	display: grid;
	grid-template-columns: 1fr auto;
	gap: 20px;
	align-items: center;
	border-bottom: 1px dotted #b5bcc6;
	padding: clamp( 16px, 2.4vw, 28px ) 0;
	font-family: var( --font-display );
	font-size: clamp( 1.35rem, 3.2vw, 2.7rem );
	font-weight: 400;
	letter-spacing: -0.03em;
	line-height: 1.1;
	color: #8d949c;
	transition: color 0.4s;
}

.claims li:first-child {
	border-top: 1px dotted #b5bcc6;
}

.claims li.on {
	color: var( --wp--preset--color--base );
}

.claims .ic {
	width: clamp( 38px, 3.4vw, 54px );
	aspect-ratio: 1;
	background: #ccd2da;
	color: var( --wp--preset--color--contrast );
	display: grid;
	place-items: center;
	flex: none;
	transition: background 0.4s;
}

.claims li.on .ic {
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
}

.claims .ic svg {
	width: 52%;
	height: 52%;
}

@media ( max-width: 700px ) {
	.st-foot {
		grid-template-columns: 1fr;
	}

	.stmt {
		max-width: none;
	}
}

/* --------------------------------------------------------------------------
   Module rail — base-2026.css 145-156
   -------------------------------------------------------------------------- */
.rail-nav {
	display: flex;
	gap: 8px;
	justify-content: flex-end;
	margin-bottom: 18px;
}

.rail-nav button {
	width: 44px;
	height: 44px;
	border-radius: 50%;
	background: rgba( 255, 255, 255, 0.05 );
	border: 1px solid rgba( 255, 255, 255, 0.14 );
	color: var( --wp--preset--color--contrast );
	cursor: pointer;
	display: grid;
	place-items: center;
	transition: background 0.2s, border-color 0.2s;
}

.rail-nav button:hover {
	background: rgba( 0, 194, 203, 0.18 );
	border-color: rgba( 0, 194, 203, 0.5 );
}

.rail {
	display: flex;
	gap: 18px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	padding-bottom: 6px;
}

.rail::-webkit-scrollbar {
	display: none;
}

.rail article {
	scroll-snap-align: start;
	flex: 0 0 clamp( 250px, 26vw, 340px );
	min-height: clamp( 300px, 32vw, 400px );
	border: 1px solid rgba( 255, 255, 255, 0.1 );
	border-radius: 0;
	padding: 26px;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	background: linear-gradient( 180deg, rgba( 255, 255, 255, 0.045 ), rgba( 255, 255, 255, 0.012 ) );
	transition: border-color 0.3s, background 0.3s, transform 0.3s;
}

.rail article:hover {
	border-color: rgba( 0, 194, 203, 0.45 );
	background: linear-gradient( 180deg, rgba( 0, 194, 203, 0.12 ), rgba( 255, 255, 255, 0.02 ) );
	transform: translateY( -3px );
}

.rail .n {
	font-family: var( --font-mono );
	font-size: 0.72rem;
	letter-spacing: 0.14em;
	color: var( --wp--preset--color--accent-bright );
}

.rail .k {
	font-family: var( --font-mono );
	font-size: 0.62rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var( --on-dark-mut );
}

.rail h3 {
	font-size: clamp( 1.5rem, 2.4vw, 2.1rem );
	font-weight: 300;
	letter-spacing: -0.03em;
	color: var( --wp--preset--color--contrast );
	margin: 8px 0 0;
}

.rail p {
	font-size: 0.9rem;
	line-height: 1.55;
	color: var( --on-dark-mut );
	margin: 12px 0 0;
}

/* --------------------------------------------------------------------------
   Duo columns — base-2026.css 158-171
   -------------------------------------------------------------------------- */
.duo {
	--dot: var( --wp--custom--rule-dotted );
}

.duo-grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	border-top: 1px dotted var( --dot );
	border-bottom: 1px dotted var( --dot );
}

.duo-col {
	padding: clamp( 30px, 4vw, 58px ) clamp( 18px, 2.6vw, 44px );
	border-left: 1px dotted var( --dot );
	display: flex;
	flex-direction: column;
}

.duo-col:last-child {
	border-right: 1px dotted var( --dot );
}

.duo-eb {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 9px;
	font-family: var( --font-mono );
	font-size: 0.7rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: #eef2ef;
}

.duo-eb i {
	width: 10px;
	height: 10px;
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	flex: none;
}

.duo-h {
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 1.9rem, 4vw, 3.5rem );
	line-height: 1.08;
	letter-spacing: -0.035em;
	color: var( --wp--preset--color--contrast );
	text-align: center;
	margin: clamp( 18px, 2.4vw, 30px ) auto clamp( 24px, 3.4vw, 44px );
	max-width: 14em;
}

.duo-cards {
	display: flex;
	flex-direction: column;
	gap: 10px;
	margin-top: auto;
}

.duo-card {
	background: #14161a;
	padding: clamp( 16px, 1.6vw, 22px );
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 12px;
	align-items: start;
	transition: background 0.25s;
}

.duo-card:hover {
	background: #191c21;
}

.duo-card i {
	width: 10px;
	height: 10px;
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	margin-top: 0.42em;
}

.duo-card p {
	margin: 0;
	font-size: 1.02rem;
	font-weight: 400;
	line-height: 1.45;
	color: #eef2ef;
	letter-spacing: -0.01em;
}

@media ( max-width: 860px ) {
	.duo-grid {
		grid-template-columns: 1fr;
	}

	.duo-col:last-child {
		border-right: 0;
		border-top: 1px dotted var( --dot );
	}
}

/* --------------------------------------------------------------------------
   Industry cards / kom igang — base-2026.css 279-297
   -------------------------------------------------------------------------- */
.inds {
	display: grid;
	grid-template-columns: repeat( 4, 1fr );
	gap: 16px;
}

@media ( max-width: 1080px ) {
	.inds {
		grid-template-columns: 1fr 1fr;
	}
}

@media ( max-width: 620px ) {
	.inds {
		grid-template-columns: 1fr;
	}
}

.inds a {
	display: flex;
	flex-direction: column;
	text-decoration: none;
	border: 1px solid var( --line );
	border-radius: 0;
	padding: 28px;
	min-height: 340px;
	background: rgba( 255, 255, 255, 0.02 );
	transition: border-color 0.3s, background 0.3s, transform 0.3s;
}

.inds a:hover {
	border-color: rgba( 0, 194, 203, 0.45 );
	background: rgba( 0, 194, 203, 0.08 );
	transform: translateY( -3px );
}

.inds h3 {
	font-size: 1.3rem;
	font-weight: 400;
	letter-spacing: -0.02em;
	color: var( --wp--preset--color--contrast );
	margin: 0 0 18px;
}

.inds ul {
	list-style: none;
	margin: 0;
	padding: 0;
	flex: 1;
}

.inds li {
	font-size: 0.9rem;
	font-weight: 300;
	line-height: 1.5;
	color: var( --on-dark-mut );
	padding: 9px 0;
	border-top: 1px solid var( --wp--custom--hairline );
}

.inds .go {
	font-size: 0.86rem;
	color: var( --wp--preset--color--accent-bright );
	margin-top: 22px;
	display: inline-flex;
	gap: 7px;
	align-items: center;
}

.starts {
	display: grid;
	grid-template-columns: repeat( 4, 1fr );
	gap: 0;
	border-top: 1px solid var( --line );
}

@media ( max-width: 1000px ) {
	.starts {
		grid-template-columns: 1fr 1fr;
	}
}

@media ( max-width: 600px ) {
	.starts {
		grid-template-columns: 1fr;
	}
}

.starts > div {
	padding: 34px clamp( 20px, 2.4vw, 34px );
	border-bottom: 1px solid var( --line );
	border-right: 1px solid var( --line );
}

.starts > div:last-child {
	border-right: 0;
}

.starts h3 {
	font-size: 1.28rem;
	font-weight: 400;
	color: var( --wp--preset--color--contrast );
	margin: 0 0 12px;
	letter-spacing: -0.02em;
}

.starts p {
	font-size: 0.92rem;
	font-weight: 300;
	line-height: 1.55;
	color: var( --on-dark-mut );
	margin: 0 0 20px;
	min-height: 4.6em;
}

/* --------------------------------------------------------------------------
   Lava blobs
   The handoff set these as per-element inline styles (base-2026.js 227-231).
   Emitted as classes so the markup carries no inline style. Shared by the
   hero `.lava` and the footer `.ft-lava`.
   -------------------------------------------------------------------------- */
.blob-1,
.blob-2,
.blob-3,
.blob-4,
.blob-5 {
	position: absolute;
	will-change: transform;
}

.blob-1 {
	left: -8%;
	bottom: -46%;
	width: 56%;
	height: 120%;
	background: radial-gradient(
		ellipse at 50% 60%,
		rgba( 0, 194, 203, 0.6 ),
		rgba( 0, 194, 203, 0 ) 62%
	);
	filter: blur( 64px );
}

.blob-2 {
	left: 26%;
	bottom: -58%;
	width: 52%;
	height: 130%;
	background: radial-gradient( ellipse, rgba( 182, 240, 243, 0.5 ), transparent 60% );
	filter: blur( 70px );
}

.blob-3 {
	right: -6%;
	bottom: -50%;
	width: 46%;
	height: 118%;
	background: radial-gradient( ellipse, rgba( 10, 107, 112, 0.6 ), transparent 60% );
	filter: blur( 72px );
}

.blob-4 {
	left: 40%;
	bottom: -30%;
	width: 34%;
	height: 70%;
	background: radial-gradient( ellipse, rgba( 111, 228, 234, 0.42 ), transparent 58% );
	filter: blur( 58px );
}

.blob-5 {
	left: 12%;
	bottom: -34%;
	width: 50%;
	height: 104%;
	background: radial-gradient( ellipse, rgba( 0, 0, 0, 0.9 ), transparent 60% );
	filter: blur( 56px );
}

@media ( prefers-reduced-motion: no-preference ) {
	.blob-1 {
		animation: lavaA 9s ease-in-out infinite;
		animation-delay: -6s;
	}

	.blob-2 {
		animation: lavaB 11.5s ease-in-out infinite;
		animation-delay: -16s;
	}

	.blob-3 {
		animation: lavaPulse 7.5s ease-in-out infinite;
		animation-delay: -10s;
	}

	.blob-4 {
		animation: lavaB 8s ease-in-out infinite;
		animation-delay: -4s;
	}

	.blob-5 {
		animation: lavaDark 8.5s ease-in-out infinite;
		animation-delay: -8s;
	}
}

@media ( prefers-reduced-motion: reduce ) {
	.blob-1,
	.blob-2,
	.blob-3,
	.blob-4,
	.blob-5 {
		animation: none !important;
	}
}

/* --------------------------------------------------------------------------
   Scroll story stage — base-2026.css 204-233
   -------------------------------------------------------------------------- */
.story {
	position: relative;
	height: 340svh;
	background: var( --wp--preset--color--base );
}

.story-stage {
	position: sticky;
	top: var( --mh-h, 120px );
	height: calc( 100svh - var( --mh-h, 120px ) );
	overflow: clip;
	display: grid;
	place-items: center;
}

.story-step {
	position: absolute;
	inset: 0;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.55s ease, visibility 0.55s;
}

.story-step.on {
	opacity: 1;
	visibility: visible;
}

.story-frame {
	position: absolute;
	border: 1px dotted var( --wp--custom--rule-dotted );
	background: #0b0d10;
	overflow: hidden;
	transform: translateY( 30px ) scale( 0.98 );
	transition: transform 0.85s cubic-bezier( 0.2, 0.7, 0.2, 1 );
	--slot-bg: #0b0d10;
}

.story-step.on .story-frame {
	transform: none;
}

.story-step.on .story-frame:nth-of-type( 2 ) {
	transition-delay: 0.08s;
}

.story-step.on .story-frame:nth-of-type( 3 ) {
	transition-delay: 0.16s;
}

.story-step .story-frame:nth-of-type( 3 ) {
	margin-bottom: clamp( 56px, 7vh, 96px );
}

.story-frame image-slot {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

.story-sq {
	position: absolute;
	width: 13px;
	height: 13px;
}

.story-lab {
	position: relative;
	z-index: 3;
	display: flex;
	align-items: center;
	gap: 10px;
	justify-content: center;
	font-family: var( --font-mono );
	font-size: 0.7rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: #8d949c;
	margin-bottom: 18px;
}

.story-lab b {
	color: var( --wp--preset--color--accent );
	font-weight: 400;
}

.story-lab s {
	width: 26px;
	height: 1px;
	background: var( --wp--custom--rule-dotted );
	text-decoration: none;
}

.story-mid {
	position: relative;
	z-index: 3;
	display: grid;
	place-items: center;
	width: min( 40vw, 620px );
}

@media ( max-width: 900px ) {
	.story-mid {
		width: min( 88vw, 620px );
	}
}

/* --gutter here is deliberate: the story title is header-aligned, not
   content-aligned. base-2026.css 221-223. */
.story-t {
	position: relative;
	z-index: 3;
	text-align: center;
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 2.1rem, 5.4vw, 4.6rem );
	line-height: 1.06;
	letter-spacing: -0.04em;
	color: var( --wp--preset--color--contrast );
	max-width: 19em;
	margin: 0 auto;
	padding-inline: var( --wp--custom--gutter );
	text-shadow: 0 2px 34px rgba( 0, 0, 0, 0.8 );
}

.story-cap {
	position: absolute;
	left: 0;
	right: 0;
	bottom: clamp( 26px, 4.4vw, 60px );
	z-index: 3;
	text-align: center;
	font-size: 0.98rem;
	font-weight: 300;
	line-height: 1.55;
	color: var( --wp--preset--color--body-text );
	max-width: min( 56ch, 38vw );
	margin-inline: auto;
	padding-inline: var( --wp--custom--gutter );
	text-shadow: 0 1px 20px rgba( 0, 0, 0, 0.8 );
}

.story-dots {
	position: absolute;
	top: 50%;
	right: clamp( 12px, 1.8vw, 30px );
	translate: 0 -50%;
	display: flex;
	flex-direction: column;
	gap: 9px;
	z-index: 4;
}

.story-dots i {
	width: 2px;
	height: 28px;
	background: rgba( 255, 255, 255, 0.2 );
	transition: background 0.3s;
}

.story-dots i.on {
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
}

@media ( max-width: 1150px ) {
	.story-mid {
		position: absolute;
		top: 11%;
		left: 0;
		right: 0;
		width: auto;
		padding-inline: var( --wp--custom--gutter );
	}

	.story-cap {
		top: 41%;
		bottom: auto;
		max-width: 52ch;
	}

	.story-frame {
		width: 29.4% !important;
		top: 56% !important;
		height: 32% !important;
		aspect-ratio: auto !important;
		bottom: auto !important;
		right: auto !important;
		margin-bottom: 0 !important;
	}

	.story-step .story-frame:nth-of-type( 1 ) {
		left: 5% !important;
	}

	.story-step .story-frame:nth-of-type( 2 ) {
		left: 35.3% !important;
	}

	.story-step .story-frame:nth-of-type( 3 ) {
		left: 65.6% !important;
	}

	.story-sq {
		display: none;
	}
}

@media ( max-width: 760px ) {
	.story {
		height: 300svh;
	}

	.story-t {
		font-size: clamp( 1.75rem, 7vw, 2.5rem );
	}

	.story-cap {
		top: 44%;
		font-size: 0.9rem;
	}

	.story-frame {
		top: 58% !important;
		height: 28% !important;
	}
}

/* --------------------------------------------------------------------------
   FAQ accordion — base-2026.css 235-242
   -------------------------------------------------------------------------- */
.faq {
	max-width: 760px;
	margin-inline: auto;
}

.faq details {
	border-bottom: 1px dotted var( --wp--custom--rule-dotted );
}

.faq summary {
	cursor: pointer;
	padding: 20px 0;
	font-weight: 500;
	font-size: var( --wp--preset--font-size--lead );
	line-height: 1.4;
	list-style: none;
	display: flex;
	justify-content: space-between;
	gap: 16px;
	align-items: center;
	color: var( --wp--preset--color--contrast );
}

.faq summary::-webkit-details-marker {
	display: none;
}

.faq summary .pm {
	width: 26px;
	height: 26px;
	border: 1px solid var( --wp--custom--rule-dotted );
	display: grid;
	place-items: center;
	flex: none;
	transition: 0.2s;
	color: var( --wp--preset--color--muted );
	font-family: var( --font-mono );
	font-size: 0.95rem;
	line-height: 1;
}

.faq details[ open ] summary .pm {
	background: var( --wp--preset--color--accent );
	border-color: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	rotate: 45deg;
}

.faq p {
	color: var( --wp--preset--color--muted );
	padding-bottom: 22px;
	max-width: 64ch;
	font-size: var( --wp--preset--font-size--medium );
	line-height: 1.65;
	text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   Statement on dark — base-2026.css 244-250
   -------------------------------------------------------------------------- */
.stmt-dark {
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 1.7rem, 4.2vw, 3.5rem );
	line-height: 1.12;
	letter-spacing: -0.035em;
	color: #8d949c;
	margin: 0;
	max-width: 26em;
	text-wrap: pretty;
}

.stmt-dark .hlw {
	background: var( --wp--preset--color--contrast );
	color: var( --wp--preset--color--base );
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
	padding: 0 0.12em 0.06em;
}

.stmt-dark .hlb {
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
	padding: 0 0.12em 0.06em;
}

.stmt-dark .sq {
	display: inline-grid;
	place-items: center;
	width: 0.82em;
	height: 0.82em;
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	vertical-align: -0.04em;
	margin-right: 0.12em;
}

.stmt-dark .hlb .sq {
	background: var( --wp--preset--color--contrast );
	color: var( --wp--preset--color--accent );
}

.stmt-dark .sq svg {
	width: 62%;
	height: 62%;
}

/* --------------------------------------------------------------------------
   Blog module — base-2026.css 299-319
   -------------------------------------------------------------------------- */
.bl-head {
	display: flex;
	flex-wrap: wrap;
	gap: 18px;
	align-items: end;
	justify-content: space-between;
	margin-bottom: clamp( 24px, 3vw, 42px );
}

.bl-grid {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 16px;
}

@media ( max-width: 980px ) {
	.bl-grid {
		grid-template-columns: 1fr 1fr;
	}
}

@media ( max-width: 640px ) {
	.bl-grid {
		grid-template-columns: 1fr;
	}
}

.bl-card {
	display: flex;
	flex-direction: column;
	background: var( --wp--custom--app--bar );
	border: 1px solid var( --wp--custom--hairline );
	text-decoration: none;
	transition: border-color 0.25s, background 0.25s;
}

.bl-card:hover {
	border-color: rgba( 0, 194, 203, 0.45 );
	background: #0e1013;
}

.bl-media {
	position: relative;
	margin: 14px 14px 0;
	aspect-ratio: 16/9;
	background: #101216;
	overflow: hidden;
	--slot-bg: #101216;
}

.bl-media image-slot {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

.bl-cap {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	display: grid;
	grid-template-columns: 1fr auto;
	align-items: stretch;
	font-size: 0.92rem;
	color: var( --wp--preset--color--base );
	background: var( --wp--preset--color--contrast );
	pointer-events: none;
}

.bl-cap span {
	padding: 7px 10px;
	letter-spacing: -0.01em;
}

.bl-cap i {
	width: 30px;
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	display: grid;
	place-items: center;
}

.bl-cap i::after {
	content: "";
	width: 9px;
	height: 9px;
	background: var( --wp--preset--color--contrast );
}

.bl-body {
	padding: 18px 16px 16px;
	display: flex;
	flex-direction: column;
	flex: 1;
}

.bl-cats {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	font-size: 0.86rem;
	color: var( --wp--preset--color--accent );
}

.bl-card h3 {
	font-size: 1.08rem;
	font-weight: 400;
	line-height: 1.35;
	letter-spacing: -0.015em;
	color: var( --wp--preset--color--contrast );
	margin: 12px 0 0;
}

.bl-card p {
	font-size: 0.94rem;
	font-weight: 300;
	line-height: 1.5;
	color: #8d949c;
	margin: 10px 0 0;
}

.bl-meta {
	display: flex;
	gap: 20px;
	font-family: var( --font-mono );
	font-size: 0.72rem;
	letter-spacing: 0.04em;
	color: #7a828c;
	margin-top: 26px;
	padding-top: 0;
}

.bl-by {
	display: grid;
	grid-template-columns: auto auto;
	justify-content: start;
	align-items: center;
	gap: 8px;
	margin-top: 14px;
	padding-top: 14px;
	border-top: 1px dotted var( --wp--custom--rule-dotted );
	font-family: var( --font-mono );
	font-size: var( --wp--preset--font-size--mono-eyebrow );
	color: #cfd4da;
}

.bl-by i {
	width: 22px;
	height: 22px;
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	display: grid;
	place-items: center;
}

.bl-by i::after {
	content: "";
	width: 8px;
	height: 8px;
	background: var( --wp--preset--color--contrast );
}

/* --------------------------------------------------------------------------
   Legal / policy pages — base-2026.css 183-202
   -------------------------------------------------------------------------- */
.legal-hero {
	padding: clamp( 50px, 7vw, 110px ) 0 clamp( 46px, 7vw, 110px );
}

.legal-hero h1 {
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 2.6rem, 8vw, 6.2rem );
	line-height: 1;
	letter-spacing: -0.045em;
	color: var( --wp--preset--color--contrast );
	margin: 26px 0 0;
}

.legal-hero .breadcrumbs {
	margin-bottom: 16px;
}

.legal-row {
	display: grid;
	grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1.2fr );
	gap: clamp( 22px, 5vw, 80px );
	padding-block: clamp( 28px, 4vw, 56px );
	border-top: 1px dotted var( --wp--custom--rule-dotted );
}

.legal-row:last-child {
	border-bottom: 1px dotted var( --wp--custom--rule-dotted );
}

.legal-k {
	font-family: var( --font-mono );
	font-size: 0.72rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: #8d949c;
}

.legal-row h2 {
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 1.35rem, 2.4vw, 2rem );
	line-height: 1.15;
	letter-spacing: -0.025em;
	color: var( --wp--preset--color--contrast );
	margin: 0;
}

.legal-row h2 .legal-n {
	display: block;
	font-family: var( --font-mono );
	font-size: 0.68rem;
	letter-spacing: 0.14em;
	color: var( --wp--preset--color--accent );
	margin-bottom: 10px;
}

.legal-body > * {
	margin: 0 0 18px;
}

.legal-body > *:last-child {
	margin-bottom: 0;
}

.legal-body p,
.legal-body li {
	font-size: 1.02rem;
	font-weight: 300;
	line-height: 1.62;
	color: #8d949c;
	text-wrap: pretty;
}

.legal-body strong {
	color: #eef0f4;
	font-weight: 400;
}

.legal-body a {
	color: var( --wp--preset--color--accent-bright );
}

.legal-body ul,
.legal-body ol {
	padding-left: 1.1em;
	display: flex;
	flex-direction: column;
	gap: 9px;
}

.legal-body h3 {
	font-size: var( --wp--preset--font-size--lead );
	font-weight: 400;
	color: var( --wp--preset--color--contrast );
	margin: 26px 0 10px;
}

.legal-body table {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.94rem;
}

.legal-body th,
.legal-body td {
	text-align: left;
	padding: 10px 12px;
	border-bottom: 1px dotted var( --wp--custom--rule-dotted );
	color: #8d949c;
	font-weight: 300;
}

.legal-body th {
	color: #eef0f4;
	font-weight: 400;
}

@media ( max-width: 800px ) {
	.legal-row {
		grid-template-columns: 1fr;
		gap: 14px;
	}
}

/* --------------------------------------------------------------------------
   Animated line illustrations — base-2026.css 355-389
   -------------------------------------------------------------------------- */
.illu {
	margin-top: 18px;
	background: var( --wp--custom--app--illu-ground );
	border: 1px solid rgba( 255, 255, 255, 0.06 );
	aspect-ratio: 2/1;
	display: grid;
	place-items: center;
	overflow: hidden;
}

.illu svg {
	width: 100%;
	height: 100%;
	display: block;
}

.illu .fl {
	stroke: rgba( 255, 255, 255, 0.16 );
	stroke-dasharray: 2 4;
	fill: none;
}

.illu .ln {
	stroke: var( --wp--preset--color--accent );
	fill: none;
	stroke-linejoin: round;
	stroke-linecap: round;
}

.illu .dim {
	stroke: rgba( 255, 255, 255, 0.28 );
	fill: none;
	stroke-linejoin: round;
}

.illu .fill {
	fill: var( --wp--preset--color--accent );
	stroke: none;
}

@media ( prefers-reduced-motion: no-preference ) {
	.illu .a-float {
		animation: illuFloat 4.6s ease-in-out infinite alternate;
	}

	.illu .a-float2 {
		animation: illuFloat 5.4s ease-in-out infinite alternate;
		animation-delay: -1.6s;
	}

	.illu .a-float3 {
		animation: illuFloat 6.2s ease-in-out infinite alternate;
		animation-delay: -3s;
	}

	.illu .a-travel {
		animation: illuTravel 3.4s ease-in-out infinite;
	}

	.illu .a-ring {
		animation: illuRing 2.8s ease-out infinite;
		transform-origin: 160px 84px;
	}

	.illu .a-ring2 {
		animation: illuRing 2.8s ease-out infinite;
		animation-delay: -0.9s;
		transform-origin: 160px 84px;
	}

	.illu .a-ring3 {
		animation: illuRing 2.8s ease-out infinite;
		animation-delay: -1.8s;
		transform-origin: 160px 84px;
	}

	.illu .a-dash {
		stroke-dasharray: 6 6;
		animation: illuDash 1.6s linear infinite;
	}

	.illu .a-slide {
		animation: illuSlide 4s ease-in-out infinite;
	}

	.illu .a-draw {
		stroke-dasharray: 120;
		stroke-dashoffset: 120;
		animation: illuDraw 3.2s ease-in-out infinite;
	}

	.illu .a-draw2 {
		stroke-dasharray: 120;
		stroke-dashoffset: 120;
		animation: illuDraw 3.2s ease-in-out infinite;
		animation-delay: -0.5s;
	}

	.illu .a-draw3 {
		stroke-dasharray: 120;
		stroke-dashoffset: 120;
		animation: illuDraw 3.2s ease-in-out infinite;
		animation-delay: -1s;
	}

	.illu .a-bar {
		animation: illuBar 2.4s ease-in-out infinite alternate;
		transform-origin: center bottom;
	}

	.illu .a-bar2 {
		animation: illuBar 2.4s ease-in-out infinite alternate;
		animation-delay: -0.8s;
		transform-origin: center bottom;
	}

	.illu .a-bar3 {
		animation: illuBar 2.4s ease-in-out infinite alternate;
		animation-delay: -1.6s;
		transform-origin: center bottom;
	}

	.illu .a-travelx {
		animation: illuTravelX 4s linear infinite;
	}

	.illu .a-travelx2 {
		animation: illuTravelX 4s linear infinite;
		animation-delay: -1.35s;
	}

	.illu .a-travelx3 {
		animation: illuTravelX 4s linear infinite;
		animation-delay: -2.7s;
	}
}

@keyframes illuFloat {
	to {
		transform: translateY( -7px );
	}
}

@keyframes illuTravelX {
	0% {
		transform: translate( -60px, 30px );
		opacity: 0;
	}

	12% {
		opacity: 1;
	}

	82% {
		opacity: 1;
	}

	100% {
		transform: translate( 62px, -31px );
		opacity: 0;
	}
}

@keyframes illuTravel {
	0% {
		transform: translateY( 0 );
		opacity: 0;
	}

	12% {
		opacity: 1;
	}

	88% {
		opacity: 1;
	}

	100% {
		transform: translateY( 34px );
		opacity: 0;
	}
}

@keyframes illuRing {
	0% {
		transform: scale( 0.35 );
		opacity: 0.9;
	}

	100% {
		transform: scale( 1.5 );
		opacity: 0;
	}
}

@keyframes illuDash {
	to {
		stroke-dashoffset: -24;
	}
}

@keyframes illuSlide {
	0%,
	100% {
		transform: translateY( 0 );
	}

	50% {
		transform: translateY( -16px );
	}
}

@keyframes illuDraw {
	0% {
		stroke-dashoffset: 120;
	}

	45%,
	100% {
		stroke-dashoffset: 0;
	}
}

@keyframes illuBar {
	to {
		transform: scaleY( 0.45 );
	}
}

.fx-off .illu *,
.illu.fx-off * {
	animation-play-state: paused !important;
}

/* --------------------------------------------------------------------------
   Contact CTA band + floating contact pill — styles.css 1772-1798
   (the handoff injected both via site.js)
   -------------------------------------------------------------------------- */
.contact-band {
	background: #0b0d12;
	padding-block: clamp( 84px, 10vw, 150px );
}

.contact-band .in {
	max-width: 1440px;
	margin-inline: auto;
	padding-inline: var( --wp--custom--content-inset );
	display: grid;
	grid-template-columns: 1.5fr 1fr;
	gap: clamp( 32px, 5vw, 80px );
	align-items: end;
}

@media ( max-width: 860px ) {
	.contact-band .in {
		grid-template-columns: 1fr;
		gap: 32px;
	}
}

.contact-band h2 {
	font-size: clamp( 40px, 5vw, 76px );
	font-weight: 300;
	line-height: 1.02;
	letter-spacing: -0.03em;
	color: var( --wp--preset--color--contrast );
	margin-top: 26px;
	text-wrap: balance;
}

.contact-band .side {
	font-size: 15.5px;
	line-height: 1.65;
	color: var( --slate );
	max-width: 400px;
}

.contact-band .cta {
	margin-top: 36px;
}

.contact-pill {
	position: fixed;
	right: 28px;
	bottom: 28px;
	z-index: 90;
	display: inline-flex;
	align-items: center;
	gap: 8px;
	background: #f3f1ed;
	color: #0b0d12;
	border-radius: 999px;
	padding: 16px 28px;
	font-size: 14.5px;
	font-weight: 500;
	box-shadow: 0 10px 30px rgba( 0, 0, 0, 0.45 );
	transition: background 0.2s, transform 0.2s;
}

.contact-pill:hover {
	background: var( --wp--preset--color--contrast );
	transform: translateY( -1px );
}

@media ( max-width: 700px ) {
	.contact-pill {
		right: 16px;
		bottom: 16px;
		padding: 13px 20px;
		font-size: 13.5px;
	}
}

/* --------------------------------------------------------------------------
   Status page — styles.css 718-754. Rendered through kepler_status_*().
   The green here is the status palette, not the brand accent; it is
   deliberately untouched by the theme layers.
   -------------------------------------------------------------------------- */
.status-banner {
	display: flex;
	align-items: center;
	gap: 16px;
	padding: 22px 26px;
	border-radius: 0;
	border: 1px solid var( --wp--custom--wash--medium );
	background: var( --wp--custom--wash--soft );
}

.status-banner .dot-lg {
	width: 16px;
	height: 16px;
	border-radius: 50%;
	background: #1b8a5a;
	flex: none;
	box-shadow: none;
	position: relative;
}

.status-banner.up .dot-lg {
	background: #1b8a5a;
}

.status-banner .dot-lg::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: inherit;
	animation: statusPulse 2s infinite;
}

@keyframes statusPulse {
	0% {
		transform: scale( 1 );
		opacity: 0.7;
	}

	100% {
		transform: scale( 2.6 );
		opacity: 0;
	}
}

@media ( prefers-reduced-motion: reduce ) {
	.status-banner .dot-lg::after {
		animation: none;
	}
}

.status-banner .st-t {
	font-weight: 700;
	font-size: 1.15rem;
	color: var( --wp--preset--color--contrast );
}

.status-banner .st-d {
	color: var( --wp--custom--status--ok );
	font-size: 0.9rem;
	margin-top: 2px;
}

.status-banner .st-time {
	margin-left: auto;
	font-family: var( --font-mono );
	font-size: 0.78rem;
	color: var( --slate-2 );
	text-align: right;
}

.svc-list {
	border: 1px solid var( --line );
	border-radius: 0;
	overflow: hidden;
	margin-top: 24px;
}

.svc {
	display: grid;
	grid-template-columns: 1.3fr 2fr auto;
	gap: 18px;
	align-items: center;
	padding: 16px 22px;
	border-top: 1px solid var( --line-2 );
}

.svc:first-child {
	border-top: none;
}

.svc .svc-nm {
	font-weight: 500;
}

.svc .svc-nm small {
	display: block;
	color: var( --slate-2 );
	font-weight: 400;
	font-size: 0.8rem;
	margin-top: 2px;
}

.svc .bars {
	display: flex;
	gap: 2px;
	height: 28px;
	align-items: stretch;
	/* appui.css .bars (the KPI chart) is page-scoped in the handoff but global
	   in the theme; the uptime bars must not inherit its 16px chart padding. */
	padding: 0;
}

.svc .bars i {
	flex: 1;
	border-radius: 2px;
	background: #35b877;
	opacity: 0.9;
}

.svc .bars i.warn {
	background: #e0a32e;
}

.svc .bars i.down {
	background: #c0392b;
}

.svc .svc-up {
	font-family: var( --font-mono );
	font-size: 0.82rem;
	color: var( --wp--custom--status--ok );
	font-weight: 500;
	text-align: right;
}

.svc .pill-op {
	font-size: 0.72rem;
	font-weight: 500;
	color: var( --wp--custom--status--ok );
	background: var( --wp--custom--wash--soft );
	border: 1px solid var( --wp--custom--wash--medium );
	padding: 4px 10px;
	border-radius: 999px;
	white-space: nowrap;
}

@media ( max-width: 640px ) {
	.svc {
		grid-template-columns: 1fr auto;
	}

	.svc .bars {
		display: none;
	}
}

.metric-grid {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 16px;
	margin-top: 24px;
}

@media ( max-width: 640px ) {
	.metric-grid {
		grid-template-columns: 1fr;
	}
}

.metric {
	border: 1px solid var( --line );
	border-radius: 0;
	padding: 22px;
}

.metric .mk {
	font-family: var( --font-mono );
	font-size: 0.76rem;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var( --slate-2 );
}

.metric .mv {
	font-family: var( --font-display );
	font-weight: 700;
	font-size: 2rem;
	letter-spacing: -0.03em;
	margin-top: 8px;
}

.metric .mv .unit {
	color: var( --emerald );
}

.incident {
	display: flex;
	gap: 16px;
	padding: 18px 0;
	border-top: 1px solid var( --line-2 );
}

.incident:first-child {
	border-top: none;
}

.incident .when {
	font-family: var( --font-mono );
	font-size: 0.8rem;
	color: var( --slate-2 );
	width: 120px;
	flex: none;
}

.incident .what strong {
	color: var( --wp--preset--color--contrast );
}

.incident .what p {
	color: var( --slate );
	font-size: 0.9rem;
	margin-top: 4px;
}

.incident .badge-res {
	font-size: 0.68rem;
	font-weight: 700;
	color: var( --wp--custom--status--ok );
	background: var( --wp--custom--wash--soft );
	border: 1px solid var( --wp--custom--wash--medium );
	padding: 2px 8px;
	border-radius: 999px;
	display: inline-block;
	margin-bottom: 6px;
}

/* --------------------------------------------------------------------------
   Document blocks — styles.css 686-715, still used by the doc-style pages
   -------------------------------------------------------------------------- */
.doc {
	max-width: 800px;
	margin-inline: auto;
}

.doc-lead {
	font-size: 1.1rem;
	color: var( --slate );
	margin-top: 18px;
	line-height: 1.6;
	max-width: 64ch;
}

.doc-section strong,
.doc-table td strong {
	color: var( --wp--preset--color--contrast );
}

.doc-section a {
	color: var( --mint-bright );
}

.doc-table {
	width: 100%;
	border-collapse: collapse;
	margin-top: 18px;
	border: 1px solid var( --line );
	border-radius: 0;
	overflow: hidden;
	font-size: 0.9rem;
}

.doc-table th {
	text-align: left;
	background: rgba( 255, 255, 255, 0.04 );
	padding: 12px 16px;
	font-size: 0.72rem;
	font-family: var( --font-mono );
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var( --slate-2 );
	font-weight: 500;
	border-bottom: 1px solid var( --line-2 );
}

.doc-table td {
	padding: 13px 16px;
	border-bottom: 1px solid var( --line-2 );
	color: var( --slate );
	vertical-align: top;
}

.doc-table tr:last-child td {
	border-bottom: none;
}

/* legacy lime residue — styles.css:984/985, never overridden. No token. */
.doc-callout {
	display: flex;
	gap: 14px;
	padding: 18px 20px;
	border-radius: 0;
	background: rgba( 189, 231, 99, 0.12 );
	border: 1px solid rgba( 189, 231, 99, 0.3 );
	margin-top: 20px;
}

.doc-callout .ic {
	flex: none;
}

.doc-callout .ic svg {
	width: 20px;
	height: 20px;
}

.doc-callout p,
.doc-callout .ic {
	color: #a9e6c2;
}

.doc-callout p {
	margin-top: 0;
	font-size: 0.92rem;
}

/* --------------------------------------------------------------------------
   Page-module overrides
   These selectors' base rules used to live only in the handoff pages' own
   <style> blocks (out of scope for the first port pass). That third cascade
   layer — 37 pages, ~100 KB — is now ported below, section by section. What
   follows immediately below (radius 0 / monochrome flattening) is the part
   that already lived in the shared sheets and won the cascade before any of
   that inline layer existed.
   -------------------------------------------------------------------------- */

/* timeline fill — was an inline style="width:75%" in the prototype */
.tl .bar i,
.tl4 .bar i {
	width: var( --tl-fill, 100% );
}

/* Two-column split wrapping a mockup. 1000px, NOT 900px: `.app-scroll .app-tbl`
   takes min-width: 660px below 1000px (appui.css:109), so the split has to be
   full width by then. `.ep .note` rides along in the same query. */
@media ( max-width: 1000px ) {
	.split2 {
		grid-template-columns: 1fr;
	}

	.ep .note {
		display: none;
	}
}

.field input,
.field select,
.field textarea,
.lf-input,
.chat-input input {
	border-radius: 0 !important;
}

.field input,
.field select,
.field textarea,
.lf-input,
.chat-input input,
.addbar input,
.addbar select {
	background: rgba( 255, 255, 255, 0.05 ) !important;
	border-color: rgba( 255, 255, 255, 0.16 ) !important;
}

.field input,
.field select,
.field textarea {
	color: var( --ink );
}

.field select option {
	background: #131514;
	color: var( --ink );
}

.toggle-bill,
.toggle-bill button,
.seg,
.seg button,
.chan,
.chan button,
.chip {
	border-radius: 0 !important;
}

/*
 * Selected contract length. The design put dark text on a light chip; the V3
 * retint kept the dark text but moved the chip to rgba(255,255,255,.08), which
 * on this near-black page rendered #0b0d12 on almost-black — the selected
 * option was effectively invisible (owner report, 2026-08-10).
 *
 * Accent fill with white text instead, and a small step up in weight and size
 * so the selection reads at a glance rather than only on inspection.
 */
.toggle-bill button.active {
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent ) !important;
	font-size: 1.06em;
	font-weight: 500;
	padding-inline: 20px;
}

.plan.feat {
	border-color: rgba( 255, 255, 255, 0.34 ) !important;
}

.plan.feat::before {
	/* priser.html:20 — verified rgb( 0, 208, 143) bg / rgb(232,234,238) text on
	   the live render; neither is fought by an !important rule. */
	border-radius: 0;
	background: var( --mint );
	color: var( --ink );
}

.tick.yes {
	/* jamfor-*.html — background wins from the inline rule (verified
	   rgb( 0, 208, 143)); the dark text is forced !important by styles.css and
	   is unaffected — verified rgb(11,13,18) on the live render. */
	background: var( --mint );
	color: #0b0d12 !important;
	border-radius: 0;
}

.tick.no {
	/* jamfor-*.html — verified rgb(14,14,14) bg / rgb(106,112,124) text on
	   the live render, neither fought by an !important rule. */
	background: var( --paper-3 );
	color: var( --slate-2 );
	border-radius: 0;
}

.tick.mid {
	/* jamfor-*.html — sole definition, no shared-sheet conflict. */
	background: rgba( 214, 78, 78, 0.16 );
	color: var( --wp--custom--status--partial );
}

.step .n,
.mig-step .num,
.flow-step .n,
.tl-step .dot,
.lead-box .chat-ava,
.tck,
.hero-meta .tck {
	background: var( --wp--preset--color--contrast ) !important;
	color: #0c0d0e !important;
	border-radius: 2px !important;
}

/* Size/shape the !important overrides above don't touch — the inline sheets
   never conflicted on these properties, so they still need porting. */
.step .n,
.flow-step .n {
	width: 36px;
	height: 36px;
	display: grid;
	place-items: center;
	font-weight: 500;
}

/*
 * .tl-step .dot was missed out of the port above. It got its colour and
 * 2px radius from the !important block, but no width, height or display —
 * so the badge stretched to the full grid column and the number sat at its
 * left edge. Values from the design (light.html:22), minus the mint fill and
 * 50% radius that the V3 retint deliberately overrides.
 *
 * z-index:1 is load-bearing: .tl-step::after draws the connector line at
 * z-index 0 across the full column, and without this it runs over the badge.
 */
.tl-step .dot {
	width: 30px;
	height: 30px;
	display: grid;
	place-items: center;
	font-family: var( --font-display );
	font-size: 0.9rem;
	font-weight: 800;
	position: relative;
	z-index: 1;
}

.mig-step .num {
	width: 34px;
	height: 34px;
	display: grid;
	place-items: center;
	font-family: var( --font-display );
	font-weight: 700;
	border: 1px solid var( --mint-soft );
}

.diff .n,
.sync-dir,
.pv-kpi .k,
.kpi .k {
	color: var( --wp--preset--color--contrast ) !important;
}

.glass-quote {
	box-shadow: none !important;
	backdrop-filter: none !important;
}

.gq-chip {
	background: transparent !important;
	border: 1px solid rgba( 255, 255, 255, 0.2 ) !important;
	border-radius: 2px !important;
	color: var( --slate ) !important;
}

.gq-chip::before {
	background: var( --wp--preset--color--contrast ) !important;
	box-shadow: none !important;
}

.lead-box.chat,
.form-card {
	box-shadow: 0 24px 70px rgba( 0, 0, 0, 0.45 ) !important;
}

.code-block,
.code-snip {
	background: #131110 !important;
}

/* Comparison tables on the jamfor-* pages. The base `.ctable` rules live in
   those pages' <style> blocks; these are the shared-sheet winners. */
.compare-col-us,
.ctable .col-us {
	background: rgba( 255, 255, 255, 0.055 ) !important;
	border-inline-color: rgba( 255, 255, 255, 0.16 ) !important;
}

.ctable .head .col-us {
	background: var( --wp--preset--color--contrast ) !important;
	color: #0c0d0e !important;
	border-color: var( --wp--preset--color--contrast ) !important;
}

.ctable .head .col-us .sub {
	color: rgba( 12, 13, 14, 0.62 ) !important;
}

/* image-slot custom element defaults on dark — styles.css 1005-1010 */
image-slot {
	--slot-fg: rgba( 255, 255, 255, 0.62 );
	--slot-fg-hover: rgba( 255, 255, 255, 0.92 );
	--slot-bg: rgba( 255, 255, 255, 0.05 );
	--slot-ring: rgba( 255, 255, 255, 0.3 );
}

/* --------------------------------------------------------------------------
   Comparison hero + table — the jamfor-* pages (4 pages: jamfor-magento,
   jamfor-nordiska, jamfor-shopify, jamfor-woocommerce). Byte-identical inline
   <style> blocks on all four — this is the .ctable content the design
   handoff's own docblock claim (corrected in comparison/render.php) got
   wrong: it renders on the 2026 dark/blue palette, not a light legacy one.
   Verified: .ctable background rgb(10,10,10), .tick.yes rgb( 0, 208, 143).
   -------------------------------------------------------------------------- */
.vs {
	display: inline-flex;
	align-items: center;
	gap: 18px;
	margin-top: 28px;
}

.vs .side {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 10px;
}

.vs .logo-chip {
	width: 80px;
	height: 80px;
	border-radius: 0;
	display: grid;
	place-items: center;
	font-family: var( --font-display );
	font-weight: 700;
	font-size: 1.6rem;
}

.vs .us {
	background: var( --ink );
	color: var( --mint );
	border: 1px solid var( --line );
	box-shadow: var( --shadow-md );
}

.vs .them {
	background: var( --paper-2 );
	color: var( --slate-2 );
	border: 1px solid var( --line );
}

.vs .vs-word {
	font-family: var( --font-mono );
	font-size: 0.9rem;
	color: var( --slate-2 );
	letter-spacing: 0.1em;
}

.vs .side small {
	font-size: 0.8rem;
	color: var( --slate );
}

.ctable {
	/* border-radius already forced to 0 by the shared .card-family rule above */
	border: 1px solid var( --line );
	overflow: hidden;
	box-shadow: var( --shadow-md );
	background: var( --paper );
}

.ctable .grp {
	display: grid;
	grid-template-columns: 1.4fr 1fr 1fr;
}

.ctable .grp.head {
	position: relative;
	z-index: 2;
}

.ctable .ch {
	padding: 16px 22px;
	font-size: 0.95rem;
	display: flex;
	align-items: center;
	gap: 9px;
	border-top: 1px solid var( --line-2 );
}


.ctable .grp:first-child .ch {
	border-top: none;
}

.ctable .ch.lab {
	font-weight: 500;
	flex-direction: column;
	align-items: flex-start;
	justify-content: center;
	gap: 3px;
}

.ctable .ch.lab small {
	font-weight: 400;
	color: var( --slate );
	font-size: 0.82rem;
}

/* .ctable .col-us (non-head rows) and .ctable .head .col-us/.sub are already
   overridden further down this file — that override wins the lime retirement
   and is unaffected by the rules above. */

.ctable .head .ch {
	background: var( --paper-2 );
	font-family: var( --font-display );
	font-weight: 700;
	font-size: 1.05rem;
	flex-direction: column;
	align-items: flex-start;
	justify-content: center;
	gap: 0;
}

.ctable .head .ch .sub {
	display: block;
	font-family: var( --font-mono );
	font-weight: 400;
	font-size: 0.66rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var( --slate-2 );
	margin-top: 4px;
}

.section-label {
	padding: 13px 22px;
	background: var( --paper-3 );
	font-family: var( --font-mono );
	font-size: 0.72rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var( --slate );
	grid-column: 1/-1;
	border-top: 1px solid var( --line-2 );
}

.tick {
	width: 22px;
	height: 22px;
	border-radius: 50%;
	display: grid;
	place-items: center;
	flex: none;
}

.tick svg {
	width: 13px;
	height: 13px;
}

.ch .val-txt {
	font-size: 0.9rem;
}

.col-us .val-txt {
	font-weight: 500;
}

@media ( max-width: 760px ) {
	/*
	 * 13px of side padding still overflowed a 375px phone: measured on
	 * /jamfor-magento/, scrollWidth 361 against clientWidth 329, so 32px of
	 * the third column was unreachable. `.ctable` inherits overflow:hidden
	 * from the design, where it clipped the rounded corners — V3 forces
	 * border-radius:0 (line 90), so it now only hides content and there is no
	 * scrollbar to recover it.
	 *
	 * Tightening the cells beats letting the table scroll sideways: a
	 * comparison only does its job when the columns are read together.
	 */
	.ctable .ch {
		padding: 12px 7px;
		font-size: 0.82rem;
		gap: 6px;
		min-width: 0;
		overflow-wrap: anywhere;
	}

	.ctable .ch.lab small,
	.ch .val-txt {
		font-size: 0.76rem;
	}
}

.tco {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 18px;
}

@media ( max-width: 760px ) {
	.tco {
		grid-template-columns: 1fr;
	}
}

.tco-card {
	/* border-radius: 0 — marketing layer */
	padding: 30px;
	border: 1px solid var( --line );
}

.tco-card.us {
	background: var( --dark );
	color: var( --on-dark );
	border: none;
}

.tco-card.them {
	background: var( --paper-2 );
}

.tco-card h3 {
	font-size: 1.3rem;
}

.tco-card .big {
	font-family: var( --font-display );
	font-weight: 700;
	font-size: clamp( 2.4rem, 5vw, 3.4rem );
	letter-spacing: -0.04em;
	margin-top: 14px;
	line-height: 1;
}

.tco-card.us .big span {
	color: var( --mint );
}

.tco-card ul {
	margin-top: 22px;
	display: flex;
	flex-direction: column;
	gap: 12px;
}

.tco-card li {
	display: flex;
	gap: 10px;
	font-size: 0.92rem;
	align-items: flex-start;
}

.tco-card.us li {
	color: var( --on-dark-mut );
}

.tco-card .li-ic {
	flex: none;
	margin-top: 2px;
}

.mig-steps {
	display: grid;
	grid-template-columns: repeat( 4, 1fr );
	gap: 16px;
	counter-reset: s;
}

@media ( max-width: 860px ) {
	.mig-steps {
		grid-template-columns: 1fr 1fr;
	}
}

.mig-step {
	/* border-radius: 0 — marketing layer (was 10px) */
	padding: 24px;
	border: 1px solid var( --line );
	background: var( --paper );
	position: relative;
}

.mig-step h4 {
	font-size: 1.05rem;
	margin-top: 16px;
}

.mig-step p {
	color: var( --slate );
	font-size: 0.88rem;
	margin-top: 8px;
}

/* `.faq` variant — jamfor-magento.html, jamfor-nordiska.html,
   jamfor-shopify.html, jamfor-woocommerce.html and priser.html (5 of the 20
   `.faq` pages) redeclare `.faq` with a centred column, a bolder question
   and an inverted open-state pm; that collides with the shared `.faq` above,
   which the other 14 (now 15) pages depend on. Scoped here as a modifier
   class instead of overriding the bare selector, toggled by the FAQ block's
   Style field. integration-fortnox.html's own `.faq` override is not part
   of this variant: its values resolve to the same tokens as the shared rule
   above (--mint/accent, weight 500) and its only real differences — a
   dotted vs solid divider, a literal vs token colour — are sub-pixel drift,
   not a second distinct reading, so it renders from the shared rule. */
.faq-centered {
	max-width: 760px;
	margin-inline: auto;
}

.faq-centered summary {
	/* Satoshi has no 600 weight — the design's font-weight:600 rounds up
	   from the shared rule's 500, the heaviest step actually available. */
	font-weight: 500;
}

.faq-centered details[ open ] summary .pm {
	background: var( --wp--custom--ink );
	border-color: var( --wp--custom--ink );
	/* The design pairs this fill with color:#fff (white-on-#e8eaee — the "+"
	   glyph would be all but invisible on our single dark theme, which never
	   flips --ink dark). Using the dark base colour here keeps the glyph
	   readable without changing the fill the 5 pages actually specify. */
	color: var( --wp--preset--color--base );
}

/* --------------------------------------------------------------------------
   Two-up mockup wrapper — .split2 base rule. 7 pages, byte-identical:
   api-nycklar, b2b, cms, search-api, self-hosted, seo, solaris. The 1000px
   collapse already lives above this section (css-port-notes.md); this is
   only the missing base grid.
   -------------------------------------------------------------------------- */
.split2 {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: clamp( 24px, 3vw, 44px );
	align-items: start;
}

/* --------------------------------------------------------------------------
   Endpoint list box — `.ep`. Lives only in each page's own inline <style>
   (api-nycklar.html:18-24, search-api.html:32-37), never in the shared
   sheets, and only `.ep .note`'s 1000px hide made it into the port before
   now (see the media query below) — the base box was missing entirely, so
   the split_pair "endpoints" panel rendered the right classes with no
   visible box. api-nycklar adds `.ep .m.del`; search-api has no DEL rows
   but is otherwise byte-identical, so `.m.del` is carried here as the
   superset.
   `.ep-terms` is a necessary addition, not a verbatim design class: solaris
   (solaris.html:107-119) reuses the same box rhythm for a hook glossary
   (`<b>useProduct</b><span>…description…</span>`) but hand-inlines every
   property on every row instead of using `.m`/`.note` — the CLAUDE.md "no
   inline style rules" rule forbids reproducing that, and the design has no
   class to reuse for this specific reading, so `.ep-terms` is the least
   invented way to carry it: one modifier on the container `.ep` already
   owns, `<b>`/bare `<span>` beneath it exactly like the source.
   -------------------------------------------------------------------------- */
.ep {
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.ep > div {
	display: flex;
	align-items: center;
	gap: 12px;
	background: #0a0a0a;
	border: 1px solid rgba( 255, 255, 255, 0.08 );
	padding: 13px 15px;
	font-family: var( --font-mono );
	font-size: 0.78rem;
	color: #c8cdd6;
}

.ep .m {
	font-size: 0.66rem;
	letter-spacing: 0.08em;
	padding: 3px 8px;
	border: 1px solid;
	flex: 0 0 auto;
}

.ep .m.get {
	color: #5fe9bd;
	border-color: rgba( 0, 194, 203, 0.45 );
	background: rgba( 0, 194, 203, 0.1 );
}

.ep .m.post {
	color: #8ff0b0;
	border-color: rgba( 120, 230, 160, 0.4 );
	background: rgba( 120, 230, 160, 0.08 );
}

.ep .m.del {
	color: #e88f8f;
	border-color: rgba( 232, 143, 143, 0.4 );
	background: rgba( 232, 143, 143, 0.08 );
}

/* solaris.html:157 inlines `margin-top:24px` on its `.ep` container so the
   glossary clears the lead above it — same inline-margin-to-class port as
   `.ep-outro` below. Scoped to the terms modifier, NOT a generic `.lead + .ep`
   rule: search-api.html:84-85 places `.ep` flush after a lead with no margin,
   and solaris is the only page that uses the terms reading. */
.ep-terms {
	margin-top: 24px;
}

.ep-terms > div {
	align-items: baseline;
	gap: 14px;
}

.ep-terms b {
	font-family: var( --font-mono );
	font-size: 0.78rem;
	color: #5fe9bd;
	font-weight: 400;
	flex: 0 0 auto;
}

.ep-terms > div > span {
	font-size: 0.84rem;
	color: #9aa2ac;
}

/* api-nycklar.html:132 follows `.ep` with a `<p class="lead" style="margin-
   top:22px">` — the 22px override carried as a class for the same "no inline
   styles" reason as everything else in this section. `.lead`'s own type
   already comes from the shared rule; only the spacing is added here. */
.ep-outro {
	margin-top: 22px;
}

/* --------------------------------------------------------------------------
   Flat endpoint rows appended inside a split_pair text column — erp-api.html
   (:62-66), enrichment-api.html and utvecklare.html all wrap their
   `.endpoint` rows in an inline `style="display:flex;flex-direction:column;
   gap:10px;margin-top:24px"` div with no class. Same "no inline styles" call
   as `.ep-terms` above: `.endpoint-list` is the container class this needs,
   since none exists in the source to reuse.
   -------------------------------------------------------------------------- */
.endpoint-list {
	display: flex;
	flex-direction: column;
	gap: 10px;
	margin-top: 24px;
}

/* --------------------------------------------------------------------------
   Quote + checklist split — gap G19. 5 pages, byte-identical: b2b, b2c,
   integration-business-central, integration-fortnox, integration-skrym.
   `.glass-quote`'s radius/box-shadow/::after are already forced off by the
   shared card-family rule and the decorative-bloom kill switch above; this
   is the rest of the component.
   -------------------------------------------------------------------------- */
.brace-split {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: clamp( 32px, 5vw, 72px );
	align-items: center;
}

@media ( max-width: 840px ) {
	.brace-split {
		grid-template-columns: 1fr;
	}
}

/* background and border are already forced (transparent / 1px solid
   var(--line), both !important) by the shared .card-family rule above —
   inline's own gradient background and rgba(255,255,255,.09) border never
   reach the screen, so neither is repeated here. */
.glass-quote {
	position: relative;
	padding: clamp( 28px, 3.5vw, 44px );
	overflow: hidden;
}

.glass-quote::before {
	content: "";
	position: absolute;
	inset: 0;
	padding: 1px;
	border-radius: inherit;
	background: linear-gradient( 150deg, rgba( 0, 194, 203, 0.5 ), rgba( 0, 194, 203, 0.05 ) 40%, rgba( 255, 255, 255, 0.05 ) );
	-webkit-mask: linear-gradient( #000 0 0 ) content-box, linear-gradient( #000 0 0 );
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	pointer-events: none;
}

.glass-quote .gq-text {
	font-size: clamp( 1.2rem, 1.9vw, 1.55rem );
	font-weight: 300;
	line-height: 1.45;
	color: var( --slate );
	position: relative;
	z-index: 1;
	text-wrap: balance;
}

.glass-quote .gq-text strong {
	color: var( --wp--preset--color--contrast );
	font-weight: 500;
}

.glass-quote .gq-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 24px;
	position: relative;
	z-index: 1;
}

/*
 * The chip's own box. This note used to say padding/background/border/font
 * "are already overridden further down this file" — they are not. The rule
 * further down (.gq-chip, ~line 3880) sets background, border, radius and
 * colour only, so padding, display and font-size were never ported from
 * b2c.html:26 and the chips rendered as bare text jammed inside a 1px
 * outline. Same for the leading dot: b2c.html:27 gives ::before its content
 * and size, and only its colour was carried over, so no dot appeared at all.
 *
 * Square corners are deliberate — the marketing layer overrides the design's
 * 999px pill radius everywhere, so that one declaration is not restored here.
 */
.glass-quote .gq-chip {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 8px 15px;
	font-size: 0.84rem;
	font-weight: 400;
}

.glass-quote .gq-chip::before {
	content: "";
	width: 6px;
	height: 6px;
	border-radius: 50%;
	flex: none;
}

/* --------------------------------------------------------------------------
   Co-brand lockup — gap G21. 3 pages: integration-business-central,
   integration-fortnox, integration-skrym. Near-identical; the canonical
   values below are the majority (2-of-3) reading for any property that
   differs — cb-partner's border-radius/font-size vary by a px each, cb-hdl's
   margin-top only on integration-skrym.
   -------------------------------------------------------------------------- */
.cobrand {
	display: inline-flex;
	align-items: center;
	gap: clamp( 14px, 2.5vw, 24px );
	flex-wrap: wrap;
}

.cobrand .cb-hdl {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	font-weight: 500;
	font-size: 1.1rem;
	color: var( --ink );
}

.cobrand .cb-hdl svg {
	width: 36px;
	height: auto;
	color: var( --mint-bright );
}

.cobrand .x {
	font-family: var( --font-mono );
	color: var( --slate-2 );
	font-size: 1.05rem;
}

.cobrand .cb-partner {
	font-weight: 500;
	font-size: 1.2rem;
	letter-spacing: -0.01em;
	color: var( --ink );
	padding: 9px 18px;
	border: 1px solid var( --line );
	background: var( --paper-2 );
	/* border-radius: 0 — marketing layer (was 12px) */
}

.cobrand .cb-partner small {
	display: block;
	font-weight: 400;
	font-size: 0.66rem;
	color: var( --slate-2 );
	letter-spacing: 0.04em;
	text-transform: uppercase;
	margin-bottom: 2px;
}

/* --------------------------------------------------------------------------
   Sync direction label — 4 pages byte-identical (b2b, b2c,
   integration-business-central, integration-skrym); integration-fortnox
   reaches the same rendered result with an extra `.card .sync-dir` selector
   instead of `display:block` inline, so this single rule covers all 5.
   Colour is already overridden further down this file.
   -------------------------------------------------------------------------- */
.sync-dir {
	font-family: var( --font-mono );
	font-size: 0.68rem;
	letter-spacing: 0.08em;
	margin-bottom: 14px;
	display: block;
}

/* --------------------------------------------------------------------------
   Legacy 3-up steps — distinct from the `steps` block's `.steps3` variant.
   4 pages, byte-identical: erp-api, integration-business-central,
   integration-fortnox, integration-skrym. Documented gap (marketing-features
   §1 row 4): "a different legacy .steps > .step > .n markup", not modelled
   by any block, but shared identically across all 4 pages.
   -------------------------------------------------------------------------- */
.steps {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 16px;
}

@media ( max-width: 760px ) {
	.steps {
		grid-template-columns: 1fr;
	}
}

.step {
	/* border-radius: 0 — marketing layer */
	padding: 26px;
	border: 1px solid var( --line );
	background: var( --paper );
}

.step h3 {
	font-size: 1.1rem;
	margin-top: 16px;
}

.step p {
	color: var( --slate );
	font-size: 0.92rem;
	margin-top: 8px;
}

/* --------------------------------------------------------------------------
   Dev code panel — enrichment-api + erp-api share the whole component
   byte-identically; utvecklare.html shares only `.code-block pre`, `.c`,
   `.n`, `.endpoint`, `.endpoint .m`, `.endpoint .m.post` and `.endpoint
   .path` with them (3-page match). utvecklare's own `.k`/`.s`/`.p` syntax
   colours are a genuinely different reading (amber/gold instead of
   lime/blue) on the exact same selectors the shared rules below use for
   enrichment-api/erp-api — merging them onto the bare `.code-block .k` etc.
   would corrupt those two pages, which load this same shared sheet.
   Resolved below as the `.code-amber` modifier class (used alongside
   `.code-block`, never instead of it), scoped with an ordinary two-class
   selector rather than `!important`. The container background is not part
   of this split: `.code-block { background: #131110 !important }` a few
   hundred lines above already applies to every `.code-block` regardless of
   page — that is the resolved cascade winner across all three pages, not an
   unmerged collision.
   -------------------------------------------------------------------------- */
/* background is already forced #131110 !important a few hundred lines above
   (`.code-block, .code-snip`) — inline's #0b0d0c never reaches the screen. */
.code-block {
	border: 1px solid rgba( 255, 255, 255, 0.09 );
	/* border-radius: 0 — marketing layer (was 18px) */
	overflow: hidden;
	box-shadow: 0 30px 80px rgba( 0, 0, 0, 0.45 ), 0 0 60px -20px rgba( 189, 231, 99, 0.35 );
}

.cb-bar {
	display: flex;
	align-items: center;
	gap: 6px;
	padding: 11px 16px;
	border-bottom: 1px solid rgba( 255, 255, 255, 0.07 );
}

.cb-bar i {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: rgba( 255, 255, 255, 0.14 );
}

.cb-bar .fn {
	font-family: var( --font-mono );
	font-size: 0.72rem;
	color: #8fa39a;
	margin-left: 8px;
}

.cb-tabs {
	display: flex;
	gap: 4px;
	margin-left: auto;
}

.cb-tab {
	font-family: var( --font-mono );
	font-size: 0.72rem;
	padding: 4px 10px;
	border-radius: 0;
	color: #8fa39a;
	cursor: pointer;
}

.cb-tab.active {
	background: rgba( 189, 231, 99, 0.14 );
	color: #bde763;
}

.cb-pane {
	display: none;
}

.cb-pane.active {
	display: block;
}

.code-block pre {
	margin: 0;
	padding: 22px;
	font-family: var( --font-mono );
	font-size: 0.84rem;
	line-height: 1.75;
	color: #d5e2e8;
	overflow: auto;
}

.code-block .k {
	color: #bde763;
}

.code-block .s {
	color: var( --wp--custom--status--warn );
}

.code-block .c {
	color: #64808b;
}

.code-block .p {
	color: #5fe9bd;
}

.code-block .n {
	color: #f0a8c8;
}

/* utvecklare.html's amber/gold reading — add alongside `.code-block`
   (`class="code-block code-amber"`), never in place of it. `.c` and `.n`
   are identical to the shared rules above on all three pages, so they are
   not repeated here. */
.code-block.code-amber .k {
	color: #ecc985;
}

.code-block.code-amber .s {
	color: #ffd9a8;
}

.code-block.code-amber .p {
	color: #c9f5e4;
}

.endpoint {
	font-family: var( --font-mono );
	font-size: 0.82rem;
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 13px 16px;
	border: 1px solid var( --line );
	border-radius: 0;
	background: var( --paper );
}

.endpoint .m {
	font-weight: 700;
	padding: 2px 8px;
	border-radius: 0;
	font-size: 0.72rem;
}

.endpoint .m.get {
	background: rgba( 189, 231, 99, 0.16 );
	color: #bde763;
}

.endpoint .m.post {
	background: rgba( 95, 233, 189, 0.16 );
	color: #5fe9bd;
}

.endpoint .m.hook {
	background: rgba( 240, 168, 200, 0.14 );
	color: #f0a8c8;
}

.endpoint .path {
	color: var( --ink );
}

.dev-split {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: clamp( 28px, 4vw, 56px );
	align-items: center;
}

@media ( max-width: 860px ) {
	.dev-split {
		grid-template-columns: 1fr;
	}
}

/* --------------------------------------------------------------------------
   Use-case card — 2 pages, byte-identical: enrichment-api, losningar.
   -------------------------------------------------------------------------- */
.usecase {
	/* border-radius: 0 — marketing layer */
	padding: 26px;
	border: 1px solid var( --line );
	background: var( --paper );
}

.usecase h3 {
	font-size: 1.1rem;
}

.usecase p {
	color: var( --slate );
	font-size: 0.9rem;
	margin-top: 8px;
}

/* Both source pages declare `.usecase .tag { margin-bottom: 14px }`
   (enrichment-api.html:32, losningar.html:20); enrichment-api additionally
   adds `display:inline-block`, which is not carried — the base.css label
   reset already makes `.tag` an inline-flex box, so margin-bottom applies
   and the block-level h3 breaks the line without it. */
.usecase .tag {
	margin-bottom: 14px;
}

/* --------------------------------------------------------------------------
   Two-up split (not the mockup-carrying `.split2`) — 2 pages, byte-identical:
   losningar, plattform.
   -------------------------------------------------------------------------- */
.split {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: clamp( 28px, 4vw, 64px );
	align-items: center;
}

@media ( max-width: 840px ) {
	.split {
		grid-template-columns: 1fr;
	}
}

/* losningar.html's B2C section mirrors the panel order (card first in the
   DOM, text visually first — inline order:1/order:2 in the handoff, banned
   here by hard rule 2). `.rev` reproduces the same visual result as a class
   instead. */
.split.rev > :first-child {
	order: 2;
}

.split.rev > :last-child {
	order: 1;
}

/* --------------------------------------------------------------------------
   Contact / demo-booking / report-gate forms — the `.field` family. Shared
   near-identically across kom-igang, kontakt and rapport (report_gate block).
   `.field`, `.success.show`, `.form-body.hide`, the row2 grid, the label and
   the focus ring are byte-identical across at least 2 of the 3; canonical
   values below cover all three renders. Page-specific wrappers (`.kg-*`,
   `.contact-block`, `.gate-note`) are ported separately.
   -------------------------------------------------------------------------- */
.field {
	margin-bottom: 16px;
}

.field.row2 {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 14px;
}

.field label {
	display: block;
	font-size: 0.84rem;
	font-weight: 500;
	margin-bottom: 7px;
}

/* width/padding/font-size/transition only — background, border-color, radius
   and text colour are already forced !important a few hundred lines above
   (the original port of this same `.field input` family). */
.field input,
.field select,
.field textarea {
	width: 100%;
	padding: 12px 14px;
	font-size: 0.94rem;
	transition: 0.15s;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
	outline: 2px solid var( --mint );
	outline-offset: -1px;
	border-color: var( --mint );
}

.field input.err,
.field select.err,
.field textarea.err {
	border-color: #ff7d6b;
	outline-color: #ff7d6b;
}

.field .hint {
	font-size: 0.76rem;
	color: #ff7d6b;
	margin-top: 5px;
	display: none;
}

.field .hint.show {
	display: block;
}

.success {
	display: none;
	text-align: center;
	padding: 30px 10px;
}

.success.show {
	display: block;
}

.form-body.hide {
	display: none;
}

.success .big-ck {
	width: 60px;
	height: 60px;
	border-radius: 50%;
	background: #35b877;
	color: var( --wp--preset--color--contrast );
	display: grid;
	place-items: center;
	margin: 0 auto 18px;
}

.success .big-ck svg {
	width: 30px;
	height: 30px;
}

/* Shared "dark card wrapping a form" surface. kontakt.html and rapport.html
   each redeclare `.form-card` with different literal values; the
   shared-layer radius/shadow overrides above already force radius 0 and a
   uniform shadow, so only background/border/padding need a single canonical
   reading. kontakt's `var(--paper)` reading is used — the token-based
   surface, not rapport's one-off `#131514`. */
.form-card {
	background: var( --paper );
	border: 1px solid var( --line );
	padding: clamp( 24px, 3vw, 38px );
}

/* --------------------------------------------------------------------------
   Conversion hero with contact card — gap G4, kom-igang only.
   -------------------------------------------------------------------------- */
.kg {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: clamp( 28px, 4vw, 72px );
	align-items: start;
}

@media ( max-width: 860px ) {
	.kg {
		grid-template-columns: 1fr;
	}
}

.kg-hero {
	padding-block: clamp( 44px, 6vw, 92px ) clamp( 52px, 7vw, 104px );
}

.kg-top {
	max-width: none;
	/* kom-igang.html's .kg-top carries its own text-align:left / margin-
	   inline:0 inline styles in the handoff (base-2026.html:kg-hero) — the
	   .sec-title / .h26-sub classes it reuses are centered by default
	   everywhere else they appear (sec_head block, .h26 hero variants), so
	   this scope opts back out of that centering instead of the hero
	   partial carrying an inline style. */
	text-align: left;
}

.kg-top .sec-title {
	font-size: clamp( 2.1rem, 5vw, 4.2rem );
	max-width: 20ch;
	margin-inline: 0;
}

.kg-top .h26-sub {
	/* `.h26-sub` otherwise only has type set when scoped under `.h26`
	   (modules.css above) — `.kg-hero` is a `.page-hero`, not `.h26`, so
	   the base type declarations are repeated here rather than relying on
	   a shared ancestor that this variant doesn't have. */
	font-size: clamp( 1rem, 1.4vw, 1.18rem );
	font-weight: 300;
	line-height: 1.55;
	color: var( --wp--preset--color--body-text );
	max-width: 54ch;
	margin: clamp( 20px, 2.6vw, 30px ) 0 0;
	text-wrap: pretty;
}

.kg-contact {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 2px;
	margin-top: clamp( 36px, 5vw, 64px );
}

@media ( max-width: 860px ) {
	.kg-contact {
		grid-template-columns: 1fr;
	}
}

.kg-card {
	display: flex;
	flex-direction: column;
	gap: 10px;
	background: #0d0f12;
	padding: clamp( 20px, 2.4vw, 30px );
	text-decoration: none;
	transition: background 0.22s;
}

a.kg-card:hover {
	background: #12151a;
}

.kg-lab {
	display: flex;
	align-items: center;
	gap: 9px;
	font-family: var( --font-mono );
	font-size: 0.68rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: #8d949c;
}

.kg-lab i {
	width: 9px;
	height: 9px;
	background: var( --mint );
	flex: none;
}

.kg-val {
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 1.25rem, 2.2vw, 1.75rem );
	letter-spacing: -0.025em;
	color: var( --wp--preset--color--contrast );
	line-height: 1.15;
}

a.kg-card:hover .kg-val {
	color: var( --mint-bright );
}

.kg-note {
	font-size: 0.88rem;
	font-weight: 300;
	color: #8d949c;
}

.kg-hero .trust {
	margin-top: clamp( 36px, 5vw, 60px );
}

.chk-pills {
	display: flex;
	gap: 8px;
	flex-wrap: wrap;
}

.chk-pill {
	padding: 8px 14px;
	/* border-radius: 0 — marketing layer (was 999px) */
	border: 1px solid var( --line );
	font-size: 0.86rem;
	cursor: pointer;
	user-select: none;
	transition: 0.15s;
}

.chk-pill.on {
	background: var( --mint-wash );
	border-color: var( --mint-soft );
	color: var( --emerald-deep );
	font-weight: 500;
}

.trust li {
	display: flex;
	gap: 12px;
	align-items: flex-start;
	padding: 16px 0;
	border-bottom: 1px solid var( --line-2 );
}

.trust li .ic {
	width: 40px;
	height: 40px;
	/* border-radius: 0 — marketing layer (was 11px) */
	background: var( --mint-wash );
	color: var( --emerald-deep );
	border: 1px solid var( --mint-soft );
	display: grid;
	place-items: center;
	flex: none;
}

.trust li .ic svg {
	width: 20px;
	height: 20px;
}

.trust li .t {
	font-weight: 500;
}

.trust li .d {
	color: var( --slate );
	font-size: 0.88rem;
	margin-top: 2px;
}

/* --------------------------------------------------------------------------
   Contact form module — gap G32, kontakt only.
   -------------------------------------------------------------------------- */
.contact-block {
	display: flex;
	gap: 14px;
	padding: 18px 0;
	border-bottom: 1px solid var( --line-2 );
}

.contact-block .ic {
	width: 44px;
	height: 44px;
	/* border-radius: 0 — marketing layer (was 12px) */
	background: var( --mint-wash );
	color: var( --emerald-deep );
	border: 1px solid var( --mint-soft );
	display: grid;
	place-items: center;
	flex: none;
}

.contact-block .ic svg {
	width: 21px;
	height: 21px;
}

.contact-block .t {
	font-weight: 500;
}

.contact-block a,
.contact-block .d {
	color: var( --slate );
	font-size: 0.92rem;
}

.contact-block a:hover {
	color: var( --emerald-deep );
}

/* --------------------------------------------------------------------------
   API key reveal panel — api-nycklar only. Not part of the app_mockup kit
   (the mockup catalogue in app_mockup/style.css does not list it).
   -------------------------------------------------------------------------- */
.secret {
	display: flex;
	align-items: center;
	gap: 12px;
	background: var( --wp--custom--app--bar );
	border: 1px solid rgba( 0, 194, 203, 0.4 );
	padding: 14px 16px;
	font-family: var( --font-mono );
	font-size: 0.8rem;
	color: #dfe4ea;
	flex-wrap: wrap;
}

.secret .tag {
	font-size: 0.62rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var( --mint-bright );
	border: 1px solid rgba( 0, 194, 203, 0.45 );
	padding: 3px 8px;
}

/* api-nycklar.html:121 pins the button to the row's far edge with an inline
   `style="margin-left:auto"` — carried here instead, same "no inline styles"
   call as `.ep-terms`/`.endpoint-list` above. `.app-btn`'s own look (colour,
   padding, cursor) already comes from appui.css; only the placement is ours. */
.secret .app-btn {
	margin-left: auto;
}

/* --------------------------------------------------------------------------
   Integration directory grid — gap G22, integrationer only.
   -------------------------------------------------------------------------- */
.int-cat {
	margin-top: 44px;
}

.int-cat h3 {
	font-size: 1.15rem;
	display: flex;
	align-items: center;
	gap: 10px;
}

.int-cat h3 .ic {
	width: 32px;
	height: 32px;
	background: var( --mint );
	color: var( --wp--preset--color--contrast );
	border: 0;
	display: grid;
	place-items: center;
}

.int-cat h3 .ic svg {
	width: 17px;
	height: 17px;
}

.int-grid {
	display: grid;
	grid-template-columns: repeat( 4, 1fr );
	gap: 2px;
	margin-top: 18px;
}

@media ( max-width: 760px ) {
	.int-grid {
		grid-template-columns: 1fr 1fr;
	}
}

.int-logo {
	border: 0;
	padding: 16px 18px 18px;
	display: flex;
	flex-direction: column;
	gap: 0;
	background: #0d0f12;
	text-decoration: none;
	transition: background 0.2s;
	min-height: 128px;
}

.int-logo .hd {
	display: grid;
	grid-template-columns: auto 1fr;
	align-items: center;
	gap: 10px;
	padding-bottom: 12px;
	border-bottom: 1px dotted var( --wp--custom--rule-dotted );
}

.int-logo .hd i {
	width: 10px;
	height: 10px;
	background: var( --mint );
}

.int-logo .d {
	font-size: 0.86rem;
	font-weight: 300;
	line-height: 1.45;
	color: #8d949c;
	margin-top: auto;
	padding-top: 16px;
}

.int-logo:hover {
	background: #12151a;
}

a.int-logo:hover .nm {
	color: var( --mint-bright );
}

.int-logo .sq {
	width: 32px;
	height: 32px;
	/* border-radius: 0 — marketing layer (was 8px) */
	background: var( --paper-3 );
	display: grid;
	place-items: center;
	font-family: var( --font-display );
	font-weight: 700;
	font-size: 0.9rem;
	color: var( --slate );
	flex: none;
}

.int-logo .nm {
	font-weight: 400;
	font-size: 1rem;
	color: var( --wp--preset--color--contrast );
	letter-spacing: -0.01em;
}

/* integrationer.html also declares a `.flow` / `.flow-step` process strip.
   `.flow-step` and `.flow-step .n` are unique to this page and are ported
   below (`.flow-step .n` shares the existing numbered-badge override). The
   `.flow` grid CONTAINER collides with the `steps` block's own `.flow`
   variant (self-hosted.html — see steps/style.css), a structurally
   different component under the same class name: porting integrationer's
   reading onto the bare `.flow` selector would corrupt self-hosted's steps
   rendering. Resolved by porting the container under a new, collision-free
   name instead of the literal one — `.flow-grid`, matching the `.value-grid`
   / `.ptype` naming already used for this kind of 3-up grid below. */
.flow-grid {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 16px;
}

@media ( max-width: 760px ) {
	.flow-grid {
		grid-template-columns: 1fr;
	}
}

.flow-step {
	text-align: center;
	padding: 28px;
}

/* --------------------------------------------------------------------------
   Values / partner-type / tier grids — gap G25. om-oss, partner.
   -------------------------------------------------------------------------- */
.value-grid {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 18px;
}

@media ( max-width: 860px ) {
	.value-grid {
		grid-template-columns: 1fr;
	}
}

.ptype {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 18px;
}

@media ( max-width: 860px ) {
	.ptype {
		grid-template-columns: 1fr;
	}
}

.tier-row {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 18px;
}

@media ( max-width: 860px ) {
	.tier-row {
		grid-template-columns: 1fr;
	}
}

.tier {
	/* border-radius: 0 — marketing layer */
	padding: 28px;
	border: 1px solid var( --line );
}

.tier.mid {
	border: 1.5px solid var( --ink );
	box-shadow: var( --shadow-md );
}

.tier .nm {
	font-family: var( --font-display );
	font-weight: 700;
	font-size: 1.2rem;
}

.tier ul {
	margin-top: 18px;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.tier li {
	display: flex;
	gap: 9px;
	font-size: 0.89rem;
}

.tier li .ck {
	color: var( --emerald );
	flex: none;
}

/* --------------------------------------------------------------------------
   Week-by-week timeline — gap G26, light.html only. Distinct from the
   `timeline` block's `.tl`/`.tl4` (timeline/style.css).
   -------------------------------------------------------------------------- */
.timeline {
	display: grid;
	grid-template-columns: repeat( 4, 1fr );
	gap: 0;
	position: relative;
}

@media ( max-width: 760px ) {
	.timeline {
		grid-template-columns: 1fr;
		gap: 14px;
	}
}

.tl-step {
	padding: 24px;
	position: relative;
}

.tl-step:not( :last-child )::after {
	content: "";
	position: absolute;
	top: 38px;
	right: -2px;
	width: 100%;
	height: 2px;
	background: var( --line );
	z-index: 0;
}

@media ( max-width: 760px ) {
	.tl-step::after {
		display: none;
	}
}

.tl-step .day {
	font-family: var( --font-mono );
	font-size: 0.72rem;
	color: var( --emerald );
	margin-top: 16px;
	font-weight: 500;
}

.tl-step h4 {
	font-size: 1.05rem;
	margin-top: 6px;
}

.tl-step p {
	color: var( --slate );
	font-size: 0.88rem;
	margin-top: 8px;
}

/* --------------------------------------------------------------------------
   Architecture diagram + module grid — gap G23/G24, plattform only. The
   `.mod-illu`/`.mod-grid` wrapper around `.illu` cells is ported in
   hdl-kit/blocks/illustration/style.css, alongside the b2b `.b2bf` wrapper it
   already carries. `.arch`'s margin-top completes the rule below — the
   design carries it as `style="margin-top:36px"` on plattform.html:69, which
   hdl-kit/blocks/arch_stack/render.php never emits inline (hard rule 2 bans
   inline style rules); the value belongs here instead, on the class it was
   always scoped to.
   -------------------------------------------------------------------------- */
.arch {
	display: grid;
	grid-template-columns: 1fr;
	gap: 14px;
	margin-top: 36px;
}

.arch-layer {
	/* border-radius: 0 — marketing layer */
	padding: 20px 24px;
	border: 1px solid var( --line );
	background: var( --paper );
	display: flex;
	align-items: center;
	gap: 18px;
	flex-wrap: wrap;
}

.arch-layer .ll {
	font-family: var( --font-mono );
	font-size: 0.68rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var( --slate-2 );
	width: 130px;
	flex: none;
}

.arch-layer .chips {
	display: flex;
	gap: 10px;
	flex-wrap: wrap;
	flex: 1;
}

.arch-layer .ac {
	padding: 8px 14px;
	/* border-radius: 0 — marketing layer (was 9px) */
	font-size: 0.86rem;
	font-weight: 500;
	background: var( --paper-2 );
	border: 1px solid var( --line-2 );
}

.arch-layer.core {
	background: linear-gradient( 140deg, #bde763, #1d5c3a 60%, #17442c );
	border: none;
	position: relative;
	overflow: hidden;
	box-shadow: 0 14px 44px -10px rgba( 189, 231, 99, 0.55 ), 0 0 0 1px rgba( 189, 231, 99, 0.35 );
}

.arch-layer.core::after {
	content: "";
	position: absolute;
	right: -15%;
	top: -60%;
	width: 55%;
	height: 220%;
	background: radial-gradient( circle, rgba( 205, 244, 125, 0.35 ), transparent 65% );
	pointer-events: none;
}

.arch-layer.core .ll {
	color: #eafff3;
	position: relative;
	z-index: 1;
}

.arch-layer.core .chips {
	position: relative;
	z-index: 1;
}

.arch-layer.core .ac {
	background: rgba( 255, 255, 255, 0.14 );
	border: 1px solid rgba( 255, 255, 255, 0.28 );
	color: var( --wp--preset--color--contrast );
}

.arch-layer.api {
	background: var( --mint-wash );
	border-color: var( --mint-soft );
}

.arch-layer.api .ac {
	background: rgba( 255, 255, 255, 0.08 );
	border-color: var( --mint-soft );
	color: var( --emerald-deep );
	font-weight: 500;
}

.mod-grid {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 18px;
}

@media ( max-width: 900px ) {
	.mod-grid {
		grid-template-columns: 1fr 1fr;
	}
}

@media ( max-width: 600px ) {
	.mod-grid {
		grid-template-columns: 1fr;
	}
}

.mod {
	/* border-radius: 0 — marketing layer */
	padding: 26px;
	border: 1px solid var( --line );
	transition: 0.25s;
}

.mod:hover {
	border-color: var( --mint-soft );
	box-shadow: var( --shadow-md );
	transform: translateY( -3px );
}

.mod .ic {
	width: 44px;
	height: 44px;
	/* border-radius: 0 — marketing layer (was 12px) */
	background: var( --mint-wash );
	color: var( --emerald-deep );
	border: 1px solid var( --mint-soft );
	display: grid;
	place-items: center;
}

.mod .ic svg {
	width: 22px;
	height: 22px;
}

.mod h3 {
	font-size: 1.15rem;
	margin-top: 18px;
}

.mod p {
	color: var( --slate );
	font-size: 0.92rem;
	margin-top: 9px;
}

.mod ul {
	margin-top: 14px;
	display: flex;
	flex-direction: column;
	gap: 7px;
}

.mod li {
	font-size: 0.85rem;
	color: var( --slate );
	display: flex;
	gap: 8px;
}

.mod li::before {
	content: "→";
	color: var( --emerald );
}

/* --------------------------------------------------------------------------
   Blog index — blogg.html only. Distinct from the `blog` ACF layout, which
   index.html uses with entirely different markup (marketing-features §1
   row 19).
   -------------------------------------------------------------------------- */
.post-grid {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 20px;
}

@media ( max-width: 900px ) {
	.post-grid {
		grid-template-columns: 1fr 1fr;
	}
}

@media ( max-width: 600px ) {
	.post-grid {
		grid-template-columns: 1fr;
	}
}

.post {
	/* border-radius: 0 — marketing layer */
	border: 1px solid var( --line );
	overflow: hidden;
	background: var( --paper );
	transition: 0.25s;
	display: flex;
	flex-direction: column;
}

.post:hover {
	box-shadow: var( --shadow-md );
	transform: translateY( -3px );
}

.post .cover {
	aspect-ratio: 16/10;
	background: linear-gradient( 135deg, var( --paper-3 ), var( --mint-wash ) );
	display: grid;
	place-items: center;
	color: var( --emerald );
	position: relative;
}

.post .cover svg {
	width: 40px;
	height: 40px;
	opacity: 0.6;
}

.post .cover.dark {
	background: linear-gradient( 135deg, var( --dark-2 ), var( --dark ) );
	color: var( --mint );
}

.post .body {
	padding: 22px;
	flex: 1;
	display: flex;
	flex-direction: column;
}

.post .cat {
	font-family: var( --font-mono );
	font-size: 0.68rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var( --emerald-deep );
}

.post h3 {
	font-size: 1.12rem;
	margin-top: 10px;
	line-height: 1.25;
}

.post p {
	color: var( --slate );
	font-size: 0.9rem;
	margin-top: 10px;
	flex: 1;
}

.post .by {
	display: flex;
	align-items: center;
	gap: 9px;
	margin-top: 18px;
	font-size: 0.82rem;
	color: var( --slate );
}

.post .by .av {
	width: 26px;
	height: 26px;
	border-radius: 50%;
	background: var( --mint-wash );
	color: var( --emerald-deep );
	display: grid;
	place-items: center;
	font-weight: 700;
	font-size: 0.7rem;
}

.feature-post {
	display: grid;
	grid-template-columns: 1.1fr 1fr;
	gap: clamp( 24px, 4vw, 48px );
	align-items: center;
	/* border-radius: 0 — marketing layer */
	border: 1px solid var( --line );
	overflow: hidden;
	background: var( --paper );
}

@media ( max-width: 840px ) {
	.feature-post {
		grid-template-columns: 1fr;
	}
}

.feature-post .cover {
	aspect-ratio: 16/11;
	background: linear-gradient( 135deg, var( --dark-2 ), var( --dark ) );
	display: grid;
	place-items: center;
	color: var( --mint );
}

.feature-post .cover svg {
	width: 64px;
	height: 64px;
	opacity: 0.7;
}

.feature-post .body {
	padding: clamp( 24px, 3vw, 40px );
}

/* --------------------------------------------------------------------------
   Split-panel field lists — gap G31. angerratt + self-hosted (`.req`,
   `.place`), seo (`.fields`, `.ints`, `.sd`, `.rob` — `.rob` itself is ported
   in app_mockup/style.css, it lives inside a mockup), solaris (`.pillrow`).
   None are identical between pages, each is single-use.
   -------------------------------------------------------------------------- */
.req {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 2px;
	background: var( --wp--custom--hairline );
	border: 1px solid var( --wp--custom--hairline );
}

.req > div {
	background: var( --dark );
	padding: clamp( 20px, 2.4vw, 28px );
	display: flex;
	gap: 14px;
}

.req i {
	width: 11px;
	height: 11px;
	background: var( --mint );
	flex: none;
	margin-top: 6px;
}

.req h3 {
	font-size: 1rem;
	color: var( --wp--preset--color--contrast );
	font-weight: 500;
}

.req p {
	font-size: 0.9rem;
	color: var( --wp--preset--color--muted );
	line-height: 1.6;
	margin-top: 7px;
}

@media ( max-width: 820px ) {
	.req {
		grid-template-columns: 1fr;
	}
}

/* self-hosted.html ALSO declares a bare `.req` — a <dl> definition list
   (`.req{grid-template-columns:auto 1fr}` + `.req dt`/`.req dd`), a
   different component from angerratt's <div> grid `.req` ported above under
   the same class name: angerratt's is a 2-col card grid, self-hosted's is a
   term/definition list, and their base `.req{}` declarations (columns, gap)
   genuinely conflict. Resolved the same way as the `.flow` collision above —
   a new, collision-free name instead of the literal one. */
.req-list {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 8px 20px;
	font-size: 0.9rem;
	color: var( --wp--preset--color--body-text );
}

.req-list dt {
	font-family: var( --font-mono );
	font-size: 0.74rem;
	color: var( --wp--custom--dim );
	padding-top: 0.2em;
}

.req-list dd {
	margin: 0;
	line-height: 1.55;
}

@media ( max-width: 620px ) {
	.req-list {
		grid-template-columns: 1fr;
		gap: 2px 0;
	}

	.req-list dd {
		margin-bottom: 12px;
	}
}

.fnote {
	font-size: 0.82rem;
	color: var( --wp--custom--dim );
	line-height: 1.6;
	margin-top: 20px;
}

.place {
	display: flex;
	flex-wrap: wrap;
	gap: 2px;
	margin-top: 28px;
}

.place span {
	background: var( --paper );
	border: 1px solid rgba( 255, 255, 255, 0.08 );
	padding: 14px 18px;
	font-family: var( --font-mono );
	font-size: 0.76rem;
	letter-spacing: 0.04em;
	color: var( --wp--preset--color--body-text );
	display: flex;
	align-items: center;
	gap: 10px;
}

.place span i {
	width: 9px;
	height: 9px;
	background: var( --mint );
}

.fields {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 9px 20px;
	font-size: 0.9rem;
	color: var( --wp--preset--color--body-text );
}

.fields dt {
	font-family: var( --font-mono );
	font-size: 0.74rem;
	color: var( --wp--custom--dim );
	padding-top: 0.2em;
	white-space: nowrap;
}

.fields dd {
	margin: 0;
	line-height: 1.55;
}

@media ( max-width: 620px ) {
	.fields {
		grid-template-columns: 1fr;
		gap: 2px 0;
	}

	.fields dd {
		margin-bottom: 12px;
	}
}

.ints {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 24px;
}

.ints span {
	font-family: var( --font-mono );
	font-size: 0.72rem;
	letter-spacing: 0.05em;
	color: var( --wp--preset--color--body-text );
	border: 1px solid rgba( 255, 255, 255, 0.13 );
	padding: 7px 11px;
}

.sd {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 2px;
	background: var( --wp--custom--hairline );
	border: 1px solid var( --wp--custom--hairline );
}

.sd > div {
	background: var( --dark );
	padding: clamp( 18px, 2.2vw, 25px );
}

.sd h3 {
	font-size: 0.95rem;
	color: var( --wp--preset--color--contrast );
	font-weight: 500;
	display: flex;
	align-items: center;
	gap: 10px;
}

.sd h3 i {
	width: 9px;
	height: 9px;
	background: var( --mint );
	flex: none;
}

.sd ul {
	list-style: none;
	margin: 13px 0 0;
	padding: 0;
	display: grid;
	gap: 6px;
}

.sd li {
	font-family: var( --font-mono );
	font-size: 0.74rem;
	color: var( --wp--preset--color--muted );
}

@media ( max-width: 1000px ) {
	.sd {
		grid-template-columns: 1fr;
	}
}

.pillrow {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 26px;
}

.pillrow span {
	font-family: var( --font-mono );
	font-size: 0.72rem;
	letter-spacing: 0.06em;
	color: var( --wp--preset--color--body-text );
	border: 1px solid rgba( 255, 255, 255, 0.13 );
	padding: 7px 11px;
}

/* --------------------------------------------------------------------------
   Second pass — content modules missed on first read. b2b, cms,
   replatforma-magento, research, self-hosted: single-page, no block owns
   this markup, no collision with anything already ported.
   -------------------------------------------------------------------------- */

/* b2b.html — feature chip grid (gap G29) and the win-back / retention panel
   row it sits next to. Both single-use, hairline-cell grids. */
.featgrid {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 2px;
	background: var( --wp--custom--hairline );
	border: 1px solid var( --wp--custom--hairline );
}

.featgrid > div {
	background: var( --dark );
	padding: clamp( 18px, 2.2vw, 25px );
}

.featgrid h3 {
	font-size: 0.95rem;
	color: var( --wp--preset--color--contrast );
	font-weight: 500;
	display: flex;
	align-items: center;
	gap: 10px;
}

.featgrid h3 i {
	width: 9px;
	height: 9px;
	background: var( --mint );
	flex: none;
}

.featgrid p {
	font-size: 0.86rem;
	color: var( --wp--custom--status--mute );
	line-height: 1.6;
	margin-top: 10px;
}

.win {
	display: flex;
	flex-wrap: wrap;
	gap: 2px;
	margin-top: 2px;
}

.win > div {
	flex: 1 1 210px;
	background: var( --dark );
	border: 1px solid rgba( 255, 255, 255, 0.08 );
	padding: clamp( 16px, 2vw, 22px );
	display: flex;
	flex-direction: column;
	gap: 9px;
}

.win.on > div:first-child {
	border-color: rgba( 0, 194, 203, 0.45 );
}

.win .p {
	font-family: var( --font-mono );
	font-size: 0.66rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var( --mint );
}

.win b {
	font-size: 0.98rem;
	color: var( --wp--preset--color--contrast );
	font-weight: 500;
}

.win dl {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 4px 12px;
	margin: 6px 0 0;
	font-family: var( --font-mono );
	font-size: 0.72rem;
}

.win dt {
	color: var( --wp--custom--dim );
}

.win dd {
	margin: 0;
	color: var( --wp--preset--color--body-text );
}

@media ( max-width: 1000px ) {
	.featgrid {
		grid-template-columns: 1fr;
	}
}

/* --------------------------------------------------------------------------
   "Coming soon" placeholder panel — gap G30, cms.html only.
   -------------------------------------------------------------------------- */
.soon {
	border: 1px solid rgba( 0, 194, 203, 0.35 );
	background: linear-gradient( 180deg, rgba( 0, 194, 203, 0.09 ), transparent );
	padding: clamp( 26px, 3.4vw, 44px );
}

.soon .tag {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	font-family: var( --font-mono );
	font-size: 0.7rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --mint-bright );
}

.soon .tag i {
	width: 9px;
	height: 9px;
	background: var( --mint );
}

.soon h3 {
	font-family: var( --font-display );
	font-weight: 400;
	font-size: clamp( 1.6rem, 3.2vw, 2.5rem );
	letter-spacing: -0.035em;
	color: var( --wp--preset--color--contrast );
	margin-top: 16px;
}

.soon p {
	color: var( --wp--preset--color--muted );
	font-size: 1rem;
	line-height: 1.6;
	margin-top: 14px;
	max-width: 56ch;
}

.soon ul {
	list-style: none;
	margin: 22px 0 0;
	padding: 0;
	display: grid;
	gap: 9px;
}

.soon li {
	display: flex;
	gap: 11px;
	font-size: 0.92rem;
	color: var( --wp--preset--color--body-text );
}

.soon li i {
	width: 9px;
	height: 9px;
	background: #3a3f47;
	flex: none;
	margin-top: 0.42em;
}

/* --------------------------------------------------------------------------
   Migration proof strip — gap G5 (hero-adjacent), replatforma-magento only.
   -------------------------------------------------------------------------- */
.hproof {
	display: flex;
	flex-wrap: wrap;
	gap: 0;
	margin-top: clamp( 28px, 3.4vw, 42px );
	border: 1px solid rgba( 255, 255, 255, 0.12 );
	max-width: 820px;
	margin-inline: auto;
}

.hproof > div {
	flex: 1 1 200px;
	padding: 15px 18px;
	border-right: 1px solid rgba( 255, 255, 255, 0.12 );
	display: flex;
	flex-direction: column;
	gap: 5px;
	text-align: left;
}

.hproof > div:last-child {
	border-right: 0;
}

.hproof b {
	font-family: var( --font-mono );
	font-size: 0.95rem;
	color: var( --wp--preset--color--contrast );
	font-weight: 400;
	letter-spacing: -0.01em;
}

.hproof span {
	font-size: 0.78rem;
	color: var( --wp--custom--status--mute );
	line-height: 1.4;
}

/* --------------------------------------------------------------------------
   Report index — gap G35, research.html only.
   -------------------------------------------------------------------------- */
.report-list {
	display: flex;
	flex-direction: column;
	gap: 14px;
}

/*
 * Two columns by default, three only when the row actually has a cover.
 *
 * The cover is optional in the markup (card_grid render.php:426), but this was
 * a fixed `auto 1fr auto`. With no cover the two real children shifted left:
 * the text landed in `auto` and sized to its own length, and the button landed
 * in `1fr` and absorbed everything else — so on /research/ the four download
 * buttons came out 731, 792, 756 and 830px wide, one per headline length.
 *
 * Now the text takes the flexible column and the button sizes to its content,
 * which makes every button identical without hard-coding a width.
 */
.report {
	display: grid;
	grid-template-columns: 1fr auto;
	gap: 22px;
	align-items: center;
	/* border-radius: 0 — marketing layer */
	padding: 22px 26px;
	border: 1px solid var( --line );
	background: var( --paper );
	transition: 0.2s;
}

.report:has( .cover ) {
	grid-template-columns: auto 1fr auto;
}

.report:hover {
	border-color: var( --mint-soft );
	box-shadow: var( --shadow-sm );
}

.report .cover {
	width: 64px;
	height: 80px;
	/* border-radius: 0 — marketing layer (was 8px) */
	background: linear-gradient( 150deg, var( --dark-2 ), var( --dark ) );
	display: grid;
	place-items: center;
	color: var( --mint );
	flex: none;
}

.report .cover svg {
	width: 26px;
	height: 26px;
}

.report .tag {
	margin-bottom: 8px;
}

.report h3 {
	font-size: 1.12rem;
}

.report p {
	color: var( --slate );
	font-size: 0.9rem;
	margin-top: 6px;
	max-width: 60ch;
}

.report .meta {
	font-size: 0.78rem;
	color: var( --slate-2 );
	font-family: var( --font-mono );
	margin-top: 8px;
}

@media ( max-width: 680px ) {
	.report {
		grid-template-columns: 1fr;
		text-align: left;
	}

	.report .cover {
		display: none;
	}

	.report .btn {
		justify-self: start;
	}
}

/* --------------------------------------------------------------------------
   Enterprise entitlement badge — self-hosted.html only.
   -------------------------------------------------------------------------- */
.ent {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	border: 1px solid rgba( 0, 194, 203, 0.5 );
	background: rgba( 0, 194, 203, 0.1 );
	padding: 7px 12px;
	font-family: var( --font-mono );
	font-size: 0.68rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --mint-bright );
}

.ent i {
	width: 8px;
	height: 8px;
	background: var( --mint );
}

/* --------------------------------------------------------------------------
   NOT PORTED — unreachable markup.

   The six bespoke card-grid variants (.mods replatforma-magento, .pkg +
   .clouds self-hosted, .cat solaris, .efeat enterprise, .jobs-tools verktyg)
   are no longer in this list either. `card_grid`'s render.php emits all six
   class sets verbatim (Variant field: Module index / Package list / Component
   catalogue / Providers / Enterprise features / Tool specs), and their CSS is
   now ported in hdl-kit/blocks/card_grid/style.css — each is a single-page
   component owned by that block, so it follows the same precedent as
   `.stat4` below rather than living in this shared sheet. Note that solaris's
   `.cat` and blogg's `.post .cat` (ported above) are different components
   sharing a class name; the block sheet scopes its container rule
   `.wrap-wide > .cat` so the two cannot collide on one page.

   `.stat4` (solaris.html) is likewise not in this list: it is the Quad variant
   of the `stat_row` block, ported in hdl-kit/blocks/stat_row/style.css
   instead of here, matching case_grid's single-page-component precedent.

   The `hero` block's `space` variant (solaris.html's `.space`, `.stars`,
   `.halo`, `.disc` behind `.h26.sol`) WAS in this "not ported" list — the
   hero partial emitted `h26 sol` but not the child markup this CSS targets
   (marketing-features.md §1 row 1 / §4 item 5). It is ported now, near the
   rays hero rules earlier in this file: render.php's `space` branch emits
   the starfield/halo/disc DOM and this sheet styles it.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   Mobile hardening — base-2026.css 429-435
   -------------------------------------------------------------------------- */
.legal-row,
.legal-body,
.legal-k {
	min-width: 0;
}

@media ( max-width: 760px ) {
	.legal-body {
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
	}

	.doc-table {
		min-width: 480px;
	}
}

@media ( max-width: 700px ) {
	.seg button,
	.seg a,
	.toggle-bill button {
		min-height: 44px;
	}
}

@media ( max-width: 560px ) {
	.row2 {
		grid-template-columns: 1fr !important;
	}
}

@media ( max-width: 520px ) {
	.nl-form .btn {
		flex: 1 1 100%;
	}
}

/* --------------------------------------------------------------------------
   OWNER CHANGE 2026-08-14 — no dot texture, and one breadcrumb line

   1. DOTS OFF EVERYWHERE. The design draws a dot field in six places: the
      forest hero's ::after, the wave background's `.still` and its blue
      `.matrix`, the pulse background's `.dots`, the home hero's `.h26-dots`
      and the footer's `.ft-dots`. The owner wants the plain grey ground, so
      every one of them drops its background-image and keeps its colour.
      Deliberately one block, at the end of the file, so reverting is a
      delete rather than an archaeology exercise.

   2. ONE BREADCRUMB LINE. Breadcrumbs sat at three different heights —
      222px on most pages, 230px on the h26 hero (jamfor-*), 232px on the
      non-centred forest hero (kontakt) — because each hero variant brings
      its own top padding and margin. Measured across nine pages. Heroes
      that carry a breadcrumb now share one top offset; the variants keep
      their own rhythm everywhere below it.
   -------------------------------------------------------------------------- */

.hero-forest::after,
.hbg-wave .still,
.hbg-wave .matrix,
.hbg-pulse .dots,
.hbg-rain .col,
.h26-dots,
.ft-dots,
.cs-hero .dots {
	background-image: none !important;
}

/*
 * The baseline is .page-hero's own formula — the hero is pulled up by the
 * header height and given the same amount back as padding (modules.css:1277),
 * so the breadcrumb lands at clamp(56px,8vw,104px) below the top of the page.
 * Do not touch that rule; it is deliberate and more specific than anything
 * written here. Only the two heroes that miss the line get corrected.
 *
 * The jamfor-* hero was 8px low. Restating the same formula makes the two
 * track together at every viewport instead of agreeing at one width, and it
 * sits on body.flush, whose own rule
 * (modules.css:843, clamp(196px,18vw,262px)) is more specific than a bare
 * .h26 selector — hence body.flush here too, or this silently loses.
 */
/*
 * Breadcrumbs on the h26 hero — out of the centred flow, onto the line.
 *
 * DELIBERATE DEVIATION FROM THE HANDOFF. The design places breadcrumbs
 * per hero type: .page-hero > .wrap on partner.html, inside .h26-in and
 * centred on jamfor-magento.html. .h26 is a `place-items: center` grid with a
 * min-height, so there the breadcrumb's position followed however long that
 * page's hero copy happened to be — 222px on jamfor-magento, 225 on cms, 273
 * on byta-e-handelsplattform. The owner asked for one line sitewide.
 *
 * Two earlier attempts are recorded so they are not repeated. `align-content:
 * start` pinned the breadcrumb but pushed the whole composition to the top,
 * leaving the min-height's slack as a void below it — visible immediately on
 * short heroes like /blogg/. Absolute positioning without the rule below
 * resolved `top` against .h26-in rather than .h26 and threw the breadcrumbs to
 * 444-516px.
 *
 * .h26-in carries `position: relative` with no offsets and no z-index — it
 * establishes a containing block and nothing else, and the background layers
 * are absolute siblings that .h26-in already paints over by DOM order. So it
 * can go static here, which lets the breadcrumb resolve against .h26 and lets
 * everything else centre exactly as the design intends.
 */
.h26:has( .breadcrumbs ) > .h26-in {
	position: static;
}

.h26 > .h26-in > .breadcrumbs {
	position: absolute;
	top: clamp( 56px, 8vw, 104px );
	left: 0;
	right: 0;
	margin-bottom: 0;
}

body.flush .h26 > .h26-in > .breadcrumbs {
	top: calc( clamp( 56px, 8vw, 104px ) + var( --wp--custom--header-height ) );
}

@media ( max-width: 1080px ) {
	body.flush .h26 > .h26-in > .breadcrumbs {
		top: calc( clamp( 56px, 8vw, 104px ) + var( --wp--custom--header-height-compact ) );
	}
}

/* --------------------------------------------------------------------------
   OWNER PASS 2026-08-14 — seven fixes reported from the live site
   -------------------------------------------------------------------------- */

/*
 * 1. .stmt descenders. The highlight (.st-hl) paints a background per line
 *    with box-decoration-break: clone, and at line-height 1.02 the next
 *    line's box lands on top of the previous line's descenders — the g in
 *    "lager" and the p in "prislista" were sliced off. Nothing but leading
 *    fixes this: padding cannot help, because the box that does the covering
 *    belongs to the following line and paints after it.
 *
 *    The number is not a guess. An inline element's background box is its
 *    content area, which browsers derive from the font's ascent+descent, not
 *    from line-height — measured at 106px against an 80.64px font. Any
 *    line-height below 106/80.64 = 1.315 leaves the boxes overlapping. 1.12
 *    was tried first and still clipped by 12px.
 */
.stmt {
	line-height: 1.32;
}

/*
 * 2. Blog cards carried the post title twice — once in .bl-cap, an absolutely
 *    positioned white bar over the thumbnail with a blue square beside it,
 *    and again as the <h3> below. .bl-by was the same blue square repeated at
 *    the card's foot with nothing in it. Both are hidden rather than removed
 *    from the block: the markup is the design's, and the day a card needs an
 *    author or an overlaid caption again the rule is what goes, not the
 *    template.
 */
.bl-cap,
.bl-by {
	display: none;
}

/*
 * 3. The trailing "Utforska stacken" button sat hard left under a centred
 *    two-column composition.
 */
.duo-cta {
	display: flex;
	justify-content: center;
}

/*
 * 4. Half the air between the module rail and the duo below it on the home
 *    page. Both sections carry the full section rhythm, so the gap was two
 *    paddings deep — one section's worth is pulled back, leaving half.
 */
.wp-block-hdl-kit-module-rail + .wp-block-hdl-kit-duo {
	margin-top: calc( -1 * clamp( 84px, 10vw, 150px ) / 2 );
}

/*
 * 5. Mega-menu seams. .mega-in uses a 1px grid gap and paints the column
 *    background on .mega-col, so the gap showed whatever was behind the
 *    panel — and where one column ran shorter than its neighbours, the page
 *    itself showed through below it. The panel now owns the surface and the
 *    dividers are borders, so there is nothing left to see through.
 */
.mega {
	background: var( --wp--preset--color--surface );
}

.mega-in {
	gap: 0;
}

.mega-col + .mega-col {
	border-left: 1px solid var( --wp--custom--hairline );
}

/*
 * Air around the claims strip.
 *
 * .st ships `padding: … 0 0` — no bottom padding — because in the design the
 * .st-foot row carried the space with its own margin-top and padding-bottom.
 * That row is the "[ → ]" arrow and the "HDL är" chip the owner had removed
 * earlier today, so the statement's closing line ended up sitting almost on
 * top of the first claim. This is that regression, repaid: the space is now
 * the section's own rather than borrowed from a child that no longer exists.
 *
 * .claims opened at clamp(10px,2vw,26px) — 26px between "resten." and the
 * first row at desktop. Both edges move to the .section-sm measure, which is
 * the rhythm a thin band like this already uses elsewhere on the site.
 */
.st {
	padding-bottom: clamp( 63px, 7.5vw, 112px );
}

.claims {
	padding-block: clamp( 63px, 7.5vw, 112px );
}

/*
 * .stmt-dark — white body text, and the same descender fix .stmt needed.
 *
 * The design sets #8d949c so the highlighted runs carry the sentence and the
 * rest recedes; the owner wants the whole line white. Deliberate deviation.
 *
 * It also clipped, for exactly the reason .stmt did: the .hlw/.hlb background
 * box measured 66px against a 56.4px line advance, so each line painted 9px
 * over the descenders above it. Same arithmetic, same answer — the box is
 * font-derived, so line-height has to clear it: 66/50.4 = 1.31.
 */
.stmt-dark {
	color: var( --wp--preset--color--contrast );
	line-height: 1.32;
}

/*
 * The cta-band heading had the same overlap pointing the other way: its
 * highlight box is 65px against a 53.9px line advance, so the box grew UP
 * past the text and collided with the "KOM IGÅNG" chip above it by 6px.
 * 65/51.84 = 1.254.
 */
.cta-band .sec-title {
	line-height: 1.28;
}

/*
 * The icon badge inside a highlight sat flush against the box's left edge.
 * base.css gives .sec-title .sq an even `margin: 0 0.1em`, then
 * `.sec-title .hl .sq` pulls it back by -0.04em — which is what closed the
 * gap on the left while the right kept its 0.1em. Even margins on both sides.
 */
.sec-title .hl .sq,
.sec-title .hlb .sq {
	margin-left: 0.1em;
}

/*
 * /kontakt/ puts its breadcrumb inside a [data-reveal] wrapper, which holds a
 * translateY(10px) until the reveal fires — and above the fold it never does,
 * so the breadcrumb renders 10px low on every load. Breadcrumbs are chrome,
 * not content; a wrapper carrying one does not animate. (This rule existed
 * before and was lost in a later edit to this file; the page went straight
 * back to 232px, which is how it was caught.)
 */
[data-reveal]:has( > .breadcrumbs ) {
	transform: none !important;
	opacity: 1 !important;
}

/* --------------------------------------------------------------------------
   OWNER CHANGE 2026-08-14 — hero and footer backgrounds move 4x slower

   The ambient layers ran at 7.5-26s, which reads as motion you watch rather
   than atmosphere you sit in. Every duration below is the design's own value
   times four; nothing else about the animations changes, so the shapes and
   easing are untouched and reverting means deleting this block.

   Only ambient background layers are here. The status dot, the logo marquee
   and the illustration float are functional or content motion and keep their
   timing.

   animation-duration overrides the shorthand's duration on its own, so each
   rule is one line rather than a restated shorthand that could drift from
   the original keyframe name or easing.
   -------------------------------------------------------------------------- */

.h26-edge {
	animation-duration: 48s;
}

.rays-field b {
	animation-duration: 30s;
}

.hbg-wave .matrix.m1 {
	animation-duration: 44s;
}

.hbg-wave .matrix.m2 {
	animation-duration: 68s;
}

.hbg-wave .bloom {
	animation-duration: 40s;
}

.hbg-iso .iso {
	animation-duration: 104s;
}

.hbg-iso .cube {
	animation-duration: 28s;
}

.hbg-pulse .ring {
	animation-duration: 36s;
}

.hbg-pulse .core {
	animation-duration: 36s;
}

.hbg-rain .sweep {
	animation-duration: 32s;
}

.space .stars .tw {
	animation-duration: 22s;
}

.space .halo {
	animation-duration: 44s;
}

.blob-1,
.blob-2,
.blob-3,
.blob-4,
.blob-5 {
	animation-duration: 36s;
}

/* --------------------------------------------------------------------------
   COLOUR CHANGE 2026-08-14 — emerald + teal

   Two colours with separate jobs. Emerald (--wp--preset--color--accent, now
   #00d08f) is what you click and what you get. Teal (#00c2cb) is the air
   behind it and never carries content. Blue survives only as the deep tone in
   the middle of the footer gradient.

   Implemented in tokens, not as the overlay the design spec describes. That
   spec was written against the static handoff, which has no token layer and
   therefore needs ~100 lines of !important to reach past base-2026.css. This
   theme resolves 66 references through one theme.json value, so the overlay
   would be answering a problem that does not exist here — and the spec's own
   closing recommendation is exactly this end state.

   CONTRAST IS THE WHOLE RISK. White on #00d08f is 1.7:1 and unreadable;
   #04140c is 9.8:1. Every rule that paints accent as a background now sets
   --wp--preset--color--on-accent, 29 of them, 14 of which had been explicitly
   white. Put emerald on a new surface and it takes dark text — no exceptions
   except the one below.
   -------------------------------------------------------------------------- */

/*
 * .gain — semantic colour for a number that means money saved. Emerald carries
 * both action and saving, which is what gives the TCO calculator two colours
 * with settled meanings before it is built.
 */
.gain,
.stat4 b.gain,
.stat .num.gain,
.who .c.gain,
.bar-gain,
.stmt-dark .hlg {
	color: var( --wp--preset--color--accent );
}

.stmt-dark .hlg {
	background: var( --wp--preset--color--accent );
	color: var( --wp--preset--color--on-accent );
	padding: 0 0.12em 0.06em;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}

/*
 * NO SEMI-LIGHT BLOCK HERE, deliberately. The design spec covers a light
 * theme; this site is dark-only by an owner decision taken before any CSS was
 * written, so there is no light ground for emerald to sit on. A first pass
 * ported the spec's rule anyway and it fired immediately — the visitor's OS
 * was in light mode, the site sets no data-theme, so every accent on the site
 * silently became the deep #0a7d5c meant for light backgrounds. Left as a
 * note rather than deleted quietly: if the site ever gains a light theme,
 * this is the rule it needs and #0a7d5c is the value.
 */

/*
 * The home hero's glow runs on past the promo band.
 *
 * .hx carries `overflow: clip` and .lava sits inset:0 inside it, so the glow
 * stopped dead on the hero's bottom edge — a hard horizontal line right above
 * the RAPPORT banner, with the banner then floating on flat black. Measured:
 * hero ends at 1440, the banner is 211px tall, the light logo band starts at
 * 1651.
 *
 * `overflow` cannot do this: clip on one axis forces the other from visible to
 * auto, which would add a scrollbar. clip-path can — a negative bottom inset
 * keeps the horizontal clip the blobs need and opens the bottom edge alone.
 *
 * The bleed deliberately overshoots the banner. The light band below is opaque
 * and paints after, so any excess is covered, and the glow lands exactly on
 * the light section's edge at every viewport instead of at one measured width.
 */
.hx {
	overflow: visible;
	clip-path: inset( 0 0 calc( -1 * clamp( 170px, 20vw, 280px ) ) 0 );
}

.lava {
	bottom: calc( -1 * clamp( 170px, 20vw, 280px ) );
	/* The horizontal clip .hx used to provide. clip-path clips painting but
	   not layout, so dropping overflow from .hx let blob-1 and blob-3 push the
	   document 132px wider than the viewport and gave the home page a
	   horizontal scrollbar. Clipping here keeps the blobs inside the field
	   while the field itself is free to run past the hero's bottom edge. */
	overflow: clip;
}

/*
 * The banner sits above the glow rather than under it. .promo already has
 * position: relative; this only guarantees the section does too, so DOM order
 * decides and the card never disappears behind the bleed.
 */
.promo-sec {
	position: relative;
	z-index: 1;
}

/*
 * The h26 background layers belong behind the content, explicitly.
 *
 * Making .h26-in static (so the breadcrumb could resolve against .h26) had a
 * consequence I did not follow through: .disc, .halo, .space, .rays-field and
 * the rest are `position: absolute; z-index: auto`, which paints them in the
 * positioned layer — above static content. While .h26-in was relative it sat
 * in that same layer and won on DOM order. Static dropped it underneath.
 *
 * Invisible on the rays pages, where the field is faint. Obvious on
 * /solaris/, whose .disc is an opaque 3600px black circle: its edge cut
 * straight across the hero's two buttons.
 *
 * Fixed by saying what was previously only implied — the layers are behind,
 * the content is in front — rather than by putting .h26-in back in the
 * positioned layer, which would take the breadcrumb bug with it.
 */
.h26 {
	isolation: isolate;
}

.h26 > .rays-field,
.h26 > .h26-dots,
.h26 > .h26-edge,
.h26 > .space,
.h26 > .halo,
.h26 > .disc,
.h26 > .hbg-wave,
.h26 > .hbg-rain,
.h26 > .hbg-pulse,
.h26 > .hbg-iso {
	z-index: -1;
}

/*
 * The globe reads as a hole rather than a planet at pure #000 on a black
 * page — only its rim was visible. The surface token lifts it just enough to
 * separate from the field behind it without competing with the halo.
 */
.h26.sol .disc {
	background: var( --wp--preset--color--surface );
}

/* ============================================================
   Article template (blog single) — port of the vaxt-ur-woocommerce handoff.

   The handoff's own note: "Artikelmallen (blogg single) finns inte i
   biblioteket ännu — det här är det enda nya." Everything else it uses
   (.legal-body, .stmt-dark, .btn, .breadcrumbs) is already ported above and is
   left alone. What is new is the frame, and it is deliberately thin: a centred
   column and nothing more.

   Two deliberate omissions from the handoff:

   1. The html[data-hdl-theme=semilight] block is NOT ported. This site is
      dark-only by owner decision, and a light-scheme rule shipped once before
      and turned every accent into #0a7d5c on visitors whose OS was light.

   2. .art-fig targets <image-slot>, the design system's placeholder element.
      WordPress renders a real <img>, so the rule addresses both.
   ============================================================ */

.art-col {
	width: min( 68ch, 92vw );
	margin: 0 auto;
}

.art-top {
	padding: clamp( 46px, 7vw, 86px ) 0 0;
}

.art-top h1 {
	font-family: var( --font-display );
	font-weight: 300;
	letter-spacing: -0.04em;
	line-height: 1.02;
	font-size: clamp( 2.1rem, 4.6vw, 3.5rem );
	margin: 22px 0 0;
	color: var( --ink );
	text-wrap: balance;
}

.art-hd {
	display: flex;
	flex-wrap: wrap;
	gap: 18px;
	margin-top: 20px;
	font-family: var( --font-mono );
	font-size: 0.7rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: #7a828c;
}

.art-hd .cat {
	color: var( --emerald );
}

.art-body {
	padding: clamp( 30px, 4vw, 44px ) 0 clamp( 40px, 5vw, 60px );
}

.art-lead {
	font-size: clamp( 1.1rem, 1.5vw, 1.28rem ) !important;
	font-weight: 300 !important;
	line-height: 1.55;
	color: var( --ink-2 ) !important;
}

/* The handoff styles h3 as the section heading, because its article is written
   with h3. The migrated posts use h2 for the same level and h3 below it, so h2
   takes the handoff's spec and h3 steps down from it — otherwise every section
   heading inherits the page-level display size and the article reads as a
   stack of hero titles. */
.art-col .legal-body h2 {
	font-family: var( --font-display );
	font-size: clamp( 1.28rem, 2vw, 1.6rem );
	font-weight: 400;
	line-height: 1.25;
	letter-spacing: -0.02em;
	margin: clamp( 32px, 4vw, 44px ) 0 12px;
	color: var( --ink );
}

.art-col .legal-body h3 {
	font-family: var( --font-display );
	font-size: clamp( 1.1rem, 1.6vw, 1.3rem );
	font-weight: 400;
	line-height: 1.3;
	letter-spacing: -0.015em;
	margin: clamp( 26px, 3vw, 34px ) 0 10px;
	color: var( --ink );
}

/* .stmt-dark sets its type on the container and expects <p> to inherit it;
   inside .legal-body the .legal-body p rule wins instead. Applies to every
   block nested here. Straight from the handoff. */
.art-col .legal-body .stmt-dark p {
	font: inherit;
	letter-spacing: inherit;
	color: inherit;
	margin: 0;
}

.art-fig {
	margin: clamp( 28px, 4vw, 42px ) 0;
}

.art-fig img,
.art-fig image-slot {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	background: #101216;
}

.art-fig figcaption {
	margin-top: 10px;
	font-size: 0.8rem;
	line-height: 1.55;
	color: var( --wp--preset--color--dim );
}

.art-foot {
	display: flex;
	flex-wrap: wrap;
	gap: 18px;
	align-items: center;
	justify-content: space-between;
	margin-top: clamp( 34px, 4vw, 50px );
	padding-top: 24px;
	border-top: 1px dotted #2b3037;
}

.art-au {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 12px;
	align-items: center;
}

.art-au i {
	width: 32px;
	height: 32px;
	background: var( --emerald );
	display: grid;
	place-items: center;
}

.art-au i::after {
	content: "";
	width: 11px;
	height: 11px;
	background: var( --wp--preset--color--on-accent );
}

.art-au b {
	display: block;
	font-size: 0.92rem;
	font-weight: 500;
	color: var( --ink );
}

.art-au span {
	display: block;
	font-family: var( --font-mono );
	font-size: 0.7rem;
	letter-spacing: 0.04em;
	color: #7a828c;
	margin-top: 3px;
}

.art-share {
	display: flex;
	gap: 8px;
}

.art-share a,
.art-share button {
	width: 32px;
	height: 32px;
	display: grid;
	place-items: center;
	background: #16181c;
	border: 0;
	color: #cfd4da;
	font-family: var( --font-mono );
	font-size: 0.72rem;
	text-decoration: none;
	cursor: pointer;
	transition: background 0.2s, color 0.2s;
}

.art-share a:hover,
.art-share button:hover {
	background: var( --emerald );
	color: var( --wp--preset--color--on-accent );
}

/* Scoped: base.css already defines a global .lbl, and .stat/.promo scope
   theirs the same way. */
.art-rel .lbl {
	font-family: var( --font-mono );
	font-size: 0.66rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --wp--preset--color--dim );
	margin: 0 0 14px;
}

.art-rel {
	padding: clamp( 36px, 5vw, 56px ) 0;
	border-top: 1px dotted #2b3037;
}

.art-next {
	display: grid;
	gap: 2px;
}

.art-next a {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 18px;
	align-items: baseline;
	justify-content: space-between;
	padding: 15px 0;
	border-bottom: 1px dotted #2b3037;
	text-decoration: none;
}

.art-next a:first-child {
	border-top: 1px dotted #2b3037;
}

.art-next b {
	font-size: 1rem;
	font-weight: 400;
	color: var( --ink );
	letter-spacing: -0.01em;
}

.art-next span {
	font-family: var( --font-mono );
	font-size: 0.7rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: #7a828c;
}

.art-next a:hover b {
	color: var( --emerald );
}

.art-cta {
	padding: 0 0 clamp( 60px, 8vw, 110px );
}

.art-cta p {
	font-size: 0.98rem;
	line-height: 1.6;
	color: #8d949c;
	max-width: 52ch;
	margin: 0;
}

.art-cta-btns {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin-top: 20px;
}

/* Horizontal clip on the two hosts that carry .grain.
 *
 * .grain is deliberately 6% oversized on every side (inset: -6%) so its 1.5%
 * jitter never exposes an edge — but nothing clipped it, so on a 1440 viewport
 * it reached 86px past the right edge and gave the whole document a horizontal
 * scrollbar.
 *
 * overflow: hidden is the wrong tool twice over. It cannot clip one axis and
 * leave the other visible — it forces the other to auto — and the vertical
 * spill here is deliberate: .lava bleeds 280px BELOW the hero so the gradient
 * runs behind the following section, and the footer blooms spill up and out.
 *
 * clip-path was the first attempt and does not work: it clips PAINTING, not
 * layout, so the document stayed 1526px wide and the scrollbar remained.
 *
 * `overflow-x: clip` is the one that does both. Unlike hidden/auto/scroll it
 * does not force the other axis to a scroll container, so overflow-y stays
 * genuinely visible and the vertical bleed survives — which is the whole
 * reason the obvious fix was unavailable.
 */
.hx,
.ft-glow {
	overflow-x: clip;
	overflow-y: visible;
}
