/*
 * Product-line landing page, emo2026.
 *
 * Used by four pages: /produkte/ and the three line pages
 * /produkte/netzwerkisolatoren/, /produkte/fussschalter/ and
 * /produkte/trenntransformatoren/. The three line pages go through one
 * template-part (template-parts/product-line.php) with a config array;
 * /produkte/ writes its own markup with the same classes, because it has
 * no highlights, no spec strip and no model cards.
 *
 * Sections: hero, highlights, spec strip, star product, explainer,
 * line bands, variant grid, CTA stripe. The star product and the line
 * bands share the banner component (.product-line__banner).
 *
 * Plain CSS, hand-authored. Apple's product-overview pages are the visual
 * reference (apple.com/de/mac, /iphone). Shared design tokens live in
 * assets/css/tokens.css (loaded as the 'emo2026-tokens' stylesheet
 * dependency). Only product-line-specific values stay local below.
 */

:root {
	/* ---- Geometry (product-line-only) ---- */
	--pl-max-width: var(--layout-content-max-width);
	--pl-side-padding: var(--layout-gutter);
	--pl-mobile-breakpoint: 833px; /* Same cutover as the nav. */

	/* ---- Vertical rhythm ----
	 * Each section gets a generous Apple-style block of breathing room.
	 * Tightens proportionally on mobile via the media query at the bottom. */
	--pl-section-pad-y: var(--space-11);     /* 96px desktop  */
	--pl-section-pad-y-mobile: var(--space-9); /* 64px under 833px */

	/* ---- Hero ----
	 * Soft slate-to-white gradient under the title. Tunable per slug
	 * via the .product-line--{slug} hook below. */
	--pl-hero-bg: linear-gradient(180deg, var(--grey-25) 0%, var(--grey-50) 60%, var(--color-bg-base) 100%);
	--pl-hero-pad-y: var(--space-12);          /* 128px */
	--pl-hero-pad-y-mobile: var(--space-10);   /*  80px */

	/* ---- Variant card ---- */
	--pl-card-radius: var(--radius-card);
	--pl-card-bg: var(--color-bg-elevated);
	--pl-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
	--pl-card-shadow-hover: 0 18px 36px rgba(0, 0, 0, 0.10);
	--pl-card-media-aspect: 4 / 3;

	/* ---- Spec strip ----
	 * Horizontal hairline-bordered band on a light backdrop. */
	--pl-spec-bg: var(--color-bg-elevated);
	--pl-spec-border: var(--color-border-hairline);

	/* ---- CTA stripe ----
	 * Deep neutral so the white type pops, mirroring Apple's footer-cards. */
	--pl-cta-stripe-bg: var(--grey-900);
	--pl-cta-stripe-fg: var(--color-text-inverse);

	/* ---- Motion ---- */
	--pl-easing: var(--motion-ease-standard);
	--pl-duration: var(--motion-duration-base);
}

/* ============================================================
 * Per-slug hero gradient overrides.
 * Lets each product line have its own brand-tinted backdrop
 * without touching the shared hero rule below.
 * ============================================================ */
/* All three were cool-blue tints under the Apple palette. On the brand
   palette they share the same soft brand wash: three near-identical
   blue-greys were a distinction nobody could see anyway, and one token
   keeps a future palette change to a single edit. Reinstate a per-line
   tint here if a line ever earns a genuinely distinct treatment. */
.product-line--netzwerkisolatoren,
.product-line--fussschalter,
.product-line--trenntransformatoren,
/* Seit 15.09.2026 laeuft auch /produkte/ in diesem System, damit der
   Einstieg aussieht wie die drei Seiten, in die er fuehrt. */
.product-line--produkte {
	--pl-hero-bg: var(--emo-grad-wash);
}

/* ============================================================
 * Host element
 * ============================================================ */
.product-line {
	color: var(--color-text-primary);
	font-family: var(--font-sans);
	background: var(--color-bg-base);
}

/* Shared narrow inner-wrapper used by sections that want the
 * standard 1200px content cap with 22px gutters. */
.product-line__hero-inner,
.product-line__variants-inner,
.product-line__cta-stripe-inner {
	max-width: var(--pl-max-width);
	margin-inline: auto;
	padding-inline: var(--pl-side-padding);
}

/* ============================================================
 * 1. HERO
 * ============================================================ */
.product-line__hero {
	background: var(--pl-hero-bg);
	padding-block: var(--pl-hero-pad-y);
	text-align: center;
}

.product-line__hero-inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-4);
}

/* Centered flex children shrink-wrap to min-content, and one long
 * compound word can make a child WIDER than the hero. A spill past the
 * viewport is cut at the left edge, out of reach of scrolling. Same
 * guard home.css documents on its tile content. */
.product-line__hero-inner > * {
	min-width: 0;
	max-width: 100%;
}

/* The line's brand mark sits above the wordmark eyebrow and needs no rule
 * of its own: the hero-inner flex column already centres and spaces its
 * children, and icons.css already inks it EMO CORE. That default exists
 * partly because of this hero, whose wash ends on the same mint an icon
 * used to be tinted with. */

.product-line__eyebrow {
	margin: 0;
	font-family: var(--font-sans);
	font-size: var(--font-size-18);
	font-weight: 500;
	/* Brand green, sitewide (owner 2026-08-31): hero eyebrows carry emo
	 * green everywhere, matching the shop hero. */
	color: var(--color-accent);
	letter-spacing: var(--letter-spacing-base);
}

.product-line__title {
	margin: 0;
	font-family: var(--font-display);
	font-size: var(--font-size-56);
	line-height: var(--line-height-display);
	letter-spacing: var(--letter-spacing-tight);
	font-weight: 600;
	color: var(--color-text-primary);
	/* No text-wrap: balance, fit-titles.js budgets these to one line. */
	overflow-wrap: break-word;
}

.product-line__tagline {
	margin: 0;
	max-width: 720px;
	font-size: var(--font-size-28);
	line-height: var(--line-height-tight);
	letter-spacing: var(--letter-spacing-base);
	font-weight: 400;
	color: var(--color-text-secondary);
}

.product-line__cta-row {
	margin-top: var(--space-5);
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-5) var(--space-7);
}

/* Chevron-style CTAs.
 * `--primary` is a filled accent pill (Apple's "Buy" button), `--secondary`
 * is a text link with the same trailing › glyph used elsewhere on the site.
 * The chevron nudges right on hover, mirroring HOME-1's pattern. */
.product-line__cta {
	display: inline-flex;
	align-items: baseline;
	gap: var(--space-2);
	font-size: var(--font-size-18);
	font-weight: 400;
	letter-spacing: var(--letter-spacing-base);
	text-decoration: none;
	border-radius: var(--radius-control);
	transition:
		background-color var(--pl-duration) var(--pl-easing),
		color var(--pl-duration) var(--pl-easing),
		transform var(--pl-duration) var(--pl-easing);
}

/* Plain text, not a filled pill (owner 2026-08-31). The hero already
   carries the headline and the tagline; a solid block under them read as
   a third weight competing with both. It keeps a heavier cut than the
   secondary link beside it, which is enough to say which action comes
   first without drawing a box around it. */
.product-line__cta--primary {
	padding: var(--space-3) 0;
	color: var(--color-link);
	font-weight: 500;
}
.product-line__cta--primary:hover,
.product-line__cta--primary:focus-visible {
	color: var(--color-link-hover);
}

.product-line__cta--secondary {
	padding: var(--space-3) 0;
	color: var(--color-link);
}
/* Same as the variant link below: hover darkens and moves the chevron,
   the underline stays for keyboard focus only. */
.product-line__cta--secondary:hover {
	color: var(--color-link-hover);
}

/* No underline (owner 2026-09-04): a later rule already gives this CTA
   the theme's focus ring, and the underline on top of it was the last
   place in the chevron-CTA family that answered a state with a line
   instead of moving the arrow. */
.product-line__cta--secondary:focus-visible {
	color: var(--color-link-hover);
}

.product-line__cta-chevron {
	display: inline-block;
	font-weight: 400;
	transition: transform var(--pl-duration) var(--pl-easing);
}
.product-line__cta:hover .product-line__cta-chevron,
.product-line__cta:focus-visible .product-line__cta-chevron {
	transform: translateX(3px);
}

/* ============================================================
 * 2. HIGHLIGHTS
 * ============================================================ */
.product-line__highlights {
	padding-block: var(--pl-section-pad-y);
	padding-inline: var(--pl-side-padding);
	background: var(--color-bg-base);
}

.product-line__highlight-list {
	max-width: var(--pl-max-width);
	margin: 0 auto;
	padding: 0;
	list-style: none;
	display: grid;
	gap: var(--space-8);
	/* auto-fit collapses EMPTY tracks only, so at wide widths the column
	 * count is item-capped and the row fills evenly. Below that the 240px
	 * floor keeps dropping columns, and a grid start-aligns a partial
	 * last row, so three items in two tracks strand one flush LEFT. The
	 * quantity queries below own every width where that can happen. */
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* Orphan wraps, at EVERY width rather than one band (an earlier pass
 * only covered 834 to 1180 and the 2+1 came straight back at 640).
 * Three items hold one row while three tracks fit, then go to a single
 * column; they never render 2+1. Four items fold to a symmetric 2x2,
 * then to one column on phones. Browsers without :has() keep the old
 * start-aligned wrap, a degradation rather than a break. */
@media (max-width: 1180px) {
	.product-line__highlight-list:has(> li:first-child:nth-last-child(3)) {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.product-line__highlight-list:has(> li:first-child:nth-last-child(4)) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 833px) {
	.product-line__highlight-list:has(> li:first-child:nth-last-child(3)) {
		grid-template-columns: minmax(0, 1fr);
	}
}

@media (max-width: 640px) {
	.product-line__highlight-list:has(> li:first-child:nth-last-child(4)) {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* Centered, like the spec strip directly below it. Left-aligned content
 * inside tracks wider than the text left a ragged right edge, so the
 * row read as pushed to the left even when its gutters were equal. */
.product-line__highlight {
	text-align: center;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-3);
}

.product-line__highlight-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	border-radius: var(--radius-md);
	background: var(--color-bg-elevated);
	color: var(--color-link);
}

.product-line__highlight-title {
	margin: 0;
	font-size: var(--font-size-21);
	line-height: var(--line-height-tight);
	font-weight: 600;
	letter-spacing: var(--letter-spacing-base);
	color: var(--color-text-primary);
}

.product-line__highlight-subhead {
	margin: 0;
	font-size: var(--font-size-16);
	line-height: var(--line-height-base);
	color: var(--color-text-secondary);
}

/* ============================================================
 * 3. SPEC STRIP
 * Horizontal dt/dd row on the elevated grey background. Wraps on
 * narrow viewports so each pair stacks instead of overflowing.
 * ============================================================ */
.product-line__spec-strip {
	background: var(--pl-spec-bg);
	border-block: 1px solid var(--pl-spec-border);
	padding-block: var(--space-7);
	padding-inline: var(--pl-side-padding);
}

.product-line__spec-list {
	max-width: var(--pl-max-width);
	margin: 0 auto;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-6) var(--space-9);
}

.product-line__spec {
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	min-width: 140px;
	text-align: center;
}

.product-line__spec-label {
	font-size: var(--font-size-12);
	font-weight: 500;
	letter-spacing: var(--letter-spacing-wide);
	text-transform: uppercase;
	color: var(--color-text-muted);
}

.product-line__spec-value {
	margin: 0;
	font-size: var(--font-size-18);
	font-weight: 600;
	letter-spacing: var(--letter-spacing-base);
	color: var(--color-text-primary);
}

/* ============================================================
 * 4. VARIANT GRID
 * 3-column desktop grid, 2-column at intermediate widths, 1-column
 * under the mobile breakpoint. Cards have a gradient placeholder media
 * area until real product photography lands.
 * ============================================================ */
/* ---------------------------------------------------------------- *
 * 3b. EXPLAINER
 *
 * The layer between the spec strip and the model grid: what the
 * products are for, how they work, and how the variants differ.
 * Reading matter, so it takes the narrow measure the group intro
 * already uses (640px) rather than the full content width, and it
 * sits left instead of centred, because several paragraphs centred
 * on one axis are hard to follow.
 *
 * Blocks stack on one column up to 833px and split into two above,
 * which is where the line lengths stop fighting the measure.
 * ---------------------------------------------------------------- */

.product-line__explainer {
	padding-block: var(--pl-section-pad-y);
	padding-inline: var(--pl-side-padding);
	background: var(--color-bg-base);
	/* Untere Haarlinie, damit der Abschnitt nicht mit "Die Modelle"
	   darunter zu einer weissen Flaeche verschmilzt. Oben trennt schon
	   der Rahmen der Eckdatenleiste. */
	border-bottom: 1px solid var(--pl-spec-border);
}

/* Der sichtbare Abschnittstitel sitzt auf derselben Breite wie der
   Inhalt darunter, sonst steht er auf grossen Schirmen breiter als das,
   was er ueberschreibt. */
.product-line__explainer > .product-line__section-title {
	max-width: min(var(--pl-max-width), 1120px);
	margin-inline: auto;
}

/* Eine Spalte, seit 15.09.2026. Vorher waren es ab 834px zwei, und
   Bloecke mit Zeilenliste zogen sich per :has() ueber beide. Das ging
   auf, solange es Prosabloecke gab: inzwischen tragen vier von fuenf
   Bloecken Zeilen, der eine Prosablock stand halbbreit und daneben war
   ein 560px breites Loch. Die Mehrspaltigkeit liegt jetzt eine Ebene
   tiefer, in den Zeilen selbst (--grid weiter unten). Die Prosa bleibt
   auf ihrer Lesebreite von 640px, die setzen -lead und -text selbst. */
.product-line__explainer-inner {
	/* Schmaler als der Rest der Seite, und das mit Absicht: der Container
	   loest auf clamp(1200px, 70vw, 2560px) auf, und auf einem sehr breiten
	   Schirm stuenden dann eine 640px-Lesespalte und ein dreispaltiges
	   Zeilenraster in 2560px Flaeche verloren nebeneinander. 1120px haelt
	   Abschnittstitel, Prosa und Zeilen als eine Einheit zusammen. */
	max-width: min(var(--pl-max-width), 1120px);
	margin: 0 auto;
	display: grid;
	gap: var(--space-9);
}

.product-line__explainer-title {
	margin: 0 0 var(--space-3);
	font-family: var(--font-display);
	font-size: var(--font-size-28);
	font-weight: 600;
	letter-spacing: var(--letter-spacing-tight);
	line-height: var(--line-height-tight);
	color: var(--color-text-primary);
	text-wrap: balance;
}

.product-line__explainer-lead {
	margin: 0 0 var(--space-4);
	max-width: 640px;
	font-size: var(--font-size-18);
	line-height: var(--line-height-base);
	color: var(--color-text-primary);
}

.product-line__explainer-text {
	margin: 0 0 var(--space-4);
	max-width: 640px;
	font-size: var(--font-size-16);
	line-height: var(--line-height-base);
	color: var(--color-text-secondary);
}

.product-line__explainer-text:last-child {
	margin-bottom: 0;
}

/* One row per variant: the name carries the weight, the sentence says
   what it is for. Hairline between rows rather than a box, so the list
   stays reading matter and does not read as a card grid. */
.product-line__explainer-rows {
	margin: var(--space-6) 0 0;
	padding: 0;
	display: grid;
	gap: 0;
}

.product-line__explainer-row {
	display: grid;
	grid-template-columns: minmax(8rem, 14rem) minmax(0, 1fr);
	gap: var(--space-2) var(--space-6);
	padding-block: var(--space-4);
	border-top: 1px solid var(--color-border-hairline);
}

.product-line__explainer-row:last-child {
	border-bottom: 1px solid var(--color-border-hairline);
}

/* Ab drei Zeilen mehrspaltig, und dann Name ueber Text statt daneben.
   Grund: sechs Bauformen als sechs volle Bildschirmzeilen waren der
   Hauptteil der Textwand, die der Owner am 15.09.2026 beanstandet hat.
   Zweispaltig halbiert den Lauf, der Name wandert nach oben, weil in
   einer halben Spaltenbreite keine 14rem Namensspalte mehr hineinpasst.
   Der Hairline-Rahmen bleibt: die Zeilen sollen weiter wie Navigation
   lesen und nicht wie die Produktkarten weiter unten. */
@media (min-width: 834px) {
	.product-line__explainer-rows--grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: var(--space-8);
	}

	.product-line__explainer-rows--grid .product-line__explainer-row {
		display: flex;
		flex-direction: column;
		gap: var(--space-1);
	}

	/* Der Aktionslink wird auf die Unterkante geschoben, damit die
	   "Zum Shop"-Zeilen einer Rasterreihe auf einer Linie stehen, auch wenn
	   ein Text daneben eine Zeile mehr braucht. */
	.product-line__explainer-rows--grid .product-line__explainer-desc {
		flex: 1;
		display: flex;
		flex-direction: column;
	}

	.product-line__explainer-rows--grid .product-line__explainer-action {
		margin-top: auto;
		padding-top: var(--space-2);
	}

	/* Mit zwei Spalten traegt jede Zeile ihre eigene Oberkante; die
	   Sonderregel fuer die letzte Zeile ergaebe sonst einen Strich mitten
	   im Raster. Der Abschluss kommt stattdessen vom Container. */
	.product-line__explainer-rows--grid .product-line__explainer-row:last-child {
		border-bottom: 0;
	}

	.product-line__explainer-rows--grid {
		border-bottom: 1px solid var(--color-border-hairline);
	}
}

@media (min-width: 1280px) {
	.product-line__explainer-rows--grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* Der Aktionslink sagt, wohin es geht. Er steht in der Textzeile und
   nicht als eigene Spalte, damit das Raster bei drei Spalten nicht
   auseinanderfaellt. */
/* Der Aktionslink sagt, wohin es geht. Eigene Zeile unter dem Text,
   Breite nur so gross wie sein Inhalt, damit die Klickflaeche nicht
   ueber die ganze Spalte laeuft. Der Chevron wandert 4px, das ist der
   Theme-Standard (info.css, content.css). */
.product-line__explainer-action {
	display: flex;
	width: fit-content;
	align-items: center;
	gap: var(--space-1);
	margin-top: var(--space-2);
	font-size: var(--font-size-16);
	font-weight: 500;
	color: var(--color-accent);
	text-decoration: none;
}

.product-line__explainer-action:hover,
.product-line__explainer-action:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.product-line__explainer-chevron {
	display: inline-block;
	transition: transform var(--pl-duration) var(--pl-easing);
}

.product-line__explainer-action:hover .product-line__explainer-chevron,
.product-line__explainer-action:focus-visible .product-line__explainer-chevron {
	transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
	.product-line__explainer-chevron {
		transition: none;
	}
}

.product-line__explainer-name {
	margin: 0;
	font-size: var(--font-size-16);
	font-weight: 600;
	color: var(--color-text-primary);
}

.product-line__explainer-name a {
	color: inherit;
	text-decoration: none;
	border-bottom: 1px solid var(--color-border-hairline);
}

.product-line__explainer-name a:hover,
.product-line__explainer-name a:focus-visible {
	border-bottom-color: currentColor;
}

.product-line__explainer-desc {
	margin: 0;
	font-size: var(--font-size-16);
	line-height: var(--line-height-base);
	color: var(--color-text-secondary);
}

@media (max-width: 833px) {
	.product-line__explainer-row {
		grid-template-columns: minmax(0, 1fr);
	}
}

.product-line__variants {
	padding-block: var(--pl-section-pad-y);
	background: var(--color-bg-base);
}

.product-line__section-title {
	margin: 0 0 var(--space-8);
	font-family: var(--font-display);
	font-size: var(--font-size-40);
	line-height: var(--line-height-tight);
	letter-spacing: var(--letter-spacing-tight);
	font-weight: 600;
	color: var(--color-text-primary);
	text-align: center;
}

.product-line__variant-grid {
	margin: 0;
	padding: 0;
	list-style: none;
	display: grid;
	gap: var(--space-7);
	grid-template-columns: repeat(3, minmax(0, 1fr));
}

.product-line__variant {
	display: flex;
}

.product-line__variant-card {
	/* Anchor for the stretched variant link: the card presses like a button
	 * (:active below), so the WHOLE card must navigate, a press that promises
	 * a click and delivers nothing breaks the familiarity rule. The bottom
	 * link's ::after overlay covers the card (see .product-line__variant-link
	 * below); this positioning context is what it stretches against. */
	position: relative;
	flex: 1;
	display: flex;
	flex-direction: column;
	background: var(--pl-card-bg);
	border-radius: var(--pl-card-radius);
	overflow: hidden;
	box-shadow: var(--pl-card-shadow);
	transition:
		transform var(--pl-duration) var(--pl-easing),
		box-shadow var(--pl-duration) var(--pl-easing);
}
.product-line__variant-card:hover {
	transform: translateY(-3px);
	box-shadow: var(--pl-card-shadow-hover);
}

/* Gradient placeholder media, six variants keyed by the `gradient` field
 * on the config. Lets each card feel distinct until real imagery exists. */
.product-line__variant-media {
	aspect-ratio: var(--pl-card-media-aspect);
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--color-text-inverse);
	font-family: var(--font-display);
	font-size: var(--font-size-28);
	font-weight: 600;
	letter-spacing: var(--letter-spacing-base);
	text-align: center;
	padding: var(--space-5);
}
.product-line__variant-media--a { background: var(--emo-grad-a);  }
.product-line__variant-media--b { background: var(--emo-grad-b);  }
.product-line__variant-media--c { background: var(--emo-grad-c);  }
.product-line__variant-media--d { background: var(--emo-grad-d);  }
.product-line__variant-media--e { background: var(--emo-grad-e);  }
.product-line__variant-media--f { background: var(--emo-grad-f);  }

.product-line__variant-media-mark {
	display: inline-block;
	padding: var(--space-2) var(--space-4);
	background: rgba(255, 255, 255, 0.12);
	border-radius: var(--radius-sm);
	-webkit-backdrop-filter: blur(2px);
	backdrop-filter: blur(2px);
}

.product-line__variant-body {
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	padding: var(--space-6);
}

/* Werkzeugkarte auf /produkte/: dieselbe Karte ohne Medienflaeche. Ein
   Werkzeug hat kein Produktfoto, und der Karomarker fuer fehlende Fotos
   gehoert hier nicht hin. Etwas mehr Polster, damit die Karte ohne Bild
   nicht wie eine Karte mit fehlendem Bild aussieht. */
.product-line__variant-card--tool .product-line__variant-body {
	padding: var(--space-7);
	gap: var(--space-4);
}

.product-line__variant-name {
	margin: 0;
	font-size: var(--font-size-21);
	line-height: var(--line-height-tight);
	font-weight: 600;
	letter-spacing: var(--letter-spacing-base);
	color: var(--color-text-primary);
}

.product-line__variant-desc {
	margin: 0;
	flex: 1;
	font-size: var(--font-size-16);
	line-height: var(--line-height-base);
	color: var(--color-text-secondary);
}

.product-line__variant-link {
	display: inline-flex;
	align-items: baseline;
	gap: var(--space-2);
	margin-top: var(--space-2);
	color: var(--color-link);
	text-decoration: none;
	font-size: var(--font-size-16);
	font-weight: 400;
	transition: color var(--pl-duration) var(--pl-easing),
		opacity var(--pl-duration) var(--pl-easing);
}

/* Stretched link: an invisible overlay makes the entire card this anchor's
 * hit area, so the card-wide press state and the navigation agree. The card
 * is position: relative and contains no other interactive elements, nothing
 * gets shadowed. */
.product-line__variant-link::after {
	content: '';
	position: absolute;
	inset: 0;
}
/* No underline on hover (owner 2026-08-31). The pointer already gets two
   signals, the ink darkens and the chevron steps right, so the rule was
   a third one drawn across the label. Keyboard focus keeps it: an
   outline alone is easy to lose on a card full of links. */
.product-line__variant-link:hover {
	color: var(--color-link-hover);
}

/* Colour only; the underline came off with the CTAs' on 2026-09-04, a
   later rule already gives this link the theme's focus ring. */
.product-line__variant-link:focus-visible {
	color: var(--color-link-hover);
}

.product-line__variant-chevron {
	display: inline-block;
	transition: transform var(--pl-duration) var(--pl-easing);
}
.product-line__variant-link:hover .product-line__variant-chevron,
.product-line__variant-link:focus-visible .product-line__variant-chevron {
	transform: translateX(3px);
}

/* ============================================================
 * 5. CTA STRIPE
 * ============================================================ */
.product-line__cta-stripe {
	background: var(--pl-cta-stripe-bg);
	color: var(--pl-cta-stripe-fg);
	padding-block: var(--space-10);
	padding-inline: var(--pl-side-padding);
	text-align: center;
}

.product-line__cta-stripe-inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-5);
}

.product-line__cta-stripe-title {
	margin: 0;
	font-family: var(--font-display);
	font-size: var(--font-size-40);
	line-height: var(--line-height-tight);
	letter-spacing: var(--letter-spacing-tight);
	font-weight: 600;
	color: var(--pl-cta-stripe-fg);
	/* 24em, not a fixed 820px. This is a display headline, not running
	 * text, and the flat cap was a body measure: the German line needs
	 * 839px and broke 19px short of fitting, with 1135px of stripe going
	 * spare. In em it scales with the type step instead of fighting it,
	 * and balance splits the lines evenly on the widths where a longer
	 * headline genuinely has to wrap. */
	max-width: 24em;
	text-wrap: balance;
}

.product-line__cta-stripe-link {
	display: inline-flex;
	align-items: baseline;
	gap: var(--space-3);
	color: var(--pl-cta-stripe-fg);
	text-decoration: none;
	font-size: var(--font-size-21);
	font-weight: 400;
	letter-spacing: var(--letter-spacing-base);
	border-bottom: 1px solid color-mix(in srgb, var(--pl-cta-stripe-fg) 40%, transparent);
	padding-bottom: var(--space-1);
	transition:
		border-color var(--pl-duration) var(--pl-easing),
		opacity var(--pl-duration) var(--pl-easing);
}
.product-line__cta-stripe-link:hover,
.product-line__cta-stripe-link:focus-visible {
	border-color: var(--pl-cta-stripe-fg);
	opacity: 0.92;
}

.product-line__cta-stripe-arrow {
	display: inline-block;
	font-size: var(--font-size-28);
	transition: transform var(--pl-duration) var(--pl-easing);
}
.product-line__cta-stripe-link:hover .product-line__cta-stripe-arrow,
.product-line__cta-stripe-link:focus-visible .product-line__cta-stripe-arrow {
	transform: translateX(4px);
}

/* ============================================================
 * Press feedback, pointer-down response under 100ms (spec 1).
 * The press duration lives inside :active so the press snaps
 * while the release eases back through the base transition.
 * ============================================================ */
.product-line__cta:active {
	transform: scale(0.97);
	transition-duration: var(--motion-duration-press);
}

/* The press is an opacity step, not a fill. This darkened the pill's
 * background back when the CTA was a filled pill; once it became plain
 * text the rule had nothing to darken but still painted, so every click
 * flashed a dark green box behind the label. */
.product-line__cta--primary:active {
	opacity: 0.55;
}

.product-line__variant-card:active {
	transform: scale(0.985);
	transition-duration: var(--motion-duration-press);
}

.product-line__variant-link:active,
.product-line__cta-stripe-link:active {
	opacity: 0.55;
	transition-duration: var(--motion-duration-press);
}

/* ============================================================
 * Responsive ladder:
 *   1024px : variant cards 3 -> 2, matching the shop archive grid,
 *            which shows the same kind of product card at the same
 *            width (shop.css)
 *    833px : hero and section type drop one step, the variant grid
 *            deliberately STAYS 2-up
 *    640px : phone, variant grid goes single column
 * ============================================================ */
@media (max-width: 1024px) {
	.product-line__variant-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 833px) {
	.product-line__hero {
		padding-block: var(--pl-hero-pad-y-mobile);
	}

	.product-line__title {
		font-size: var(--font-size-40);
	}

	.product-line__tagline {
		font-size: var(--font-size-21);
	}

	.product-line__highlights,
	.product-line__variants,
	.product-line__explainer,
	.product-line__lines {
		padding-block: var(--pl-section-pad-y-mobile);
	}

	.product-line__section-title,
	.product-line__cta-stripe-title,
	.product-line__banner-heading {
		font-size: var(--font-size-28);
	}

	.product-line__banner-claim {
		font-size: var(--font-size-18);
	}

	/* Die drei Baender ruecken zusammen, sonst steht auf dem Telefon mehr
	   Luft zwischen ihnen als Inhalt in ihnen. */
	.product-line__lines-inner {
		gap: var(--space-6);
	}

	/* Variant grid: tighter gutter, still two columns. */
	.product-line__variant-grid {
		gap: var(--space-6);
	}

	/* Spec strip: stack vertically, flex-wrap was already on, but the
	 * 9-unit horizontal gap was dominating; tighten and let each spec
	 * span its own row. */
	.product-line__spec-list {
		flex-direction: column;
		align-items: stretch;
		gap: var(--space-4);
	}
	.product-line__spec {
		min-width: 0;
	}

	.product-line__cta-row {
		gap: var(--space-4);
		flex-direction: column;
		align-items: stretch;
	}
	.product-line__cta {
		justify-content: center;
	}
}

/* Phone, 640px. Declared AFTER the 1024px block so the narrower query
   wins on source order at equal specificity. */
@media (max-width: 640px) {
	.product-line__variant-grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* Honor the user's reduced-motion preference. */
@media (prefers-reduced-motion: reduce) {
	.product-line__cta,
	.product-line__cta-chevron,
	.product-line__variant-card,
	.product-line__variant-link,
	.product-line__variant-chevron,
	.product-line__cta-stripe-link,
	.product-line__cta-stripe-arrow {
		transition: none;
	}
	.product-line__variant-card:hover {
		transform: none;
	}

	/* Transforms are stripped; keep the press readable as a
	   background/opacity shift instead (spec 7 keeps feedback). */
	.product-line__cta:active,
	.product-line__variant-card:active {
		transform: none;
	}

	/* Both CTAs, not just the secondary: they are the same kind of
	   control now, so the press reads the same way with motion off. */
	.product-line__cta:active {
		opacity: 0.55;
	}

	.product-line__variant-card:active {
		background: var(--grey-100);
	}
}

/* ---- a11y: explicit focus rings on CTAs --------------------------------
 * The hover/focus rules above only color-shift the buttons; keyboard users
 * also need a discrete outline. Mirrors the navbar's contract (2px solid
 * --color-link, offset). The CTA stripe link sits on a deep neutral
 * background, so its outline uses the inverse text color for contrast.
 * The variant card itself becomes the focus surface for its inner link
 * (focus-within) so the whole card lights up, same affordance as hover. */
.product-line__cta--primary:focus-visible,
.product-line__cta--secondary:focus-visible,
.product-line__variant-link:focus-visible {
	outline: 2px solid var(--color-link);
	outline-offset: 4px;
	border-radius: var(--radius-sm);
}

.product-line__cta-stripe-link:focus-visible {
	outline: 2px solid var(--pl-cta-stripe-fg);
	outline-offset: 4px;
	border-radius: var(--radius-sm);
}

.product-line__variant-card:focus-within {
	box-shadow: var(--pl-card-shadow-hover);
}

/* ============================================================
 * Variant groups + real product cards (photo, price, badge).
 * Added for the family-grouped line pages; gradient placeholder
 * cards keep working unchanged.
 * ============================================================ */

.product-line__variant-group + .product-line__variant-group {
	margin-top: var(--space-11, 96px);
}

.product-line__group-intro {
	margin: calc(-1 * var(--space-4)) auto var(--space-7);
	max-width: 640px;
	text-align: center;
	font-size: var(--font-size-18);
	line-height: var(--line-height-base);
	color: var(--color-text-secondary);
}

.product-line__variant-media--photo {
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--color-bg-base);
	border-bottom: 1px solid var(--color-border-hairline);
}

.product-line__variant-img {
	max-width: 72%;
	max-height: 78%;
	object-fit: contain;
}

.product-line__variant-media {
	position: relative;
}

.product-line__variant-badge {
	position: absolute;
	top: var(--space-4);
	left: var(--space-4);
	padding: 5px 12px;
	border-radius: calc(var(--pl-card-radius) - var(--space-4)) var(--radius-chip) var(--radius-chip) var(--radius-chip);  /* shared top-left corner is concentric with the card */
	background: var(--color-cta);
	color: var(--color-cta-ink);
	font-size: var(--font-size-12);
	font-weight: 700;
	letter-spacing: var(--letter-spacing-wide);
	text-transform: uppercase;
}

.product-line__variant-price {
	margin: calc(-1 * var(--space-2)) 0 var(--space-4);
	font-size: var(--font-size-16);
	font-weight: 600;
	color: var(--color-text-primary);
}

/* ============================================================
 * Material fallbacks for the translucent media chip (spec 5).
 * Dark fills keep the white label readable on every gradient.
 * ============================================================ */

@media (prefers-reduced-transparency: reduce) {
	.product-line__variant-media-mark {
		background: rgba(0, 0, 0, 0.45);
		-webkit-backdrop-filter: none;
		backdrop-filter: none;
	}
}

@media (prefers-contrast: more) {
	.product-line__variant-media-mark {
		background: rgba(0, 0, 0, 0.7);
		-webkit-backdrop-filter: none;
		backdrop-filter: none;
		border: 1px solid var(--color-text-inverse);
	}
}

/* ============================================================
 * Variant banner
 *
 * A model family that ships as ONE product gets a splash band
 * instead of a card grid (emoswitch blue: only the dual pedal
 * exists). The layout mirrors .esb-hero in emoswitch-blue.css so
 * a reader who follows the link recognises the same product on
 * the landing page. That stylesheet is NOT loaded here, so the
 * accent lives in local --pl-banner-* values on the modifier.
 * ============================================================ */

.product-line__banner {
	display: grid;
	grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
	gap: var(--space-7);
	align-items: center;
	padding: var(--space-9) var(--space-8);
	border-radius: var(--pl-card-radius);
	background: var(--pl-banner-bg, var(--emo-grad-wash));
	/* The render is wider than its column and bleeds toward the edge;
	 * clip so that never becomes horizontal page scroll. */
	overflow: clip;
}

/* emoswitch blue: the landing page's own palette (--esb-accent /
 * --esb-tint) and hero wash, restated locally. The badge tint is the
 * plain #155dfc accent at 10%; type never uses it undiluted, see the
 * contrast note on the CTAs. */
.product-line__banner--blue {
	--pl-banner-accent-deep: #0f45c4;
	--pl-banner-bg: linear-gradient(115deg, #e4e9ff 0%, #eaf1ff 42%, #f4f9ff 100%);
	--pl-banner-badge-bg: rgb(21 93 252 / 0.1);
}

/* ---------------------------------------------------------------- *
 * 3a. Sternprodukt
 *
 * Eigene Sektion zwischen Eckdatenleiste und Ueberblick. Sie traegt den
 * Verlauf des Banners, damit das wichtigste Produkt der Linie sich vom
 * weissen Grund der Nachbarabschnitte abhebt, und sie hat weniger
 * Polsterung als eine volle Sektion: darueber schliesst die Eckdatenleiste
 * mit ihrer Haarlinie ab, darunter faengt der Ueberblick mit seiner
 * eigenen Polsterung an.
 * ---------------------------------------------------------------- */
.product-line__feature {
	padding-block: var(--space-9);
	padding-inline: var(--pl-side-padding);
	background: var(--color-bg-base);
}

.product-line__feature-inner {
	max-width: var(--pl-max-width);
	margin-inline: auto;
}

/* Hoehendeckel fuer das Produktbild.
   Owner 15.09.2026: "the star showcase should be as thin as the emo blue
   card, the others are too thick". Der blue-Render ist querformatig
   (824x472) und ergibt eine 449px hohe Karte; die beiden Produktfotos waren
   quadratisch (600x600) und ergaben 647px. Beide sind jetzt freigestellt
   und auf das Motiv beschnitten, damit auch querformatig. Der Deckel faengt
   den Rest ab: er greift erst oberhalb der Hoehe, die der blue-Render von
   sich aus hat, der bleibt also unveraendert.

   Freigestellt heisst wirklich freigestellt: die Originale sind
   Palette-PNG mit eingebranntem weissem Grund. Die Fassungen unter
   *-freigestellt.png sind mit PIL erzeugt, Hintergrund von den vier Ecken
   aus geflutet (weisse Flaechen im Produkt bleiben dadurch stehen), Saum
   in zwei Durchgaengen abgebaut, dann auf die Alphakante beschnitten. */
.product-line__feature .product-line__banner-img {
	/* 325px, nicht rund gegriffen: der blue-Render ergibt in seiner Spalte
	   von sich aus 321px. Der Deckel liegt knapp darueber, greift also nur
	   bei Bildern, die hoeher kaemen. Alle drei Karten landen damit auf 447
	   bis 453px, vorher waren zwei davon 647px. */
	max-height: 325px;
	object-fit: contain;
}

@media (max-width: 833px) {
	.product-line__feature {
		padding-block: var(--space-7);
	}
}

/* ---------------------------------------------------------------- *
 * Linienbaender auf /produkte/
 *
 * Dasselbe Bauteil wie der emoswitch-blue-Banner, nur ohne Wortmarke
 * und ohne Verlauf: drei davon untereinander auf --emo-grad-wash waeren
 * drei grosse gruene Flaechen. Stattdessen der Kartengrund, den auch die
 * Modellkarten tragen, damit die drei Baender als drei gleichwertige
 * Einheiten lesen. Gitter, Bildbehandlung und der Umbruch auf eine
 * Spalte kommen unveraendert von .product-line__banner.
 * ---------------------------------------------------------------- */
.product-line__lines {
	padding-block: var(--pl-section-pad-y);
	padding-inline: var(--pl-side-padding);
}

.product-line__lines-inner {
	max-width: var(--pl-max-width);
	margin-inline: auto;
	display: flex;
	flex-direction: column;
	gap: var(--space-7);
}

.product-line__banner--line {
	--pl-banner-bg: var(--pl-card-bg);
	border: 1px solid var(--pl-spec-border);
	box-shadow: var(--pl-card-shadow);
}

/* Medienflaeche der Linienbaender.
   Seit 15.09.2026 sind auch die drei Gruppenaufnahmen freigestellt, die
   weisse Platte ist damit entfallen. Was bleibt, ist ein festes
   Seitenverhaeltnis: die drei Bilder haben verschiedene Formate (693x389,
   701x269, 659x371), und ohne festen Kasten waeren die drei Baender
   untereinander verschieden hoch. Das Bild sitzt darin zentriert und
   laeuft nicht ueber, ein Gruppenbild braucht den Bleed nicht. */
.product-line__banner--line .product-line__banner-media {
	aspect-ratio: 16 / 10;
	display: grid;
	place-items: center;
}

.product-line__banner--line .product-line__banner-img {
	width: auto;
	height: auto;
	max-width: 100%;
	max-height: 100%;
	margin-inline: auto;
}

/* h3, nicht h2: die Abschnitts-h2 steht darueber (visuell verborgen),
   die Gliederung bleibt damit h1 > h2 > h3. Die Groesse ist die der
   Abschnittstitel, nur linksbuendig. */
.product-line__banner-heading {
	margin: var(--space-2) 0 var(--space-3);
	font-family: var(--font-display);
	font-size: var(--font-size-40);
	font-weight: 600;
	line-height: var(--line-height-tight);
	letter-spacing: var(--letter-spacing-tight);
	color: var(--color-text-primary);
	text-wrap: balance;
}

/* Die Anspruchszeile der Linie, in der Hausform: Nominalgruppen mit
   Punkt. Sie traegt mehr Gewicht als der Satz darunter. */
.product-line__banner-claim {
	margin: 0 0 var(--space-3);
	max-width: 34ch;
	font-size: var(--font-size-21);
	line-height: var(--line-height-tight);
	color: var(--color-text-primary);
	text-wrap: balance;
}

.product-line__banner-copy {
	min-width: 0;
}

.product-line__banner-badge {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	margin: 0 0 var(--space-4);
	padding: var(--space-1) var(--space-3);
	border-radius: var(--radius-control);
	background: var(--pl-banner-badge-bg, rgb(0 0 0 / 0.06));
	/* Deep accent: the plain accent on this wash is 4.2:1, under the AA
	 * floor for the badge's small semibold text. Same call as
	 * .esb-hero__badge. */
	color: var(--pl-banner-accent-deep, var(--color-text-primary));
	font-size: var(--font-size-14);
	font-weight: 600;
}

.product-line__banner-badge-icon svg {
	display: block;
	width: 16px;
	height: 16px;
}

/* Wordmark as styled text, the same reading as the landing hero:
 * the product name in ink, the accent word white on the rounded
 * teal-to-blue gradient chip. Stops sampled from the live logo. */
.product-line__banner-title {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.22em;
	margin: 0 0 var(--space-4);
	font-family: var(--font-sans);
	font-size: clamp(2.2rem, 4vw, 3.4rem);
	font-weight: 500;
	letter-spacing: -0.04em;
	line-height: 1.15;
	color: var(--color-text-primary);
	text-align: left;
}

.product-line__banner-mark {
	padding: 0 0.18em 0.05em;
	border-radius: 0.16em;
	color: var(--color-text-inverse);
	background:
		linear-gradient(180deg, rgb(255 255 255 / 0.5) 0%, rgb(255 255 255 / 0) 55%),
		linear-gradient(101deg, #4fd6d4 0%, #12b0c8 38%, #3f89d8 72%, #5278e1 100%);
}

.product-line__banner-text {
	margin: 0 0 var(--space-5);
	max-width: 46ch;
	font-size: var(--font-size-18);
	line-height: var(--line-height-base);
	color: var(--color-text-secondary);
}

.product-line__banner-cta-row {
	margin: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-3) var(--space-6);
}

/* inline-block, NOT inline-flex: a label long enough to wrap (a longer
   translation, a narrow phone) would, as a flex item, pin the chevron
   to the first line and strand the rest under it. Inline flow puts the
   chevron after the last word wherever that falls. */
.product-line__banner-cta {
	display: inline-block;
	font-size: var(--font-size-16);
	letter-spacing: var(--letter-spacing-base);
	text-decoration: none;
	transition: color var(--pl-duration) var(--pl-easing);
}

/* Both CTAs are plain text, not filled pills (owner 2026-09-04), the
 * same call the hero CTAs took on 2026-08-31: the band already carries
 * the wordmark, the tagline and the render, and a solid block under
 * them read as a fourth weight competing with all three. The primary
 * keeps a heavier cut than the link beside it, which is enough to say
 * which action comes first without drawing a box around it.
 *
 * Both sit on --pl-banner-accent-deep, ~7:1 on the wash; the plain
 * accent is 4.2:1, under the AA floor for this size. Hover darkens
 * from there, so the interactive state never drops below the resting
 * one (the mix idiom is content.css's). */
.product-line__banner-cta--primary {
	padding: var(--space-3) 0;
	color: var(--pl-banner-accent-deep, var(--color-link));
	font-weight: 600;
}

.product-line__banner-cta--secondary {
	padding: var(--space-3) 0;
	color: var(--pl-banner-accent-deep, var(--color-link));
	font-weight: 500;
}

.product-line__banner-cta:hover,
.product-line__banner-cta:focus-visible {
	color: color-mix(in srgb, var(--pl-banner-accent-deep, var(--color-link)) 82%, #000);
}

/* Focus ring, not an underline: the same affordance the hero CTAs and
   the rest of the theme's chevron links use. */
.product-line__banner-cta:focus-visible {
	outline: 2px solid var(--pl-banner-accent-deep, var(--color-link));
	outline-offset: 4px;
	border-radius: var(--radius-sm);
}

.product-line__banner-chevron {
	display: inline-block;
	margin-inline-start: var(--space-2);
	transition: transform var(--pl-duration) var(--pl-easing);
}

.product-line__banner-cta:hover .product-line__banner-chevron,
.product-line__banner-cta:focus-visible .product-line__banner-chevron {
	transform: translateX(3px);
}

.product-line__banner-media {
	margin: 0;
	/* Let the render overflow its grid cell rather than being boxed by it. */
	min-width: 0;
}

.product-line__banner-img {
	display: block;
	/* Sized as a share of its column, not to a fixed pixel cap, so the
	 * product scales with the band instead of shrinking to a thumbnail
	 * on wide screens. Same call as .esb-hero__media img. */
	width: 108%;
	max-width: 108%;
	height: auto;
	margin-inline-start: auto;
}

@media (max-width: 833px) {
	.product-line__banner {
		grid-template-columns: minmax(0, 1fr);
		padding: var(--space-7) var(--space-6);
		text-align: center;
	}

	/* Render first: it identifies the product faster than the wordmark. */
	.product-line__banner-media {
		order: -1;
	}

	/* One column: no bleed, or the band's clip would crop the product. */
	.product-line__banner-img {
		width: 100%;
		max-width: 100%;
		margin-inline: auto;
	}

	.product-line__banner-title,
	.product-line__banner-cta-row {
		justify-content: center;
	}

	.product-line__banner-text {
		margin-inline: auto;
	}
}

@media (max-width: 480px) {
	/* Two text links side by side read as one wrapped sentence at this
	   width; stack them, each no wider than its own label. */
	.product-line__banner-cta-row {
		flex-direction: column;
		align-items: center;
	}
}

@media (prefers-reduced-motion: reduce) {
	.product-line__banner-cta,
	.product-line__banner-chevron {
		transition: none;
	}
}
