/* Shared components used across inner pages (not the homepage) — built as
   each page gets migrated off WPBakery, matching the reference site. */

/* --- Single Case hero: dynamic bg (featured image) + post title --- */
.kb-case-hero {
	position: relative;
	min-height: 100vh;
	background-color: var(--kb-color-darker);
	background-size: cover;
	background-position: center;
	display: flex;
	align-items: center;
	justify-content: center;
}

body.admin-bar .kb-case-hero {
	min-height: calc(100vh - 32px);
}

/* Autoplaying video variant (first use: /cases/verdi/, set via the
   post's own _kb_case_hero_video meta) — sits behind the same overlay
   and title as the image variant, just swapping the background layer
   for a covering <video>. */
.kb-case-hero__video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: right bottom;
}

.kb-case-hero__overlay {
	position: absolute;
	inset: 0;
	background: var(--kb-color-darker);
	opacity: 0.4;
}

.kb-case-hero__title {
	position: relative;
	z-index: 1;
	color: var(--kb-color-white);
	text-transform: uppercase;
	font-weight: 800;
	font-size: 75px;
	text-align: center;
	margin: 0;
	padding: 0 24px;
}

/* .kb-case-body itself is intentionally unstyled — every block inside
   (.kb-feature etc.) already constrains and centers itself consistently.
   Constraining here too would double up the side padding and make the
   plain image-only rows (no .kb-feature wrapper) render at a different
   width than the rest. */

@media (max-width: 781px) {
	.kb-case-hero__title {
		font-size: 36px;
	}
}

/* /cases/furore-werbung/-only: no dark overlay on the hero image —
   requested as an explicit one-off exception ("ausnahmsweise"); every
   other case study keeps the shared .kb-case-hero__overlay. */
body.postid-114375 .kb-case-hero__overlay {
	display: none;
}

/* --- Generic page header: kicker + title + intro + parallax bg image --- */
.kb-page-header {
	position: relative;
	padding: var(--kb-space-section-top) 24px 96px;
	overflow: hidden;
	text-align: center;
}

.kb-page-header__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
}

.kb-page-header__bg-image {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	will-change: transform;
}

/* core/cover's own dim-overlay only steps in 10% increments via its
   has-background-dim-N0 classes — override to the exact 0.95 used by the
   .kb-page-header__bg::after version below, so both mechanisms match. */
.kb-page-header .wp-block-cover__background {
	opacity: 0.95 !important;
}

/* Exception: /seo-agentur/'s --dark hero measures 0.5 in production
   (color-jevc/--kb-color-dark, not the shared 0.95 light overlay) —
   same specificity as the rule above, placed after it so source order
   settles the tie in this variant's favor. */
.kb-page-header--dark .wp-block-cover__background {
	opacity: 0.5 !important;
}

.kb-page-header__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(247, 247, 247, 0.95);
}

.kb-page-header__inner {
	position: relative;
	z-index: 1;
	max-width: 1020px;
	margin: 0 auto;
}

/* Stacks existing full-width content (e.g. a .kb-feature row already
   sized correctly for the site's default content width) above
   .kb-page-header__bg, without imposing __inner's 1020px cap — for
   heroes that reuse an already-built section as-is instead of a
   dedicated narrow inner column. */
.kb-page-header__content {
	position: relative;
	z-index: 1;
	/* .kb-page-header's own base rule defaults to centered text (for the
	   plain centered hero variant) — this one only reuses --vh100/--
	   parallax, not --left, so without this override the text/checklist
	   inherited the centered default instead of production's flush-left
	   layout. */
	text-align: left;
}

/* --vh100's justify-content:center leaves empty space above the
   centered logo that's proportional to leftover 100vh space — a FIXED
   negative margin-top on .kb-page-header__content (tried first) only
   works at the one viewport height it was measured against; on a
   shorter real browser window the same px value overshoots past
   .kb-page-header's own `overflow: hidden` and clips the logo. Fixing
   this robustly means not fighting the vh-based centering at all:
   this page-only modifier (added to the outer .kb-page-header group
   alongside --vh100) switches to top-aligned content with its own
   fixed, viewport-independent padding-top, so the gap above the logo
   is a constant ~84px (roughly half of the ~167px centered gap
   originally measured) at every window size, never vh-dependent. */
.kb-page-header--vh100.kb-page-header--top-gap-84 {
	justify-content: flex-start;
	padding-top: 84px;
}

.kb-page-header__kicker {
	color: var(--kb-color-dark);
	text-transform: uppercase;
	font-size: 15px;
	font-weight: 600;
	letter-spacing: 0.04em;
	margin: 0 0 16px;
}

.kb-page-header__title {
	color: var(--kb-color-dark);
	font-size: 44.79px;
	font-weight: 600;
	line-height: 1.2;
	margin: 0 0 24px;
}

.kb-page-header__intro {
	font-size: 17px;
	line-height: 1.7;
	color: var(--kb-color-gray-text);
	max-width: 780px;
	margin: 0 auto 32px;
}

/* Reported gray-on-light-hero-background as hard to read on more than
   one page now (/woocommerce-agentur/, /shopify/) — dark reads reliably
   on every hero's ~white 0.95-opacity overlay. Scoped to .kb-page-header
   context (not the bare .kb-page-header__intro/.kb-check-list li rules
   used elsewhere in body sections), and placed before the --dark/
   --accent/--video/--narrow overrides below so those keep winning on
   equal specificity via source order — variants that already picked
   their own color stay untouched. */
.kb-page-header .kb-page-header__intro,
.kb-page-header .kb-check-list li {
	color: var(--kb-color-dark);
}

@media (max-width: 781px) {
	.kb-page-header {
		padding: 64px 24px;
	}

	.kb-page-header__title {
		font-size: 29.86px;
	}
}

/* Dark variant — shorter, dim overlay over the bg image instead of the
   near-opaque light one, white title. No kicker/intro needed here, but
   both still work if used. */
.kb-page-header--dark {
	padding: 64px 24px;
}

/* Solid brand-orange bg with a small repeating tile pattern instead of
   the shared full-bleed .kb-page-header__bg image + light overlay —
   production's /magento-agentur/magento-support/ hero has no dimming
   overlay at all (overlay_alpha 0 in the original), just the raw
   pattern directly on the brand color. One-off, not meant to be
   combined with .kb-page-header__bg. */
.kb-page-header--magento-support {
	background-color: #f26322;
	background-image: url("https://staging.knorke.de/wp-content/uploads/2021/05/magento-support-pattern-bg-1.png");
	background-repeat: repeat;
	background-size: 25%;
}

.kb-page-header__form-card {
	background: var(--kb-color-white);
	border-radius: var(--kb-radius-card);
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
	padding: 32px;
}

/* Taller variant for pages where the reference hero has more vertical
   breathing room than the shared --dark padding gives (e.g. /fonts/). */
.kb-page-header--tall {
	padding: 136px 24px;
}

/* Fixed-height variant matching the reference's data-height-ratio="50"
   hero pattern (~450px, same convention as .kb-blog-hero) — for headers
   that are just an image + title with no kicker/intro, padding alone
   can't reliably reach the reference height (e.g. /jobs/). */
.kb-page-header--h450 {
	min-height: 450px;
	display: flex;
	align-items: center;
	justify-content: center;
}

@media (max-width: 599px) {
	.kb-page-header--h450 {
		min-height: 320px;
	}
}

.kb-page-header--dark .kb-page-header__bg::after {
	background: rgba(20, 22, 24, 0.3);
}

.kb-page-header--dark .kb-page-header__title,
.kb-page-header--dark .kb-page-header__kicker {
	color: var(--kb-color-white);
}

/* /seo-agentur/ is the first --dark hero with an intro paragraph and
   check-list — production reads those white too. */
.kb-page-header--dark .kb-page-header__intro,
.kb-page-header--dark .kb-check-list li {
	color: var(--kb-color-white);
}

/* CTA button inverts to a white pill with dark text against the hero
   photo; on hover it flips to a transparent/outline look (border stays
   white, text turns white too — the shared :hover rule would otherwise
   drop it to --kb-color-dark, invisible on this dark background). */
.kb-page-header--dark .wp-block-buttons .wp-block-button__link {
	background-color: var(--kb-color-white);
	color: var(--kb-color-dark);
	border-color: var(--kb-color-white);
}

.kb-page-header--dark .wp-block-buttons .wp-block-button__link:hover {
	background-color: transparent;
	color: var(--kb-color-white);
}

/* Full-viewport-height variant (e.g. WordPress-Support). Stacks its
   children (e.g. a product image above the kicker/title/intro block)
   vertically — without flex-direction:column here, multiple children
   would sit side by side in the default row direction and squeeze/overflow
   each other. */
.kb-page-header--vh100 {
	min-height: 100vh;
	display: flex;
	flex-direction: column;
	justify-content: center;
}

/* Left-aligned content variant — kicker/title/intro/button read from the
   left edge of the (still centered-as-a-block) content column, instead of
   the shared centered-text default. */
.kb-page-header--left {
	text-align: left;
	/* Production insets this hero ~70px from the content edge, not the
	   shared 24px — measured off the live page. */
	padding-left: 72px;
	padding-right: 72px;
}

.kb-page-header--left .kb-page-header__inner {
	max-width: none;
	width: 100%;
}

.kb-page-header--left .kb-page-header__intro {
	margin: 0 0 32px;
}

@media (max-width: 781px) {
	.kb-page-header--left {
		padding-left: 24px;
		padding-right: 24px;
	}
}

/* --left normally goes full-bleed (max-width:none), but /wordpress-agentur/'s
   production reference caps its single-column hero text at 1020px even
   though the background image still spans the full width — add this
   modifier on .kb-page-header__inner when a --left hero needs that cap
   back instead of introducing a whole new page-header variant for it. */
.kb-page-header--left .kb-page-header__inner.kb-page-header__inner--narrow {
	max-width: 1020px;
	width: 100%;
	/* Without this, the inherited `margin: 0 auto` from the base
	   .kb-page-header__inner rule auto-centers this 1020px box inside its
	   wider --left container instead of staying flush-left — the --left
	   variant above only neutralizes that by setting width:100% (no
	   leftover space to center into), but re-capping the width here at
	   1020px reintroduces the leftover space, so it needs its own reset. */
	margin-left: 0;
	margin-right: 0;
}

/* Production's title here measures 60px/400 (not the shared 44.79px/600) —
   weight kept at 500 per the site-wide minimum-weight-500 rule, same
   reasoning as --accent below. */
.kb-page-header--left .kb-page-header__inner--narrow .kb-page-header__title {
	font-size: 60px;
	font-weight: 500;
}

/* Intro text + checklist here measure 18px/dark on production, not the
   shared 17px/gray-text — and the intro paragraph runs the full 1020px
   column width, not the shared 780px cap. */
.kb-page-header--left .kb-page-header__inner--narrow .kb-page-header__intro,
.kb-page-header--left .kb-page-header__inner--narrow .kb-check-list li {
	font-size: 18px;
	line-height: 1.75;
	color: var(--kb-color-dark);
}

.kb-page-header--left .kb-page-header__inner--narrow .kb-page-header__intro {
	max-width: none;
}

/* /woocommerce-agentur/-only override: wider column (1200px, not the
   shared 1020px) and a bolder title (600, not the shared 500). Extra
   modifier class rather than editing --narrow itself, since 4 other
   pages share that class at the original values. */
.kb-page-header--left .kb-page-header__inner--narrow.kb-page-header__inner--wide {
	max-width: 1200px;
}

.kb-page-header--left .kb-page-header__inner--narrow.kb-page-header__inner--wide .kb-page-header__title {
	font-weight: 600;
}

/* /woocommerce-agentur/ has no intro paragraph between the title and the
   checklist (unlike the other --narrow pages) — production measures a
   36px gap there. Scoped to the title-directly-followed-by-checklist
   case via the adjacent-sibling selector, so pages that do have an intro
   paragraph in between (title + p, not title + ul) keep their own
   already-verified 24px margin untouched. Margins collapse against the
   checklist's own 24px margin-top (.kb-check-list), so this needs to be
   the full 36px, not the 12px difference. */
.kb-page-header--left .kb-page-header__inner--narrow .kb-page-header__title + .kb-check-list {
	margin-top: 36px;
}

/* Two-column variant (text left, media right) — the standard shape for
   most landing-page heroes (services/products with a header image next to
   the pitch). Unlike --left, this caps .kb-page-header__inner at the
   site's normal narrow content width instead of going full-bleed: with a
   second column already sharing the row, an unconstrained width would
   stretch both columns far past what the reference design uses. */
.kb-page-header--split {
	text-align: left;
}

.kb-page-header--split .kb-page-header__inner {
	max-width: var(--kb-container-width-narrow);
	width: 100%;
}

.kb-page-header--split .kb-page-header__intro {
	margin: 0 0 32px;
}

/* Plain, larger, non-uppercase kicker (measured 31px/600 on production) —
   same reasoning as --accent below: scoped here, not changed globally,
   since centered heroes elsewhere keep the small uppercase eyebrow. */
.kb-page-header--split .kb-page-header__kicker {
	font-size: 31px;
	font-weight: 600;
	text-transform: none;
	letter-spacing: normal;
}

/* Production's two-column hero title measures 53.75px (line-height stays
   the shared 1.2 ratio, so no separate override needed there). */
.kb-page-header--split .kb-page-header__title {
	font-size: 53.75px;
}

/* /e-mail-marketing-agentur/ only: 5px smaller than the shared --split
   size, requested as a one-off exception — scoped so the other 11 pages
   using --split keep their current size. */
.kb-page-header--split .kb-page-header__title.kb-page-header__title--tight {
	font-size: 48.75px;
}

@media (max-width: 781px) {
	.kb-page-header--split .kb-page-header__title {
		font-size: 35px;
	}
}

/* Solid accent (yellow) background instead of a dimmed bg image — no
   .kb-page-header__bg image is used on this variant, so no overlay is
   needed either. */
.kb-page-header--accent {
	background: var(--kb-color-accent);
}

/* On the yellow-bg variant the kicker is a plain, larger, non-uppercase
   line (measured 26px/400 on production) rather than the shared small
   uppercase eyebrow — scoped here rather than changing
   .kb-page-header__kicker globally, since other pages (e.g. Services) use
   the shared uppercase eyebrow as-is. */
.kb-page-header--accent .kb-page-header__kicker {
	font-size: 26px;
	font-weight: 500;
	text-transform: none;
	letter-spacing: normal;
	color: #000;
	margin-bottom: 8px;
}

/* Production's hero H1 is 60px (the shared default is 44.79px). Weight is
   400 there; kept at 500 to respect this project's site-wide
   minimum-weight-500 rule. */
.kb-page-header--accent .kb-page-header__title {
	font-size: 60px;
	font-weight: 500;
}

/* Lead text and perk lists run the full content width here (the shared
   .kb-page-header__intro caps at 780px, which wrapped the lead about a
   third too early) and sit one step up in size. */
.kb-page-header--accent .kb-page-header__intro {
	max-width: none;
	font-size: 18px;
	line-height: 1.75;
}

.kb-page-header--accent .kb-check-list li {
	font-size: 18px;
	line-height: 1.75;
}

/* Production's hero checklist here uses plain black check icons (no
   accent-color class), unlike other checklists on this page (e.g. the
   pricing list) which are intentionally yellow — scoped to this hero only. */
.kb-page-header--accent .kb-check-list li::before {
	background-color: #000;
}

/* Lead text + checklist copy here was still inheriting the shared
   muted-gray body-text color — production reads pure black on this hero. */
.kb-page-header--accent .kb-page-header__intro,
.kb-page-header--accent .kb-check-list li {
	color: #000;
}

/* Logo marquee below the button: 20% larger than the shared
   .kb-partners-slider size, and 50% faster than the shared 40s scroll —
   scoped to this hero so the actual homepage Partners section (which
   reuses the same base classes) is unaffected. */
.kb-page-header--accent .kb-partners-slider__item {
	height: 120px;
}

.kb-page-header--accent .kb-partners-slider__item img {
	max-width: 220px;
	object-fit: contain;
}

.kb-page-header--accent .kb-partners-slider__track {
	animation-duration: 27.6s;
}

/* --- Image collage for a .kb-feature__image column (multiple images side
   by side instead of one photo or one stacked column) --- */
.kb-feature__image--grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 8px;
}

.kb-feature__image--grid .wp-block-image {
	margin: 0;
}

.kb-feature__image--grid img {
	aspect-ratio: 1 / 1;
	object-fit: cover;
}

/* --- Font card grid (Fonts overview page) --- */
.kb-font-grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 32px;
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
	padding: 0 24px;
}

/* EN /fonts/ page requested 100px breathing room before the contact
   section below (which otherwise sits flush against the grid) — scoped
   modifier rather than the shared .kb-font-grid rule, since DE's /fonts/
   page uses the same grid and wasn't flagged. */
.kb-font-grid--gap-bottom-100 {
	margin-bottom: 100px;
}

.kb-font-card {
	display: block;
	text-decoration: none;
	color: inherit;
}

.kb-font-card__img {
	position: relative;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	border-radius: 4px;
	background: var(--kb-color-darker);
}

.kb-font-card__img img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform 0.4s ease, opacity 0.3s ease;
}

.kb-font-card__img::after {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--kb-color-darker);
	opacity: 0;
	transition: opacity 0.3s ease;
}

.kb-font-card:hover .kb-font-card__img::after {
	opacity: 0.5;
}

.kb-font-card:hover .kb-font-card__img img {
	transform: scale(1.05);
}

.kb-font-card__title {
	margin: 16px 0 0;
	font-size: 20px;
	font-weight: 600;
	text-align: center;
}

@media (max-width: 599px) {
	.kb-font-grid {
		grid-template-columns: 1fr;
	}
}

/* --- Tool/logo grid grouped by category (used in the "Werkzeuge" pattern,
   e.g. /e-commerce-agentur/) — a flex-wrap flow rather than a fixed-column
   grid, since categories have wildly different item counts (4 vs. 18) and a
   rigid grid would leave uneven gaps in the shorter ones. Matches
   production's own icon-inline flow, which does the same. */
.kb-tool-group {
	margin-bottom: 72px;
}

.kb-tool-group:last-child {
	margin-bottom: 0;
}

.kb-tool-group .wp-block-separator.is-style-kb-accent {
	margin: 16px 0 24px;
}

.kb-tool-grid {
	display: flex;
	flex-wrap: wrap;
	gap: 28px 18px;
}

.kb-tool-item {
	width: 100px;
	text-align: center;
}

.kb-tool-item__logo {
	display: block;
	position: relative;
	width: 100px;
	height: 100px;
	margin: 0 auto;
}

.kb-tool-item__logo img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.kb-tool-item__label {
	display: block;
	margin: 8px 0 0;
	font-size: 14px;
	color: var(--kb-color-dark);
}

/* --- Section heading used above a reused pattern (Team, Logowall, etc.) --- */
.kb-section-title {
	text-align: center;
	max-width: 700px;
	margin: 96px auto 48px;
}

.kb-section-title h2 {
	font-size: 44.79px;
	font-weight: 600;
	line-height: 1.2;
	margin: 0 0 16px;
}

.kb-section-title .wp-block-separator.is-style-kb-accent {
	margin: 0 auto;
}

/* /cases/ "A selection of our customers:" — requested 50% less space to
   the logowall below it than the shared 48px default. */
.kb-section-title--gap-24 {
	margin-bottom: 24px;
}

@media (max-width: 781px) {
	.kb-section-title h2 {
		font-size: 29.86px;
	}
}

/* --- Feature row: image + heading + text + button, image-left/text-right --- */
.kb-feature {
	padding: 64px 24px;
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
}

/* +100px top/bottom over the shared 64px, requested as a one-off for
   "Das bringt Dich nach vorn" on /seo-agentur/ — not the sitewide
   padding-scale pass the user wants to do separately/later. */
.kb-feature--extra-padding {
	padding-top: 164px;
	padding-bottom: 164px;
}

/* 100px top spacing only (bottom stays the shared 64px) — requested for
   /cases/furore-werbung/'s three main sections. */
.kb-feature--top-100 {
	padding-top: 100px;
}

/* /seo-agentur/-only: normalize every headline to weight 600.
   .kb-feature__title--service (700) and .kb-section-title--lg (500)
   are shared classes used correctly at their own weight on other
   pages — scoped via the body's page-id so this doesn't touch them
   elsewhere. */
body.page-id-61455 .kb-feature__title--service,
body.page-id-61455 .kb-section-title--lg {
	font-weight: 600;
}

/* /cases/pvsid/-only: normalize every headline to weight 600.
   .kb-case-hero__title (800) and .kb-case-meta__client (500) are the
   shared single-Case hero/meta components, used at their own weight on
   every other case study — scoped via the body's postid so this doesn't
   touch them elsewhere. */
body.postid-140689 .kb-case-hero__title,
body.postid-140689 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/tag-der-schiene/-only: same normalize-to-600 exception as
   pvsid above. */
body.postid-106538 .kb-case-hero__title,
body.postid-106538 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/cosyworld/-only: meta client normalized to 600 like pvsid
   above, but the hero title itself keeps production's actual 900
   (requested explicitly — not every case study's hero runs at the
   shared 800 default). */
body.postid-96652 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-96652 .kb-case-hero__title {
	font-weight: 900;
}

/* /cases/fast-forward/-only: hero title at 900 (matches production's
   own weight here; an earlier round briefly set this to 600 before
   being corrected back). */
body.postid-96165 .kb-case-hero__title {
	font-weight: 900;
}

/* /cases/theater-im-delphi/-only: hero title at 900, matches production. */
body.postid-94942 .kb-case-hero__title {
	font-weight: 900;
}

/* /cases/cold-world/-only: hero title at 900 (matches production), every
   other headline on the page at 600 — .kb-case-meta__client was the only
   one still running at its shared 500 default. */
body.postid-93471 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-93471 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/buschfunk/-only: hero at 900 (matches production), every other
   headline at 600. */
body.postid-91748 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-91748 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/verdi/-only: hero at 900 (matches production), every other
   headline at 600. */
body.postid-90800 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-90800 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/addilo/-only: hero at 900 (matches production), every other
   headline at 600. */
body.postid-75993 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-75993 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/sleep8/-only: hero at 900 (matches production), every other
   headline at 600. */
body.postid-63047 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-63047 .kb-case-meta__client {
	font-weight: 600;
}

/* /en/cases/sleep8/ (postid-68279) — same page as postid-63047 above,
   English translation. */
body.postid-68279 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-68279 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/thelatest/-only: meta client at 600 like every other case; the
   hero title itself is never rendered here (see single-portfolio.php's
   $hero_hide_title), so no hero font-weight override is needed. */
body.postid-61489 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/g-class-experience-2/-only: hero at 900 (matches production),
   every other headline at 600. */
body.postid-61037 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-61037 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/beyosa/-only: hero at 900 (matches production), every other
   headline at 600. */
body.postid-60893 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-60893 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/ehappy/-only: hero at 900 (matches production), every other
   headline at 600 (production actually runs its lone in-page h2 at 900
   too, but per standing instruction every case page normalizes in-body
   headlines to 600 regardless). */
body.postid-59884 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-59884 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/rollupmonster/-only: hero at 900 (matches production), every
   other headline at 600. */
body.postid-59704 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-59704 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/berlin-mural-fest/-only: hero at 900 (matches production),
   every other headline at 600. */
body.postid-59144 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-59144 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/berlin-mural-fest/-only: vertically center every text/image
   row's two columns against each other — same fix and same reason as
   /cases/bannerheld-de/ and /cases/tante-biggie/ above. This page's
   rows were never given this fix on either language (confirmed still
   top-aligned on DE too via measurement), unlike the font-weight rule
   above which was already correct. */
body.postid-59144 .kb-feature__row {
	align-items: center !important;
}

body.postid-59144 .kb-feature__content {
	align-self: center !important;
}

/* /en/cases/berlin-mural-fest/ (postid-68288) — same page as postid-59144
   above, English translation. Hero/headline weights already matched
   production via the shared .kb-feature__title/.kb-case-meta__client
   defaults + hero-only bump, mirrored here; valign-middle mirrored too. */
body.postid-68288 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-68288 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-68288 .kb-feature__row {
	align-items: center !important;
}

body.postid-68288 .kb-feature__content {
	align-self: center !important;
}

/* /cases/wallpen/-only: hero at 900 (matches production), every other
   headline at 600. */
body.postid-59055 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-59055 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/der-bannerexpress/-only: hero at 900 (matches production),
   every other headline at 600. */
body.postid-58979 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-58979 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/wheel2wall/-only: production runs weight 900 on every headline
   here, not just the hero (verified against all four .kb-feature__title
   instances on this page) — deviates from the usual hero-900/rest-600
   split seen on other case pages. */
body.postid-58631 .kb-case-hero__title,
body.postid-58631 .kb-feature__title {
	font-weight: 900;
}

body.postid-58631 .kb-case-meta__client {
	font-weight: 600;
}

/* /en/cases/wheel2wall/ (postid-68061) — same page as postid-58631
   above, English translation. Requested at weight 600, but this page's
   production (like tante-biggie) runs 900 on every headline — matched
   DE/production rather than the literal ask. */
body.postid-68061 .kb-case-hero__title,
body.postid-68061 .kb-feature__title {
	font-weight: 900;
}

body.postid-68061 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/wunstkunst/-only: production runs weight 900 on every headline
   here too (hero + all three .kb-feature__title instances), same
   deviation as /cases/wheel2wall/ above. */
body.postid-55237 .kb-case-hero__title,
body.postid-55237 .kb-feature__title {
	font-weight: 900;
}

/* /en/cases/wunstkunst/-only: Karl Valentin quote runs without the
   left accent border per explicit request (DE keeps its border, same
   pattern as /en/cases/cosyworld/). */
body.postid-68576 .wp-block-quote {
	border-left: none;
}

body.postid-55237 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/ebm-financial/-only: production runs weight 900 on every
   headline here too (hero + both .kb-feature__title instances), same
   deviation as /cases/wheel2wall/ and /cases/wunstkunst/ above. */
body.postid-55209 .kb-case-hero__title,
body.postid-55209 .kb-feature__title {
	font-weight: 900;
}

body.postid-55209 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/tante-biggie/-only: production runs weight 900 on every
   headline here too (hero + both .kb-feature__title instances), same
   deviation as /cases/wheel2wall/, /cases/wunstkunst/ and
   /cases/ebm-financial/ above. */
body.postid-54942 .kb-case-hero__title,
body.postid-54942 .kb-feature__title {
	font-weight: 900;
}

body.postid-54942 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/tante-biggie/-only: vertically center every text/image row's
   two columns against each other — same fix and same reason as
   /cases/bannerheld-de/ above (WP global styles' !important beats the
   shared .kb-feature__row default, and .kb-feature__content's own
   align-self:flex-start needs overriding on top of that). */
body.postid-54942 .kb-feature__row {
	align-items: center !important;
}

body.postid-54942 .kb-feature__content {
	align-self: center !important;
}

/* /cases/tante-biggie/-only: force the first gallery to genuinely 2 per
   row — same issue as the .kb-case-media gallery fix above: the
   block's own "columns" attribute/class is just a label with no
   matching CSS in this theme (no core block-library stylesheet
   loaded), so flex-basis:auto was sizing each square-cropped photo off
   its own dimensions instead. */
body.postid-54942 .kb-case-media .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 8px) / 2);
}

/* /en/cases/tante-biggie/ (postid-68321) — same page as postid-54942
   above, English translation. Requested at weight 600, but this page's
   production runs 900 on every headline just like DE's version does
   (see comment above) — matched DE/production rather than the literal
   ask; same valign-middle and 2-col gallery fixes as DE, mirrored. */
body.postid-68321 .kb-case-hero__title,
body.postid-68321 .kb-feature__title {
	font-weight: 900;
}

body.postid-68321 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-68321 .kb-feature__row {
	align-items: center !important;
}

body.postid-68321 .kb-feature__content {
	align-self: center !important;
}

body.postid-68321 .kb-case-media .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 8px) / 2);
}

/* /cases/mondo-pazzo/-only: production runs weight 900 on every
   headline here too (hero + both .kb-feature__title instances), same
   deviation as the last several cases above. Also vertically center
   every text/image row's two columns, and force the gallery to
   genuinely 3 per row (same "columns" attribute/no-matching-CSS issue
   as the other galleries fixed above). */
body.postid-54864 .kb-case-hero__title,
body.postid-54864 .kb-feature__title {
	font-weight: 900;
}

body.postid-54864 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-54864 .kb-feature__row {
	align-items: center !important;
}

body.postid-54864 .kb-feature__content {
	align-self: center !important;
}

body.postid-54864 .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

body.postid-54864 .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

/* /en/cases/mondo-pazzo/ (postid-68407) — same page as postid-54864
   above, English translation. Requested at weight 600, but this page's
   production (like tante-biggie/wheel2wall) runs 900 on every headline
   — matched DE/production rather than the literal ask. */
body.postid-68407 .kb-case-hero__title,
body.postid-68407 .kb-feature__title {
	font-weight: 900;
}

body.postid-68407 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-68407 .kb-feature__row {
	align-items: center !important;
}

body.postid-68407 .kb-feature__content {
	align-self: center !important;
}

body.postid-68407 .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

body.postid-68407 .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

/* /make-love-not-war/: same 3-column gallery-columns-is-cosmetic-only
   fix as above (no WP core block-library CSS loaded, so the "columns"
   attribute needs an explicit flex-basis rule per page). */
body.postid-77674 .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

body.postid-77674 .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

/* /einfach-wieder-esel-sein/: same 3-column gallery fix. */
body.postid-64308 .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

body.postid-64308 .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

/* /sorry/: same 3-column gallery fix. */
body.postid-59597 .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

body.postid-59597 .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

/* /sorry/'s hero: the only featured image available (sorry-vorschau.jpg)
   is 600x338 — badly upscaled to fill a 75vh hero, no larger source
   exists (checked). User chose to keep the image rather than drop it or
   supply a bigger one. backdrop-filter on the overlay (which already
   sits directly over the background image, behind the z-index:1 title)
   blurs just the photo layer without blurring the text above it —
   turns visible upscale artifacts into an intentional-looking soft
   backdrop instead of a technical flaw. */
body.postid-59597 .kb-blog-hero__overlay {
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
}

/* /the-weird-crew-5-year-anniversary/: same 3-column gallery fix, plus
   a uniform 16:9 crop per image (raw event photos, mixed portrait/
   landscape natively — requested explicitly, not WP core's own
   "is-cropped" default of 1:1 square, so scoped here rather than made
   generic). */
body.postid-57371 .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

body.postid-57371 .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

body.postid-57371 .wp-block-gallery.kb-feature__row figure.wp-block-image img {
	aspect-ratio: 16 / 9;
	object-fit: cover;
	width: 100%;
	height: 100%;
}

/* /pop-up-zentrale-wien/: "das gleiche" as the-weird-crew-5-year-
   anniversary — same raw-event-photo DSC0xxxx.jpg naming/source, same
   3-column gallery + lightbox + uniform 16:9 crop. */
body.postid-57305 .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

body.postid-57305 .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

body.postid-57305 .wp-block-gallery.kb-feature__row figure.wp-block-image img {
	aspect-ratio: 16 / 9;
	object-fit: cover;
	width: 100%;
	height: 100%;
}

/* /spud-bencer/: the vimeo embed below the gallery had no width
   constraint of its own (unlike .kb-feature-wrapped blocks), so it
   rendered edge-to-edge across the full available content column
   instead of matching the gallery's 1200px width above it. */
body.postid-56712 .wp-block-embed {
	max-width: var(--kb-container-width-narrow);
	margin-left: auto;
	margin-right: auto;
}

/* /cases/bullet-shop-berlin/-only: standard hero-900/rest-600 split
   (no page-wide 900 deviation this time — verified against production).
   Vertically center every text/image row's two columns, and force the
   first gallery (7 images) to genuinely 4 per row — same gap conflict
   and no-matching-CSS issues as the galleries fixed above. The second,
   much larger "social media" gallery (66 fan photos) is intentionally
   left untouched per explicit instruction — no lightbox, no layout
   changes. */
body.postid-54568 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-54568 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-54568 .kb-feature__row {
	align-items: center !important;
}

body.postid-54568 .kb-feature__content {
	align-self: center !important;
}

body.postid-54568 .kb-case-media .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

body.postid-54568 .kb-case-media .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

/* /en/cases/bullet-shop-berlin/ (postid-68384) — same page as postid-54568
   above, English translation. */
body.postid-68384 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-68384 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-68384 .kb-feature__row {
	align-items: center !important;
}

body.postid-68384 .kb-feature__content {
	align-self: center !important;
}

/* blaubeeren-reihe.png is a purely decorative strip (1016x280), not one
   of the actual product-shot gallery images — moved out of the
   wp:gallery block entirely (no lightbox membership) and placed right
   after it as its own full-width image inside the same .kb-case-media
   background. */
.kb-case-media__deco {
	width: 100%;
	max-width: var(--kb-container-width-narrow);
	margin: 24px auto 0;
}

.kb-case-media__deco img {
	width: 100%;
	height: auto;
	display: block;
}

/* Row of social icon links below "Let the social media burn" — matches
   production's Instagram/YouTube/Tumblr row (its Facebook icon glyph
   is broken/invisible there too, so only these three are replicated).
   Same inline-SVG-icon technique as .kb-vmenu__social in the header,
   just sized up for a standalone content section instead of the thin
   sidebar menu. */
.kb-case-social {
	display: flex;
	justify-content: center;
	align-items: center;
	gap: 32px;
	margin-top: 32px;
}

.kb-case-social__icon {
	display: block;
	color: var(--kb-color-dark);
	opacity: 0.85;
}

.kb-case-social__icon svg {
	width: 44px;
	height: 44px;
	display: block;
}

.kb-case-social__icon:hover {
	opacity: 1;
	color: var(--kb-color-accent);
}

/* /cases/wunstkunst/-only: the intro section's image should sit flush
   against the hero right above it (no gap), so it reads as continuing
   down out of the hero photo instead of looking cropped off. Because
   this column is a stretched flex item (align-items:normal on
   .kb-feature__row), a negative margin-top here only translates to
   half that much visible upward shift — empirically measured 1px
   margin = 0.5px shift — so the value is double the actual 109.375px
   gap that needed closing. */
body.postid-55237 .kb-feature:first-child .kb-feature__image {
	margin-top: -219px;
}

/* /cases/wheel2wall/-only: the intro section ("Wheel2Wall - Charity" +
   branding logo) gets 80vh with its content vertically centered inside
   that height, instead of just sitting at its natural content height.
   :first-child, not :first-of-type — the latter matched the unrelated
   second gallery too (a <figure>, the first of ITS tag among siblings),
   forcing it into a broken single-column flex-direction:column stack. */
body.postid-58631 .kb-feature:first-child {
	min-height: 80vh;
	display: flex;
	flex-direction: column;
	justify-content: center;
}

/* /cases/bannerheld-de/-only: hero at 900 (matches production), every
   other headline at the shared default 600. */
body.postid-55272 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-55272 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/bannerheld-de/-only: vertically center each text/image row's two
   columns against each other. .kb-feature__row already declares
   align-items:center as its base rule, but WP's own global-styles
   ".wp-block-columns { align-items: normal !important; }" always wins
   over it regardless of specificity — only another !important can beat
   an !important. On top of that, the theme's own shared
   .kb-feature__content rule further down (align-self:flex-start, so
   text stays pinned to the top against a taller image by default on
   every other case page) also needs overriding here specifically. */
body.postid-55272 .kb-feature__row {
	align-items: center !important;
}

body.postid-55272 .kb-feature__content {
	align-self: center !important;
}

/* /en/cases/bannerheld-banner-print-shop/ (postid-68397) — same page as
   postid-55272 above, English translation. */
body.postid-68397 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-68397 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-68397 .kb-feature__row {
	align-items: center !important;
}

body.postid-68397 .kb-feature__content {
	align-self: center !important;
}

/* /cases/der-bannerexpress/-only: gaps between sections were too tight —
   give every .kb-feature section 70vh and center its content vertically
   inside that height instead of just adding more padding. */
body.postid-58979 .kb-feature {
	min-height: 70vh;
	display: flex;
	flex-direction: column;
	justify-content: center;
}

/* /cases/zukunft-mit-stern/-only: hero at 900 (matches production), every
   other headline at 600. Production itself actually runs its in-page h2s
   at 900 too, but per standing instruction every case page normalizes
   in-body headlines to 600 regardless of the legacy per-element value. */
body.postid-63087 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-63087 .kb-case-meta__client {
	font-weight: 600;
}

/* /cases/zukunft-mit-stern/-only: vertically center the two text/image
   rows against each other — never given this fix on either language
   (confirmed both still top-aligned via measurement), same fix as the
   other cases above. */
body.postid-63087 .kb-feature__row {
	align-items: center !important;
}

body.postid-63087 .kb-feature__content {
	align-self: center !important;
}

/* /en/cases/zukunft-mit-stern/ (postid-68282) — same page as postid-63087
   above, English translation. */
body.postid-68282 .kb-case-hero__title {
	font-weight: 900;
}

body.postid-68282 .kb-case-meta__client {
	font-weight: 600;
}

body.postid-68282 .kb-feature__row {
	align-items: center !important;
}

body.postid-68282 .kb-feature__content {
	align-self: center !important;
}

/* /cases/buschfunk/'s testimonial quote measures at the site's plain
   shared H2 size (44.79px/600) rather than virtualQ's oversized 60px/900
   or cosyworld's smaller 26px/600 — scoped override, same reasoning as
   both of those. */
body.postid-91748 .kb-testimonial__quote {
	font-size: 44.79px;
	font-weight: 600;
}

body.postid-91748 .kb-testimonial__cite {
	font-size: 18px;
	font-weight: 400;
	font-style: normal;
}

/* Scroll-rotated record cover (first use: /cases/buschfunk/'s "Musik in
   unseren Ohren" section) — rotation itself is driven by vinyl-spin.js;
   this only pins the rotation origin to the disc's own centre. */
.kb-vinyl {
	transform-origin: 50% 50%;
}

/* /cases/cosyworld/'s testimonial quote runs much smaller than
   virtualQ's (production measured 26px/600 quote, 15px/400/normal
   cite) — scoped override rather than changing the shared default,
   which virtualQ needs at its own larger 60px/900. */
body.postid-96652 .kb-testimonial__quote {
	font-size: 26px;
	font-weight: 600;
}

body.postid-96652 .kb-testimonial__cite {
	font-size: 15px;
	font-weight: 400;
	font-style: normal;
}

/* /en/cases/cosyworld/ (postid-144401) — same page as above, English
   translation. It has no scoped override of its own so it was falling
   back to virtualQ's 60px/900 default; match DE's production-measured
   size here too. Left accent border removed per explicit request for
   this page only (DE keeps the default border). */
body.postid-144401 .kb-testimonial__quote {
	font-size: 26px;
	font-weight: 600;
}

body.postid-144401 .kb-testimonial__cite {
	font-size: 15px;
	font-weight: 400;
	font-style: normal;
}

body.postid-144401 .kb-testimonial {
	border-left: none;
}

/* /serverside-tracking-funktion-anwendung-und-vorteile/'s closing CTA
   form runs full content width (~1300px) by default — narrow it to the
   theme's existing 800px container step, same value the
   .kb-contact--narrow-800 modifier uses elsewhere, just applied
   directly since this page's form isn't built on the full .kb-contact
   component (it's a plain .kb-contact__form inside .kb-intro-cta). */
body.postid-108034 .kb-contact__form {
	max-width: var(--kb-container-width-narrowest);
	margin-left: auto;
	margin-right: auto;
}

/* Thin top divider, scoped to the container's own (narrow, centered)
   width rather than full-bleed — for two plain-background .kb-feature
   sections sitting back to back with no color/spacer between them, so
   they'd otherwise blend into one block. */
.kb-feature--divider-top {
	border-top: 1px solid var(--kb-color-gray-lighter);
}

/* Lets a direct child (e.g. a .kb-cases__grid.alignfull) actually reach
   full width — the base rule above caps this element itself at 1200px,
   so a 100%-width child inside it would still stop there. Keeps the
   padding/background from whichever other .kb-feature modifier this is
   combined with, just removes the width cap. */
.kb-feature--full-bleed {
	max-width: none;
}

/* Wide-but-not-full-bleed variant (1400px vs. the shared 1200px) — for
   sections that need more breathing room than the narrow container
   without going edge to edge, e.g. a 3-column case-story grid. */
.kb-feature--wide {
	max-width: var(--kb-container-width);
}

.kb-feature__row {
	align-items: center;
	gap: 64px;
}

/* 66.66% / 33.33% split (production's col-lg-8 / col-lg-4), e.g. the
   Shopify FAQ sections. flex-grow ratio rather than a % flex-basis so
   the row's own 64px gap is automatically subtracted before the 2:1
   split is applied, instead of having to bake the gap into the math.
   !important: WP core prints its own per-block generated-class rule
   (.wp-container-core-columns-is-layout-xxxxx > .wp-block-column
   {flex-grow:1}) for every plain wp:columns row with equal specificity
   to a plain child-combinator selector, but later in source order —
   it wins the equal-specificity tie without this. */
.kb-feature__row--faq > .kb-feature__content {
	flex: 2 1 0 !important;
}

.kb-feature__row--faq > .kb-feature__image {
	flex: 1 1 0 !important;
}

/* Same 1-part flex-basis as .kb-feature__image above, for a --faq row's
   narrow column when it's text, not an image (/gender-struggle-dieser-
   kundin/'s "Knorke in die Zukunft" side column) — .kb-feature__image
   itself also carries text-align:center + align-self:center, which
   would wrongly center-align that column's text; this reuses only the
   flex-ratio mechanism without those. */
.kb-feature__row--faq > .kb-feature__content--narrow {
	flex: 1 1 0 !important;
}

/* The row's own align-items:center above is routinely overridden back to
   "normal" by WP core's own per-instance layout-support style (a
   `.wp-container-core-columns-is-layout-xxxxx` rule, printed inline per
   block with !important) — confirmed via getComputedStyle on
   /int-agencies/'s "Globale Moves" row, where align-items measured
   "normal" despite this base rule. Text is pinned to the top by design
   (see .kb-feature__content below) so that mostly went unnoticed, but a
   row that actually wants both columns vertically centered needs this
   explicit !important opt-in rather than relying on the base rule alone. */
.kb-feature__row.kb-feature__row--valign-middle {
	align-items: center !important;
}

/* Text should always start at the top of its column instead of floating
   centered alongside a taller image, unless the row above opts back into
   centering via --valign-middle + .kb-feature__content--centered. */
.kb-feature__content {
	align-self: flex-start;
}

/* Centered independently of the row's own align-items (which WP core
   forces to "normal" on every .wp-block-columns via a global !important
   rule — overriding align-self on the child is the reliable way around
   that, rather than fighting the container property). */
.kb-feature__content.kb-feature__content--centered {
	align-self: center;
}

/* Flat, un-rounded, shadow-free card treatment for a .kb-feature__content
   column that production renders as a plain colored box (measured on
   /magento-agentur/: 36px padding, background:#fff or #f7f7f7, radius 0,
   no shadow — matches the site's Uncode-era "uncell style-color-*-bg"
   tiles). Two color variants rather than one generic modifier, since both
   occur side by side on the same page for different sections. */
.kb-feature__content.kb-feature__content--white-box {
	background: var(--kb-color-white);
	padding: 36px;
}

.kb-feature__content.kb-feature__content--gray-box {
	background: var(--kb-color-gray-light);
	padding: 36px;
}

/* Card with its CTA button pinned to the bottom regardless of how much
   text precedes it (/welches-onlineshop-system-zu-dir-passt/'s 4
   shop-system tiles — production keeps all 4 buttons on one baseline
   even though the checklists above them run different lengths).
   Combined modifier (not baked into --white-box/--gray-box alone,
   which other pages use for non-card contexts like an accordion). */
.kb-feature__content--white-box.kb-feature__content--card,
.kb-feature__content--gray-box.kb-feature__content--card {
	display: flex;
	flex-direction: column;
}

.kb-feature__content--white-box.kb-feature__content--card .wp-block-buttons,
.kb-feature__content--gray-box.kb-feature__content--card .wp-block-buttons {
	margin-top: auto;
	padding-top: 24px;
}

/* Third color variant — /usability-conversion-rate-optimierung/'s "Warum
   Knorke?" boxes sit on the section's own --kb-color-gray-light
   background, so --gray-box would be invisible here; production uses a
   slightly darker #eaeaea instead (measured, no matching site variable). */
.kb-feature__content.kb-feature__content--offwhite-box {
	background: #eaeaea;
	padding: 36px;
}

/* Vertical gap between a run of stacked, individually-boxed heading+text
   tiles (/magento-agentur/magento-sprachpaket/'s "Wobei unterstützt..."
   block, each own gray-box group rather than columns in a row) — measured
   36px on production, matching the tile's own padding. A dedicated
   modifier rather than a bare adjacent-sibling rule on
   --gray-box/--white-box themselves: those classes are also used on
   .wp-block-column siblings inside a flex row elsewhere (e.g.
   /magento-agentur/), where an added margin-top would misalign the row. */
.kb-feature__content--stacked + .kb-feature__content--stacked {
	margin-top: 36px;
}

/* /magento-agentur/magento-sprachpaket/'s "Lad dir hier direkt..."
   download section (.kb-section--dark): production's second-column
   checklist runs left-aligned with white text/icons, not the shared
   centered/gray-text default — scoped to this dark-section context since
   it's the only known page pairing a checklist with .kb-section--dark. */
.kb-section--dark .kb-check-list {
	text-align: left;
}

.kb-section--dark .kb-check-list li {
	color: var(--kb-color-white);
}

.kb-section--dark .kb-check-list li::before {
	background-color: var(--kb-color-white);
}

/* /shopware-6-mit-knorke/'s "Leistungen" marquee (reuses .kb-tag-marquee,
   see sections.css) sits on this dark background — the shared item/sep
   color defaults to --kb-color-dark for the light sections it was built
   for (/wordpress-support/), which would be invisible here. */
.kb-section--dark .kb-tag-marquee__item,
.kb-section--dark .kb-tag-marquee__sep {
	color: var(--kb-color-white);
}

/* /shopware-6-mit-knorke/'s "Leistungen" marquee needs to bleed edge-to-
   edge past .kb-section--dark's own reading-width padding — same
   negative-margin cancellation technique as .kb-cases__grid.alignfull
   (vw-based, not %-based: the marquee's own containing block after
   .kb-section--dark's padding is a different basis than the padding
   itself, so only a shared vw formula reliably cancels it — see that
   rule's own comment in sections.css for the full reasoning). */
.kb-tag-marquee--full-bleed {
	margin-inline: calc(-1 * max(24px, calc((100vw - var(--kb-vmenu-reserve) - var(--kb-container-width-narrow)) / 2 + 24px)));
}

/* Same page, same marquee: requested 15px larger than the shared 29px
   base (which /wordpress-support/'s tag marquee still uses unchanged). */
.kb-tag-marquee--lg .kb-tag-marquee__item,
.kb-tag-marquee--lg .kb-tag-marquee__sep {
	font-size: 44px;
}

/* Box headline inside a white/gray tile: measured 26px on production for
   every page currently using these tiles (/e-mail-marketing-agentur/,
   /shopify/), smaller than the 29px bare .kb-feature__title--sm default
   used everywhere else. */
.kb-feature__content--white-box .kb-feature__title--sm,
.kb-feature__content--gray-box .kb-feature__title--sm {
	font-size: 26px;
}

/* Tighter row gap for a shared .kb-feature__row carrying white/gray box
   tiles — production's own gutter for this tile pattern is 36px (matches
   the tile's own padding), well under the row's normal 64px default.
   Opt-in modifier rather than lowering .kb-feature__row itself: other
   pages (e.g. /magento-agentur/) reuse the same white/gray-box tiles at a
   different, smaller gap (18px) so the value isn't universal. */
.kb-feature__row--tight-gap {
	gap: 36px;
}

/* Equal-height tiles for a tight-gap box row (/leadinfo/'s and
   /int-agencies/'s 2x2 info-box grids — production runs all 4 tiles at
   the same height regardless of text length). The shared
   .kb-feature__content{align-self:flex-start} base rule opts every
   content column out of the flex row's own stretch behavior by design
   (so text doesn't float centered next to a taller image elsewhere) —
   that's exactly what's unwanted here, so it's reset back to stretch
   specifically for gray/white-box tiles inside a tight-gap row. */
.kb-feature__row--tight-gap > .kb-feature__content--gray-box,
.kb-feature__row--tight-gap > .kb-feature__content--white-box {
	align-self: stretch;
}

/* Vertical gap between two stacked box-tile rows (/int-agencies/'s 2x2
   grid of gray boxes, built as two separate wp:columns blocks since
   Gutenberg columns can't span more than one row natively) — matches
   the same 36px used for the horizontal gap and the tiles' own padding,
   measured on production. Adjacent-sibling selector so it fires
   automatically whenever two tight-gap rows sit back to back, without
   needing a page-specific rule. */
.kb-feature__row--tight-gap + .kb-feature__row--tight-gap {
	margin-top: 36px;
}

/* Wave-line "Dicke gelbe Wellenlinie." separator image: opt-in 40px
   bottom margin instead of the WP-core figure default (16px), applied per
   page/instance via className since the plain image is reused sitewide at
   its default spacing. */
.kb-wave-line--gap-40 {
	margin-bottom: 40px;
}

/* /leadinfo/'s collage image sitting as the first child of the "Warum
   Leadinfo?" gray-lighter-bg section — production measures 108px from
   the section's top edge to the image, 12px less than the section's own
   shared 120px top padding (--kb-space-section-top). */
.kb-leadinfo-collage {
	margin-top: -12px;
}

/* Caps a lone .kb-feature__content column (no sibling column in the row)
   at production's 66.66% (Uncode col-lg-8, e.g. /e-mail-marketing-agentur/'s
   FAQ section) instead of the full row width it gets by default with only
   one child. !important needed for the same reason as .kb-feature__row--faq
   above: WP core's own per-block generated-class rule sets flex-grow:1 with
   equal-or-higher specificity, later in source order. Centered via auto
   margins — a flex-basis alone leaves the column flush against the row's
   own justify-content:flex-start default, sitting visibly left of center
   (caught on /wordpress-mit-knorke/'s "Dein WordPress Projekt..."). */
.kb-feature__row--content-66 > .kb-feature__content {
	flex: 0 0 66.66% !important;
	max-width: 66.66%;
	margin-left: auto;
	margin-right: auto;
}

/* Narrower, centered single-column body copy — production runs the
   /woocommerce-agentur/ intro paragraph at ~2/3 of the section width
   (Uncode col-lg-8-of-12) instead of the shared full-bleed .kb-feature
   width. Fixed px (not %) so it naturally falls back to 100% once the
   viewport itself is narrower, matching every other narrow-column
   pattern on this site (.kb-page-header__intro, .kb-accordion--narrow).
   Margin auto centers it since .kb-feature__row is a flex row and this
   is its only child. */
/* WP core's own global layout styles ship an inline
   ".is-layout-flex > :is(*, div) { margin: 0 }" reset that (via the type
   selector inside :is()) outweighs a single class here, so the auto
   margins needed to center this column need !important to win. */
.kb-feature__content--narrow-66 {
	max-width: 800px;
	margin-left: auto !important;
	margin-right: auto !important;
}

/* Same idea at production's /woocommerce-agentur/ "WooCommerce
   Leistungen" ratio (Uncode col-lg-6-of-12 = exactly half the section
   width). */
.kb-feature__content--narrow-50 {
	max-width: 600px;
	margin-left: auto !important;
	margin-right: auto !important;
}

/* Centers the direct-child image/heading/accent-wave-separator of a
   .kb-feature used as a standalone section header with no column
   wrapper — /shopify/'s "Shopify Agentur von A-Z" heading block renders
   left-aligned by default without this. Scoped to direct children only
   (not text-align on the whole group) so it doesn't inherit down into
   the body-copy columns that follow the header inside the same group. */
.kb-feature--centered-header > .wp-block-image {
	display: block;
	width: fit-content;
	margin-left: auto;
	margin-right: auto;
}

/* Specifically the section's own kb-section-title--lg heading, not any
   other direct-child h2 the group might contain further down (e.g.
   /shopify/'s "Und damit nicht genug" sub-heading in this same group,
   which should stay left-aligned). */
.kb-feature--centered-header > h2.kb-section-title--lg {
	text-align: center;
	margin-bottom: 0;
}

/* The accent-wave separator sits right after that heading — pull it
   flush against the heading (no default figure top-margin gap) and put
   the 40px breathing room after it instead, ahead of the body copy
   below, rather than between the heading and the wave itself. */
.kb-feature--centered-header > h2.kb-section-title--lg + .wp-block-image {
	margin-top: 0;
	margin-bottom: 40px;
}

/* When a plain intro paragraph follows that same wave separator (e.g.
   /shopify/'s "Warum wir als Agentur Shopify lieben" — production has
   an intro paragraph here that the migration silently dropped, restored
   separately), give it the same 40px breathing room before whatever
   comes next (here: the 6-tile grid). */
.kb-feature--centered-header > .wp-block-image + p {
	margin-bottom: 40px;
}

/* The shared .is-style-kb-accent separator centers itself (margin:16px
   auto 24px) — for a section whose heading text is left-aligned (the
   .kb-feature default), a centered line under it reads as a mismatch.
   Left-aligns just the separator without touching the many other
   sections that intentionally keep it centered under centered text. */
.kb-feature--left-accent > hr.is-style-kb-accent {
	margin-left: 0;
}

/* FAQ heading capped to the same width as its own .kb-accordion--narrow
   (700px, left-aligned) instead of running the section's full width —
   the accordion narrows, but the heading above it didn't. */
.kb-feature--narrow-header > h6,
.kb-feature--narrow-header > h2.kb-feature__title {
	max-width: 700px;
}

/* "Dein Weg zum Erfolg" on /ki-seo-agentur/ needed 120px of breathing
   room below its button — margin-bottom on the button itself was the
   wrong tool: this section reuses .kb-steps purely as a scoping hook
   for the "1./2./3./4." digit color/size below, and that class's own
   padding:0 (meant for its actual, unrelated counter-list component)
   left this section with a genuine 0px bottom padding. A margin here
   collapses straight through that zero padding into plain white space
   after the gray box instead of staying inside it as gray — visible as
   the gray background ending abruptly right at the button. Setting the
   section's own padding-bottom directly avoids the collapse question
   entirely: padding is always inside the painted box. Only bottom is
   touched, not top/left/right/max-width, since only the button's gap
   was reported wrong. */
.kb-feature--gray-bg.kb-steps {
	padding-bottom: 120px;
}

/* Light 1px border + more inner/outer spacing for a .kb-feature__content
   used as a plain bordered tile (e.g. /shopify/'s A-Z section 2-column
   text + "Und damit nicht genug") instead of the borderless default. */
.kb-feature__content--bordered-box {
	border: 1px solid var(--kb-color-gray);
	padding: 32px;
}

/* /marketing-agentur-socialmediamarketing/'s "Du stellst eine Anfrage" →
   "Shopware SEO Betreuung" row: production runs the 4 boxes through a
   dark-to-light gray gradient with white text on the 3 darker ones — the
   plain .kb-feature__content columns here had no background at all. */
.kb-feature__content--gray-1,
.kb-feature__content--gray-2,
.kb-feature__content--gray-3,
.kb-feature__content--gray-4 {
	padding: 36px;
}

.kb-feature__content--gray-1 { background-color: #272727; }
.kb-feature__content--gray-2 { background-color: #515151; }
.kb-feature__content--gray-3 { background-color: #7b7b7b; }
.kb-feature__content--gray-4 { background-color: #d8d8d8; }

.kb-feature__content--gray-1 .kb-feature__title--sm,
.kb-feature__content--gray-1 .kb-check-list li,
.kb-feature__content--gray-2 .kb-feature__title--sm,
.kb-feature__content--gray-2 .kb-check-list li,
.kb-feature__content--gray-3 .kb-feature__title--sm,
.kb-feature__content--gray-3 .kb-check-list li {
	color: var(--kb-color-white);
}

.kb-feature__content--gray-4 .kb-check-list li {
	color: var(--kb-color-dark);
}

/* Production runs these 4 boxes at an 18px gutter, not the shared 64px
   .kb-feature__row default (measured via getComputedStyle on production). */
.kb-feature__row--gray-boxes {
	gap: 18px;
}

/* "Step N" eyebrow above each box's heading, and the intro sentence
   between the heading and the checklist — both missing entirely from the
   converted markup (only the checklist itself survived). Colors come
   from the existing --gray-1..4 white/dark rules above (this just adds
   the two new element types to those selectors' job). */
.kb-feature__step-label {
	font-size: 15px;
	font-weight: 400;
	margin: 0 0 36px;
}

.kb-feature__step-text {
	font-size: 15px;
	line-height: 1.7;
	margin: 36px 0 18px;
}

.kb-feature__content--gray-1 .kb-feature__step-label,
.kb-feature__content--gray-1 .kb-feature__step-text,
.kb-feature__content--gray-2 .kb-feature__step-label,
.kb-feature__content--gray-2 .kb-feature__step-text,
.kb-feature__content--gray-3 .kb-feature__step-label,
.kb-feature__content--gray-3 .kb-feature__step-text {
	color: var(--kb-color-white);
}

.kb-feature__content--gray-4 .kb-feature__step-text {
	color: var(--kb-color-dark);
}

.kb-feature__row--bordered-boxes {
	gap: 32px;
	/* Base .kb-feature__row centers items on the cross axis (each column
	   only as tall as its own content) — stretch instead so two bordered
	   boxes side by side always match height regardless of text length. */
	align-items: stretch;
}

/* align-items on the row alone isn't enough: .kb-feature__content has
   its own align-self:flex-start (elsewhere, for the usual image+text
   rows where text shouldn't stretch to match a taller image) — align-
   self on the child always wins over the parent's align-items, so it
   needs its own override here. */
.kb-feature__row--bordered-boxes > .kb-feature__content {
	align-self: stretch;
}

/* Equal-height columns without pulling in --bordered-boxes' own 32px
   gap override (its gap is specific to that use case; this modifier
   is just the stretch behavior, reusable on a plain 64px-gap row). */
.kb-feature__row--equal-height {
	align-items: stretch;
}

.kb-feature__row--equal-height > .kb-feature__content {
	align-self: stretch;
}

/* Force truly equal thirds. flex:1 1 0 !important on the children still
   left columns with visibly less content (e.g. a short icon+one-line
   CTA tile next to two paragraph-length service tiles) narrower than
   their siblings — WP core's per-instance generated class evidently
   wins that tie despite equal specificity/!important (it's injected as
   a later inline <style>, not this linked stylesheet). Locking
   flex-grow/shrink to 0 with an explicit calculated basis removes any
   room for that competing rule to redistribute space at all, matching
   the same technique already used for .kb-steps-slider__card's 3-per-
   row math — 128px is this row's own 2×64px gap, not the steps
   slider's 36px one, so it needed its own copy rather than reusing
   that class. */
.kb-feature__row--thirds > .kb-feature__content {
	flex: 0 0 calc((100% - 128px) / 3) !important;
}

/* A tile inside an equal-height row that isn't itself a white/gray box
   (e.g. the accent-yellow .kb-icon-cta) is still flex/shrink-to-fit by
   default, so it doesn't fill the now-equal-width column around it. */
.kb-feature__row--equal-height .kb-icon-cta {
	width: 100%;
	height: 100%;
	box-sizing: border-box;
}

/* Icons read as too large at the shared 100px inside a compact
   equal-height card grid (measured: /ki-seo-agentur/'s "Unsere AIO
   Services" needed ~50% smaller to match production). */
.kb-feature__row--equal-height .kb-icon-feature__icon {
	width: 50px;
	height: 50px;
}

.kb-feature__row--bordered-boxes + .kb-feature__row--bordered-boxes {
	margin-top: 32px;
}

.kb-feature__image {
	text-align: center;
	align-self: center;
}

/* Top-aligned variant for a row where the image should sit flush with
   the content column's top instead of centering against its (taller)
   height — e.g. /wordpress-agentur/'s "WordPress SEO" row. */
.kb-feature__image--top {
	align-self: flex-start;
}

/* --- Full-bleed 50/50 image+headline split (font detail pages, e.g.
   /en/fonts/fresh-prince-graffiti-font-unique-designs/'s "Funky Fresh
   Felttip Flow" rows). Production runs these edge-to-edge — full viewport
   width minus the vmenu sidebar, which body's own padding-right already
   reserves, so plain max-width:none is enough, no vw-calc needed — with
   the image filling its entire column height, not the standard padded/
   inset .kb-feature__image treatment. */
.kb-feature--fullbleed-split {
	max-width: none;
	padding: 0;
}

.kb-feature--fullbleed-split .kb-feature__row {
	gap: 0;
	align-items: stretch;
	min-height: 75vh;
}

.kb-feature--fullbleed-split .kb-feature__content,
.kb-feature--fullbleed-split .kb-feature__image {
	align-self: stretch;
	flex: 0 0 50% !important;
	max-width: 50%;
}

.kb-feature--fullbleed-split .kb-feature__content {
	display: flex;
	flex-direction: column;
	justify-content: center;
	padding: 64px;
}

.kb-feature--fullbleed-split .kb-feature__content > * {
	max-width: 70%;
}

/* Production measures the h3 variant ("Symbols, arrows, lines and more")
   smaller than the h2 rows — scoped to this modifier rather than
   .kb-feature__title itself, which other pages rely on staying a flat
   44.79px regardless of heading level. */
.kb-feature--fullbleed-split h3.kb-feature__title {
	font-size: 37.32px;
}

.kb-feature--fullbleed-split .kb-feature__image {
	position: relative;
	overflow: hidden;
	text-align: initial;
}

.kb-feature--fullbleed-split .kb-feature__image .wp-block-image {
	margin: 0;
	height: 100%;
}

.kb-feature--fullbleed-split .kb-feature__image img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

@media (max-width: 959px) {
	.kb-feature--fullbleed-split .kb-feature__row {
		flex-direction: column;
		min-height: 0;
	}

	.kb-feature--fullbleed-split .kb-feature__content,
	.kb-feature--fullbleed-split .kb-feature__image {
		flex: 0 0 auto !important;
		max-width: 100%;
	}

	.kb-feature--fullbleed-split .kb-feature__image {
		aspect-ratio: 1 / 1;
	}

	.kb-feature--fullbleed-split .kb-feature__content > * {
		max-width: 100%;
	}
}

/* One-off scaled-down variants for feature-row photos that run too large
   compared to production on a specific page/section (not a sitewide
   default, since most .kb-feature__image photos are already correctly
   sized) — suffix is the resulting percentage of the column width. */
.kb-feature__image.kb-feature__image--80 .wp-block-image:not(.is-resized) img {
	width: 80%;
	margin: 0 auto;
}

.kb-feature__image.kb-feature__image--70 .wp-block-image:not(.is-resized) img {
	width: 70%;
	margin: 0 auto;
}

.kb-feature--spacious {
	padding-top: 132px;
	padding-bottom: 132px;
}

/* /gender-struggle-dieser-kundin/'s explicit request: unify every section
   on that page to a generous, consistent gap of at least 150px, rather
   than the shared 64px .kb-feature default (kept separate from
   --spacious above, which is a different, already-used 132px value on
   other pages). */
.kb-feature--generous {
	padding-top: 150px;
	padding-bottom: 150px;
}

.kb-feature--flush-top {
	padding-top: 0;
}

/* 144px top/bottom — production's /cases/rollupmonster/ CTA section
   ("Individuelle und passgenaue Magento 2 Entwicklung"), measured
   directly (Uncode's "penta" padding step), roomier than the shared
   --spacious 132px. Named --cta-padding, not --roomy: that name is
   already taken by an unrelated 130px rule further down this file. */
.kb-feature--cta-padding {
	padding-top: 144px;
	padding-bottom: 144px;
}

/* Explicit 120px top space (matching --kb-space-section-top, the site's
   "start of a major section" value) for a section that would otherwise
   inherit the shared .kb-feature 64px default. */
.kb-feature--top-space {
	padding-top: var(--kb-space-section-top);
}

.kb-feature--flush-bottom {
	padding-bottom: 0;
}

/* /en/design-agency/'s "Design projects" heading sat flush against the
   cases grid below it (0px gap, from --flush-bottom) — wants a deliberate
   40px instead of either the flush 0 or the shared 64px default. */
.kb-feature--gap-bottom-40 {
	padding-bottom: 40px;
}

/* /fonts/ intro ("Fontastique"/"Our handmade web fonts..."): production
   constrains this to ~1000px instead of the shared 1200px .kb-feature
   default — same fix already applied to the DE page's kb-intro-cta via
   a layout contentSize attribute, mirrored here as a class since this
   version uses a plain .kb-feature group instead. */
.kb-feature--content-1000 {
	max-width: 1000px;
}

/* Narrower reading column for a plain (non-full-bleed) .kb-feature
   section — /wie-aendert-man-die-url-von-localhost-.../'s whole article
   body runs at production's own fixed 800px column
   (--kb-container-width-narrowest), not the shared 1200px default. */
.kb-feature--content-800 {
	max-width: var(--kb-container-width-narrowest);
}

/* /en/magento-agency/'s "How We Work For You" intro (heading+line+lead
   text): +100px on top of the shared 64px top padding (more room above
   the section), and -50px off the shared 64px bottom padding (the gap
   to the tabs component directly below it, confirmed too loose via
   screenshot). */
.kb-feature--how-we-work-spacing {
	padding-top: 164px;
	padding-bottom: 14px;
}

/* Same page, requested in two follow-up rounds: "Dein Vorteil:"/
   "Voraussetzungen:" (h3) 5px then a further 6px smaller than the
   shared 44.79px .kb-feature__title default (44.79 -> 39.79 -> 33.79),
   "Nun ans Eingemachte" (h2) 8px then a further 6px smaller
   (44.79 -> 36.79 -> 30.79). Postid-scoped rather than a reusable
   modifier — one-off size tweak, no other page has asked for this
   specific set of reductions. */
body.postid-65120 h3.kb-feature__title {
	font-size: 33.79px;
}

body.postid-65120 h2.kb-feature__title {
	font-size: 30.79px;
}

/* /welches-onlineshop-system-zu-dir-passt/'s 4 shop-system boxes sit in
   a .kb-feature--gray-bg (full-bleed background) section — that class
   already sets its own padding-inline (a vw-based calc reproducing a
   ~1200px content column) and max-width:none, both of which come after
   the base .kb-feature rule in source order and so win the cascade tie
   over a plain .kb-feature--flush-sides{padding-left/right:0} (confirmed
   via getComputedStyle: padding stayed 104px, not 0). Requested exactly
   1200px, but --gray-bg's calc measured ~1137px in practice — rather
   than touch that shared formula (used sitewide), this zeros the
   section's own padding entirely (compound selector to reliably beat
   --gray-bg regardless of source order) and lets .kb-feature__row--
   gap-20 below own the precise 1200px centering instead. */
.kb-feature--gray-bg.kb-feature--flush-sides {
	padding-inline: 24px;
}

/* Same page: requested 20px gap between the 4 boxes instead of the
   shared .kb-feature__row default (64px) — a distinct value from the
   existing --tight-gap (36px, built for a different page's box tiles),
   so a separate modifier rather than reusing/changing that one. Also
   carries the precise 1200px centering for this row (see comment on
   --flush-sides above). */
.kb-feature__row--gap-20 {
	gap: 20px;
	max-width: 1200px;
	margin-left: auto;
	margin-right: auto;
}

/* /magento-agentur/magento-support/'s "Der Werdegang..." intro: heading,
   accent line and text centered (explicit deviation from production,
   which runs this left-aligned — requested directly), plus the gap
   into the tabs component below cut by 60%. That gap was actually two
   independent paddings meeting (this section's own 64px bottom padding
   + the tabs section's own 64px top padding, .kb-feature--flush-top
   applied there to zero its half) — 128px total down to ~51px, all of
   it now living here as this section's own bottom padding. Same WP-core
   .wp-block-columns margin-bottom collapse risk as .kb-feature--flush-
   bottom below, so the row's own margin-bottom is zeroed too rather
   than trusting the reduced padding alone. */
.kb-feature--werdegang-intro {
	text-align: center;
	padding-bottom: 51px;
}

.kb-feature--werdegang-intro .kb-feature__row {
	margin-bottom: 0;
}

/* WP core's inlined block-library CSS gives .wp-block-columns a default
   margin-bottom: 1.75em regardless of theme — invisible on blocks that
   already have generous padding, but it silently added ~28px back on top
   of the zeroed padding above. */
.kb-feature--flush-bottom .kb-feature__row {
	margin-bottom: 0;
}

/* Same margin-collapse issue as above, this time on /wordpress-agentur/'s
   "Eine Auswahl unserer WordPress Projekte" heading: .kb-section-title's
   own 48px margin-bottom collapsed straight through this element's now-
   zero bottom padding, landing as 48px of dead white space BEFORE the
   next sibling (the cases grid) rather than inside this box. */
.kb-feature--flush-bottom .kb-section-title {
	margin-bottom: 0;
}

/* Same margin-collapse issue again on /en/design-agency/'s "Design
   projects" heading — .kb-section-title's own 48px margin-bottom was
   adding on top of --gap-bottom-40's 40px padding (88px total measured)
   instead of that 40px being the whole gap. */
.kb-feature--gap-bottom-40 .kb-section-title {
	margin-bottom: 0;
}

/* /wordpress-mit-knorke/'s "Unser Knorke-Team" heading sits directly
   above the reusable .kb-team block (ref 152034); zeroing the OUTER
   group's own padding via --flush-top wasn't enough — .kb-team itself
   carries its own 120px padding-top (--kb-space-section-top), built for
   standalone use with no preceding custom headline. Scoped to this
   nesting rather than changing .kb-team's own padding: 3 other pages use
   the same reusable block standalone and need that 120px kept. */
.kb-feature--flush-top .kb-team {
	padding-top: 0;
}

/* Heading-only content column (no body text) should sit vertically centered
   next to a tall image instead of pinned to the top like the default
   text-heavy feature rows. */
.kb-feature--center-content .kb-feature__content {
	align-self: center;
}

/* --- Icon bar: small icon + short caption, centered — repeats across most
   landing pages right under the hero (3-up row). Core's own
   .wp-block-image flex/justify-content centering isn't loaded on this site
   (wp-block-library CSS is split per-block and this page doesn't need the
   rest of it), so centering the image is done here explicitly rather than
   relying on that. --- */
.kb-icon-bar {
	text-align: center;
}

.kb-icon-bar .wp-block-image {
	display: flex;
	justify-content: center;
}

/* --- Shop-system grid ("Welches Shopsystem", /e-commerce-agentur/ and
   siblings): white cards on the section's gray background, 3-up — a 5th/6th
   item wraps to a second row and simply left-aligns in the remaining
   columns, matching production. --- */
.kb-shopsystem-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 24px;
	margin-top: 48px;
}

.kb-shopsystem-grid__item {
	text-align: center;
	background: var(--kb-color-white);
	border-radius: var(--kb-radius-card);
	padding: 36px;
}

.kb-shopsystem-grid__item .wp-block-image {
	display: flex;
	justify-content: center;
	margin: 0 0 16px;
}

.kb-shopsystem-grid__item .kb-feature__title--sm {
	margin: 0 0 8px;
}

.kb-shopsystem-grid__item .kb-feature__text {
	margin: 0 0 20px;
}

@media (max-width: 960px) {
	.kb-shopsystem-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 599px) {
	.kb-shopsystem-grid {
		grid-template-columns: 1fr;
	}
}

/* --- Image slider: single-image carousel with prev/next arrows + dots,
   used where a page has multiple images to show in one feature column
   instead of a static grid (e.g. font showcase pages) --- */
.kb-image-slider {
	position: relative;
	overflow: hidden;
}

.kb-image-slider__track {
	display: flex;
	transition: transform 0.4s ease;
}

.kb-image-slider__slide {
	flex: 0 0 100%;
	width: 100%;
}

.kb-image-slider__slide img {
	display: block;
	width: 100%;
	height: auto;
}

.kb-image-slider__arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 40px;
	height: 40px;
	border: none;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.85);
	color: var(--kb-color-dark);
	font-size: 22px;
	line-height: 1;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	z-index: 1;
	padding: 0;
}

.kb-image-slider__arrow--prev {
	left: 16px;
}

.kb-image-slider__arrow--next {
	right: 16px;
}

.kb-image-slider__dots {
	position: absolute;
	bottom: 16px;
	left: 50%;
	transform: translateX(-50%);
	display: flex;
	gap: 8px;
	z-index: 1;
}

.kb-image-slider__dot {
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.6);
	border: none;
	cursor: pointer;
	padding: 0;
}

.kb-image-slider__dot.is-active {
	background: var(--kb-color-accent);
}

.kb-feature__caption {
	color: var(--kb-color-white);
	font-size: 25.92px;
	font-weight: 600;
	text-align: center;
	margin: 16px 0 0;
}

.kb-feature__image img {
	display: block;
	height: auto;
	max-width: 100%;
	border-radius: 4px;
}

/* Photos fill the column; a block given an explicit width in the editor
   (e.g. a logo that shouldn't stretch full-width like a photo does) keeps
   that width instead — setting `width: auto` here would actually discard
   the intended size and fall back to the image's raw intrinsic pixel size,
   since an author CSS `width` rule always wins over the img's own `width`
   HTML attribute. Leaving `width` alone lets that attribute apply. */
.kb-feature__image .wp-block-image:not(.is-resized) img {
	width: 100%;
}

.kb-feature__image .wp-block-image.is-resized img {
	margin: 0 auto;
}

.kb-feature__image .wp-block-image:not(:last-child) {
	margin-bottom: 16px;
}

/* A full-bleed background-image variant of .kb-feature — the columns
   inside still constrain/center at the same content width, but the
   background itself (set inline per-instance, it's page-specific content)
   spans the full section width. Padding matches top and bottom exactly. */
.kb-case-media {
	position: relative;
	background-size: cover;
	background-position: center;
	padding: 96px 24px;
}

.kb-case-media .kb-feature__row {
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
}

/* Each column centers its own contents (image + caption) as a unit, so the
   caption lines up under the image itself rather than the full (wider)
   column width. */
.kb-case-media .kb-feature__row > .wp-block-column {
	display: flex;
	flex-direction: column;
	align-items: center;
}

/* /cases/wheel2wall/'s skateboard-deck gallery reuses .kb-feature__row
   (for the .kb-case-media width cap above), but that class's own 64px
   gap and the gallery's default flex-basis:auto (sized off each photo's
   own square crop) only fit 2 per row instead of 3 — inconsistent with
   the plain .kb-feature gallery below it, whose narrower photos fit 3
   on their own. Explicit thirds + the same 8px gap as that gallery make
   both consistent regardless of each photo's own proportions. */
.kb-case-media .wp-block-gallery.kb-feature__row {
	gap: 8px;
}

.kb-case-media .wp-block-gallery.kb-feature__row figure.wp-block-image {
	flex: 0 0 calc((100% - 16px) / 3);
}

/* Plain decorative full-bleed image band with no content of its own —
   production's /cases/furore-werbung/ horizontal divider (furore-bg.svg)
   between two text sections. No .kb-feature wrapper, so it isn't capped
   to the narrow content width (see .kb-case-body comment above). Height
   matched to production's rendered 216px. */
.kb-divider-banner {
	height: 216px;
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
}

/* Full-viewport-height variant — production's /cases/tag-der-schiene/
   in-between showcase photos ("full" height-ratio row in Uncode, both
   measured at exactly 100vh) rather than a thin divider band. */
.kb-divider-banner--full {
	height: 100vh;
}

/* 90vh variant — production's /cases/tech-for-net-zero/ 3-phone showcase
   row (Uncode "data-height-ratio=90", measured at exactly 90vh). */
.kb-divider-banner--90 {
	height: 90vh;
}

/* 75vh variant — production's /cases/virtualq-.../ closing image row
   (Uncode "data-height-ratio=75", measured at exactly 75vh). */
.kb-divider-banner--75 {
	height: 75vh;
}

/* 61vh / 60vh variants — production's /cases/g-class-experience-2/ two
   divider rows (Uncode "data-height-ratio=61" and "=60"). */
.kb-divider-banner--61 {
	height: 61vh;
}

.kb-divider-banner--60 {
	height: 60vh;
}

/* 70vh variant — production's /cases/wallpen/ camelion divider row
   (Uncode "data-height-ratio=70"). */
.kb-divider-banner--70 {
	height: 70vh;
}

/* 80vh variant — production's /cases/wheel2wall/ two plain-image divider
   rows (Uncode "data-height-ratio=80"). */
.kb-divider-banner--80 {
	height: 80vh;
}

/* Video variant — production's /cases/wheel2wall/ divider between the
   "Knorke sammelt..." and mockup rows runs a looping background video
   (w2wwebvid4.mp4) instead of a static image, with the same dark tint
   the other dividers get from a photo (measured opacity 0.24 on
   --kb-color-darker). Structure mirrors .kb-case-hero__video, but this
   one lives in post content (no PHP template hook for a mid-page
   divider), so it's authored as raw HTML via wp:html. */
.kb-divider-banner--video {
	position: relative;
	overflow: hidden;
}

.kb-divider-banner--video .kb-divider-banner__video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.kb-divider-banner--video::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(20, 22, 24, 0.24);
}

/* Caps the testimonial blockquote at the shared 1200px content width
   instead of stretching to fill the full-bleed .kb-case-media it sits
   in — requested for /cases/cosyworld/, applies to every kb-testimonial
   (virtualQ's ran the same uncapped way, same fix). */
.kb-testimonial {
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
}

/* Quote/cite sizing for the photo-background testimonial (first use:
   /cases/virtualq-.../, requested explicitly at 60px/26px — much larger
   than the browser's plain blockquote default). */
.kb-testimonial__quote {
	font-size: 60px;
	font-weight: 900;
	line-height: 1.3;
	margin: 0 0 16px;
}

.kb-testimonial__cite {
	font-size: 26px;
}

.kb-feature__content .wp-block-separator.is-style-kb-accent {
	margin: 16px 0 24px;
}

.kb-feature__title {
	font-size: 44.79px;
	font-weight: 600;
	line-height: 1.2;
	margin: 0 0 16px;
}

.kb-feature__text {
	font-size: 15px;
	line-height: 1.7;
	color: var(--kb-color-dark);
	margin: 0 0 24px;
}

/* Extra breathing room above a lead paragraph that follows a centered
   title + accent line, when the default 24px gap after the separator
   reads as too tight (e.g. the "Wie wir für Dich arbeiten" tabs intro). */
.kb-feature__text--spaced {
	margin-top: 16px;
}

/* /marketing-agentur-socialmediamarketing/'s "Wie Knorke als SMM Agentur..."
   intro needs 50px before the 5-service grid below it instead of the
   shared 24px default. */
.kb-feature__text--gap-bottom-50 {
	margin-bottom: 50px;
}

/* Bolder one-off variant, same idea as .kb-section-title--bold above but
   for a .kb-feature__text lead paragraph (shared default stays 500). */
.kb-feature__text--bold {
	font-weight: 600;
}

.kb-feature__list {
	margin: 36px 0 36px;
}

/* Icon + bold title + description tile, 3-column grid — Uncode's
   vc_icon shortcode (icon_image + title + text), the single biggest
   unconverted construct per tools/README.md (19 pages). First reusable
   build of it: /adobe-commerce/'s 8-tile "B2B Funktionalitäten" etc.
   grid. Production measures the title at 24px/700, no icon-specific
   color/background — reuses the shared .kb-feature__text for the body
   copy rather than a new class. */
.kb-icon-feature__icon {
	width: 100px;
	height: 100px;
	object-fit: contain;
	margin: 0 0 16px;
}

/* Font-icon variant of the tile above (Uncode's vc_icon with an FA icon
   class instead of icon_image, e.g. /magento-support/'s "Support von
   Experten" row) — lucide-style inline SVG standing in for the FA glyph,
   same 100px box, tinted with the icon's own icon_color="accent". */
.kb-icon-feature__icon--accent {
	color: var(--kb-color-accent);
}

/* /magento-agentur/magento-support/'s "Support von Experten" row: 30%
   smaller than the shared 100px box (used elsewhere at full size, e.g.
   /adobe-commerce/, /shopware-seo-agentur/) — scoped to a row modifier
   rather than the shared class. */
.kb-feature__row--icon-70 .kb-icon-feature__icon {
	width: 70px;
	height: 70px;
}

.kb-icon-feature__title {
	font-size: 24px;
	font-weight: 700;
	line-height: 1.3;
	margin: 0 0 12px;
}

.kb-feature__list p {
	font-size: 15px;
	font-weight: 500;
	margin: 4px 0 0;
}

.kb-feature__list p:first-child {
	margin-top: 0;
}

@media (max-width: 781px) {
	.kb-feature {
		padding: 40px 24px;
	}

	.kb-feature__title {
		font-size: 29.86px;
	}
}

/* --- Cases archive: filter bar + Isotope grid --- */
.kb-cases-archive {
	padding: 0;
}

.kb-cases-filter {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 24px;
	margin: 0 0 48px;
	padding: 0 24px;
}

.kb-cases-filter__btn {
	background: none;
	border: 0;
	padding: 0;
	font-size: 11px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--kb-color-gray-text);
	cursor: pointer;
	text-decoration: none;
}

.kb-cases-filter__btn:hover {
	color: var(--kb-color-dark);
}

.kb-cases-filter__btn.is-active {
	color: var(--kb-color-dark);
	box-shadow: 0 2px 0 var(--kb-color-accent);
	padding-bottom: 4px;
}

/* Isotope takes over positioning at runtime (absolute + inline transforms) —
   this is the plain-CSS/no-JS fallback layout, using float+percentage widths
   rather than the homepage grid's CSS Grid (Isotope can't lay out grid
   children, only block/floated ones). */
.kb-cases-archive .kb-cases__grid {
	display: block;
	position: relative;
}

.kb-cases-archive .kb-cases__item {
	float: left;
	width: 33.3333%;
}

@media (max-width: 959px) {
	.kb-cases-archive .kb-cases__item {
		width: 50%;
	}
}

@media (max-width: 599px) {
	.kb-cases-archive .kb-cases__item {
		width: 100%;
	}
}

/* --- Generic CTA banner: parallax bg + centered title/text/button --- */
.kb-cta-banner {
	position: relative;
	padding: var(--kb-space-section-top) 24px 96px;
	overflow: hidden;
	text-align: center;
}

.kb-cta-banner__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
}

.kb-cta-banner__bg-image {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	will-change: transform;
}

.kb-cta-banner__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(247, 247, 247, 0.93);
}

.kb-cta-banner__inner {
	position: relative;
	z-index: 1;
	max-width: 700px;
	margin: 0 auto;
}

.kb-cta-banner__title {
	font-size: 44.79px;
	font-weight: 600;
	line-height: 1.2;
	margin: 0 0 16px;
}

.kb-cta-banner__text {
	font-size: 17px;
	line-height: 1.7;
	color: var(--kb-color-gray-text);
	margin: 0 0 32px;
}

@media (max-width: 781px) {
	.kb-cta-banner {
		padding: 64px 24px;
	}

	.kb-cta-banner__title {
		font-size: 29.86px;
	}
}

/* --- Inline YouTube embed (first use: /cases/zukunft-mit-stern/) — a
   plain responsive 16:9 wrapper, since no Gutenberg core embed-block CSS
   is loaded in this theme. --- */
.kb-video-embed {
	max-width: 840px;
	aspect-ratio: 16 / 9;
	margin: 0 auto;
}

.kb-video-embed iframe {
	width: 100%;
	height: 100%;
	border: 0;
}

/* Grid of multiple video embeds (first use: /cases/beyosa/'s Vimeo
   showcase) — each cell reuses .kb-video-embed's responsive 16:9 wrapper,
   just without its own centering/max-width since the grid handles sizing. */
.kb-video-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 24px;
}

.kb-video-grid .kb-video-embed {
	max-width: none;
}

@media (max-width: 781px) {
	.kb-video-grid {
		grid-template-columns: 1fr;
	}
}

/* --- Before/after image compare slider (native <input type=range>, no
   dependency on a jQuery plugin) --- */
.kb-compare {
	position: relative;
	overflow: hidden;
	border-radius: 4px;
	line-height: 0;
}

.kb-compare__after,
.kb-compare__before {
	position: absolute;
	inset: 0;
}

.kb-compare__after img,
.kb-compare__before img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.kb-compare__before {
	clip-path: inset(0 50% 0 0);
}

.kb-compare__handle {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 50%;
	width: 2px;
	background: var(--kb-color-accent);
	transform: translateX(-50%);
	pointer-events: none;
}

/* Yellow drag handle with a left/right chevron icon — without it, nothing
   signals the divider is actually draggable (measured against production,
   which uses exactly this accent-yellow-circle-plus-chevrons look). */
.kb-compare__handle::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 44px;
	height: 44px;
	border-radius: 50%;
	background-color: var(--kb-color-accent);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 18 3 12 9 6'/%3E%3Cpolyline points='15 6 21 12 15 18'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: center;
	background-size: 20px 20px;
	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}

.kb-compare__range {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	opacity: 0;
	cursor: ew-resize;
	-webkit-appearance: none;
	appearance: none;
}

.kb-compare__label {
	position: absolute;
	bottom: 12px;
	font-size: 12px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--kb-color-white);
	background: rgba(20, 22, 24, 0.6);
	padding: 4px 10px;
	border-radius: 3px;
	pointer-events: none;
}

.kb-compare__label--before {
	left: 12px;
}

.kb-compare__label--after {
	right: 12px;
}

/* --- Project details box at the foot of a single Case --- */
.kb-case-meta {
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
	padding: var(--kb-space-section-top) 24px 96px;
}

.kb-case-meta__client {
	font-size: 20px;
	font-weight: 500;
	color: var(--kb-color-gray-mid);
	margin: 0 0 40px;
}

.kb-case-meta__row {
	display: flex;
	gap: 64px;
}

.kb-case-meta__description {
	flex: 0 0 66.6%;
	font-size: 17px;
	line-height: 1.7;
	color: var(--kb-color-gray-text);
	margin: 0;
}

.kb-case-meta__facts {
	flex: 1;
	margin: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.kb-case-meta__fact {
	display: flex;
	gap: 24px;
}

.kb-case-meta__fact dt {
	flex: 0 0 130px;
	font-size: 15px;
	font-weight: 600;
	color: var(--kb-color-dark);
}

.kb-case-meta__fact dd {
	margin: 0;
	font-size: 15px;
	color: var(--kb-color-gray-text);
}

.kb-case-meta__fact dd a {
	color: inherit;
}

@media (max-width: 781px) {
	.kb-case-meta__row {
		flex-direction: column;
		gap: 32px;
	}

	.kb-case-meta__description {
		flex-basis: auto;
	}
}

/* --- Prev/next Case navigation --- */
.kb-case-nav {
	background: var(--kb-color-gray-light);
	padding: 32px 24px;
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.kb-case-nav__prev,
.kb-case-nav__next {
	flex: 1;
	font-size: 12px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.kb-case-nav__next {
	text-align: right;
}

.kb-case-nav a {
	color: var(--kb-color-dark);
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.kb-case-nav a:hover {
	color: var(--kb-color-accent);
}

.kb-case-nav__disabled {
	color: var(--kb-color-gray);
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.kb-case-nav svg {
	width: 14px;
	height: 14px;
}

.kb-case-nav__all {
	flex: 0 0 auto;
	font-size: 12px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

/* --- Legal text pages (Datenschutz, Impressum, AGB) — plain reading
   layout: sticky ToC sidebar + long-form article. Font sizes/spacing
   values measured directly off the reference via getComputedStyle, not
   approximated. --- */
.kb-legal {
	max-width: var(--kb-container-width);
	margin: 0 auto;
	padding: var(--kb-space-section-top) 24px 96px;
}

/* /datenschutzerklaerung/-only: much tighter top gap than the shared
   --kb-space-section-top (120px, used site-wide for major section
   starts) — .kb-legal is also used by /impressum/ with a different
   column layout, so this can't change generically. The logo/nav sit
   in the fixed .kb-vmenu (not in-flow), so there's no fixed header to
   clear at the top here. */
body.page-id-59310 .kb-legal {
	padding-top: 48px;
}

.kb-legal__row {
	align-items: flex-start;
	gap: 64px;
}

/* 33.33% / 66.66% split via fixed flex-basis (grow:0/shrink:0), not a
   flex-grow ratio: content-col's own 96px padding pushed its
   min-content floor above the "fair" 2/3 share when grow was used,
   skewing the visible split to ~30/70 instead of 33/66 — confirmed via
   getBoundingClientRect. A fixed % basis sidesteps that since neither
   column ever needs to grow/shrink off it. Plain percentages resolve
   against the row's full inner width WITHOUT excluding its own 64px
   gap (confirmed via measurement — 33.33%+66.66% plus the gap
   overflowed the row by ~64px), so the gap has to be subtracted by
   hand via calc() to land exactly on the requested 1:2 ratio of the
   two columns' own widths.
   !important: WP core's per-block generated-class rule
   (.wp-container-core-columns-is-layout-xxxxx > .wp-block-column
   {flex-grow:1}) has equal specificity to a plain single-class
   selector but comes later in source order, so it wins the tie
   without this — confirmed via getComputedStyle showing "flex: 1 0
   0px" instead of the flex-basis:28% set here previously. */
.kb-legal__toc-col {
	flex: 0 0 calc((100% - 64px) * 0.3333) !important;
}

.kb-legal__toc {
	position: sticky;
	top: 32px;
}

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

.kb-legal__toc li {
	margin: 0 0 12px;
}

.kb-legal__toc a {
	display: block;
	text-decoration: none;
	font-size: 14px;
	font-weight: 600;
	padding: 12px 20px;
	border: 2px solid var(--kb-color-dark);
	border-radius: 4px;
	transition: background 0.2s ease, color 0.2s ease;
}

/* Same-specificity tie against the shared ".kb-legal a" accent-color rule
   (later in the file) needs a compound selector to reliably win. */
.kb-legal .kb-legal__toc a {
	color: var(--kb-color-dark);
}

.kb-legal__toc a:hover {
	background: var(--kb-color-dark);
	color: var(--kb-color-white);
}

.kb-legal__content-col {
	flex: 0 0 calc((100% - 64px) * 0.6666) !important;
	background: var(--kb-color-gray-light);
	padding: 48px;
	/* Bleed the gray background out through .kb-legal's own padding on
	   two sides — right, so it reaches flush up to the fixed
	   right-side nav (.kb-legal's own right edge already touches
	   .kb-vmenu with zero gap, only its inner padding was holding the
	   column back); top, so it reaches flush to the very top of the
	   page (nothing else is in-flow up there — logo/nav live in the
	   fixed .kb-vmenu). A box-shadow bleed (not a negative margin) so
	   it doesn't feed back into the flex-basis calc above. One shadow
	   with both offsets combined, not two separate single-axis
	   shadows — two independent rectangles each stop at the original
	   edge on their other axis and leave the top-right corner
	   uncovered; a single (24px, -48px) shadow is one rectangle that
	   already spans the corner. */
	box-shadow: 24px -48px 0 0 var(--kb-color-gray-light);
}

.kb-legal__h1 {
	font-size: 35px;
	font-weight: 500;
	margin: 0 0 24px;
}

.kb-legal__h3 {
	font-size: 24px;
	font-weight: 500;
	margin: 48px 0 0;
	scroll-margin-top: 32px;
}

.kb-legal__h4 {
	font-size: 20px;
	font-weight: 500;
	margin: 27px 0 0;
}

.kb-legal__text {
	font-size: 15px;
	line-height: 26.25px;
	color: var(--kb-color-dark);
	margin: 18px 0 0;
}

.kb-legal__list {
	margin: 18px 0 0;
	padding-left: 18px;
}

.kb-legal__list li {
	margin: 0;
	font-size: 15px;
	line-height: 26.25px;
	color: var(--kb-color-dark);
}

.kb-legal a {
	color: var(--kb-color-accent);
	text-decoration: none;
}

.kb-legal a:hover {
	text-decoration: underline;
}

@media (max-width: 959px) {
	.kb-legal__row {
		flex-direction: column;
	}

	/* Undo the desktop 1:2 flex-grow split (!important there, so this
	   needs !important too — flex-grow along a now-vertical column axis
	   would otherwise size these by height, not stack them at full
	   width). */
	.kb-legal__toc-col {
		flex: 1 1 auto !important;
		width: 100%;
	}

	.kb-legal__toc {
		position: static;
	}

	.kb-legal__content-col {
		flex: 1 1 auto !important;
		max-width: 100%;
		box-shadow: none;
	}
}

/* --- Single Blog-post hero: shorter than the Case hero (75vh vs 100vh in
   the reference, confirmed via getBoundingClientRect at two viewport
   heights — a fixed px value doesn't scale like production's does),
   title uppercase-free but just as heavy (900) as the Case hero. White
   background-color, not dark: production's own hero row background is
   plain white (getComputedStyle-confirmed), and at least this post's
   hero PNG has semi-transparent areas — a dark fallback color behind it
   tinted those areas near-black instead of the intended light gray. */
.kb-blog-hero {
	position: relative;
	min-height: 75vh;
	background-color: var(--kb-color-white);
	background-size: cover;
	background-position: center;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.kb-blog-hero__overlay {
	position: absolute;
	inset: 0;
	background: var(--kb-color-dark);
	opacity: 0.3;
}

.kb-blog-hero__title {
	position: relative;
	z-index: 1;
	color: var(--kb-color-white);
	font-weight: 900;
	font-size: 75px;
	text-align: center;
	margin: 0;
	padding: 0 24px;
	max-width: 1000px;
}

@media (max-width: 781px) {
	.kb-blog-hero {
		min-height: 320px;
	}

	.kb-blog-hero__title {
		font-size: 36px;
	}
}

/* Lead paragraph below the hero title — /welches-onlineshop-system-zu-
   dir-passt/ is the first blog post with one on production (measured:
   18px, white, left-aligned text inside a centered ~700px column). Not
   every post has this — single.php only renders it when a per-post
   override provides lead text. */
.kb-blog-hero__lead {
	position: relative;
	z-index: 1;
	color: var(--kb-color-white);
	font-size: 18px;
	text-align: left;
	max-width: 700px;
	margin: 24px auto 0;
	padding: 0 24px;
}

/* --- Blog archive grid --- */
.kb-blog-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 32px;
	max-width: var(--kb-container-width);
	margin: 0 auto;
	padding: 0 24px 96px;
}

.kb-blog-card {
	display: block;
	text-decoration: none;
	color: inherit;
}

.kb-blog-card__img {
	position: relative;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: 4px;
}

.kb-blog-card__img img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform 0.4s ease;
}

.kb-blog-card:hover .kb-blog-card__img img {
	transform: scale(1.05);
}

.kb-blog-card__title {
	margin: 16px 0 8px;
	font-size: 20px;
	font-weight: 600;
	color: var(--kb-color-dark);
}

.kb-blog-card__excerpt {
	margin: 0 0 8px;
	font-size: 15px;
	line-height: 1.6;
	color: var(--kb-color-gray-text);
}

.kb-blog-card__date {
	margin: 0;
	font-size: 12px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: var(--kb-color-gray-text);
	border-top: 1px solid var(--kb-color-gray-lighter);
	padding-top: 8px;
}

@media (max-width: 959px) {
	.kb-blog-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 599px) {
	.kb-blog-grid {
		grid-template-columns: 1fr;
	}
}

/* --- Jobs page --- */

/* Perk tiles under "Dein Gewinn als Knorke-Mitglied" — one CSS Grid (3
   columns, wraps to a 2nd row of its own accord) instead of two separate
   .kb-feature/wp:columns blocks, so both rows share identical gap/sizing
   instead of drifting apart. Card look: no box-shadow (site convention:
   shadows are out, flat cards with a small radius are in), left-aligned
   text and icon-on-top per the reference. */
.kb-perk-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 36px;
}

.kb-perk-card {
	background: var(--kb-color-gray-light);
	border-radius: var(--kb-radius-card);
	padding: 36px;
	text-align: left;
}

/* The first tile is the section title itself, styled as one of the 6 cards
   (matches production: same bg/no-shadow card, just heading, no body
   text) rather than a separate heading row above the grid. Vertically
   centered within its cell, unlike the icon cards below. */
.kb-perk-card--title {
	display: flex;
	align-items: center;
}

.kb-perk-card--title h2 {
	font-size: 32px;
	margin: 0;
}

.kb-perk-card__icon svg {
	display: block;
	width: 45px;
	height: 45px;
	color: var(--kb-color-accent);
	margin-bottom: 27px;
}

.kb-perk-card__title {
	margin: 0 0 18px;
}

@media (max-width: 781px) {
	.kb-perk-grid {
		grid-template-columns: 1fr;
	}
}

/* Secondary CTA ("Nichts Passendes dabei?") between the intro and "Wir
   lieben Initiative" — same component as .kb-intro-cta, just a smaller
   h3 instead of the section's usual h2 since it's a supporting CTA, not
   a full section title. */
.kb-jobs-cta {
	padding-top: 0;
	padding-bottom: 64px;
}

/* "Wir lieben Initiative" — full-bleed parallax background + light overlay,
   same pattern as .kb-cta-banner__bg / .kb-contact__bg elsewhere in the
   theme, just scoped to a .kb-intro-cta instance via a modifier instead of
   changing every .kb-intro-cta usage site-wide. */
.kb-intro-cta--bg {
	position: relative;
	overflow: hidden;
}

.kb-intro-cta__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
}

.kb-intro-cta__bg-image {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.kb-intro-cta__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(247, 247, 247, 0.93);
}

.kb-intro-cta__inner {
	position: relative;
	z-index: 1;
}

/* --- Contact cards: circular icon + heading + text + link, 3-up row
   (used on Kontakt, and the same shape on Jobs / Cases "dein-projekt") --- */
.kb-contact-card {
	text-align: center;
}

.kb-contact-card__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	width: 115px;
	height: 115px;
	margin: 0 auto 24px;
	border-radius: 50%;
	border: 2px solid transparent;
	background: var(--kb-color-dark);
	color: var(--kb-color-white);
	transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.kb-contact-card__icon:hover {
	background: transparent;
	border-color: var(--kb-color-dark);
	color: var(--kb-color-dark);
}

.kb-contact-card__icon svg {
	width: 48px;
	height: 48px;
}

.kb-contact-card__title {
	margin-bottom: 8px;
}

/* --- Numbered step cards (blog posts explaining a short process) --- */
.kb-step-cards {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 24px;
	margin: 32px 0;
}

.kb-step-card {
	background: var(--kb-color-white);
	border: 1px solid var(--kb-color-gray-lighter);
	border-radius: var(--kb-radius-card);
	padding: 36px;
}

.kb-step-card__num {
	font-size: 25.92px;
	font-weight: 600;
	margin: 0 0 8px;
}

@media (max-width: 781px) {
	.kb-step-cards {
		grid-template-columns: 1fr;
	}
}

/* --- Anniversary boxes (emoji "icon" + heading + text), 2 per row --- */
.kb-anniversary-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 36px;
}

.kb-anniversary-box {
	background: var(--kb-color-gray-light);
	padding: 36px;
	text-align: center;
}

.kb-anniversary-box__icon {
	font-size: 40px;
	line-height: 1;
	margin: 0 0 16px;
}

@media (max-width: 781px) {
	.kb-anniversary-grid {
		grid-template-columns: 1fr;
	}
}

/* --- Landing pages (WordPress-Agentur etc.): checklist with a small
   check icon (Font Awesome "check" solid, embedded via CSS mask so there's
   no icon-font dependency — same approach as the footer nav arrows). Two
   layouts: inline/wrapping (hero) and stacked (feature lists). --- */
.kb-check-list {
	list-style: none;
	margin: 24px 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 8px 32px;
}

.kb-check-list--stacked {
	flex-direction: column;
	gap: 12px;
}

/* Hanging-indent bullet, not flex: a flex row splits an item's inline
   content (the <strong> label + the text after it) into separate flex
   items, so on a long item that wraps to a second line, the wrapped
   text stays confined to the "text" item's own column instead of
   flowing the full item width — it looks like the bold label pins a
   block/column rather than reading as a lead-in to running text. A
   plain block with padding-left + an absolutely positioned icon lets
   the text reflow normally at full width on wrapped lines, which is
   what every multi-line item here actually needs. */
.kb-check-list li {
	position: relative;
	padding-left: 28px;
	font-size: 17px;
	line-height: 1.5;
	color: var(--kb-color-gray-text);
}

.kb-check-list li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.25em;
	width: 18px;
	height: 18px;
	background-color: var(--kb-color-accent);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5L6.5 12L13 4' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5L6.5 12L13 4' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
}

/* Pointing-hand variant — /shopify/'s hero checklist uses a hand-with-
   extended-index-finger icon in production (Font Awesome "hand-o-right"),
   not the shared checkmark. Path is Font Awesome Free's "hand-point-right"
   solid glyph (CC BY 4.0), traced/verified by rendering it standalone
   before use. Slightly larger than the checkmark (20px vs 18px) since the
   hand shape reads worse at very small sizes. */
.kb-check-list--hand li::before {
	width: 20px;
	height: 20px;
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M480 96c17.7 0 32 14.3 32 32s-14.3 32-32 32l-208 0 0-64 208 0zM320 288c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0zm64-64c0 17.7-14.3 32-32 32l-48 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l48 0c17.7 0 32 14.3 32 32zM288 384c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0zm-88-96l.6 0c-5.4 9.4-8.6 20.3-8.6 32c0 13.2 4 25.4 10.8 35.6C177.9 364.3 160 388.1 160 416c0 11.7 3.1 22.6 8.6 32l-8.6 0C71.6 448 0 376.4 0 288l0-61.7c0-42.4 16.9-83.1 46.9-113.1l11.6-11.6C82.5 77.5 115.1 64 149 64l27 0c35.3 0 64 28.7 64 64l0 88c0 22.1-17.9 40-40 40s-40-17.9-40-40l0-56c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 56c0 39.8 32.2 72 72 72z' fill='black'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M480 96c17.7 0 32 14.3 32 32s-14.3 32-32 32l-208 0 0-64 208 0zM320 288c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0zm64-64c0 17.7-14.3 32-32 32l-48 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l48 0c17.7 0 32 14.3 32 32zM288 384c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64 0zm-88-96l.6 0c-5.4 9.4-8.6 20.3-8.6 32c0 13.2 4 25.4 10.8 35.6C177.9 364.3 160 388.1 160 416c0 11.7 3.1 22.6 8.6 32l-8.6 0C71.6 448 0 376.4 0 288l0-61.7c0-42.4 16.9-83.1 46.9-113.1l11.6-11.6C82.5 77.5 115.1 64 149 64l27 0c35.3 0 64 28.7 64 64l0 88c0 22.1-17.9 40-40 40s-40-17.9-40-40l0-56c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 56c0 39.8 32.2 72 72 72z' fill='black'/%3E%3C/svg%3E");
}

/* Plain right-arrow variant — /shopify/'s "Wie wir arbeiten" step cards
   use a simple arrow icon (Font Awesome "arrow-right2"), not the hand or
   the checkmark. */
.kb-check-list--arrow li::before {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8h11m-4-4l4 4-4 4' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2 8h11m-4-4l4 4-4 4' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* Plain dash variant — /marketing-agentur-socialmediamarketing/'s "Du
   stellst eine Anfrage" step box uses Font Awesome "minus", not the
   checkmark. */
.kb-check-list--minus li::before {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8h10' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8h10' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* Document/file outline variant — same page's "Konkretes Angebot" step
   box (Font Awesome "file-o"). */
.kb-check-list--file li::before {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 1h5l3 3v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1z M9 1v3h3' fill='none' stroke='black' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 1h5l3 3v10a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1z M9 1v3h3' fill='none' stroke='black' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* Road glyph variant — same page's "Shopware SEO Betreuung" step box
   (Font Awesome "road"): a simplified trapezoid road with two center-line
   dashes. */
.kb-check-list--road li::before {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 1h4l3 14H3z' fill='none' stroke='black' stroke-width='1.3' stroke-linejoin='round'/%3E%3Cpath d='M7.4 6.5h1.2M7.1 11h1.8' fill='none' stroke='black' stroke-width='1.3' stroke-linecap='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 1h4l3 14H3z' fill='none' stroke='black' stroke-width='1.3' stroke-linejoin='round'/%3E%3Cpath d='M7.4 6.5h1.2M7.1 11h1.8' fill='none' stroke='black' stroke-width='1.3' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* Plus variant — /wordpress-support/'s short-case stat lists use Font
   Awesome "plus" in dark, not the shared accent-yellow checkmark. */
.kb-check-list--plus li::before {
	background-color: var(--kb-color-dark);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2v12M2 8h12' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2v12M2 8h12' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* Same plus glyph as above, but keeping the shared accent-yellow color
   instead of overriding to dark — /magento-agentur/magento-sprachpaket/'s
   hero checklist uses a yellow plus (Font Awesome "plus" + text-accent-
   color), not the dark one wordpress-support needs. */
.kb-check-list--plus-accent li::before {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2v12M2 8h12' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 2v12M2 8h12' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* Asterisk variant — /gender-struggle-dieser-kundin/'s "Glossar (kind of)"
   3-column word list uses Font Awesome "asterisk" (a 6-spoke star, not
   traced from FA but visually equivalent: one vertical + two diagonal
   lines crossing at center). */
.kb-check-list--asterisk li::before {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1v14M2.8 5l10.4 6M2.8 11l10.4-6' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1v14M2.8 5l10.4 6M2.8 11l10.4-6' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* Body-text variant — reads as a continuation of the paragraph above it
   (same size/color) instead of a distinct feature-list component. Label
   stays on one line since it functions as an inline lead-in, not a
   fixed-width column. */
.kb-check-list--body-text li {
	font-size: 15px;
	color: var(--kb-color-dark);
}

.kb-check-list--body-text li strong {
	white-space: nowrap;
}

/* Muted-gray icon instead of the shared accent yellow — composes with
   any icon-shape modifier above (--hand, --arrow, or the default
   checkmark). */
.kb-check-list--gray-icon li::before {
	background-color: var(--kb-color-gray);
}

/* Plain black item text instead of the shared muted gray — independent
   of --body-text's font-size change, for lists that should read black
   but keep the default (not paragraph-matching) size. */
.kb-check-list--dark li {
	color: var(--kb-color-dark);
}

/* Case-story grid ("Unsere SEM Erfolgsgeschichten" etc.): image, a small
   eyebrow line naming the campaign, the client name as the real (bold)
   headline, then a checklist of deliverables. The converter had this
   backwards — the campaign sentence as a full heading, the client name
   demoted to a small kicker — production runs the client name as the
   actual headline. */
.kb-case-story__eyebrow {
	font-size: 18px;
	font-weight: 400;
	color: var(--kb-color-dark);
	margin: 16px 0 24px;
}

.kb-case-story__name {
	font-size: 29px;
	font-weight: 900;
	line-height: 1.2;
	color: var(--kb-color-dark);
	margin: 0 0 16px;
}

/* Uniform image height regardless of each photo's natural aspect ratio
   (production specifies 16:9 for all three case images: media_ratio
   "sixteen-nine" in the Uncode backup) — without this the Cosyworld/Fast
   Forward/Mercedes photos render at three different heights since each
   source photo has its own natural ratio. */
.kb-case-story__image img {
	aspect-ratio: 16 / 9;
	width: 100%;
	height: auto;
	object-fit: cover;
}

/* Single white card wrapping a whole FAQ grid (e.g. "Warum SEM?"'s 9
   Q&A blocks), sitting on the surrounding .kb-feature--gray-bg —
   production gives each block its own gray box, but this treatment asks
   for one shared white box instead, with the Q&A text centered inside. */
.kb-faq-box {
	background: var(--kb-color-white);
	border-radius: var(--kb-radius-card);
	padding: 48px;
}

.kb-faq-box .kb-feature__title,
.kb-faq-box .kb-feature__text {
	text-align: center;
}

/* Each Q&A row is its own .kb-feature__row block (not a flex sibling of
   the others), so the 64px .kb-feature__row gap only ever applied
   between the 3 columns of a single row — consecutive rows had just
   ~28px from paragraph margins, visibly tighter than the horizontal
   gap. Match it so the grid reads evenly spaced in both directions. */
.kb-faq-box .kb-feature__row + .kb-feature__row {
	margin-top: 64px;
}

/* Small muted line directly above a .kb-section-title, for a short lead-in
   sentence that isn't a full eyebrow label (e.g. "Die Knorke Agentur und
   WordPress: ein Dreamteam" ahead of "Eine Auswahl unserer WordPress
   Projekte"). */
.kb-section-kicker {
	text-align: center;
	font-size: 17px;
	font-weight: 500;
	color: var(--kb-color-gray-text);
	max-width: 700px;
	margin: 0 auto;
}

.kb-section-kicker + .kb-section-title {
	margin-top: 16px;
}

/* Larger kicker used on the service landing pages (production measures
   29px there, vs the 17px the shared kicker uses). */
.kb-section-kicker--lg {
	font-size: 29px;
	max-width: none;
	margin-bottom: 40px;
}

/* --- Landing pages: 3-up stat row (image + heading), e.g. "150+ Projekte /
   seit 2012 / Inhouse" — image is a small illustrative graphic, not a full
   feature photo, so it gets its own max-width instead of filling the
   column like .kb-feature__image does. --- */
.kb-stats {
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
	padding: 48px 24px 0;
}

.kb-stats__grid {
	justify-content: center;
	text-align: center;
	gap: 48px;
}

.kb-stats__item img {
	max-width: 180px;
	margin: 0 auto 16px;
}

.kb-stats__item h4 {
	font-size: 20px;
	font-weight: 600;
	margin: 0;
}

@media (max-width: 781px) {
	.kb-stats__grid {
		flex-wrap: wrap;
	}

	.kb-stats__item {
		flex-basis: 100% !important;
	}
}

/* --- Landing pages: native <details>/<summary> accordion for the closing
   long-form SEO section (no JS dependency, matches the "no runtime
   WPBakery" rule — production uses a JS accordion for the same content). --- */
.kb-accordion {
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
}

/* Narrower centered variant (measured ~912px on production for the
   "Unser Liebling: Shopware" accordion) — combined-class selector so it
   reliably wins over the base rule above regardless of stylesheet order,
   without touching .kb-accordion--narrow (a different, left-aligned
   700px variant used for a side-by-side FAQ+image layout elsewhere). */
.kb-accordion.kb-accordion--width-narrower {
	max-width: var(--kb-container-width-narrower);
}

/* /en/shopware-agency/'s "Our Favorite Store: Shopware" heading sat at the
   shared .kb-feature 1200px width, reading further left than the FAQ
   accordion directly below it (900px, centered) — matches the accordion's
   own width/centering instead. */
.kb-feature__title--faq-width {
	max-width: var(--kb-container-width-narrower);
	margin-left: auto;
	margin-right: auto;
}

.kb-accordion__item {
	border-bottom: 1px solid var(--kb-color-gray-lighter);
	padding: 20px 0;
}

.kb-accordion__item summary {
	cursor: pointer;
	font-size: 20px;
	font-weight: 600;
	list-style: none;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
}

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

/* The question text is wrapped in an h3 for real heading semantics
   (SEO/accessibility — accordion questions had no heading element at
   all before) — reset it to inherit summary's own flex/typography so
   it stays visually identical. */
.kb-accordion__item summary h3 {
	margin: 0;
	font-size: inherit;
	font-weight: inherit;
	line-height: inherit;
	display: inline;
}

/* Font Awesome "plus" / "minus" (classic solid), embedded via CSS mask so
   there's no icon-font dependency — same approach as the footer nav
   arrows and the .kb-check-list checkmarks. 15px keeps the same optical
   size the previous typographic "+" had (its ink measured ~11x8px at
   29px), while the icon itself is a true square plus. */
.kb-accordion__item summary::after {
	content: "";
	flex-shrink: 0;
	width: 15px;
	height: 15px;
	background-color: var(--kb-color-dark);
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H48c-17.7 0-32 14.3-32 32s14.3 32 32 32H192V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H400c17.7 0 32-14.3 32-32s-14.3-32-32-32H256V80z'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M256 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H48c-17.7 0-32 14.3-32 32s14.3 32 32 32H192V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H400c17.7 0 32-14.3 32-32s-14.3-32-32-32H256V80z'/%3E%3C/svg%3E");
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
}

.kb-accordion__item[open] summary::after {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z'/%3E%3C/svg%3E");
}

.kb-accordion__item p {
	font-size: 15px;
	line-height: 1.7;
	color: var(--kb-color-gray-text);
	margin: 16px 0 0;
}

/* --- Landing pages: process-step numbered list (e.g. "In 5 Schritten zum
   Launch") — plain text list, no image column. --- */
.kb-steps {
	max-width: var(--kb-container-width-medium);
	margin: 0 auto;
	counter-reset: kb-steps;
	padding: 0;
	list-style: none;
}

.kb-steps li {
	counter-increment: kb-steps;
	display: flex;
	gap: 24px;
	padding: 20px 0;
	border-bottom: 1px solid var(--kb-color-gray-lighter);
	font-size: 16px;
	line-height: 1.6;
}

.kb-steps li:last-child {
	border-bottom: none;
}

.kb-steps li::before {
	content: counter(kb-steps);
	flex-shrink: 0;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background: var(--kb-color-dark);
	color: var(--kb-color-white);
	display: flex;
	align-items: center;
	justify-content: center;
	font-weight: 600;
	font-size: 16px;
}

/* --- WordPress-Support page: scrolling topic-tag divider — real marquee
   matching production (a static wrapping row was used at first, but
   production genuinely scrolls this full-bleed), reusing the same
   translateX(-50%) track technique and @keyframes as the logo marquee
   above and the homepage Partners slider. --- */
.kb-tag-marquee {
	overflow: hidden;
	padding: 24px 0;
}

.kb-tag-marquee__track {
	display: flex;
	width: max-content;
	animation: kb-partners-scroll 30s linear infinite;
}

.kb-tag-marquee:hover .kb-tag-marquee__track {
	animation-play-state: paused;
}

/* Items and the "|" dividers are separate flex children, each with the
   same horizontal padding, so the space left and right of every divider
   is identical. (Baking the "|" into each item's own text made the gap
   before a divider twice the gap after it.)

   Deliberately padding rather than `gap`: the track loops by translating
   -50%, which is only seamless when the two halves are pure sums of child
   widths — a flex `gap` adds one extra inter-item gap between the halves
   and makes the loop jump by half a gap on every cycle. */
.kb-tag-marquee__item,
.kb-tag-marquee__sep {
	flex: 0 0 auto;
	white-space: nowrap;
	padding: 0 11px;
	font-size: 29px;
	font-weight: 600;
	color: var(--kb-color-dark);
}

.kb-tag-marquee__sep {
	font-weight: 400;
}

/* --- Section background used above the tag marquee ("Keine bittere
   Pille..."), matching production's light-gray row — a named modifier
   rather than changing .kb-feature globally, since most .kb-feature
   instances stay plain white. --- */
/* Full-bleed tinted section: the background spans the whole content
   column while the text inside keeps the normal reading width.

   .kb-feature is itself max-width-constrained and centered, so a
   background on it would only tint the inner column — visible as an
   inset gray block once the viewport is wider than the 1200px reading
   width. The element therefore goes full width and the reading width is
   re-created by the section's own horizontal padding, which leaves every
   child's own max-width/alignment behaving exactly as before (an inner
   wrapper with its own max-width would fight them instead).

   The max() keeps the usual 24px gutter on viewports narrower than the
   reading width. vw-based (via --kb-vmenu-reserve), not %, on purpose:
   a truly full-bleed child (.kb-cases__grid.alignfull, below) has to
   cancel this exact gutter with an equal-and-opposite margin, and
   percentage margin/padding on two different elements resolve against
   two different containing-block widths (parent's own vs. its content
   box after this padding is subtracted) — they'd only cancel by
   coincidence. vw has no such containing-block ambiguity, so the same
   calc() literal, copied into both rules, cancels exactly. */
.kb-feature--gray-bg,
.kb-price-section {
	background: var(--kb-color-gray-light);
	max-width: none;
	padding-inline: max(24px, calc((100vw - var(--kb-vmenu-reserve) - var(--kb-container-width-narrow)) / 2 + 24px));
}

/* Same full-bleed-background/centered-content technique as
   .kb-feature--gray-bg, Knorke yellow instead of light gray. */
.kb-feature--accent-bg {
	background: var(--kb-color-accent);
	max-width: none;
	padding-inline: max(24px, calc((100vw - var(--kb-vmenu-reserve) - var(--kb-container-width-narrow)) / 2 + 24px));
}

/* /magento-agentur/magento-support/'s migration-banner reusable block
   (ref 64999): decorative photo layered on top of --accent-bg's solid
   yellow, matching production's row-background + block-bg-overlay
   combo — same absolute-image approach as .kb-feature__bg/.kb-page-
   header__bg elsewhere, just without a dimming overlay (this one reads
   as a plain full-bleed photo, not text-legibility treatment). */
.kb-feature--accent-bg-photo {
	position: relative;
	overflow: hidden;
}

.kb-feature--accent-bg-photo .kb-feature__bg-photo {
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
}

.kb-feature--accent-bg-photo .kb-feature__bg-photo img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center bottom;
}

.kb-feature--accent-bg-photo > *:not(.kb-feature__bg-photo) {
	position: relative;
	z-index: 1;
}

/* Same technique again, one shade darker (production's color-gyho
   #eaeaea vs. --gray-bg's color-lxmt #f7f7f7) — for a section that
   needs to read as a distinct step down from an adjacent --gray-bg
   section rather than blending into it. */
.kb-feature--gray-lighter-bg {
	background: var(--kb-color-gray-lighter);
	max-width: none;
	padding-inline: max(24px, calc((100vw - var(--kb-vmenu-reserve) - var(--kb-container-width-narrow)) / 2 + 24px));
}

/* Narrower reading width (800px) than the shared 1200px calc() basis
   the full-bleed modifiers above use, for a section whose background
   should stay full-bleed while its content reads narrower still (e.g.
   combined with --gray-lighter-bg). A plain max-width here would fight
   the full-bleed technique — same calc() approach as --gray-bg/
   --accent-bg/--gray-lighter-bg, just against --kb-container-width-
   narrowest, and placed after them so this rule's padding-inline wins
   the tie on equal specificity when combined on the same element. */
.kb-feature--narrow {
	max-width: none;
	padding-inline: max(24px, calc((100vw - var(--kb-vmenu-reserve) - var(--kb-container-width-narrowest)) / 2 + 24px));
}

/* Generous vertical breathing room, matching production's "triple padding"
   statement rows (measured ~554px section height vs the 280px the default
   .kb-feature padding produced). */
.kb-feature--roomy {
	padding-top: 130px;
	padding-bottom: 130px;
}

.kb-feature--roomy .kb-section-title {
	margin-top: 24px;
	margin-bottom: 0;
}

/* Extra breathing room below a section only (e.g. "Integration &
   Anbindung" before the Payment/Versand/... rows start) — unlike
   --roomy, which is symmetric top+bottom. */
.kb-feature--roomy-bottom {
	padding-bottom: 130px;
}

/* --- WordPress-Support page: price card (the "Unser WordPress Support
   Angebot" box) — same flat-card convention as .kb-perk-card, just with
   left-aligned content since it holds a checklist, not a centered title. --- */
.kb-price-card {
	background: var(--kb-color-white);
	border-radius: var(--kb-radius-card);
	box-shadow: none;
	padding: 48px;
}

.kb-price-card__price {
	font-size: 36px;
	font-weight: 800;
	margin: 0 0 16px;
}

/* Production sets the price itself noticeably larger than the "/Monat"
   suffix that follows it in the same line. */
.kb-price-card__price .kb-price-card__amount {
	font-size: 50px;
}

/* Info icon + hover/focus tooltip on a checklist item (production shows a
   small "i" icon next to some perks; hovering/focusing reveals the detail
   text instead of always showing it inline). CSS-only, no JS. */
.kb-tooltip {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 15px;
	height: 15px;
	border-radius: 50%;
	background: var(--kb-color-gray-text);
	color: var(--kb-color-white);
	font-size: 10px;
	font-weight: 700;
	font-style: normal;
	cursor: help;
	flex-shrink: 0;
}

.kb-tooltip__text {
	position: absolute;
	bottom: calc(100% + 8px);
	left: 50%;
	transform: translateX(-50%);
	width: 260px;
	background: var(--kb-color-dark);
	color: var(--kb-color-white);
	font-size: 13px;
	font-weight: 400;
	line-height: 1.5;
	padding: 12px 14px;
	border-radius: 4px;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.15s ease;
	z-index: 2;
	pointer-events: none;
}

.kb-tooltip:hover .kb-tooltip__text,
.kb-tooltip:focus .kb-tooltip__text {
	opacity: 1;
	visibility: visible;
}

/* --- WordPress-Support page: short-case highlight row (image + name +
   subtitle + stat checklist + link), 3 used back to back. --- */
.kb-case-highlight__stats {
	margin: 24px 0;
}

/* --- WordPress-Support page: 8-up competency grid ("Services rundum
   sorglos") — same flat-card convention as .kb-perk-card. --- */
.kb-competency-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 24px;
}

/* Production renders these as plain text columns (no card background or
   padding) — the earlier gray-card treatment here was an invention. */
.kb-competency-card {
	background: none;
	box-shadow: none;
	padding: 0;
}

/* Animated icon above each service. Production ships these as Lottie
   JSON image-sequences totalling ~35 MB; they are re-encoded here as
   animated WebP at display resolution (~7 MB total) and lazy-loaded, so
   the animation is preserved without the payload. */
.kb-competency-card__icon {
	display: block;
	width: 100px;
	height: 100px;
	object-fit: contain;
	margin: 0 0 16px;
}

.kb-competency-card h5 {
	margin: 0 0 12px;
	font-size: 13px;
	font-weight: 700;
	text-transform: none;
	letter-spacing: normal;
}

.kb-competency-card p {
	font-size: 15px;
	line-height: 1.75;
	color: var(--kb-color-dark);
	margin: 0;
}

@media (max-width: 959px) {
	.kb-competency-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 599px) {
	.kb-competency-grid {
		grid-template-columns: 1fr;
	}
}

/* ===================================================================
   Service/SEO landing pages (WordPress-Support, WordPress-Agentur, and
   the ~13 remaining footer landing pages).

   These pages use a noticeably smaller heading scale than the homepage:
   measured against production, section headings are 29px, not the
   44.79px the shared .kb-section-title / .kb-feature__title default to.
   Rather than special-casing each page, the scale lives here as
   modifiers so the remaining landing pages can reuse it.
   =================================================================== */

/* Standard landing-page section heading (29px), vs the homepage's 44.79px. */
.kb-section-title--sm {
	max-width: none;
	margin-bottom: 32px;
}

.kb-section-title--sm h2,
.kb-section-title--sm h3 {
	font-size: 29px;
	font-weight: 500;
	line-height: 1.2;
}

/* The one large "statement" heading a landing page gets (production uses
   50px/900 for it, e.g. "Keine bittere Pille, sondern Frohlocken!"). */
.kb-section-title--statement h2 {
	font-size: 50px;
	font-weight: 900;
	line-height: 1.2;
}

/* Left-aligned section heading (production left-aligns several of them,
   e.g. "Services rundum sorglos", "Noch Fragen?"). */
.kb-section-title--left {
	text-align: left;
	margin-left: 0;
	margin-right: 0;
}

.kb-section-title--left .wp-block-separator.is-style-kb-accent {
	margin-left: 0;
}

/* Wide variant — the shared .kb-section-title caps at 700px, which forces
   production's single-line headings to wrap and squeezes the intro
   paragraph to roughly two-thirds of its real width. */
.kb-section-title--wide {
	max-width: 1104px;
}

.kb-section-title--wide p {
	font-size: 15px;
	line-height: 1.75;
}

/* Smaller feature-row title, matching the 29px landing-page scale
   (used for the short-case blocks: "Tag der Schiene", "GANGWAY", ...). */
.kb-feature__title--sm {
	font-size: 29px;
	line-height: 1.2;
}

/* /magento-agentur/magento-preise/'s "Was kostet eine Magento Agentur?"
   row: both sub-headlines measure 29px/400 on production despite being
   semantically an h2 and an h3 (bare heading tags there inherit
   different default sizes/weights, which is why they looked mismatched
   here) — reuses the 29px scale above, scoped further to also drop the
   weight to 400 so the h2 and h3 read identically side by side. */
.kb-feature__row--equal-subtitles .kb-feature__title--sm {
	font-weight: 400;
}

/* Bare <h5> inside a .kb-feature__content column (icon+h5+text service
   tiles, e.g. /wordpress-mit-knorke/'s "Services rundum sorglos",
   /magento-agentur/, /adobe-commerce/) — the global bare h5 rule in
   base.css (16px/uppercase, meant for small kicker labels) is wrong here;
   production measures ~26px/600/no-transform on all three pages that use
   this pattern, plus 18px down to the paragraph instead of the ~8px the
   heading's own default margin gives. */
.kb-feature__content h5 {
	font-size: 26px;
	font-weight: 600;
	text-transform: none;
	letter-spacing: normal;
	margin-bottom: 18px;
}

/* Centered icon+title+text cards (e.g. the SEA-Services grid on
   /deine-sea-agentur-aus-berlin/, pattern 103097) — image, title and text
   all centered within their column. Title measured at 24px/400 on
   production, not the 29px/600 the bare .kb-feature__title--sm above
   gives everywhere else, so it's scoped to this modifier instead of
   changed globally. */
.kb-feature--centered-cards .kb-feature__row {
	text-align: center;
}

.kb-feature--centered-cards .wp-block-image {
	display: flex;
	justify-content: center;
}

.kb-feature--centered-cards .kb-feature__title--sm {
	font-size: 24px;
	font-weight: 400;
}

/* Icon-grid item title in the recurring "Services" block (pattern 108293).
   Only the first item ("Beratung") originally carried a title class
   (kb-feature__title--sm, 29px) — the other five fell back to a plain,
   differently-sized/uppercase h5. Unified all six to this instead. */
.kb-feature__title--service {
	font-size: 24px;
	font-weight: 700;
}

/* Accent separator under the Services block's own section title — left-
   aligned (the title isn't centered) with extra bottom space before the
   icon grid starts. Scoped to this one title via its own class rather
   than the shared .kb-feature__content left-margin rule, so it doesn't
   also change the (already-correct) spacing on Payment/Versand/etc. */
.kb-services__title + .wp-block-separator.is-style-kb-accent {
	margin: 16px 0 40px;
}

/* Kicker eyebrow above a .kb-feature__title/.kb-section-title--lg title —
   only fires when a matching title actually follows immediately (the
   Payment/Versand/etc. pattern). The same tag+class combos are also used
   on some pages as a plain, dark grid-item title with nothing following
   (e.g. the shop-system grid's "Magento"/"Shopware", or /shopify/'s
   services grid), which must NOT go gray — hence :has() instead of a
   blanket tag+class rule. /sem-agentur-berlin/ additionally uses a bare
   h2.kb-feature__title--sm as the kicker (with an h3.kb-feature__title as
   the title it introduces), on top of the h4/h6 variants seen elsewhere. */
h4.kb-feature__title--sm:has(+ h2.kb-feature__title),
h2.kb-feature__title--sm:has(+ h2.kb-feature__title),
h2.kb-feature__title--sm:has(+ h3.kb-feature__title) {
	color: var(--kb-color-gray-text);
}

/* Same kicker-eyebrow role as h4.kb-feature__title--sm above, but some
   pages (e.g. /woocommerce-agentur/) use a bare h6 instead — no size/color
   rule existed for h6 at all before this, so it fell back to the browser
   default (tiny, body-color) instead of production's 29px gray eyebrow. */
h6.wp-block-heading:has(+ h2.kb-section-title--lg),
h6.wp-block-heading:has(+ h2.kb-feature__title) {
	font-size: 29px;
	font-weight: 600;
	color: var(--kb-color-gray-text);
}

/* /usability-conversion-rate-optimierung/ uses yet another kicker
   variant: a bare h2 (no class at all) instead of h4/h6/h2--sm. Sized
   29px like the others, but weight 400 (not 600) — measured off
   production. Excludes the titled h2 variants so it can't also catch
   the title itself or another kicker class by accident. */
h2.wp-block-heading:not(.kb-feature__title):not(.kb-section-title--lg):not(.kb-feature__title--sm):has(+ h2.kb-section-title--lg),
h2.wp-block-heading:not(.kb-feature__title):not(.kb-section-title--lg):not(.kb-feature__title--sm):has(+ h2.kb-contact__title) {
	font-size: 29px;
	font-weight: 400;
	color: var(--kb-color-gray-text);
}

/* Landing-page sections that sit on production's light-gray row
   background. .kb-feature--gray-bg already covers .kb-feature; these
   cover the other section components used on these pages. */
.kb-section--gray-bg {
	background: var(--kb-color-gray-light);
}

/* Price/offer section: production inverts the usual treatment — light-gray
   section with a WHITE card on top (not a gray card on white). */
.kb-price-section {
	background: var(--kb-color-gray-light);
}

/* FAQ accordion on these pages is a narrow left-hand column, not full
   content width. */
.kb-accordion--narrow {
	max-width: 700px;
	margin-left: 0;
}

.kb-accordion--narrow summary {
	font-size: 17px;
	font-weight: 500;
}

/* Body text at the same 17px as the --narrow summary above, instead of
   the shared 15px — production's /wordpress-mit-knorke/ FAQ measures
   both title and answer at 17px. Kept separate from --narrow itself
   since other --narrow pages measured 15px body text. */
.kb-accordion--body-lg .kb-accordion__item p {
	font-size: 17px;
}

/* Step-number section ("Dein Weg zum Erfolg" on /ki-seo-agentur/) reuses
   kb-section-title--lg for its "1./2./3./4." digits, but production sizes
   them bigger and accent-colored here instead of the usual 50px/dark
   section-title treatment — scoped to this section only. */
.kb-steps h2.kb-section-title--lg {
	font-size: 60px;
	color: var(--kb-color-accent);
}

/* Standalone icon+heading CTA tile inside an icon grid (the "Los geht's!"
   card ending the AIO-Services grid on /ki-seo-agentur/) — accent
   background, whole tile is the link. */
.kb-icon-cta {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	justify-content: center;
	background: var(--kb-color-accent);
	padding: 32px;
	text-decoration: none;
}

.kb-icon-cta svg {
	width: 48px;
	height: 48px;
	margin-bottom: 16px;
	color: var(--kb-color-dark);
}

.kb-icon-cta .kb-feature__title--service {
	margin: 0;
}

/* Larger centered section heading (production uses 50px for these, e.g.
   "Design Projekte"); weight kept at 500 per the site-wide minimum.
   Written for the className-on-a-wrapper markup; some pages instead put
   the className directly on the <h2> itself (e.g. /woocommerce-agentur/),
   which the descendant selector alone doesn't reach. */
.kb-section-title--lg h2,
h2.kb-section-title--lg {
	font-size: 50px;
	font-weight: 500;
	line-height: 1.2;
}

/* Bolder one-off variant — /woocommerce-agentur/'s "WooCommerce
   Leistungen" and "First steps..." headings need 600, not the shared
   500 default other .kb-section-title--lg headings on this and other
   pages use (e.g. "Eine Auswahl unserer WooCommerce Projekte" further
   down this same page keeps 500). Extra modifier class instead of
   changing the shared rule above. */
.kb-section-title--lg.kb-section-title--bold h2,
h2.kb-section-title--lg.kb-section-title--bold {
	font-weight: 600;
}

/* Generic, tag/class-agnostic bold opt-in for a bare heading that has no
   other shared class to hang a scoped modifier on (e.g. the un-classed
   h2 kickers on /usability-conversion-rate-optimierung/, which the
   existing h6-kicker :has() rule doesn't reach since these are h2s).
   !important: the bare-h2-kicker rule below this page was originally
   built for (h2.wp-block-heading:not(...):has(+h2...)) carries much
   higher specificity from its :not()/:has() chain, and explicitly
   forces weight 400 — opting a specific instance back into 600 needs to
   win that fight rather than out-specify it. */
.kb-heading--bold {
	font-weight: 600 !important;
}

/* A centered heading inside the usually-left-aligned .kb-feature__content
   (e.g. a lone intro paragraph in an otherwise 2-up row) needs its accent
   separator centered too, overriding the shared left-margin rule below. */
.kb-feature__content h2.has-text-align-center + .wp-block-separator.is-style-kb-accent {
	margin: 16px auto 24px;
}

/* Looping video as a page-header background (production uses one on
   /design-agentur/). Sits in the same .kb-page-header__bg wrapper as the
   image variant, so the existing overlay applies unchanged. */
.kb-page-header__bg-video {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Video-backed headers use a lighter overlay than the near-opaque one the
   image variant needs, so the motion stays visible. */
.kb-page-header--video .kb-page-header__bg::after {
	background: rgba(255, 255, 255, 0.85);
}

/* Two-column hero (text left, artwork right), 53.75px headline. Content
   width re-measured 2026-08-22: production actually scales fluidly with
   the viewport (~75% of it, no fixed cap up to at least 2560px) rather
   than sitting at a fixed width — the earlier "1020px" figure here was
   simply wrong. Using the site's own narrow container token is a much
   closer match than the old hardcoded value at the viewport widths that
   matter in practice, even though it won't reproduce the fluid scaling
   at very wide screens. */
.kb-page-header--video .kb-page-header__inner {
	max-width: var(--kb-container-width-narrow);
}

.kb-page-header--video .kb-page-header__title {
	font-size: 53.75px;
}

.kb-page-header--video .kb-page-header__intro,
.kb-page-header--video .kb-check-list li {
	font-size: 18px;
	line-height: 1.75;
	color: var(--kb-color-dark);
	max-width: none;
}

/* Round-tripped back to stacked/column after trying inline row: at M
   size the combined button width didn't fit the 50% hero column on one
   line, so row+nowrap wrapped each label internally instead (2-3 lines
   per button) — worse than the original stack. Column layout without a
   forced width lets each button size to its own (single-line) label
   instead of the old width:100% full-bleed first button. */
.kb-page-header--video .wp-block-buttons {
	flex-direction: column;
	align-items: flex-start;
	gap: 12px;
}

.kb-page-header--video .wp-block-buttons .wp-block-button__link {
	white-space: nowrap;
}

/* Kicker sitting directly above a heading inside a feature row: left
   aligned and tight to the heading, unlike the standalone centered one. */
.kb-feature__content .kb-section-kicker {
	text-align: left;
	max-width: none;
	margin: 0 0 8px;
}

/* --- Two-up service grid with an illustration per item (Design-Agentur
   "Services"). Distinct from .kb-competency-grid, which is a four-up
   text-only grid. --- */
.kb-service-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 36px;
	max-width: 1104px;
	margin: 0 auto;
}

/* White cards on the section's gray background (production's treatment). */
.kb-service-grid__item {
	text-align: center;
	background: var(--kb-color-white);
	border-radius: var(--kb-radius-card);
	padding: 40px 32px;
}

.kb-service-grid__item img {
	display: block;
	width: 100%;
	max-width: 370px;
	height: auto;
	margin: 0 auto 24px;
}

.kb-service-grid__item h3 {
	font-size: 37.32px;
	font-weight: 600;
	line-height: 1.2;
	margin: 0 0 12px;
}

.kb-service-grid__item p {
	font-size: 15px;
	line-height: 1.75;
	margin: 0;
}

@media (max-width: 781px) {
	.kb-service-grid {
		grid-template-columns: 1fr;
		gap: 48px;
	}
}

/* --- Dark full-bleed section (Design-Agentur "Knorke Fonts" row).
   Same full-bleed technique as .kb-feature--gray-bg. --- */
.kb-section--dark {
	position: relative;
	overflow: hidden;
	background: var(--kb-color-dark);
	color: var(--kb-color-white);
	max-width: none;
	padding-inline: max(24px, calc((100% - var(--kb-container-width-narrow)) / 2 + 24px));
	text-align: center;
}

/* Optional photo behind a dark section, dimmed by an overlay (production
   puts one behind the Knorke-Fonts row). Same bg-layer pattern as
   .kb-page-header__bg / .kb-contact__bg. */
.kb-section__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
}

.kb-section__bg-image {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.kb-section__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(30, 34, 37, 0.3);
}

/* Plain .kb-feature section with a dimmed parallax photo behind its
   text — same bg-layer pattern as .kb-page-header__bg/.kb-contact__bg/
   .kb-section__bg above, but for an otherwise ordinary light .kb-feature
   section (not a hero, the dedicated .kb-contact component, or a dark
   section) — first use: /magento-preise/'s "Wie viel kostet ein
   Onlineshop?" block, which production runs on the same webdesign-
   knorke.png + light-gray dim overlay as the hero/contact sections. */
/* Full-bleed box (background spans the whole viewport width, same
   calc()-padding technique as .kb-feature--gray-bg), while the actual
   columns inside keep reading at the normal ~1200px content width —
   the padding-inline value is exactly half the leftover space beyond
   that width, so it recreates the reading column automatically without
   a separate max-width on the inner content. */
.kb-feature--has-bg {
	position: relative;
	overflow: hidden;
	max-width: none;
	padding-inline: max(24px, calc((100vw - var(--kb-vmenu-reserve) - var(--kb-container-width-narrow)) / 2 + 24px));
}

.kb-feature__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
}

.kb-feature__bg-image {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.kb-feature__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(247, 247, 247, 0.98);
}

.kb-feature--has-bg > *:not(.kb-feature__bg) {
	position: relative;
	z-index: 1;
}

/* /cases/der-bannerexpress/-only: "Bannerdesigner aus eigener Schmiede" reuses
   .kb-feature--has-bg for its full-bleed + parallax photo, but needs the dark
   tint + white text production runs there instead of the shared light-gray
   dim above — same tie-break pattern as .kb-page-header--dark. */
body.postid-58979 .kb-feature__bg::after {
	background: rgba(20, 22, 24, 0.35);
}

/* /en/cases/der-bannerexpress/ (postid-68569) — same page as postid-58979
   above, English translation. Was still falling back to the shared
   light-gray dim (see .kb-feature__bg::after default). */
body.postid-68569 .kb-feature__bg::after {
	background: rgba(20, 22, 24, 0.35);
}

.kb-section--dark > *:not(.kb-section__bg) {
	position: relative;
	z-index: 1;
}

.kb-section--dark h2,
.kb-section--dark h3,
.kb-section--dark p {
	color: var(--kb-color-white);
}

/* /design-agentur/'s "The Fresh Prince" logo sat flush against the
   "Zu den Lizenzen" button below it (0px gap) — the raw <img> in this
   wp:html block has no margin of its own, unlike a normal wp:image
   block's figure wrapper. Scoped under .kb-section--dark (not just the
   bare class) so it out-specifies that section's own
   ".kb-section--dark img { margin: 0 auto }" reset, which otherwise wins
   on element-vs-class specificity despite coming first in the file.
   Also had to extend that reset's display:block to <picture> above —
   on /en/design-agency/ Imagify had wrapped this exact image in
   <picture class="kb-section__logo-img"><img>...</picture> (moving the
   class off the <img>), so the class-based margin-bottom here landed on
   an element that was still display:inline by default and did nothing. */
.kb-section--dark .kb-section__logo-img {
	margin-bottom: 32px;
}

/* /en/design-agency/ specifically wants 40px here, not the shared 32px
   DE still uses. */
body.page-id-105541 .kb-section--dark .kb-section__logo-img {
	margin-bottom: 40px;
}

/* Match the shared section-heading scale; a bare h2 would otherwise fall
   back to the global clamp() and land at 40px. */
.kb-section--dark h2 {
	font-size: 44.79px;
	font-weight: 600;
	line-height: 1.2;
	margin-bottom: 32px;
}

.kb-section--dark .wp-block-button__link {
	background: var(--kb-color-white);
	color: var(--kb-color-dark);
	border-color: var(--kb-color-white);
}

.kb-section--dark .wp-block-button__link:hover {
	background: transparent;
	color: var(--kb-color-white);
}

.kb-section--dark img,
.kb-section--dark picture {
	display: block;
	margin: 0 auto;
}

/* --- Video lightbox (native <dialog>, see assets/js/video-modal.js).
   The dialog element itself is the click-catching backdrop area; the
   video sits in an inner box so a click beside it closes the modal. --- */
.kb-video-modal {
	border: 0;
	padding: 0;
	background: transparent;
	width: min(1100px, 92vw);
	max-width: none;
	max-height: 92vh;
	overflow: visible;
	color: var(--kb-color-white);
}

.kb-video-modal::backdrop {
	background: rgba(20, 22, 24, 0.88);
}

.kb-video-modal video {
	display: block;
	width: 100%;
	height: auto;
	/* preload="none" means the intrinsic size is unknown until playback
	   starts; without this the box collapses and then jumps. */
	aspect-ratio: 16 / 9;
	max-height: 84vh;
	border-radius: var(--kb-radius-card);
	background: #000;
}

.kb-video-modal__close {
	position: absolute;
	top: -44px;
	right: 0;
	width: 32px;
	height: 32px;
	padding: 0;
	border: 0;
	background: none;
	color: var(--kb-color-white);
	cursor: pointer;
	line-height: 1;
}

.kb-video-modal__close::before {
	content: "";
	display: block;
	width: 100%;
	height: 100%;
	background-color: currentColor;
	/* Font Awesome classic-solid "xmark", embedded via mask like the
	   other icons in this theme. */
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath d='M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath d='M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z'/%3E%3C/svg%3E");
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
}

@media (max-width: 781px) {
	.kb-video-modal__close {
		top: -40px;
	}
}

/* --- Vertical tabs (e.g. the "Wie wir für Dich arbeiten" process steps).

   CSS-only, driven by radio inputs, so there is no JS dependency. The
   markup order is: all inputs, then all labels, then all panels — they must
   be siblings for the `:checked ~` pairing below to reach across.

   The pairings are written out per index rather than generated, because CSS
   cannot count. Eight is well above the six the site currently uses; add
   more lines if a longer set ever appears. --- */
.kb-tabs {
	display: grid;
	grid-template-columns: 280px 1fr;
	column-gap: 56px;
	align-items: start;
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
}

.kb-tabs input {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
	pointer-events: none;
}

.kb-tabs__label {
	grid-column: 1;
	display: block;
	cursor: pointer;
	padding: 16px 0;
	border-bottom: 1px solid var(--kb-color-gray-lighter);
	/* Reserved unconditionally (transparent by default) so the active
	   state only swaps the color — it never adds layout width that
	   would shift the label text sideways relative to the others. */
	border-right: 2px solid transparent;
	/* The continuous line down the whole column (production has this on
	   the tab list's own border, not per item) — box-shadow instead of a
	   second border, since border-right is already spoken for above. */
	box-shadow: inset -1px 0 0 var(--kb-color-gray-lighter);
	font-size: 12px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 1.5px;
	color: var(--kb-color-dark);
	transition: color 0.15s ease, border-color 0.15s ease;
}

.kb-tabs__label:hover {
	color: var(--kb-color-accent);
}

/* Panels all share the second column; only the checked one is shown. The
   explicit grid has no rows, so a generous span keeps them spanning however
   many rows the labels create. */
.kb-tabs__panel {
	grid-column: 2;
	grid-row: 1 / 100;
	display: none;
	padding-top: 40px;
}

/* Unified panel heading — only the first panel ("Anfrage") originally
   carried kb-feature__title (44.79px); the other five were bare h2s at
   whatever the browser/base default happened to be. */
.kb-tabs__panel h2 {
	font-size: 29px;
	font-weight: 600;
	line-height: 1.2;
	margin: 0 0 16px;
}

.kb-tabs__panel .wp-block-separator.is-style-kb-accent {
	margin: 0 0 24px;
}

.kb-tabs__panel p {
	font-size: 15px;
	line-height: 1.75;
	margin: 0 0 16px;
}

.kb-tabs input:nth-of-type(1):checked ~ .kb-tabs__label:nth-of-type(1),
.kb-tabs input:nth-of-type(2):checked ~ .kb-tabs__label:nth-of-type(2),
.kb-tabs input:nth-of-type(3):checked ~ .kb-tabs__label:nth-of-type(3),
.kb-tabs input:nth-of-type(4):checked ~ .kb-tabs__label:nth-of-type(4),
.kb-tabs input:nth-of-type(5):checked ~ .kb-tabs__label:nth-of-type(5),
.kb-tabs input:nth-of-type(6):checked ~ .kb-tabs__label:nth-of-type(6),
.kb-tabs input:nth-of-type(7):checked ~ .kb-tabs__label:nth-of-type(7),
.kb-tabs input:nth-of-type(8):checked ~ .kb-tabs__label:nth-of-type(8) {
	color: var(--kb-color-accent);
	border-right-color: var(--kb-color-accent);
}

.kb-tabs input:nth-of-type(1):checked ~ .kb-tabs__panel:nth-of-type(1),
.kb-tabs input:nth-of-type(2):checked ~ .kb-tabs__panel:nth-of-type(2),
.kb-tabs input:nth-of-type(3):checked ~ .kb-tabs__panel:nth-of-type(3),
.kb-tabs input:nth-of-type(4):checked ~ .kb-tabs__panel:nth-of-type(4),
.kb-tabs input:nth-of-type(5):checked ~ .kb-tabs__panel:nth-of-type(5),
.kb-tabs input:nth-of-type(6):checked ~ .kb-tabs__panel:nth-of-type(6),
.kb-tabs input:nth-of-type(7):checked ~ .kb-tabs__panel:nth-of-type(7),
.kb-tabs input:nth-of-type(8):checked ~ .kb-tabs__panel:nth-of-type(8) {
	display: block;
}

/* Keyboard focus has to stay visible even though the input itself is
   visually hidden. */
.kb-tabs input:focus-visible ~ .kb-tabs__label {
	outline: 2px solid var(--kb-color-accent);
	outline-offset: 2px;
}

/* On narrow screens the two columns collapse into one: the full label list
   first, then the selected panel underneath. Interleaving each panel with
   its own label (accordion style) would need a per-index `order` rule for
   every tab, which is not worth the extra weight here. */
@media (max-width: 781px) {
	.kb-tabs {
		grid-template-columns: 1fr;
		row-gap: 8px;
	}

	.kb-tabs__label,
	.kb-tabs__panel {
		grid-column: 1;
	}

	.kb-tabs__panel {
		grid-row: auto;
	}
}

/* --- Steps slider: dark full-bleed section, /shopify/'s "Wie wir
   arbeiten". Measured directly against production (an Owl Carousel)
   rather than assumed: the visible card area is NOT full-bleed/native-
   scrolling — it's a FIXED-width window matching the site's normal
   content column (~1128px measured, close enough to the shared
   --kb-container-width-narrow to reuse that instead of a one-off
   value), overflow:hidden, with the cards slid inside it via a JS
   transform (data-lg="3": 3 cards/page on desktop). On mobile
   (data-sm="1": 1 card/page) the window itself changes shape — it
   keeps the normal left inset but runs flush to the true right edge
   instead of staying centered/contained, so exactly one full-bleed-
   feeling card is visible at a time. No carousel library — a plain
   flex track + translateX in steps-slider.js reproduces both without
   one. Meant to be reused on future pages with the same "recurring
   block", not a one-off for this page. --- */
.kb-steps-slider {
	position: relative;
	/* Same background photo + dark-overlay mechanism as the shared
	   .kb-page-header__bg pattern (production: webdesign-knorke.png at
	   0.98 opacity dark overlay) — here as a plain background-image
	   since this section has no separate bg layer markup, with the
	   overlay as ::before instead so it can sit under the content
	   without an extra element in the markup. */
	background-image: url("https://staging.knorke.de/wp-content/uploads/2021/05/webdesign-knorke.png");
	background-size: cover;
	background-position: center;
	color: var(--kb-color-white);
	/* .kb-feature (the other class on this same element) sets
	   max-width:1200px — removed here so the section fills its parent's
	   full content width. Deliberately NOT `width:100vw` +
	   `margin-left:calc(50% - 50vw)` (an earlier version of this rule
	   used that): 100vw measures the viewport including the space a
	   vertical scrollbar occupies, so on any page tall enough to scroll
	   it's a few pixels wider than the page's real content width —
	   exactly the classic "100vw causes a horizontal scrollbar" bug,
	   confirmed here via getBoundingClientRect() showing this element a
	   few px past both edges of document.documentElement.clientWidth.
	   This element already sits as a direct, unwrapped child of the
	   normal content flow (no narrower ancestor), so max-width:none
	   alone is enough to reach true full width without measuring the
	   viewport at all. */
	max-width: none;
	padding: 96px 0;
	overflow: hidden;
}

.kb-steps-slider::before {
	content: "";
	position: absolute;
	inset: 0;
	background: var(--kb-color-darker);
	opacity: 0.95;
}

.kb-steps-slider__inner,
.kb-steps-slider__viewport {
	position: relative;
	z-index: 1;
}

.kb-steps-slider__inner {
	max-width: var(--kb-container-width-narrow);
	margin: 0 auto;
	padding: 0 24px;
	text-align: center;
}

.kb-steps-slider__inner .kb-feature__title {
	color: var(--kb-color-white);
}

.kb-steps-slider__inner .wp-block-image {
	display: inline-block;
}

/* The fixed-width viewing window — same width as every other section's
   normal content column, centered, clipping the wider track inside it.
   This (not the dark background above) is what actually determines how
   many cards are visible at once. */
.kb-steps-slider__viewport {
	max-width: var(--kb-container-width-narrow);
	margin: 48px auto 0;
	padding: 0 24px;
	overflow: visible;
}

@media (max-width: 959px) {
	/* Production's mobile card runs flush to the true right edge (only
	   a left inset, matching the normal content margin) instead of
	   staying centered/contained — .kb-steps-slider is already 100vw
	   here (its own padding aside), so this only needs to cancel the
	   viewport's own max-width/centering, not repeat the vw math. */
	.kb-steps-slider__viewport {
		max-width: none;
		margin: 48px 0 0;
		padding: 0 0 0 24px;
	}
}

.kb-steps-slider__track {
	/* position:relative makes track the offsetParent of its cards, so
	   card.offsetLeft in steps-slider.js is measured relative to it —
	   needed for the transform math to be correct (transform shifts
	   track relative to its own untransformed position, so the target
	   offset must be in that same coordinate space). */
	position: relative;
	display: flex;
	/* Deliberate deviation from production (which has 0 gap, cards
	   sharing touching borders) — 36px breathing room between cards
	   instead. */
	gap: 36px;
	/* Moved by steps-slider.js via transform: translateX(), not native
	   scroll — matches production (Owl Carousel slides a fixed-width
	   window's contents by JS, it isn't an overflow:auto scroller). */
	transition: transform 0.4s ease;
}

/* Dot pagination (one dot per page of cards, not one per card) — built
   by steps-slider.js, which also keeps the active dot in sync and
   slides the track when a dot is clicked. Mirrors production's separate
   [uncode_carousel_nav] element sitting below the slider itself. */
.kb-steps-slider__dots {
	/* .kb-steps-slider::before (the dark background overlay) is
	   position:absolute with no z-index — in the stacking order that
	   still paints above a plain position:static sibling appended after
	   it, so without this the overlay sat visually on top of the dots
	   (washing out their color) AND ate their clicks (elementFromPoint
	   at a dot's own center landed on the overlay, not the dot). */
	position: relative;
	z-index: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	margin-top: 32px;
}

.kb-steps-slider__dot {
	width: 9.6px;
	height: 9.6px;
	padding: 0;
	border: none;
	border-radius: 50%;
	background: var(--kb-color-gray-text);
	cursor: pointer;
}

.kb-steps-slider__dot.is-active {
	width: 14.4px;
	height: 14.4px;
	background: var(--kb-color-accent);
}

/* 3 per page on desktop (production's data-lg="3"), edge to edge with
   no gap — each card's own border is what visually separates them,
   same as production measures (sequential cards with zero gap between
   their bounding boxes). box-sizing:border-box so the border doesn't
   push the 3-per-row math past 100%. */
.kb-steps-slider__card {
	/* 33.3333% would overflow now that .kb-steps-slider__track has its
	   own 36px gap — flex-basis percentages are resolved against the
	   container's size without deducting gap space when flex-grow/
	   shrink are 0, so 3 cards at a plain third each plus 2 real gaps
	   would run past the viewport's edge. Subtracting the 2 gaps
	   between 3 cards up front keeps 3 fitting exactly. */
	flex: 0 0 calc((100% - 72px) / 3);
	box-sizing: border-box;
	/* Matches production exactly (measured: solid, fully opaque white,
	   not a translucent tint). */
	border: 2px solid var(--kb-color-white);
	padding: 32px;
	text-align: left;
}

@media (max-width: 959px) {
	/* 1 per page on mobile (production's data-sm="1"). */
	.kb-steps-slider__card {
		flex-basis: 100%;
	}
}

.kb-steps-slider__card h3 {
	font-size: 22px;
	font-weight: 600;
	margin: 0 0 12px;
}

.kb-steps-slider__card p {
	font-size: 15px;
	line-height: 1.6;
	margin: 0 0 16px;
	color: var(--kb-color-white);
}

.kb-steps-slider__card .kb-check-list {
	margin: 0;
}

.kb-steps-slider__card .kb-check-list li {
	font-size: 14px;
	color: var(--kb-color-white);
}

/* --- Pricing cards (3-tier), first use: /wordpress-website-erstellen-lassen/ --- */
.kb-pricing__grid {
	display: flex;
	align-items: stretch;
	gap: 32px;
}

.kb-pricing__card {
	flex: 1;
	display: flex;
	flex-direction: column;
	background: var(--kb-color-gray-light);
	border: 1px solid var(--kb-color-gray);
	border-radius: 4px;
	padding: 40px 32px;
	text-align: center;
}

/* Middle/featured tier gets the accent border, matching the theme's
   existing accent-color convention rather than inventing a new "badge". */
.kb-pricing__card--featured {
	border-color: var(--kb-color-accent);
	border-width: 2px;
}

.kb-pricing__name {
	font-size: 20px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	margin: 0 0 8px;
}

.kb-pricing__price {
	font-size: 42px;
	font-weight: 800;
	margin: 0 0 24px;
}

.kb-pricing__card .kb-check-list {
	text-align: left;
	margin: 0 0 32px;
	flex-grow: 1;
}

.kb-pricing__card .wp-block-buttons {
	margin-top: auto;
	justify-content: center;
}

@media (max-width: 781px) {
	.kb-pricing__grid {
		flex-direction: column;
	}
}

/* --- Testimonial cards, first use: /wordpress-website-erstellen-lassen/ ---
   Placeholder-safe: cards render fine with example copy until real
   customer quotes replace it during Feinschliff. */
.kb-testimonials__grid {
	display: flex;
	align-items: stretch;
	gap: 32px;
}

.kb-testimonials__card {
	flex: 1;
	background: var(--kb-color-gray-light);
	border-radius: 4px;
	padding: 32px;
}

.kb-testimonials__quote {
	font-style: italic;
	font-size: 17px;
	line-height: 1.6;
	margin: 0 0 16px;
}

.kb-testimonials__author {
	font-weight: 700;
	margin: 0;
}

.kb-testimonials__role {
	color: var(--kb-color-gray-text);
	font-size: 14px;
	margin: 4px 0 0;
}

@media (max-width: 781px) {
	.kb-testimonials__grid {
		flex-direction: column;
	}
}

