/*
 * Exostruct – Komponenten
 *
 * Nur Bausteine, die tatsächlich mehrfach vorkommen. Jede Komponente muss die
 * Abnahmekriterien aus docs/design-system.md §8 erfüllen: Kontrast,
 * Tastaturbedienung, mobile Darstellung, lange Texte, Fehler-, Lade- und
 * Leerzustand, ausschließlich Tokens.
 */

/* ------------------------------------------------------------------
 * Sprungmarke
 * WordPress erzeugt den Link und seine visuell versteckte Grundstellung. Das
 * Theme gestaltet nur den Fokuszustand, damit es genau ein erstes Tastaturziel
 * gibt und kein zweiter Link Platz vor dem Kopfbereich beansprucht.
 * ------------------------------------------------------------------ */
#wp-skip-link:focus {
	inset-block-start: var(--wp--preset--spacing--20);
	inset-inline-start: var(--wp--preset--spacing--20);
	z-index: 100;
	min-block-size: var(--touch-target);
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--50);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-weight: 600;
	line-height: var(--line-height-ui);
	text-decoration: none;
	border-radius: var(--radius-sm);
}

/* Die Core-Grundregel setzt am versteckten Link `outline: none`. */
#wp-skip-link:focus-visible {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

/* ------------------------------------------------------------------
 * Kopfbereich
 * ------------------------------------------------------------------ */
/*
 * Kopfbereich und Hero sind eine einzige Fläche, keine zwei aneinander
 * gesetzten. Die frühere Trennlinie dazwischen hat genau das behauptet, was
 * die Einstiegszone nicht sein soll. Über hellem Inhalt trennt sich der
 * dunkle Kopfbereich beim Scrollen von selbst; dafür braucht es keine Kante.
 */
.exo-header {
	position: sticky;
	inset-block-start: 0;
	z-index: 20;
	padding-block: 0;
	background-color: var(--color-surface-stage);
	box-shadow: none;

	/* Dunkle Fläche, deshalb dieselbe Umschaltung wie in dunklen Abschnitten. */
	--color-focus: var(--wp--preset--color--brand-500);
}

/*
 * Auf Unterseiten trägt der äußere Template-Part das Sticky-Verhalten.
 *
 * `.exo-header` selbst liegt eine Ebene tiefer in einem `header`-Element, das
 * exakt seine eigene Höhe hat. Ein Sticky-Kind darf den Rand seines
 * Containing Blocks nicht verlassen und scrollte deshalb trotz
 * `position: sticky` sofort mit diesem Wrapper aus dem Viewport. Der äußere
 * Header bleibt dagegen im normalen Dokumentfluss und überdeckt keinen Inhalt.
 */
body:not([class~="home"]) .wp-site-blocks > header.wp-block-template-part {
	position: sticky;
	inset-block-start: 0;
	z-index: 20;
}

body:not([class~="home"]) .exo-header {
	position: static;
}

.exo-header__brand img {
	block-size: auto;
	inline-size: clamp(8.75rem, 14vw, 11rem);
}

/*
 * Wortmarke.
 *
 * Die Vektorfassung kommt aus dem Theme, nicht aus der Mediathek – WordPress
 * lässt SVG-Uploads nicht zu. Ausgeliefert über patterns/brand-logo.php.
 *
 * Breite über clamp() statt fester Pixelwerte: Die Marke soll auf schmalen
 * Geräten nicht die Navigation verdrängen. Brand Identity §9.1 nennt 140 px
 * als Mindestbreite – der untere Wert liegt bewusst darüber.
 */
.exo-brand {
	display: inline-flex;
	align-items: center;
	/* Schutzraum nach §9.1: mindestens die halbe Logohöhe. */
	padding-block: var(--wp--preset--spacing--20);
}

.exo-brand__mark {
	inline-size: clamp(9.5rem, 16vw, 11.5rem);
	block-size: auto;
}

.exo-footer__brand .exo-brand__mark {
	inline-size: clamp(9rem, 14vw, 10.5rem);
	margin-block-end: var(--wp--preset--spacing--40);
}

/*
 * Im erzwungenen Farbmodus entfernt der Browser Bildfarben nicht, ersetzt
 * aber Hintergründe. Die Wortmarke bleibt dadurch sichtbar; ein zusätzlicher
 * Rahmen wäre störend.
 */
@media (forced-colors: active) {
	.exo-brand__mark {
		forced-color-adjust: none;
	}
}

/* ------------------------------------------------------------------
 * Navigation
 * Der Kern-Navigationsblock bringt Auszeichnung und Tastaturführung mit.
 * Hier nur Gestaltung – keine Nachbildung vorhandener Funktion.
 * ------------------------------------------------------------------ */
.exo-nav :where(.wp-block-navigation-item__content) {
	color: var(--color-text-on-dark);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 500;
	text-decoration: none;
	padding-block: var(--wp--preset--spacing--20);
}

.exo-nav :where(.wp-block-navigation-item__content):hover {
	color: var(--color-text);
	text-decoration: underline;
	text-underline-offset: 0.4em;
	text-decoration-thickness: 2px;
	text-decoration-color: var(--color-brand);
}

/* Aktueller Menüpunkt wird nicht nur farblich markiert. */
.exo-nav :where(.current-menu-item > .wp-block-navigation-item__content) {
	text-decoration: underline;
	text-underline-offset: 0.4em;
	text-decoration-thickness: 2px;
	text-decoration-color: var(--color-brand);
}

/* ------------------------------------------------------------------
 * Karte
 *
 * Ohne feste Höhe: In einem Raster sorgt `align-items: stretch` – die Vorgabe –
 * ohnehin für gleich hohe Karten. Ein zusätzliches `block-size: 100%` wirkte
 * dagegen auch dort, wo zwei Karten untereinander in derselben Spalte stehen:
 * Beide beanspruchten die volle Spaltenhöhe, und die zweite lief nach unten
 * heraus. Gemessen auf der Startseite an der DLP/SLA-Karte.
 * ------------------------------------------------------------------ */
.exo-card {
	container-type: inline-size;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--40);
	padding: var(--wp--preset--spacing--50);
	background-color: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	transition: border-color var(--duration-normal) var(--easing-standard),
		box-shadow var(--duration-normal) var(--easing-standard);
}

/* Hebt die Karte, wenn irgendwo darin der Fokus liegt oder gehovert wird. */
/*
 * Ohne diese Zeile stehen alle Kartenüberschriften mittig, der Fließtext
 * darunter linksbündig.
 *
 * Grund: Die Karten sind Gruppen mit `layout: constrained`. WordPress setzt
 * darauf `margin-left: auto !important; margin-right: auto !important` - in
 * einem Blockfluss harmlos, denn ein Block nimmt ohnehin die volle Breite. Die
 * Karte ist aber ein Flex-Container, und dort gewinnen auto-Ränder gegen
 * `align-items: stretch`: Jedes Kind schrumpft auf seine Inhaltsbreite und
 * rückt in die Mitte. Bei einem Absatz fällt es nicht auf, weil der Text
 * umbricht und die volle Breite füllt; bei einer kurzen Überschrift wie
 * „3D-Druck" schon.
 *
 * `!important` ist hier nicht zu vermeiden - die Vorgabe kommt selbst mit
 * `!important` und liegt in unlayered CSS, das nicht überschrieben würde.
 */
/*
 * Zusätzlich zu den seitlichen Rändern werden auch die senkrechten aufgehoben.
 *
 * Das Fließlayout gibt jedem Kind außer dem ersten einen oberen Rand von 24 px.
 * In einem Flex-Container addiert der sich auf die eigene Lücke der Karte: Auf
 * der Startseite lagen zwischen Bild und Titel der Verfahrenskarten dadurch
 * 51 px, zwischen Titel und Text 35 px, während die Polsterung 24 px vorsah -
 * drei verschiedene Abstände in einer einzigen Karte. Die Karte gliedert sich
 * jetzt ausschließlich über ihre Lücke (R1).
 *
 * Dieselbe Aufhebung gilt für alle Komponenten, die ihre Kinder selbst mit
 * `gap` gliedern. Sie stehen bewusst in einer gemeinsamen Regel: Wären es
 * sieben einzelne, würde eine achte Komponente sie erfahrungsgemäß vergessen -
 * genau so entstand der Versatz, der in AP-17 dreimal einzeln repariert wurde.
 *
 * `!important` ist nicht zu vermeiden: Die Vorgabe kommt aus einer generierten
 * Containerklasse mit zwei Klassen (0,2,0), gegen die keine Themeregel mit
 * vertretbarer Spezifität ankommt.
 */
.exo-card > *,
.exo-path > *,
.exo-service > *,
.exo-step > *,
.exo-scope > *,
.exo-spec > *,
.exo-limit > *,
.exo-hero__copy > *,
.exo-section-heading > *,
.exo-advantages > .wp-block-group > * {
	margin: 0 !important;
}

.exo-card:hover,
.exo-card:focus-within {
	border-color: var(--color-border-strong);
	box-shadow: var(--shadow-md);
}

.exo-card__media {
	aspect-ratio: 3 / 2;
	object-fit: cover;
	inline-size: 100%;
	border-radius: var(--radius-sm);
}

.exo-card__title {
	font-size: var(--wp--preset--font-size--xl);
	line-height: var(--line-height-ui);
}

/*
 * `flex-grow` statt eines automatischen Randes: Der Rand wird von der Regel
 * oben mit `!important` aufgehoben, und ein zweites `!important` an derselben
 * Komponente wäre nicht mehr nachvollziehbar. Der wachsende Textblock schiebt
 * ein folgendes Ziel genauso zuverlässig an den Fuß der Karte.
 */
.exo-card__text {
	flex-grow: 1;
	color: var(--color-text-secondary);
}

/*
 * Die ganze Karte ist klickbar, der Link bleibt aber ein echter Link im
 * Fokus-Fluss. Kein JavaScript, kein Verlust von "Link in neuem Tab".
 */
.exo-card__link::after {
	content: "";
	position: absolute;
	inset: 0;
}

.exo-card:has(.exo-card__link) {
	position: relative;
}

/* ------------------------------------------------------------------
 * Karte mit Bild
 * Das Bild sitzt bündig an der Oberkante, der Text behält seinen Innenabstand.
 * Ein Foto mit umlaufendem Rand wirkt wie versehentlich eingefügt.
 * ------------------------------------------------------------------ */
.exo-card--medien {
	padding-block-start: 0;
	padding-inline: 0;
	overflow: hidden;
}

.exo-card--medien > .wp-block-post-featured-image img {
	border-start-start-radius: var(--radius-md);
	border-start-end-radius: var(--radius-md);
	border-end-start-radius: 0;
	border-end-end-radius: 0;
}

.exo-card--medien > :not(.wp-block-post-featured-image) {
	padding-inline: var(--wp--preset--spacing--50);
}

.exo-card--medien > :last-child {
	padding-block-end: var(--wp--preset--spacing--50);
}

/*
 * Der Kartentitel ist ein Link und käme sonst in Linkblau. Auf einer Karte, die
 * als Ganzes zum Verfahren führt, liest sich das wie ein zweites, abweichendes
 * Ziel - er bleibt deshalb in Textfarbe und zeigt erst beim Überfahren, dass er
 * anklickbar ist.
 */
.exo-card--medien .wp-block-post-title a {
	color: var(--color-text-primary);
	text-decoration: none;
}

.exo-card--medien .wp-block-post-title a:hover,
.exo-card--medien .wp-block-post-title a:focus-visible {
	text-decoration: underline;
}

/* ------------------------------------------------------------------
 * Kompakter Verfahrensvergleich und Materialauswahl
 *
 * Die Startseite ordnet ein und verlinkt; Bilder und vollständige Kennwerte
 * bleiben den Archiven und Detailseiten vorbehalten. Dadurch entsteht keine
 * zweite Galerie mit denselben Aufgaben wie die Fachseiten.
 * ------------------------------------------------------------------ */
/*
 * Verfahren als Flächen, Werkstoffe als Marken.
 *
 * Vorher trug beides dieselbe Gliederung: eine obere Haarlinie, darunter
 * Zeilen. Die zwei Verfahren mit je drei Sätzen und die sieben Werkstoffe mit
 * je einem Wort sind aber nicht dieselbe Art von Inhalt. In einem
 * vierspaltigen Zeilenraster stand hinter jedem Werkstoffnamen ein Pfeil am
 * rechten Spaltenrand - bei „PP" mit acht Leerzeichen Abstand, bei
 * „PA12+CF15" mit keinem. Getrennte Formen lösen das: die Verfahren als
 * lesbare Karten, die Werkstoffe als kompakte Ziele in Textbreite.
 */
.exo-process-comparison {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	list-style: none;
	margin: 0;
	padding: 0;
}

.exo-process-comparison > li {
	margin-block: 0;
}

/*
 * Die Karte führt das Verfahren mit Aufnahme, Namen und Kurzbeschreibung.
 *
 * Das Bild sitzt bündig in der Karte statt innerhalb der Polsterung: Es ist
 * die Fläche, an der das Verfahren wiedererkannt wird, und trägt die Karte
 * nach oben ab. `overflow: clip` hält es an der Rundung.
 */
.exo-process-summary {
	display: grid;
	align-content: start;
	gap: var(--wp--preset--spacing--30);
	block-size: 100%;
	padding: 0 var(--wp--preset--spacing--50) var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface);
	overflow: clip;
	transition: border-color var(--duration-fast) var(--easing-standard);
}

/*
 * Der Ausbruch aus der seitlichen Polsterung ist Absicht: Die Karte polstert
 * ihren Text, das Bild soll aber bis an die Kante laufen. Ein eigener
 * Polsterwert am Text hätte dieselbe Wirkung, aber vier Stellen statt einer.
 */
.exo-process-summary__image {
	margin-inline: calc(-1 * var(--wp--preset--spacing--50));
	margin-block-end: var(--wp--preset--spacing--20);
}

.exo-process-summary__image img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	border-radius: 0;
}

.exo-process-summary:hover,
.exo-process-summary:focus-within {
	border-color: var(--color-border-strong);
}

.exo-process-summary__title,
.exo-process-summary__text,
.exo-process-summary__text .wp-block-post-excerpt__excerpt,
.exo-material-list .wp-block-post-title {
	margin: 0;
}

.exo-process-summary__title a,
.exo-material-list .wp-block-post-title a {
	color: var(--color-text-primary);
	text-decoration: none;
}

.exo-process-summary__title a:hover,
.exo-process-summary__title a:focus-visible,
.exo-material-list .wp-block-post-title a:hover,
.exo-material-list .wp-block-post-title a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.3em;
}

.exo-process-summary__text {
	max-inline-size: 54ch;
	color: var(--color-text-secondary);
}

/*
 * Werkstoffe sind Ziele, keine Zeilen: Sieben Bezeichnungen von zwei bis neun
 * Zeichen füllen keine Spalte und brauchen auch keine. Als umbrechende Reihe
 * stehen sie so dicht, dass sie als eine Gruppe lesbar bleiben.
 */
.exo-material-list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--30);
	list-style: none;
	margin: 0;
	padding: 0;
}

.exo-material-list > li {
	margin-block: 0;
}

.exo-material-list .wp-block-post-title {
	margin: 0;
	font-weight: 600;
}

.exo-material-list .wp-block-post-title a {
	display: inline-flex;
	align-items: center;
	min-block-size: var(--touch-target);
	padding-inline: var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	background-color: var(--color-surface);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.exo-material-list .wp-block-post-title a:hover,
.exo-material-list .wp-block-post-title a:focus-visible {
	border-color: var(--color-brand);
	background-color: var(--color-surface-brand);
	text-decoration: none;
}

.exo-material-label {
	margin-block: 0 var(--wp--preset--spacing--30) !important;
	color: var(--color-text-muted);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
}

@media (width >= 48rem) {
	.exo-process-comparison {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--50);
	}
}

/* ------------------------------------------------------------------
 * Ablaufschritte
 * ------------------------------------------------------------------ */
/*
 * Der Ablauf ist der einzige Abschnitt der Startseite, in dem eine
 * Nummerierung eine echte Information trägt: Die Schritte laufen tatsächlich
 * in dieser Reihenfolge. Die Zahl darf deshalb Gewicht bekommen und sitzt
 * unmittelbar unter der Linie, an der der Schritt beginnt.
 */
.exo-step__number {
	display: block;
	inline-size: auto;
	block-size: auto;
	border-radius: 0;
	background: none;
	color: var(--color-text);
	font-weight: 700;
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--heading-3);
	font-variant-numeric: tabular-nums;
	line-height: var(--line-height-tight);
	margin-block-end: var(--wp--preset--spacing--50);
}

.exo-step__title {
	font-size: var(--wp--preset--font-size--xl);
	line-height: var(--line-height-ui);
	margin-block-end: var(--wp--preset--spacing--20);
}

.exo-step p:last-child {
	color: var(--color-text-secondary);
	margin-block-end: 0;
}

/* ------------------------------------------------------------------
 * Abschnitte
 * ------------------------------------------------------------------ */
/*
 * Jede Fläche führt ihre eigene Linienfarbe als `--rule`. Komponenten
 * innerhalb einer Fläche greifen nur auf `--rule` zu und funktionieren
 * dadurch auf hellem, dunklem, warmem und orangem Grund unverändert. Ohne
 * das müsste jede Trennlinie je Fläche einzeln überschrieben werden – genau
 * daraus war im Vorzustand die uneinheitliche Rasterung entstanden.
 */
.exo-section {
	--rule: var(--color-border);

	padding-block: var(--section-default);
}

.exo-section--dark {
	--rule: var(--color-border-dark);

	/*
	 * Auf dunklem Grund kehrt sich der Fokuskontrast um: `brand-700` liegt
	 * dort bei 2,4:1, das hellere `brand-500` bei 9,4:1. Beide Flächen tragen
	 * damit dieselbe Farbe der Marke, nur in der Stufe, die man auch sieht.
	 */
	--color-focus: var(--wp--preset--color--brand-500);

	background-color: var(--color-surface-dark);
	color: var(--color-text-on-dark);
}

.exo-section--dark :is(h1, h2, h3, h4, h5, h6) {
	color: var(--color-text-on-dark);
}

/*
 * Fließtextlinks auf dunkler Fläche.
 *
 * Die Ausnahme für tertiäre Aktionen ist notwendig, nicht kosmetisch: Diese
 * Regel liegt mit zwei Klassen über der Komponentenregel und färbte sonst auch
 * die Ziele der Leistungszeilen orange - dieselbe Rolle also einmal orange und
 * auf heller Fläche in Textfarbe. Siehe Regel R12.
 */
.exo-section--dark a:not(.wp-block-button__link, .exo-path__link, .exo-service__link) {
	color: var(--color-brand);
}

.exo-section--subtle {
	background-color: var(--color-surface-subtle);
}

.exo-section--warm {
	--rule: var(--wp--preset--color--brand-700);

	background-color: var(--color-surface-brand);
}

.exo-section--brand {
	--rule: var(--wp--preset--color--brand-700);

	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
}

.exo-section--brand :is(h1, h2, h3, h4, h5, h6) {
	color: var(--color-text-on-brand);
}

/* ------------------------------------------------------------------
 * Akkordeon (FAQ)
 * Auf <details>/<summary> aufgebaut: ohne JavaScript bedienbar,
 * durchsuchbar und von Haus aus tastaturfähig.
 * ------------------------------------------------------------------ */
.exo-accordion {
	border-block-start: 1px solid var(--color-border);
}

.exo-accordion > details {
	border-block-end: 1px solid var(--color-border);
}

/*
 * Die Zusammenfassung ist die Bedienfläche der Frage. Sie war bisher weder als
 * solche gekennzeichnet noch verlässlich groß genug: ohne Zeigerzustand, ohne
 * Mindesthöhe und mit einer Trefferfläche, die exakt an der Textkante endete.
 */
.exo-accordion summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--40);
	min-block-size: var(--touch-target);
	padding-block: var(--wp--preset--spacing--40);
	font-weight: 600;
	list-style: none;
	cursor: pointer;
	transition: color var(--duration-fast) var(--easing-standard);
}

.exo-accordion summary:hover {
	color: var(--color-text-secondary);
}

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

/* Richtungshinweis, weil das Standarddreieck entfernt wurde. */
.exo-accordion summary::after {
	content: "";
	flex: none;
	inline-size: 0.625rem;
	block-size: 0.625rem;
	border-inline-end: 2px solid currentcolor;
	border-block-end: 2px solid currentcolor;
	rotate: 45deg;
	transition: rotate var(--duration-normal) var(--easing-standard);
}

.exo-accordion details[open] summary::after {
	rotate: -135deg;
}

.exo-accordion :where(details > :not(summary)) {
	padding-block-end: var(--wp--preset--spacing--40);
	max-inline-size: 68ch;
	color: var(--color-text-secondary);
}

/* ------------------------------------------------------------------
 * Statusmeldung
 * Farbe allein trägt nie die Bedeutung – Icon und Text gehören dazu.
 * ------------------------------------------------------------------ */
.exo-notice {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	padding: var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border);
	border-inline-start-width: 3px;
	border-radius: var(--radius-sm);
	background-color: var(--color-surface-subtle);
}

.exo-notice__title {
	font-weight: 600;
	grid-column: 2;
}

.exo-notice__text {
	grid-column: 2;
	color: var(--color-text-secondary);
}

/*
 * Ein Hinweis ohne Symbol.
 *
 * Das Raster hat zwei Spalten, weil die erste das Symbol trägt. Fehlt es, stand
 * der Text weiterhin in Spalte 2 - und Spalte 1 blieb als leere Rinne stehen.
 * Hier wird das Raster einspaltig, und der Text nimmt sie ein.
 */
.exo-notice--schmucklos {
	grid-template-columns: minmax(0, 1fr);
}

.exo-notice--schmucklos .exo-notice__title,
.exo-notice--schmucklos .exo-notice__text {
	grid-column: 1;
}

/*
 * Abstände im Text des Hinweises - **nur** im schmucklosen.
 *
 * Der Blockabstand des Themes greift dort nicht: Die Absätze stehen in einem
 * eigenen Kasten und nicht im Seitenfluss. Ohne die Regel klebten die beiden
 * Sätze aneinander und der Knopf an ihnen (Rückmeldung vom 2026-08-19).
 *
 * Der Geltungsbereich ist eng, und das ist Absicht: `.exo-notice__text` tragen
 * acht Blöcke, und in den meisten ist es der Absatz **selbst**. Unbeschränkt
 * hätten die Regeln dort die Abstände seiner Inline-Kinder genullt und die
 * fette Schrift jeder Fehler- und Erfolgsmeldung umgefärbt - für einen Kasten,
 * um den es gar nicht ging. Am 2026-08-20 von der Codeprüfung gefunden.
 */
.exo-notice--schmucklos .exo-notice__text > * {
	margin-block: 0;
}

.exo-notice--schmucklos .exo-notice__text > * + * {
	margin-block-start: var(--wp--preset--spacing--20);
}

/*
 * Der erste Satz führt und steht deshalb in Textfarbe: Der Kasten ist als
 * Ganzes zurückgenommen, aber die Aussage darin soll es nicht sein.
 */
.exo-notice--schmucklos .exo-notice__text strong {
	color: var(--color-text);
}

.exo-notice--success { border-inline-start-color: var(--color-success); }
.exo-notice--warning { border-inline-start-color: var(--color-warning); }
.exo-notice--danger  { border-inline-start-color: var(--color-danger); }

/*
 * Der Infohinweis hatte keine eigene Randfarbe und lief als einziger in Grau -
 * ausgerechnet der Fall „kein Preis, aber ein Weg" (Rückmeldung des
 * Auftraggebers vom 2026-08-16). `brand-700` statt `brand-500`, damit die Kante
 * auf der getönten Fläche sichtbar bleibt.
 */
.exo-notice--info { border-inline-start-color: var(--wp--preset--color--brand-700); }

.exo-notice__icon {
	display: grid;
	place-items: center;
	color: var(--wp--preset--color--brand-700);
}

/*
 * Abstand über einer Handlungsaufforderung im Hinweis: Ohne ihn klebt der Knopf
 * am letzten Absatz, und der Hinweis liest sich als ein Block, in dem der Weg
 * nach vorn untergeht.
 */
.exo-notice__text > .wp-block-button {
	margin-block-start: var(--wp--preset--spacing--30);
}

/*
 * Abstand zwischen der Themenüberschrift und ihrer Fragenliste (FAQ).
 *
 * Der Blockabstand von Gutenberg setzt zwischen Überschrift und folgendem Block
 * denselben Wert wie zwischen zwei Absätzen. Auf der FAQ-Seite stehen dadurch
 * „Aufträge und Dateien" und die erste Frage darunter so dicht, dass die
 * Überschrift wie die erste Zeile der Liste wirkt (Rückmeldung vom 2026-08-19).
 *
 * Der Abstand hängt an der Liste und nicht an der Überschrift: Eine Überschrift
 * weiß nicht, was nach ihr kommt, eine Liste weiß, was vor ihr steht.
 */
.wp-block-heading + .exo-accordion {
	/*
	 * `!important` wie an den übrigen Stellen, an denen der Blockabstand von
	 * Gutenberg überstimmt werden muss: Er kommt aus `:where(.is-layout-flow) >
	 * * + *` und gewinnt sonst über die Reihenfolge.
	 *
	 * `spacing--50` sind 1,5 rem. `spacing--40` wäre 1 rem gewesen - genau der
	 * Wert, den Gutenberg ohnehin setzt; die Regel hätte nichts geändert. Am
	 * 2026-08-19 nachgemessen: 16 px vorher wie nachher.
	 */
	margin-block-start: var(--wp--preset--spacing--50) !important;
}

/*
 * Und Luft zur nächsten Themenüberschrift: Ohne sie stößt die letzte Frage
 * eines Themas an die Überschrift des nächsten, und beide Blöcke verschmelzen.
 */
.exo-accordion + .wp-block-heading {
	margin-block-start: var(--wp--preset--spacing--60) !important;
}

/* ------------------------------------------------------------------
 * Formulare
 * ------------------------------------------------------------------ */
.exo-field {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--20);
}

.exo-field__label {
	font-weight: 500;
}

.exo-field__hint {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-secondary);
}

/*
 * Sicherheitshinweis am Datei-Upload: Zeichen und Text auf einer Zeile, wie
 * ein Fußnotenhinweis statt wie eine Warnung - der Hinweis ist eine Zusage,
 * kein Alarm.
 */
.exo-field__hint--secure {
	display: flex;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--20);
	margin-block-start: var(--wp--preset--spacing--20) !important;
}

.exo-field__hint-icon {
	flex: none;
	inline-size: 1rem;
	block-size: 1rem;
	margin-block-start: 0.15em;
	color: var(--color-text-muted);
	fill: none;
	stroke: currentcolor;
	stroke-width: 1.7;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.exo-field :where(input, select, textarea) {
	min-block-size: var(--touch-target);
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	background-color: var(--color-surface);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-sm);
}

/*
 * Im Fokus trägt auch der Rand des Feldes die Marke, nicht nur der Ring
 * darum. Der Ring allein liegt außerhalb der Kontur; mit dem mitgefärbten
 * Rand liest sich das Feld als eine Einheit statt als Feld mit Rahmen.
 * Die Farbe kommt aus `--color-focus` und wechselt damit auf dunklen
 * Flächen automatisch mit.
 */
.exo-field :where(input, select, textarea):focus-visible {
	border-color: var(--color-focus);
}

.exo-field textarea {
	/* Wächst mit dem Inhalt, ohne JavaScript. */
	field-sizing: content;
	min-block-size: 6rem;
}

/*
 * :user-invalid statt :invalid – meldet erst nach einer Eingabe, nicht
 * schon beim Laden eines leeren Pflichtfelds.
 */
.exo-field :where(input, select, textarea):user-invalid {
	border-color: var(--color-danger);
}

.exo-field__error {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-danger);
	font-weight: 500;
}

.exo-field__required {
	color: var(--color-danger);
}

/* ------------------------------------------------------------------
 * Vergleichstabelle
 * Unterhalb von 48rem gestapelt statt gequetscht.
 * ------------------------------------------------------------------ */
.exo-table-scroll {
	overflow-x: auto;
	/* Sichtbarer Hinweis, dass seitlich mehr Inhalt liegt. */
	background:
		linear-gradient(to right, var(--color-surface) 30%, transparent),
		linear-gradient(to left, var(--color-surface) 30%, transparent) 100% 0,
		radial-gradient(farthest-side at 0 50%, rgb(22 25 29 / 12%), transparent),
		radial-gradient(farthest-side at 100% 50%, rgb(22 25 29 / 12%), transparent) 100% 0;
	background-repeat: no-repeat;
	background-size: 3rem 100%, 3rem 100%, 1rem 100%, 1rem 100%;
	background-attachment: local, local, scroll, scroll;
}

.exo-table-scroll table {
	inline-size: 100%;
	border-collapse: collapse;
}

.exo-table-scroll :where(th, td) {
	padding: var(--wp--preset--spacing--30);
	border-block-end: 1px solid var(--color-border);
	text-align: start;
}

.exo-table-scroll th {
	font-weight: 600;
}

.exo-table-scroll caption {
	caption-side: top;
	text-align: start;
	padding-block-end: var(--wp--preset--spacing--30);
	color: var(--color-text-secondary);
}

/* ------------------------------------------------------------------
 * Unterseiten
 *
 * Die Seite teilt ihre Achse mit dem Rahmen, aber nicht dessen Breite:
 * Fließtext, Überschriften und Listen bleiben auf Lesebreite begrenzt und
 * enden links an derselben Kante wie Kopfbereich und Fußbereich.
 *
 * Ausgenommen sind alle Blöcke, die ihre Breite selbst mitbringen –
 * ausgerichtete Blöcke, Muster, Raster, Tabellen und das Anfrageformular.
 * Ohne diese Ausnahme würde ein vollbreites Muster auf einer Unterseite auf
 * Textbreite zusammenfallen.
 * ------------------------------------------------------------------ */
/*
 * Bewusst ohne Breitenbegrenzung: Der Titel ist ein direktes Kind des
 * eingeschränkten Layouts und bekommt von dort einen `!important`-
 * Automatikrand. Solange er die volle Containerbreite einnimmt, läuft dieser
 * Rand ins Leere; mit einer Begrenzung würde er die Überschrift zentrieren.
 * Die Zeilenlänge regelt stattdessen der Umbruchausgleich.
 */
.exo-page__title {
	letter-spacing: -0.02em;
	text-wrap: balance;
}

/*
 * Unterseiten brauchen keinen 96-px-Schauflächenabstand wie die großen
 * Startseitenabschnitte. 48/64 px halten den Einstieg klar vom kompakten
 * Header getrennt, ohne auf Desktop eine leere Bühne zu erzeugen.
 */
.exo-page,
.exo-listing {
	padding-block: var(--section-compact);
}

/*
 * `post-content` läuft bewusst im Standardlayout. WordPress erzeugt dort
 * jedoch keinen Blockabstand; nach dem globalen Margin-Reset klebten Intro,
 * Überschriften, Absätze, Formulare und Abschlussmuster unmittelbar
 * aneinander. Die folgenden Rollen bilden einen ruhigen Inhaltsfluss, ohne
 * Abstände innerhalb fachlicher Komponenten zu verändern.
 */
.exo-page__body > p.exo-lead:first-child {
	margin-block-end: var(--wp--preset--spacing--50) !important;
}

.exo-page__body > :is(h2, h3, h4) {
	margin-block-start: var(--wp--preset--spacing--60) !important;
}

.exo-page__body > :is(h2, h3, h4) + :is(p, ul, ol, blockquote) {
	margin-block-start: var(--wp--preset--spacing--20) !important;
}

.exo-page__body > :is(p, ul, ol, blockquote) + :is(p, ul, ol, blockquote) {
	margin-block-start: var(--wp--preset--spacing--30) !important;
}

/*
 * Gruppen im Inhaltsfluss standen in keiner der Rollen darüber.
 *
 * Sichtbar auf dem Sofortangebot: Unter dem Rahmen mit Datei und Ausführung
 * folgt die Gruppe „Welche Dateien das Werkzeug erkennt" - und ihre Überschrift
 * saß mit 0 px unmittelbar auf dessen Unterkante (gemessen am 2026-08-18,
 * gemeldet vom Auftraggeber). Sie las sich damit als Fortsetzung des Kastens
 * statt als eigener Abschnitt.
 *
 * Derselbe Wert wie für eine Überschrift auf dieser Ebene: Eine Gruppe beginnt
 * hier in aller Regel mit einer, und ob sie ein `h2` direkt oder in einer
 * Gruppe trägt, darf den Abstand davor nicht ändern.
 *
 * Vollbreite Gruppen bleiben ausgenommen - für sie gilt die Rolle weiter unten,
 * und ein Muster, das bis zum Fensterrand läuft, bringt seinen Abstand als
 * eigene Polsterung mit.
 */
.exo-page__body > .wp-block-group:not([class~="alignfull"], :first-child) {
	margin-block-start: var(--wp--preset--spacing--60) !important;
}

/*
 * Tabellen stehen in den Rollen darüber nicht: Der Tabellenblock ist ein
 * `figure`, und nach dem globalen Margin-Reset hatte er weder oben noch unten
 * einen Abstand. Auf „Versand und Zahlung" klebte der erläuternde Satz
 * unmittelbar an der Unterkante des Tabellenrahmens und las sich wie eine
 * weitere Zeile davon. Die Tabelle ist ein abgesetzter Gegenstand und bekommt
 * denselben Abstand wie die anderen Blöcke - unten etwas mehr, weil der
 * Rahmen unten dichter schließt als eine Textzeile oben.
 */
.exo-page__body > .wp-block-table {
	margin-block: var(--wp--preset--spacing--40) var(--wp--preset--spacing--50) !important;
}

.exo-page__body > .exo-request,
.exo-page__body > :not([class~="alignfull"]) + [class~="alignfull"] {
	margin-block-start: var(--wp--preset--spacing--50) !important;
}

.exo-page__body > [class~="alignfull"] + [class~="alignfull"] {
	margin-block-start: 0 !important;
}

/* Ein letzter Vollbreitenabschnitt trägt seine eigene untere Polsterung. */
.exo-page:has(.exo-page__body > [class~="alignfull"]:last-child) {
	padding-block-end: 0;
}

/*
 * Lesebreite für Kopf- und Abschlussgruppen von Einzel- und Archivseiten.
 * Wie beim FAQ sitzt die Begrenzung an den Kindern: Die Gruppe selbst bleibt
 * voll breit, damit der Automatikrand des eingeschränkten Layouts sie nicht
 * in die Seitenmitte zieht.
 */
.exo-measure > * {
	max-inline-size: var(--container-text);
}

/*
 * Vollbreite Blöcke brechen auch auf Unterseiten bis zum Viewportrand aus.
 *
 * Im Fließlayout kennt WordPress keine Sonderbehandlung für `alignfull` - ein
 * Block füllt dort schlicht seinen Container. Der Beitragsinhalt liegt aber im
 * 80-rem-Container, sodass vollbreite Muster auf Unterseiten bei 1280 px
 * endeten, während dieselben Muster auf der Startseite bis zum Rand liefen.
 *
 * Die negativen Ränder vergrößern den Block um genau die Differenz zwischen
 * Container und Viewport. `overflow-x: clip` am Wurzelelement fängt die
 * Scrollleistenbreite ab, die `vw` mitzählt.
 */
.exo-page__body > [class~="alignfull"] {
	max-inline-size: none;
	margin-inline: calc(50% - 50vw);
}

.exo-page__body > [class~="alignwide"] {
	max-inline-size: var(--container-wide);
	margin-inline: calc(50% - min(var(--container-wide), 100vw) / 2);
}

/* Ausgerichtete Blöcke über die Attributschreibweise: Die Kernklassen
 * `alignfull` und `alignwide` tragen kein Themepräfix. */
.exo-page__body > :not(
	[class~="alignfull"],
	[class~="alignwide"],
	.wp-block-group,
	.wp-block-columns,
	.wp-block-table,
	.wp-block-buttons,
	.wp-block-query,
	.exo-request,
	.exo-accordion
) {
	max-inline-size: var(--container-text);
}

/* ------------------------------------------------------------------
 * Wissensbeiträge
 *
 * Ein Beitrag ist eine Leseseite, keine weitere Karte im Archiv. Kopf,
 * Inhalt und Navigation verwenden deshalb dieselbe linke 80-rem-Achse;
 * nur der Fließtext wird auf 48 rem begrenzt. Medien und Tabellen dürfen
 * breiter werden, wenn ihr Informationsgehalt das benötigt.
 * ------------------------------------------------------------------ */
.exo-article-header {
	padding-block: var(--section-compact);
	background-color: var(--color-surface-subtle);
	border-block-end: 1px solid var(--color-border);
}

/*
 * Der Kopfbereich liegt auf derselben Achse wie der Beitrag darunter.
 *
 * Sonst stünden Rückweg, Kopfdaten und Titel über die volle Containerbreite,
 * während Bild und Text darunter in einer mittigen Spalte liegen - die Seite
 * hätte zwei Achsen. Die Klasse `exo-article-header` behält ihre volle
 * Hintergrundfläche, nur der Inhalt folgt der Spalte.
 */
.exo-article-header__inner {
	max-inline-size: var(--article-measure);
	margin-inline: auto;
}

.exo-article-header__inner > * {
	margin-block-start: 0;
}

.exo-article__back {
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
}

.exo-article__back a,
.exo-article-navigation__overview a {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	color: var(--color-text);
	text-decoration: none;
}

.exo-article__back a:hover span:last-child,
.exo-article__back a:focus-visible span:last-child,
.exo-article-navigation__overview a:hover span:first-child,
.exo-article-navigation__overview a:focus-visible span:first-child {
	text-decoration: underline;
	text-decoration-color: var(--color-brand);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.25em;
}

.exo-article__meta {
	gap: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	margin-block-start: var(--wp--preset--spacing--60);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 500;
	letter-spacing: 0.08em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
	color: var(--color-text-secondary);
}

.exo-article__meta a {
	color: inherit;
	text-decoration: none;
}

.exo-article__meta a:hover,
.exo-article__meta a:focus-visible {
	color: var(--color-text);
	text-decoration: underline;
	text-decoration-color: var(--color-brand);
	text-underline-offset: 0.25em;
}

.exo-article__date {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--40);
}

.exo-article__date::before {
	content: "";
	inline-size: 1px;
	block-size: 1em;
	background-color: var(--color-border-strong);
}

.exo-article__title {
	max-inline-size: 22ch;
	margin-block-start: var(--wp--preset--spacing--30);
	letter-spacing: -0.025em;
}

/*
 * Der Beitrag ist eine mittige Spalte, kein linksbündiger Text in einer
 * breiten Fläche.
 *
 * Zuvor war der Körper 1280px breit, der Text darin aber auf 656px begrenzt
 * und linksbündig gesetzt: Rechts blieben gemessen 620px leer, und das
 * Beitragsbild lief über die ganze Breite darüber hinweg. Die Seite hatte
 * dadurch keine erkennbare Achse.
 *
 * Jetzt trägt der Körper selbst die Spaltenbreite und steht mittig. Alles
 * darin - Bild, Fließtext, Listen, Tabellen und Spaltenblöcke - liegt auf
 * derselben Breite und derselben Achse.
 */
/*
 * Kein oberer Rand: Der Textkörper trägt seine eigene Polsterung von
 * `--section-compact`. Der Blockabstand des Fließlayouts (24 px) addierte
 * sich darauf - gemessen 88 px zwischen Kopfbereich und erster Zeile, ohne
 * dass dort etwas stünde.
 */
.exo-article__body {
	max-inline-size: calc(var(--article-measure) + var(--gutter-page) + var(--gutter-page));
	margin-block-start: 0 !important;
	margin-inline: auto;
	padding: var(--section-compact) var(--gutter-page);
}

/*
 * Lesebreite nach Brand Identity §11: Fließtext höchstens 65-72ch.
 *
 * `--container-text` sind 48rem. Bei 16px Fließtext ergab das gemessene 768px,
 * also rund 96 Zeichen je Zeile - ein Drittel über der Vorgabe. Auf dieser
 * Breite verliert das Auge beim Zeilenwechsel den Anschluss, und genau das
 * machte die Wissensbeiträge mühsam.
 *
 * Der Wert steht bewusst in `rem` und nicht in `ch`: `ch` bezieht sich auf die
 * Schriftgröße des Elements selbst. Eine 1,75rem-Überschrift bekäme damit die
 * anderthalbfache Breite des Fließtextes darunter - gemessen 1142px gegen
 * 652px - und stünde sichtbar über die rechte Textkante hinaus. 41rem
 * entsprechen den geforderten rund 68 Zeichen bei 1rem Fließtext und gelten
 * für alle Stufen gleich.
 */
/*
 * Gemessen statt geschätzt.
 *
 * Brand Identity §11 begrenzt den Fließtext auf 65-72ch. `ch` ist die Breite
 * der Ziffer Null - bei 1rem Fließtext in Manrope 9,59px. Die Obergrenze von
 * 72ch entspricht damit 690px, also 43rem.
 *
 * Die frühere Angabe von 41rem beruhte auf einer Schätzung der Zeichenbreite
 * und lag mit 656px bei 68ch.
 *
 * FESTLEGUNG DES AUFTRAGGEBERS AM 2026-08-12: 740px.
 *
 * Das sind 46,25rem und rund 77ch - vier Zeichen über der Spanne aus §11. Die
 * Vorgabe ist ausdrücklich so gewünscht und steht hier, damit sie nicht beim
 * nächsten Abgleich mit der Brand Identity stillschweigend auf 43rem
 * zurückgesetzt wird. In tatsächlichen Zeichen sind es rund 88 je Zeile, weil
 * ein Durchschnittszeichen dieser Schrift schmaler ist als die Ziffer Null.
 */
.exo-article {
	--article-measure: 46.25rem;
}

/*
 * Die Breite trägt jetzt der Körper, nicht jedes einzelne Kind. Eine zweite
 * Begrenzung hier würde die Spalte innerhalb der Spalte erneut einengen.
 */
.exo-article .exo-article__content > * {
	max-inline-size: 100%;
	margin-inline: 0;
}

/*
 * Auch Medien, Tabellen und Spaltenblöcke bleiben auf der Spaltenbreite.
 *
 * Sie durften zuvor bis zur Inhaltsbreite von 1120px laufen, während der Text
 * bei 656px endete. Im Wechsel sprang die linke Kante des Beitrags dadurch
 * zwischen zwei Achsen. Die Regel bleibt als Stelle bestehen, an der eine
 * spätere Ausnahme bewusst getroffen werden kann.
 */
.exo-article .exo-article__content > :is(
	figure,
	table,
	.wp-block-columns,
	.wp-block-gallery,
	.wp-block-video,
	.wp-block-embed,
	[class~="alignwide"],
	[class~="alignfull"]
) {
	max-inline-size: 100%;
}

.exo-article .exo-article__content > * + * {
	margin-block-start: var(--wp--preset--spacing--40);
}

/*
 * Eigene Überschriftenstufen für den Fließtext.
 *
 * Die Presets `heading-2` (2,5rem) und `heading-3` (1,5rem) sind für
 * Abschnittsüberschriften der Startseite gemacht, wo eine Überschrift eine
 * ganze Bühne trägt. Im Beitrag stehen sie über 1rem-Fließtext: gemessen 40px
 * gegen 16px, also Faktor 2,5. Eine Zwischenüberschrift bekam damit mehr
 * Gewicht als der Beitragstitel selbst tragen konnte, und der Beitrag zerfiel
 * in Überschriften mit Text dazwischen statt in gegliederten Text.
 *
 * Die Stufen hier folgen dem Fließtext: 1,75 / 1,375 / 1,125rem. Sie gelten
 * auch für Überschriften in Spaltenblöcken - dort steht in den Beiträgen der
 * Bild-Text-Wechsel, und eine Stufe darf nicht davon abhängen, wie tief sie
 * verschachtelt ist.
 */
.exo-article .exo-article__content :is(h2, h3, h4) {
	letter-spacing: -0.01em;
	line-height: var(--line-height-heading);
}

.exo-article .exo-article__content :is(h2, h3, h4):not(:first-child) {
	margin-block-start: var(--wp--preset--spacing--60);
}

.exo-article .exo-article__content h2 {
	font-size: 1.75rem;
}

.exo-article .exo-article__content h3 {
	font-size: 1.375rem;
}

.exo-article .exo-article__content h4 {
	font-size: var(--wp--preset--font-size--lg);
}

.exo-article .exo-article__content :is(h2, h3, h4) + * {
	margin-block-start: var(--wp--preset--spacing--30);
}

/*
 * Nur die oberste Stufe bekommt eine Trennlinie. In den Beiträgen gliedert h2
 * den Text in zwei bis vier große Teile; die Linie macht diese Teilung beim
 * Überfliegen sichtbar, ohne dass eine zweite Schriftgröße nötig wäre. Auf h3
 * wiederholt läge dagegen alle zwei Absätze eine Kante.
 */
.exo-article .exo-article__content h2:not(:first-child) {
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--color-border);
}

/*
 * Die Beiträge stellen Bild und Erläuterung als Spaltenpaar gegenüber. Ohne
 * Begrenzung bestimmt die Bildhöhe die Zeilenhöhe des Paares: Die Renderings
 * sind quadratisch, die Erläuterungen daneben vier Zeilen lang, und zwischen
 * zwei Abschnitten stand dadurch eine halbe Bildschirmhöhe Leerraum.
 */
.exo-article__content .wp-block-columns .wp-block-image img {
	max-block-size: 18rem;
	inline-size: auto;
	border-radius: var(--radius-md);
}

.exo-article .exo-article__content > p:first-child {
	font-size: var(--font-size-lead);
	color: var(--color-text-secondary);
}

.exo-article__content :is(ul, ol) {
	padding-inline-start: var(--wp--preset--spacing--50);
}

.exo-article__content li + li {
	margin-block-start: var(--wp--preset--spacing--20);
}

.exo-article__content blockquote {
	padding-inline-start: var(--wp--preset--spacing--50);
	border-inline-start: var(--wp--preset--spacing--10) solid var(--color-brand);
	color: var(--color-text-secondary);
}

.exo-article__content :is(img, video, iframe) {
	max-inline-size: 100%;
}

.exo-article__content figure > figcaption {
	margin-block-start: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
	color: var(--color-text-secondary);
}

/* ------------------------------------------------------------------
 * Tabellen in Beiträgen und auf Seiten
 *
 * Der Geltungsbereich umfasst beide Textkörper: `.exo-article__content` für
 * Wissensbeiträge, `.exo-page__body` für die übrigen Seiten - Versand und
 * Zahlung, AGB und was sonst tabellarisch etwas festhält. Zuvor galten diese
 * Regeln nur für Beiträge; dieselbe Preistabelle sah auf einer Seite anders
 * aus als in einem Beitrag, ohne dass die Unterscheidung eine Bedeutung
 * gehabt hätte. `:is()` statt zweier Regelsätze: Die Spezifität bleibt die
 * einer einzelnen Klasse, und die Begründungen darunter stehen weiterhin
 * jeweils einmal.
 *
 * Zwei Fassungen lagen hier übereinander, und keine gewann.
 *
 * Die Fassung des Themes war rahmenlos: Zeilenlinien, sonst nichts. Die
 * Beiträge aus dem Altsystem tragen aber überwiegend den Blockstil
 * „Streifen", und dessen fest eingebautes `#f0f0f0` blieb bestehen. Auf dem
 * Papier eine Tabelle ohne Kästchen, auf dem Bildschirm ein graues
 * Streifenmuster mit blassen Kopfzeilen und ohne erkennbaren Rand - die
 * Tabelle schwamm im Fließtext, statt darin ein eigener Gegenstand zu sein.
 *
 * Diese Fassung entscheidet sich: Die Tabelle ist ein abgesetzter Block mit
 * Rahmen und Rundung, wie die Datenblätter der Material- und Produktseiten.
 * Die Kopfzeile trägt eine getönte Fläche und Beschriftungen in der
 * Systemschrift für Kennwerte; die Streifen entfallen zugunsten von
 * Zeilenlinien. Damit gilt für Tabellen dieselbe Sprache wie überall sonst,
 * unabhängig davon, welchen Blockstil ein Altbeitrag mitbringt.
 *
 * Der Rahmen übernimmt zugleich die Aufgabe, die vorher die bündige linke
 * Kante hatte: Er sagt, wo die Tabelle anfängt und aufhört. Deshalb tragen
 * jetzt auch die äußeren Zellen ihre Polsterung.
 * ------------------------------------------------------------------ */
/*
 * Der Rahmen sitzt auf der Hülle, nicht auf der Tabelle: Nur so bleibt er
 * beim seitlichen Rollen stehen, statt mitzuwandern. `overflow-x: auto`
 * bewirkt zugleich, dass die Rundung den Inhalt beschneidet.
 */
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) .wp-block-table,
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) > table {
	overflow-x: auto;
	overscroll-behavior-inline: contain;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
}

:is(.exo-article__content, .exo-page__body, .exo-orders-scope) table {
	inline-size: 100%;
	border-collapse: collapse;
	font-size: var(--wp--preset--font-size--sm);
	font-variant-numeric: tabular-nums;
	line-height: var(--line-height-ui);
}

:is(.exo-article__content, .exo-page__body, .exo-orders-scope) :is(th, td) {
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border: 0;
	border-block-end: 1px solid var(--color-border);
	text-align: start;
	vertical-align: top;
}

/* Die letzte Zeile braucht keine Linie: Darunter liegt der Rahmen. */
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) tbody tr:last-child :is(th, td) {
	border-block-end: 0;
}

/*
 * Kopfzeile als getönte Leiste.
 *
 * Die Beschriftungen stehen in der Schrift, die auf dieser Website
 * durchgehend Kennwerte auszeichnet - dieselbe wie in den Kenndaten der
 * Material- und Produktseiten. Wer die Tabelle überfliegt, erkennt die
 * Kopfzeile daran, nicht an ihrer Schriftstärke.
 *
 * `th[scope="row"]` ist ausgenommen: Eine solche Zelle beschriftet ihre Zeile
 * und nicht eine Spalte. In einer Tabelle aus Merkmal und Wert - der
 * Eigenschaftstabelle des Sofortangebots - traf die Regel sonst allein die
 * erste Zeile, weil sie die erste ist. „Bauraum" stand dort in Versalien auf
 * getöntem Grund, „Maße" und „Volumen" darunter nicht; die Tabelle behauptete
 * eine Kopfzeile, die es nicht gibt.
 */
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) thead th,
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) tr:first-child th:not([scope="row"]) {
	border-block-end: 1px solid var(--color-border-strong);
	background-color: var(--color-surface-subtle);
	color: var(--color-text-muted);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	white-space: nowrap;
}

/*
 * Die Redaktion setzt in Kopfzellen häufig zusätzlich `<strong>`. In
 * Versalien und halbfetter Schrift wäre das eine dritte Auszeichnung für
 * dieselbe Aussage.
 */
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) thead th strong,
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) tr:first-child th:not([scope="row"]) strong {
	font-weight: inherit;
}

/*
 * Das Merkmal führt die Zeile und steht deshalb in Textfarbe und halbfett -
 * gleich, ob es als `td` in der ersten Spalte steht oder als `th[scope="row"]`
 * ausgezeichnet ist. Ohne die zweite Hälfte trüge die Zeilenbeschriftung das
 * fette Vorgabegewicht des Browsers und wäre schwerer als dieselbe Angabe in
 * jeder anderen Tabelle.
 */
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) tbody td:first-child,
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) tbody th[scope="row"] {
	color: var(--color-text);
	font-weight: 600;
}

/*
 * Der Blockstil „Streifen" wird zurückgenommen.
 *
 * Sein `#f0f0f0` ist fest verdrahtet, steht neben keiner Farbe dieser
 * Website und liegt außerdem quer zur Zeilenlinie: Zwei Systeme gliederten
 * dieselbe Tabelle. Der Blockstil bleibt im Editor wählbar, richtet aber
 * keinen Schaden mehr an.
 *
 * Der Stil setzt zusätzlich alle Zellenrahmen auf `transparent` - denn wo
 * Streifen gliedern, braucht es keine Linien. Da die Streifen entfallen,
 * kommen die Linien zurück; ohne diese Regel stünde die Tabelle vollständig
 * ohne Zeilentrennung da, was in den Beiträgen mit zehn Zeilen und
 * mehrzeiligen Zellen nicht mehr lesbar war.
 */
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) .wp-block-table.is-style-stripes {
	border: 1px solid var(--color-border);
}

:is(.exo-article__content, .exo-page__body, .exo-orders-scope) .wp-block-table.is-style-stripes tbody tr {
	background-color: transparent;
}

:is(.exo-article__content, .exo-page__body, .exo-orders-scope) .wp-block-table.is-style-stripes :is(th, td) {
	border-block-end-color: var(--color-border);
}

:is(.exo-article__content, .exo-page__body, .exo-orders-scope) .wp-block-table.is-style-stripes thead th {
	border-block-end-color: var(--color-border-strong);
}

:is(.exo-article__content, .exo-page__body, .exo-orders-scope) .wp-block-table.is-style-stripes tbody tr:last-child :is(th, td) {
	border-block-end-width: 0;
}

:is(.exo-article__content, .exo-page__body, .exo-orders-scope) tbody tr:hover {
	background-color: var(--color-surface-subtle);
}

/*
 * Die Beschriftung gehört über den Rahmen, nicht hinein: Sie benennt die
 * Tabelle und ist nicht Teil ihrer Daten.
 */
:is(.exo-article__content, .exo-page__body, .exo-orders-scope) table caption {
	caption-side: top;
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border-block-end: 1px solid var(--color-border);
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	text-align: start;
}

/* Altbeiträge enthalten teils Abstandshalter aus dem früheren Layout. Der
 * Artikelrhythmus übernimmt diese Aufgabe reproduzierbar über Tokens. */
.exo-article__content > .wp-block-spacer {
	display: none;
}

.exo-article-navigation {
	padding-block: var(--section-compact);
	background-color: var(--color-surface-subtle);
	border-block-start: 1px solid var(--color-border);
}

.exo-article-navigation__header > * + * {
	margin-block-start: var(--wp--preset--spacing--20);
}

/*
 * Vorheriger und nächster Beitrag als Karten.
 *
 * Zuvor trug jede Seite nur eine Haarlinie, und der nächste Beitrag war
 * rechtsbündig gesetzt. Beides zusammen ergab zwei Blöcke ohne erkennbaren
 * Zusammenhang: Die Linien lagen 18px versetzt zueinander, weil der
 * Blockabstand von Gutenberg auf das zweite Kind einen oberen Rand setzt, und
 * der rechtsbündige Titel lief auf einer eigenen Achse aus.
 *
 * Als gleich große Karten mit gemeinsamer linker Kante lesen sich beide als
 * ein Angebot - dieselbe Sprache wie die Karten auf der Startseite.
 */
.exo-article-navigation__links {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	margin-block-start: var(--component-gap-md);
	align-items: stretch;
}

.exo-article-navigation__links > div {
	min-inline-size: 0;
	margin-block: 0;
}

.exo-article-navigation__links a {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--20);
	block-size: 100%;
	min-block-size: var(--touch-target);
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface);
	color: var(--color-text);
	text-decoration: none;
	transition: border-color var(--duration-fast) var(--easing-standard);
}

.exo-article-navigation__links a:hover,
.exo-article-navigation__links a:focus-visible {
	border-color: var(--color-brand);
}

/* Die beiden Klassen entstehen im Core-Block `post-navigation-link` und
 * können deshalb nicht dem Themepräfix folgen. */
/* stylelint-disable selector-class-pattern */
.exo-article-navigation__links a:hover .post-navigation-link__title,
.exo-article-navigation__links a:focus-visible .post-navigation-link__title {
	text-decoration: underline;
	text-decoration-color: var(--color-brand);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.25em;
}

.exo-article-navigation__links .post-navigation-link__label {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 500;
	letter-spacing: 0.08em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
	color: var(--color-text-secondary);
}

.exo-article-navigation__links .post-navigation-link__title {
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 600;
	line-height: var(--line-height-ui);
}
/* stylelint-enable selector-class-pattern */

/*
 * Der Rückweg zur Übersicht schließt den Abschnitt ab und steht deshalb
 * abgesetzt unter den beiden Karten, nicht als dritte gleichrangige Fläche.
 */
.exo-article-navigation__overview {
	margin-block-start: var(--component-gap-md);
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--color-border);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
}

@media (width >= 48rem) {
	.exo-article-navigation__links {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--50);
	}
}

/* ------------------------------------------------------------------
 * Fußbereich
 * ------------------------------------------------------------------ */
/*
 * Der Fußbereich liegt auf derselben tiefsten Fläche wie die Einstiegszone.
 * Die Seite bekommt dadurch zwei gleiche dunkle Enden; alles dazwischen ist
 * Arbeitsfläche.
 */
.exo-footer {
	--rule: var(--color-border-dark);

	padding-block: var(--section-compact) var(--wp--preset--spacing--50);
	background-color: var(--color-surface-stage);
	color: var(--color-text-on-dark);
}

.exo-footer a:not(.wp-block-button__link) {
	color: var(--color-text-on-dark);
	text-decoration: none;
}

.exo-footer a:not(.wp-block-button__link):hover {
	text-decoration: underline;
	text-underline-offset: 0.3em;
}

/*
 * Die Spaltenköpfe sind Bezeichnungen, keine Aussagen – gesetzt wie die
 * Abschnittsmarken der Seite. Das nimmt ihnen Gewicht gegenüber den Zielen
 * darunter, um die es im Fußbereich tatsächlich geht.
 */
.exo-footer :is(h2, h3, h4) {
	color: var(--wp--preset--color--ink-300);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 500;
	letter-spacing: 0.14em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
	margin-block-end: var(--wp--preset--spacing--40);
}

/*
 * Die Linkgruppen sind semantisch Listen, optisch aber Navigation. Punkte vor
 * jedem Ziel tragen dort nichts bei und stören die linke Achse der Spalte.
 */
.exo-footer__grid ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--wp--preset--spacing--30);
}

.exo-footer__legal {
	gap: var(--wp--preset--spacing--40);
	margin-block-start: var(--wp--preset--spacing--60);
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--rule);
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
}

/* ------------------------------------------------------------------
 * Zitat
 * theme.json kennt in `styles.blocks` keine einzelnen Randseiten, deshalb
 * hier statt dort.
 * ------------------------------------------------------------------ */
.wp-block-quote {
	border-inline-start: 3px solid var(--color-brand);
	padding-inline-start: var(--wp--preset--spacing--50);
	font-style: normal;
}

.wp-block-quote cite {
	display: block;
	margin-block-start: var(--wp--preset--spacing--30);
	font-size: var(--wp--preset--font-size--sm);
	font-style: normal;
	color: var(--color-text-secondary);
}

/* ------------------------------------------------------------------
 * Projektanfrage
 * Die Auszeichnung stammt aus exostruct-core; hier steht ausschließlich
 * die Gestaltung. Siehe blocks/project-request/render.php.
 * ------------------------------------------------------------------ */
/* Zur Ausrichtung siehe die Begründung bei p.exo-lead in utilities.css. */
div.exo-request {
	max-inline-size: var(--container-text);
	margin-inline: 0 auto !important;
	padding: var(--wp--preset--spacing--50);
	background-color: var(--color-surface-subtle);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);

	/*
	 * Auch der Rahmen ist eine Spalte mit Abstand: Ohne ihn klebten Meldung,
	 * Vorgangskennung und Formular aneinander, und die Beschriftung der ersten
	 * Feldgruppe saß auf dem Kasten darüber.
	 */
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--50);

	/*
	 * Bezugsgröße der Container-Abfragen weiter unten. Sie steht hier und nicht
	 * an .exo-request__row: Eine Abfrage misst immer den nächsten Container
	 * *oberhalb* des Elements. Ein Element, das sich selbst zum Container
	 * erklärt, misst deshalb nie sich selbst – die Abfrage greift dann nie.
	 */
	container-type: inline-size;
}

/* --- Schritt 1: Auswahl der Anfrageart ----------------------------
 *
 * Große Flächen, keine Radioknöpfe. Die Auswahl ist die erste Handlung auf
 * dieser Seite und soll aus zwei Metern Entfernung als solche erkennbar sein;
 * ein Ring mit 16 px Durchmesser leistet das nicht.
 *
 * Es sind Verweise, keine Formularelemente: Die Auswahl ändert nichts, sie
 * führt weiter (siehe blocks/project-request/render.php). Deshalb tragen sie
 * auch keine Absendeschaltfläche - ein Klick genügt.
 * ---------------------------------------------------------------- */
.exo-request__choice {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
}

.exo-request__choice-title {
	margin-block: 0;
	font-size: var(--wp--preset--font-size--heading-3);
	letter-spacing: -0.02em;
}

.exo-request__choice-lead {
	max-inline-size: 62ch;
	margin-block: 0;
	color: var(--color-text-secondary);
}

.exo-request__options {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	margin-block: var(--wp--preset--spacing--30) 0;
	padding-inline-start: 0;
	list-style: none;
}

.exo-request__options > li {
	margin-block: 0;
}

/*
 * Die Fläche trägt die Bedienbarkeit, nicht der Titel darin: Der ganze Block
 * ist das Ziel, damit auf dem Telefon nicht eine Zeile Text getroffen werden
 * muss.
 */
/*
 * Das Zeichen steht in einer eigenen Spalte links, Titel und Text in der
 * zweiten. Es über den Titel zu setzen kostete auf dem Telefon eine Zeilenhöhe
 * je Karte, ohne die Unterscheidbarkeit zu verbessern - nebeneinander liest
 * sich die Karte als eine Aussage.
 */
.exo-request__option {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	gap: var(--wp--preset--spacing--10) var(--wp--preset--spacing--30);
	block-size: 100%;
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
	color: var(--color-text);
	text-decoration: none;
	transition: border-color var(--duration-fast) var(--easing-standard),
		box-shadow var(--duration-fast) var(--easing-standard);
}

/*
 * Dieselbe Geometrie wie die Einstiegswege der Startseite (AP-25): 24er-Raster,
 * `currentColor`, keine Hover-Reaktion - das Zeichen benennt den Weg, es ist
 * nicht die Handlung.
 */
.exo-request__option-icon {
	grid-row: span 2;
	inline-size: var(--wp--custom--icon--orientation);
	block-size: var(--wp--custom--icon--orientation);
	flex: none;
	color: var(--color-brand-hover);
	fill: none;
	stroke: currentcolor;
	stroke-width: 1.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.exo-request__option:hover,
.exo-request__option:focus-visible {
	border-color: var(--color-border-strong);
	box-shadow: var(--shadow-sm);
}

/*
 * Der Pfeil steht am Titel, nicht am Fuß der Fläche: Er gehört zur Aussage
 * „hier geht es weiter" und wandert sonst bei unterschiedlich langen
 * Beschreibungen auf verschiedene Höhen.
 */
.exo-request__option-title {
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 600;
	line-height: var(--line-height-ui);
}

.exo-request__option-title::after {
	content: " →";
	color: var(--color-brand-hover);
}

.exo-request__option-text {
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

@container (width >= 34rem) {
	.exo-request__options {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* --- Schritt 2: Kopf des gewählten Formulars ---------------------- */
.exo-request__intro {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--20);
}

.exo-request__title {
	margin-block: 0;
	font-size: var(--wp--preset--font-size--heading-3);
	letter-spacing: -0.02em;
}

.exo-request__intro .exo-lead {
	max-inline-size: 62ch;
	margin-block: 0;
}

/*
 * Der Rückweg steht oben und nicht unter dem Formular: Wer merkt, dass er
 * falsch abgebogen ist, merkt es beim Lesen der Einleitung - nicht nach dem
 * Ausfüllen.
 */
.exo-request__switch {
	margin-block: var(--wp--preset--spacing--20) 0;
	font-size: var(--wp--preset--font-size--sm);
}

/*
 * Ohne diese Regel stehen die Felder eines Formulars ohne Gruppen unmittelbar
 * aneinander: Der Abstand käme sonst allein von fieldset.exo-request__group.
 */
.exo-request__form {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--50);
}

.exo-request__group {
	/* Der Standardrahmen von fieldset wirkt schwer und folgt keinem Token. */
	border: 0;
	border-block-start: 1px solid var(--color-border);
	padding: 0;
	/* Der Abstand davor kommt aus dem Gap des Formulars. */
	margin: 0;
	padding-block-start: var(--wp--preset--spacing--50);
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--50);
}

.exo-request__group legend {
	padding: 0;
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 600;
	line-height: var(--line-height-ui);
}

/*
 * Container Query statt Viewport-Abfrage: Das Formular steht je nach Seite in
 * unterschiedlich breiten Bereichen. Der Container ist div.exo-request.
 *
 * Ausrichtung an der Oberkante: Beschriftung, Hilfetext und Eingabe jedes
 * Feldes sind eigene Zeilenspuren dieser Reihe (AP-18). Trägt nur eines der
 * beiden Felder einen Hinweistext, bleibt die ungenutzte Spur beim
 * Nachbarfeld leer, statt dass sich dessen Beschriftung oder Eingabe
 * verschiebt – beide Zeilen bleiben in jedem Fall gemeinsam ausgerichtet.
 */
.exo-request__row {
	display: grid;
	grid-template-rows: auto auto auto;
	gap: var(--wp--preset--spacing--50);
	align-items: start;
}

@container (width >= 34rem) {
	.exo-request__row {
		grid-template-columns: 1fr 1fr;
	}

	/*
	 * Drei statt zwei Spalten für kurze Angaben, die zusammengehören - im
	 * Widerrufsformular Bestellnummer, Bestell- und Empfangsdatum. Als
	 * halbbreite Felder wären sie doppelt so breit wie ihr Inhalt und ließen
	 * die Reihe leer wirken.
	 */
	.exo-request__row--three {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.exo-request__row > .exo-field {
	/* Fallback für Browser ohne Subgrid, ausschlaggebend ist die Zeile darunter. */
	grid-template-rows: auto auto auto;
	grid-template-rows: subgrid;
	grid-row: span 3;
	display: grid;
}

.exo-request__row > .exo-field > .exo-field__label {
	grid-row: 1;
}

.exo-request__row > .exo-field > .exo-field__hint {
	grid-row: 2;
}

.exo-request__row > .exo-field > :where(input, select, textarea) {
	grid-row: 3;
}

/* ------------------------------------------------------------------
 * Verknüpfte Inhalte
 * Liste statt Karten: Verknüpfungen sind Verweise, keine Werbeflächen.
 * Ein Raster aus Bildkarten zöge die Aufmerksamkeit vom Inhalt der Seite ab.
 * ------------------------------------------------------------------ */
.exo-related {
	display: grid;
	gap: var(--wp--preset--spacing--70);
	margin-block-start: var(--wp--preset--spacing--70);
	padding-block-start: var(--wp--preset--spacing--60);
	border-block-start: 1px solid var(--color-border);
}

/*
 * Bewusst eine Viewport-Abfrage und keine Container-Abfrage: Der Block steht
 * im Inhaltsbereich einer Detailseite, und dort gibt es keinen Vorfahren mit
 * `container-type`. Eine Container-Abfrage misst aber immer den nächsten
 * Container *oberhalb* – ohne einen solchen träfe sie nie zu.
 */
@media (width >= 48rem) {
	.exo-related:has(.exo-related__group + .exo-related__group) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--60);
	}
}

.exo-related__title {
	font-size: var(--wp--preset--font-size--lg);
	line-height: var(--line-height-ui);
	margin-block-end: var(--wp--preset--spacing--40);
}

.exo-related__list {
	list-style: none;
	padding: 0;
	margin: 0;
	display: grid;
	gap: var(--wp--preset--spacing--40);
}

.exo-related__item {
	display: grid;
	gap: var(--wp--preset--spacing--10);
}

.exo-related__link {
	font-weight: 500;
	text-underline-offset: 0.25em;
}

.exo-related__excerpt {
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
}

/*
 * Vorgangskennung über dem Stammdatenformular. Sie beantwortet die erste
 * Frage, die ein Kunde beim Öffnen eines persönlichen Links hat: Wozu gehört
 * das hier?
 */
.exo-customer-data__reference {
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border-inline-start: 3px solid var(--color-brand);
	background-color: var(--color-surface-subtle);
	font-size: var(--wp--preset--font-size--sm);
}

/* ------------------------------------------------------------------
 * Bewertungsskala
 * Radiogruppe statt Auswahlliste oder Sternen: fünf Stufen sind auf einen
 * Blick erfassbar, die Bedeutung beider Enden steht dauerhaft dabei, und
 * jede Stufe ist einzeln per Tastatur erreichbar. Sterne wären hübscher
 * und für Screenreader wertlos.
 * ------------------------------------------------------------------ */
.exo-scale {
	border: 0;
	padding: 0;
	margin: 0;
}

/*
 * Fünf feste Spalten statt umbrechender Flexbox: Bei schmalen Geräten brach
 * die Skala sonst nach der vierten Stufe um, und die „5“ stand allein über
 * die ganze Breite. Eine Ordinalskala, die in zwei Zeilen zerfällt, wird als
 * zwei Gruppen gelesen und die letzte Stufe optisch überbetont.
 */
.exo-scale__options {
	display: grid;
	grid-template-columns: repeat(5, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--10);
	margin-block-start: var(--wp--preset--spacing--30);
}

@media (width >= 30rem) {
	.exo-scale__options {
		gap: var(--wp--preset--spacing--20);
	}
}

.exo-scale__option {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--wp--preset--spacing--10);
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--20);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface);
	text-align: center;
	cursor: pointer;
	transition: border-color var(--duration-fast) var(--easing-standard),
		background-color var(--duration-fast) var(--easing-standard);
}

.exo-scale__option:hover {
	border-color: var(--color-border-strong);
}

/*
 * Die Auswahl wird nicht allein über Farbe angezeigt: Der Rahmen wird
 * kräftiger und der Wert fett. Damit bleibt sie auch bei Farbenblindheit
 * und im erzwungenen Farbmodus erkennbar.
 */
.exo-scale__option:has(input:checked) {
	border-color: var(--color-brand);
	border-width: 2px;
	padding: calc(var(--wp--preset--spacing--30) - 1px) calc(var(--wp--preset--spacing--20) - 1px);
	background-color: var(--color-surface-subtle);
}

.exo-scale__option:has(input:checked) .exo-scale__value {
	font-weight: 700;
}

.exo-scale__option:has(input:focus-visible) {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

/*
 * Der Radiobutton selbst wird verborgen, nicht entfernt: Er bleibt für
 * Tastatur und Screenreader vorhanden, die ganze Fläche ist sein Label.
 */
.exo-scale__option input[type="radio"] {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	opacity: 0;
	pointer-events: none;
}

.exo-scale__value {
	font-size: var(--wp--preset--font-size--lg);
	line-height: var(--line-height-ui);
}

/*
 * Die Bedeutung der Enden steht unter der Skala, nicht in den Schaltflächen.
 * In einer Fünftelbreite musste „unwahrscheinlich“ sonst mitten im Wort
 * brechen – ohne Trennstrich, weil Silbentrennung nicht überall verfügbar
 * ist. Unter der Skala ist Platz, und die Skala liest sich als Kontinuum von
 * links nach rechts. Vorgelesen wird die Bedeutung über aria-label am
 * jeweiligen Bedienelement.
 */
.exo-scale__ends {
	display: flex;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--40);
	margin-block-start: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--xs);
	color: var(--color-text-secondary);
}

.exo-scale__ends .exo-scale__end:last-child {
	text-align: end;
}

.exo-field--check label {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: var(--wp--preset--spacing--30);
	align-items: start;
	cursor: pointer;
}

.exo-field--check input[type="checkbox"] {
	/* Ausrichtung an der ersten Textzeile statt an der Boxmitte. */
	margin-block-start: 0.25em;
	inline-size: 1.15rem;
	block-size: 1.15rem;
	min-block-size: 0;
}

.exo-request input[type="file"] {
	padding: var(--wp--preset--spacing--30);
	border: 1px dashed var(--color-border-strong);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface);
	inline-size: 100%;
}

.exo-request input[type="file"]::file-selector-button {
	margin-inline-end: var(--wp--preset--spacing--40);
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-pill);
	background-color: var(--color-surface);
	font-weight: 600;
	cursor: pointer;
}

.exo-request__submit {
	margin: 0;
	margin-block-start: var(--wp--preset--spacing--20);
}

.exo-request__submit button {
	padding: 0.75rem 1.5rem;
	border: 0;
	border-radius: var(--radius-pill);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-weight: 600;
}

.exo-request__submit button:hover {
	background-color: var(--color-brand-hover);
}

/* ------------------------------------------------------------------
 * Suchfeld
 *
 * Eingabe und Schaltfläche sind ein zusammengehöriges Bedienelement und
 * tragen deshalb dieselbe Rundung. Dieselbe Gestalt benutzt die Produktsuche
 * im Shop-Einstieg; die Rolle ist dieselbe, nur die Fläche darunter wechselt.
 * ------------------------------------------------------------------ */
.exo-listing__search {
	display: block;
	margin-block: var(--component-gap-md);
}

.exo-search {
	max-inline-size: var(--container-text);
}

.exo-search__label {
	display: block;
	margin-block-end: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
}

/*
 * Ein Bedienelement, nicht zwei nebeneinander.
 *
 * Zuvor standen ein umrandetes Eingabefeld und eine abgesetzte Schaltfläche
 * nebeneinander - zwei Rahmen, zwei Rundungen, ein Spalt dazwischen. Jetzt
 * trägt der Rahmen die ganze Zeile: Lupe, Eingabe und Aktion liegen darin und
 * lesen sich als eine Suche. Der Rahmen reagiert auf `:focus-within`, sodass
 * die Tastaturbedienung die gesamte Zeile markiert und nicht nur das Feld.
 */
.exo-search__control {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr) auto;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--10)
		var(--wp--preset--spacing--10) var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-pill);
	background-color: var(--color-surface);
	transition: border-color var(--duration-fast) var(--easing-standard);
}

.exo-search__control:focus-within {
	border-color: var(--color-brand);
}

.exo-search__icon {
	inline-size: 1.25rem;
	block-size: 1.25rem;
	color: var(--color-text-muted);
	fill: none;
	stroke: currentcolor;
	stroke-width: 1.75;
	stroke-linecap: round;
}

/*
 * Das Feld bringt keinen eigenen Rahmen mehr mit; der Rahmen ist die Zeile.
 * Der Fokusring wird deshalb ebenfalls unterdrückt - er läge sonst innerhalb
 * der markierten Zeile ein zweites Mal an.
 */
.exo-search__input {
	min-inline-size: 0;
	min-block-size: var(--control-standard);
	padding: 0;
	border: 0;
	background-color: transparent;
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--base);
}

.exo-search__input:focus,
.exo-search__input:focus-visible {
	outline: none;
}

.exo-search__input::placeholder {
	color: var(--color-text-muted);
}

.exo-search__submit {
	min-block-size: var(--control-compact);
	padding-inline: var(--wp--preset--spacing--50);
	border: 0;
	border-radius: var(--radius-pill);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	cursor: pointer;
}

.exo-search__submit:hover {
	background-color: var(--color-brand-hover);
}

/* ------------------------------------------------------------------
 * Suchfeld aus dem Kernblock
 *
 * Zwei Stellen benutzen den Kernblock `wp:search` statt des eigenen Musters
 * der Wissenssuche: die Trefferseite (`templates/search.html`), weil der Block
 * den Suchbegriff bereits ausgefüllt mitbringt, und die 404-Seite
 * (`templates/404.html`), wo die Suche der nächste Schritt nach einer ins
 * Leere laufenden Adresse ist.
 *
 * Ungestylt liefert der Block ein scharfkantiges Feld mit abgesetzter
 * Schaltfläche daneben: dieselbe Suche wie im Kopfbereich und in der
 * Wissenssuche, aber in einer dritten Gestalt - und das ausgerechnet dort, wo
 * jemand gerade nicht gefunden hat, was er suchte. Diese Regeln geben ihm die
 * Form der beiden anderen: eine durchgehend gerundete Zeile, deren Rahmen Feld
 * und Aktion umfasst.
 *
 * Der Aufbau folgt `.exo-shop-search` (woocommerce.css), weil dort derselbe
 * Kernblock in dieselbe Form gebracht wird; nur die Fläche darunter ist hell
 * statt dunkel.
 * ------------------------------------------------------------------ */
.exo-search-block {
	margin-block: var(--component-gap-md);
}

/*
 * Die Breitenbegrenzung sitzt auf der Bedienzeile, nicht auf dem Block.
 *
 * Am Block selbst zog WordPress sie in die Mitte: Ein eingeschränktes Layout
 * setzt seinen Kindern `margin-left: auto; margin-right: auto !important`, und
 * ein Kind, das schmaler ist als der Container, landet damit mittig - während
 * Überschrift und Trefferliste daneben an der linken Containerkante stehen.
 * Sichtbar war das als ein Suchfeld, das gegenüber allem anderen der Seite
 * eingerückt war. Bleibt der Block so breit wie der Container, greift dessen
 * Zentrierung ins Leere, und die Zeile darin beginnt links wie alles andere.
 */
.exo-search-block .wp-block-search__inside-wrapper {
	max-inline-size: var(--container-text);
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--10)
		var(--wp--preset--spacing--10) 2.75rem;
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-pill);
	background-color: var(--color-surface);
	transition: border-color var(--duration-fast) var(--easing-standard);
}

.exo-search-block .wp-block-search__inside-wrapper:focus-within {
	border-color: var(--color-brand);
}

/* Lupe als Maske: eine Form, keine zweite Datei und kein Zeichensatz. */
.exo-search-block .wp-block-search__inside-wrapper::before {
	content: "";
	position: absolute;
	inset-inline-start: var(--wp--preset--spacing--40);
	inline-size: 1.25rem;
	block-size: 1.25rem;
	background-color: var(--color-text-muted);
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='m15.5 15.5 4.5 4.5'/%3E%3C/svg%3E");
	mask-repeat: no-repeat;
	mask-size: contain;
}

.exo-search-block .wp-block-search__input {
	min-inline-size: 0;
	min-block-size: var(--control-standard);
	padding: 0;
	border: 0;
	border-radius: 0;
	background-color: transparent;
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--base);
}

.exo-search-block .wp-block-search__input:focus,
.exo-search-block .wp-block-search__input:focus-visible {
	outline: none;
}

.exo-search-block .wp-block-search__input::placeholder {
	color: var(--color-text-muted);
}

.exo-search-block .wp-block-search__button {
	min-block-size: var(--control-compact);
	margin: 0;
	padding-inline: var(--wp--preset--spacing--50);
	border: 0;
	border-radius: var(--radius-pill);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
}

.exo-search-block .wp-block-search__button:hover {
	background-color: var(--color-brand-hover);
}

/* ------------------------------------------------------------------
 * Archiv- und Wissenskarten
 * Materialien, Verfahren, Modelle, Projekte und Fachbeiträge sind jeweils
 * eigenständige Ziele. Ein gemeinsamer Kartenrahmen bindet Bild, Titel und
 * Auszug zusammen; ohne zusätzliche Dekoration oder Bewegung.
 * ------------------------------------------------------------------ */
.exo-listing .wp-block-post-template {
	gap: var(--wp--preset--spacing--50);
	align-items: stretch;
}

/*
 * `margin-block: 0` überschreibt den Kernabstand von `is-layout-flow`.
 *
 * Diese Auflistungen laufen als Query-Loop mit `"layout":{"type":"default"}`
 * (Flow-Layout), aber mit selbst gebautem CSS-Grid statt WordPress' nativem
 * Grid-Layout. Der Kern setzt in einem Flow allen Kindern außer dem ersten
 * einen `margin-block-start`; das addiert sich zum eigenen `gap` und
 * verschiebt jede zweite Karte einer Zeile nach unten, ohne die Zeile selbst
 * zu strecken - der Effekt sichtbar erst bei zwei Karten nebeneinander, im
 * Portfolio also in jeder Zeile außer der letzten unvollständigen.
 */
.exo-listing .wp-block-post-template > li {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
	margin-block: 0;
	padding: var(--wp--preset--spacing--40);
	background-color: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	transition: border-color var(--duration-fast) var(--easing-standard);
}

.exo-listing .wp-block-post-template > li:hover,
.exo-listing .wp-block-post-template > li:focus-within {
	border-color: var(--color-border-strong);
}

.exo-listing .wp-block-post-template > li > * {
	margin-block-start: 0 !important;
}

.exo-listing .wp-block-post-featured-image {
	margin: 0;
	overflow: hidden;
	border-radius: var(--radius-sm);
}

.exo-listing .wp-block-post-title {
	line-height: var(--line-height-ui);
}

.exo-listing .wp-block-post-title a {
	color: var(--color-text);
	text-decoration: none;
}

.exo-listing .wp-block-post-title a::after {
	content: " →";
	color: var(--color-brand);
}

.exo-listing .wp-block-post-title a:hover,
.exo-listing .wp-block-post-title a:focus-visible {
	text-decoration: underline;
	text-decoration-color: var(--color-brand);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.25em;
}

.exo-listing .wp-block-post-excerpt {
	color: var(--color-text-secondary);
}

/* ------------------------------------------------------------------
 * Materialübersicht: Zeilen statt Karten
 *
 * Sieben Werkstoffe in drei Kartenspalten ließen die letzte Reihe mit einer
 * einzelnen Karte stehen. Vor allem aber verglich das Raster Bilder: Die
 * Aufnahme lag oben und breit, die Angaben darunter klein. Verglichen wird
 * hier jedoch der Auszug - er nennt Hitzebeständigkeit und Eignung. In
 * Zeilen stehen diese Auszüge exakt untereinander und lassen sich senkrecht
 * durchlesen.
 * ------------------------------------------------------------------ */
/*
 * Kein Abstand über der Liste.
 *
 * Zwei Quellen speisten ihn: der Blockabstand von WordPress am Abfrageblock
 * (`margin-block-start: var(--wp--preset--spacing--50)`) und der untere Rand
 * der Auswahlhilfe. Beide fielen zusammen, weil benachbarte Ränder
 * verschmelzen - sichtbar waren 64 px, und das Entfernen einer der beiden
 * Quellen allein hätte daran nichts geändert.
 *
 * Die Liste beginnt mit einer Trennlinie und braucht davor keinen
 * Abschnittsabstand: Die Linie grenzt bereits ab.
 *
 * `.exo-listing` gehört zwingend in den Selektor: Die Klasse `.exo-materials`
 * trägt auch der gleichnamige Abschnitt der Startseite, und dort standen die
 * beiden Abfrageblöcke - Verfahrenskarten und Werkstoffliste - danach ohne
 * jeden Abstand aufeinander. Die Beschriftung „Werkstoffe" klebte an der
 * Unterkante der letzten Verfahrenskarte.
 */
.exo-listing.exo-materials .wp-block-query,
.exo-listing.exo-materials .exo-material-rows,
.exo-listing.exo-materials .exo-material-rows > li {
	margin-block-start: 0 !important;
}

/*
 * Der Abstand unter der Auswahlhilfe kommt allein von ihr.
 *
 * Die Liste hat oben keinen Rand (siehe oben), also entscheidet der untere
 * Rand der Auswahlhilfe über den ganzen Zwischenraum. Er stand zeitweise auf
 * 0: Dann berührte die Trennlinie der ersten Zeile fast die Kante der
 * Werkzeugfläche, und beide lasen sich als ein Element. Ein Rand in
 * Abschnittsgröße trennt das Werkzeug wieder von der Liste, ohne den doppelten
 * Abstand von früher zurückzuholen.
 */
.exo-listing.exo-materials .exo-finder {
	margin-block-end: var(--component-gap-lg);
}

.exo-listing .wp-block-post-template.exo-material-rows {
	gap: 0;
	border-block-start: 1px solid var(--color-border);
}

.exo-listing .wp-block-post-template.exo-material-rows > li {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--wp--preset--spacing--40);
	align-items: center;
	padding: var(--wp--preset--spacing--50) 0;
	background: none;
	border: 0;
	border-block-end: 1px solid var(--color-border);
	border-radius: 0;
}

/*
 * Die Zeile hebt sich beim Zeigen an, ohne ihre Kanten zu verschieben: Ein
 * Rahmenwechsel wie bei den Karten hätte die Trennlinien der Nachbarzeilen
 * mitgezogen.
 */
.exo-listing .wp-block-post-template.exo-material-rows > li:hover,
.exo-listing .wp-block-post-template.exo-material-rows > li:focus-within {
	border-color: var(--color-border);
	background-color: var(--color-surface-subtle);
}

.exo-material-rows .exo-material-row__media {
	overflow: hidden;
	inline-size: 100%;
	border-radius: var(--radius-sm);
}

.exo-material-rows .exo-material-row__media img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

.exo-material-row__text {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	min-inline-size: 0;
}

.exo-material-row__text > * {
	margin-block: 0 !important;
}

.exo-material-rows .wp-block-post-excerpt p {
	max-inline-size: 68ch;
	margin-block: 0;
	line-height: var(--line-height-ui);
}

@media (width >= 48rem) {
	/*
	 * Das Bild bleibt Wiedererkennung, nicht Bühne: 12 rem sind breit genug,
	 * um Farbe und Oberfläche zu zeigen, und schmal genug, dass der Auszug
	 * die Zeile führt.
	 */
	.exo-listing .wp-block-post-template.exo-material-rows > li {
		grid-template-columns: 12rem minmax(0, 1fr);
		gap: var(--component-gap-md);
	}
}

/* ------------------------------------------------------------------
 * Anfrage- und Kontaktseite: Formular mit Begleitspalte
 *
 * Beide Seiten bestanden aus Einleitung und Formular in einem 80-rem-Container;
 * die rechte Hälfte blieb leer - ausgerechnet dort, wo die Fragen auftauchen,
 * die vom Absenden abhalten (Was muss ich mitschicken? Was passiert mit meiner
 * Datei? Passt mein Bauteil?).
 *
 * Die Spalte ist bewusst keine Wiederholung des Formulars in Worten, sondern
 * trägt die Angaben, die den Absendevorgang betreffen. Auf schmalen
 * Bildschirmen steht sie unter dem Formular: Erst die Aufgabe, dann die
 * Erläuterung.
 * ------------------------------------------------------------------ */
/* ------------------------------------------------------------------
 * Hinweis auf das Sofortangebot über der Anfrageauswahl (AP-42, OF-27)
 *
 * Derselbe Rahmen und dieselbe Breite wie der Kasten der Anfrageauswahl
 * darunter (`div.exo-request`): Beide sind Container derselben Ordnung auf
 * derselben Seite, und zwei verschiedene Rahmenstärken behaupteten einen
 * Unterschied, den es nicht gibt.
 *
 * Die Fläche bleibt offen. Der Kasten steht auf dem Seitengrund statt auf
 * einem eigenen Grauton; die Kante trägt der Rahmen allein.
 * ------------------------------------------------------------------ */
.exo-teaser {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	max-inline-size: var(--container-text);
	margin-block: var(--component-gap-md) !important;
	margin-inline: 0 auto !important;
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: transparent;
}

.exo-teaser__kopf {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	gap: var(--wp--preset--spacing--30);
	align-items: start;
}

.exo-teaser__kopf > div > * {
	margin-block: 0;
}

.exo-teaser__icon {
	inline-size: var(--wp--custom--icon--orientation);
	block-size: var(--wp--custom--icon--orientation);
	flex: none;
	fill: none;
	stroke: currentcolor;
	stroke-width: 1.5;
	stroke-linecap: round;
	stroke-linejoin: round;
	color: var(--color-brand);
}

.exo-teaser__titel {
	margin-block: 0.15rem 0 !important;
	font-size: var(--wp--preset--font-size--lg);
	letter-spacing: -0.01em;
}

.exo-teaser__lead {
	max-inline-size: 62ch;
	margin-block-start: var(--wp--preset--spacing--20) !important;
	color: var(--color-text-secondary);
}

/*
 * Zwei Spalten ab 34rem, darunter untereinander. Die Abgrenzung ist die halbe
 * Aussage; sie darf auf dem Telefon nicht wegfallen, nur weil sie dort
 * untereinander steht.
 */
.exo-teaser__spalten {
	display: grid;
	gap: var(--wp--preset--spacing--40);
}

@media (width >= 34rem) {
	.exo-teaser__spalten {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

.exo-teaser__spalte-titel {
	margin-block: 0 var(--wp--preset--spacing--20) !important;
	font-family: var(--wp--preset--font-family--mono, inherit);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--color-text-muted);
}

.exo-teaser__liste {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin-block: 0;
	padding-inline-start: 0;
	list-style: none;
}

.exo-teaser__liste li {
	position: relative;
	padding-inline-start: 1.5rem;
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

/*
 * Haken und Strich stehen für „geeignet" und „nicht geeignet" und tragen damit
 * Information — sie sind keine Aufzählungspunkte in Verkleidung. Als
 * Pseudoelement, damit sie nicht in der Vorlesereihenfolge landen; die
 * Zwischenüberschrift sagt bereits, welche Spalte man liest.
 */
.exo-teaser__liste li::before {
	position: absolute;
	inset-inline-start: 0;
	font-weight: 700;
}

.exo-teaser__liste--ja li::before {
	content: "✓";
	color: var(--color-success, #16803c);
}

.exo-teaser__liste--nein li::before {
	content: "–";
	color: var(--color-text-muted);
}

/*
 * Die Formatliste ist der Grund, warum STEP überhaupt gewählt wird: Steht in
 * einem Fließtext „STL, 3MF und andere", liest niemand STEP mit. Als eigene
 * Liste mit Zusatz je Gruppe ist die Reihenfolge selbst eine Empfehlung.
 */
.exo-teaser__formate {
	padding-block-start: var(--wp--preset--spacing--30);
	border-block-start: 1px solid var(--color-border);
}

.exo-teaser__formatliste {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	margin-block: 0;
	padding-inline-start: 0;
	list-style: none;
}

.exo-teaser__formatliste li {
	display: flex;
	flex-direction: column;
}

.exo-teaser__format {
	font-family: var(--wp--preset--font-family--mono, inherit);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	color: var(--color-text);
}

.exo-teaser__formathinweis {
	font-size: var(--wp--preset--font-size--xs);
	color: var(--color-text-muted);
}

.exo-teaser__fussnote {
	max-inline-size: 72ch;
	margin-block: var(--wp--preset--spacing--30) 0 !important;
	color: var(--color-text-muted);
	font-size: var(--wp--preset--font-size--xs);
	line-height: var(--line-height-ui);
}

@media (width < 34rem) {
	.exo-teaser__kopf {
		grid-template-columns: minmax(0, 1fr);
	}
}

.exo-request-layout {
	display: grid;
	gap: var(--component-gap-lg);
	align-items: start;
	margin-block-start: var(--component-gap-md) !important;
}

/*
 * Der Blockabstand von Gutenberg setzt auf jedes Kind außer dem ersten einen
 * oberen Rand. In einer Rasterzeile verschiebt der die zweite Spalte gegenüber
 * der ersten - die Randspalte begann dadurch 24 px unter der Überschrift,
 * obwohl beide in derselben Zeile stehen. Derselbe Fall wie bei
 * `.exo-about__grid` weiter unten; der Abstand kommt bereits aus `gap`.
 */
.exo-request-layout > * {
	margin-block: 0 !important;
}

/*
 * Die Formularspalte hat einen eigenen Rhythmus, statt ihn dem Zufall zu lassen.
 *
 * Hier stand nur `margin-block: 0` - der Blockabstand von Gutenberg war damit
 * abgeschaltet und nichts trat an seine Stelle: Die Einleitung klebte an der
 * Überschrift (0 px), während sie auf jeder anderen Seite 24 px Abstand hat, und
 * die Abstände über den beiden Containern kamen aus deren eigenen Regeln.
 * Gemeldet vom Auftraggeber am 2026-08-16.
 *
 * Jetzt eine Spalte mit `gap`: ein Abstand für alle Kinder, und die beiden
 * Container bekommen zusätzlich Luft nach oben - sie sind Abschnitte, keine
 * Absätze.
 */
.exo-request-layout__form > * {
	margin-block: 0 !important;
}

/*
 * Der Rhythmus über Ränder und **nicht** über eine Flex-Spalte mit `gap`.
 *
 * Flex war der erste Versuch und brach das Formular: `div.exo-request` trägt
 * `margin-inline: 0 auto`, und ein automatischer Rand in der Querachse eines
 * Flex-Containers verhindert das Dehnen. Aus 350 px wurden 50 px, der
 * Absendeknopf schrumpfte von 300 px auf 48 px - gemessen auf /kontakt/ bei
 * 390 px, gefunden von der Layoutprüfung, nicht von mir.
 *
 * Im Blockfluss bedeutet derselbe automatische Rand nichts: Ein Blockelement mit
 * `inline-size: auto` bleibt voll breit. Deshalb hier Ränder statt `gap`.
 */
.exo-request-layout__form > * + * {
	margin-block-start: var(--wp--preset--spacing--50) !important;
}

/* Die beiden Container sind Abschnitte, keine Absätze - sie bekommen mehr Luft. */
.exo-request-layout__form > :is(.exo-offer-teaser, .exo-request, .exo-request__choice) {
	margin-block-start: var(--wp--preset--spacing--60) !important;
}

.exo-request-aside {
	display: grid;
	gap: var(--wp--preset--spacing--50);
}

.exo-request-aside__card {
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
}

.exo-request-aside__card > * {
	margin-block: 0 !important;
}

.exo-request-aside__card > * + * {
	margin-block-start: var(--wp--preset--spacing--30) !important;
}

.exo-request-aside__card :is(p, li) {
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-request-aside__card ul {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	padding-inline-start: 1.1rem;
}

.exo-request-aside__card li {
	margin-block: 0;
}

.exo-request-aside__card strong {
	color: var(--color-text);
}

/*
 * Die drei Schritte und die Kennwerte tragen ihre Aussage im Satzanfang und
 * brauchen keinen Aufzählungspunkt davor - er stünde vor einer Überschrift
 * in Satzform.
 */
.exo-request-aside__steps,
.exo-request-aside__facts,
.exo-request-aside__links {
	padding-inline-start: 0 !important;
	list-style: none;
}

.exo-request-aside__facts > li > strong {
	display: block;
	color: var(--color-text-muted);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.exo-request-aside__links > li {
	padding-block-end: var(--wp--preset--spacing--30);
	border-block-end: 1px solid var(--color-border);
}

.exo-request-aside__links > li:last-child {
	padding-block-end: 0;
	border-block-end: 0;
}

.exo-request-aside__note {
	color: var(--color-text-muted) !important;
	font-size: var(--wp--preset--font-size--xs) !important;
}

.exo-request-aside__card--contact {
	border-color: var(--color-border-strong);
	background-color: var(--color-surface-subtle);
}

@media (width >= 64rem) {
	/*
	 * Zwei Drittel für die Aufgabe, ein Drittel für die Auskunft. Das
	 * Formular behält damit die Breite, in der seine zweispaltigen Reihen
	 * greifen (Container-Abfrage bei 34 rem).
	 */
	.exo-request-layout {
		grid-template-columns: minmax(0, 2fr) minmax(18rem, 1fr);
	}

}

/*
 * Bewusst nicht klebend.
 *
 * Ein `position: sticky` mit begrenzter Höhe war der erste Versuch: Die Spalte
 * ist mit sechs Karten höher als der Bildschirm, und die letzten drei
 * verschwanden hinter einer inneren Bildlaufleiste - Inhalt, den niemand
 * findet. Die Spalte läuft deshalb mit der Seite.
 */

/* ------------------------------------------------------------------
 * Portfolio
 *
 * Die Vorhaben sind Demonstrationsbeispiele, solange keine Fotos und keine
 * geklärten Bildrechte vorliegen (OF-10). Zwei Dinge folgen daraus für die
 * Gestaltung:
 *
 * 1. Der Hinweis darauf ist keine Fußnote. Er steht vor den Karten und
 *    bekommt eine eigene Fläche - wer ihn übersieht, hält die Beispiele
 *    für ausgeführte Aufträge.
 * 2. Die Bildfläche ist ein ausgewiesener Platzhalter, kein Stockfoto. Sie
 *    hält die Kartenhöhe und verschwindet, sobald ein Beitragsbild da ist.
 * ------------------------------------------------------------------ */
.exo-demo-note {
	max-inline-size: var(--container-text);
	margin-block-start: var(--component-gap-md) !important;
	padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--50);
	border-inline-start: 3px solid var(--color-brand);
	background-color: var(--color-surface-brand);
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-demo-note strong {
	color: var(--color-text);
}

.exo-demo-note--listing {
	max-inline-size: 78ch;
	margin-block-end: var(--component-gap-md) !important;
}

.exo-project-cards {
	display: grid;
	gap: var(--component-gap-md);
}

/*
 * Die Trefferliste braucht dieselbe Erklärung wie die Projektkarten: Der
 * Query-Loop läuft im Flow-Layout, und `.exo-listing .wp-block-post-template`
 * setzt dort zwar ein `gap`, das im Flow aber wirkungslos bleibt. Zusammen mit
 * dem `margin-block: 0` der Karten stießen die Treffer unmittelbar
 * aneinander - eine durchgehende Fläche aus Rahmen statt einer Liste einzeln
 * ansteuerbarer Ziele. Als Grid greift das gemeinsame `gap`.
 */
.exo-search-results {
	display: grid;
	gap: var(--wp--preset--spacing--50);
}

.exo-listing .wp-block-post-template.exo-project-cards > li {
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--50);
}

/*
 * Platzhalter statt Foto.
 *
 * Die Schraffur ist bewusst grob und die Beschriftung bleibt lesbar: Die
 * Fläche soll nicht wie ein ladendes Bild aussehen, sondern wie eine
 * Leerstelle, die noch gefüllt wird.
 */
.exo-project__media {
	display: grid;
	place-items: center;
	aspect-ratio: 3 / 2;
	border: 1px dashed var(--color-border-strong);
	border-radius: var(--radius-sm);
	background-image: repeating-linear-gradient(
		135deg,
		var(--color-surface-subtle) 0 10px,
		var(--color-surface) 10px 20px
	);
}

.exo-project__media-label {
	color: var(--color-text-muted);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

/*
 * Gemeinsame Hülle für Platzhalter, Bild und Kennzeichnung.
 *
 * `position: relative`, damit die Kennzeichnung unten links im Bild sitzen
 * kann statt darunter - sie beschriftet die Fläche, sie ist kein eigener
 * Absatz im Textfluss.
 */
.exo-project__figure {
	position: relative;
	margin-block: 0 !important;
}

/*
 * Liegt ein Beitragsbild vor, weicht der Platzhalter. `:has()` erspart hier
 * eine Bedingung in der Vorlage - Blockvorlagen kennen keine.
 */
.exo-project__figure:has(.exo-project__photo img) .exo-project__media {
	display: none;
}

/*
 * Kennzeichnung der Bilder.
 *
 * Die Portfolio-Bilder sind erzeugte Darstellungen, keine Aufnahmen der
 * beschriebenen Vorhaben. Ohne Hinweis stünden sie als Beleg für ausgeführte
 * Arbeiten da - der Hinweis gehört deshalb sichtbar in das Bild, nicht in
 * eine leicht überlesene Fußnote darunter.
 *
 * Als Schild unten links, wie eine Bildunterschrift in der Fotografie: dunkler
 * Grund unabhängig von der Bildhelligkeit, damit der Text auf jedem Motiv
 * lesbar bleibt, ohne das ganze Bild abzudunkeln.
 *
 * Umgekehrte Bedingung zur Platzhalterregel darüber: sichtbar nur dort, wo
 * tatsächlich ein Bild liegt. Über der Platzhalterfläche „Foto folgt" wäre
 * die Kennzeichnung eines nicht vorhandenen Bildes sinnlos.
 */
.exo-project__symbolbild {
	display: none;
	position: absolute;
	inset-block-end: var(--wp--preset--spacing--20);
	inset-inline-start: var(--wp--preset--spacing--20);
	z-index: 1;
	margin: 0 !important;
	padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--20);
	max-inline-size: calc(100% - 2 * var(--wp--preset--spacing--20));
	background-color: rgb(0 0 0 / 55%);
	border-radius: var(--radius-sm);
	color: var(--color-text-on-dark);
	font-size: var(--wp--preset--font-size--xs);
	line-height: var(--line-height-ui);
}

.exo-project__figure:has(.exo-project__photo img) .exo-project__symbolbild {
	display: block;
}

.exo-project__industry {
	margin-block-start: var(--wp--preset--spacing--20) !important;
	color: var(--color-text-muted);
}

.exo-project__head {
	display: grid;
	gap: var(--component-gap-md);
	align-items: center;
	margin-block-start: var(--component-gap-md);
}

.exo-project__intro > * {
	max-inline-size: var(--container-text);
	margin-block: 0 !important;
}

.exo-project__intro > .wp-block-post-title {
	margin-block-start: var(--wp--preset--spacing--20) !important;
}

.exo-project__intro > .exo-lead {
	margin-block-start: var(--wp--preset--spacing--40) !important;
}

.exo-project__photo {
	margin-block: 0 !important;
	overflow: hidden;
	border-radius: var(--radius-md);
}

.exo-project__body {
	margin-block-start: var(--component-gap-lg) !important;
}

/* Die Kenndaten tragen dieselbe Bauart wie der Fertigungsrahmen der
 * Leistungsseite; nur die Breite kommt hier aus dem Beitragsinhalt. */
.exo-page__body.exo-project__body > .exo-specs {
	max-inline-size: none;
	margin-block-start: var(--wp--preset--spacing--40) !important;
}

.exo-project__related {
	margin-block-start: var(--component-gap-lg);
}

.exo-project__cta {
	margin-block-start: var(--component-gap-lg);
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-subtle);
}

.exo-project__cta > * {
	max-inline-size: 60ch;
	margin-block: 0 !important;
}

.exo-project__cta > p {
	margin-block-start: var(--wp--preset--spacing--20) !important;
	color: var(--color-text-secondary);
}

.exo-project__cta > .wp-block-buttons {
	margin-block-start: var(--wp--preset--spacing--50) !important;
}

@media (width >= 48rem) {
	.exo-project-cards {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (width >= 64rem) {
	.exo-project__head {
		grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
		gap: var(--component-gap-lg);
	}
}

/* ------------------------------------------------------------------
 * Materialseite
 * ------------------------------------------------------------------ */
.exo-material__head,
.exo-process__head {
	display: grid;
	gap: var(--component-gap-md);
	align-items: start;
}

.exo-material__intro > *,
.exo-process__intro > * {
	max-inline-size: var(--container-text);
	margin-block: 0 !important;
}

.exo-material__intro > .wp-block-post-title,
.exo-process__intro > .wp-block-post-title {
	margin-block-start: var(--wp--preset--spacing--20) !important;
}

.exo-material__intro > .exo-lead,
.exo-process__intro > .exo-lead {
	margin-block-start: var(--wp--preset--spacing--40) !important;
}

.exo-material__media,
.exo-process__media {
	margin-block: 0 !important;
	overflow: hidden;
	border-radius: var(--radius-md);
}

.exo-material__media img,
.exo-process__media img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

/* ------------------------------------------------------------------
 * Verfahrensseite
 *
 * Sie teilt sich die Regeln mit der Materialseite, statt eigene zu führen:
 * Beide sind Einzelseiten desselben Zuschnitts - Rubrik, Titel, Einleitung,
 * Bild daneben, Inhalt, Verwandtes, Handlungsaufforderung. Zwei Regelsätze für
 * dieselbe Form liefen auseinander, sobald einer gepflegt wird; die
 * Verfahrensseite war am 2026-08-19 der Beleg dafür, denn sie stand noch auf
 * dem Stand vor der Überarbeitung der Materialseite: Titel schmal, darunter ein
 * Foto über die vollen 80 rem in 16:9, und zum Schluss eine Trennlinie mitten
 * auf der Seite.
 *
 * Die Selektoren stehen deshalb gemeinsam. Wo sich die beiden unterscheiden
 * müssen, steht es ausdrücklich darunter.
 * ------------------------------------------------------------------ */

/*
 * Der Beitragsinhalt beginnt unter dem Kopfbereich, nicht direkt an ihm.
 * Die Abstandsregeln von `.exo-page__body` greifen erst zwischen den
 * Kindern des Inhalts.
 */
.exo-material__body,
.exo-process__body {
	margin-block-start: var(--component-gap-lg) !important;
}

/*
 * Datenblatt statt Aufzählung.
 *
 * Der Inhalt jeder Materialseite endet mit „Eigenschaften" und vier
 * Merkmalen - Steifigkeit, mechanisches Verhalten, Hitzebeständigkeit,
 * Eignung. Als Punktliste in der Textspalte standen vier Kennwerte
 * untereinander wie eine Einkaufsliste. Als Feld nebeneinander sind sie
 * das, was sie sind: die vergleichbaren Daten dieses Werkstoffs.
 *
 * Die Regel greift bewusst nur auf oberster Ebene des Materialinhalts.
 * Aufzählungen innerhalb einer Erläuterung blieben unberührt - es gibt
 * dort bisher keine.
 */
/*
 * Der Selektor nennt beide Klassen des Inhalts: Die Lesebreitenregel
 * `.exo-page__body > :not(…)` liegt durch die Klassenliste in `:not()` bei
 * (0,2,0). Mit nur einer Klasse blieb das Datenblatt auf 48 rem stehen und
 * brach in drei Spalten um - bei vier Merkmalen also mit einer einzelnen
 * Zelle in der zweiten Reihe.
 */
.exo-page__body.exo-material__body > .exo-props {
	display: grid;
	grid-template-columns: 1fr;
	gap: 0;
	max-inline-size: none;
	margin-block-start: var(--wp--preset--spacing--40) !important;
	padding-inline-start: 0;
	border-block-start: 1px solid var(--color-border);
	list-style: none;
}

.exo-material__body > .exo-props > li {
	display: flex;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--30);
	margin-block: 0;
	padding-block: var(--wp--preset--spacing--40);
	padding-inline-end: var(--wp--preset--spacing--50);
	border-block-end: 1px solid var(--color-border);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	line-height: var(--line-height-ui);
}

/*
 * Symbol je Eigenschaftsart.
 *
 * Vier Merkmale nebeneinander lasen sich als vier gleich aussehende Sätze;
 * beim Vergleich zweier Materialseiten musste man jedes Mal lesen, welche
 * Zelle die Temperatur trägt. Das Zeichen macht die Art der Angabe vor dem
 * Text erkennbar - es ersetzt ihn nicht und steht deshalb für Screenreader
 * nicht im Dokument (`aria-hidden` wäre nötig, wenn es Inhalt trüge).
 *
 * Umgesetzt als Maske statt als Hintergrundbild: Die Farbe kommt damit aus
 * `background-color` und folgt dem Zustand der Fläche, ohne dass je Zustand
 * eine zweite Datei nötig wäre.
 */
.exo-material__body > .exo-props > li::before {
	content: "";
	flex: none;
	inline-size: 1.25rem;
	block-size: 1.25rem;
	margin-block-start: 0.05em;
	background-color: var(--color-brand);
	mask-position: center;
	mask-repeat: no-repeat;
	mask-size: contain;
}

/* Thermometer: Hitzebeständigkeit. */
.exo-prop--hitze::before {
	mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13.5V5a2 2 0 1 1 4 0v8.5a4 4 0 1 1-4 0Z"/><path d="M12 9v5"/></svg>');
}

/*
 * Wellenlinie: Flexibilität und Steifigkeit.
 *
 * Ersetzt am 2026-08-13 einen flachen Bogen, der auf der Fläche eher wie eine
 * Brücke oder ein Regenbogen las als wie ein biegsamer Werkstoff. Die Welle
 * hat keine feste Referenz wie ein Bogen zwischen zwei Auflagepunkten und
 * steht deshalb unmittelbarer für Biegung an sich - passend sowohl für „stark
 * flexibel" als auch für „starr" (dort mit dem Zusatz „kaum flexibel" im Text,
 * das Zeichen bleibt dasselbe wie bei jeder anderen Eigenschaftsart auch).
 */
.exo-prop--flex::before {
	mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 15c1.5-5 3-5 4.5 0s3 5 4.5 0 3-5 4.5 0 3 5 4.5 0"/></svg>');
}

/*
 * Schild mit Haken: Beständigkeit gegen Abrieb, Schlag und Bruch.
 *
 * Ersetzt am 2026-08-13 einen Schildumriss ohne Innenzeichnung, der bei
 * 20 px kaum von einer Pille oder einem Reifen zu unterscheiden war. Der
 * Haken macht aus der Fläche eindeutig ein Schutzsymbol - dieselbe Bedeutung,
 * aber ohne bei erster Betrachtung erraten werden zu müssen.
 */
.exo-prop--belastung::before {
	mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3 5 6.5V11c0 5 3 8.5 7 10 4-1.5 7-5 7-10V6.5L12 3Z"/><path d="m9 11.5 2 2 4-4.5"/></svg>');
}

/* Feder: geringes Gewicht. */
.exo-prop--gewicht::before {
	mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M20 4c-7 0-12 4-12 10v4l-3 2"/><path d="M8 14h6M11 9h5"/></svg>');
}

/* Lupe: Detailgenauigkeit. */
.exo-prop--detail::before {
	mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="6"/><path d="m20 20-4.5-4.5"/></svg>');
}

/* Glatte Bahn: Oberflächengüte. */
.exo-prop--oberflaeche::before {
	mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9h18M3 15h18"/><path d="M6 5v2M12 5v2M18 5v2"/></svg>');
}

/* Schichten: Auswahl an Materialvarianten. */
.exo-prop--vielfalt::before {
	mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="m12 4 8 4-8 4-8-4 8-4Z"/><path d="m4 12 8 4 8-4M4 16l8 4 8-4"/></svg>');
}

/* Ziel: wofür sich der Werkstoff eignet. */
.exo-prop--eignung::before {
	mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3"/></svg>');
}

/* ------------------------------------------------------------------
 * Bilanz: dafür und dagegen
 *
 * Zwei Listen nebeneinander, Haken gegen Kreuz. Die Trennung beantwortet
 * die Frage, die auf einer Materialseite ansteht - wofür taugt der
 * Werkstoff, und woran scheitert er. Beide Zeichen sind CSS-Formen und
 * kein Text: Ein „✓" im Inhalt läge in der Vorlesereihenfolge vor jedem
 * Punkt und in Suchergebnissen mit im Auszug.
 * ------------------------------------------------------------------ */
.exo-page__body.exo-material__body > .exo-verdict {
	display: grid;
	gap: var(--component-gap-md);
	max-inline-size: none;
	margin-block-start: var(--component-gap-lg) !important;
}

/*
 * Beide Spalten beginnen auf derselben Höhe.
 *
 * Das Fließlayout von WordPress gibt jedem Kind außer dem ersten einen oberen
 * Rand - im Raster traf das die zweite Spalte und ließ „Dagegen spricht" 24 px
 * tiefer stehen als „Dafür spricht".
 */
.exo-verdict > *,
.exo-verdict__col > * {
	margin-block: 0 !important;
}

.exo-verdict__col > ul {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	margin-block-start: var(--wp--preset--spacing--40) !important;
	padding-inline-start: 0;
	list-style: none;
}

.exo-verdict__col > ul > li {
	position: relative;
	margin-block: 0;
	padding-inline-start: 2rem;
	color: var(--color-text-secondary);
	line-height: var(--line-height-ui);
}

/* Haken wie in der Auswahlhilfe und der Leistungsübersicht - dieselbe Aussage. */
.exo-pros > li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0.45em;
	inset-block-start: 0.3em;
	inline-size: 0.36em;
	block-size: 0.66em;
	border: solid var(--color-brand);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

/*
 * Das Kreuz besteht aus zwei gedrehten Strichen derselben Stärke wie der
 * Haken. Es ist gedeckt gesetzt, nicht rot: Ein Nachteil ist keine
 * Fehlermeldung, sondern eine Eigenschaft, die woanders ein Vorteil ist.
 */
.exo-cons > li::before,
.exo-cons > li::after {
	content: "";
	position: absolute;
	inset-inline-start: 0.3em;
	inset-block-start: 0.62em;
	inline-size: 0.8em;
	block-size: 2px;
	background-color: var(--color-text-muted);
}

.exo-cons > li::before {
	transform: rotate(45deg);
}

.exo-cons > li::after {
	transform: rotate(-45deg);
}

@media (width >= 48rem) {
	.exo-page__body.exo-material__body > .exo-verdict {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--component-gap-lg);
	}
}

.exo-material__related,
.exo-process__related {
	margin-block-start: var(--component-gap-lg);
}

.exo-material__cta,
.exo-process__cta {
	margin-block-start: var(--component-gap-lg);
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-subtle);
}

.exo-material__cta > *,
.exo-process__cta > * {
	max-inline-size: 60ch;
	margin-block: 0 !important;
}

.exo-material__cta > p,
.exo-process__cta > p {
	margin-block-start: var(--wp--preset--spacing--20) !important;
	color: var(--color-text-secondary);
}

.exo-material__cta > .wp-block-buttons,
.exo-process__cta > .wp-block-buttons {
	margin-block-start: var(--wp--preset--spacing--50) !important;
}

/*
 * Feste Spaltenzahlen statt `auto-fit`: Jede Materialseite führt genau vier
 * Merkmale. `auto-fit` ergab bei mittleren Breiten drei Spalten und ließ das
 * vierte allein in einer zweiten Reihe stehen - mit einer Trennlinie, die
 * nach einem Drittel der Breite endete.
 */
@media (width >= 40rem) {
	.exo-page__body.exo-material__body > .exo-props {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (width >= 64rem) {
	.exo-page__body.exo-material__body > .exo-props {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	/*
	 * Text und Bild teilen sich die Zeile im Verhältnis 3:2. Das Bild bekommt
	 * damit rund 30 rem statt der vollen 80 rem - genug, um den Werkstoff zu
	 * zeigen, ohne die erste Aussage der Seite zu sein.
	 */
	.exo-material__head,
	.exo-process__head {
		grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
		gap: var(--component-gap-lg);

		/*
		 * Beide Spalten mittig zueinander: Der Kopftext ist rund 130 px hoch,
		 * das Bild dreimal so viel. Oben ausgerichtet blieb unter dem Text ein
		 * leeres Feld von der Höhe des Bildes stehen; mittig verteilt sich der
		 * Unterschied auf beide Seiten und liest sich als Satzspiegel.
		 */
		align-items: center;
	}
}

/* ------------------------------------------------------------------
 * AP-15 – verifiziertes Rahmendesign
 *
 * Die Regeln bilden 80-rem-Inhaltscontainer, responsive Seitenstege und
 * klar getrennte Flächen ab. Schatten und Radien bleiben eigenständigen,
 * tatsächlich interaktiven Einheiten vorbehalten.
 * ------------------------------------------------------------------ */
html {
	overflow-x: clip;
}

body {
	--wp--style--root--padding-left: var(--gutter-page);
	--wp--style--root--padding-right: var(--gutter-page);
}

.wp-site-blocks > * {
	margin-block-start: 0;
}

.entry-content > * {
	margin-block-start: 0;
}

.wp-site-blocks {
	overflow-x: clip;
}

.wp-block-button__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-block-size: var(--control-standard);
	transition:
		background-color var(--duration-fast) var(--easing-standard),
		border-color var(--duration-fast) var(--easing-standard),
		color var(--duration-fast) var(--easing-standard);
}

/*
 * Der gedrückte Zustand fehlte bisher vollständig: Zeiger und Klick sahen
 * gleich aus, sodass auf einem Touchgerät keine Rückmeldung ankam. Er ist eine
 * Stufe dunkler als der Zeigerzustand, damit die Reihenfolge Ruhe - Zeiger -
 * Gedrückt auch ohne Farbwissen als Verlauf lesbar bleibt (Regel R8).
 */
.wp-block-button__link:active {
	background-color: var(--wp--preset--color--brand-700);
}

.is-style-outline .wp-block-button__link:active {
	background-color: rgb(255 255 255 / var(--state-pressed));
}

.exo-section--compact,
.exo-faq,
.exo-final-cta {
	padding-block: var(--section-compact);
}

/* Kopfbereich und Hero sind eine zusammenhängende dunkle Bühne. */
.exo-header__inner {
	min-block-size: var(--control-dominant);
	gap: var(--wp--preset--spacing--20);
	padding-block: var(--wp--preset--spacing--40);
}

/*
 * Die beiden Headerzeilen besitzen ihre Höhe bereits durch vollständige
 * Trefferflächen und eine eigene Trennlinie. Der automatische Blockabstand
 * der übergeordneten Gutenberg-Gruppe erzeugte dazwischen ein funktionsloses
 * 24-px-Band. Bei ausgeblendeter Utility-Zeile kollabierte derselbe Abstand
 * sogar bis vor den gesamten Header. Deshalb gilt hier bewusst für Start- und
 * Unterseiten derselbe Nullabstand.
 */
.exo-header > .exo-header__inner {
	margin-block-start: 0 !important;
}

/*
 * Servicezeile.
 *
 * Sie erscheint erst, wenn die vollständige Navigation erscheint. Darunter
 * führt die Navigationsschublade dieselben Ziele - eine zweite, 34 px hohe
 * Zeile würde auf einem 844 px hohen Gerät nur Höhe kosten und dieselben Links
 * doppelt anbieten.
 */
/*
 * Der Selektor nennt zusätzlich die Blockklasse: Die Vorgabe
 * `.wp-block-group.is-layout-flex { display: flex }` liegt mit zwei Klassen
 * über einer einzelnen Hilfsklasse. Ohne das stand die Servicezeile auf
 * Mobilgeräten sichtbar über der Marke - als einzelner, mittig gesetzter
 * Link „Anmelden" in Linkblau.
 */
.exo-header .wp-block-group.exo-header__utility {
	display: none;
}

@media (width >= 80rem) {
	/*
	 * Ohne eigene Polsterung: Die Höhe der Zeile kommt aus der Trefferfläche von
	 * Konto und Warenkorb (44 px). Eine zusätzliche Polsterung addierte sich
	 * darauf, statt die Zeile schmaler zu machen.
	 */
	.exo-header .wp-block-group.exo-header__utility {
		position: relative;
		isolation: isolate;
		display: flex;
		align-items: center;
		padding-block: 0;
	}

	/*
	 * Die Fläche der Servicezeile läuft bis zum Viewportrand, ihr Inhalt bleibt
	 * auf der Achse (R5). Begründung zu `calc(50% - 50vw)` siehe Faktenband.
	 */
	.exo-header__utility::before {
		content: "";
		position: absolute;
		z-index: -1;
		inset-block: 0;
		inset-inline: calc(50% - 50vw);
		background-color: var(--color-surface-dark);
		border-block-end: 1px solid var(--color-border-dark);
	}

	.exo-header__hint {
		display: flex;
		align-items: center;
		gap: var(--wp--preset--spacing--20);
		margin-block: 0;
		color: var(--wp--preset--color--ink-300);
		font-size: var(--wp--preset--font-size--xs);
		line-height: var(--line-height-ui);
	}

	/*
	 * Genau eine der beiden Auskünfte. Die Herkunft gehört zur Startseite,
	 * die Versandgrenze in den Shop - dort ist sie die Angabe, die vor dem
	 * Kauf zählt. `display: none` nimmt die jeweils andere auch aus der
	 * Vorlesereihenfolge, sie steht also nicht doppelt im Dokument.
	 */
	.exo-header__hint--versand {
		display: none;
	}

	body[class~="woocommerce-page"] .exo-header__hint--herkunft {
		display: none;
	}

	body[class~="woocommerce-page"] .exo-header__hint--versand {
		display: flex;
	}

	/*
	 * Die Flagge steht für die Standortangabe daneben, nicht als Schmuck neben
	 * einer Überschrift (Regel §9.1). Sie ist als Farbverlauf gesetzt statt als
	 * Datei: drei harte Stopps brauchen keine Anfrage, kein Bildformat und
	 * keinen Alternativtext - die Aussage trägt der Text, den sie begleitet.
	 *
	 * Die Haarlinie trennt Schwarz vom dunklen Kopfbereich; ohne sie verliert
	 * der obere Streifen seine Kante.
	 */
	.exo-header__hint--herkunft::before {
		content: "";
		flex: none;
		inline-size: 1.125rem;
		block-size: 0.75rem;
		border: 1px solid rgb(255 255 255 / 25%);
		border-radius: 1px;
		/*
		 * `border-box` und `no-repeat` sind hier tragend, nicht kosmetisch.
		 *
		 * Vorgabe für Verläufe ist `background-origin: padding-box` bei
		 * gleichzeitigem `background-clip: border-box`: Der Verlauf wird also
		 * im Polsterbereich aufgespannt, aber bis zur Rahmenkante gezeichnet.
		 * Die Vorgabe `background-repeat: repeat` füllt den verbleibenden
		 * Streifen mit der Fortsetzung der Kachel - über der oberen Kante stand
		 * dadurch das Ende des Verlaufs, also ein gelber Strich über Schwarz.
		 */
		background-origin: border-box;
		background-repeat: no-repeat;
		background-image: linear-gradient(
			to bottom,
			#000 0 33.33%,
			#d00 33.33% 66.66%,
			#ffce00 66.66% 100%
		);
	}

	.exo-header__utility-actions {
		gap: var(--wp--preset--spacing--40);
	}
}

/*
 * Die Servicezeile erklärt den Einstieg auf der Startseite. Auf einer
 * Unterseite würde sie dauerhaft Höhe belegen und die dort bereits getroffene
 * Navigation wiederholen. Die Hauptzeile bleibt vollständig erhalten.
 *
 * AUSNAHME SHOP
 *
 * Auf WooCommerce-Seiten bleibt sie stehen. Unterhalb von 80rem führt die
 * Navigation Kundenkonto und Warenkorb selbst (`exo-nav__mobile-only`);
 * genau ab der Breite, ab der diese beiden Ziele dort ausgeblendet werden,
 * verschwanden sie auf jeder Shopseite vollständig - im Shop, im Warenkorb
 * und in der Kasse gab es weder eine Anmeldung noch einen Weg zum
 * Warenkorb. Für eine Bestellung sind beides keine Wiederholung der
 * Navigation, sondern der Weg zum Abschluss.
 */
body:not([class~="home"], [class~="woocommerce-page"]) .exo-header .wp-block-group.exo-header__utility {
	display: none;
}

/*
 * Der Schutzraum der Wortmarke entfällt im Kopfbereich, weil dessen Höhe
 * bereits aus `.exo-header__inner` kommt. Die Marke ist aber ein Link zur
 * Startseite und braucht deshalb trotzdem eine vollwertige Bedienfläche: Das
 * Logo ist bei 390 px nur 23 px hoch, ohne diese Mindesthöhe läge das
 * Touchziel unter jeder Vorgabe.
 */
.exo-header .exo-brand {
	padding-block: 0;
	min-inline-size: var(--touch-target);
	min-block-size: var(--touch-target);
}

.exo-header .exo-brand__mark {
	inline-size: 8.75rem;
}

.exo-header__brand {
	order: 1;
}

/*
 * Unterhalb der Desktopbreite steht die Primäraktion neben dem Menüknopf, nicht
 * zwischen Marke und Menüknopf. Ohne den Automatikrand verteilt
 * `justify-content: space-between` drei Elemente gleichmäßig, und die
 * wichtigste Schaltfläche der Seite stand frei in der Mitte des Kopfbereichs.
 */
.exo-header__cta {
	order: 2;
	flex: none;
}

/*
 * Der Selektor nennt den Kopfbereich zusätzlich: Die Flex-Vorgabe
 * `.wp-container-<n>.is-layout-flex > * { margin: 0 }` liegt mit zwei Klassen
 * über einer einzelnen Hilfsklasse und setzte den Automatikrand auf null
 * zurück.
 */
.exo-header .exo-header__inner > .exo-header__cta {
	margin-inline-start: auto;
}

.exo-header__cta .wp-block-button__link {
	min-block-size: var(--control-compact);
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-nav {
	order: 3;
	flex: none;
}

.exo-nav :where(.wp-block-navigation-item__content):hover,
.exo-nav :where(.current-menu-item > .wp-block-navigation-item__content) {
	color: var(--color-text-on-dark);
}

.exo-nav .wp-block-navigation__responsive-container-open,
.exo-nav .wp-block-navigation__responsive-container-close {
	display: flex;
	align-items: center;
	justify-content: center;
	min-inline-size: var(--control-compact);
	min-block-size: var(--control-compact);
	color: var(--color-text-on-dark);
}

body .exo-nav .wp-block-navigation__responsive-container:not(.is-menu-open) {
	display: none;
}

/*
 * Die geöffnete Schublade: Abstand und Ausrichtung.
 *
 * **Farben stehen hier nicht.** Sie sind Blockattribute in `parts/header.html`
 * (`overlayBackgroundColor`, `overlayTextColor`) – die Begründung steht dort.
 * Kurz: Die Kernregel für die weiße Fläche hat fünf Klassen und weicht
 * ausdrücklich zurück, wenn die Navigation eigene Farben trägt. Dagegen
 * anzuschreiben wäre ein Spezifitätswettlauf gegen den vorgesehenen Weg.
 *
 * **Die Ausrichtung ebenfalls über den vorgesehenen Weg.** WordPress setzt im
 * offenen Zustand
 *
 *   align-items: var(--navigation-layout-justification-setting, initial)
 *
 * und füllt die Variable aus der Layout-Einstellung des Blocks – die hier
 * `justifyContent: right` lautet, weil die Navigation im Kopfbereich rechts
 * steht. In der senkrechten Schublade führte das zu rechtsbündigen Verweisen:
 * gemessen begann der erste bei 275 px von 390. Eine eigene
 * `align-items`-Regel verlor gegen die Kernregel (drei Klassen gegen drei,
 * später geladen); die Variable zu setzen wirkt dagegen an genau der Stelle,
 * die die Kernregel ausliest.
 *
 * Sie muss dabei **auch an der Liste selbst** stehen, nicht nur am Container:
 * Das `ul` trägt `items-justified-right`, und diese Klasse setzt die Variable
 * näher am Element als jede Regel auf einem Vorfahren. Am Container allein
 * gesetzt blieb der Wert am `ul` `flex-end` – die Verweise standen dann 20 px
 * eingerückt, also nicht auf der linken Achse des Seiteninhalts.
 */
body .exo-nav .wp-block-navigation__responsive-container.is-menu-open,
body .exo-nav .is-menu-open .wp-block-navigation__responsive-container-content,
body .exo-nav .is-menu-open .wp-block-navigation__container {
	--navigation-layout-justification-setting: flex-start;
}

body .exo-nav .wp-block-navigation__responsive-container.is-menu-open {
	padding: var(--gutter-page);
}

.exo-nav .is-menu-open .wp-block-navigation__responsive-container-content {
	padding-block-start: var(--wp--preset--spacing--90);
}

/* Die Ausrichtung kommt aus der Variablen oben, hier nur der Abstand. */
.exo-nav .is-menu-open .wp-block-navigation__container {
	gap: var(--wp--preset--spacing--40);
}

.exo-nav .is-menu-open .wp-block-navigation-item__content {
	font-size: var(--wp--preset--font-size--xl);
}

/* Die geschlossene WooCommerce-Schublade darf bei 320 px nicht außerhalb des
 * Viewports zur Dokumentbreite beitragen; beim Öffnen entfernt der Block das
 * Attribut selbst. */
[class~="wc-block-mini-cart__drawer"][aria-hidden="true"] {
	display: none;
}

[class~="wc-block-mini-cart__drawer"],
[class~="wc-block-mini-cart__drawer"] [class~="wc-block-components-drawer__content"] {
	min-inline-size: 0;
	max-inline-size: 100vw;
}

/*
 * Die Breite der Schublade wird über die Variable gesetzt, nicht über
 * `inline-size`.
 *
 * WARUM DAS EIN UNTERSCHIED IST
 *
 * WooCommerce koppelt zwei Eigenschaften an dieselbe Zahl:
 *
 *   width:     var(--drawer-width)
 *   transform: translateX(max(-100%, var(--neg-drawer-width)))
 *
 * Die Schublade sitzt bei `left: 100%` – also rechts außerhalb des Fensters –
 * und wird um ihre eigene Breite nach links geschoben. Beide Werte müssen
 * übereinstimmen, sonst schiebt sie sich nicht vollständig herein.
 *
 * Zuvor stand hier `inline-size`. Das überschrieb die Breite auf 768 px
 * (`--container-text`), während die Verschiebung bei der Vorgabe von 480 px
 * blieb. Gemessen bei 1440 px Fensterbreite: Die Schublade reichte von 960 px
 * bis 1728 px und stand damit 288 px außerhalb des Bildschirms – „Ihr Warenkorb
 * ist gerade leer!" war rechts abgeschnitten und „Einkauf beginnen" klebte an
 * der Kante.
 *
 * Über die Variablen bleiben Breite und Verschiebung gekoppelt, auch beim
 * Schließen (dort rechnet WooCommerce mit `min(100%, var(--drawer-width))`).
 */
[class~="wc-block-mini-cart__drawer"] {
	--drawer-width: min(var(--container-text), 100vw);
	--neg-drawer-width: calc(min(var(--container-text), 100vw) * -1);
}

/* Hero: volle dunkle Breite, asymmetrisches 7/5-Raster ab Desktop. */
.exo-hero {
	position: relative;
	padding-block: 0;
	background-color: var(--color-surface-stage);
	overflow: clip;
}

/*
 * Das Foto liegt hinter dem gesamten Abschnitt, nicht als Kachel daneben.
 *
 * Als gleichwertige zweite Spalte konkurrierte es mit der Aussage: zwei
 * Hälften, keine Komposition. Als abgedunkelte Fläche gibt es dem Einstieg
 * Tiefe und Material, ohne die Lesbarkeit oder die Hierarchie anzutasten.
 * Die Abdeckung ist keine Dekoration, sondern die Bedingung dafür, dass
 * weißer Text darauf die geforderten Kontraste erreicht.
 */
/*
 * `max-inline-size: none` ist hier tragend, nicht kosmetisch: Als direktes
 * Kind des eingeschränkten Layouts bekam das Backdrop die Containerbreite von
 * 80 rem und lief mittig, während die Fläche dahinter bis zum Rand reichte -
 * links und rechts blieb je ein Streifen ohne Foto. Ohne Begrenzung füllt es
 * die durch `inset: 0` aufgespannte Fläche, und die Automatikränder des
 * Layouts lösen sich zu null auf, weil kein Restplatz bleibt.
 */
/*
 * Abstände im Hero kommen aus Polsterung, nie aus Rändern: Ein oberer Rand des
 * ersten Kindes kollabiert durch die Sektion hindurch und schiebt den gesamten
 * Hero nach unten - sichtbar als weißer Streifen unter dem Kopfbereich.
 */
.exo-hero > div.exo-hero__grid,
.exo-hero > div.exo-hero__rail,
.exo-hero > figure.exo-hero__backdrop {
	margin-block: 0;
}

.exo-hero__backdrop {
	position: absolute;
	inset: 0;
	z-index: 0;
	max-inline-size: none;
	margin: 0;
	pointer-events: none;
}

.exo-hero__backdrop img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	object-position: 50% 55%;
	border-radius: 0;
}

/*
 * Gerichtete statt flächiger Abdunklung (Regel R9).
 *
 * Vorher lag das Bild bei 45 % Deckkraft unter einer gleichmäßigen Fläche mit
 * weiteren 42 %. Rechnerisch erfüllte das die Kontrastvorgabe, sichtbar blieb
 * aber nur noch Grau: Die Aufnahme zeigt einen dunklen Druckkopf über einem
 * dunklen Bett, und eine flächige Abdeckung nimmt genau die wenigen hellen
 * Kanten heraus, aus denen das Motiv besteht.
 *
 * Der Verlauf trennt die beiden Aufgaben: Links, wo Text steht, ist die Fläche
 * nahezu deckend und trägt Weiß mit vollem Kontrast. Nach rechts läuft sie aus,
 * dort steht kein Text und das Foto bleibt Foto. Das ist die Komposition, die
 * Hetzner im Hero benutzt - Bild bis zum Rand, Aussage auf gedeckter Fläche.
 */
.exo-hero__backdrop::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: linear-gradient(
		to right,
		rgb(22 25 29 / 97%) 0%,
		rgb(22 25 29 / 93%) 28%,
		rgb(22 25 29 / 66%) 54%,
		rgb(22 25 29 / 34%) 78%,
		rgb(22 25 29 / 24%) 100%
	);
}

/*
 * Zweite, senkrechte Ebene: Der Kopfbereich klebt oben und liegt auf derselben
 * Farbe. Ohne diesen Übergang entstünde am Rand des Kopfbereichs eine sichtbare
 * Kante zwischen einfarbiger Fläche und Foto.
 */
.exo-hero__backdrop::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background-image: linear-gradient(
		to bottom,
		rgb(22 25 29 / 85%) 0%,
		rgb(22 25 29 / 0%) 22%,
		rgb(22 25 29 / 0%) 100%
	);
}

.exo-hero > :not(.exo-hero__backdrop) {
	position: relative;
	z-index: 1;
}

.exo-hero__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 0;
}

/*
 * Leistungsübersicht im Einstieg.
 *
 * Teildeckende Fläche statt `opacity`: Deckkraft auf dem Element würde auch
 * Überschrift und Liste ausblenden. Der Alphawert liegt auf der Farbe, damit
 * nur die Fläche durchlässig ist.
 */
.exo-hero__panel {
	padding: var(--wp--preset--spacing--50);
	border: 1px solid rgb(255 255 255 / 14%);
	border-radius: var(--radius-lg);
	background-color: rgb(22 25 29 / 80%);
}

/* Der Automatikrand des Flow-Layouts käme sonst zwischen Text und Fläche. */
.exo-hero__grid > .exo-hero__panel {
	margin-block: 0 var(--hero-padding);
}

.exo-hero__panel-title {
	margin-block: 0 var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
}

/*
 * Prüfliste.
 *
 * Das Häkchen ist aus zwei Rahmenkanten gedreht statt als Datei oder Zeichen
 * gesetzt: Es skaliert mit der Schriftgröße, braucht keine zweite Anfrage und
 * ist von der Schriftverfügbarkeit unabhängig. Als reine Auszeichnung bleibt
 * es für Screenreader unsichtbar - die Liste trägt ihre Bedeutung selbst.
 */
.exo-checklist {
	margin-block: 0;
	padding-inline-start: 0;
	list-style: none;
}

.exo-checklist > li {
	position: relative;
	padding-inline-start: 1.75rem;
	line-height: var(--line-height-ui);
}

.exo-checklist > li + li {
	margin-block-start: var(--wp--preset--spacing--30);
}

.exo-checklist > li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0.3em;
	inset-block-start: 0.28em;
	inline-size: 0.36em;
	block-size: 0.66em;
	border: solid var(--color-brand);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

.exo-hero__copy {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	justify-content: center;
	gap: var(--wp--preset--spacing--40);
	padding-block: var(--hero-padding);
}

/*
 * Laufweite nach Designsystem höchstens -0,025em.
 *
 * `22ch` ist die gemessene Breite, bei der die Aussage bei 56 px auf genau zwei
 * Zeilen umbricht. Enger gefasst wurden daraus drei Zeilen und der Hero wuchs
 * um eine ganze Zeilenhöhe; weiter gefasst lief die erste Zeile bis unter das
 * Foto.
 */
.exo-hero h1 {
	max-inline-size: 22ch;
	letter-spacing: -0.03em;
	line-height: var(--line-height-tight);
	text-wrap: balance;
}

.exo-hero p.exo-lead {
	max-inline-size: 46ch;
	color: var(--wp--preset--color--ink-200);
	font-size: var(--font-size-lead);
}

.exo-hero .exo-eyebrow {
	color: var(--color-brand);
}

/* Die Hero-Aktion ist die dominante Aktion der Seite: 56 px, nicht 48. */
.exo-hero__actions {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--30);
	margin-block-start: var(--wp--preset--spacing--30);
}

/* Der Abstand kommt aus dem Flex-Gap, nicht zusätzlich aus dem Blockfluss. */
.exo-hero__actions > .wp-block-button {
	margin-block-start: 0 !important;
}

.exo-hero__actions .wp-block-button__link {
	min-block-size: var(--control-dominant);
	padding-inline: var(--wp--preset--spacing--50);
}

.exo-hero .is-style-outline .wp-block-button__link {
	background-color: transparent;
	color: var(--color-text-on-dark);
	border: 1px solid var(--color-border-strong);
}

.exo-hero .is-style-outline .wp-block-button__link:hover {
	background-color: var(--color-surface-dark-raised);
	color: var(--color-text-on-dark);
	border-color: var(--color-text-on-dark);
}

.exo-hero__note {
	max-inline-size: 46ch;
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

/* ------------------------------------------------------------------
 * Faktenband
 *
 * Der Balken am Fuß der Bühne war ohne Regeln: Die Deklarationen waren beim
 * Entfernen des Datenpanels mitgelöscht worden, wodurch fünf Einträge
 * untereinander standen und der Hero auf 910 px wuchs. Er ist ein eigener
 * Abschnittstyp (Regel R6) und bekommt deshalb eine eigene Fläche.
 * ------------------------------------------------------------------ */
.exo-hero__rail {
	position: relative;
	display: grid;
	gap: var(--wp--preset--spacing--30);
	padding-block: var(--wp--preset--spacing--40);
}

/*
 * Die Fläche des Bands läuft bis zum Viewportrand, sein Inhalt nicht (R5).
 *
 * `calc(50% - 50vw)` misst gegen die eigene Breite des Bands: Bei 1280 px
 * Inhalt in einem 1440-px-Viewport sind das exakt die 80 px bis zur Kante,
 * ohne dass der Seitensteg als Zahl auftauchen muss.
 */
.exo-hero__rail::before {
	content: "";
	position: absolute;
	z-index: -1;
	inset-block: 0;
	inset-inline: calc(50% - 50vw);
	background-color: rgb(22 25 29 / 86%);
	border-block-start: 1px solid var(--color-border-dark);
}

/*
 * Die Einträge bleiben in voller Höhe der Zelle und richten ihren Text selbst
 * mittig aus. Würde stattdessen das Raster zentrieren, schrumpften die Zellen
 * auf ihre Texthöhe und die senkrechten Trennlinien wären unterschiedlich lang -
 * je nachdem, ob ein Eintrag ein- oder zweizeilig umbricht.
 */
.exo-hero__rail > p.exo-rail__item {
	display: flex;
	align-items: center;
	margin-block: 0;
	color: var(--wp--preset--color--ink-100);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 500;
	line-height: var(--line-height-ui);
	text-wrap: balance;
}

.exo-section-heading {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	padding-block-start: var(--wp--preset--spacing--40);
	margin-block-end: var(--component-gap-lg);
	border-block-start: 1px solid var(--rule, var(--color-border));
}

.exo-section-heading h2 {
	max-inline-size: 20ch;
	letter-spacing: -0.02em;
	text-wrap: balance;
}

.exo-section-heading .exo-eyebrow {
	color: var(--color-text-secondary);
}

/*
 * Raster erhalten ihren Abstand aus `gap`, niemals aus Rändern.
 *
 * Das Fließlayout gibt jedem Kind außer dem ersten einen oberen Rand. In
 * einem Raster verschiebt dieser Rand das Element innerhalb seiner Zelle:
 * Das erste Element einer Reihe steht dann eine Abstandsstufe höher als
 * seine Nachbarn. Genau daraus entstand der Versatz zwischen den drei
 * Auswahlwegen und zwischen den Leistungen der oberen Reihe – sichtbar als
 * drei Überschriften auf drei verschiedenen Höhen.
 *
 * Die Selektoren nennen zusätzlich das Element, weil die Vorgabe über eine
 * generierte Containerklasse mit gleicher Spezifität kommt und sonst die
 * Reihenfolge der Stylesheets entscheiden würde.
 */
.exo-paths > div.exo-path,
.exo-service-list > div.exo-service,
.exo-steps > div.exo-step,
.exo-advantages > div.wp-block-group {
	margin-block: 0;
}

/*
 * Nur die drei tatsächlichen Auswahlwege erhalten Kartenkonturen.
 *
 * Ohne Nummerierung: Die drei Wege sind Alternativen, keine Reihenfolge.
 * `01 02 03` hatte eine Abfolge behauptet, die es nicht gibt – wer ein
 * Standardprodukt sucht, kommt nicht als Drittes, sondern stattdessen.
 * Nummern trägt auf dieser Seite deshalb nur der Ablauf.
 *
 * Der Vorrang der Projektanfrage steckt nicht mehr in einem farbigen Streifen
 * über der ersten Karte – der hatte deren Inhalt um seine eigene Stärke nach
 * unten geschoben, sodass die drei Überschriften auf drei verschiedenen Höhen
 * standen. Stattdessen trägt der Hauptweg die dunkle Fläche der Einstiegszone.
 * Das gewichtet deutlicher und lässt alle drei Karten exakt gleich beginnen.
 */
.exo-paths {
	display: grid;
	gap: var(--component-gap-md);
	align-items: stretch;
}

.exo-path {
	/*
	 * Die Textfarbe kommt aus einer Variablen, nicht aus einer zweiten Regel.
	 *
	 * Vorher setzte `.exo-path--primary p` die helle Farbe, verlor aber gegen
	 * `.exo-path > p:not(:last-child)`, das eine Klasse und zwei Elemente
	 * mitbringt. Auf der dunklen Karte stand der Text dadurch in Sekundärgrau:
	 * gemessen 2,65:1 gegen die Fläche, deutlich unter der Vorgabe. Über die
	 * Variable entscheidet die Fläche, nicht die Reihenfolge der Selektoren -
	 * dasselbe Muster wie bei `--rule`.
	 */
	--path-text: var(--color-text-secondary);

	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--60);
	background-color: var(--color-surface);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	box-shadow: none;
}

.exo-path--primary {
	--path-text: var(--wp--preset--color--ink-200);

	background-color: var(--color-surface-stage);
	border-color: var(--color-surface-stage);
}

/*
 * Die drei Linienzeichen machen die alternativen Einstiegspunkte schneller
 * unterscheidbar. Sie wiederholen keine Handlung und reagieren deshalb nicht
 * auf Hover. `currentColor` hält dieselbe Geometrie auf beiden Kartenflächen
 * kontrastreich, ohne eine zweite SVG-Variante zu benötigen.
 */
/*
 * `.exo-about__icon` teilt diese Regel, statt sie zu wiederholen: Die
 * Zielgruppen auf „Über Exostruct" tragen dieselbe Strichstärke und dieselbe
 * Größe wie die Einstiegswege. Zwei Definitionen liefen mit der Zeit
 * auseinander, und der Unterschied wäre auf zwei Seiten sichtbar, die
 * dieselbe Sprache sprechen sollen.
 */
.exo-path__icon,
.exo-about__icon {
	inline-size: var(--wp--custom--icon--orientation);
	block-size: var(--wp--custom--icon--orientation);
	flex: none;
	fill: none;
	stroke: currentcolor;
	stroke-width: 1.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/*
 * Das Zeichen nimmt die Farbe der Marke auf, weil die Trennlinie über dem
 * Block sie schon trägt - Linie und Zeichen gehören zusammen und bilden nicht
 * zwei Betonungen.
 */
.exo-about__icon {
	color: var(--color-brand);
}

.exo-path--primary .exo-path__icon {
	color: var(--color-brand);
}

.exo-path--primary :is(h1, h2, h3, h4, h5, h6) {
	color: var(--color-text-on-dark);
}

.exo-path--primary .exo-path__link {
	color: var(--color-text-on-dark);
}

.exo-path > p:not(:last-child) {
	max-inline-size: 40ch;
	color: var(--path-text);
}

/*
 * Die drei Ziele liegen auf einer gemeinsamen Linie, auch wenn die
 * Beschreibungen unterschiedlich lang sind. Umgesetzt über den wachsenden
 * Textblock statt über einen automatischen Rand - Ränder sind in diesen
 * Komponenten aufgehoben, siehe Kommentar bei `.exo-card > *`.
 */
.exo-path > p:nth-last-child(2) {
	flex-grow: 1;
}

/*
 * Der Weg steht immer am Fuß der Karte. Dadurch liegen die drei Ziele auf
 * einer gemeinsamen Linie, auch wenn die Beschreibungen unterschiedlich lang
 * sind – die Karte bleibt lesbar als „Beschreibung oben, Entscheidung unten“.
 */
.exo-path > p:last-child {
	padding-block-start: var(--wp--preset--spacing--30);
}

/* ------------------------------------------------------------------
 * Tertiäre Aktion (Regel R7)
 *
 * Vorher war das Ziel einer Karte ein gewöhnlicher Fließtextlink und kam damit
 * in Linkblau, während dasselbe Ziel auf der dunklen Karte daneben orange war -
 * zwei Farben für dieselbe Rolle in einem Abschnitt. Beide sind jetzt in der
 * Textfarbe ihrer Fläche gesetzt.
 *
 * Orange bleibt der Primäraktion vorbehalten. Es wäre als Textfarbe ohnehin
 * problematisch: `brand-500` erreicht auf Weiß 1,9:1 und `brand-700` 3,6:1,
 * beides unter der Vorgabe für Fließtext. Als Farbe der Unterstreichung im
 * Zeigerzustand ist es zulässig, weil sie keine Information allein trägt.
 * ------------------------------------------------------------------ */
.exo-path__link,
.exo-service__link {
	/*
	 * Die Trefferfläche ist die Vorgabe, nicht die Texthöhe: Gemessen waren die
	 * Ziele 20 px hoch. Regel R7 verlangt für tertiäre Aktionen 44 px.
	 */
	display: inline-flex;
	align-items: center;
	min-block-size: var(--touch-target);
	color: inherit;
	font-weight: 600;
	text-decoration: none;
}

.exo-action__label {
	text-decoration-line: underline;
	text-decoration-color: transparent;
	text-decoration-thickness: 2px;
	text-underline-offset: 0.3em;
	transition: text-decoration-color var(--duration-fast) var(--easing-standard);
}

.exo-path__link:hover .exo-action__label,
.exo-path__link:focus-visible .exo-action__label,
.exo-service__link:hover .exo-action__label,
.exo-service__link:focus-visible .exo-action__label {
	text-decoration-color: var(--color-brand);
}

/*
 * Der Abstand kommt aus dem Rand, nicht aus einem Leerzeichen im Inhalt: In
 * einem `inline-block` fällt ein führendes Leerzeichen weg, und der Pfeil klebte
 * an der Beschriftung.
 */
.exo-path__link::after,
.exo-service__link::after {
	content: "→";
	display: inline-block;
	margin-inline-start: 0.4em;
	transition: transform var(--duration-fast) var(--easing-standard);
}

.exo-path:hover .exo-path__link::after,
.exo-service:hover .exo-service__link::after {
	transform: translateX(0.25em);
}

/* Leistungen: ein zusammenhängendes dunkles Linienraster. */
.exo-services .exo-section-heading .exo-eyebrow {
	color: var(--color-brand);
}

.exo-services .exo-section-heading .exo-lead {
	color: var(--wp--preset--color--ink-300);
}

/*
 * Das Raster entsteht aus Linien, nicht aus gefüllten Zellen.
 *
 * Vorher lag unter dem Raster eine helle Fläche, die durch 1-px-Fugen
 * scheinen sollte. Sobald zwei Zellen einer Reihe unterschiedlich hoch
 * waren, wurde aus der Fuge ein sichtbarer heller Balken quer durch den
 * Abschnitt. Echte Rahmen an den Zellen können das nicht: Sie liegen immer
 * genau an der Zellkante, unabhängig von der Höhe des Inhalts.
 *
 * Ebenfalls ohne Nummerierung – vier Leistungen sind kein Ablauf.
 */
.exo-service-list {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	margin-block-start: var(--component-gap-lg);
}

/*
 * Eine Leistung ist eine eigenständige Fläche.
 *
 * Zuvor waren es Zeilen, die nur eine Haarlinie trennte. Bei vier Einträgen mit
 * Name, Erläuterung und Ziel las sich das als Tabelle, obwohl die vier
 * Leistungen nebeneinander stehen und nicht aufeinander aufbauen - und die
 * Zeile gab dem Ziel rechts außen keinen erkennbaren Bezug zum Namen links.
 * Als Karte trägt jede Leistung ihren eigenen Rahmen: Name, Erläuterung und
 * genau ein Ziel liegen sichtbar zusammen.
 *
 * Die Abgrenzung zum Auswahlraster weiter oben kommt aus der Fläche, nicht aus
 * dem Layout: Dort helle Karten auf hellem Grund, hier angehobene dunkle
 * Flächen auf der dunklen Bühne.
 */
.exo-service {
	position: relative;
	isolation: isolate;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border-dark);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-dark-raised);
	transition:
		border-color var(--duration-fast) var(--easing-standard),
		transform var(--duration-fast) var(--easing-standard);
}

/*
 * Zustandsebene nach R8: Dieselbe Deckkraft wie bei Karten und Schaltflächen,
 * nur mit heller Ebene, weil der Abschnitt dunkel ist. Sie liegt hinter dem
 * Inhalt und folgt exakt der Kontur der Karte.
 */
.exo-service::before {
	content: "";
	position: absolute;
	z-index: -1;
	inset: 0;
	background-color: var(--state-layer-on-dark);
	border-radius: inherit;
	opacity: 0;
	transition: opacity var(--duration-fast) var(--easing-standard);
}

.exo-service:hover::before,
.exo-service:focus-within::before {
	opacity: var(--state-hover);
}

.exo-service:hover,
.exo-service:focus-within {
	border-color: var(--color-brand);
}

/*
 * Kein zusätzlicher Markenstrich an der Oberkante im Zeigerzustand: Der
 * wechselnde Rahmen und die Zustandsebene zeigen bereits an, welche Karte
 * angesteuert ist. Ein dritter gleichzeitiger Hinweis war eine Kante zu viel.
 */
.exo-service__title {
	margin-block: 0;
}

.exo-service__text {
	max-inline-size: 52ch;
	color: var(--wp--preset--color--ink-300);
}

/*
 * Das Ziel steht am Fuß der Karte, auf gleicher Höhe über alle vier hinweg.
 * Der Automatikrand schiebt es dorthin, auch wenn die Erläuterungen
 * unterschiedlich lang umbrechen.
 */
.exo-service > .exo-service__action {
	margin-block: auto 0 !important;
	white-space: nowrap;
}

/*
 * Die Trefferfläche ist die Zeile, nicht die Beschriftung.
 *
 * Zulässig, weil jede Zeile genau ein Ziel hat: Es gibt keinen zweiten Link,
 * den die aufgespannte Fläche verdecken könnte. Der Text bleibt markierbar,
 * weil die Fläche über ein Pseudoelement kommt und nicht über ein Umschließen
 * des gesamten Inhalts.
 */
.exo-service__link::before {
	content: "";
	position: absolute;
	inset: 0;
}

/* ------------------------------------------------------------------
 * Leistungsseite: Umfang, Rahmen, Grenzen
 *
 * Drei Abschnitte, die es auf der Startseite nicht gibt - die Übersicht
 * bestand zuvor aus denselben zwei Mustern wie dort und wiederholte sie
 * wortgleich.
 *
 * Sie sind bewusst KEINE Karten. Karten tragen auf der Startseite bereits
 * zwei Rollen (Einstiegswege, Leistungen); eine dritte Kartensorte hätte
 * dieselbe Gestalt für eine andere Aussage benutzt (Regel R6). Der Umfang
 * ist eine Gegenüberstellung von Ausgangspunkt und Ergebnis und wird
 * deshalb als Zeilenraster gesetzt, der Rahmen als Kenndatenfeld.
 * ------------------------------------------------------------------ */
/*
 * Der erste Abschnitt beginnt mit deutlichem Abstand zur Einleitung.
 *
 * Der Blockabstand des Inhalts (24 px) ist der Abstand zwischen zwei
 * Absätzen, nicht der zwischen Einleitung und erstem Abschnitt: Die
 * getönte Fläche setzte damit unmittelbar unter dem Fließtext an und las
 * sich als dessen Fortsetzung.
 *
 * Der Selektor nennt zusätzlich `[class~="alignfull"]`. Ohne das lag die
 * allgemeine Regel `.exo-page__body > :not([class~="alignfull"]) +
 * [class~="alignfull"]` mit drei Selektorteilen darüber - beide tragen
 * `!important`, und bei gleichem Rang entscheidet die Spezifität. Die
 * Angabe blieb dadurch wirkungslos.
 */
.exo-page__body > [class~="alignfull"].exo-scope-section {
	margin-block-start: var(--component-gap-lg) !important;
}

.exo-scope-list {
	display: grid;
	gap: 0;
	margin-block-start: var(--component-gap-lg);
	border-block-start: 1px solid var(--rule);
}

/*
 * Eine Zeile je Leistung: Name, Ausgangspunkt, Ergebnis.
 *
 * Die Spaltenaufteilung ist die Aussage des Abschnitts. Wer wissen will,
 * welche Leistung zu seinem Stand passt, liest die mittlere Spalte
 * senkrecht durch - deshalb stehen alle Ausgangspunkte untereinander und
 * nicht jeweils unter ihrem Namen.
 */
.exo-scope {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	padding-block: var(--wp--preset--spacing--50);
	border-block-end: 1px solid var(--rule);
}

.exo-scope-list > div.exo-scope {
	margin-block: 0;
}

.exo-scope__title {
	font-size: var(--wp--preset--font-size--xl);
	line-height: var(--line-height-heading);
}

/*
 * Der Name führt zur Leistungsseite und ist in Textfarbe gesetzt: Ein
 * blauer oder oranger Titel wäre die vierte Linkfarbe des Systems für
 * dieselbe Rolle (Regel R12).
 */
.exo-scope__title a {
	color: inherit;
	text-decoration: none;
}

.exo-scope__title a:hover,
.exo-scope__title a:focus-visible {
	text-decoration: underline;
	text-decoration-color: var(--color-brand);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.3em;
}

.exo-scope__cell {
	max-inline-size: 46ch;
	color: var(--color-text-secondary);
	line-height: var(--line-height-ui);
}

/*
 * Die Beschriftung steht über dem Wert, nicht davor: Vor dem Wert liefe sie
 * bei jedem Umbruch in den Text hinein, und aus „Ausgangspunkt Handskizze mit
 * Maßen" würde beim Überfliegen ein Satz statt eines Wertepaars.
 */
.exo-scope__label {
	display: block;
	margin-block-end: var(--wp--preset--spacing--10, 0.25rem);
	color: var(--color-text-muted);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

/* Kenndaten des Fertigungsrahmens. */
.exo-specs {
	display: grid;
	gap: var(--component-gap-md);
	margin-block-start: var(--component-gap-lg);
}

.exo-spec {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	padding-block-start: var(--wp--preset--spacing--40);
	border-block-start: 1px solid var(--rule);
}

.exo-specs > div.exo-spec,
.exo-limits > div.exo-limit {
	margin-block: 0;
}

.exo-spec__label {
	color: var(--color-text-muted);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
}

/*
 * Der Wert trägt die Zahl und steht deshalb in Tabellenziffern: In
 * „350 × 350 × 350 mm" laufen sonst die Ziffernbreiten auseinander, und
 * zwei untereinander stehende Bauräume fluchten nicht.
 */
.exo-spec__value {
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	line-height: var(--line-height-heading);
}

.exo-spec__note {
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

/* Grenzen: gleichrangige Festlegungen, keine Rangfolge. */
.exo-limits {
	display: grid;
	gap: var(--component-gap-md);
	margin-block-start: var(--component-gap-lg);
}

.exo-limit {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	padding-block-start: var(--wp--preset--spacing--40);
	border-block-start: 1px solid var(--rule);
}

.exo-limit p {
	max-inline-size: 52ch;
	color: var(--color-text-secondary);
	line-height: var(--line-height-ui);
}

/* Gleiche Geometrie wie die Vorzüge oben auf der Seite (`exo-advantage__icon`). */
.exo-limit__icon {
	inline-size: var(--wp--custom--icon--orientation);
	block-size: var(--wp--custom--icon--orientation);
	flex: none;
	color: var(--color-text-muted);
	fill: none;
	stroke: currentcolor;
	stroke-width: 1.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}

@media (width >= 48rem) {
	.exo-specs,
	.exo-limits {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (width >= 64rem) {
	/*
	 * Erst ab dieser Breite tragen drei Spalten den Text ohne Flatterrand.
	 * Darunter stehen Name, Ausgangspunkt und Ergebnis untereinander - die
	 * Reihenfolge bleibt dieselbe, die Zuordnung geht nicht verloren.
	 */
	.exo-scope {
		grid-template-columns: minmax(12rem, 1fr) minmax(0, 1.4fr) minmax(0, 1.4fr);
		gap: var(--component-gap-md);
		align-items: start;
	}

	.exo-specs {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* Ablauf: Sequenz statt vier schwebender Karten. */
.exo-process .exo-steps {
	display: grid;
	gap: 0;
	margin-block-start: var(--component-gap-lg);
	border-block-start: 1px solid var(--rule);
}

.exo-process .exo-step,
.exo-process .exo-step:nth-child(even),
.exo-process .exo-step:nth-child(odd) {
	padding: var(--wp--preset--spacing--50) 0;
	background: none;
	border: 0;
	border-block-end: 1px solid var(--rule);
	border-radius: 0;
	box-shadow: none;
}

.exo-process-query,
.exo-material-query {
	margin-block-start: var(--component-gap-lg);
}

.exo-section-action,
.exo-material-note {
	margin-block-start: var(--component-gap-md);
}

/*
 * Zusammenarbeit: drei gleichrangige Festlegungen.
 *
 * Zuvor stand die Überschrift als Frage links und die drei Punkte als Antworten
 * rechts, getrennt durch Haarlinien. Der Aufbau behauptete einen Bezug, den es
 * nicht gibt: Die drei Punkte beantworten die Überschrift nicht, sie zählen
 * auf. Als Raster gleich breiter Flächen tragen sie sichtbar dasselbe Gewicht.
 */
.exo-advantages {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	margin-block-start: var(--component-gap-lg);
}

/*
 * `justify-items: start` ist die eigentliche Korrektur: Die drei Spalten
 * lagen im eingeschränkten Blocklayout, das seine Kinder mit einem
 * `!important`-Automatikrand zentriert. Die Überschriften standen dadurch
 * mittig über linksbündigem Fließtext. Die Blockmarkierung ist inzwischen auf
 * das Fließlayout umgestellt; diese Regel hält die linke Achse zusätzlich
 * fest, falls ein Abschnitt später wieder eingeschränkt gesetzt wird.
 */
.exo-advantages > .wp-block-group {
	display: grid;
	align-content: start;
	justify-items: start;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--wp--preset--color--brand-100);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface);
}

.exo-advantages p {
	color: var(--color-text-secondary);
	max-inline-size: 42ch;
}

/*
 * Symbol der Festlegung. Gleiches Raster und gleiche Strichstärke wie die
 * Orientierungssymbole der Einstiegswege, damit beide als dieselbe Familie
 * lesbar bleiben. Die Marke färbt nur den Strich, nicht eine Fläche - ein
 * gefüllter Kreis hätte drei Farbflecken in eine ruhige Reihe gesetzt.
 */
.exo-advantage__icon {
	inline-size: var(--wp--custom--icon--orientation);
	block-size: var(--wp--custom--icon--orientation);
	flex: none;
	margin-block-end: var(--wp--preset--spacing--10);
	color: var(--color-brand);
	fill: none;
	stroke: currentcolor;
	stroke-width: 1.5;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/*
 * Lesebreite ohne Achsenwechsel.
 *
 * Die Begrenzung sitzt an den Kindern, nicht am Container. Das eingeschränkte
 * Blocklayout des Abschnitts zentriert seine direkten Kinder mit einem
 * `!important`-Automatikrand; ein begrenzter Container liefe damit wieder in
 * die Seitenmitte. `.exo-faq-wrap` bleibt deshalb selbst voll breit - dort
 * ist der Automatikrand wirkungslos - und gibt die Textbreite an seine Kinder
 * weiter, die im Fließlayout liegen und keinen solchen Rand erhalten.
 */
.exo-faq-wrap {
	display: grid;
	gap: var(--component-gap-md);
}

.exo-faq-wrap > * {
	margin-block: 0 !important;
	max-inline-size: var(--container-text);
}

.exo-faq__aside {
	display: grid;
	align-content: start;
	gap: var(--wp--preset--spacing--50);
}

.exo-faq__aside > * {
	margin-block: 0 !important;
}

.exo-faq__card {
	display: grid;
	justify-items: start;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface);
}

.exo-faq__card > * {
	margin-block: 0 !important;
}

.exo-faq__card p:not(.exo-eyebrow, .exo-faq-contact) {
	color: var(--color-text-secondary);
}

.exo-faq-contact {
	font-size: var(--wp--preset--font-size--sm);
}

.exo-faq__links-title {
	margin-block: 0 var(--wp--preset--spacing--30) !important;
	color: var(--color-text-muted);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
}

.exo-faq__link-list {
	margin: 0;
	padding-inline-start: 0;
	list-style: none;
	border-block-start: 1px solid var(--color-border);
}

.exo-faq__link-list > li {
	margin-block: 0;
	border-block-end: 1px solid var(--color-border);
}

.exo-faq__link-list a {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--20);
	min-block-size: var(--touch-target);
	color: var(--color-text);
	font-weight: 600;
	text-decoration: none;
}

.exo-faq__link-list a::after {
	content: "→";
	flex: none;
	color: var(--color-text-muted);
}

.exo-faq__link-list a:hover,
.exo-faq__link-list a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

/*
 * Der Abschluss ist eine dunkle Bühne, kein Markenband.
 *
 * Als vollflächiges Orange trug er mehr Gewicht als der Einstieg, und die
 * Primärschaltfläche musste darauf in Graphit gesetzt werden - die Marke stand
 * also auf der Fläche statt auf der Aktion. Auf Graphit kehrt sich das um:
 * Die Fläche verbindet den Abschluss mit Kopfbereich und Fußzeile, Orange
 * bleibt der einen Schaltfläche vorbehalten.
 */
.exo-final-cta__grid {
	--rule: var(--color-border-dark);

	display: grid;
	gap: var(--component-gap-md);
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border-dark);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-stage);
	color: var(--color-text-on-dark);
}

.exo-final-cta__grid :is(h1, h2, h3, h4, h5, h6) {
	color: var(--color-text-on-dark);
}

.exo-final-cta__copy,
.exo-final-cta__steps {
	display: grid;
	align-content: start;
	gap: var(--wp--preset--spacing--30);
}

.exo-final-cta__copy > *,
.exo-final-cta__steps > * {
	margin-block: 0 !important;
}

.exo-final-cta h2 {
	max-inline-size: 18ch;
	letter-spacing: -0.02em;
}

.exo-final-cta .exo-eyebrow {
	color: var(--color-brand);
}

.exo-final-cta p.exo-lead {
	max-inline-size: 46ch;
	color: var(--wp--preset--color--ink-300);
}

.exo-final-cta__action {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--30);
	margin-block-start: var(--wp--preset--spacing--20) !important;
}

.exo-final-cta__note {
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-final-cta .wp-block-button__link {
	min-block-size: var(--control-dominant);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
}

.exo-final-cta .wp-block-button__link:hover {
	background-color: var(--color-brand-hover);
	color: var(--color-text-on-brand);
}

/*
 * Was nach dem Absenden passiert.
 *
 * Die Nummerierung trägt hier eine echte Information: Die drei Schritte laufen
 * tatsächlich in dieser Reihenfolge. Fristen fehlen bewusst - sie wären ohne
 * Beleg (AGENTS.md §9.6).
 */
.exo-final-cta__steps {
	gap: var(--wp--preset--spacing--40);
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border-dark);
	border-radius: var(--radius-md);
	background-color: rgb(255 255 255 / 4%);
}

.exo-final-cta__steps-title {
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
}

.exo-final-cta__list {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	margin: 0;
	padding-inline-start: 0;
	list-style: none;
	counter-reset: exo-cta-schritt;
}

.exo-final-cta__list > li {
	position: relative;
	margin-block: 0;
	padding-inline-start: 2.5rem;
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
	counter-increment: exo-cta-schritt;
}

.exo-final-cta__list > li::before {
	content: counter(exo-cta-schritt);
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: -0.1em;
	display: grid;
	place-items: center;
	inline-size: 1.75rem;
	block-size: 1.75rem;
	border: 1px solid var(--color-border-dark);
	border-radius: var(--radius-pill);
	color: var(--color-brand);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.exo-final-cta__list strong {
	display: block;
	margin-block-end: 0.15em;
	color: var(--color-text-on-dark);
	font-weight: 600;
}

/*
 * Der Footer bleibt vollständig, aber niedriger und deutlich gerastert.
 *
 * Der Abstand über und unter dem Raster ist eigens gesetzt: Ohne ihn schloss
 * das Raster oben unmittelbar an die Abschlussfläche der Seite an und unten an
 * die Rechtszeile - der Fußbereich las sich als Fortsetzung des letzten
 * Abschnitts statt als eigene Ebene.
 *
 * `.exo-footer__grid` doppelt: Der Block `wp:columns` erzeugt bei jedem
 * Rendern ohne eigenes `layout`-Attribut die generische Kernregel
 * `.is-layout-flex { display: flex; }` - eine einzelne Klasse, exakt
 * gleiche Spezifität wie diese Regel bisher. Bei vier ähnlich schweren
 * Spalten sah das gleich verteilte Flexbox-Ergebnis einem Raster zufällig
 * ähnlich genug, um nicht aufzufallen; mit der deutlich höheren
 * Newsletter-Spalte als fünftem Kind (`flex-wrap: nowrap` aus derselben
 * Kernregel) quetschte Flexbox alle fünf Spalten auf dieselbe schmale
 * Breite. Die verdoppelte Klasse gewinnt den Vergleich unabhängig von der
 * Reihenfolge im Dokument.
 */
.exo-footer__grid.exo-footer__grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--60) var(--wp--preset--spacing--40);
	margin-block: var(--component-gap-lg) !important;
}

.exo-footer__grid > .wp-block-column {
	margin: 0;
}

/*
 * Silbentrennung statt wörtlicher Bruchstelle.
 *
 * Die globale Regel `overflow-wrap: break-word` (base.css) verhindert
 * Überlauf, trennt ein zu langes Wort dafür aber an einer beliebigen Stelle
 * ohne Trennzeichen - sichtbar an „Exostruct UG (haftungsbeschrän/kt)" in den
 * schmaleren Spalten dieses Rasters. `hyphens: auto` nutzt stattdessen die
 * Worttrennung des Sprachwörterbuchs (`lang="de"` steht am `<html>`-Element)
 * und markiert die Stelle mit einem Bindestrich.
 */
.exo-footer__grid {
	hyphens: auto;
}

.exo-footer__intro,
.exo-footer__newsletter {
	grid-column: 1 / -1;
}

.exo-footer__muted {
	color: var(--wp--preset--color--ink-300);
}

.exo-footer__legal-links {
	gap: var(--wp--preset--spacing--40) var(--wp--preset--spacing--50);
}

/*
 * Newsletter-Anmeldung im Fußbereich.
 *
 * `.exo-notice` ist für helle Abschnitte gebaut: helle Kartenfläche,
 * dunkler Text, geerbt von dort, wo die Karte liegt. Im dunklen Fußbereich
 * vererbte sich sonst die helle Schrift des Fußbereichs auf die helle
 * Kartenfläche - lesbar nur durch Zufall des Kontrasts, nicht durch Absicht.
 * Diese Regel setzt für die Karte ausdrücklich wieder die Textfarben eines
 * hellen Abschnitts, unabhängig davon, in welchem Abschnitt sie steht.
 */
.exo-footer .exo-notice {
	color: var(--color-text);
}

.exo-footer .exo-notice__text {
	color: var(--color-text-secondary);
}

.exo-newsletter__intro {
	display: grid;
	gap: var(--wp--preset--spacing--10);
	margin-block-end: var(--wp--preset--spacing--30);
}

.exo-newsletter__text {
	margin: 0;
	max-inline-size: 32rem;
	color: var(--wp--preset--color--ink-300);
	line-height: var(--line-height-ui);
}

.exo-newsletter__form {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	max-inline-size: 32rem;
}

.exo-newsletter__row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20);
}

.exo-newsletter__email {
	flex: 1 1 14rem;
}

.exo-newsletter__email input {
	inline-size: 100%;
	min-block-size: var(--touch-target);
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	background-color: var(--color-surface);
	color: var(--color-text);
	border: 1px solid var(--color-border-dark);
	border-radius: var(--radius-sm);
}

.exo-newsletter__submit {
	flex: none;
	min-block-size: var(--touch-target);
	padding-inline: var(--wp--preset--spacing--40);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	border: none;
	border-radius: var(--radius-sm);
	font: inherit;
	font-weight: 600;
	cursor: pointer;
	transition: background-color var(--duration-fast) var(--easing-standard);
}

.exo-newsletter__submit:hover,
.exo-newsletter__submit:focus-visible {
	background-color: var(--color-brand-hover);
}

.exo-newsletter__privacy {
	max-inline-size: 32rem;
}

.exo-newsletter__privacy span {
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-newsletter__privacy a {
	color: var(--wp--preset--color--ink-300);
}

.exo-newsletter__code {
	font-family: var(--wp--preset--font-family--mono);
	letter-spacing: 0.04em;
}

@media (width < 23rem) {
	.exo-header .exo-brand__mark {
		inline-size: 2.5rem;
		block-size: 2.5rem;
	}
}

/*
 * Unterhalb der Desktopbreite steht der Text über die volle Breite. Ein
 * seitlicher Verlauf hätte dort keine ruhige Fläche mehr, sondern eine helle
 * rechte Textkante. Die Abdunklung läuft deshalb senkrecht: dicht, wo Text
 * steht, offener zum Fuß hin, wo das Foto sichtbar bleibt.
 */
@media (width < 64rem) {
	.exo-hero__backdrop::after {
		background-image: linear-gradient(
			to bottom,
			rgb(22 25 29 / 94%) 0%,
			rgb(22 25 29 / 90%) 58%,
			rgb(22 25 29 / 74%) 100%
		);
	}
}

@media (width < 48rem) {
	body[class~="admin-bar"] .exo-header {
		inset-block-start: 0;
	}

	.exo-hero__actions {
		flex-direction: column;
		align-items: flex-start;
		inline-size: 100%;
	}

	.exo-hero__actions .wp-block-button,
	.exo-hero__actions .wp-block-button__link {
		inline-size: 100%;
	}

	.exo-final-cta__action,
	.exo-final-cta__action .wp-block-buttons,
	.exo-final-cta__action .wp-block-button,
	.exo-final-cta__action .wp-block-button__link {
		inline-size: 100%;
	}

	.exo-final-cta__action {
		padding-block-start: var(--wp--preset--spacing--50);
		border-block-start: 1px solid var(--rule);
	}

	.exo-request__submit button {
		inline-size: 100%;
		min-block-size: var(--control-standard);
	}
}

@media (width >= 48rem) {
	/*
	 * Der Einleitungssatz steht unter der Überschrift, nicht daneben.
	 *
	 * Zuvor lagen Überschrift links und Fließtext rechts auf derselben Höhe.
	 * Das las sich als zwei gleichrangige Spalten, obwohl der Satz die
	 * Überschrift erläutert - das Auge sprang zwischen beiden hin und her und
	 * fand keinen Anfang. Untereinander folgt die Reihenfolge der Aussage.
	 *
	 * Die Begrenzung hält den Satz auf Lesebreite; ohne sie liefe er über die
	 * volle Containerbreite von 80rem.
	 */
	.exo-section-heading--split > * + * {
		max-inline-size: 60ch;
		margin-block-start: var(--wp--preset--spacing--40) !important;
	}

	/*
	 * Der Abschluss behält seine zwei Spalten: Rechts steht dort kein
	 * erläuternder Text, sondern die Handlungsaufforderung.
	 */
	/*
	 * `stretch` statt `end`: Die Schritte rechts sind eine eigene Fläche und
	 * sollen die Höhe der Aussage links tragen. Unten ausgerichtet blieb über
	 * ihnen ein Rest offener Fläche, der wie ein Setzfehler aussah.
	 */
	.exo-final-cta__grid {
		grid-template-columns: minmax(0, 7fr) minmax(18rem, 5fr);
		align-items: stretch;
		column-gap: var(--component-gap-lg);
	}

	/*
	 * Fragen links auf Lesebreite, Weiterführung rechts. Die Fragenliste
	 * behält damit ihre Breite, und die zuvor leere rechte Hälfte trägt den
	 * nächsten Schritt.
	 */
	.exo-faq-wrap {
		grid-template-columns: minmax(0, var(--container-text)) minmax(16rem, 1fr);
		column-gap: var(--component-gap-lg);
		align-items: start;
	}

	.exo-faq-wrap > * {
		max-inline-size: none;
	}

	.exo-paths {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	/*
	 * Zwei Karten nebeneinander. Vier gleich breite Spalten drückten die
	 * Erläuterungen auf unter 25 Zeichen Zeilenlänge und rissen jede Karte in
	 * sechs Zeilen auseinander.
	 */
	.exo-service-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--50);
	}
}

@media (width >= 64rem) {
	.exo-advantages {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--50);
	}

	.exo-process .exo-steps {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	.exo-process .exo-step,
	.exo-process .exo-step:nth-child(even),
	.exo-process .exo-step:nth-child(odd) {
		padding: var(--wp--preset--spacing--60);
		border-block-end: 0;
		border-inline-start: 1px solid var(--rule);
	}

	.exo-process .exo-step:first-child {
		padding-inline-start: 0;
		border-inline-start: 0;
	}

	.exo-process .exo-step:last-child {
		padding-inline-end: 0;
	}

	/*
	 * Alle vier Spalten in einer Reihe: Marke, die beiden Linklisten und die
	 * Newsletter-Anmeldung. Marke und Anmeldung tragen mehr als eine Zeile
	 * kurzer Links - Logo und Aussage die eine, Feld, Schaltfläche und
	 * mehrzeiliger Einwilligungstext die andere - und bekommen deshalb je
	 * einen eigenen Mindestwert; die Linklisten teilen sich den Rest.
	 */
	.exo-footer__grid.exo-footer__grid {
		grid-template-columns: minmax(13rem, 2fr) repeat(2, minmax(0, 1fr)) minmax(17rem, 2fr);
		column-gap: var(--wp--preset--spacing--80);
	}

	.exo-footer__intro,
	.exo-footer__newsletter {
		grid-column: auto;
	}

	/*
	 * Die zweite Spalte trägt eine Liste aus sechs kurzen Einträgen. Mit
	 * 24rem Mindestbreite lief sie deutlich breiter, als der längste Eintrag
	 * braucht, und die Fläche wirkte gegenüber der Aussage links zu schwer.
	 */
	.exo-hero__grid {
		grid-template-columns: minmax(0, 8fr) minmax(19rem, 4fr);
		gap: var(--component-gap-lg);
		min-block-size: var(--hero-min-height);
	}

	.exo-hero__copy {
		padding-block: var(--hero-padding);
	}

	/*
	 * Ab hier trägt das Raster zwei Spalten: Die Fläche steht neben der
	 * Aussage und mittig zu ihr, nicht darunter.
	 */
	.exo-hero__grid > .exo-hero__panel {
		align-self: center;
		margin-block: 0;
	}

	/* Balken in einer Reihe, Einträge durch senkrechte Linien getrennt. */
	.exo-hero__rail {
		grid-auto-flow: column;
		grid-auto-columns: minmax(0, 1fr);
		gap: 0;
		padding-block: var(--wp--preset--spacing--50);
	}

	.exo-hero__rail > p.exo-rail__item {
		padding-inline-end: var(--wp--preset--spacing--50);
	}

	.exo-hero__rail > p.exo-rail__item + p.exo-rail__item {
		padding-inline-start: var(--wp--preset--spacing--50);
		border-inline-start: 1px solid var(--color-border-dark);
	}
}

@media (width >= 80rem) {
	.exo-header__inner {
		gap: var(--wp--preset--spacing--60);
	}

	.exo-header .exo-brand__mark {
		inline-size: 10.5rem;
	}

	.exo-nav {
		order: 2;
		flex: 1 1 auto;
	}

	body .exo-nav .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: block;
		position: relative;
		inline-size: auto;
		block-size: auto;
		background: transparent;
	}

	.exo-nav .wp-block-navigation__responsive-container-open {
		display: none;
	}

	.exo-nav .wp-block-navigation__responsive-container-content,
	.exo-nav .wp-block-navigation__container {
		align-items: center;
	}

	.exo-nav .wp-block-navigation__container {
		column-gap: var(--wp--preset--spacing--40);
	}

	/*
	 * Navigationsziele waren 36 px hoch. Die Hauptzeile ist 72 px hoch und
	 * trägt die volle Trefferfläche, ohne dass sie dadurch wächst.
	 */
	.exo-nav .wp-block-navigation-item__content {
		display: flex;
		align-items: center;
		min-block-size: var(--touch-target);
	}

	/*
	 * Der Selektor nennt zusätzlich das Element und die Navigation, weil die
	 * Kernregel `.wp-block-navigation .wp-block-navigation-item` mit zwei
	 * Klassen bereits höher liegt als eine einzelne Hilfsklasse. Ohne das
	 * blieben Kundenkonto und Warenkorb auf dem Desktop in der Navigation
	 * stehen – zusätzlich zu den beiden Symbolen der Utility-Gruppe, die
	 * dieselben Ziele bereits abdecken.
	 */
	.exo-nav li.exo-nav__mobile-only {
		display: none;
	}

	.exo-header__utility-actions > :is(.wp-block-woocommerce-customer-account, [class~="wc-block-mini-cart"]) {
		display: flex;
		flex: none;
		color: var(--color-text-on-dark);
	}

	/*
	 * WooCommerce liefert Konto und Warenkorb mit 40 px aus. Das unterschreitet
	 * die Vorgabe für Bedienflächen; die Symbole selbst bleiben unverändert.
	 *
	 * In der Servicezeile trägt die Trefferfläche nicht die Zeilenhöhe: Sie
	 * darf über die 34 px hohe Fläche hinausragen, weil daneben nichts liegt,
	 * was dadurch verschoben würde.
	 */
	.exo-header__utility-actions [class~="wc-block-customer-account__link"],
	.exo-header__utility-actions [class~="wc-block-mini-cart__button"] {
		display: flex;
		align-items: center;
		justify-content: center;
		min-inline-size: var(--touch-target);
		min-block-size: var(--touch-target);
	}

	/*
	 * Das Kontosymbol ist ein Link und erbt sonst die Linkfarbe aus
	 * theme.json - es stand blau neben dem weißen Warenkorbsymbol, das als
	 * Button ausgeliefert wird. Beide gehören zur selben Utility-Gruppe und
	 * werden gleich behandelt.
	 */
	.exo-header__utility-actions [class~="wc-block-customer-account__link"],
	.exo-header__utility-actions [class~="wc-block-customer-account__link"]:hover,
	.exo-header__utility-actions [class~="wc-block-customer-account__link"]:focus-visible {
		color: var(--color-text-on-dark);
	}

	/*
	 * Konto und Warenkorb sind Navigationsziele, keine Fließtextlinks. Sie
	 * folgen deshalb der Navigation: ohne Unterstreichung im Ruhezustand,
	 * unterstrichen erst im Hover und Fokus.
	 */
	.exo-header__utility-actions [class~="wc-block-customer-account__link"] {
		gap: var(--wp--preset--spacing--20);
		font-size: var(--wp--preset--font-size--sm);
		text-decoration: none;
	}

	.exo-header__utility-actions [class~="wc-block-customer-account__link"]:hover,
	.exo-header__utility-actions [class~="wc-block-customer-account__link"]:focus-visible {
		text-decoration: underline;
		text-underline-offset: 0.4em;
		text-decoration-color: var(--color-brand);
		text-decoration-thickness: 2px;
	}

	.exo-header__utility-actions [class~="wc-block-mini-cart__button"] {
		gap: var(--wp--preset--spacing--20);
		font-size: var(--wp--preset--font-size--sm);
	}

	.exo-header .exo-header__inner > .exo-header__cta {
		order: 3;
		margin-inline-start: 0;
	}

	.exo-hero__grid {
		gap: var(--component-gap-lg);
	}

	/*
	 * Ab dieser Breite ist genug Platz, um Marke und Newsletter-Anmeldung
	 * wieder auf ihre bequemen Mindestbreiten zu setzen; die Linklisten
	 * behalten den Rest.
	 */
	.exo-footer__grid.exo-footer__grid {
		grid-template-columns: minmax(16rem, 2fr) repeat(2, minmax(0, 1fr)) minmax(20rem, 2fr);
	}
}

/* ------------------------------------------------------------------
 * Über Exostruct
 *
 * Die Seite bestand aus einer durchgehenden Textspalte, die auf Desktop
 * knapp die halbe Breite belegte und die andere Hälfte leer ließ. Die drei
 * Abschnitte sind inhaltlich gleichrangig und stehen deshalb nebeneinander.
 * ------------------------------------------------------------------ */
.exo-about__grid {
	display: grid;
	gap: var(--component-gap-md);
	margin-block-start: var(--component-gap-md) !important;
}

/*
 * Der Blockabstand von Gutenberg setzt auf jedes Kind außer dem ersten einen
 * oberen Rand. In einer Rasterzeile verschiebt der die zweite und dritte
 * Spalte gegenüber der ersten - die drei Trennlinien lagen dadurch nicht auf
 * einer Höhe. Der Abstand kommt bereits aus `gap`.
 */
.exo-about__grid > .exo-about__block,
.exo-about__block > * {
	margin-block: 0 !important;
}

.exo-about__block {
	display: grid;
	align-content: start;
	gap: var(--wp--preset--spacing--30);
	padding-block-start: var(--wp--preset--spacing--40);
	border-block-start: 2px solid var(--color-brand);
}

.exo-about__block p {
	color: var(--color-text-secondary);
}

/*
 * Kenndaten des Betriebs direkt unter der Einleitung.
 *
 * Sie sind der Grund, warum die Seite überhaupt gelesen wird: Ein
 * Fertigungsbetrieb beantwortet „wer wir sind" über das, was er kann. Die
 * Angaben tragen dieselbe Bauart wie der Fertigungsrahmen der
 * Leistungsseite - keine zweite Sprache für dieselbe Sorte Information.
 */
.exo-page__body > .exo-about__facts {
	max-inline-size: none;
	margin-block-start: var(--component-gap-md) !important;
}

/* Die beiden Abschnitte beginnen mit Abstand zur Einleitung, wie bei den
 * Leistungen - zur Spezifität siehe dort. */
.exo-page__body > [class~="alignfull"].exo-about__section {
	margin-block-start: var(--component-gap-lg) !important;
}

/*
 * Begrenzte Blöcke bleiben in der Inhaltsspalte.
 *
 * Zwei Fehlversuche stecken in dieser Regel:
 *
 * 1. Mit eigener Höchstbreite zentrierte das eingeschränkte Layout die
 *    Blöcke über automatische Seitenränder - sie standen in der Mitte,
 *    während Überschrift und Fließtext links beginnen.
 * 2. Der Gegenversuch `margin-inline: 0 auto` hob genau diese Ränder auf.
 *    Damit begannen die Blöcke am Rand des vollbreiten Abschnitts statt an
 *    der Inhaltsspalte: bei 1920 px gemessen 48 px statt 320 px.
 *
 * Richtig ist die Bauart von `.exo-measure`: Der Block behält seine volle
 * Breite und damit die Achse des Abschnitts, die Begrenzung sitzt an
 * seinen Kindern.
 */
.exo-about__grid--zwei .exo-about__block p {
	max-inline-size: 52ch;
}

.exo-about__umwelt {
	margin-block-start: var(--component-gap-lg) !important;
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--rule);
}

.exo-about__umwelt > * {
	max-inline-size: var(--container-text);
	margin-block: 0 !important;
}

.exo-about__umwelt > p {
	margin-block-start: var(--wp--preset--spacing--30) !important;
	color: var(--color-text-secondary);
}

/*
 * Der Gründungsabschnitt ist eine eigene Bühne.
 *
 * Zuvor standen die beiden Karten als heller Kasten auf hellem Grund
 * unmittelbar unter dem Fließtext - der Abschnitt war da, hob sich aber von
 * nichts ab. Als dunkle Fläche trennt er sich klar von den drei Textspalten
 * darüber und nimmt die Sprache von Kopfbereich und Fußzeile auf.
 */
/*
 * Ansprechpartner auf heller Fläche.
 *
 * Zuvor war der Abschnitt eine dunkle Bühne. Auf einer Seite, die mit
 * hellen Kenndaten beginnt und über zwei getönte Abschnitte läuft, war er
 * damit die dritte Flächenart - und die dunkelste ausgerechnet dort, wo es
 * um die Menschen geht, nicht um Technik. Die Abgrenzung trägt jetzt die
 * Kontur, nicht die Farbe.
 */
.exo-about__people {
	margin-block-start: var(--section-compact) !important;
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-subtle);
}

.exo-about__people > * {
	margin-block: 0 !important;
}

.exo-about__people .exo-eyebrow {
	color: var(--color-text-muted);
}

.exo-about__people > h2 {
	margin-block: var(--wp--preset--spacing--20) var(--component-gap-md) !important;
	color: var(--color-text);
}

/*
 * Gründerkarten.
 *
 * Zwei Personen, gleiche Rolle im Aufbau, gleiche Fläche. Die Karte trägt
 * Porträt, Name, Funktion sowie Zuständigkeit und Ausbildung - beide Angaben
 * liegen belegt vor (OF-17). Erfundene Kurzbiografien kommen weiterhin nicht
 * dazu (AGENTS.md §9.6).
 */
.exo-founders {
	display: grid;
	gap: var(--wp--preset--spacing--50);
}

/*
 * Die Karte liegt als weiße Fläche auf dem getönten Abschnitt: zwei Stufen
 * Helligkeit statt einer Farbe. Damit bleibt die Person die hellste Fläche
 * der Seite, ohne dass eine weitere Farbe dazukommt.
 */
.exo-founder {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);

	/*
	 * Oben ausgerichtet, seit die Karte mehr als zwei Zeilen trägt: Zentriert
	 * standen die runden Porträts der beiden Karten auf verschiedenen Höhen,
	 * sobald eine Angabe umbrach.
	 */
	align-items: start;
	gap: var(--wp--preset--spacing--50);
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface);
}

/*
 * Platzhalter statt Foto.
 *
 * Die Initialen unterscheiden die beiden Karten, ohne ein Porträt
 * vorzutäuschen. Die gestrichelte Kontur und die Beschriftung darunter machen
 * kenntlich, dass hier eine Aufnahme fehlt - eine gefüllte Fläche mit
 * Initialen sähe wie eine getroffene Gestaltungsentscheidung aus.
 *
 * Sobald die Porträts vorliegen, ersetzt ein `img` diese Fläche; Maß und
 * Rundung bleiben dieselben (docs/assets-required.md §4c).
 */
.exo-founder__portrait {
	display: grid;
	place-items: center;
	align-content: center;
	gap: 0.15rem;
	flex: none;
	inline-size: 6.5rem;
	block-size: 6.5rem;
	border: 1px dashed var(--color-border-strong);
	border-radius: var(--radius-pill);
	background-color: var(--color-surface-subtle);
}

/*
 * Liegt die Aufnahme vor, tritt sie an die Stelle des Platzhalters und erbt
 * dessen Maße und runde Form. Der gestrichelte Rand entfällt: Er bedeutet
 * „hier fehlt noch etwas" und wäre um ein vorhandenes Foto irreführend.
 */
.exo-founder__portrait--photo {
	display: block;
	overflow: hidden;
	border: 0;

	/*
	 * Weiß, nicht die getönte Fläche des Platzhalters: Beide Aufnahmen sind auf
	 * Weiß freigestellt. Der Platzhalter behält seine getönte Fläche - er soll
	 * ja auffallen.
	 */
	background-color: #fff;
}

/*
 * Kein Zuschnitt mehr im Stylesheet.
 *
 * Bis zum 2026-08-18 stand hier ein gemessener Ausschnitt je Person: Die
 * gelieferten Aufnahmen waren freigestellte Brustbilder mit viel Rand, und im
 * Kreis von 6,5 rem saß der Kopf sonst als kleiner Fleck. Zwei Aufnahmen mit
 * verschiedener Kopfhöhe brauchten dafür verschiedene Werte - drei Zahlen je
 * Person, in der Vorlage gesetzt und hier ausgewertet.
 *
 * Der Auftraggeber hat die Aufnahmen am 2026-08-18 selbst zugeschnitten und
 * mittig neu abgelegt. Damit ist der Ausschnitt in der Datei, wo er hingehört:
 * Das Bild füllt den Kreis, und eine dritte Aufnahme braucht keine neuen Zahlen
 * mehr, sondern nur denselben Zuschnitt.
 */
.exo-founder__portrait--photo img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

/*
 * `brand-700` statt `brand-500`: Auf heller Fläche erreicht das helle
 * Orange 1,9:1 und wäre als Textfarbe nicht lesbar.
 */
.exo-founder__initials {
	color: var(--wp--preset--color--brand-700);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	letter-spacing: 0.04em;
	line-height: 1;
}

.exo-founder__pending {
	color: var(--color-text-muted);
	font-size: 0.625rem;
	letter-spacing: 0.06em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
}

.exo-founder__name {
	margin-block: 0;
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--xl);
}

.exo-founder__role {
	display: inline-block;
	margin-block: var(--wp--preset--spacing--20) 0;
	padding: 0.15rem var(--wp--preset--spacing--30);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	color: var(--wp--preset--color--brand-700);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.04em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
}

/*
 * Zuständigkeit und Ausbildung als Beschriftung-Wert-Paare.
 *
 * Dieselbe Form wie die Kenndaten der Material- und Produktseiten: Beschriftung
 * in kleinen Versalien, Wert darunter im Fließtext. Wer die beiden Karten
 * vergleicht, findet dieselbe Angabe an derselben Stelle.
 */
.exo-founder__facts {
	display: grid;
	gap: var(--wp--preset--spacing--10);
	margin-block: var(--wp--preset--spacing--40) 0;
}

.exo-founder__facts dt {
	color: var(--color-text-muted);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.06em;
	line-height: var(--line-height-ui);
	text-transform: uppercase;
}

.exo-founder__facts dd {
	margin-block: 0 var(--wp--preset--spacing--30);
	margin-inline: 0;
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-founder__facts dd:last-child {
	margin-block-end: 0;
}

@media (width >= 48rem) {
	.exo-founders {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (width >= 64rem) {
	.exo-about__grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: var(--component-gap-lg);
	}

	/*
	 * Zwei Einträge gehören in zwei Spalten.
	 *
	 * Im Dreierraster standen „Unternehmen" und „Privatkunden" in zwei
	 * schmalen Spalten, die dritte blieb leer: Der Text brach nach vier
	 * Wörtern um, während rechts ein Drittel des Abschnitts frei lag.
	 */
	.exo-about__grid--zwei {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* ------------------------------------------------------------------
 * Auswahlhilfe
 *
 * Ein Werkzeug, kein Abschnitt. Es steht deshalb als eigene Fläche auf der
 * Seite und ist an seiner Kontur als bedienbar erkennbar - anders als die
 * Listen darunter, die man liest.
 *
 * Die Gestaltung setzt bewusst nichts voraus, was JavaScript bräuchte: Das
 * Formular schickt ab und der Server antwortet. Alle Zustände hier sind
 * Zustände des Dokuments, keine Zustände einer Anwendung.
 * ------------------------------------------------------------------ */
.exo-finder {
	margin-block: var(--component-gap-lg);
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-subtle);
}

.exo-finder__intro > * {
	margin-block: 0;
}

.exo-finder__title {
	font-size: var(--wp--preset--font-size--heading-3);
	letter-spacing: -0.02em;
}

.exo-finder__lead {
	max-inline-size: 62ch;
	margin-block-start: var(--wp--preset--spacing--30) !important;
	color: var(--color-text-secondary);
}

/* --- Bereits gegebene Antworten ---------------------------------
 *
 * Der Preis der schrittweisen Führung ist, dass die vorigen Antworten aus
 * dem Blick verschwinden. Diese Liste holt sie zurück - knapp, ohne die
 * aktuelle Frage zu überlagern, und jede Zeile führt zu ihrer Frage.
 * ---------------------------------------------------------------- */
.exo-finder__answers {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin-block: var(--component-gap-md) 0;
	padding-block-end: var(--wp--preset--spacing--40);
	padding-inline-start: 0;
	border-block-end: 1px solid var(--color-border);
	list-style: none;
}

.exo-finder__answer {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	margin-block: 0;
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-finder__answer-question {
	color: var(--color-text-secondary);
}

.exo-finder__answer-value {
	font-weight: 600;
}

/*
 * Der Änderungslink steht rechts, sobald Platz dafür da ist. Auf schmalen
 * Bildschirmen rutscht er in die nächste Zeile, statt die Antwort zu
 * quetschen.
 */
.exo-finder__answer-change {
	margin-inline-start: auto;
	color: var(--color-text-secondary);
	white-space: nowrap;
}

.exo-finder__answer-change:hover {
	color: var(--color-brand);
}

.exo-finder__form {
	display: grid;
	gap: var(--component-gap-md);
	margin-block-start: var(--component-gap-md);
}

/*
 * `fieldset` bringt Browservorgaben für Rahmen und Polsterung mit, die sich
 * je nach Browser unterscheiden. Sie werden zurückgesetzt; die Gruppierung
 * bleibt erhalten, weil sie für Screenreader die Frage mit ihren Antworten
 * verbindet.
 */
.exo-finder__step {
	min-inline-size: 0;
	margin: 0;
	padding: 0;
	border: 0;
}

.exo-finder__legend {
	display: flex;
	align-items: baseline;
	gap: var(--wp--preset--spacing--30);
	padding: 0;
	margin-block-end: var(--wp--preset--spacing--40);
}

.exo-finder__number {
	display: grid;
	place-items: center;
	flex: none;
	inline-size: 1.75rem;
	block-size: 1.75rem;
	border-radius: var(--radius-pill);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.exo-finder__question {
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 600;
	line-height: var(--line-height-heading);
}

/*
 * Der Schrittzähler nennt das Ende. „Frage 2 von 4" ist der Unterschied
 * zwischen einer überschaubaren Aufgabe und einem Formular ohne Boden.
 */
.exo-finder__progress {
	margin-block: calc(-1 * var(--wp--preset--spacing--20)) var(--wp--preset--spacing--40);
	padding-inline-start: calc(1.75rem + var(--wp--preset--spacing--30));
	color: var(--color-text-secondary);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	letter-spacing: 0.04em;
}

/*
 * Folgt der Hinweis, gehören beide Zeilen zusammen: Der Hinweis verliert
 * seinen negativen Anfangsabstand, der ihn sonst an den Zähler klebt.
 */
.exo-finder__progress + .exo-finder__hint {
	margin-block-start: 0;
}

.exo-finder__hint {
	max-inline-size: 68ch;
	margin-block: calc(-1 * var(--wp--preset--spacing--20)) var(--wp--preset--spacing--40);
	padding-inline-start: calc(1.75rem + var(--wp--preset--spacing--30));
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

/*
 * Alle Antwortflächen einer Frage sind gleich hoch.
 *
 * Ohne `grid-auto-rows: 1fr` richtet sich jede Zeile nach ihrem eigenen
 * Inhalt: „≤ 115 × 65 × 165 mm" bleibt einzeilig, „Weiß ich noch nicht"
 * bricht auf dem Telefon um - und die Flächen stehen unterschiedlich hoch
 * nebeneinander. Gleich große Ziele sind hier keine Kosmetik, sondern
 * gleichwertige Antworten: Eine größere Fläche liest sich als die
 * empfohlene.
 */
.exo-finder__options {
	display: grid;
	grid-auto-rows: 1fr;
	gap: var(--wp--preset--spacing--30);
	padding-inline-start: calc(1.75rem + var(--wp--preset--spacing--30));
}

/*
 * Die gesamte Fläche ist das Ziel, nicht nur das Auswahlfeld. Ein
 * Radioknopf misst rund 16px; Regel R7 verlangt für Bedienelemente 44px.
 */
.exo-finder__option {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	min-block-size: var(--touch-target);
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
	cursor: pointer;
	transition: border-color var(--duration-fast) var(--easing-standard);
}

.exo-finder__option:hover {
	border-color: var(--color-border-strong);
}

/*
 * Die gewählte Antwort trägt die Marke. `:has()` erspart hier eine
 * JavaScript-Zustandsverwaltung: Der Browser kennt den Zustand ohnehin.
 */
.exo-finder__option:has(input:checked) {
	border-color: var(--color-brand);
	background-color: var(--color-surface-brand);
}

.exo-finder__option:has(input:focus-visible) {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

.exo-finder__option input {
	flex: none;
	inline-size: 1.125rem;
	block-size: 1.125rem;
	margin: 0;
}

/*
 * „Weiter" und „Zurück" gehören zusammen und stehen deshalb eng beieinander;
 * der weite Abstand ließ sie als zwei unabhängige Angebote lesen. „Von vorn
 * beginnen" ist dagegen kein dritter Schritt derselben Reihe, sondern der
 * Ausstieg aus der ganzen Auswahl - es rückt über `margin-inline-start: auto`
 * an den rechten Rand des Behälters, und der Abstand dorthin entsteht aus dem
 * freien Raum, nicht aus einem Zahlenwert.
 */
.exo-finder__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
}

.exo-finder__actions .exo-finder__reset {
	margin-inline-start: auto;
}

.exo-finder__submit {
	min-block-size: var(--control-standard);
	padding-inline: var(--wp--preset--spacing--60);
	border: 0;
	border-radius: var(--radius-pill);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-size: var(--wp--preset--font-size--base);
	font-weight: 600;
	cursor: pointer;
}

.exo-finder__submit:hover {
	background-color: var(--color-brand-hover);
}

/*
 * Zurück, Von vorn beginnen: Nebenwege neben der einen Schaltfläche, die
 * weiterführt. Sie sind Links, keine Knöpfe - sie ändern nichts, sie
 * führen nur an eine andere Stelle derselben Auswahl.
 */
/*
 * „Zurück" ist die zweite Handlung des Schritts, nicht ein Nebenweg: Wer
 * eine Antwort korrigieren will, sucht ein Bedienelement neben „Weiter"
 * und keinen Textlink. Es trägt deshalb die sekundäre Form - dieselbe
 * Höhe und Rundung wie die Hauptschaltfläche, aber Kontur statt Fläche.
 * Orange bleibt der einen Handlung vorbehalten, die weiterführt (R7).
 */
.exo-finder__back {
	display: inline-flex;
	align-items: center;
	min-block-size: var(--control-standard);
	padding-inline: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-pill);
	background-color: var(--color-surface);
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--base);
	font-weight: 600;
	text-decoration: none;
	transition: border-color var(--duration-fast) var(--easing-standard);
}

.exo-finder__back:hover,
.exo-finder__back:focus-visible {
	border-color: var(--color-brand);
}

/*
 * „Von vorn beginnen" trägt jetzt die zurückhaltende Form, die zuvor
 * „Zurück" hatte: Ein Weg, der alle bisherigen Antworten verwirft, gehört
 * nicht als drittes Bedienelement neben die beiden Schaltflächen.
 */
.exo-finder__reset,
.exo-finder__again a {
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
}

.exo-finder__reset:hover,
.exo-finder__again a:hover {
	color: var(--color-brand);
}

.exo-finder__again {
	margin-block-start: var(--wp--preset--spacing--40);
}

/* --- Ergebnis --------------------------------------------------- */
.exo-finder__result {
	margin-block-start: var(--component-gap-md);
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border-dark);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-stage);
	color: var(--color-text-on-dark);
}

.exo-finder__result > * {
	margin-block: 0;
}

.exo-finder__result-label {
	color: var(--color-brand);
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.exo-finder__best-name {
	margin-block: var(--wp--preset--spacing--20) 0;
	color: var(--color-text-on-dark);
	font-size: var(--wp--preset--font-size--heading-3);
}

.exo-finder__reasons {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin-block: var(--wp--preset--spacing--40) 0;
	padding-inline-start: 0;
	list-style: none;
}

.exo-finder__reasons > li {
	position: relative;
	margin-block: 0;
	padding-inline-start: 1.75rem;
	color: var(--wp--preset--color--ink-300);
	line-height: var(--line-height-ui);
}

/* Häkchen wie in der Leistungsübersicht des Einstiegs – dieselbe Aussage. */
.exo-finder__reasons > li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0.3em;
	inset-block-start: 0.28em;
	inline-size: 0.36em;
	block-size: 0.66em;
	border: solid var(--color-brand);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

.exo-finder__none {
	color: var(--wp--preset--color--ink-200);
	font-size: var(--font-size-lead);
	line-height: var(--line-height-body);
}

/*
 * Eine Anforderung, die kein Werkstoff erfüllt (Auswahlhilfe). Steht über dem
 * Vorschlag, weil sie ihn einschränkt: Wer sie überliest, nimmt eine Empfehlung
 * mit, die eine seiner Angaben nicht erfüllt. Betonung über den Balken, nicht
 * über Rot - es ist kein Fehler des Besuchers.
 */
.exo-finder__gap {
	margin-block-end: var(--wp--preset--spacing--30);
	border-inline-start: 3px solid var(--wp--preset--color--brand-500);
	padding-inline-start: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-body);
}

.exo-finder__gap a {
	display: inline-block;
	margin-block-start: 0.25rem;
}

.exo-finder__alternatives {
	margin-block-start: var(--component-gap-md) !important;
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--color-border-dark);
}

.exo-finder__alternatives-title {
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.exo-finder__alternative-list {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	margin-block: var(--wp--preset--spacing--40) 0;
	padding-inline-start: 0;
	list-style: none;
}

.exo-finder__alternative-list > li {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	margin-block: 0;
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-finder__alternative-list strong {
	color: var(--color-text-on-dark);
	font-weight: 600;
}

.exo-finder__excluded {
	margin-block-start: var(--wp--preset--spacing--50) !important;
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
}

/*
 * Die Zeile war als bedienbar nicht erkennbar: Sie sah aus wie eine
 * Zwischenüberschrift, obwohl ein Klick die Ausschlussgründe aufklappt.
 *
 * Der Pfeil steht rechts und in Markenfarbe wie bei den übrigen weiterführenden
 * Zeilen der Website - er dreht sich beim Öffnen aber nach unten, statt
 * unverändert nach rechts zu zeigen. Ein statischer Rechtspfeil kündigt einen
 * Seitenwechsel an; hier bleibt man auf der Seite, und der gedrehte Pfeil sagt
 * genau das.
 *
 * `list-style: none` samt WebKit-Pseudoelement entfernt das eingebaute Dreieck
 * links: Zwei Zeichen für dieselbe Handlung, an beiden Enden der Zeile.
 */
.exo-finder__excluded summary {
	min-block-size: var(--touch-target);
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	cursor: pointer;
	color: var(--wp--preset--color--ink-200);
	font-weight: 600;
	list-style: none;
}

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

.exo-finder__excluded summary::after {
	content: "→";
	margin-inline-start: auto;
	color: var(--color-brand);
	font-weight: 400;
	transition: transform var(--duration-fast) var(--easing-standard);
}

.exo-finder__excluded[open] summary::after {
	transform: rotate(90deg);
}

.exo-finder__excluded ul {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin-block: var(--wp--preset--spacing--30) 0;
	padding-inline-start: var(--wp--preset--spacing--50);
	line-height: var(--line-height-ui);
}

.exo-finder__excluded strong {
	color: var(--wp--preset--color--ink-200);
}

.exo-finder__disclaimer {
	margin-block-start: var(--component-gap-md) !important;
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--color-border-dark);
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-finder__cta {
	margin-block-start: var(--wp--preset--spacing--40) !important;
	font-weight: 600;
}

.exo-finder__cta a {
	color: var(--color-brand);
}

@media (width >= 48rem) {
	.exo-finder__options {
		grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
	}
}

/* ------------------------------------------------------------------
 * Prüfwerkzeuge (Bauraum-Check, Konstruktionsprüfung)
 *
 * Teilen sich die Gestalt mit der Auswahlhilfe: eigene Fläche, an der
 * Kontur als bedienbar erkennbar, Ergebnis auf dunkler Bühne. Der
 * Unterschied liegt in der Eingabe - hier Zahlen statt vorgegebener
 * Antworten.
 * ------------------------------------------------------------------ */
.exo-check {
	margin-block: var(--component-gap-lg);
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-subtle);
}

.exo-check__intro > * {
	margin-block: 0;
}

.exo-check__title {
	font-size: var(--wp--preset--font-size--heading-3);
	letter-spacing: -0.02em;
}

.exo-check__lead {
	max-inline-size: 62ch;
	margin-block-start: var(--wp--preset--spacing--30) !important;
	color: var(--color-text-secondary);
}

.exo-check__form {
	display: grid;
	gap: var(--component-gap-md);
	margin-block-start: var(--component-gap-md);
}

.exo-check__group {
	min-inline-size: 0;
	margin: 0;
	padding: 0;
	border: 0;
}

.exo-check__legend {
	padding: 0;
	margin-block-end: var(--wp--preset--spacing--30);
	font-weight: 600;
}

.exo-check__radios {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--30);
}

.exo-check__radio {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	min-block-size: var(--touch-target);
	padding-inline: var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
	cursor: pointer;
}

.exo-check__radio:has(input:checked) {
	border-color: var(--color-brand);
	background-color: var(--color-surface-brand);
}

.exo-check__radio:has(input:focus-visible) {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

.exo-check__radio input {
	flex: none;
	inline-size: 1.125rem;
	block-size: 1.125rem;
	margin: 0;
}

.exo-check__fields {
	display: grid;
	gap: var(--wp--preset--spacing--50);
}

.exo-check__field {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	min-inline-size: 0;
}

.exo-check__label {
	font-weight: 600;
	line-height: var(--line-height-ui);
}

/*
 * Die Einheit steht im Feld, nicht daneben. Ein „mm" hinter dem Rahmen
 * gehört optisch zur nächsten Spalte; darin ist eindeutig, worauf es sich
 * bezieht. Der Rahmen liegt deshalb an der Hülle und reagiert stellvertretend
 * auf den Fokus des Feldes.
 */
.exo-check__input {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	padding-inline: var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface);
}

.exo-check__input:focus-within {
	border-color: var(--color-brand);
}

.exo-check__input input {
	min-inline-size: 0;
	inline-size: 100%;
	min-block-size: var(--control-standard);
	padding: 0;
	border: 0;
	background-color: transparent;
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--base);
	font-variant-numeric: tabular-nums;
}

.exo-check__input input:focus,
.exo-check__input input:focus-visible {
	outline: none;
}

.exo-check__unit {
	flex: none;
	color: var(--color-text-muted);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-check__toggle {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	min-block-size: var(--touch-target);
	font-weight: 500;
	cursor: pointer;
}

.exo-check__toggle input {
	flex: none;
	inline-size: 1.125rem;
	block-size: 1.125rem;
	margin: 0;
}

.exo-check__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--50);
}

.exo-check__submit {
	min-block-size: var(--control-standard);
	padding-inline: var(--wp--preset--spacing--60);
	border: 0;
	border-radius: var(--radius-pill);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-size: var(--wp--preset--font-size--base);
	font-weight: 600;
	cursor: pointer;
}

.exo-check__submit:hover {
	background-color: var(--color-brand-hover);
}

.exo-check__reset {
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
}

/* --- Ergebnis --------------------------------------------------- */
.exo-check__result {
	margin-block-start: var(--component-gap-md);
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border-dark);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-stage);
	color: var(--color-text-on-dark);
}

.exo-check__result > * {
	margin-block: 0;
}

.exo-check__verdict {
	font-size: var(--font-size-lead);
	font-weight: 600;
	line-height: var(--line-height-heading);
}

/*
 * Der Zustand hängt nicht allein an der Farbe: Jeder Eintrag trägt seinen
 * Text, und die Zusammenfassung nennt die Anzahl. Die Farbe beschleunigt das
 * Erfassen, sie trägt es nicht (WCAG 1.4.1).
 */
.exo-check__verdict--ja {
	color: var(--wp--preset--color--success-600);
}

.exo-check__verdict--knapp {
	color: var(--color-brand);
}

.exo-check__verdict--nein {
	color: var(--wp--preset--color--danger-600);
}

.exo-check__list {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	margin-block: var(--component-gap-md) 0;
	padding-inline-start: 0;
	list-style: none;
}

.exo-check__item {
	display: grid;
	gap: var(--wp--preset--spacing--10);
	margin-block: 0;
	padding-inline-start: var(--wp--preset--spacing--50);
	border-inline-start: 3px solid var(--color-border-dark);
	line-height: var(--line-height-ui);
}

.exo-check__item--ok {
	border-inline-start-color: var(--wp--preset--color--success-600);
}

.exo-check__item--knapp {
	border-inline-start-color: var(--color-brand);
}

.exo-check__item--befund {
	border-inline-start-color: var(--wp--preset--color--danger-600);
}

.exo-check__item strong {
	color: var(--color-text-on-dark);
	font-weight: 600;
}

.exo-check__item span {
	color: var(--wp--preset--color--ink-300);
}

/* Der belegende Satz steht kleiner: Er begründet, er behauptet nicht. */
.exo-check__source {
	color: var(--wp--preset--color--ink-500) !important;
	font-size: var(--wp--preset--font-size--sm);
}

.exo-check__note {
	margin-block-start: var(--component-gap-md) !important;
	padding: var(--wp--preset--spacing--40);
	border-radius: var(--radius-md);
	background-color: rgb(255 255 255 / 5%);
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-check__disclaimer {
	margin-block-start: var(--component-gap-md) !important;
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--color-border-dark);
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-check__cta {
	margin-block-start: var(--wp--preset--spacing--40) !important;
	font-weight: 600;
}

.exo-check__cta a {
	color: var(--color-brand);
}

@media (width >= 48rem) {
	.exo-check__fields {
		grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
	}

	.exo-check--bauraum .exo-check__fields {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* ------------------------------------------------------------------
 * Mobile Handlungsleiste
 *
 * Nur unterhalb der Desktopbreite: Der Kopfbereich hat dort genug Platz für
 * seine eigene feste Handlung (`.exo-header__cta`), eine zweite am
 * Bildschirmrand wäre dort eine Dopplung. `inc/mobile-cta.php` gibt die
 * Auszeichnung auf jeder Vorlage aus; ob sie sichtbar wird, entscheidet
 * ausschließlich dieses Stylesheet.
 * ------------------------------------------------------------------ */
.exo-mobile-cta {
	display: none;
}

@media (width < 48rem) {
	/*
	 * DIE DREI FESTEN EBENEN DIESER WEBSITE, VON UNTEN NACH OBEN
	 *
	 *   10  diese Aktionsleiste
	 *   20  `.exo-header` (sticky) – und damit alles darin, auch das
	 *       geöffnete Menü
	 *
	 * Hier stand 30, also über dem Kopfbereich. Das war ein Fehler mit einer
	 * unangenehmen Folge: Weil `.exo-header` mit `position: sticky` und
	 * `z-index: 20` einen **Stapelkontext** aufspannt, gilt der Wert 100000 des
	 * geöffneten Menüs nur *innerhalb* dieses Kontexts. Nach außen zählt allein
	 * die 20 des Kopfbereichs. Die Leiste mit 30 lag deshalb über der
	 * geöffneten Navigation – gemessen: bei y=808 traf der Zeiger die Leiste,
	 * nicht die Schublade.
	 *
	 * Eine höhere Zahl am Menü hätte daran nichts geändert; sie wird am
	 * Kontextrand abgeschnitten. Richtig ist die Reihenfolge der beiden
	 * Geschwister.
	 *
	 * Unter dem Inhalt darf die Leiste nicht liegen: Ein Wert über `auto`
	 * genügt, damit sie über gewöhnlichem Seiteninhalt bleibt.
	 */
	.exo-mobile-cta {
		position: fixed;
		inset-inline: 0;
		inset-block-end: 0;
		z-index: 10;
		display: flex;
		justify-content: center;

		/* Reicht unter Home-Leiste/Gestenzone iOS-typischer Geräte weiter,
		   ohne auf Geräten ohne Aussparung zusätzlichen Rand zu erzeugen. */
		padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--30)
			max(var(--wp--preset--spacing--30), env(safe-area-inset-bottom));
		background-color: var(--color-surface);
		border-block-start: 1px solid var(--color-border);
		box-shadow: var(--shadow-lg);
	}

	/*
	 * Body-Klasse aus `inc/mobile-cta.php`: Nur auf Seiten mit sichtbarer
	 * Leiste hält der Fußbereich Abstand, sonst bliebe auf der
	 * Projektanfrage und im Bestellvorgang eine unbegründete Lücke.
	 */
	.exo-has-mobile-cta .exo-footer {
		padding-block-end: calc(var(--wp--preset--spacing--80) + env(safe-area-inset-bottom));
	}
}

.exo-mobile-cta__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--wp--preset--spacing--20);
	inline-size: 100%;
	max-inline-size: 26rem;
	min-block-size: var(--control-standard);
	padding-inline: var(--wp--preset--spacing--50);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-weight: 600;
	text-decoration: none;
	border-radius: var(--radius-pill);
	transition: background-color var(--duration-fast) var(--easing-standard);
}

.exo-mobile-cta__link:hover,
.exo-mobile-cta__link:focus-visible {
	background-color: var(--color-brand-hover);
	color: var(--color-text-on-brand);
}

.exo-mobile-cta__icon {
	inline-size: 1.1rem;
	block-size: 1.1rem;
	flex: none;
	fill: none;
	stroke: currentcolor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* ------------------------------------------------------------------
 * Konfigurator-Vorschau (AP-41, ADR-0038)
 * Die Auszeichnung entsteht im Plugin, die Gestaltung hier - wie beim
 * Anfrageformular. `.exo-configurator__stage` bekommt ihre Höhe zusätzlich
 * per JavaScript zugewiesen (Breite × 0,7), diese Regeln sind der Rahmen
 * davor und der Rückfall ohne JavaScript oder WebGL.
 * ------------------------------------------------------------------ */
.exo-configurator {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--40);
}

/*
 * DIE DATEIFLÄCHE
 *
 * Das `input` liegt unsichtbar hinter der Fläche, bleibt aber das Feld: Es
 * behält Tastaturbedienung, Pflichtangabe und die Formatliste des Browsers. Die
 * Fläche ist sein `label` - deshalb genügt ein Klick oder die Leertaste, ohne
 * eine Zeile JavaScript. Der Fokusring sitzt an der Fläche (`:focus-within`),
 * weil das Feld selbst nicht zu sehen ist.
 */
.exo-upload {
	gap: var(--wp--preset--spacing--20);
}

.exo-upload__zone {
	display: grid;
	place-items: center;
	gap: var(--wp--preset--spacing--20);
	padding: var(--wp--preset--spacing--60) var(--wp--preset--spacing--40);
	border: 1px dashed var(--color-border-strong);
	border-radius: var(--radius-md);
	background-color: var(--color-surface-subtle);
	text-align: center;
	cursor: pointer;
	transition:
		border-color 120ms ease,
		background-color 120ms ease;
}

.exo-upload__zone:hover {
	border-color: var(--wp--preset--color--brand-700);
	background-color: var(--color-surface);
}

.exo-upload:focus-within .exo-upload__zone {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

/* Während eine Datei über der Fläche hängt (JavaScript). */
.exo-upload--zieht .exo-upload__zone {
	border-color: var(--wp--preset--color--brand-700);
	border-style: solid;
	background-color: var(--color-surface);
}

.exo-upload__icon {
	color: var(--wp--preset--color--brand-700);
	line-height: 1;
}

.exo-upload__title {
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--md);
	font-weight: 600;
}

.exo-upload__hint {
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

/*
 * Nicht `display: none`: Ein so verstecktes Feld ist für die Tastatur nicht
 * erreichbar und fällt aus der Formularprüfung des Browsers.
 */
.exo-upload__input {
	position: absolute;
	inline-size: 1px;
	block-size: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/*
 * „Auswahl übernehmen" ist der Weg ohne Skript: Es baut die abhängigen Listen
 * über den Server neu auf. Mit Skript folgen sie dem Material unmittelbar.
 */
.exo-offer__form--js .exo-offer__ohne-js {
	display: none;
}

/* Läuft das Skript, entfällt der Absendeknopf: Die Auswahl erledigt alles. */
.exo-configurator--js .exo-configurator__ohne-js {
	display: none;
}

.exo-upload__gewaehlt {
	margin-block: 0;
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--sm);
}

/*
 * EIN CONTAINER FÜR DATEI UND AUSFÜHRUNG
 *
 * Vorgabe des Auftraggebers vom 2026-08-16, und fachlich richtig: Es ist ein
 * Vorgang, keine zwei. Die Linie zeigt den Schritt, der Rahmen den Zusammenhang -
 * die Auswahl ohne Datei ist wirkungslos, die Datei ohne Auswahl ergibt keinen
 * Preis.
 */
.exo-instant {
	display: flex;
	flex-direction: column;
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
}

.exo-instant > * + * {
	margin-block-start: var(--wp--preset--spacing--50);
	padding-block-start: var(--wp--preset--spacing--50);
	border-block-start: 1px solid var(--color-border);
}

/*
 * Im gemeinsamen Rahmen gibt der Auswahlteil seinen eigenen auf.
 *
 * `.exo-offer` bringt Rahmen, eigene Fläche, Innenabstand und eine Breitengrenze
 * mit - es stand auf der Anfrageseite auch allein. Innerhalb von `.exo-instant`
 * ergab das einen Kasten im Kasten: schmaler als das Feld darüber, mit zwei
 * Linien statt einer, und die Trennlinie ging darin unter. Ein Vorgang, ein
 * Rahmen, eine Linie.
 */
.exo-instant > .exo-offer {
	/*
	 * Ränder, Innenabstand und Linie stehen hier vollständig, nicht nur als
	 * Rücknahme: `.exo-offer` setzt seine eigenen Ränder mit `!important`
	 * durch (sie müssen sich auf der Anfrageseite gegen die Blockabstände des
	 * Editors halten), und ein `padding: 0` hier nahm der Regel darüber den
	 * Abstand zur Linie wieder weg. Erst am Bild von Staging zu sehen: Die
	 * Überschrift klebte am Uploadfeld, eine Linie gab es nicht.
	 */
	max-inline-size: none;
	margin-block: var(--wp--preset--spacing--50) 0 !important;
	margin-inline: 0 !important;
	padding: var(--wp--preset--spacing--50) 0 0;
	border-block-start: 1px solid var(--color-border);
	border-block-end: 0;
	border-inline: 0;
	border-radius: 0;
	background-color: transparent;
}


/* Gleiche Stufe wie „Ausführung und Preis" in der zweiten Hälfte des Rahmens. */
.exo-configurator__titel {
	margin-block: 0 var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--lg);
}

/*
 * ZWEI SPALTEN: ANSICHT LINKS, AUSWAHL UND EIGENSCHAFTEN RECHTS
 *
 * Rückmeldung vom 2026-08-18: „3d viewer soll links sein, rechts daneben
 * auswahl von verfahren und farbe und darunter die Eigenschaften".
 *
 * Bis dahin standen Auswahl, Bühne und Befunde untereinander - die Ansicht war
 * dadurch schmal, und wer die Farbe wechselte, sah das Ergebnis erst nach dem
 * Scrollen. Nebeneinander bleibt die Wirkung der Auswahl im Blick.
 *
 * Schmale Anzeigen behalten die Spalten untereinander: Zwei Spalten auf 390 px
 * hieße zwei zu schmale Spalten. Der Umbruchpunkt liegt bei 60rem und nicht bei
 * den üblichen 48rem, weil die Bühne quadratisch nahe ist und darunter beide
 * Hälften gedrückt wirken.
 */
.exo-configurator__viewer {
	display: grid;
	gap: var(--wp--preset--spacing--40);
}

@media (width >= 60rem) {
	.exo-configurator__viewer {
		grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
		align-items: start;
	}

	/* Der Hinweis gehört unter beide Spalten, nicht in eine davon. */
	.exo-configurator__hinweis {
		grid-column: 1 / -1;
	}
}

/*
 * Die Bühne und ihre Werkzeugebene teilen sich einen Kasten: Der Knopf liegt
 * über der Ansicht, gehört aber nicht in sie hinein - siehe die Begründung zur
 * Zeigererfassung in configurator-viewer.js.
 */
.exo-configurator__buehne {
	position: relative;
}

.exo-configurator__seite {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--40);
}

.exo-configurator__controls {
	display: grid;
	gap: var(--wp--preset--spacing--10) var(--wp--preset--spacing--30);
	grid-template-columns: minmax(0, 1fr);
	align-items: center;
}

.exo-configurator__select {
	min-block-size: var(--touch-target);
	padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--20);
	background-color: var(--color-surface);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-sm);
}

/*
 * Die Bühne hat ihre Höhe von Anfang an.
 *
 * Vorher war sie leer, bis das Modell geladen war, und wuchs dann auf die Höhe,
 * die das Skript rechnet (Breite × 0,7). Die halbe Seite sprang in dem Moment
 * nach unten - wer den Knopf darunter treffen wollte, traf ihn nicht mehr
 * (Rückmeldung vom 2026-08-19).
 *
 * `aspect-ratio: 10 / 7` ist dasselbe Verhältnis, das `groesseAnpassen()` in
 * `configurator-viewer.js` setzt. Zwei Stellen für eine Zahl sind eine zu viel;
 * hier ist sie die Vorabantwort, dort die maßgebliche. Läuft sie auseinander,
 * springt die Seite wieder - deshalb steht sie an beiden Stellen mit demselben
 * Kommentar.
 */
.exo-configurator__stage {
	position: relative;
	inline-size: 100%;
	aspect-ratio: 10 / 7;
	min-block-size: 20rem;
	overflow: hidden;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
	touch-action: none;
	cursor: grab;
}

/*
 * Dateiname oben links, in der Ansicht und nicht darüber: Er gehört zum Bild.
 * Er beantwortet die Frage, die nach dem dritten Versuch kommt - welche Datei
 * sehe ich hier gerade?
 *
 * `pointer-events: none`, damit er das Ziehen nicht abfängt. Ein Name, über den
 * sich das Modell nicht drehen lässt, wäre ein Loch in der Bedienfläche.
 */
.exo-configurator__dateiname {
	position: absolute;
	inset-block-start: var(--wp--preset--spacing--20);
	inset-inline-start: var(--wp--preset--spacing--20);
	z-index: 1;
	max-inline-size: calc(100% - 2 * var(--wp--preset--spacing--20));
	margin: 0;
	padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--20);
	border-radius: var(--radius-sm);
	background-color: color-mix(in srgb, var(--color-surface) 85%, transparent);
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--xs);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	pointer-events: none;
}

/* Ladeanzeige mittig, solange Modell und Annahme laufen. */
.exo-configurator__laden {
	position: absolute;
	inset: 0;
	display: grid;
	place-content: center;
	justify-items: center;
	gap: var(--wp--preset--spacing--20);
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-configurator__spinner {
	inline-size: 1.75rem;
	block-size: 1.75rem;
	border: 2px solid var(--color-border);
	border-block-start-color: var(--color-brand);
	border-radius: var(--radius-pill);
	animation: exo-drehen 900ms linear infinite;
}

@keyframes exo-drehen {
	to {
		transform: rotate(360deg);
	}
}

/*
 * Wer Bewegung im Bild vermeidet, bekommt keinen Kreisel, sondern einen
 * ruhenden Ring. Die Auskunft steht ohnehin als Text daneben.
 */
@media (prefers-reduced-motion: reduce) {
	.exo-configurator__spinner {
		animation: none;
	}
}

.exo-configurator__stage:active {
	cursor: grabbing;
}

.exo-configurator__stage:focus-visible {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

/*
 * Der Radius steht zusätzlich am Canvas.
 *
 * `overflow: hidden` am Kasten darüber genügte nicht: three.js malt seinen
 * Hintergrund über die volle Fläche des Canvas, und der lag mit eckigen Ecken
 * über den runden des Kastens (Rückmeldung vom 2026-08-18: „der hintergrund
 * des 3d viewers ignoriert aktuell die eckenrundung des containers"). Ein
 * eigener Radius am Canvas beschneidet die Farbfläche dort, wo sie entsteht -
 * unabhängig davon, ob der Kasten darüber noch beschneidet.
 */
.exo-configurator__stage canvas {
	display: block;
	inline-size: 100%;
	block-size: 100%;
	border-radius: inherit;
}

/*
 * Die Hinweise der Dateiauswertung, über der Ansicht.
 *
 * Sie standen bis zum 2026-08-20 als Zeilen in der Eigenschaftstabelle, mit
 * dem Schlüssel des ERP als Beschriftung („Hinweis: netzschluss") und direkt
 * unter der Zeile, die dasselbe schon als Messwert sagte. Die Tabelle trägt
 * Eigenschaften; ein Satz in Prosa ist keine.
 *
 * Bewusst schmucklos: dieselbe Kante wie eine Warnung, aber ohne Symbol und
 * ohne Überschrift. Der Kasten sitzt unmittelbar über dem Modell, und was dort
 * steht, gehört zu dem, was man gleich sieht.
 */
.exo-configurator__befundhinweise {
	margin-block-end: var(--wp--preset--spacing--20);
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border);
	border-inline-start: 3px solid var(--color-warning);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface-subtle);
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--small);
}

.exo-configurator__befundhinweise p {
	margin: 0;
}

.exo-configurator__befundhinweise p + p {
	margin-block-start: var(--wp--preset--spacing--20);
}

/*
 * Die Werkzeugleiste steht **unter** der Bühne, nicht darin.
 *
 * In der Ecke der Ansicht lag ein einzelner Knopf; acht liegen dort nicht mehr,
 * ohne das Bild zu verdecken - und auf 320 px wäre die halbe Ansicht Knopf. Die
 * Leiste bricht deshalb um und behält ihre Gruppen zusammen: Ausrichtung,
 * Menge, Blickrichtung, Bauraum. Getrennte Gruppen, weil ein „+" neben einem
 * Drehpfeil sonst so aussieht, als drehte es weiter.
 */
.exo-configurator__tools {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20);
	margin-block-start: var(--wp--preset--spacing--20);
}

.exo-configurator__toolgroup {
	display: flex;
	align-items: center;
	gap: 1px;
	padding: 2px;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
	background-color: var(--color-surface);
}

/*
 * Die Auskunft des Einpassens. Sie steht als eigene Zeile unter den Gruppen -
 * `flex-basis: 100%` bricht sie um -, damit sie die Leiste nicht breiter macht
 * und auf schmalen Anzeigen keine Gruppe zerreisst.
 */
.exo-configurator__toolmeldung {
	flex-basis: 100%;
	margin: 0;
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--small);
}

.exo-configurator__werkzeug {
	display: grid;
	place-items: center;
	inline-size: var(--touch-target);
	block-size: var(--touch-target);
	padding: 0;
	border: 0;
	border-radius: var(--radius-pill);
	background-color: transparent;
	color: var(--color-text-primary);
	cursor: pointer;
	transition:
		background-color 120ms ease,
		color 120ms ease;
}

.exo-configurator__werkzeug:hover {
	background-color: var(--color-surface-subtle);
}

.exo-configurator__werkzeug:focus-visible {
	outline: 2px solid var(--color-focus);
	outline-offset: -2px;
}

/*
 * Ein abgeschalteter Knopf bleibt sichtbar und verliert nur seine Wirkung: Wer
 * bei einem Stück steht, soll sehen, dass „weniger" hier endet, statt sich zu
 * fragen, wohin der Knopf verschwunden ist.
 */
.exo-configurator__werkzeug:disabled {
	color: var(--color-text-secondary);
	opacity: 0.45;
	cursor: default;
}

/* Der gedrückte Zustand des Bauraum-Schalters. */
.exo-configurator__werkzeug[aria-pressed='true'] {
	background-color: var(--color-surface-subtle);
	color: var(--color-brand);
}

.exo-configurator__menge {
	min-inline-size: 2.5rem;
	padding-inline: var(--wp--preset--spacing--10);
	font-size: var(--wp--preset--font-size--sm);
	font-variant-numeric: tabular-nums;
	text-align: center;
}


/*
 * Die Eigenschaftstabelle trägt `figure.wp-block-table` und wird damit vom
 * Theme gestaltet wie jede andere Tabelle im Seitenkörper. Hier steht nur, was
 * ihre Lage in der rechten Spalte betrifft; alles Übrige wäre eine zweite
 * Meinung zum Tabellenbild. Begründung in configurator-viewer.js.
 */
.exo-configurator__befunde {
	margin: 0;
}

.exo-configurator__hinweis,
.exo-configurator__noscript,
.exo-configurator__fallback {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-secondary);
}

/*
 * „Andere Datei wählen" neben der Ansicht.
 *
 * Kein Hauptknopf: Der Weg vorwärts ist die Auswahl rechts, dies ist der Weg
 * zurück. Er sieht deshalb aus wie ein Verweis und nicht wie eine Schaltfläche,
 * bleibt aber ein `button` - er löst eine Aktion aus und führt nirgendwohin.
 */
.exo-configurator__wechsel {
	align-self: start;
	padding: var(--wp--preset--spacing--10) 0;
	border: 0;
	background: none;
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	text-decoration: underline;
	text-underline-offset: 0.2em;
	cursor: pointer;
}

.exo-configurator__wechsel:hover {
	color: var(--color-text-primary);
}

.exo-configurator__wechsel:focus-visible {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

/*
 * Zusammengeklappte Dateifläche, solange ein Preis steht.
 *
 * Sie sieht aus wie ein Weg, nicht wie ein Formularrest: eine Zeile mit dem
 * Zeigefinger darauf. Die Begründung, warum sie überhaupt bleibt, steht in
 * render.php - ohne sie gäbe es keinen Weg zu einer zweiten Datei.
 */
.exo-configurator__erneut > summary {
	inline-size: fit-content;
	padding-block: var(--wp--preset--spacing--10);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-secondary);
	cursor: pointer;
}

.exo-configurator__erneut > summary:hover {
	color: var(--color-text-primary);
}

.exo-configurator__erneut[open] > summary {
	margin-block-end: var(--wp--preset--spacing--20);
}

/*
 * Datei nicht angenommen (AP-52). Deutlicher als der Hinweis darunter, aber
 * keine Fehlermeldung in Rot: Der Kunde hat nichts falsch gemacht, und der Weg
 * weiter ist ein zweites Ablegen. Der Balken links trägt die Betonung, nicht
 * die Textfarbe - sie muss lesbar bleiben.
 */
.exo-configurator__abgelehnt {
	margin-block-start: var(--wp--preset--spacing--20);
	border-inline-start: 3px solid var(--wp--preset--color--brand-500);
	padding-inline-start: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-primary);
}

@media (width >= 48rem) {
	.exo-configurator__stage {
		max-block-size: 32rem;
	}
}

/* ---------------------------------------------------------------------------
 * Sofortangebot: Auswahl und Preis (AP-42)
 *
 * Der Block sitzt unter der Dateiannahme auf derselben Seite und trägt dieselbe
 * getönte Fläche wie sie – zwei Kästen einer Ordnung, wie der Auftraggeber es
 * für den Hinweis auf der Anfrageseite entschieden hat.
 *
 * Der Preis ist die einzige Stelle mit hervorgehobener Fläche. Er ist eine
 * verbindliche Zusage; alles andere auf der Seite führt nur dorthin.
 * --------------------------------------------------------------------------- */

.exo-offer {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	max-inline-size: var(--container-text);
	margin-block: var(--component-gap-md) !important;
	margin-inline: 0 auto !important;
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	background-color: var(--color-surface-subtle);
}

.exo-offer__titel {
	margin-block: 0;
	font-size: var(--wp--preset--font-size--lg);
}

/*
 * Zwei Spalten ab 40 rem: Sieben Auswahlfelder untereinander ergeben eine
 * Strecke, die auf einem Notebook nicht mehr in ein Bild passt – und wer die
 * Auswahl ändert, muss den Preis darunter sehen können.
 *
 * Ausrichtung wie in den Anfrageformularen (AP-18): Beschriftung, Hilfetext und
 * Eingabe jedes Feldes sind eigene Zeilenspuren der Reihe. „Menge" trägt als
 * einziges Feld einen Hinweis („1 bis 50 Stück"); ohne diese Spuren schob er das
 * Eingabefeld nach unten, und es stand tiefer als die Auswahl daneben. Die
 * ungenutzte Spur bleibt beim Nachbarfeld einfach leer.
 */
.exo-offer__stufen {
	display: grid;
	grid-template-rows: auto auto auto;
	gap: var(--wp--preset--spacing--30);
	align-items: start;
}

@media (width >= 40rem) {
	.exo-offer__stufen {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

.exo-offer__stufen > .exo-field {
	display: grid;
	/* Fallback für Browser ohne Subgrid, ausschlaggebend ist die Zeile darunter. */
	grid-template-rows: auto auto auto;
	grid-template-rows: subgrid;
	grid-row: span 3;
}

.exo-offer__stufen > .exo-field > .exo-field__label {
	grid-row: 1;
}

.exo-offer__stufen > .exo-field > .exo-field__hint {
	grid-row: 2;
}

.exo-offer__stufen > .exo-field > .exo-field__control {
	grid-row: 3;
}

/*
 * Die Nachbearbeitung ist ein `fieldset`, weil mehrere Ankreuzfelder eine
 * gemeinsame Beschriftung brauchen. Rahmen und Polsterung der Browservorgabe
 * entfallen – wie bei `.exo-request__group`; die Beschriftung trägt dieselbe
 * Auszeichnung wie jede andere Feldbeschriftung, sonst behauptet die Gruppe eine
 * Ordnung über den übrigen sechs Stufen, die sie nicht hat.
 */
.exo-offer__nachbearbeitung {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	border: 0;
	margin: 0;
	padding: 0;
}

.exo-offer__nachbearbeitung > legend {
	padding: 0;
	margin-block-end: var(--wp--preset--spacing--20);
	font-weight: 500;
}

/*
 * Zwei Absender an einem Formular, zwei Gewichte.
 *
 * „Preis berechnen" ist das Ziel, „Auswahl übernehmen" nur der Weg dorthin
 * (es verkleinert die abhängigen Listen). Beide in Markenfarbe stellten die
 * Frage, welcher gemeint ist – gemessen im Bild, bevor diese Regel hier stand.
 *
 * Die Kernvorlage `is-style-outline` greift nur innerhalb der Blockauszeichnung
 * `.wp-block-button`; ein Formularknopf trägt sie nicht.
 */
.exo-offer__zweitknopf,
.exo-offer__zweitknopf:hover,
.exo-offer__zweitknopf:focus-visible {
	border: 1px solid var(--color-border-strong);
	background-color: var(--color-surface);
	color: var(--color-text);
}

.exo-offer__zweitknopf:hover {
	background-color: var(--color-surface-subtle);
}

.exo-offer__zweitknopf:active {
	background-color: var(--color-border);
}

/*
 * Die Knopfzeile bekommt Luft nach oben und unten (Rückmeldung vom 2026-08-16).
 * Sie ist der Punkt, an dem der Kunde handelt; vorher stand sie unmittelbar an
 * den Auswahlfeldern und darunter am nächsten Abschnitt.
 */
.exo-offer__aktionen {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--30);
	align-items: center;
	margin-block: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
}

.exo-offer__preis {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-md);
	background-color: var(--color-surface);
}

/*
 * Abgelaufen wird zurückgenommen, nicht rot gemeldet: Es ist kein Fehler des
 * Kunden, sondern eine Frist, die abgelaufen ist. Der Betrag bleibt lesbar,
 * damit nachvollziehbar ist, was einmal galt – ein Kaufknopf steht dort nicht.
 */
.exo-offer__preis--abgelaufen {
	border-color: var(--color-border);
	background-color: var(--color-surface-subtle);
	color: var(--color-text-secondary);
}

.exo-offer__betrag {
	display: grid;
	gap: var(--wp--preset--spacing--10);
	margin-block: 0;
}

.exo-offer__betrag > strong {
	font-size: var(--wp--preset--font-size--heading-2);
	font-weight: 600;
	line-height: 1.1;
}

.exo-offer__betrag-hinweis,
.exo-offer__gueltig,
.exo-offer__kennung,
.exo-offer__hinweis {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-secondary);
}

.exo-offer__gueltig,
.exo-offer__kennung {
	margin-block: 0;
}

.exo-offer__gueltig--abgelaufen {
	color: var(--color-text);
}

/*
 * Steuerhinweis unter dem Betrag. Klein, aber nicht versteckt: Er sagt, für
 * welches Land der Bruttobetrag gilt, und verhindert, dass ein Kunde im EU-Ausland
 * die Zusage an der Kasse für gebrochen hält.
 */
.exo-offer__steuerhinweis {
	margin-block: calc(-1 * var(--wp--preset--spacing--10)) var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--xs);
	line-height: var(--line-height-body);
	color: var(--color-text-secondary);
}

/*
 * Die Aufschlüsselung als Tabelle im Bild aller übrigen Tabellen
 * (`figure.wp-block-table`, Rückmeldung vom 2026-08-19). Hier steht nur ihre
 * Breite; alles Übrige käme sonst als zweite Meinung zum Tabellenbild.
 *
 * NICHT ÜBER DIE VOLLE BREITE
 *
 * Zwei kurze Spalten über 48 rem gezogen rissen Anteil und Prozentwert
 * auseinander - das Auge musste die Zeile ablaufen, um beides zu verbinden.
 * `fit-content` lässt die Tabelle so schmal werden, wie ihr Inhalt es zulässt.
 *
 * Die Obergrenze ist nicht das Drittel der Lesebreite (16 rem), sondern
 * 22 rem: Bei 16 rem bricht „Rüsten, Arbeit, Betriebsstoffe" auf drei Zeilen,
 * und eine Tabelle, deren Beschriftungen umbrechen, spart Breite auf Kosten
 * der Höhe. Auf schmalen Anzeigen begrenzt `100%`.
 */
.exo-offer__anteile {
	inline-size: fit-content;
	max-inline-size: min(100%, 22rem);
	margin-block: var(--wp--preset--spacing--20) 0;
	margin-inline: 0;
}

/* Zahlen an der Kante, an der sie sich vergleichen lassen. */
.exo-offer__anteile td {
	text-align: end;
}

.exo-offer__kauf {
	margin-block: 0;
}

/* ------------------------------------------------------------------
 * Fortschrittsanzeige im Kundenbereich (AP-45)
 *
 * `.exo-orders-scope` ist der Geltungsbereich, den diese Kontoseite um ihre
 * eigene Ausgabe legt. Er steht in derselben `:is()`-Gruppe wie
 * `.exo-page__body` und `.exo-article__content`, damit eine Tabelle hier
 * aussieht wie jede andere Tabelle der Website. Ohne ihn stand die
 * Positionstabelle als nackter Text da: Der Kundenbereich gehört WooCommerce
 * und ist keiner der beiden Inhaltsbereiche, für die die Tabellenregeln
 * geschrieben sind.
 *
 * ER HEISST NICHT `.exo-account`
 *
 * So hieß er zuerst, und das war ein Fehler: Das Theme legt dieselbe Klasse
 * bereits auf das `<main>` der Kontoseite (`page-kundenkonto.html`). Die
 * Tabellenregeln hätten damit den **ganzen** Kontobereich erfasst - auch die
 * Bestellungen, Downloads und Adressen von WooCommerce, die eigene Regeln
 * tragen. Zwei Systeme über derselben Tabelle ergäben ein drittes. Am
 * 2026-08-19 auf Staging aufgefallen, weil die Klasse zweimal im Dokument
 * stand.
 *
 * Die Seite liegt in WooCommerces Kontobereich und erbt dessen Rahmen. Hier
 * steht nur, was der Auftragsstand zusätzlich braucht: die Liste, das
 * Fortschrittsband und die Trennung von Schätzung und Zusage.
 *
 * Das Band ist eine geordnete Liste und keine Grafik. Ein Balken mit einer
 * Prozentzahl behauptete eine Genauigkeit, die es nicht gibt - zwischen
 * „In Fertigung" und „Nacharbeit" liegt kein messbarer Anteil. Stationen mit
 * Namen sagen dasselbe ehrlicher, funktionieren ohne Farbe und lassen sich
 * vorlesen.
 * ------------------------------------------------------------------ */
.exo-orders {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	margin-block: var(--wp--preset--spacing--40);
	padding: 0;
	list-style: none;
}

.exo-orders__link {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	gap: var(--wp--preset--spacing--10) var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--40);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	color: inherit;
	text-decoration: none;
}

.exo-orders__link:hover {
	border-color: var(--color-border-strong);
	background-color: var(--color-surface-subtle);
}

.exo-orders__link:focus-visible {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

.exo-orders__nummer {
	font-family: var(--wp--preset--font-family--mono);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-orders__status {
	grid-column: 1;
	font-weight: 600;
}

.exo-orders__seit {
	grid-column: 2;
	grid-row: 2;
	align-self: end;
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-secondary);
}

/*
 * Unter 30 rem stehen Nummer, Stand und Datum untereinander: Zwei Spalten
 * drückten den Stand auf 320 px in den Umbruch, und ein umbrechender Stand
 * liest sich wie zwei.
 */
@media (width <= 30rem) {
	.exo-orders__link {
		grid-template-columns: minmax(0, 1fr);
	}

	.exo-orders__seit {
		grid-column: 1;
		grid-row: auto;
	}
}

.exo-order__back {
	margin-block: 0 var(--wp--preset--spacing--30);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-order__title {
	margin-block: 0 var(--wp--preset--spacing--10);
	font-family: var(--wp--preset--font-family--mono);
}

.exo-order__bestellung,
.exo-order__fussnote,
.exo-order__leer,
.exo-order__rechnung,
.exo-order__stand-hinweis {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-secondary);
}

/*
 * Der Hinweis auf einen alten Stand steht abgesetzt, nicht als Warnung: Es ist
 * kein Fehler, sondern eine Einordnung. Rot wäre eine Störungsmeldung, und die
 * verlangt AP-45 ausdrücklich nicht.
 */
.exo-order__stand-hinweis {
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border-inline-start: 3px solid var(--color-border-strong);
	background-color: var(--color-surface-subtle);
	border-radius: var(--radius-sm);
}

.exo-order__band {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin-block: var(--wp--preset--spacing--40);
	padding: 0;
	list-style: none;
	counter-reset: none;
}

.exo-order__station {
	position: relative;
	padding-inline-start: var(--wp--preset--spacing--50);
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-secondary);
}

/*
 * Der Punkt trägt den Zustand, die Schrift trägt ihn ein zweites Mal: Wer
 * Farben nicht unterscheidet, erkennt den aktuellen Stand am Gewicht und an
 * der Textfarbe. Für Vorlesegeräte steht der Zustand zusätzlich als Wort in
 * der Zeile.
 */
.exo-order__station::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	inset-block-start: 0.35em;
	inline-size: 0.75em;
	block-size: 0.75em;
	border: 2px solid var(--color-border-strong);
	border-radius: var(--radius-pill);
	background-color: var(--color-surface);
}

.exo-order__station--vorbei::before {
	border-color: var(--color-brand);
	background-color: var(--color-brand);
}

.exo-order__station--jetzt {
	color: var(--color-text);
	font-weight: 600;
}

.exo-order__station--jetzt::before {
	border-color: var(--color-brand);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand) 25%, transparent);
}

.exo-order__stand--einzeln {
	margin-block: var(--wp--preset--spacing--40);
	font-weight: 600;
}

.exo-order__termine {
	display: grid;
	grid-template-columns: minmax(0, auto) minmax(0, 1fr);
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	margin-block: var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-order__termine dt {
	color: var(--color-text-secondary);
}

.exo-order__termine dd {
	margin-inline-start: 0;
	font-variant-numeric: tabular-nums;
}

/*
 * Die Einordnung als Schätzung steht unter dem Zeitraum, nicht daneben: Neben
 * dem Datum ließe sie sich überlesen, und dann steht dort scheinbar ein
 * zugesagter Termin.
 */
.exo-order__schaetzung {
	display: block;
	font-size: var(--wp--preset--font-size--xs);
	color: var(--color-text-secondary);
	font-variant-numeric: normal;
}

@media (width <= 30rem) {
	.exo-order__termine {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--wp--preset--spacing--10);
	}

	.exo-order__termine dd {
		margin-block-end: var(--wp--preset--spacing--20);
	}
}

.exo-order__untertitel {
	margin-block: var(--wp--preset--spacing--50) var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--lg);
}

.exo-order__sendungen {
	margin-block: 0;
	padding-inline-start: var(--wp--preset--spacing--50);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-order__positionen {
	margin-block: var(--wp--preset--spacing--40);
}

.exo-order__fussnote {
	margin-block-start: var(--wp--preset--spacing--50);
}

/* ------------------------------------------------------------------
 * Daueraufträge im Kundenbereich (AP-46)
 *
 * Dieselbe Kontoseite, derselbe Geltungsbereich: `.exo-dauer-scope` steht
 * neben `.exo-orders-scope` am selben Element und erbt dessen Tabellen- und
 * Textregeln. Hier steht nur, was eine Vereinbarung zusätzlich braucht.
 *
 * DIE VEREINBARUNG IST EINE KARTE, DER AUFTRAG EINE ZEILE
 *
 * Ein Dauerauftrag trägt Kopfangaben, Positionen, erzeugte Aufträge und ein
 * Formular - das ist zu viel für eine Listenzeile. Er bekommt deshalb einen
 * eigenen Rahmen, während die daraus erzeugten Aufträge in derselben
 * `.exo-orders`-Liste stehen wie auf der Auftragsseite: Es sind dieselben
 * Dinge, und sie sollen gleich aussehen.
 *
 * DAS FORMULAR SIEHT NICHT AUS WIE EINE EINSTELLUNG
 *
 * Kein Umschalter, keine Schieber - eine Auswahl, drei Felder und eine
 * Schaltfläche „Wunsch absenden". Ein Schalter verspräche eine Wirkung, die
 * es nicht gibt: Über jede Änderung entscheidet ein Mensch im ERP.
 * ------------------------------------------------------------------ */
.exo-dauer {
	margin-block: var(--wp--preset--spacing--50);
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
}

.exo-dauer__titel {
	margin-block: 0 var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--lg);
}

.exo-dauer__kopf {
	display: grid;
	grid-template-columns: minmax(0, auto) minmax(0, 1fr);
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	margin-block: 0;
	font-size: var(--wp--preset--font-size--sm);
}

.exo-dauer__kopf dt {
	color: var(--color-text-secondary);
}

.exo-dauer__kopf dd {
	margin-inline-start: 0;
	font-variant-numeric: tabular-nums;
}

@media (width <= 30rem) {
	.exo-dauer__kopf {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--wp--preset--spacing--10);
	}

	.exo-dauer__kopf dd {
		margin-block-end: var(--wp--preset--spacing--20);
	}
}

.exo-dauer__untertitel {
	margin-block: var(--wp--preset--spacing--50) var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--base);
}

.exo-dauer__positionen {
	margin-block: var(--wp--preset--spacing--40);
}

.exo-dauer__wuensche {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin-block: 0;
	padding: 0;
	list-style: none;
	font-size: var(--wp--preset--font-size--sm);
}

/*
 * Der Wunsch trägt seinen Stand in derselben Zeile, aber ruhiger gesetzt: Was
 * der Kunde gewünscht hat, ist die Aussage; „Antwort steht aus" ist die
 * Einordnung dazu.
 */
.exo-dauer__wunsch {
	padding-inline-start: var(--wp--preset--spacing--30);
	border-inline-start: 3px solid var(--color-border);
}

.exo-dauer__wunsch-art {
	font-weight: 600;
}

.exo-dauer__wunsch-stand,
.exo-dauer__wunsch-grund {
	color: var(--color-text-secondary);
}

.exo-dauer__wunsch-grund {
	display: block;
}

.exo-dauer__form {
	margin-block-start: var(--wp--preset--spacing--50);
	padding-block-start: var(--wp--preset--spacing--40);
	border-block-start: 1px solid var(--color-border);
}

.exo-dauer__erklaerung,
.exo-dauer__fussnote,
.exo-dauer__zuordnung {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--color-text-secondary);
}

.exo-dauer__fussnote {
	margin-block-start: var(--wp--preset--spacing--50);
}

/*
 * Der Zustand der Zuordnung steht über der Liste und erklärt, warum sie leer
 * ist. Abgesetzt wie der Standhinweis der Auftragsseite und aus demselben
 * Grund: Es ist eine Einordnung, keine Störung.
 */
.exo-dauer__zuordnung {
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border-inline-start: 3px solid var(--color-border-strong);
	background-color: var(--color-surface-subtle);
	border-radius: var(--radius-sm);
}

/*
 * Die Rückmeldung nach dem Absenden. Der Erfolg trägt die Markenfarbe, der
 * Fehlschlag die Fehlerfarbe - und beide denselben Aufbau, damit die Meldung
 * an derselben Stelle steht und nicht springt.
 */
.exo-dauer__meldung {
	margin-block: var(--wp--preset--spacing--40);
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border-inline-start: 3px solid var(--color-border-strong);
	background-color: var(--color-surface-subtle);
	border-radius: var(--radius-sm);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-dauer__meldung--erfolg {
	border-inline-start-color: var(--color-brand);
}

.exo-dauer__meldung--fehler {
	border-inline-start-color: var(--color-danger);
}
