/*
 * The checkout: two columns of page, six columns of field, one button.
 *
 * WHY A FOURTH STYLESHEET AND NOT `storefront.css`
 *
 * `storefront.css` is enqueued on EVERY page of every shop — `Storefront::registerStyle()`
 * says why, and it is right: the confirmation bar after adding to the basket is
 * `position: fixed` and can appear anywhere. The checkout is on one page. Its
 * rules travel on the rail `catalog.css`, `buy.css` and `mini-cart.css` already
 * use: registered, never enqueued, pulled in by `CheckoutWidget::get_style_depends()`.
 *
 * MEASURED, BECAUSE THE SPLIT IS NOT A PREFERENCE. On 2026-08-31
 * `assets/storefront/ostia.css` stood at 3.003 gzipped bytes against the 3.072
 * the build asserts — 69 bytes free, with § VII.6.2 owing this file a grid, a
 * sticky column, a six-column field row and a whole error state. The same
 * argument § VI.8 made for `ostia-checkout.js`, one layer down: a shop's
 * product page should not download the checkout's layout.
 *
 * WHAT MAY STAND HERE (§ II.6.1, § VII.6.2): layout only. Grid, spans, gaps,
 * sticky behaviour, breakpoints, `min-width: 0`. No colour, no font, no border,
 * no radius, no shadow — every one of those is a control on `CheckoutWidget`
 * pointing at the class beside it (§ VII.6.10), so the template owns the look.
 *
 * THE EXCEPTIONS, COUNTED — six, each undoing a browser default or making a
 * state perceptible, none of them a design decision (5 and 6 are written
 * where they stand: the focus ring, and the picture of a removed position):
 *
 *   1. `min-height: 2.75rem` on every text control. WCAG 2.2 SC 2.5.5 wants a
 *      44 px target; a theme may make a box bigger and must not make it
 *      smaller, so it is `min-height` and not `height` (the same fix
 *      `storefront.css` already made for the quantity box).
 *   2. `font-size: max(16px, 1rem)` on every text control. Under 16 px Safari
 *      on iOS zooms the page when the field takes focus, and a checkout that
 *      zooms reads as broken. A floor, not a typeface.
 *   3. `outline: 2px solid currentColor` on a field that is wrong. An error
 *      nobody can see is not an error, and `currentColor` takes no colour
 *      decision — it is whatever the theme is already writing in. The widget
 *      offers a real colour on top (`.ostia-field--error .ostia-field__input`).
 *   4. `background`/`color` on the closing bar, from system colours and behind
 *      two custom properties. Same argument `storefront.css` makes for
 *      `.ostia-added`: this is markup the storefront creates over the page, so
 *      it cannot inherit a design it was never given, and a bar you cannot read
 *      against the form behind it is not a bar.
 *
 * WHY CONTAINER QUERIES AND NOT MEDIA QUERIES
 *
 * Because the tightness is in the CONTAINER, never in the window. § VI paid for
 * that lesson once already: the basket's remove button sat under the totals on
 * a wide window inside a narrow theme column, because the media query asked the
 * wrong element how much room there was. The checkout is worse — it is the one
 * island a shop is likely to drop into a 640 px content column. So the page
 * columns, the field pairs and the closing bar all ask `.ostia-checkout` and
 * `.ostia-checkout__form` how wide THEY are.
 *
 * Project plan § VII.6.2, § VII.6.7, § VII.6.10.
 */

/* ── The two columns of the page (§ VII.6.2) ────────────────────────────── */

/*
 * The form is the query container. It cannot query itself, which is why the
 * grid is one element further in: `__columns` asks `.ostia-checkout` how wide
 * it is and lays itself out accordingly.
 */
.ostia-checkout {
	container-type: inline-size;
	container-name: ostia-checkout;
	display: flex;
	flex-direction: column;
	gap: var(--ostia-checkout-gap, 1.5rem);
	min-width: 0;
}

/*
 * ⚠ EIGENER ABSTAND FÜR DIE SPALTEN, WEIL EINE ZAHL DREI AUFGABEN HATTE.
 *
 * `--ostia-checkout-gap` steht auf `.ostia-checkout`, auf `__columns` und auf
 * `__form`. Gemessen am 2026-09-08 bei 1440 px: 44 px zwischen den Abschnitten
 * des Formulars (richtig, `Kasse.dc.html` setzt 44) UND 44 px zwischen Formular
 * und Übersicht (falsch, das Blatt setzt 80). Eine Zahl kann nicht beides sein,
 * also bekommt der Spaltenabstand seine eigene und fällt auf die alte zurück,
 * wo niemand sie setzt — ein Shop, der nichts ändert, sieht keinen Unterschied.
 */
.ostia-checkout__columns {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	/* Rows keep the rhythm of the form (44 px between blocks), columns the
	   80 px of the page raster — one number could not be both, see below. */
	gap: var(--ostia-checkout-gap, 1.5rem) var(--ostia-checkout-columns-gap, var(--ostia-checkout-gap, 1.5rem));
	align-items: start;
}

/*
 * DER SCHLUSSBLOCK IST EIN DRITTES RASTERFELD, und wo er steht, entscheidet
 * dieses Stylesheet — nicht die Insel.
 *
 * `Kasse.dc.html` zeichnet Kästchen, Knopf und Schlusssatz am Ende der
 * Formularspalte; das Gesetz will die Summe unmittelbar VOR dem Knopf gelesen
 * (§ 312j Abs. 2 BGB), und eine Vorlesehilfe liest die Quellreihenfolge. Also
 * schreibt die Insel Formular → Übersicht → Schlussblock, und hier wird der
 * Schlussblock unter die Formularspalte GESTELLT: Spalte 1, Zeile 2, die
 * Übersicht daneben über beide Zeilen. Geometrie, nichts sonst — Rahmen und
 * Polster des Blocks setzt der Regler `co_closing`.
 *
 * In einer Spalte (unter 48 rem) gilt die Quellreihenfolge: Formular,
 * Übersicht, Knopf — wie bisher, und wie die Leiste am unteren Rand es
 * voraussetzt.
 */
.ostia-checkout__closing {
	display: flex;
	flex-direction: column;
	gap: 1.25rem;
	min-width: 0;
	max-width: var(--ostia-checkout-form-max, none);
}

.ostia-checkout__form {
	/* The second container. The field pairs of § VII.6.2 depend on how wide the
	   FORM column is, which is not how wide the checkout is once the summary
	   sits beside it. */
	container-type: inline-size;
	container-name: ostia-checkout-form;
	display: flex;
	flex-direction: column;
	gap: var(--ostia-checkout-gap, 1.5rem);
	min-width: 0;
	/*
	 * DIE SPALTE IST NICHT DER SATZSPIEGEL. `Kasse.dc.html` gibt der linken
	 * Spalte 1fr von 1.280 px — also 780 — und deckelt den Inhalt darin auf
	 * 640. Gemessen am 2026-09-08 ohne Deckel: jedes ganzbreite Feld war
	 * 820 px breit, ein Eingabefeld also 180 px breiter als gezeichnet.
	 *
	 * Ein `max-width` auf dem Rasterelement und nicht auf der Spur: die Spur
	 * bleibt 1fr, damit die Übersicht dort steht, wo das Blatt sie zeichnet
	 * (x = 940). Ein `--ostia-checkout-form: 640px` auf der Spur hätte sie um
	 * 140 px nach links gezogen.
	 */
	max-width: var(--ostia-checkout-form-max, none);
}

.ostia-checkout__aside {
	display: flex;
	flex-direction: column;
	gap: var(--ostia-checkout-field-gap, .75rem);
	min-width: 0;
}

/*
 * 48rem = 768 px OF CONTAINER, AND THE PLAN'S 1024 px IS A WINDOW.
 *
 * § VII.6.2 sets the second page column at 1024 px of window. This file cannot
 * ask about a window, and it should not: measured 2026-08-31 with
 * `tests/Browser/checkout-layout.mjs`, the same markup gets
 *
 *   · 1.196 px of container on the shop's own Elementor checkout page — at
 *     1.366 px of window AND at 1.920 px, because Elementor's content width is
 *     boxed. The window moved by 554 px and the checkout's room did not move at
 *     all, which is the whole argument for asking the container;
 *   · 735 px on an ordinary page of the block theme, at every window from
 *     768 px up;
 *   · 600 px inside a 600 px column at a 1.366 px window.
 *
 * So the second column appears on the first of those and not on the other two,
 * and that is right rather than a shortfall: 735 px minus a 22rem summary minus
 * the gap leaves the address form 359 px, and § VII.6.2 refuses a summary column
 * narrow enough to wrap "1 × Umhängetasche Nora 189,00 €".
 *
 * ⚠ Which means acceptance 3's "zwei Spalten bei 1366 px" is only true where the
 * theme gives the checkout the room — on the shop's own checkout page it is, on
 * a 735 px block-theme page it is not and must not be.
 */
@container ostia-checkout (min-width: 48rem) {
	.ostia-checkout__columns {
		grid-template-columns:
			minmax(0, var(--ostia-checkout-form, 1fr))
			minmax(18rem, var(--ostia-checkout-aside, 22rem));
		grid-template-rows: auto 1fr;
	}

	.ostia-checkout__form {
		grid-column: 1;
		grid-row: 1;
	}

	.ostia-checkout__aside {
		grid-column: 2;
		grid-row: 1 / 3;
	}

	.ostia-checkout__closing {
		grid-column: 1;
		grid-row: 2;
	}

	/*
	 * THE SUMMARY STICKS, WITH A LID.
	 *
	 * Without `max-height` a basket of twenty positions makes the column taller
	 * than the window and the order button unreachable — the mistake sticky
	 * summary columns make almost every time.
	 *
	 * ⟲ DER SATZ „der Knopf kommt mit, und Summe und Knopf sind in einem
	 *    Bildlaufbehälter" stand hier und stimmt seit dem 2026-09-10 nicht
	 *    mehr: der Schlussblock steht seither in der Formularspalte. Abnahme 5
	 *    wird deshalb gemessen, wie das Gesetz sie stellt — Knopf ins Bild
	 *    holen, nachsehen, ob die Summe mitsteht (`checkout-layout.mjs`).
	 */
	.ostia-checkout__aside {
		position: sticky;
		top: var(--ostia-checkout-sticky-top, 1.5rem);
		align-self: start;
		max-height: calc(100vh - var(--ostia-checkout-sticky-top, 1.5rem) - 1.5rem);
		/* ⟲ NICHT MEHR `overflow-y: auto` AUF DER GANZEN SPALTE — siehe unten. */
		display: flex;
		flex-direction: column;
		min-height: 0;
	}

	/*
	 * ⚠ DIE LISTE SCROLLT, DIE SUMMEN STEHEN.
	 *
	 * Der Deckel auf der Spalte ist richtig: ohne ihn macht ein Korb mit
	 * zwanzig Positionen den Bestellknopf unerreichbar. Falsch war, WAS unter
	 * dem Deckel scrollt. Bis zum 2026-09-21 scrollte die ganze Spalte, und
	 * damit scrollten die Summen mit: auf dem Abnahmefoto
	 * `storefront--checkout--viele--1366.png` stand am Fuss der Spalte
	 * „Gesamt 1.339,60 €" — und darüber NUR Positionen. Zwischensumme,
	 * USt-Zeile, Versand und der Steuerhinweis waren aus dem Bild
	 * geschoben. Der Betrag stand ohne jeden Steuerausweis da, und § 14
	 * Abs. 4 Nr. 7 UStG ist der Grund, warum diese Spalte überhaupt Zeilen
	 * je Satz hat.
	 *
	 * ⟲ EIN ERSTER VERSUCH AM SELBEN TAG WAR SCHLIMMER als das Problem: die
	 *    Gesamtzeile wurde `position: sticky; bottom: 0` geheftet. Sie stand
	 *    dann zwar im Bild — als weisser Balken in einem beigen Kasten, unter
	 *    dem eine halbe Produktkachel hervorsah, und die übrigen Summenzeilen
	 *    blieben trotzdem weg. Eine Zahl sichtbar zu machen, indem man den
	 *    Rest verdeckt, ist keine Reparatur.
	 *
	 * Jetzt scrollt genau das, was lang werden kann: die Positionsliste.
	 * Alles, was die Kundin vor dem Bestellen gesehen haben muss, steht
	 * darunter fest. `min-height: 0` ist die tragende Hälfte davon — ohne sie
	 * weigert sich ein Flex-Kind, kleiner als sein Inhalt zu werden, und der
	 * Deckel greift wieder auf die ganze Spalte durch.
	 */
	.ostia-checkout__summary {
		display: flex;
		flex-direction: column;
		min-height: 0;
	}

	.ostia-checkout__items {
		overflow-y: auto;
		min-height: 0;
		flex: 0 1 auto;
	}

}

/* ── The six columns of the address block (§ VII.6.2) ───────────────────── */

.ostia-checkout__block {
	display: grid;
	grid-template-columns: repeat(6, minmax(0, 1fr));
	gap: var(--ostia-checkout-field-gap, .75rem) var(--ostia-checkout-field-gap, 1rem);
	margin: 0;
	padding: 0;
	border: 0;
	min-width: 0;
}

/* A legend, a hint, a notice — anything that is not a field — takes the row.
   `<legend>` also needs its UA padding removed or it hangs left of the grid. */
.ostia-checkout__block > :not(.ostia-field) {
	grid-column: 1 / -1;
}

.ostia-checkout__block legend {
	padding: 0;
}

/*
 * A field is a stack of label, control, hint, message — and it must be able to
 * shrink. `min-width: 0` is the load-bearing half of that in a grid: without it
 * a long hint sets the column's minimum and the two-column layout silently
 * becomes one wide column with an overflow.
 */
.ostia-field {
	display: flex;
	flex-direction: column;
	/* 6 px zwischen Beschriftung und Feld, wie die Zeichnung sie setzt. */
	gap: .375rem;
	margin: 0;
	min-width: 0;
	grid-column: span var(--ostia-field-span, 6);
}

/*
 * ⚠ UND DAS THEME GIBT JEDEM `label` 16 PX NACH UNTEN.
 *
 * Gemessen am 2026-09-08 auf `ostia-storefront`: `label { margin-bottom: 1rem }`
 * — richtig für ein einzelnes Formularfeld im Fliesstext, falsch in einem
 * Stapel, der seinen Abstand schon über `gap` regelt. Zweimal Abstand ergab
 * 20 px zwischen Beschriftung und Feld, und in einer Auswahlkarte kamen die
 * 16 px UNTER dem Etikett dazu: die Karte war 94 statt 78 px hoch, ohne dass
 * irgendwo etwas danach aussah.
 *
 * Geometrie, wie der Deckel weiter oben — und aus demselben Grund zwei Ebenen
 * tief, damit sie den Elementwähler des Themes schlägt.
 */
.ostia-field label {
	margin: 0;
}

/*
 * PLZ AND ORT ARE ONE ROW AT EVERY WIDTH, INCLUDING 390 px.
 *
 * Two columns of six and four of six. § VII.6.2 sets this explicitly and
 * refuses to let it collapse: in every addressing habit these two are one line,
 * and a checkout that stacks them looks like a form somebody forgot to finish.
 * At 390 px of window that is about 88 px and 190 px, both of which hold their
 * content.
 */
.ostia-field--postcode {
	--ostia-field-span: 2;
}

.ostia-field--city {
	--ostia-field-span: 4;
}

/*
 * The pairs: first/last name, province/country. Full width until the FORM
 * column is wide enough for two, never before.
 *
 * 30rem is the form column, not the window: below it a half is 14rem, and
 * "Prinz-Eugen-Straße" no longer fits a label above a box.
 */
.ostia-field--half {
	--ostia-field-span: 6;
}

@container ostia-checkout-form (min-width: 30rem) {
	.ostia-field--half {
		--ostia-field-span: var(--ostia-checkout-half, 3);
	}
}

/*
 * ⚠ DAS THEME DECKELT UNSERE FELDER, UND ZWAR NICHT AUS VERSEHEN.
 *
 * Gemessen am 2026-09-08 auf `ostia-storefront`:
 *
 *   `p { max-width: var(--s-measure); }`                    → 680 px
 *   `input[type="text"], … , select, textarea { max-width: 26rem; }` → 416 px
 *
 * Beides ist für Fliesstext und ein einzelnes Formularfeld richtig. In einem
 * Raster aus sechs Spalten ist es falsch: die Insel schreibt jedes Feld als
 * `<p class="ostia-field">`, also war JEDES ganzbreite Feld der Kasse 680 statt
 * 736 px breit und jedes EINGABEFELD darin 416 — schmaler als die Hälfte
 * daneben. Auf dem Bild sah es aus, als hätte jemand die Breiten geraten.
 *
 * DAS IST GEOMETRIE UND KEINE GESTALTUNG: Die Deckel sind eine Aussage über
 * eine Lesezeile, und in unserem Raster gibt es keine Lesezeile, sondern eine
 * Zelle. Die Zelle ist bereits vermessen (`--ostia-field-span`), und ein
 * zweiter, kleinerer Deckel darüber macht aus einem Sechsspalter eine Kolonne
 * mit Luft rechts.
 *
 * ⚠ ZWEI KLASSEN TIEF, WEIL EINE NICHT REICHT. `input[type="text"]` wiegt
 * (0,1,1); `.ostia-field__input` wiegt (0,1,0) und verliert. `.ostia-checkout`
 * davor macht (0,2,0) — das ist der ganze Grund für den längeren Wähler.
 */
.ostia-checkout p {
	max-width: none;
}

.ostia-checkout .ostia-field__input {
	max-width: 100%;
}

/*
 * ⚠ AUSNAHME 2 STEHT EIN ZWEITES MAL DA, WEIL SIE OBEN VERLOR — UND DREI
 *   KLASSEN TIEF, WEIL ZWEI NICHT REICHEN.
 *
 * Gemessen am 2026-09-08 mit `checkout-layout.mjs`: 15 px auf JEDEM
 * Eingabefeld JEDER Kasse, an dreizehn Stellen gemeldet. Zwei Wähler stehen
 * davor, und beide wiegen mehr als `.ostia-field__input` (0,1,0):
 *
 *   `input[type="text"] { font: inherit; }`            (0,1,1)  — das Theme
 *   `.elementor-kit-7 input[type="text"] { 15px }`     (0,2,1)  — der Kit
 *
 * Der zweite ist der teure, und er wiegt mehr, als er aussieht: `Look::kit()`
 * setzt Elementors Formular-Theme-Style auf 15 px, und der Wähler dazu lautet
 *
 *   `.elementor-kit-7 input:not([type="button"]):not([type="submit"])`
 *
 * — eine Klasse, zwei `:not()` mit je einem Attribut und ein Typ, also (0,3,1).
 * Ein Versuch mit drei Klassen (0,3,0) verlor daran, und das war im Bild nicht
 * zu sehen: die Zahl blieb 15. Die Untergrenze braucht deshalb VIER Klassen.
 * Kein `!important` — der Regler des Widgets steht mit (0,4,0) gleichauf und
 * kommt später, ein Shop kann also weiterhin GRÖSSER werden. Kleiner nicht,
 * und das ist der Zweck.
 *
 * Warum überhaupt eine Untergrenze: unter 16 px zoomt iOS beim Antippen eines
 * Eingabefelds in die Seite hinein. Eine Kasse, die beim ersten Feld springt,
 * liest sich als kaputt.
 */
.ostia-checkout .ostia-checkout__form .ostia-field .ostia-field__input {
	font-size: max(16px, 1rem);
}

/* ── The controls themselves ────────────────────────────────────────────── */

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

.ostia-field__input {
	box-sizing: border-box;
	width: 100%;
	min-width: 0;
	/* Exceptions 1 and 2 — see the head of this file. */
	min-height: 2.75rem;
	font-size: max(16px, 1rem);
}

/* Never wider than its own cell, and 6rem wherever the cell allows it
   (§ VII.6.2 asks for the floor; `min()` is what keeps the floor from becoming
   a horizontal scrollbar inside a narrow theme column). */
.ostia-field--postcode .ostia-field__input {
	min-width: min(6rem, 100%);
}

.ostia-field__hint,
.ostia-field__error {
	min-width: 0;
	font-size: .875em;
}

/*
 * AUSNAHME 5 — DER FOKUSRING, und er steht hier, weil der Regler ihn nicht
 * allein setzen kann.
 *
 * ⚠ GEMESSEN AN ELEMENTOR 4.2.2, `core/files/css/base.php:361`: trägt ein
 * Regler einen GLOBAL, ersetzt Elementor den ganzen Wert hinter dem Doppelpunkt
 * —
 *
 *     preg_replace( '/(:)[^;]+(;?)/', '$1' . $global . '$2', $css_property )
 *
 * — aus `outline: 2px solid {{VALUE}};` wird also `outline:var(--e-global-…);`
 * und damit gar kein Umriss. Der Regler schreibt deshalb nur noch
 * `outline-color`, und Breite und Art stehen hier.
 *
 * Ohne sichtbaren Fokus ist die Kasse mit der Tastatur nicht bedienbar
 * (WCAG 2.4.7) — dieselbe Art Ausnahme wie Nummer 3, und aus demselben Grund
 * ohne eigene Farbe: `currentColor` ist, was das Theme ohnehin schreibt.
 */
.ostia-field__input:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 2px;
}

/* Exception 3. A wrong field has to look different from a right one before any
   template has been styled at all. */
.ostia-field--error .ostia-field__input {
	outline: 2px solid currentColor;
	outline-offset: 1px;
}

/* A postcode we merely do not recognise is a warning, not a refusal — the order
   goes through. So it is marked, and marked less. */
.ostia-field--warn .ostia-field__input {
	outline: 1px dashed currentColor;
	outline-offset: 1px;
}

/* A radio or a checkbox reads left to right, not as a stack. The ROW carries
   the 44 px target: a 44 px radio is not a radio, and what a finger aims at is
   the label beside it. */
.ostia-field--choice {
	--ostia-field-span: 6;
	flex-direction: row;
	align-items: center;
	gap: .5rem;
	min-height: 2.75rem;
}

.ostia-field--choice input {
	flex: 0 0 auto;
	width: auto;
	min-width: 0;
}

/* Das Kästchen in der Grösse, die die Zeichnung setzt — 18 px, ein Pixel
   unter der ersten Textzeile. Trefferfläche, wie beim Radioknopf der Karten;
   die Farbe kommt weiterhin aus `co_choice_accent`. */
.ostia-field--choice input[type="checkbox"] {
	inline-size: 1.125rem;
	block-size: 1.125rem;
	margin-top: 1px;
}

/* Die Beschriftung einer Auswahlzeile darf schrumpfen und umbrechen; ihre
   Schrift setzt der Regler `co_choice_label`. */
.ostia-field__choice-label {
	min-width: 0;
}

/*
 * THE ROW WAS 44 px AND THE TARGET WAS 27.
 *
 * `min-height: 2.75rem` above sets the height of the ROW, and the sentence
 * "a 44 px radio is not a radio" that stood here concluded from it that the row
 * carries the target. It does not: `align-items: center` leaves the box and its
 * label 27 px tall (checkbox) and 29 px (the delivery radios) in the middle of
 * a 44 px row, and the padding around them accepts no pointer action at all.
 * Measured by `tests/Browser/checkout-layout.mjs` on all three surfaces and all
 * four widths, 2026-08-31: 19 of 236 checks.
 *
 * SC 2.5.5 (Enhanced, 44 px) is about "the region of the display that will
 * accept a pointer action", and for a control with a `<label for>` that region
 * is the box AND the label — so the label is where the height has to be. Under
 * SC 2.5.8 (Minimum, 24 px) they always passed; § VII.6.2 cites the 44.
 *
 * No font size is set here on purpose: the 16 px elsewhere in this file exists
 * for the iOS zoom on a field being TYPED INTO, and a checkbox cannot be typed
 * into.
 */
.ostia-field--choice label {
	display: flex;
	align-items: center;
	min-height: 2.75rem;
	min-width: 0;
}

/*
 * DAS ZUSTIMMUNGSKÄSTCHEN: ein Satz mit zwei Verweisen, Kästchen oben links.
 *
 * Kein 44-px-Etikett in der Mitte wie bei den einzeiligen Auswahlzeilen — der
 * Satz kann zwei Zeilen lang werden, und dann gehört das Kästchen an die
 * erste (Blatt „Kasse": margin-top 1px, gap 11px). Die Fehlermeldung darunter
 * nimmt die ganze Zeile, sonst stünde sie rechts neben dem Satz.
 *
 * ⚠ NACH `.ostia-field--choice label` UND NICHT DAVOR — GEMESSEN AM
 *   2026-09-10, und es ist genau die Falle, die `.ostia-checkout__ship label`
 *   zwei Bildschirmseiten weiter unten schon einmal aufgeschrieben hat: beide
 *   Wähler wiegen gleich viel, also entscheidet die Reihenfolge. Davor
 *   gestellt gewann `display: flex`, und ein Flexcontainer verwirft den
 *   Leerraum zwischen seinen Elementen — auf dem Bild stand „Ich habe
 *   dieAGBund dieWiderrufsbelehrunggelesen". Ein Satz mit Verweisen darin ist
 *   Fliesstext und kein Flexcontainer.
 */
.ostia-checkout__consent {
	flex-wrap: wrap;
	align-items: flex-start;
	gap: .6875rem;
}

.ostia-checkout__consent input {
	margin-top: .1875rem;
}

/*
 * DAS ZIEL IST 44 px HOCH, AUCH WENN DER SATZ AUF EINE ZEILE PASST.
 *
 * SC 2.5.5 will 44 px in beide Richtungen. Die Zeile war so hoch wie ihr
 * Text: passte der Satz in EINE Zeile, waren das 22 px. Gemessen am
 * 2026-09-20 auf der Kassenseite des Shops bei 1366 und 1920 px —
 * „640×22 px". Auf den schmaleren Probeseiten brach der Satz um und die
 * Prüfung war grün: die Regel war zufällig erfüllt, je nach Spaltenbreite.
 *
 * `min-height` und nicht `display: flex`: der Kommentar über diesem Block
 * erklärt, warum ein Flexcontainer hier falsch wäre — er verwirft den
 * Leerraum zwischen den Verweisen, und der Satz las sich „Ich habe
 * dieAGBund dieWiderrufsbelehrunggelesen". Der Text bleibt oben stehen, wo
 * er neben dem Kästchen gehört; nur die anklickbare Fläche wächst nach
 * unten.
 */
.ostia-checkout__consent label {
	display: block;
	flex: 1 1 0;
	min-height: 44px;
}

.ostia-checkout__consent .ostia-field__error {
	flex-basis: 100%;
}

/*
 * DIE RECHTSLINKS IM EINWILLIGUNGSSATZ SIND UNTERSTRICHEN.
 *
 * Nicht Gestaltung, sondern WCAG 1.4.1: ein Verweis mitten im Fliesstext darf
 * sich nicht allein durch die Farbe vom Satz unterscheiden. Gemessen am
 * 2026-09-20 mit axe auf der Kassenseite: `link-in-text-block`, schwerwiegend,
 * zweimal — die AGB und die Widerrufsbelehrung, also genau die beiden
 * Dokumente, die Art. 246a EGBGB vor der Bestellung erreichbar verlangt.
 *
 * Die Unterstreichung steht hier und nicht an allen Verweisen: ausserhalb
 * eines Satzes trägt die Stelle selbst die Unterscheidung, und dort wäre sie
 * Gestaltung. Deshalb bleibt `.ostia-checkout__legal` — die freistehende
 * Reihe „Widerruf · AGB · Datenschutz", die erscheint, wenn das Kästchen
 * abgeschaltet ist — ohne Regel; axe beanstandet sie nicht, weil kein Satz
 * um sie herum steht. Der Abstand hält die Linie von den Unterlängen frei.
 */
.ostia-checkout__consent label a {
	text-decoration: underline;
	text-underline-offset: .125em;
}

/*
 * „optional" NEBEN DER BESCHRIFTUNG, UND ES DARF NICHT UMBRECHEN.
 *
 * Die Zeichnung (`docs/gui/zielbild/Kasse.dc.html`) markiert das Freiwillige
 * statt des Pflichtfelds — bei zehn Pflichtfeldern von zwölf ist die Ausnahme
 * die Information. Was hier steht, ist Geometrie: das Wort gehört an die
 * Beschriftung und nicht auf eine zweite Zeile. Grösse und Farbe kommen vom
 * Regler `co_optional`.
 */
.ostia-field__optional {
	white-space: nowrap;
}

/*
 * VERSANDART UND ZAHLUNG SIND KÄSTEN, NICHT ZEILEN (§ VII.6.2, Blatt „Kasse").
 *
 * Eine Auswahlzeile ist nicht gleich Auswahlzeile: „Rechnungsadresse weicht
 * ab" ist ein Kästchen im Fliesstext, „Standard — Österreichische Post,
 * Dienstag, kostenfrei" ist eine Karte mit drei Angaben. Deshalb ein eigener
 * Modifikator statt einer Regel auf `--choice`: sonst bekäme jedes Kästchen im
 * Formular einen Rahmen, und die Zeichnung zeigt genau das Gegenteil.
 *
 * Rahmen, Polster und Radius setzt der Regler `co_option` — hier steht nur,
 * WO die Teile liegen: Knopf oben links, Text daneben, Preis rechts.
 */
.ostia-field--option {
	align-items: flex-start;
	gap: .8125rem;
}

/* Der Knopf sitzt auf der Höhe der ersten Textzeile, nicht in der Mitte einer
   zweizeiligen Karte — und er ist so gross, wie die Zeichnung ihn setzt: der
   Vorgabeknopf des Browsers ist 13 px und verschwindet in einer 78 px hohen
   Karte. Geometrie; die Farbe setzt der Regler `co_choice_accent`. */
.ostia-field--option input {
	margin-top: .5rem;
	inline-size: 1.1875rem;
	block-size: 1.1875rem;
}

.ostia-field--option label {
	flex: 1 1 auto;
}

/* ── The closing block (§ VII.6.6) ──────────────────────────────────────── */

/*
 * THE SUMMARY AND THE BUTTON ARE ONE BLOCK, and the CSS says so.
 *
 * § 312j Abs. 2 BGB wants the essential characteristics, the total and the
 * shipping cost "unmittelbar bevor der Verbraucher seine Bestellung abgibt".
 * Nothing here may put space, a column break or a scroll between the summary
 * and the button — they are siblings in `__aside` with no gap control of their
 * own beyond the one that separates every part of it.
 */
.ostia-checkout__summary {
	display: flex;
	flex-direction: column;
	gap: .25rem;
	min-width: 0;
}

.ostia-checkout__items {
	margin: 0 0 .5rem;
	padding: 0;
	list-style: none;
}

.ostia-checkout__item,
.ostia-checkout__line,
.ostia-checkout__payment {
	display: flex;
	justify-content: space-between;
	gap: 1rem;
	margin: 0;
	min-width: 0;
}

/*
 * THE LABEL IS A STACK, because the row is a description and not a title.
 *
 * § 312j Abs. 2 BGB wants the wesentliche Merkmale (Art. 246a § 1 Abs. 1 Satz 1
 * Nr. 1 EGBGB) on the view with the button, and a variant's merkmale do not fit
 * on the same line as its quantity and its price. So the label column carries
 * the name, the options and the article number under one another while the
 * amount stays on the row's baseline.
 *
 * Structure only, as everywhere here: the smaller size marks the two lines as
 * subordinate to the name, which is the reading order the law is about. What
 * they look like is the template's business (§ VII.6.10).
 */
.ostia-checkout__label {
	min-width: 0;
}

/* Only in the item rows. The totals, the delivery line and the payment line
   carry one text node each, and turning those into columns would be a change
   with no reason behind it. */
.ostia-checkout__item .ostia-checkout__label {
	display: flex;
	flex-direction: column;
}

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

.ostia-checkout__options,
.ostia-checkout__sku {
	font-size: .875em;
	min-width: 0;
}

.ostia-checkout__value {
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.ostia-checkout__line--discount,
.ostia-checkout__line--shipping,
.ostia-checkout__line--net,
.ostia-checkout__line--tax {
	/* Structure only. Which of them is emphasised is a control (§ VII.6.10);
	   what the stylesheet owes is that they all sit on one flow. */
	align-items: baseline;
}

.ostia-checkout__line--total {
	padding-top: .5rem;
}

.ostia-checkout__note {
	margin: 0;
	font-size: .875em;
}

.ostia-checkout__note--bad {
	font-weight: 600;
}

.ostia-checkout__legal {
	margin: 0;
}

.ostia-checkout__code {
	display: flex;
	flex-direction: column;
	gap: .25rem;
	min-width: 0;
}

/*
 * Die Bestellübersicht, wie die Zeichnung sie setzt: Kopfzeile mit dem Weg
 * zurück, Vorschau mit Mengenmarke, Betrag auf dem Knopf.
 *
 * Geometrie, wie überall in dieser Datei — welche Achse, wie breit die
 * Vorschau, wo die Marke sitzt. Farbe und Grösse setzt die Vorlage.
 */
.ostia-checkout__summary-head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	margin: 0 0 .75rem;
}

/* Der Weg zurück in den Warenkorb, an der rechten Kante der Kopfzeile.
   `flex: 0 0 auto`, damit er nicht schrumpft, wenn die Überschrift wächst. */
.ostia-checkout__change {
	flex: 0 0 auto;
}

/* Der Block der Versandarten. Wie jeder andere `__block` eine Spalte — die
   Regel steht getrennt, weil eine Klasse ohne eigene Regel eine Klasse ist,
   die niemand stylen kann, und `CheckoutClassGuardTest` das prüft. */
.ostia-checkout__delivery {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.ostia-checkout__item {
	align-items: flex-start;
	padding: .375rem 0;
}

/*
 * AUSNAHME 6 — DIE VERGRIFFENE POSITION, und sie steht hier aus demselben
 * Grund wie Ausnahme 3: ein Zustand muss wahrnehmbar sein, bevor irgendeine
 * Vorlage gestaltet wurde. Blatt „Fehler" legt das Bild auf 55 % Deckung; die
 * Durchstreichung des Namens ist ein Regler (`co_item_removed`), die Deckung
 * eines Bildes ist keine Farbe und kein Schriftwert — sie steht hier.
 */
.ostia-checkout__item--removed img {
	opacity: .55;
}

/* Der Hinweis über der Positionsliste — Titel und Satz untereinander, wie die
   Fehlermeldung. Fläche, Kante und Farbe setzt der Regler `co_notice`. */
.ostia-checkout__notice {
	display: flex;
	flex-direction: column;
	gap: .3125rem;
	min-width: 0;
}

.ostia-checkout__notice-title,
.ostia-checkout__notice-text {
	min-width: 0;
}

.ostia-checkout__thumb {
	position: relative;
	flex: 0 0 auto;
	margin-right: .75rem;
}

.ostia-checkout__thumb img {
	display: block;
	width: 58px;
	height: auto;
	aspect-ratio: 3 / 4;
	object-fit: cover;
}

/* Die Menge sitzt AUF der Vorschau, nicht vor dem Namen: „2 × Schultertasche
   Mira" liest sich als Teil des Titels, und in einer Liste aus drei Zeilen
   sucht das Auge die Zahl dann im Text statt am Bild. */
.ostia-checkout__badge {
	position: absolute;
	top: -6px;
	right: -6px;
	/* 18 × 18, wie gezeichnet — 22 waren sichtbar zu gross. */
	min-width: 1.125rem;
	height: 1.125rem;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	font-size: .75rem;
	font-variant-numeric: tabular-nums;
}

/*
 * VERSANDART: NAME UND ZEITPUNKT UNTEREINANDER, DER PREIS DANEBEN.
 *
 * Hier stand eine Zeile aus drei Teilen mit `align-items: baseline`. Die
 * Zeichnung setzt den Zeitpunkt UNTER den Namen — „Standard — Österreichische
 * Post · Dienstag, 8. September · kostenfrei" ist in einer Zeile eine
 * Aufzählung, in zwei Zeilen eine Karte mit Titel und Nebenzeile. Ein Raster
 * aus zwei Spalten macht beides ohne eine zweite Verschachtelung: Name und
 * Zeitpunkt in Spalte 1, der Preis in Spalte 2 auf der Zeile des Namens.
 *
 * NACH `.ostia-field--choice label` und nicht davor: beide Wähler sind gleich
 * spezifisch, also entscheidet die Reihenfolge, wessen `display` gilt.
 */
.ostia-checkout__ship label,
.ostia-checkout__pay label {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	column-gap: .75rem;
	align-items: baseline;
	width: 100%;
}

.ostia-checkout__ship-name,
.ostia-checkout__pay-name {
	grid-column: 1;
	min-width: 0;
}

/* Die Nebenzeile der Karte — Zustelltag, Zahlungsziel. Blatt „Kasse" gibt
   jeder Zahlungsart eine („14 Tage Zahlungsziel, auch beim ersten Kauf"),
   und sie kommt als `description` mit der Zahlungsart vom Server. */
.ostia-checkout__ship-when,
.ostia-checkout__pay-when {
	grid-column: 1;
	font-size: .875em;
}

.ostia-checkout__ship-price {
	grid-column: 2;
	grid-row: 1;
	font-variant-numeric: tabular-nums;
}

/* „kostenfrei" in der Karte und in der Summenzeile: ein Modifikator, damit
   der Regler `co_free_color` ihm die Farbe einer Zusage geben kann. */
.ostia-checkout__ship-price--free,
.ostia-checkout__value--free {
	min-width: 0;
}

/* Die Zahlungskarte selbst — wie `__ship` eine Spalte des Blocks. */
.ostia-checkout__pay {
	min-width: 0;
}

/* Der Betrag auf dem Knopf, an dessen rechter Kante. */
.ostia-checkout__submit {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: .5rem;
}

.ostia-checkout__submit-total {
	font-variant-numeric: tabular-nums;
}

.ostia-checkout__after {
	margin: .5rem 0 0;
	font-size: .8125em;
}

.ostia-checkout__submit {
	align-self: var(--ostia-checkout-submit-align, stretch);
	cursor: pointer;
	min-height: 2.75rem;
}

.ostia-checkout__submit[disabled] {
	cursor: not-allowed;
}

/* ── The states (§ VII.6.7, § VII.6.9) ──────────────────────────────────── */

.ostia-checkout__errors {
	margin: 0;
}

/*
 * DIE MELDUNG IST EIN STAPEL AUS ZWEI SÄTZEN, und der zweite ist der wichtige.
 *
 * Blatt `Fehler.dc.html`: die Überschrift sagt, WAS passiert ist, die Zeile
 * darunter, dass kein Geld geflossen ist. Zwei Blöcke untereinander, sonst
 * laufen sie zu einem Absatz zusammen und der zweite Satz verschwindet im
 * ersten — genau die Stelle, an der jemand anruft oder ein zweites Mal bucht.
 */
.ostia-checkout__error {
	display: flex;
	flex-direction: column;
	gap: .375rem;
	margin: 0;
	min-width: 0;
}

.ostia-checkout__error-title,
.ostia-checkout__error-text,
.ostia-checkout__error-safe,
.ostia-checkout__error-ref {
	min-width: 0;
}

/* Die zwei Wege aus der Meldung heraus: nebeneinander, mit Umbruch, und beide
   mindestens 44 px hoch (WCAG 2.2 SC 2.5.5). Farbe, Rahmen und Polster sind
   die Regler `co_retry` und `co_error_cart`. */
.ostia-checkout__error-actions {
	display: flex;
	flex-wrap: wrap;
	gap: .75rem;
	min-width: 0;
}

.ostia-checkout__retry,
.ostia-checkout__error-cart {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 2.75rem;
	cursor: pointer;
}

/* The checkout saying it cannot take an order at all. `currentColor` so a
   theme's ink carries the bar and we ship no palette — the same exception
   `storefront.css` already makes for the variant picker's state. */
.ostia-checkout__blocked {
	margin: 0;
	padding: .75rem 1rem;
	border-left: 3px solid currentColor;
}

.ostia-checkout__errors-title {
	margin: 0;
}

.ostia-checkout__errors-list {
	margin: .25rem 0 0;
	padding-inline-start: 1.25rem;
}

.ostia-checkout--empty,
.ostia-checkout--done {
	display: flex;
	flex-direction: column;
	gap: .5rem;
}

/*
 * DER GEZEICHNETE LEERZUSTAND STEHT IN DER VORLAGE, und die Insel zeigt ihn.
 *
 * Er beginnt mit `hidden` im Markup und wird von `checkout.js` aufgedeckt,
 * sobald die Sitzung sagt, dass der Korb leer ist — nicht über `data-ostia-if`,
 * dessen Effekt vor der Antwort entscheidet und den Kasten über jedem vollen
 * Korb für die Dauer der Anfrage aufblitzen liesse. Elementors Container setzt
 * `display` selbst, darum verliert das `[hidden]` des Browsers gegen ihn und
 * braucht diese Zeile — dieselbe, die `storefront.css` für `data-ostia-if`
 * schreibt.
 */
[data-ostia-checkout-empty][hidden] {
	display: none !important;
}

.ostia-checkout__number {
	margin: 0;
	font-variant-numeric: tabular-nums;
}

.ostia-checkout__instructions {
	margin: 0;
	/* An IBAN copies cleanly only if the line breaks the way it was written. */
	white-space: pre-wrap;
	font-family: inherit;
}

/* ── The bar at the foot of a narrow window (§ VII.6.1) ─────────────────── */

/*
 * It carries the total and a way to reach the button. IT DOES NOT ORDER: the
 * ordering button exists exactly once in the document, in the summary, with the
 * positions above it — which is what § 312j Abs. 2 BGB is about, and a bar at
 * the foot of the window has nothing above it.
 *
 * `position: sticky` and not `fixed`: it belongs to the checkout, so it must
 * leave with it. A fixed bar outlives the form it belongs to on a page that
 * scrolls past the widget.
 */
.ostia-checkout__sticky {
	position: sticky;
	bottom: 0;
	z-index: 1;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: .75rem;
	margin: 0;
	padding: var(--ostia-checkout-sticky-padding, .75rem 0);
	/* Exception 4 — see the head of this file. System colours rather than a
	   choice of ours: they follow the reader's own light or dark setting, and
	   both are behind a property a control can overwrite. */
	background: var(--ostia-checkout-sticky-bg, Canvas);
	color: var(--ostia-checkout-sticky-fg, CanvasText);
}

.ostia-checkout__sticky-total {
	display: flex;
	align-items: baseline;
	gap: .5rem;
	min-width: 0;
}

.ostia-checkout__sticky-button {
	flex: 0 0 auto;
	min-height: 2.75rem;
	cursor: pointer;
}

/*
 * AND IT STANDS DOWN WHERE THE SUMMARY IS ALREADY BESIDE THE FORM.
 *
 * AFTER the rules above and not in the `@container` block at the top of this
 * file, and that placement is the whole of it: a container query adds no
 * specificity, so `display: none` written earlier loses to `display: flex`
 * written later. Measured 2026-08-31 on the shop's own checkout page — 1.196 px
 * of container at 1.920 px of window, two columns, sticky summary AND the
 * closing bar still at the foot. It looked deliberate. The same run reported
 * green at 1.366 px only because the quote had not arrived yet and the bar was
 * not in the DOM at all, which is the sort of pass that hides the next one.
 */
@container ostia-checkout (min-width: 48rem) {
	.ostia-checkout__sticky {
		display: none;
	}
}
