/*
 * Exostruct – Angleichung von WooCommerce
 *
 * Diese Datei wird nur geladen, wenn WooCommerce aktiv ist (inc/assets.php).
 *
 * WARUM EINE EIGENE DATEI
 *
 * Die Klassennamenkonvention des Projekts lässt nur eigene Präfixe zu
 * (`exo-`, `wp-`, `is-`, `has-`). WooCommerce bringt eigene Klassen mit, an
 * denen sich nichts ändern lässt. Statt die Konvention für das gesamte Theme
 * aufzuweichen, steht die Ausnahme hier - begrenzt auf diese Datei und in
 * `.stylelintrc.json` als solche vermerkt.
 *
 * WAS HIER NICHT STEHT
 *
 * Kein Nachbau von Struktur oder Verhalten. Angeglichen werden ausschließlich
 * Farben, Abstände, Rundungen und Typografie auf die Tokens des Designsystems.
 * Was WooCommerce an Aufbau mitbringt, bleibt unangetastet.
 */

.woocommerce-page main,
.woocommerce main {
	padding-block: var(--wp--preset--spacing--70);
}

/* ------------------------------------------------------------------
 * Kundenkonto
 *
 * Anmeldung und Kontoverwaltung sind Arbeitsoberflächen. Der Seitenkopf
 * benennt die Aufgabe; darunter bleibt das Formular auf Lesebreite und nutzt
 * WooCommerce unverändert für Nonces, Validierung und Authentifizierung.
 * ------------------------------------------------------------------ */
.woocommerce-account main.exo-account {
	padding-block: 0;
}

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

.exo-account__title {
	max-inline-size: 22ch;
	letter-spacing: -0.025em;
}

.exo-account__body {
	padding-block: var(--section-compact);
}

.exo-account__content > .woocommerce {
	max-inline-size: var(--container-content);
}

/*
 * Abgemeldeter Zustand: Anmeldung und Registrierung stehen nebeneinander.
 *
 * Zuvor war die Kontoseite ohne Kontonavigation auf Textbreite begrenzt, und
 * beide Formulare drängten sich in die linke Hälfte, während rechts die halbe
 * Seite leer blieb. Die beiden Wege sind gleichrangig - wer hier ankommt, hat
 * entweder ein Konto oder noch keines - und bekommen deshalb gleich breite
 * Spalten.
 *
 * Die Spalten liegen nicht direkt in `.woocommerce`, sondern in dessen
 * `.u-columns`-Hülle: WooCommerce setzt hier noch das ältere Float-Raster aus
 * `.u-column1` und `.u-column2` ein. Ein Raster auf `.woocommerce` hätte
 * deshalb nur diese eine Hülle verteilt - gemessen zwei Spalten zu 528px, von
 * denen die zweite leer blieb.
 */
.exo-account__content > .woocommerce:not(:has(.woocommerce-MyAccount-navigation)) {
	max-inline-size: var(--container-content);
}

/*
 * Nur Anmeldung, ohne Registrierung.
 *
 * WooCommerce liefert die beiden Formulare in `.u-columns`; ist die
 * Registrierung abgeschaltet, fehlt diese Hülle und das Anmeldeformular steht
 * allein. Ohne eigene Begrenzung lief es dann über die volle Katalogbreite -
 * gemessen 1120px für drei Felder, mit einer Schaltfläche irgendwo in der
 * Mitte. Genau dieser Zustand stand auf Staging, weil die Einstellung dort in
 * der Datenbank fehlte.
 *
 * Die Regel greift unabhängig von der Einstellung: Sie hält den Einzelfall
 * lesbar, statt ihn davon abhängig zu machen, dass eine Option gesetzt ist.
 */
.exo-account__content > .woocommerce:has(.woocommerce-form-login):not(
	:has(.u-columns, .woocommerce-MyAccount-navigation)
) {
	max-inline-size: var(--container-text);
}

.exo-account .u-columns.col2-set {
	display: grid;
	gap: var(--component-gap-md) var(--component-gap-lg);
	align-items: start;
	inline-size: 100%;
}

/*
 * Der Clearfix des Float-Rasters muss weg, bevor das Raster greift.
 *
 * WooCommerce hängt an `.col2-set` ein `::before` und ein `::after` mit
 * `display: table`. In einem Rastercontainer werden beide zu vollwertigen
 * Rasterelementen: `::before` belegte die erste Zelle, wodurch die Anmeldung in
 * die zweite Spalte rutschte und die Registrierung in eine zweite Zeile fiel -
 * gemessen Anmeldung bei x=672, Registrierung bei x=80 und 486px darunter.
 * Ohne Floats hat der Clearfix ohnehin keine Aufgabe mehr.
 */
.exo-account .u-columns.col2-set::before,
.exo-account .u-columns.col2-set::after {
	display: none;
}

/*
 * Float und feste Breite der Altlast abräumen: Beides stammt aus dem
 * Float-Raster und widerspricht der Rasterzuteilung darüber.
 */
.exo-account .u-columns > .u-column1,
.exo-account .u-columns > .u-column2 {
	display: flex;
	flex-direction: column;
	block-size: 100%;
	float: none;
	inline-size: auto;
	margin: 0;
}

.exo-account__content > .woocommerce > h2 {
	margin-block: 0 var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--heading-3);
}

/*
 * Anmeldung und Registrierung tragen dieselbe Fläche.
 *
 * WooCommerce gestaltet nur das Anmeldeformular als Kasten; die Registrierung
 * daneben stand ohne eigene Fläche auf Weiß. Zwei gleichrangige Wege sahen
 * dadurch aus wie ein Hauptweg und ein Nachtrag.
 */
.exo-account .woocommerce-form-login,
.exo-account .woocommerce-form-register {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	block-size: 100%;
	align-content: start;
	margin: 0;
	padding: var(--wp--preset--spacing--40);
	background-color: var(--color-surface-subtle);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
}

.exo-account .woocommerce-form-login .form-row,
.exo-account .woocommerce-form-register .form-row,
.exo-account .woocommerce-form-login .lost_password {
	margin: 0;
	padding: 0;
}

.exo-account .woocommerce-form-login .form-row > label:not(.woocommerce-form-login__rememberme),
.exo-account .woocommerce-form-register .form-row > label {
	display: block;
	margin-block-end: var(--wp--preset--spacing--20);
	font-weight: 600;
}

.exo-account .woocommerce-form-login input.input-text,
.exo-account .woocommerce-form-register input.input-text {
	inline-size: 100%;
	min-block-size: var(--control-standard);
}

.exo-account .woocommerce-form-login > .form-row:not(.form-row-wide) {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--30) var(--wp--preset--spacing--50);
}

/*
 * Der Datenschutzhinweis ist Pflichtangabe, aber nicht die Aussage des
 * Formulars. Er steht deshalb kleiner und in Sekundärfarbe - lesbar, ohne dem
 * Passwortfeld darüber die Aufmerksamkeit zu nehmen.
 */
.exo-account .woocommerce-privacy-policy-text p {
	margin: 0;
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

.exo-account .woocommerce-form-register__submit {
	min-block-size: var(--control-standard);
	margin: 0;
	justify-self: start;
}

/*
 * „Angemeldet bleiben" auf einer Mittelachse mit seinem Kästchen.
 *
 * Der Selektor nennt Formular und Elementart zusätzlich, weil WooCommerce die
 * Beschriftung mit zwei stärkeren Regeln belegt:
 * `.woocommerce form .form-row label { display: block }` (0,2,2) und
 * `.woocommerce .woocommerce-form-login .woocommerce-form-login__rememberme
 * { display: inline-block }` (0,3,0). Gegen beide kam eine Regel mit zwei
 * Klassen nicht an - die Beschriftung blieb ein Blockelement, `align-items`
 * lief ins Leere.
 *
 * `min-block-size` entfällt: Ein 44px hoher Berührungsbereich um ein 20px
 * großes Kästchen zentriert dessen Box zwar rechnerisch, lässt die Reihe aber
 * höher wirken als die übrigen Formularzeilen und verschiebt den optischen
 * Schwerpunkt nach unten. Der Berührungsbereich kommt stattdessen aus
 * `padding-block`, das rundum gleich groß ist.
 */
.exo-account .woocommerce-form-login label.woocommerce-form-login__rememberme {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	padding-block: var(--wp--preset--spacing--10);
	font-weight: 500;
	cursor: pointer;
}

/*
 * Selbst gezeichnetes Kästchen statt der nativen Erscheinung.
 *
 * `accent-color` (tokens.css) genügte nicht: Chromium zeichnet ein
 * angehaktes Kästchen mit `accent-color` intern anders als ein leeres -
 * die abgerundete Ecke des leeren Kästchens verschwand im angehakten Zustand
 * zu einer scharfen Kante. `appearance: none` nimmt dem Browser die
 * Zeichnung vollständig ab; Rahmen, Radius und Häkchen kommen von hier und
 * bleiben damit in jedem Zustand und auf jeder Plattform gleich.
 *
 * `flex: none` verhindert, dass das Kästchen im Flexkontext schrumpft.
 */
.exo-account .woocommerce-form-login label.woocommerce-form-login__rememberme input {
	appearance: none;
	flex: none;
	inline-size: 1.25rem;
	block-size: 1.25rem;
	margin: 0;
	border: 1.5px solid var(--color-border-strong);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface);
	cursor: pointer;
	transition: background-color var(--duration-fast) var(--easing-standard),
		border-color var(--duration-fast) var(--easing-standard);
}

.exo-account .woocommerce-form-login label.woocommerce-form-login__rememberme input:checked {
	border-color: var(--color-brand);
	background-color: var(--color-brand);
	background-repeat: no-repeat;
	background-position: center;
	background-size: 0.8rem;
	/* Häkchen als eingebettetes SVG, Farbe fest auf Weiß statt currentColor:
	   `background-image` kennt keine dynamische Farbvererbung. */
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m3.5 8.5 3 3 6-7'/%3E%3C/svg%3E");
}

.exo-account .woocommerce-form-login label.woocommerce-form-login__rememberme input:hover {
	border-color: var(--color-brand);
}

.exo-account .woocommerce-form-login__submit {
	min-block-size: var(--control-standard);
	margin: 0;
}

.exo-account .lost_password {
	padding-block-start: var(--wp--preset--spacing--40);
	border-block-start: 1px solid var(--color-border);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-account .lost_password a {
	color: var(--color-text);
	font-weight: 600;
	text-underline-offset: 0.25em;
}

/* Angemeldeter Zustand: WooCommerce-Funktionen bleiben dieselben, werden aber
 * ohne die historischen Floats in eine belastbare Kontonavigation gesetzt. */
.exo-account .woocommerce-MyAccount-navigation,
.exo-account .woocommerce-MyAccount-content {
	float: none;
	inline-size: auto;
}

.exo-account .woocommerce-MyAccount-navigation ul {
	margin: 0;
	padding: 0;
	list-style: none;
	border-block-start: 1px solid var(--color-border);
}

.exo-account .woocommerce-MyAccount-navigation li {
	border-block-end: 1px solid var(--color-border);
}

.exo-account .woocommerce-MyAccount-navigation a {
	display: flex;
	align-items: center;
	min-block-size: var(--touch-target);
	padding-block: var(--wp--preset--spacing--30);
	color: var(--color-text);
	font-weight: 600;
	text-decoration: none;
}

.exo-account .woocommerce-MyAccount-navigation a:hover,
.exo-account .woocommerce-MyAccount-navigation a:focus-visible,
.exo-account .woocommerce-MyAccount-navigation .is-active a {
	text-decoration: underline;
	text-decoration-color: var(--color-brand);
	text-decoration-thickness: 2px;
	text-underline-offset: 0.25em;
}

.exo-account .woocommerce:has(.woocommerce-MyAccount-navigation) {
	display: grid;
	gap: var(--component-gap-lg);
}

/*
 * Derselbe Clearfix wie bei `.col2-set`, hier an `.woocommerce` selbst: Sein
 * `::before` belegte die erste Rasterzelle, sodass die Kontonavigation in die
 * zweite Spalte rutschte und der Inhalt darunter in eine neue Zeile fiel.
 */
.exo-account .woocommerce:has(.woocommerce-MyAccount-navigation)::before,
.exo-account .woocommerce:has(.woocommerce-MyAccount-navigation)::after {
	display: none;
}

@media (width < 48rem) {
	/*
	 * „Angemeldet bleiben" und die Anmeldeaktion stehen mobil untereinander.
	 *
	 * Als Flexzeile teilten sie sich die Breite, und `inline-size: 100%` an der
	 * Schaltfläche bezog sich auf ihren Flexanteil statt auf die Formularbreite
	 * - gemessen 292px in einem 308px breiten Formular. Gestapelt füllt die
	 * Aktion die Zeile tatsächlich aus.
	 */
	.exo-account .woocommerce-form-login > .form-row:not(.form-row-wide) {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		justify-items: stretch;
	}

	.exo-account .woocommerce-form-login__submit,
	.exo-account .woocommerce-form-register__submit {
		inline-size: 100%;
		justify-self: stretch;
	}
}

@media (width >= 48rem) {
	.exo-account .woocommerce-form-login,
	.exo-account .woocommerce-form-register {
		padding: var(--wp--preset--spacing--60);
	}

	.exo-account .woocommerce:has(.woocommerce-MyAccount-navigation) {
		grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
	}

	.exo-account .u-columns.col2-set {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* ------------------------------------------------------------------
 * Shop-Einstieg und Katalograhmen
 *
 * Das Produktarchiv ist kein gewöhnlicher Textinhalt: Suche, Sortierung und
 * Kaufziele bilden eine zusammenhängende Anwendung. Die Bühne erklärt den
 * direkt bestellbaren Weg und stellt die Produktsuche vor den Katalog. Alle
 * Produktdaten und Kaufvorgänge bleiben dabei in WooCommerce.
 * ------------------------------------------------------------------ */
.woocommerce-page main.exo-shop {
	padding-block: 0;
}

.exo-shop > *,
.exo-shop-hero__copy > *,
.exo-shop-hero__search > *,
.exo-shop-catalog__header > *,
.exo-shop-service__header > *,
.exo-shop-service__item > *,
.exo-shop-project-route__inner > *,
.exo-shop-empty > * {
	margin-block: 0 !important;
}

.exo-shop-hero,
.exo-shop-catalog,
.exo-shop-service,
.exo-shop-project-route {
	padding-inline: var(--gutter-page);
}

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

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

.exo-shop-hero .wc-block-breadcrumbs {
	margin-block: 0 var(--wp--preset--spacing--60);
	color: var(--wp--preset--color--ink-300);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-shop-hero .wc-block-breadcrumbs a {
	color: var(--wp--preset--color--ink-100);
}

.exo-shop-hero .wc-block-breadcrumbs a:hover {
	color: var(--color-text-on-dark);
}

.exo-shop-hero__inner {
	display: grid;
	gap: var(--component-gap-lg);
	align-items: center;
}

.exo-shop-hero__copy,
.exo-shop-hero__search {
	display: grid;
	gap: var(--wp--preset--spacing--30);
}

.exo-shop-hero__copy h1 {
	max-inline-size: 18ch;
	color: var(--color-text-on-dark);
	letter-spacing: -0.03em;
	line-height: var(--line-height-tight);
}

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

.exo-shop-hero__copy p.exo-lead {
	max-inline-size: 52ch;
	color: var(--wp--preset--color--ink-200);
}

.exo-shop-hero__search {
	padding: var(--wp--preset--spacing--50);
	background-color: var(--color-surface-dark-raised);
	border: 1px solid var(--color-border-dark);
	border-radius: var(--radius-lg);
}

.exo-shop-search .wp-block-search__label {
	display: block;
	margin-block-end: var(--wp--preset--spacing--20);
	color: var(--color-text-on-dark);
	font-weight: 600;
}

/*
 * Ein Bedienelement, nicht zwei nebeneinander.
 *
 * Dieselbe Gestalt wie die Wissenssuche (`.exo-search__control`): Der Rahmen
 * trägt die ganze Zeile, Lupe und Aktion liegen darin. Die Lupe kommt hier aus
 * einem Pseudoelement, weil der Kernblock keine Stelle für ein eigenes Symbol
 * vorsieht und Markup im Block nicht ergänzt werden soll.
 */
.exo-shop-search .wp-block-search__inside-wrapper {
	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-shop-search .wp-block-search__inside-wrapper:focus-within {
	border-color: var(--color-brand);
}

/* Lupe als Maske: eine Form, keine zweite Datei und kein Zeichensatz. */
.exo-shop-search .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-shop-search .wp-block-search__input {
	min-inline-size: 0;
	min-block-size: var(--control-standard);
	padding: 0;
	background-color: transparent;
	color: var(--color-text);
	border: 0;
	border-radius: 0;
}

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

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

/*
 * Eingabefeld und Schaltfläche sind ein Bedienelement, keine zwei.
 *
 * Die Schaltfläche trug bisher `--radius-pill`, das Feld daneben `--radius-sm`:
 * eine vollständig gerundete Kapsel unmittelbar neben einer scharfkantigen
 * Fläche, getrennt durch 8px. Die beiden Formen lasen sich als zwei
 * unabhängige Elemente, die zufällig nebeneinander stehen. Dieselbe Rundung
 * fasst sie zu einer Suche zusammen - die Kapselform bleibt den Schaltflächen
 * vorbehalten, die allein stehen.
 */
.exo-shop-search .wp-block-search__button {
	min-block-size: var(--control-compact);
	margin: 0;
	padding-inline: var(--wp--preset--spacing--50);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	border: 0;
	border-radius: var(--radius-pill);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
}

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

.exo-shop-hero__search .exo-shop-search__hint {
	color: var(--wp--preset--color--ink-300);
	line-height: var(--line-height-ui);
}

/*
 * „Suche zurücksetzen" steht im selben Absatz wie der Hinweis, aber sichtbar
 * als Weg: unterstrichen und in der Textfarbe der dunklen Fläche, damit es
 * sich vom erläuternden Satz daneben abhebt. `margin-inline-start` statt
 * eines Leerzeichens, weil der Abstand zum Satz eine gestalterische Angabe
 * ist und keine sprachliche.
 */
.exo-shop-hero__search .exo-shop-search__reset {
	margin-inline-start: var(--wp--preset--spacing--20);
	color: var(--color-text-on-dark);
	font-weight: 600;
	text-decoration: underline;
}

.exo-shop-hero__search .exo-shop-search__reset:hover,
.exo-shop-hero__search .exo-shop-search__reset:focus-visible {
	color: var(--wp--preset--color--brand-500);
}

.exo-shop-catalog {
	padding-block: var(--section-default);
}

.exo-shop-catalog__header,
.exo-shop-service__header {
	display: grid;
	gap: var(--wp--preset--spacing--20);
}

.exo-shop-catalog__header {
	margin-block-end: var(--wp--preset--spacing--50) !important;
}

.exo-shop-catalog__header .exo-eyebrow,
.exo-shop-service__header .exo-eyebrow {
	color: var(--color-text-secondary);
}

.exo-shop-tools {
	gap: var(--wp--preset--spacing--40);
	padding-block: var(--wp--preset--spacing--30);
	margin-block-end: var(--wp--preset--spacing--50) !important;
	border-block: 1px solid var(--color-border);
}

.exo-shop-tools .woocommerce-ordering {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
}

/*
 * „Sortieren nach" stand nicht auf der Mitte des Auswahlfelds daneben.
 *
 * Grund war kein fehlendes `align-items` - das steht auf `center` - sondern ein
 * geerbter unterer Rand von 9,8px an der Beschriftung. Flex zentriert den
 * Randbereich, nicht den Text darin, sodass die Schrift um die halbe Randhöhe
 * nach oben rutschte (gemessen 6px). Ohne den Rand liegen beide auf einer
 * Mittelachse.
 */
.exo-shop-tools .woocommerce-ordering label {
	margin: 0;
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	white-space: nowrap;
}

/*
 * Dasselbe gilt für die Trefferangabe links: Ihr unterer Rand hob sie
 * gegenüber der Sortierung an.
 */
.exo-shop-tools .woocommerce-result-count {
	margin: 0;
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
}

/*
 * Das Auswahlfeld war mit 146px so breit wie die Beschriftung daneben, obwohl
 * es nur einen kurzen Zustand anzeigt. Schmaler gefasst tritt es hinter die
 * Trefferangabe zurück, die die eigentliche Auskunft der Zeile ist.
 */
.exo-shop-tools .woocommerce-ordering select {
	inline-size: 8.5rem;
	min-block-size: var(--touch-target);
	padding-inline: var(--wp--preset--spacing--30);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface);
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--sm);
}

.exo-shop-catalog .wp-block-woocommerce-product-collection {
	margin-block: 0;
}

/*
 * Der Serviceblock schließt die Seite ab und stößt an die Fußzeile.
 *
 * Er steht jetzt hinter dem Projektweg und ist damit das letzte Element vor
 * dem Fußbereich. Zwischen seiner hellen Fläche und der dunklen Fußzeile stand
 * ein Streifen Seitenhintergrund - eine leere Zone ohne Aufgabe, die die
 * beiden zusammengehörenden Nachschlagebereiche auseinanderzog. Ohne sie
 * gehen Fläche und Fußzeile ineinander über; die Kante zwischen hell und
 * dunkel übernimmt die Trennung.
 */
.exo-shop-service {
	padding-block: var(--section-compact);
	background-color: var(--color-surface-subtle);
}

/*
 * Der untere Abschnittsabstand des Hauptbereichs muss dafür weichen: Er liegt
 * hinter dem Band und ließe sich von dort aus nicht wegnehmen. Auf dem
 * Produktarchiv steht die Polsterung ohnehin auf 0 (siehe oben).
 */
main.exo-product {
	padding-block-end: 0;
}

.exo-shop-service__header {
	margin-block-end: var(--component-gap-md) !important;
}

/*
 * „Versand und Zahlung" stand höher als „Widerruf" und „Produktfrage klären".
 *
 * Der Blockabstand von Gutenberg setzt auf jedes Kind außer dem ersten einen
 * oberen Rand. Im Rasterlayout addiert sich dieser Rand innerhalb der Zelle,
 * statt zwischen Zeilen zu wirken: Das zweite und dritte Feld begannen dadurch
 * gemessen 24px tiefer als das erste, obwohl alle drei in derselben Rasterzeile
 * liegen. Der Abstand kommt bereits aus `gap`.
 */
.exo-shop-service__grid {
	display: grid;
	gap: var(--wp--preset--spacing--50);
}

.exo-shop-service__grid > .exo-shop-service__item {
	margin-block: 0;
}

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

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

.exo-shop-service__item h3 a,
.exo-shop-project-route__link {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	min-block-size: var(--touch-target);
	color: var(--color-text);
	font-weight: 600;
	text-decoration: none;
}

.exo-shop-service__item h3 a::after,
.exo-shop-project-route__link::after {
	content: "→";
	color: var(--color-brand-hover);
}

.exo-shop-service__item h3 a:hover .exo-action__label,
.exo-shop-service__item h3 a:focus-visible .exo-action__label,
.exo-shop-project-route__link:hover .exo-action__label,
.exo-shop-project-route__link:focus-visible .exo-action__label {
	text-decoration-color: var(--color-brand-hover);
}

.exo-shop-service__item p,
.exo-shop-project-route__inner > p:not(:last-child) {
	max-inline-size: 48ch;
	color: var(--color-text-secondary);
}

/*
 * Der Projektweg ist ein Hinweis am Ende des Katalogs, kein eigener Abschnitt.
 *
 * Als vollbreites Band lag er in derselben Gewichtung wie der Katalog darüber
 * und war nach dem Fußbereich die zweitgrößte Fläche der Seite - für den
 * Nebenweg, der ausdrücklich nicht über den Shop läuft. Als begrenzter Block
 * bleibt die Aussage erhalten, ohne den Katalog zu überstimmen.
 */
.exo-shop-project-route {
	padding-block: var(--section-compact);
}

.exo-shop-project-route__inner {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	align-items: center;
	padding: var(--component-gap-md);
	border: 1px solid var(--wp--preset--color--brand-100);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-brand);
}

.exo-shop-empty {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	max-inline-size: var(--container-text);
	padding: var(--wp--preset--spacing--50);
	background-color: var(--color-surface-subtle);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
}

@media (width >= 48rem) {
	.exo-shop-hero__inner {
		grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
	}

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

@media (width >= 64rem) {
	.exo-shop-project-route__inner {
		grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.3fr) auto;
		gap: var(--wp--preset--spacing--60);
	}
}

@media (width < 40rem) {
	/*
	 * Die Zeile bleibt eine Zeile.
	 *
	 * Solange Eingabe und Aktion zwei getrennte Elemente waren, war Stapeln
	 * richtig. In der gemeinsamen Fläche säße die Schaltfläche dann unter der
	 * Eingabe *innerhalb* desselben Rahmens - eine Kapsel mit zwei Etagen.
	 * Stattdessen rückt die Beschriftung enger; die Trefferfläche bleibt über
	 * die Höhe erhalten.
	 */
	.exo-shop-search .wp-block-search__button {
		padding-inline: var(--wp--preset--spacing--40);
	}
}

/* Ergebniszahl und Sortierung bleiben als gemeinsame Werkzeugzeile lesbar. */
.woocommerce-page main .wp-block-group:has(> .wp-block-woocommerce-product-results-count) {
	gap: var(--wp--preset--spacing--40);
}

.woocommerce-page .woocommerce-ordering,
.woocommerce-page .woocommerce-result-count {
	margin: 0;
}

.woocommerce-page .woocommerce-ordering select {
	min-block-size: var(--touch-target);
	padding-inline: var(--wp--preset--spacing--30);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface);
	font: inherit;
}

/* Preise in der Marken-Typografie, nicht in der Vorgabe des Plugins. */
.woocommerce .price,
.woocommerce-Price-amount {
	font-weight: 600;
	color: var(--color-text);
}

.woocommerce .price del {
	color: var(--color-text-secondary);
	font-weight: 400;
}

/*
 * Der Preiszusatz nennt Endpreis und Versandhinweis. Er gehört zur
 * Pflichtangabe und darf deshalb nicht wie Kleingedrucktes wirken – nur
 * leiser als der Preis selbst.
 */
.woocommerce .woocommerce-price-suffix {
	display: block;
	margin-block-start: var(--wp--preset--spacing--10);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 400;
	color: var(--color-text-secondary);
}

/* Schaltflächen des Shops folgen denen des Themes. */
.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce #respond input#submit {
	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;
	line-height: var(--line-height-ui);
}

.woocommerce a.button:hover,
.woocommerce button.button:hover,
.woocommerce input.button:hover,
.woocommerce #respond input#submit:hover {
	background-color: var(--color-brand-hover);
	color: var(--color-text-on-brand);
}

.woocommerce a.button.alt,
.woocommerce button.button.alt {
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
}

/* Produktkacheln in der Übersicht wie die Karten des Themes. */
.woocommerce ul.products li.product {
	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);
}

.woocommerce ul.products li.product:hover,
.woocommerce ul.products li.product:focus-within {
	border-color: var(--color-border-strong);
	box-shadow: var(--shadow-md);
}

/*
 * Der aktuelle Shop verwendet den WooCommerce-Produktblock statt der
 * klassischen `ul.products`-Liste. Beide Darstellungen erhalten dieselbe
 * ruhige Kartenrolle.
 */
.woocommerce .wc-block-product-template {
	gap: var(--wp--preset--spacing--50);
	align-items: stretch;
}

.woocommerce .wc-block-product-template .wc-block-product {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
	padding: var(--wp--preset--spacing--30);
	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);
}

.woocommerce .wc-block-product-template .wc-block-product:hover,
.woocommerce .wc-block-product-template .wc-block-product:focus-within {
	border-color: var(--color-border-strong);
}

.woocommerce .wc-block-product-template .wc-block-product > * {
	margin-block: 0 !important;
}

.woocommerce .wc-block-product-template .wc-block-components-product-image,
.woocommerce .wc-block-product-template .wc-block-components-product-image img {
	border-radius: var(--radius-sm);
}

.woocommerce .wc-block-product-template .wp-block-post-title {
	line-height: var(--line-height-ui) !important;
}

.woocommerce .wc-block-product-template .wp-block-post-title a {
	color: var(--color-text);
	text-decoration: none;
}

.woocommerce .wc-block-product-template .wp-block-post-title a:hover,
.woocommerce .wc-block-product-template .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;
}

.woocommerce .wc-block-product-template .wp-block-woocommerce-product-button {
	margin-block-start: auto !important;
}

.woocommerce .wc-block-product-template .wp-block-woocommerce-product-button button {
	margin-block-end: 0 !important;
}

@media (width < 48rem) {
	.woocommerce-page main .wp-block-group:has(> .wp-block-woocommerce-product-results-count) {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		justify-items: stretch;
	}

	.exo-shop-tools .woocommerce-ordering {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
	}

	.exo-shop-tools .woocommerce-ordering label {
		white-space: normal;
	}

	/*
	 * Der Produktblock schreibt allen direkten Kindern des ausgerichteten
	 * Werkzeugcontainers eine intrinsische Breite mit `!important`. Ohne die
	 * gleichwertige Gegenregel bleibt die Sortierung trotz Grid nur 247 px
	 * breit. Auf Mobil gehört sie als einziges Steuerelement in die volle Zeile.
	 */
	.woocommerce-page main
		.wp-block-group:has(> .wp-block-woocommerce-product-results-count)
		> .wc-block-catalog-sorting,
	.woocommerce-page main
		.wp-block-group:has(> .wp-block-woocommerce-product-results-count)
		.woocommerce-ordering,
	.woocommerce-page main
		.wp-block-group:has(> .wp-block-woocommerce-product-results-count)
		.woocommerce-ordering
		select {
		inline-size: 100% !important;
		width: 100% !important;
		max-inline-size: none;
		min-inline-size: 0;
		justify-self: stretch;
	}
}

/*
 * Die Spaltenzahl gilt dem Katalog, nicht jedem Produktraster.
 *
 * Ohne die Eingrenzung auf `.exo-shop-catalog` griffen diese Regeln auch auf
 * die ähnlichen Produkte der Produktseite - dort mit `!important`, also
 * unschlagbar. Deren Fünfspaltigkeit ließ sich dadurch nicht einstellen, und
 * die Ursache stand 700 Zeilen entfernt in einem Block, der vom Katalog
 * handelt.
 */
@media (width < 23rem) {
	.exo-shop-catalog .wc-block-product-template {
		grid-template-columns: minmax(0, 1fr) !important;
	}
}

@media (width >= 64rem) {
	.exo-shop-catalog .wc-block-product-template {
		grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
	}
}

.woocommerce ul.products li.product img {
	border-radius: var(--radius-sm);
}

.woocommerce ul.products li.product .woocommerce-loop-product__title {
	font-size: var(--wp--preset--font-size--lg);
	line-height: var(--line-height-ui);
}

/*
 * Produkttitel in Textfarbe statt in Linkblau. Auf einer Kachel ist der ganze
 * Bereich anklickbar; ein blauer Titel wirkt dort wie ein zweites Ziel neben
 * dem Knopf, obwohl beide zum selben Produkt führen.
 */
.woocommerce ul.products li.product a:where(:not(.button)) {
	color: var(--color-text);
	text-decoration: none;
}

.woocommerce ul.products li.product a:where(:not(.button)):hover {
	text-decoration: underline;
	text-underline-offset: 0.25em;
	text-decoration-color: var(--color-brand);
	text-decoration-thickness: 2px;
}

/* Formularfelder im Kassenvorgang wie die eigenen Formulare. */
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea,
.woocommerce form .form-row select {
	padding: var(--wp--preset--spacing--30);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface);
	color: var(--color-text);
	font-family: inherit;
	font-size: var(--wp--preset--font-size--base);
}

.woocommerce form .form-row input.input-text:focus-visible,
.woocommerce form .form-row textarea:focus-visible,
.woocommerce form .form-row select:focus-visible {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
}

/*
 * Die Meldungen des Plugins tragen von Haus aus eine eigene Farbwelt und einen
 * farbigen Balken. Hier auf die Zustandsfarben des Systems gezogen; die
 * Bedeutung hängt weiterhin nicht allein an der Farbe, weil WooCommerce den
 * Text mitliefert.
 */
.woocommerce-message,
.woocommerce-info,
.woocommerce-error {
	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);
	color: var(--color-text);
}

.woocommerce-message { border-inline-start-color: var(--color-success); }
.woocommerce-info    { border-inline-start-color: var(--color-brand); }
.woocommerce-error   { border-inline-start-color: var(--color-danger); }

/* Tabellen in Warenkorb und Bestellübersicht. */
.woocommerce table.shop_table {
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	border-collapse: separate;
	border-spacing: 0;
}

.woocommerce table.shop_table th {
	font-weight: 600;
	color: var(--color-text);
}

/* ------------------------------------------------------------------
 * Warenkorb und Kasse (Blockversion)
 *
 * WooCommerce liefert Warenkorb und Kasse als Blöcke mit eigenem Stylesheet.
 * Angeglichen werden nur Fläche, Rahmen, Abstand und Schriftgröße - Aufbau,
 * Beträge, Steuerausweis und der gesamte Kaufvorgang bleiben unangetastet.
 * ------------------------------------------------------------------ */

/*
 * Die Zusammenfassung ist eine eigenständige Einheit und bekommt deshalb eine
 * eigene Fläche (Regel R6). Ohne sie standen Zwischensumme, Steuer und die
 * Schaltfläche zur Kasse frei auf Weiß, während die Artikelliste daneben durch
 * ihre Zeilenlinien klar gerahmt war - zwei Hälften mit unterschiedlichem
 * Gewicht, obwohl die rechte die Entscheidung trägt.
 */
.wc-block-cart__sidebar .wc-block-components-sidebar,
.wc-block-cart .wc-block-cart__sidebar > * {
	box-sizing: border-box;
}

.wc-block-cart__sidebar {
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-subtle);
}

/*
 * Das Vorschaubild ist die einzige Wiedererkennung der Zeile. Mit 64 px stand
 * es unter der Größe, ab der ein gedrucktes Bauteil überhaupt erkennbar ist.
 */
.wc-block-cart-item__image img {
	inline-size: 5.5rem;
	max-inline-size: none;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	object-fit: cover;
}

.wc-block-cart-items th {
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

/* Produktname wie auf der Kachel in Textfarbe, nicht als Fließtextlink. */
.wc-block-cart-item__wrap .wc-block-components-product-name {
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 600;
	text-decoration: none;
}

.wc-block-cart-item__wrap .wc-block-components-product-name:hover,
.wc-block-cart-item__wrap .wc-block-components-product-name:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/*
 * Mengenwahl und Entfernen sind Bedienelemente und brauchen volle Ziele.
 *
 * Der Rahmen muss dem folgen. WooCommerce gibt dem Feld `width: 107px` - eine
 * Zahl, die zu seinen eigenen 24 px breiten Knöpfen passt. Mit den 44 px, die
 * ein Berührungsziel braucht, ergeben Minus, Eingabe und Plus zusammen 128 px:
 * Der Plusknopf stand 21 px über den Rahmen hinaus, der ihn dadurch anschnitt,
 * während beim Minus links alles stimmte (gemeldet am 2026-08-18, in
 * Seitenleiste und auf der Warenkorb-Seite).
 *
 * `fit-content` statt einer eigenen Zahl: Die Breite folgt damit dem
 * Berührungsziel, statt eine zweite Stelle zu sein, die beim nächsten Wert
 * nachgezogen werden müsste.
 */
.wc-block-components-quantity-selector {
	inline-size: fit-content;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-pill);
}

.wc-block-components-quantity-selector .wc-block-components-quantity-selector__button {
	min-inline-size: var(--touch-target);
	min-block-size: var(--touch-target);
	color: var(--color-text);
}

.wc-block-cart-item__remove-link {
	min-block-size: var(--touch-target);
	color: var(--color-text-secondary);
}

.wc-block-cart-item__remove-link:hover,
.wc-block-cart-item__remove-link:focus-visible {
	color: var(--color-danger);
}

/*
 * Weiter zur Kasse ist die Primäraktion der Seite und trägt deshalb dieselbe
 * Höhe wie jede andere dominante Schaltfläche des Systems.
 */
.wc-block-cart__submit-button,
.wc-block-components-checkout-place-order-button {
	min-block-size: var(--control-dominant);
	border-radius: var(--radius-pill);
	background-color: var(--color-brand);
	color: var(--color-text-on-brand);
	font-weight: 600;
}

.wc-block-cart__submit-button:hover,
.wc-block-components-checkout-place-order-button:hover {
	background-color: var(--color-brand-hover);
	color: var(--color-text-on-brand);
}

/*
 * Der leere Warenkorb ist eine Auskunft, keine Fehlermeldung. Er steht deshalb
 * linksbündig auf der Achse der Seite - WooCommerce zentriert ihn von Haus aus
 * mitsamt der eingeblendeten Grafik.
 */
.wc-block-cart__empty-cart__title {
	margin-block-end: var(--wp--preset--spacing--30);
	text-align: start;
	font-size: var(--wp--preset--font-size--heading-3);
}

/*
 * Die Grafik des leeren Warenkorbs wird über ein Pseudoelement der Überschrift
 * eingeblendet. Sie ist Ausschmückung ohne Aufgabe (AGENTS.md §9.1); der
 * Seiteninhalt führt die Klasse `with-empty-cart-icon` deshalb nicht mehr.
 * Diese Regel greift zusätzlich, falls sie über den Editor zurückkehrt.
 */
.wc-block-cart__empty-cart__title.with-empty-cart-icon::before {
	content: none;
}


/*
 * Achse von Titel und Inhalt auf den Shopseiten.
 *
 * Zwei Vorgaben von WooCommerce zogen beide auseinander:
 *
 * 1. Das Plugin begrenzt `.wp-block-post-title` auf Warenkorb-, Kassen- und
 *    Kontoseiten auf 1000px. Im eingeschränkten Layout des Themes zentriert
 *    der `!important`-Automatikrand die Überschrift daraufhin - gemessen
 *    stand „Warenkorb" 140px weiter innen als der Warenkorb darunter.
 * 2. Der Warenkorb- und der Kassenblock tragen `alignwide`. Die Kernregel für
 *    globale Polsterung zieht ein solches Kind um genau diese Polsterung nach
 *    außen; der Block begann dadurch am Viewportrand statt auf der Seitenachse.
 *
 * Beide Elemente füllen ihren Container ohnehin. Die Begrenzung und der
 * Ausbruch entfallen deshalb, statt sie mit Gegenrändern auszugleichen.
 *
 * Der Titel bekommt dabei ausdrücklich die Containerbreite und nicht `none`:
 * Der Automatikrand des eingeschränkten Layouts errechnet sich aus der
 * Differenz zur verfügbaren Breite. Ohne Begrenzung wird diese Differenz null,
 * und der Titel stünde 32px links neben dem Inhalt darunter statt auf
 * derselben Achse.
 */
.woocommerce-cart .exo-page > .exo-page__title,
.woocommerce-checkout .exo-page > .exo-page__title,
.woocommerce-account .exo-page > .exo-page__title,
.woocommerce-account .exo-account__header > .exo-account__title {
	max-inline-size: var(--container-default);
}

.exo-page__body > .wp-block-woocommerce-cart.alignwide,
.exo-page__body > .wp-block-woocommerce-checkout.alignwide {
	max-inline-size: 100%;
	margin-inline: 0;
}

/*
 * Abstände im leeren Warenkorb.
 *
 * Der Blockeditor erzeugt für die Kinder dieses Blocks keinen Abstand, und der
 * globale Margin-Reset des Themes nimmt den verbliebenen. Überschrift, Satz,
 * Schaltflächen und Produktzeile klebten dadurch aneinander.
 */
.wp-block-woocommerce-empty-cart-block > * + * {
	margin-block-start: var(--wp--preset--spacing--40);
}

.wp-block-woocommerce-empty-cart-block > .wp-block-buttons {
	margin-block-start: var(--wp--preset--spacing--50);
}

.wp-block-woocommerce-empty-cart-block > h3 {
	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--xl);
}

/*
 * Die Produktkacheln standen auf unterschiedlichen Höhen: Titel über eine oder
 * zwei Zeilen verschoben Preis und Schaltfläche jeder Kachel einzeln, sodass
 * vier Kaufziele auf vier verschiedenen Grundlinien lagen. Als Spalte mit
 * Automatikrand vor der Schaltfläche endet jede Kachel auf derselben Kante.
 */
.wp-block-woocommerce-empty-cart-block .wc-block-grid__products {
	align-items: stretch;
}

/*
 * Der Selektor nennt zusätzlich das Element: WooCommerce setzt Ausrichtung und
 * Abstände auf `.wc-block-grid__product` mit eigener Spezifität; eine einzelne
 * Klasse setzte sich dagegen nicht durch.
 */
.wp-block-woocommerce-empty-cart-block li.wc-block-grid__product {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	block-size: 100%;
	margin-block-end: 0;
	padding: 0;
	text-align: start;
}

/*
 * Der Bildrahmen ist bei WooCommerce `inline-block` und schrumpft damit auf die
 * Eigenbreite der Datei - gemessen 224px in einer 308px breiten Kachel. Als
 * Block füllt er die Spalte, und die vier Bilder stehen auf gleicher Breite.
 */
.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-image {
	display: block;
	inline-size: 100%;
	margin-block-end: var(--wp--preset--spacing--30);
}

/*
 * Feste Bildhöhe statt Seitenverhältnis: Bei `aspect-ratio` folgt die Höhe der
 * Spaltenbreite. Die vierte Spalte einer umbrechenden Reihe ist durch Rundung
 * wenige Pixel breiter, ihr Bild wurde dadurch 4px höher - und Titel, Preis und
 * Schaltfläche der vierten Kachel standen sichtbar tiefer als die der drei
 * anderen. Mit fester Höhe liegen alle vier auf denselben Grundlinien.
 */
.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-image img {
	inline-size: 100%;
	block-size: 14rem;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	object-fit: cover;
}

/*
 * Der Titel ist auf einer Kachel kein Fließtextlink: Die ganze Kachel führt
 * zum Produkt, und ein farbig unterstrichener Titel wirkt dort wie ein zweites
 * Ziel neben der Schaltfläche darunter.
 *
 * Angesprochen wird der umschließende Link, nicht der Titel: Bild und Titel
 * liegen gemeinsam in `.wc-block-grid__product-link`, der Titel selbst ist ein
 * `div` ohne eigenes `a`.
 */
.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-link {
	display: block;
	color: var(--color-text);
	text-decoration: none;
}

/* Die Produktzeile darunter ist eine Ergänzung, kein zweiter Hauptinhalt. */
.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-title {
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--base);
	font-weight: 600;
}

.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-link:hover .wc-block-grid__product-title,
.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-link:focus-visible .wc-block-grid__product-title {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/*
 * WooCommerce zentriert Preis und Schaltfläche über automatische Seitenränder
 * (gemessen je 48px bzw. 84px). Sie stehen dadurch weder auf der Achse des
 * Titels darüber noch auf der des Bildes. Die Ränder entfallen; die Kachel
 * bekommt damit eine einzige linke Kante.
 */
.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-title,
.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-price,
.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-add-to-cart {
	margin-inline: 0;
	padding-inline: 0;
}

.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-price {
	margin-block: var(--wp--preset--spacing--20) 0;
	font-size: var(--wp--preset--font-size--sm);
}

.wp-block-woocommerce-empty-cart-block .wc-block-grid__product-add-to-cart {
	margin-block-start: var(--wp--preset--spacing--40);
	justify-content: flex-start;
}

/* ------------------------------------------------------------------
 * Produktseite
 *
 * Die Vorlage von WooCommerce stellt Galerie und Zusammenfassung in zwei
 * Spalten, schiebt die Attribute in einen Reiter und hängt vier Kacheln
 * darunter. Das ist die Voreinstellung jedes Shops.
 *
 * Hier trägt der Kaufbereich eine eigene Fläche, die Kenndaten stehen
 * offen als Datenblatt, und der Aufbau folgt der Materialseite: Bild und
 * Kopf nebeneinander, darunter die Daten, dann der Fließtext. Zwei Seiten
 * mit derselben Aufgabe sehen damit auch gleich aus.
 * ------------------------------------------------------------------ */
.exo-product__top {
	display: grid;
	gap: var(--component-gap-md);
	align-items: start;
	margin-block-start: var(--component-gap-md);
}

.exo-product__media {
	margin: 0;
}

/*
 * Der Blockrahmen füllt seine Spalte.
 *
 * WooCommerce deckelt den Block auf die Breite seiner Einzelbildgröße - hier
 * 512 px. Neben einer 730 px breiten Spalte standen dadurch 218 px leere
 * Fläche zwischen Bild und Kaufkarte, die wie ein Layoutfehler aussah. Die
 * Vorlagen laden ohnehin über `srcset` eine passende Auflösung nach; das
 * Original liegt bei 1080 px.
 */
.exo-product__media .wp-block-woocommerce-product-image-gallery {
	margin: 0;
	inline-size: 100% !important;
	max-inline-size: 100%;
	float: none !important;
}

/*
 * DIE BREITENBEGRENZUNG SITZT AN DER GALERIE, NICHT AM BILD
 *
 * 85 % statt der vollen Spaltenbreite: Bei einem quadratischen Produktfoto
 * neben einer deutlich kürzeren Kaufkarte zog das Bild auf voller Breite die
 * ganze Aufmerksamkeit auf sich und ließ die Karte daneben unfertig wirken.
 *
 * Linksbündig, nicht zentriert: Zentriert begann das Bild knapp 48 px rechts
 * von der linken Seitenkante, während Brotkrümel, Titel und Kenndaten dort
 * anliegen. Solange der Rahmen unsichtbar war, fiel der Versatz kaum auf; mit
 * einem Rahmen, der sich aufs Bild legt, ist er eine zweite linke Kante. Die
 * freie Fläche liegt jetzt vollständig zwischen Bild und Kaufkarte und liest
 * sich damit als Spaltenabstand.
 *
 * Diese 85 % standen zuvor am `img`. Die Galerie und die drei Rahmen darunter
 * blieben dabei spaltenbreit, das Bild schrumpfte darin - gemessen ein Rahmen
 * von 636,9 px um ein Bild von 541,4 px. Das hatte drei sichtbare Folgen:
 *
 *   1. Der abgerundete, beschnittene Rahmen lag 95,5 px neben dem Bild.
 *   2. Der Zoom (`.zoomImg`) füllt den Rahmen, nicht das Bild. Beim Hover
 *      sprang die sichtbare Fläche deshalb um 95,5 px in die Breite.
 *   3. Die Lupe setzt ihren Abstand von der Kante der Galerie und stand
 *      dadurch fast 50 px rechts neben der Bildkante.
 *
 * An der Galerie begrenzt, erben Wrapper, Bildrahmen und Zoom-Behälter die
 * Breite, und die Höhe folgt dem Bild - der Rahmen hat damit für jedes
 * Seitenverhältnis dasselbe Format wie die Datei.
 */
.exo-product__media .woocommerce-product-gallery {
	margin: 0;
	inline-size: 85% !important;
	max-inline-size: 85%;
	float: none !important;
}

/*
 * Das Bild füllt den Rahmen, den die Galerie vorgibt. `block-size: auto` hält
 * das Seitenverhältnis der Datei; weil der Rahmen keine eigene Höhe setzt,
 * übernimmt er sie vom Bild.
 *
 * `:not(.zoomImg)` schließt das zweite Bild aus, das die Lupenfunktion in den
 * Rahmen legt: Es ist absolut gesetzt, trägt seine Maße als Inline-Stil und
 * muss größer als der Rahmen bleiben, damit überhaupt etwas zu vergrößern ist.
 */
.exo-product__media .woocommerce-product-gallery__image img:not(.zoomImg) {
	display: block;
	inline-size: 100%;
	block-size: auto;
	border-radius: var(--radius-md);
}

/*
 * Der Bildrahmen trägt die Rundung, nicht nur das Bild selbst.
 *
 * Beim Vergrößern über die eingebaute Lupenfunktion (Hover) legt WooCommerce
 * ein zweites, deutlich größeres `<img>` in diesen Rahmen und verschiebt es
 * per Versatz passend zur Zeigerposition - die eigenen abgerundeten Ecken
 * dieses zweiten Bildes liegen dabei fast immer außerhalb der sichtbaren
 * Fläche. Ohne eine eigene Rundung *am Rahmen* zeigte die sichtbare,
 * zugeschnittene Fläche deshalb scharfe Ecken, sobald man den Mauszeiger auf
 * das Bild bewegte, obwohl das ruhende Bild abgerundet erschien.
 */
.exo-product__media .woocommerce-product-gallery__image {
	overflow: hidden;
	border-radius: var(--radius-md);
}

/*
 * Die Lupe von WooCommerce liegt als absolut gesetzter Knopf über dem Bild
 * und war die einzige Fläche, die man dort zuerst sah. Sie bleibt bedienbar,
 * tritt aber zurück.
 */
.exo-product__media .woocommerce-product-gallery__trigger {
	inset-block-start: var(--wp--preset--spacing--30);
	inset-inline: auto var(--wp--preset--spacing--30);
	opacity: 0.75;
}

.exo-product__buy {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	padding: var(--component-gap-md);
	border: 1px solid var(--color-border);
	border-radius: var(--radius-lg);
	background-color: var(--color-surface-subtle);
}

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

.exo-product__cat {
	margin-block: 0 !important;
	color: var(--color-text-muted);
}

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

.exo-product__cat a:hover {
	text-decoration: underline;
	text-underline-offset: 0.3em;
}

.exo-product__title {
	font-size: var(--wp--preset--font-size--heading-2);
	line-height: var(--line-height-heading);
	letter-spacing: -0.02em;
}

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

/*
 * Der Preis ist die Zahl, wegen der die Karte existiert: Er steht in
 * Tabellenziffern und in der Größe einer Überschrift, ohne eine zu sein.
 */
.exo-product__price {
	font-size: var(--wp--preset--font-size--heading-3);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	line-height: 1.1;
}

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

/* Menge und Schaltfläche in einer Zeile, beide in voller Bedienhöhe. */
.exo-product__buy form.cart {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	margin: 0 !important;
}

/*
 * Die Aufräum-Pseudoelemente von WooCommerce müssen weg.
 *
 * `form.cart::before` und `::after` sind ein Clearfix aus der Zeit der
 * Float-Layouts. In einem Flex-Container sind sie keine unsichtbaren
 * Hilfsmittel mehr, sondern vollwertige Flex-Elemente: Das leere `::before`
 * belegte den ersten Platz, und der Zwischenraum dahinter schob das Mengenfeld
 * gemessen 10 px nach rechts. Es stand damit als einziges Element der Karte
 * nicht auf deren linker Kante.
 *
 * Der vorangestellte Elementname ist nötig, um die Spezifität der
 * WooCommerce-Regel (`.woocommerce div.product form.cart::before`) zu
 * erreichen.
 */
main.exo-product .exo-product__buy form.cart::before,
main.exo-product .exo-product__buy form.cart::after {
	display: none;
}

/* --- Mengenfeld --------------------------------------------------
 *
 * Minus links, Plus rechts, das Feld dazwischen - alles in einer gemeinsamen
 * Kontur, damit die drei Teile als ein Bedienelement lesbar sind und nicht als
 * Feld mit zwei Knöpfen daneben. Die Schaltflächen setzt `assets/js/quantity.js`
 * ein; ohne JavaScript bleibt das schlichte Zahlenfeld übrig, weshalb hier
 * beide Zustände gestaltet sind.
 * ---------------------------------------------------------------- */
.exo-product__buy form.cart .quantity {
	display: flex;
	align-items: stretch;
	margin: 0;
	float: none;
}

/*
 * `.quantity` vierfach statt einfach: WooCommerce liefert für Blockthemes die
 * Regel `.woocommerce div.product form.cart div.quantity .qty
 * { margin-right: .5em }` - fünf Klassen (woocommerce, product, cart,
 * quantity, qty) und drei Elemente (div, form, div), Spezifität (0,5,3).
 * Die nahe liegende Verdopplung auf fünf eigene Klassen (0,5,2) genügte noch
 * nicht: Bei gleicher Klassenzahl entscheidet die Elementzahl, und dort liegt
 * WooCommerce mit drei Elementen vor den zweien dieser Regel (form, input).
 * Die vierfache Klasse hebt die Klassenzahl auf sechs und gewinnt den
 * Vergleich unabhängig von der Elementzahl - ohne eine neue Klasse im
 * Auszeichnungscode zu erfinden und ohne `!important`.
 */
.exo-product__buy form.cart .quantity.quantity.quantity.quantity input {
	min-block-size: var(--control-standard);
	inline-size: 3.5rem;
	margin: 0;
	padding-inline: var(--wp--preset--spacing--20);
	border: 1px solid var(--color-border-strong);
	border-radius: var(--radius-sm);
	background-color: var(--color-surface);
	font-variant-numeric: tabular-nums;
	text-align: center;
}

/*
 * Die vierfache `.quantity` auch hier, und zwar aus einem zweiten Grund als
 * oben: Diese Regel muss die Regel darüber schlagen, nicht die von
 * WooCommerce. Mit nur einfacher Klasse plus Attribut (0,3,2) lag sie unter
 * deren (0,6,2), und `border` samt `border-radius` der Grundregel blieben
 * stehen - das Feld behielt seine runden Ecken und seine seitlichen Rahmen,
 * obwohl Minus und Plus unmittelbar daran anschließen. Sichtbar war das als
 * doppelte Linie zwischen Knopf und Feld und als Rundung mitten in der
 * gemeinsamen Kontur.
 */
.exo-product__buy form.cart .quantity.quantity.quantity.quantity[data-exo-quantity] input {
	inline-size: 3rem;
	border-inline: 0;
	border-radius: 0;

	/*
	 * Die eingebauten Pfeilchen entfallen, sobald Minus und Plus dastehen:
	 * Zwei Wege für dieselbe Handlung, der eine zwei Pixel hoch.
	 */
	appearance: textfield;
}

/*
 * Der Fokusring wandert vom Feld auf das ganze Bedienelement.
 *
 * Am Feld selbst liegt er wegen `outline-offset: 2px` über Minus und Plus und
 * zerschneidet die gemeinsame Kontur; die Grundregel in base.css rundet ihn
 * zusätzlich auf 2px ab, mitten in einer Kante, die gerade sein soll. Um die
 * Hülle gelegt umschließt derselbe Ring alle drei Teile - kein Überlappen,
 * und die Tastaturbedienung bleibt sichtbar.
 *
 * `:has(input:focus-visible)` statt `:focus-within`: Bei Fokus auf Minus oder
 * Plus trägt die Schaltfläche bereits ihren eigenen Ring, ein zweiter um die
 * Hülle wäre doppelt gemoppelt.
 */
.exo-product__buy form.cart .quantity[data-exo-quantity] input:focus-visible {
	outline: none;
}

.exo-product__buy form.cart .quantity[data-exo-quantity]:has(input:focus-visible) {
	outline: 2px solid var(--color-focus);
	outline-offset: 2px;
	border-radius: var(--radius-sm);
}

.exo-product__buy form.cart .quantity[data-exo-quantity] input::-webkit-inner-spin-button,
.exo-product__buy form.cart .quantity[data-exo-quantity] input::-webkit-outer-spin-button {
	appearance: none;
	margin: 0;
}

.exo-quantity__step {
	display: grid;
	place-items: center;
	inline-size: var(--control-standard);
	min-block-size: var(--control-standard);
	padding: 0;
	border: 1px solid var(--color-border-strong);
	background-color: var(--color-surface);
	color: var(--color-text);
	font-size: var(--wp--preset--font-size--base);
	line-height: 1;
	cursor: pointer;
	transition: background-color var(--duration-fast) var(--easing-standard);
}

.exo-quantity__step:first-child {
	border-start-start-radius: var(--radius-sm);
	border-end-start-radius: var(--radius-sm);
}

.exo-quantity__step:last-child {
	border-start-end-radius: var(--radius-sm);
	border-end-end-radius: var(--radius-sm);
}

.exo-quantity__step:hover:not(:disabled) {
	background-color: var(--color-surface-subtle);
}

/*
 * Gesperrt statt versteckt: Die Zeile behält ihre Breite, wenn das Minimum
 * erreicht ist. Eine verschwindende Schaltfläche ließe das Feld springen.
 */
.exo-quantity__step:disabled {
	color: var(--color-text-muted);
	cursor: default;
}

.exo-product__buy form.cart .single_add_to_cart_button {
	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-product__buy form.cart .single_add_to_cart_button:hover {
	background-color: var(--color-brand-hover);
}

.exo-product__assurances {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin: 0 !important;
	padding-block-start: var(--wp--preset--spacing--40);
	padding-inline-start: 0;
	border-block-start: 1px solid var(--color-border);
	list-style: none;
}

.exo-product__assurances > li {
	margin: 0;
	color: var(--color-text-secondary);
	font-size: var(--wp--preset--font-size--sm);
	line-height: var(--line-height-ui);
}

/* --- Kenndaten --------------------------------------------------- */
.exo-product__specs,
.exo-product__description,
.exo-product__related {
	margin-block-start: var(--component-gap-lg);
}

.exo-product__specs > h2,
.exo-product__description > h2 {
	margin-block: 0 var(--wp--preset--spacing--40) !important;
}

/*
 * Datenblatt statt Attributtabelle.
 *
 * WooCommerce liefert eine gestreifte Tabelle mit kursiven Werten. Sie wird
 * auf dieselbe Form gebracht wie die Kenndaten der Material- und
 * Portfolioseiten: Zeilen statt Gitter, Beschriftung in Versalien, Werte in
 * Tabellenziffern.
 */
.exo-product__specs table {
	inline-size: 100%;
	border-collapse: collapse;
}

.exo-product__specs :is(th, td) {
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border: 0;
	border-block-end: 1px solid var(--color-border);
	background: none !important;
	text-align: start;
	vertical-align: top;
}

.exo-product__specs :is(th, td):first-child {
	padding-inline-start: 0;
}

.exo-product__specs th {
	inline-size: 14rem;
	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-product__specs td,
.exo-product__specs td p {
	color: var(--color-text);
	font-style: normal;
	font-variant-numeric: tabular-nums;
}

.exo-product__description .entry-content > * {
	max-inline-size: var(--container-text);
}

/* --- Ähnliche Produkte -------------------------------------------
 *
 * WooCommerce vergibt die Klasse `columns-5`, legt die Kacheln aber als
 * umbrechende Flex-Zeile mit fester Breite aus. Fünf Kacheln zu 240 px plus
 * vier Abstände ergaben 1296 px in einer 1280 px breiten Spalte - die fünfte
 * fiel in eine eigene Zeile und stand dort allein. Ein Raster teilt die
 * vorhandene Breite auf, statt sie vorauszusetzen.
 *
 * Die Stufen springen von fünf auf drei auf zwei Spalten. Vier Spalten fehlen
 * bewusst: Bei fünf Kacheln entstünde dabei genau der einzelne Nachzügler,
 * um den es hier geht.
 * ---------------------------------------------------------------- */
/*
 * `.wp-block-heading` doppelt: WooCommerce erzeugt für den Block „Ähnliche
 * Produkte" eine eigene Regel `.wp-block-woocommerce-product-collection
 * h2.wp-block-heading { font-size: var(--wp--preset--font-size--small) }`
 * mit einem Element-Selektor (`h2`) mehr als hier bisher - bei gleicher
 * Klassenzahl (2 = 2) entscheidet dieser eine Element-Selektor, und die
 * Überschrift blieb bei 13px statt der vorgesehenen Zwischenüberschriftgröße
 * stehen. Die verdoppelte Klasse hebt die Klassenzahl auf drei und gewinnt
 * unabhängig von der Elementzahl.
 */
.exo-product__related .wp-block-heading.wp-block-heading {
	margin-block: 0 var(--component-gap-md) !important;
	font-size: var(--wp--preset--font-size--heading-3);
}

.exo-product__related .wc-block-product-template {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--40);
}

/*
 * Die Kachelbreite kommt aus dem Raster, nicht aus einem Prozentwert.
 *
 * WooCommerce setzt `width: calc(20% - 1em)` über einen doppelt geschriebenen
 * Klassennamen (Spezifität 0,4,1). Als Rasterelement bezieht sich das Prozent
 * nicht mehr auf die Zeile, sondern auf die eigene Spalte: Aus 20 % von 416 px
 * wurden 67 px Kachel in einer 416 px breiten Spalte. Die Gegenregel verwendet
 * denselben Kniff, ohne sich auf die Spaltenzahl im Klassennamen festzulegen.
 */
.exo-product__related .wc-block-product-template.is-flex-container.is-flex-container > li {
	inline-size: auto;
	max-inline-size: none;
	margin: 0;
}

@media (width >= 48rem) {
	.exo-product__related .wc-block-product-template {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (width >= 64rem) {
	/*
	 * Bild und Kaufbereich im Verhältnis 1,1:1.
	 *
	 * Vorher standen sie auf 3:2 - eine Aufteilung, die eine breite Aufnahme
	 * voraussetzt. Die Produktfotos sind quadratisch: Das Bild füllte seine
	 * Spalte nicht, und zwischen ihm und der Kaufkarte klaffte eine leere
	 * Zone. Bei annähernd gleichen Spalten steht das Quadrat auf voller
	 * Spaltenbreite, und die Kaufkarte gewinnt die Fläche, auf der die
	 * Entscheidung fällt.
	 */
	.exo-product__top {
		grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
		gap: var(--component-gap-lg);
	}

	.exo-product__related .wc-block-product-template {
		grid-template-columns: repeat(5, minmax(0, 1fr));
	}
}

/*
 * Kundenbereich: eigene Konfigurator-Dateien (AP-39). Rein funktionale
 * Minimalgestaltung, solange der Konfigurator selbst noch nicht existiert.
 */
.exo-configurator-files {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
}

.exo-configurator-files__item {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--30);
	flex-wrap: wrap;
	padding-block: var(--wp--preset--spacing--20);
	border-block-end: 1px solid var(--color-border);
}

.exo-configurator-files__delete {
	display: inline-flex;
	margin: 0;
}
