/*
 * The catalogue page: grid, tile, filter column. Flow and nothing else.
 *
 * WAS `loop.css` (§ IV.2). The file is not the widget's — the same rules dress
 * the tile whether it came from `ostia-products` or from a Loop Item document
 * of Elementor core widgets. The HANDLE stays `ostia-loop`: three widgets
 * outside this module name it as a string, and renaming it unstyles them.
 *
 * WHAT MAY STAND HERE (§ II.6.1): layout only. No colour, background, font,
 * radius or shadow — each of those is a control on the widget pointing at the
 * class below it, so the template owns the look and the plugin owns the flow.
 *
 * THE EXCEPTIONS, COUNTED — three, only the first in the tile:
 *
 *   1. `opacity` on the stacked second picture and on a disabled button
 *      (`hover-swap`, `state-visible`). § IV.3 prescribes this mechanism, and
 *      no permitted property hides an element while keeping it stacked;
 *      `display` and `visibility` would also stop the picture being fetched.
 *   2. `font-size: 1em` on the filter group heading (`theme-style`) — an
 *      `<h3>`, and without it a filter column is a column of headlines.
 *   3. `font-weight: 600` on the chosen filter value: § II.6.2 names this very
 *      declaration as the example of the `state-visible` ground code.
 *
 * Every selector is a class of ours, at most two deep. `.ostia-ui td` (0,1,1)
 * quietly beat every component class (0,1,0) in the admin and cost a day.
 */

/* ---- the grid ---------------------------------------------------------- */

/*
 * CUSTOM PROPERTIES, so the theme can own the grid. These used to be the
 * properties themselves with a control default of three, so Elementor wrote
 * `grid-template-columns` into every shop whether anyone had chosen or not,
 * landing after the theme and winning.
 *
 * `repeat(N, minmax(0, 1fr))` AND NEVER `auto-fit` (§ IV.5): three hits in a
 * four-column grid would stretch to a third of the page each and turn three
 * products into three posters.
 *
 * The floor is the 2/2/3/4 and 8/12/16/16 px read off the reference shops.
 * Templates set the real values; this is what setting nothing gets.
 */
.ostia-loop {
	--ostia-loop-columns-floor: 2;
	--ostia-loop-gap-floor: 8px;

	display: grid;
	grid-template-columns: repeat(var(--ostia-loop-columns, var(--ostia-loop-columns-floor)), minmax(0, 1fr));

	/*
	 * ZWEI ACHSEN, ZWEI ABSTAENDE. `Katalog.dc.html` setzt `gap: 32px 24px`:
	 * mehr Luft zwischen den Reihen als zwischen den Spalten, weil eine Reihe
	 * aus Bild, Name und Preis ein Absatz ist und eine Spalte nur eine Fuge.
	 * Ohne den Reglerwert faellt der Reihenabstand auf den Spaltenabstand
	 * zurueck, also auf das, was vorher galt.
	 */
	gap: var(--ostia-loop-row-gap, var(--ostia-loop-gap, var(--ostia-loop-gap-floor)))
	     var(--ostia-loop-gap, var(--ostia-loop-gap-floor));
}

@media (min-width: 600px) {
	.ostia-loop { --ostia-loop-gap-floor: 12px; }
}

@media (min-width: 1024px) {
	.ostia-loop { --ostia-loop-columns-floor: 3; --ostia-loop-gap-floor: 16px; }
}

@media (min-width: 1200px) {
	.ostia-loop { --ostia-loop-columns-floor: 4; }
}

/* ---- the tile ---------------------------------------------------------- */

/*
 * `min-width: 0` is load-bearing: a grid item's minimum is its content width,
 * so one long word pushes the column past its track and the row overflows —
 * § IV.8's "sehr langer Titel". Both names, per the transition of § IV.2.
 */
/*
 * ⚠ `:not(.e-con)` — UND DAS IST KEINE FEINHEIT, SONDERN DER GRUND, WARUM DIE
 * KACHEL DES LOOP-ITEMS IHRE ABSTAENDE NICHT BEKAM.
 *
 * Kacheln entstehen an zwei Stellen. Unser Listen-Widget schreibt ein
 * gewoehnliches `<div class="ostia-tile">`, das diese Regel braucht. Elementors
 * Loop-Item ist ein CONTAINER (`e-con`) mit derselben Klasse — und ein
 * Container hat seinen eigenen Abstandsregler, den die Vorlage setzt. Beide
 * Regeln haben dieselbe Spezifitaet (0,1,0); gemessen am 2026-09-10 auf
 * /kategorie/taschen/ gewann unsere: `gap: 6px` statt der 5 px, die
 * `TILE_BOX` schreibt, und der Kachelrhythmus des Blattes war nicht
 * einstellbar.
 *
 * Also gilt sie nur dort, wo es keinen Reglerweg gibt.
 */
.ostia-loop__item,
.ostia-tile:not(.e-con) {
	display: flex;
	flex-direction: column;
	gap: var(--ostia-tile-gap, 6px);
	min-width: 0;
}

.ostia-tile { min-width: 0; }

/*
 * THE PICTURE BOX IS ALWAYS THERE, WITH OR WITHOUT A PICTURE. It carries the
 * ratio, so it is what makes a row of tiles one height; the widget skipped it
 * for a product without a photograph and the row then had two (measured on
 * /shop/: 12 tiles, 10 boxes). 3:4 sits between the three ratios read off the
 * reference shops and is the only exact simple one.
 */
.ostia-loop__media,
.ostia-tile__media {
	/* ⚠ FLEX UND NICHT `block`. Der Kasten ist an zwei Stellen derselbe:
	   unser Listen-Widget legt ein absolut positioniertes Bild hinein (dem
	   ist die Anzeigeart egal), und Elementors Loop-Item ein Bild-Widget im
	   Fluss — und das kann nur über die Flex-Achse auf volle Höhe kommen.
	   Mit `block` war `flex: 1` auf dem Kind wirkungslos, und das Bild blieb
	   257 px hoch in einem 369 px hohen Kasten. */
	display: flex;
	flex-direction: column;
	position: relative;
	overflow: hidden;
	aspect-ratio: var(--ostia-loop-ratio, 3 / 4);
}

/*
 * BOTH PICTURES FILL THE BOX, AND THE SELECTOR IS TWO DEEP ON PURPOSE.
 *
 * Elementor's own frontend sheet carries `.elementor img { height: auto }` —
 * specificity (0,1,1) against a component class's (0,1,0), so a one-class rule
 * here loses and the picture falls back to its own ratio. Measured on /shop/
 * before this line: a 378 px box with a 284 px square in it and 94 px of
 * nothing underneath, on every tile with a photograph. Two of OUR classes is
 * (0,2,0) and wins without `!important` — the borderline § II.1.2 R4 allows,
 * and the reason it allows it.
 */
.ostia-loop__media .ostia-loop__image,
.ostia-tile__media .ostia-tile__image,
.ostia-tile__media .ostia-tile__image--alt,
/*
 * ⚠ UND JEDES BILD IM KASTEN, NICHT NUR UNSERES. Kacheln entstehen an ZWEI
 * Stellen: unser Listen-Widget schreibt `ostia-tile__image` — und Elementors
 * Loop-Grid, das die Kategorieseite benutzt, rendert die eigene
 * Beitragsbild-Kachel mit `attachment-large size-large wp-image-…` und keiner
 * unserer Klassen. Die Regel darüber traf sie nie.
 *
 * Gemessen am 2026-09-07 auf /kategorie/taschen/: Kasten 277 × 369 px,
 * Bild 257 × 257 px, **112 px Leere zwischen Bild und Produktnamen** — auf
 * jeder Kachel der Seite. Es ist derselbe Befund, den der Absatz oben für
 * /shop/ beschreibt, an der zweiten Stelle, an der Kacheln gebaut werden.
 *
 * `.elementor` davor macht (0,2,1) gegen Elementors (0,1,1) und gewinnt ohne
 * `!important`.
 */
.elementor .ostia-tile__media img,
.elementor .ostia-loop__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: var(--ostia-tile-fit, cover);
}

/*
 * ⚠ UND ALLES ZWISCHEN KASTEN UND BILD. Elementors Bild-Widget baut je nach
 * Einstellung `Widget > Container > img` oder `Widget > a > img`; die Kette
 * ist nicht verlässlich, und keine Hülle darin hat eine Höhe. `height: 100%`
 * auf dem Bild bezieht sich damit auf null.
 *
 * Zwei Messungen bis hierher, beide auf /kategorie/taschen/:
 *   Kasten 277 × 369, Bild 257 × 257 — 112 px Leere unter jedem Bild.
 *   Mit `position: absolute; inset: 0` am Bild: 257 × 29.
 *
 * Was trägt, ist die Achse statt fester Höhen: der Kasten ist ein
 * Flex-Container (Elementor macht jeden `e-con` zu einem), also streckt
 * `flex: 1` das erste Kind über die ganze Höhe, und `height: 100%` auf allem
 * darunter reicht sie durch. `min-height: 0` ist die Zeile, ohne die ein
 * Flex-Kind nie kleiner wird als sein Inhalt.
 */
.elementor .ostia-tile__media > .elementor-element,
.elementor .ostia-loop__media > .elementor-element {
	flex: 1 1 auto;
	min-height: 0;
	width: 100%;
}

.elementor .ostia-tile__media a,
.elementor .ostia-loop__media a,
.elementor .ostia-tile__media .elementor-widget-container,
.elementor .ostia-loop__media .elementor-widget-container {
	display: block;
	height: 100%;
	width: 100%;
}

/*
 * THE SECOND PICTURE, AND NOT ONE BYTE OF JAVASCRIPT (§ IV.3). Revealed on
 * `:hover` and `:focus-within` — the second half is what makes it reachable
 * from a keyboard. On a touch device neither fires and the picture is not
 * lost: it stands in the product page's gallery too.
 */
.ostia-tile__image--alt {
	opacity: 0;
	transition: opacity var(--ostia-tile-swap-ms, 200ms) linear;
}

.ostia-tile:hover .ostia-tile__image--alt,
.ostia-tile:focus-within .ostia-tile__image--alt {
	opacity: 1;
}

/* The strip of flags over the picture. Corner and spacing are controls. */
.ostia-tile__badges {
	position: absolute;
	inset: var(--ostia-tile-badges-inset, 0 auto auto 0);
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
	max-width: 100%;
}

.ostia-tile__flag {
	display: inline-block;
}

/*
 * TWO LINES, AND THE SPACE FOR TWO EVEN WITH ONE. A tile must not take its
 * height from a product name, or a row of four has four heights. The line
 * count is a control. The `em` fallback stands first on purpose: an engine
 * that does not know `lh` drops the second declaration and keeps the
 * approximation rather than losing the reservation.
 */
.ostia-loop__title,
.ostia-tile__title {
	/* ⚠ DER KACHELNAME IST EIN `<h3>`, UND EIN `<h3>` BRINGT RAENDER MIT.
	 *
	 * Das Theme gibt ihm `margin: .7em 0 .1em` — auf 16 px Grundschrift
	 * 11,2 px oben. In einer Flex-Spalte addiert sich das zu dem, was die
	 * Regler setzen: 9 px unter dem Bild plus 5 px Luecke plus 11,2 px Rand
	 * ergaben **25 px** zwischen Bild und Name, wo `Main.dc.html` 14
	 * zeichnet. Gemessen am 2026-09-08 auf der Katalogseite.
	 *
	 * Abstand ist Layout und gehoert hierher; welcher Abstand, entscheiden
	 * die Regler `loop_item_gap` und `loop_media_margin`. Diese Zeile nimmt
	 * nur weg, was der Browser dazwischenlegt. */
	margin: 0;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: var(--ostia-tile-title-lines, 2);
	line-clamp: var(--ostia-tile-title-lines, 2);
	overflow: hidden;
	min-width: 0;
	/* ⚠ RESERVIEREN UND KLEMMEN SIND ZWEI DINGE, UND NUR EINES DAVON IST
	 * VORGABE (shop-18). Die Klammer darueber schneidet einen langen Namen ab
	 * — die bleibt, sonst macht ein Name die Kachel hoeher als ihre Nachbarn.
	 * Die reservierte HOEHE stand hier als Vorgabe und war ein Fehler:
	 * gemessen am 2026-09-09 standen unter jedem einzeiligen Namen 21 px
	 * Leere, und der Preis sass tiefer als im Blatt. Sie ist jetzt aus, bis
	 * der Regler `loop_title_reserve` sie einschaltet — und dann fuer beide
	 * Kachelwege, weil das Loop-Item denselben Wert erbt. */
	min-height: calc(var(--ostia-tile-title-lines, 2) * 1.35em * var(--ostia-tile-title-reserve, 0));
	min-height: calc(var(--ostia-tile-title-lines, 2) * 1lh * var(--ostia-tile-title-reserve, 0));
	overflow-wrap: anywhere;
}

/*
 * ⚠ UND DIE UEBERSCHRIFT IM KASTEN, NICHT NUR DER KASTEN. Auf dem Loop-Item
 * traegt `ostia-tile__title` die HUELLE des Heading-Widgets, und der `<h2>`
 * darin bringt die Raender des Themes mit — gemessen am 2026-09-10:
 * 58 px Titelhoehe fuer eine Zeile Text. Die Klammer greift dort ebenfalls
 * nur auf dem Element, das den Text traegt.
 */
.ostia-tile__title > .elementor-heading-title {
	margin: 0;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: var(--ostia-tile-title-lines, 2);
	line-clamp: var(--ostia-tile-title-lines, 2);
	overflow: hidden;
	overflow-wrap: anywhere;
}

/*
 * The price block: several statements on one line, wrapping when they must.
 *
 * ⚠ DER ABSTAND NUR DORT, WO ES KEINEN REGLERWEG GIBT — dieselbe Teilung wie
 * bei der Kachel selbst. Im Loop-Item ist die Preiszeile ein Container mit
 * eigenem Abstandsregler; gemessen am 2026-09-10 gewann unsere Vorgabe von
 * 8 px gegen die 9 des Blattes, die in der Vorlage standen.
 */
.ostia-tile__prices {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	min-width: 0;
}

.ostia-tile__prices:not(.e-con) {
	gap: var(--ostia-tile-prices-gap, 8px);
}

/* Each on its own row: beside the total price they read as a second offer. */
.ostia-tile__reference,
.ostia-tile__base {
	flex-basis: 100%;
}

.ostia-loop__price,
.ostia-tile__price,
.ostia-tile__price-was {
	font-variant-numeric: tabular-nums;  /* money: a price whose digits jump is not a column */
}

/*
 * The text lines, and it is not decoration: a long unbroken run — a maker's
 * name, a unit in a Grundpreis — would push the tile past its track. The
 * failure `min-width: 0` fixes on the tile itself, one level down.
 */
.ostia-tile__brand,
.ostia-tile__discount,
.ostia-tile__reference,
.ostia-tile__base,
.ostia-tile__tax,
.ostia-tile__shipping,
.ostia-tile__sizes,
.ostia-tile__stock {
	min-width: 0;
	overflow-wrap: anywhere;
}

/* The colours. A row of links that wraps rather than a row that overflows. */
.ostia-tile__swatches {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ostia-tile-swatch-gap, 6px);
	min-width: 0;
}

.ostia-tile__swatch {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	white-space: nowrap;
}

/*
 * DER FARBPUNKT IST EIN KREIS OHNE INHALT, und deshalb braucht er eine
 * Groesse, die nicht vom Text kommt: `Katalog.dc.html` zeichnet 16 px. Die
 * Zahl steht am Regler `loop_swatch_size`, hier steht nur, dass ein leeres
 * Element ueberhaupt eine Ausdehnung hat — ohne diese Zeile ist ein `<a>`
 * ohne Text null Pixel breit und der Punkt unsichtbar.
 *
 * Die FARBE steht als `style` am Element und ist Inhalt, keine Gestaltung:
 * „cognac ist #A8703C" ist eine Aussage ueber die Ware, wie das Foto daneben.
 */
.ostia-tile__swatch--dot {
	flex: 0 0 auto;
	width: var(--ostia-tile-swatch-size, 1rem);
	height: var(--ostia-tile-swatch-size, 1rem);
}

/* „3 Farben" steht in derselben Zeile wie die Punkte und rueckt ein wenig ab. */
.ostia-tile__swatch-count {
	align-self: center;
	white-space: nowrap;
}

/* „Benachrichtigen, wenn da" ist ein Verweis in der Verfuegbarkeitszeile. */
.ostia-tile__notify {
	overflow-wrap: anywhere;
}

/*
 * DER SCHLEIER UEBER DEM AUSVERKAUFTEN BILD (`Main.dc.html`: weisse Flaeche
 * mit .62 Deckkraft). Hier steht nur, DASS eine Flaeche ueber dem Bild liegt
 * und wie weit sie reicht; welche Farbe sie hat, entscheidet der Regler
 * `loop_soldout_veil` — ohne ihn ist sie durchsichtig und damit unsichtbar.
 * Ueber dem Bild und unter den Abzeichen, damit das Schild „AUSVERKAUFT"
 * nicht mitverblasst.
 */
.ostia-tile--soldout .ostia-tile__media::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.ostia-tile__badges { z-index: 1; }

/*
 * One class for both shapes — the button and the "choose first" link — so a
 * control reaches them together and the tile keeps its height either way.
 */
.ostia-loop__buy,
.ostia-tile__buy {
	display: inline-block;
	align-self: start;
	cursor: pointer;
}

.ostia-loop__buy[disabled],
.ostia-tile__buy[disabled] {
	cursor: not-allowed;
	opacity: .55;  /* state-visible: a disabled button that looks enabled is a trap */
}

/* ---- the states of § IV.8 ---------------------------------------------- */

/* Empty, and with a way out: twelve empty states in this shop had none. */
.ostia-loop__empty {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: .5rem;
}

.ostia-loop__empty-title,
.ostia-loop__empty-text {
	margin: 0;
}

.ostia-loop__notice {
	margin: 0 0 1rem;
}

/*
 * DIE BLÄTTERUNG IST EINE REIHE VON ZIELEN, KEINE ZEILE ZAHLEN.
 *
 * Gemessen am 2026-09-08 auf /shop-mit-filterspalte/: „1 2 3 … 10 Weiter"
 * stand linksbündig, und die Ziffer „2" war **10 px breit und 20 px hoch** —
 * ein Ziel von 200 px², wo WCAG 2.5.5 (AAA) 44 × 44 und 2.5.8 (AA) 24 × 24
 * nennt. `Katalog.dc.html` zeichnet 40 × 40 px, mittig, 8 px auseinander.
 *
 * Hier steht nur die Geometrie: Grösse, Abstand, Ausrichtung. Rahmen und
 * Farbe der Kästchen fehlen und haben eine Zeile in der Funktionsmatrix —
 * `ProductLoopWidget` hat für die Blätterung bisher nur `Canon::shell`, also
 * Polster und Aussenabstand, und ein Rahmen aus diesem Stylesheet wäre eine
 * Gestaltung, die kein Shop mehr ändern kann.
 */
.ostia-loop__pages {
	margin-top: 24px;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: .5rem;
}

.ostia-loop__pages .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.5rem;
	min-height: 2.5rem;
	padding: 0 .5rem;
}

/* „Zurück" und „Weiter" tragen ein Wort und brauchen die Breite dafür. */
.ostia-loop__pages .prev,
.ostia-loop__pages .next {
	padding: 0 1rem;
}

/* WCAG 2.3.3. The picture still swaps; only the fade goes. */
@media (prefers-reduced-motion: reduce) {
	.ostia-tile__image--alt {
		transition: none;  /* motion */
	}
}

/* THE FILTER LIST. Server-rendered anchors, 0 bytes of bundle. Decision 350. */
/*
 * Die Abstände sind die des Blattes `docs/gui/zielbild/Katalog.dc.html`: die
 * Spalte setzt 30 px zwischen ihre Blöcke, eine Gruppe 13 px zwischen Titel
 * und Werten und zwischen den Werten. Sie stehen ZUSÄTZLICH als Vorgabe an
 * `facets_wrap_gap`, `facets_values_gap` und `facets_active_gap` im Widget,
 * weil Elementors Regler sonst mit seinen eigenen 24 px darüberschreibt —
 * gemessen am 2026-09-08: die Werteliste stand 49 px auseinander, und keine
 * Zeile dieses Stylesheets war daran beteiligt.
 */
.ostia-facets { display: flex; flex-direction: column; gap: 1.875rem; }
.ostia-facets__active { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.ostia-facets__chip { display: inline-flex; align-items: center; gap: .375rem; }
.ostia-facets__panel { min-width: 0; }
.ostia-facets__summary { cursor: pointer; }
.ostia-facets__group { display: flex; flex-direction: column; gap: var(--ostia-facet-group-gap, .625rem); }

/*
 * ⚠ DIE GRUPPE IST EIN `<details>` UND IHR KOPF EIN `<summary>` (shop-12).
 *
 * Das Blatt zeichnet neben „Farbe" ein Aufklapp-Symbol; im Band (shop-26) ist
 * dieselbe Gruppe zugeklappt und ihre Werte gehen als Flaeche darunter auf.
 * Beides ist ein natives Element — kein ARIA-Nachbau, volle Tastatur, null
 * Byte Buendel, dieselbe Entscheidung wie beim Klappbereich der Spalte
 * darueber.
 *
 * `font-size: 1em` bleibt (theme-style, siehe Kopf): der Kopf war ein `<h3>`
 * und ist jetzt ein `<summary>` — Themes geben BEIDEN eine eigene Groesse mit,
 * und ohne diese Zeile ist eine Filterspalte eine Spalte aus Ueberschriften.
 * Das Dreieck des Browsers faellt weg, weil daneben das gezeichnete Symbol
 * steht und zwei Pfeile an einer Zeile einer zu viel sind.
 */
.ostia-facets__label { margin: 0; font-size: 1em; display: flex; align-items: center; cursor: pointer; }
.ostia-facets__label { list-style: none; }
.ostia-facets__label::-webkit-details-marker { display: none; }
.ostia-facets__label::marker { content: ""; }

.ostia-facets__chevron {
	flex: 0 0 auto;
	width: var(--ostia-facet-chevron, .75rem);
	height: var(--ostia-facet-chevron, .75rem);
	margin-left: auto;
	transition: transform 120ms linear;
}

/* Aufgeklappt zeigt das Symbol nach oben — der Zustand, den `[open]` schon hat. */
.ostia-facets__group[open] > .ostia-facets__label .ostia-facets__chevron { transform: rotate(180deg); }

.ostia-facets__drop { display: flex; flex-direction: column; gap: var(--ostia-facet-group-gap, .625rem); }

@media (prefers-reduced-motion: reduce) {
	.ostia-facets__chevron { transition: none; }  /* motion */
}
.ostia-facets__values { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: .5rem; }
.ostia-facets__value a { display: flex; align-items: baseline; gap: .625rem; padding: .125rem 0; }
.ostia-facets__value a[aria-current="true"] { font-weight: 600; }  /* state-visible, see the header */
.ostia-facets__count { font-variant-numeric: tabular-nums; }  /* money */
.ostia-facets__reset { align-self: flex-start; }
.ostia-facets__end { display: block; }

/*
 * „6 weitere anzeigen" — der Rest einer Gruppe.
 *
 * Das Blatt zeichnet einen Verweis, keinen Aufklapper mit Dreieck: das
 * Zeichen des Browsers steht vor einem Wort, das schon sagt, was es tut, und
 * es ist das einzige Dreieck in einer Spalte aus Kästchen. Weg damit — wie
 * beim Kopf der Spalte eine Zeile darüber, aus demselben Grund.
 *
 * Wie der Verweis AUSSIEHT, entscheidet `facets_more` am Widget; hier steht
 * nur, dass er eine Zeile ist und keinen Marker trägt.
 */
.ostia-facets__rest > summary { list-style: none; cursor: pointer; display: inline-block; }
.ostia-facets__rest > summary::-webkit-details-marker { display: none; }
.ostia-facets__rest > summary::marker { content: ""; }
.ostia-facets__rest > .ostia-facets__values { margin-top: .5rem; }

/*
 * The skip link, from HUGO BOSS. Off-screen rather than `display: none`: a
 * link that is not rendered is one the keyboard cannot reach either.
 *
 * ⚠ POLSTER UND RAHMEN GEHÖREN ZUM VERSTECKEN. Ohne die beiden Zeilen ist
 * dieses Element 1 × 1 px GROSS und 50 × 30 px BREIT: `width` und `height`
 * beschreiben den Inhalt, das Kit gibt jedem Klickziel 14/24 px Polster und
 * einen Rahmen, und beides steht weiter da. Gemessen am 2026-09-07 — der
 * Wächter meldete zwei Überlappungen mit der Filterüberschrift, bei 390 und
 * 768 px, und das war kein Fehlalarm: der unsichtbare Kasten lag auf der
 * Zeile, die man antippt, um die Filter zu öffnen.
 *
 * Es ist dieselbe Zeile, die in `screen-reader-text` von WordPress steht,
 * und aus demselben Grund.
 */
.ostia-facets__skip {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	white-space: nowrap;
	clip-path: inset(50%);
}

.ostia-facets__skip:focus-visible {
	position: static;
	width: auto;
	height: auto;
	padding: revert;
	border: revert;
	clip-path: none;
}

/*
 * DAS SUCHFELD (§ VIII.4.1).
 *
 * Struktur, sonst nichts: eine Zeile, die umbricht, ein Feld, das den Platz
 * nimmt, ein Knopf, der nicht umbricht. Wie es aussieht, entscheidet die
 * Vorlage über die Regler des Widgets — die Beschriftung steht sichtbar über
 * dem Feld und ist kein Platzhalter, weil ein Platzhalter beim Tippen
 * verschwindet und für eine Sprachausgabe gar kein Name ist.
 */
.ostia-search { display: flex; flex-wrap: wrap; align-items: end; gap: .5rem; }
.ostia-search__label { flex: 1 0 100%; }
.ostia-search__field { flex: 1 1 12rem; min-width: 0; }
.ostia-search__button { flex: 0 0 auto; }

/* „Meistgesucht": eine Reihe Wege, die Rubrik über ihnen. Achse und
 * Trefferfläche stehen hier, Grösse, Rahmen und Rundung an den Reglern —
 * derselbe Schnitt wie eine Zeile darüber. Die 34 px sind das Ziel, nicht
 * die Gestalt: WCAG 2.5.8 nennt 24 × 24 als Untergrenze. */
.ostia-search__suggestions { display: flex; flex-wrap: wrap; align-items: center; }
.ostia-search__suggestions-label { flex: 1 0 100%; }
.ostia-search__suggestion { display: inline-flex; align-items: center; min-height: 34px; }

/* THE FILTER PANEL IS A DISCLOSURE ON A PHONE AND A LIST ON A DESKTOP.
 *
 * The `<details>` is rendered open in every case — see `FacetLinks::panel()`
 * for why one element cannot be closed on a phone and open on a desktop
 * without JavaScript. Above 1024 px the control disappears and what is left
 * is an ordinary list of links, which is what a filter column is.
 *
 * `list-style: none` and the `::-webkit-details-marker` rule remove the
 * triangle where the summary IS shown: it reads as a folder icon next to a
 * word that is already a button. */
.ostia-facets__summary { list-style: none; }
.ostia-facets__summary::-webkit-details-marker { display: none; }

@media (min-width: 1024px) {
	/* ⚠ NICHT MEHR `display: none`, SONDERN NUR NICHT MEHR ANKLICKBAR.
	 *
	 * Bis zum 2026-09-07 verschwand die Zeile „Filter" auf dem Desktop ganz,
	 * und damit auch der einzige Ort, an dem „Alle Filter entfernen" stehen
	 * konnte: die Spalte begann mit „Farbe" und man musste raten, dass die
	 * Liste darunter überhaupt ein Filter ist. Die Zeichnung setzt dort einen
	 * Kopf, und jeder Referenzshop tut es auch.
	 *
	 * Der Aufklapper bleibt weg — auf dem Desktop ist nichts zuzuklappen —
	 * aber die Überschrift bleibt. `pointer-events` statt `display`, damit
	 * ein Klick daneben das `<details>` nicht schliesst. */
	.ostia-facets__panel > .ostia-facets__summary {
		pointer-events: none;
		cursor: default;
	}

	.ostia-facets__skip { display: none; }

	/*
	 * DER KOPF DER SPALTE: WORT LINKS, ZURÜCKSETZEN RECHTS — UND DIE CHIPS
	 * DAZWISCHEN, WIE DAS BLATT SIE SETZT.
	 *
	 * ⚠ EIN GRID AUF DEM `<details>` HAT DAS NIE GETAN, UND ES SAH AUCH NICHT
	 *   SO AUS, ALS TÄTE ES NICHTS. Bis zum 2026-09-08 stand hier
	 *   `.ostia-facets__panel { display: grid }` mit `grid-column: 1 / -1` auf
	 *   den Gruppen. Gemessen auf /shop-mit-filterspalte/ mit Chrome 151:
	 *   Spalte 270 px breit, „Filter" in einer 100-px-Spalte, **jede
	 *   Filtergruppe in einer 154 px schmalen zweiten Spalte daneben** — die
	 *   Werte 116 px eingerückt, die Zahlen am rechten Rand, und die
	 *   `grid-column`-Angabe im berechneten Stil korrekt als `1 / -1`.
	 *
	 *   Der Grund ist neu und steht in keinem Lehrbuch von 2023: Chrome legt
	 *   den Inhalt eines `<details>` seit `::details-content` in EINEN
	 *   anonymen Kasten. Das Grid hatte damit nicht sechs Kinder, sondern
	 *   zwei — `<summary>` und diesen Kasten. Alles, was für die Kinder galt,
	 *   galt für niemanden.
	 *
	 *   `display: contents` auf beiden Ebenen hebt beide Kästen auf, und dann
	 *   sind Kopf, Chips und Gruppen wieder Geschwister in EINEM Raster —
	 *   dem der Spalte selbst, nicht dem des `<details>`. Nur so kann die
	 *   Chip-Reihe zwischen Kopf und erste Gruppe: sie steht im HTML VOR dem
	 *   `<details>`, und ein Raster mit ausdrücklichen Zeilen ist der einzige
	 *   Weg, sie dahinter zu setzen, ohne die Struktur zu verbiegen, die die
	 *   Tastatur braucht.
	 *
	 *   Ein Browser ohne `::details-content` (Firefox, ältere Safari) braucht
	 *   nur die erste der beiden Zeilen und bekommt dasselbe Ergebnis.
	 *
	 * ⚠ NUR IM AUFGEKLAPPTEN ZUSTAND (`[open]`). `display: contents` nimmt
	 *   dem `<details>` auch die Fähigkeit, seinen Inhalt zu VERBERGEN —
	 *   nachgemessen: ein geschlossenes `<details>` mit
	 *   `::details-content { display: contents }` zeigt seinen Inhalt. Auf
	 *   dem Desktop ist der Aufklapper stillgelegt, aber die Tastatur
	 *   erreicht das `<summary>` weiterhin; fällt `[open]` weg, fällt auch
	 *   diese Regel weg und das Element klappt wieder normal zu.
	 */
	.ostia-facets {
		display: grid;
		grid-template-columns: 1fr auto;
		align-items: baseline;
		column-gap: 1rem;
		row-gap: 1.875rem;
	}

	.ostia-facets__panel[open] { display: contents; }
	.ostia-facets__panel[open]::details-content { display: contents; }

	.ostia-facets__panel[open] > .ostia-facets__summary { grid-row: 1; grid-column: 1; }
	.ostia-facets__panel[open] > .ostia-facets__reset { grid-row: 1; grid-column: 2; justify-self: end; }
	.ostia-facets__active { grid-row: 2; grid-column: 1 / -1; }
	.ostia-facets__group,
	.ostia-facets__end { grid-column: 1 / -1; }

	/*
	 * ⚠ ZWEIMAL „ALLE FILTER ENTFERNEN" IN EINER SPALTE IST EINMAL ZU VIEL.
	 *
	 * `FacetLinks` setzt den Verweis an zwei Stellen, und mit gutem Grund:
	 * die Chip-Reihe steht auch dort, wo die Spalte zugeklappt ist. Sobald
	 * beide sichtbar sind — und das sind sie genau dann, wenn der Kopf offen
	 * neben den Chips steht — sagen zwei Zeilen dasselbe, zwei Zeilen
	 * auseinander. Das Blatt hat einen.
	 *
	 * Die Bedingung nennt beide Voraussetzungen ausdrücklich: es gibt einen
	 * im Kopf UND der Kopf ist aufgeklappt. Klappt jemand mit der Tastatur zu,
	 * ist der im Kopf weg — und dann muss der in der Chip-Reihe wieder da
	 * sein, sonst führt aus einem Filter kein Weg mehr heraus.
	 */
	.ostia-facets:has(.ostia-facets__panel[open] > .ostia-facets__reset)
		.ostia-facets__active > .ostia-facets__reset { display: none; }
}

/*
 * Unterhalb von 1024 px bleibt das `<details>` ein `<details>`: es klappt zu,
 * und ein zugeklappter Filter ist auf einem Telefon der ganze Zweck. Der Kopf
 * steht dann über der Chip-Reihe statt darunter — die einzige Stelle, an der
 * das Blatt und das Gebaute sich unterscheiden, und die Reihenfolge, die auf
 * einem schmalen Schirm die bessere ist: was gerade filtert, steht sichtbar,
 * auch wenn die Liste selbst geschlossen ist.
 */
.ostia-facets__panel {
	display: flex;
	flex-direction: column;
	gap: 1.875rem;
}

/*
 * Ein Kästchen vor jedem Wert — der Zustand, den die Zeichnung zeigt.
 *
 * ⚠ UND ES BLEIBT EIN LINK. Die Werte sind Anker, weil jede Kombination eine
 * Adresse hat: teilbar, ohne JavaScript, im Verlauf. Ein echtes
 * `<input type="checkbox">` wäre ein Formular und würde beides aufgeben.
 * Das Kästchen ist deshalb gezeichnet und nicht bedienbar — der Screenreader
 * hört „Link, schwarz, 24, aktuelle Seite", was vollständig und wahr ist,
 * und das Auge sieht, was es aus jedem anderen Shop kennt.
 *
 * ⚠ HIER STEHT NUR DER PLATZ, NICHT DAS AUSSEHEN. Der erste Entwurf malte das
 * Kästchen hier fertig — Rahmen, Radius, Häkchen als zwei Farbverläufe —, und
 * `ProductTileTest::testTheStylesheetPaintsNothing` hat es beim ersten Lauf im
 * Container gemeldet: `catalog.css has started painting: background,
 * border-radius`. Die Prüfung hat recht. Das Stylesheet trägt Layout, die
 * Gestaltung trägt das Bedienfeld, und ein Kästchen, dessen Farbe hier steht,
 * ist eines, das kein Shop an sein Kit anpassen kann.
 *
 * Geblieben ist die Geometrie: dass Platz da ist, wie viel, und dass er nicht
 * schrumpft. Rahmen, Radius und Häkchen setzt `facets_box` im Widget.
 */
.ostia-facets__value a::before {
	content: "";
	flex: 0 0 auto;
	width: var(--ostia-facet-box, 16px);
	height: var(--ostia-facet-box, 16px);
	align-self: center;

	/* ⚠ BREITE UND ART DES RAHMENS, ABER KEINE FARBE — UND DAS IST EINE
	   REPARATUR, KEINE VERFEINERUNG. Der Regler `facets_box_color` schrieb
	   `border: 1px solid {{VALUE}}`; Elementor ersetzt bei einem Global den
	   ganzen Eigenschaftswert und machte daraus `border: var(<farbe>)`, was
	   ungültig ist. Das Kästchen stand seither ohne Rahmen da — gemessen am
	   2026-09-08 im erzeugten `post-*.css`, sichtbar als sechzehn Pixel
	   Nichts vor jedem Filterwert.

	   Die Farbe bleibt beim Regler, weil sie eine Entscheidung des Shops ist.
	   Hier steht nur, DASS es eine Kante gibt und wie stark — dieselbe
	   Teilung wie bei der Grösse eine Zeile höher. Ohne einen Wert vom
	   Regler erbt sie `currentColor`, also die Schriftfarbe des Wertes: ein
	   sichtbares Kästchen statt gar keines. */
	border-style: solid;
	border-width: 1px;
}

/* Der Wert wächst, die Zahl bleibt rechts, das Kästchen davor bleibt fest. */
.ostia-facets__value a > .ostia-facets__count { margin-left: auto; }

/*
 * DIE KNOPFREIHE — DIE ZWEITE GESTALT EINES FILTERWERTS.
 *
 * `Katalog.dc.html` setzt Größe als Reihe: „Klein Mittel Groß" nebeneinander,
 * 62 px Mindestbreite, 7 px auseinander. Der Grund ist Platz, gemessen am
 * 2026-09-08 an der ausgelieferten Spalte: neun Grössen als Liste waren
 * **297 px Spaltenhöhe für neun Kürzel**, dieselben neun als Reihe sind zwei
 * Zeilen. Welche Gruppe so steht, entscheidet die Vorlage (`buttons`) — hier
 * steht nur, wie eine Reihe aussieht, wenn es eine ist.
 *
 * Das Kästchen fällt weg: der Knopf IST der Zustand, und zwei Anzeigen
 * desselben Zustands nebeneinander sind eine zu viel.
 */
.ostia-facets__values--pills {
	flex-direction: row;
	flex-wrap: wrap;
	gap: .4375rem;
}

.ostia-facets__value--pill a {
	align-items: center;
	justify-content: center;
	min-width: 3.875rem;
}

.ostia-facets__value--pill a::before { display: none; }

/*
 * THE TWO CLASSES THE TILE EMITTED AND NOTHING STYLED.
 *
 * Counted 2026-09-01: 22 of the 24 `ostia-tile*` classes had a rule here, and
 * these two had none — so a sold-out tile looked exactly like a deliverable
 * one, and a tile with no picture collapsed to whatever the theme gave it.
 * Structure only, as everywhere in this file: the sold-out tile is dimmed and
 * its button says so by being a button that cannot be pressed; the empty media
 * box keeps the ratio the picture would have had, so a grid of tiles does not
 * jump because one article has no photograph yet.
 */
.ostia-tile--soldout {
	/* Not `display: none`: an article the shop still lists is an article the
	   customer may want to see, and hiding it is a decision for the template
	   (the loop can filter), never for a stylesheet. */
	opacity: .72;
}

.ostia-tile--soldout .ostia-tile__buy[disabled],
.ostia-tile__buy[disabled] {
	cursor: not-allowed;
}

.ostia-tile__media--empty {
	aspect-ratio: 3 / 4;
}

/* ── DER MERKEN-KNOPF ─────────────────────────────────────────────────────
 *
 * Layout only, like everything else in this file: `ProductLoopWidget` carries a
 * control for each of the three classes, and a rule here that paints is a rule
 * an operator has to fight.
 *
 * A `<form>` in a tile is a block element that would otherwise claim a line of
 * its own with the browser's own margins. It gets none, and the button inside
 * it is the thing with the 44 px target — on the BUTTON and not on the form,
 * because padding around a control accepts no pointer input (decision 459).
 */
/*
 * Der Merkknopf als Quadrat mit Herz (`show_label` aus): das Wort bleibt im
 * Markup und wird vorgelesen, nur der Schirm zeigt es nicht — dasselbe Rezept
 * wie bei jeder anderen unsichtbaren Beschriftung in diesem Projekt.
 */
.ostia-wish--icon .ostia-wish__label {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.ostia-wish {
  margin: 0;
}

.ostia-wish__button {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  min-height: 2.75rem;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  /* Inherited so the button is not the browser's blue on a shop that has not
     styled it yet. Not a colour of our own — that is the operator's. */
  color: inherit;
  font: inherit;
}

.ostia-wish__icon {
  /* The heart must not resize the row when it switches between outline and
     filled: both glyphs are one character, but their advance widths differ. */
  display: inline-block;
  min-width: 1em;
  text-align: center;
}

/*
 * ── DAS HERZ AUF DEM BILD ───────────────────────────────────────────────────
 *
 * `Merkliste.dc.html` und `Konto.dc.html` setzen es als Kreis oben rechts auf
 * das Foto, 30 px, weiss. Bis heute war es ein gerahmter Knopf von 65 × 51 px
 * als eigene ZEILE unter dem Kaufknopf — gemessen am 2026-09-09 auf
 * /kundenkonto/.
 *
 * ⚠ DAS FORMULAR STEHT NEBEN DEM BILDVERWEIS, NICHT DARIN. Ein `<form>` in
 * einem `<a>` ist ungueltiges HTML, und der Knopf darin ist nicht bedienbar;
 * `Tile::media()` legt beide als Geschwister in den Bildkasten, der ohnehin
 * `position: relative` traegt (die Abzeichen liegen schon darauf).
 *
 * Hier steht nur Lage und Trefferflaeche. Wie der Kreis AUSSIEHT — Flaeche,
 * Radius, Polster, Groesse — entscheiden `loop_wish_*` am Widget.
 */
.ostia-tile__media > .ostia-wish {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
}

.ostia-tile__media > .ostia-wish .ostia-wish__button {
  width: var(--ostia-wish-size, 2rem);
  height: var(--ostia-wish-size, 2rem);
  min-height: 0;
  justify-content: center;
  gap: 0;
  position: relative;
}

/*
 * ⚠ 44 PX TREFFERFLAECHE UM EINEN 30-PX-KREIS, und deshalb als Pseudo-Element
 * statt als Polster: Polster um ein Bedienelement vergroessert den Kreis, den
 * man sieht (Entscheidung 459). Das hier vergroessert nur, was den Zeiger
 * annimmt — die Zeichnung bleibt 30 px, das Ziel wird 44.
 */
.ostia-tile__media > .ostia-wish .ostia-wish__button::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

/*
 * Die Ergebniszeile: Trefferzahl links, Sortierung rechts.
 *
 * Die Zahl steht IM Sortier-Widget und nicht daneben, weil sie erst beim
 * Rendern feststeht — siehe den Block in `SortWidget::render()`. Für das
 * Layout heisst das: das Widget ist die Zeile, nicht das Formular darin.
 */
.elementor-widget-ostia-sort .elementor-widget-container {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: .75rem 1.5rem;
}

.ostia-sort__count {
	margin: 0;
}

/* Die Zahl in „41 von 62 Artikeln" — Ziffern gleicher Breite, damit die Zeile
   beim Filtern nicht wandert. Dieselbe Regel wie an jeder anderen Zahl. */
.ostia-sort__found { font-variant-numeric: tabular-nums; }  /* money */

/*
 * ⚠ UND DAS FORMULAR IST SELBST EINE ZEILE. Ohne diese vier Zeilen ist
 * `<form>` ein Block und `<label>`, `<select>` und der Knopf stehen
 * UNTEREINANDER — auf /kategorie/taschen/ am 2026-09-08 gemessen: drei
 * Zeilen, 100 px hoch, der Knopf allein in der dritten. Das Blatt setzt
 * „Sortieren" und das Auswahlfeld nebeneinander an den rechten Rand, und die
 * Zeile darüber ist nur dann eine, wenn beide Hälften welche sind.
 *
 * Der Abstand steht als Vorgabe an `sort_form_gap` im Widget; hier steht nur
 * die Richtung.
 */
.ostia-sort {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .625rem;
}

/*
 * ⚠ UND DAS AUSWAHLFELD NIMMT SEINE BREITE VOM INHALT. `display: flex` allein
 *   reichte nicht: Elementors Theme Style gibt jedem `select` volle Breite,
 *   also nahm es die ganze Zeile und schob den Knopf in die dritte. Genau so
 *   sah es nach der ersten Fassung dieses Blocks aus — gemessen, nicht
 *   vermutet.
 */
.ostia-sort__label,
.ostia-sort__button { flex: 0 0 auto; }

.ostia-sort__select {
	flex: 0 1 auto;
	width: auto;
	max-width: 100%;
	min-width: 0;
}

/*
 * ⚠ DAS AUSWAHLFELD UND SEIN PFEIL (shop-15).
 *
 * Ein `<select>` bringt den Pfeil des Betriebssystems mit, und der laesst
 * sich nicht gestalten: gemessen am 2026-09-08 stand auf der Shopseite ein
 * 184 × 39 px grosses Feld in #EFEFEF mit dem Systempfeil, waehrend das Blatt
 * 190 × 40 px mit Feldkante, Radius 4 und einem eigenen Chevron zeichnet.
 * `appearance: none` nimmt den Systempfeil weg, das SVG steht an seiner
 * Stelle und faengt keine Klicks ab, damit das Feld unter ihm anklickbar
 * bleibt.
 *
 * Nur Achse und Platz. Kante, Radius, Schrift und die Farbe des Pfeils sind
 * `sort_select_*` und `sort_chevron_*` am Widget.
 */
.ostia-sort__field {
	position: relative;
	display: inline-flex;
	align-items: center;
	flex: 0 1 auto;
	min-width: 0;
	max-width: 100%;
}

.ostia-sort__field > .ostia-sort__select {
	appearance: none;
	-webkit-appearance: none;
	width: 100%;
	/* Platz fuer den Pfeil, damit ein langer Eintrag nicht darunter laeuft. */
	padding-right: calc(var(--ostia-sort-chevron, .75rem) + 1.5em);
}

.ostia-sort__chevron {
	position: absolute;
	right: .75em;
	width: var(--ostia-sort-chevron, .75rem);
	height: var(--ostia-sort-chevron, .75rem);
	pointer-events: none;
}

/*
 * ⚠ VOM SCHIRM, NICHT AUS DEM FORMULAR (shop-16). Der Knopf traegt das
 * Formular ohne JavaScript und bleibt in der Tabulatorfolge; sichtbar wird er
 * wieder, sobald ihn jemand mit der Tastatur erreicht. Dieselbe Zeile wie in
 * `screen-reader-text` von WordPress, aus demselben Grund — Polster und
 * Rahmen gehoeren zum Verstecken, sonst liegt ein unsichtbarer Kasten ueber
 * der Zeile daneben.
 */
/*
 * ⚠ `!important`, WIE IN WORDPRESS' `screen-reader-text` — UND AUS DEMSELBEN
 *   GRUND. Der Knopf traegt Reglerwerte (`facets_price_go_*`, `sort_*`), und
 *   Elementor schreibt sie als `{{WRAPPER}} .ostia-facets__price-go` — (0,2,0)
 *   und spaeter im Stapel. Ohne Vorrang blies die Vorlage den versteckten
 *   Knopf am 2026-09-10 wieder auf 50 x 30 px auf, mitten auf dem Preisfeld:
 *   acht Ueberlappungen und ein unsichtbarer Kasten ueber einem Eingabefeld.
 *   Verstecken ist kein Gestaltungswert, den ein Regler ueberstimmen darf.
 */
.ostia-sort__button--hidden,
.ostia-facets__price-go--hidden {
	position: absolute !important;
	width: 1px !important;
	height: 1px !important;
	min-height: 0 !important;
	padding: 0 !important;
	border: 0 !important;
	overflow: hidden;
	white-space: nowrap;
	clip-path: inset(50%);
}

.ostia-sort__button--hidden:focus-visible,
.ostia-facets__price-go--hidden:focus-visible {
	position: static;
	width: auto;
	height: auto;
	padding: revert;
	border: revert;
	clip-path: none;
}


/* ── DAS FILTERBAND (shop-26) ───────────────────────────────────────────────
 *
 * Dieselbe Spalte ueber 1280 px war kein Band: gemessen am 2026-09-09 auf
 * /shop-mit-filterband/ standen die Werte untereinander, die Zaehler 1100 px
 * vom Wort entfernt, und vor der ersten Kachel lagen 810 px Filter. Ein Band
 * fuehrt die Gruppen NEBENEINANDER, jede als Aufklapper, deren Werteliste als
 * Flaeche darunter aufgeht.
 *
 * Nur Achse und Lage. Flaeche, Kante und Radius der Aufklappflaeche sind
 * `facets_drop_*` am Widget; ohne sie ist sie durchsichtig, und das ist als
 * Vorgabe richtig — eine Flaeche, die dieses Stylesheet malt, kann kein Shop
 * mehr aendern.
 */
/* ⚠ `flex-direction` GEHOERT DAZU, SONST IST DAS BAND EINE SPALTE.
 * Gemessen am 2026-09-10, als die Vorlage `layout => band` zum ersten Mal
 * setzte: die Gruppen standen untereinander. `.ostia-facets` traegt seit jeher
 * `flex-direction: column` (oben) und ab 1024 px ein Grid, dessen Gruppen
 * `grid-column: 1 / -1` haben — die Bandregel hat beides bis auf `display`
 * ueberschrieben und die Achse stehen lassen. */
.ostia-facets--band { display: flex; flex-direction: row; flex-wrap: wrap; align-items: baseline; }
.ostia-facets--band .ostia-facets__panel { flex-direction: row; flex-wrap: wrap; align-items: baseline; }
.ostia-facets--band .ostia-facets__group { position: relative; }

.ostia-facets--band .ostia-facets__group[open] > .ostia-facets__drop {
	position: absolute;
	top: 100%;
	left: 0;
	z-index: 5;
	min-width: var(--ostia-facet-drop, 13rem);
	max-height: 60vh;
	overflow-y: auto;
}

/* Am rechten Rand klappt die Flaeche nach innen statt aus dem Bild heraus. */
.ostia-facets--band .ostia-facets__group:last-of-type[open] > .ostia-facets__drop { left: auto; right: 0; }

/* ── DIE PREISSPANNE (shop-09) ──────────────────────────────────────────────
 *
 * Das eine Formular der Spalte: eine Grenze wird getippt, nicht geklickt. Die
 * Felder teilen sich die Zeile, „bis" steht dazwischen und schrumpft nicht.
 * Groesse, Kante und Radius der Felder sind `facets_price_field_*`.
 */
.ostia-facets__price { display: flex; flex-wrap: wrap; align-items: center; }
.ostia-facets__price-sep { flex: 0 0 auto; }

.ostia-facets__price-field {
	flex: 1 1 var(--ostia-facet-price-field, 4.5rem);
	width: var(--ostia-facet-price-field, 4.5rem);
	min-width: 0;
	/* Die Spinnknoepfe eines Zahlenfeldes sind in einem 38-px-Feld zwei
	   Ziele von je 9 px — unter jeder Trefferflaechenregel, und sie
	   verschieben den Text. Getippt wird hier ohnehin. */
	appearance: textfield;
	-moz-appearance: textfield;
}

.ostia-facets__price-field::-webkit-outer-spin-button,
.ostia-facets__price-field::-webkit-inner-spin-button { appearance: none; margin: 0; }

/* Der Knopf nimmt die ganze Breite unter den Feldern — in 248 px ist neben
   zwei Feldern und „bis" kein Platz mehr fuer ein drittes Element. */
.ostia-facets__price-go { flex: 1 0 100%; }

/* Die Schaltergruppe steht als letzte und traegt im Blatt eine Linie ueber
   sich; die Linie ist `facets_switches_border_*` am Widget, hier steht nur,
   dass sie ganz unten steht. */
.ostia-facets__group--switches { order: 1; }

/*
 * ── DER SATZ AUF DER KATEGORIEKACHEL (cat-25) ──────────────────────────────
 *
 * `Kategorien.dc.html` setzt unter „Umhängetaschen 24" einen Satz: „Von der
 * kleinen Clutch bis zur Wochentasche". Name und Zahl stehen auf einer
 * Grundlinie (`storefront.css`), der Satz gehoert darunter — also eine eigene
 * Zeile im selben Kasten. Nur Achse; Groesse und Farbe sind `cattile_text_*`.
 */
.ostia-cattile__label { flex-wrap: wrap; }
.ostia-cattile__text { flex: 1 0 100%; min-width: 0; }
