/*
 * ChurchTools Events – frontend styles for all three layouts (list/grid/upcoming).
 * Scoped entirely under .ctp-events so it never leaks into the surrounding theme.
 * Colors/radius/surface pull from the active theme's Global Styles (theme.json)
 * where available, with plain fallbacks for classic themes that don't define them.
 */

.ctp-events {
    --ctp-accent: var(--wp--preset--color--primary, #2563eb);
    --ctp-color-text: inherit;
    --ctp-color-muted: color-mix(in srgb, currentColor 64%, transparent);
    --ctp-color-surface: var(--wp--preset--color--base, #fdfbf8);
    --ctp-color-border: color-mix(in srgb, currentColor 12%, transparent);
    --ctp-radius: var(--wp--custom--ctp--radius, 14px);
    /* Radius for the fully rounded bits (calendar/all-day badges, eventfinder
       buttons, the popup's close button). Its own variable rather than a
       hard-coded 999px so the Design tab's "Eckig" setting reaches them too:
       CardDesign::cssVariables() flattens both radius variables at once, which
       a calc() off --ctp-radius alone can't express ("pill, unless square"). */
    --ctp-radius-pill: 999px;

    /*
     * Interactive chrome (eventfinder buttons, "load more", the popup's close
     * button) draws from its own tokens rather than --ctp-accent. --ctp-accent
     * is a *calendar's* identity color — every card, item and hero re-sets it
     * inline from the calendar's configured color — so wiring the controls to
     * it meant a site could not restyle its buttons without also recoloring
     * the calendar badges, and vice versa. Defaults are deliberately neutral
     * (surface with a hairline, inverting to ink on hover/selected), which
     * drops into most site designs unchanged; a theme overrides these five
     * without touching anything else.
     */
    /* Weiss statt Kachelgrund, und der Rand in der eingestellten Buttonfarbe
       (--ctp-color-button-strong) statt in einem grauen Haarstrich: Der Knopf
       soll sich als Bedienelement zu erkennen geben, ohne gefuellt zu sein -
       gefuellt ist er erst im gewaehlten Zustand. */
    --ctp-color-button: #fff;
    --ctp-color-button-text: var(--wp--preset--color--contrast, #111827);
    --ctp-color-button-border: var(--ctp-color-button-strong);
    --ctp-color-button-strong: var(--wp--preset--color--contrast, #111827);
    --ctp-color-button-strong-text: var(--ctp-color-surface);
    --ctp-gap: clamp(1.35rem, 1.6vw + 0.7rem, 2.4rem);
    /* Two-layer shadow: a faint contact shadow plus a soft, warm-tinted
       ambient one — restrained rather than heavy, so cards read with a
       touch of lift without dominating the page. */
    --ctp-shadow: 0 1px 3px color-mix(in srgb, currentColor 7%, transparent),
        0 20px 40px -22px color-mix(in srgb, #8a6a3a 30%, transparent);
    --ctp-columns: 3;
    /* Floor for a single grid card — see .ctp-events--grid .ctp-events__list
       below for how it's combined with --ctp-columns. */
    --ctp-card-min: 240px;

    /*
     * Fallbacks only — real values come from the inline style each template
     * sets from CardDesign::styleAttribute() (see EventListRenderer::render()).
     * These just keep behavior sane for a cached page rendered by an older
     * plugin version, or a theme override template that doesn't emit
     * $args['design_style']. Values match CardDesign::DEFAULT_ORDER: media,
     * then calendar/title/subtitle/excerpt/date/time/location as the content
     * block.
     */
    --ctp-order-media: 0;
    --ctp-order-content: 1;
    --ctp-order-calendar: 1;
    --ctp-order-title: 2;
    --ctp-order-subtitle: 3;
    --ctp-order-excerpt: 4;
    --ctp-order-date: 5;
    --ctp-order-time: 6;
    --ctp-order-location: 7;

    /*
     * One type scale for everything the component renders. Every text element
     * below picks a step from it instead of inheriting the theme's body size,
     * which is what used to drive card and popup apart: the cards carried
     * explicit rem sizes while the popup's description carried none, so on a
     * theme with a 21px body font the popup text came out half again as large
     * as the card text it was opened from. The same mismatch made list-layout
     * titles (unsized, theme-driven) larger than grid-card titles (1.08rem)
     * and left the month divider smaller than either.
     *
     * All steps derive from --ctp-font-base, so a site that wants the whole
     * component bigger or smaller overrides that one value rather than
     * re-tuning a dozen rules.
     */
    --ctp-font-base: 1rem;
    --ctp-font-2xs: calc(var(--ctp-font-base) * 0.7);
    --ctp-font-xs: calc(var(--ctp-font-base) * 0.78);
    --ctp-font-sm: calc(var(--ctp-font-base) * 0.875);
    --ctp-font-md: var(--ctp-font-base);
    --ctp-font-lg: calc(var(--ctp-font-base) * 1.125);
    --ctp-font-xl: calc(var(--ctp-font-base) * 1.375);
    --ctp-font-2xl: calc(var(--ctp-font-base) * 2);
    /* Eine Groesse fuer alle Schaltflaechen des Plugins. Bewusst zwischen sm
       und md: Die Knoepfe des Eventfinders standen auf sm und wirkten fuer
       eine Reihe von Bedienelementen zu klein, „Weitere Termine laden“ erbte
       md und war daneben zu gross - beides dieselbe Sorte Knopf, also
       dieselbe Groesse. */
    --ctp-font-control: calc(var(--ctp-font-base) * 0.94);

    color: var(--ctp-color-text);
    font-size: var(--ctp-font-md);
    line-height: 1.5;
}

.ctp-events__empty {
    color: var(--ctp-color-muted);
    font-style: italic;
}

/* ---------- toolbar: search + calendar filter (list/grid layouts only, both opt-in — see EventListRenderer::render()) ---------- */

.ctp-events__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.85rem;
    margin-block-end: var(--ctp-gap);
}

.ctp-events__search {
    position: relative;
    flex: 1 1 16rem;
    min-width: 12rem;
    display: flex;
    align-items: center;
}

/* Im Eventfinder steht das Suchfeld als eigener Abschnitt unter den
   Knopfreihen - ueber die volle Breite gezogen waere es das breiteste Element
   einer sonst mittigen Werkzeugleiste. */
.ctp-events__eventfinder .ctp-events__search {
    width: min(100%, 26rem);
    flex: 0 1 auto;
    align-self: center;
}

.ctp-events__search .ctp-events__icon {
    position: absolute;
    left: 0.85rem;
    width: 1rem;
    height: 1rem;
    color: var(--ctp-color-muted);
    pointer-events: none;
}

.ctp-events__search-input {
    width: 100%;
    padding: 0.55rem 0.95rem 0.55rem 2.4rem;
    border: 1px solid var(--ctp-color-border);
    border-radius: calc(var(--ctp-radius) * 0.6);
    background-color: var(--ctp-color-surface);
    color: var(--ctp-color-text);
    font: inherit;
}

/* Firefox/WebKit both add their own reset-icon/clear-button before
 * :focus-visible is even reachable there — unset so the two native search
 * decorations (an extra magnifier glyph, an X clear button) don't collide
 * with the custom icon and padding above. */
.ctp-events__search-input::-webkit-search-decoration,
.ctp-events__search-input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

.ctp-events__filter {
    padding: 0.55rem 2.1rem 0.55rem 0.95rem;
    border: 1px solid var(--ctp-color-border);
    border-radius: calc(var(--ctp-radius) * 0.6);
    background-color: var(--ctp-color-surface);
    color: var(--ctp-color-text);
    font: inherit;
    cursor: pointer;
}

.ctp-events__filter:focus-visible,
.ctp-events__search-input:focus-visible {
    outline: 2px solid var(--ctp-accent);
    outline-offset: 1px;
}

.ctp-events__toolbar-empty {
    flex-basis: 100%;
    margin: 0;
    color: var(--ctp-color-muted);
    font-style: italic;
}

/* ---------- eventfinder: gefuehrte Werkzeugleiste, ersetzt die einfache
   filter/search toolbar above when opted into (list/grid layouts only, see
   EventListRenderer::render()) ---------- */

.ctp-events__eventfinder {
    /* Spalte statt der Zeile mit Umbruch, die .ctp-events__toolbar vorgibt: Hier
       liegen die Reihen uebereinander, sie sind keine Elemente derselben Zeile. */
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    /*
     * Riegel gegen waagerechten Ueberlauf. Die Themenleiste darunter ist auf
     * schmalen Schirmen breiter als der Schirm - sie *soll* scrollen. Fehlt an
     * irgendeiner Stelle dieser Kette die Erlaubnis zu schrumpfen, dehnt sie
     * stattdessen ihre Vorfahren, und dann wird die ganze Seite an dieser einen
     * Stelle breit, waehrend alles andere in Handybreite steht. Genau so ist es
     * gemeldet worden. Die drei Zeilen kosten nichts und schliessen den Fall an
     * der Wurzel aus, statt ihn eine Ebene tiefer zu reparieren.
     */
    min-width: 0;
    max-width: 100%;
    overflow-x: clip;
}

/*
 * Mittig ausgerichtet, wie „Weitere Termine laden“ unter der Liste (siehe
 * .ctp-events__more): Beides sind Bedienelemente, die zur Liste gehoeren und
 * nicht zu ihr gehoerender Text - links buendig standen sie in der Spalte wie
 * ein weiterer Absatz.
 *
 * Zentriert werden die Inhalte der Abschnitte, nicht die Abschnitte selbst:
 * Die Trennlinie zwischen „Thema“ und „Zeitraum“ soll weiterhin ueber die
 * ganze Breite laufen und nicht auf die Breite ihrer Knoepfe schrumpfen.
 */
.ctp-events__finder-label {
    margin: 0 0 0.9rem;
    font-size: var(--ctp-font-lg);
    font-weight: 700;
    text-align: center;
}

/*
 * Eine Reihe je Filterdimension. Die Trennlinie zwischen ihnen ist am
 * 2026-09-02 weggefallen: Seit die Ueberschriften „Thema" und „Zeitraum" weg
 * sind und der Zeitraum in einem Segmentschalter sitzt, sind das nicht mehr
 * drei beschriftete Abschnitte, sondern eine Bedienleiste - und in einer
 * Bedienleiste trennt der Abstand, nicht der Strich. Das Suchfeld darunter
 * behaelt seine Linie: Es ist eine andere Art von Eingabe.
 */
.ctp-events__finder-row {
    /* Spalte, damit die Ueberschrift eine eigene Zeile bekommt und ihre Knoepfe
       auf der naechsten beginnen. */
    display: flex;
    flex-direction: column;
    align-items: center;
    /*
     * Feste Breite statt inhaltsabhaengiger - und zwar auf *jeder* Ebene dieser
     * Kette (Reihe, Leiste, Gruppe) und bei jeder Fensterbreite.
     *
     * Ohne sie bemisst sich jedes dieser Elemente an seinem Inhalt, und eine
     * nicht umbrechende Knopfreihe ist breiter als jeder Bildschirm. Drei vom
     * Nutzer gemeldete Fehler kamen daher: Das Raster der Themen fiel auf dem
     * Desktop auf eine Spalte zusammen (ein Raster ohne definierte Breite kennt
     * keine Spaltenzahl), die zentrierte Ueberschrift wurde in einem viel zu
     * breiten Kasten zentriert und hing dadurch rechts am Rand, und der
     * Blaetterknopf blieb aus, weil das Skript in diesem Kasten mass, dass
     * rechts nichts fehle.
     */
    width: 100%;
    min-width: 0;
    max-width: 100%;
    gap: 0.55rem;
    margin-block-start: 0.95rem;
}

/*
 * Die Zeitraum-Reihe traegt ihre Trennung allein in der Ueberschrift. Eine Linie
 * stand hier zwischenzeitlich zusaetzlich und ist auf Nutzerentscheidung wieder
 * gefallen (2026-09-02): Das Wort genuegt, und ohne den Strich liest sich der
 * Eventfinder als eine Leiste statt als zwei gestapelte Kaesten.
 */
.ctp-events__finder-row--timeframe {
    padding-block-start: 0.35rem;
}

.ctp-events__finder-row:first-of-type {
    margin-block-start: 0;
}

.ctp-events__finder-row-label {
    font-size: var(--ctp-font-md);
    font-weight: 700;
    color: var(--ctp-color-text);
}

.ctp-events__finder-group {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    min-width: 0;
    max-width: 100%;
    /*
     * Zentriert die Gruppe selbst, nicht nur ihren Inhalt. Klingt doppelt
     * gemoppelt neben `justify-content: center`, ist es aber nicht: Sobald die
     * Layout-Routine die Reihe verengt, um den einzelnen Knopf in der letzten
     * Zeile zu vermeiden (siehe assets/js/frontend.js), ist die Gruppe schmaler
     * als die Leiste - und sass ohne diese Zeile linksbuendig darin. Der ganze
     * Knopfblock stand dann sichtbar neben der Mitte, waehrend die Ueberschrift
     * darueber mittig blieb.
     */
    margin-inline: auto;
}

/*
 * Die Leiste, in der eine Knopfreihe liegt: Sie traegt den Blaetterknopf und den
 * Verlauf am rechten Rand und muss dafuer der Bezugspunkt ihrer Lage sein.
 */
.ctp-events__finder-strip {
    position: relative;
    display: flex;
    width: 100%;
    max-width: 100%;
    /*
     * Ohne diese Zeile sprengt die Leiste ihren Container. Ein Flex-Element hat
     * `min-width: auto` und wird damit nie schmaler als sein Inhalt - die
     * zwoelf Themenknoepfe in einer nicht umbrechenden Reihe sind aber breiter
     * als jeder Bildschirm. Die Folge war beim Nachmessen sichtbar: Der ganze
     * Eventfinder wurde breiter als das Fenster, der Segmentschalter darunter
     * (Breite 100 % eines zu breiten Elternteils) lief rechts aus dem Bild, und
     * der Blaetterknopf sass am rechten Rand einer Leiste, die es gar nicht auf
     * den Schirm schaffte.
     */
    min-width: 0;
}

/*
 * Der Blaetterknopf sitzt am rechten Rand *ueber* der Leiste. Er ist rund und
 * gefuellt, damit er nicht wie ein weiterer Themenknopf aussieht, und er
 * erscheint nur, wenn tatsaechlich noch etwas folgt - das entscheidet
 * assets/js/frontend.js, weil CSS es nicht wissen kann.
 */
/*
 * Die Pfeile in den Verlaeufen. Der Verlauf allein war zu leise - gemeldet war,
 * dass nicht zu erkennen ist, dass sich die Reihe schieben laesst. Ein
 * gefuelltes Zeichen darin sagt es unmissverstaendlich und ist zugleich der Weg
 * fuer alle, die nicht wischen.
 *
 * Die Ecken kommen aus dem Design-Reiter: --ctp-radius-pill ist der Radius, den
 * CardDesign::cssVariables() bei der Einstellung „Eckig" flach zieht. Ein festes
 * `border-radius: 50%` stand hier zuerst und war falsch - der Knopf blieb rund,
 * waehrend ringsum alles eckig wurde.
 *
 * `z-index`, weil der Verlauf als ::after des Elternteils *nach* den Knoepfen
 * gemalt wird und sie sonst ueberzoege.
 */
.ctp-events__finder-scroll {
    position: absolute;
    z-index: 1;
    inset-block-start: 50%;
    translate: 0 -50%;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    padding: 0 0 0.12em;
    border: 1px solid var(--ctp-color-button-strong);
    border-radius: var(--ctp-radius-pill);
    background-color: var(--ctp-color-button-strong);
    color: var(--ctp-color-button-strong-text);
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
}

.ctp-events__finder-scroll--next {
    inset-inline-end: 0;
}

.ctp-events__finder-scroll--prev {
    inset-inline-start: 0;
}

.ctp-events__finder-scroll:hover {
    background-color: color-mix(in srgb, var(--ctp-color-button-strong) 82%, #fff);
}

.ctp-events__finder-scroll:focus-visible {
    outline: 2px solid var(--ctp-accent);
    outline-offset: 1px;
}

/*
 * Schiebemodus. Ob eine Knopfreihe umbricht oder seitlich geschoben wird,
 * entscheidet nicht mehr eine Fensterbreite, sondern das Ergebnis des Umbruchs
 * selbst: Ab drei Zeilen schaltet assets/js/frontend.js hier um
 * (Nutzerentscheidung 2026-09-02). Eine feste Schwelle wie „unter 782 Pixel"
 * ging daran vorbei - mit vier Kategorien bricht auf einem Handy gar nichts um,
 * mit zwanzig auf einem breiten Schirm sehr wohl.
 *
 * Dass diese Entscheidung an JavaScript haengt, kostet nichts: Ohne Skript
 * filtern die Knoepfe ohnehin nicht, der Eventfinder ist dann als Ganzes
 * wirkungslos.
 */
.ctp-events__finder-strip--scroll .ctp-events__finder-group {
    flex-wrap: nowrap;
    /*
     * Mittig, solange der Inhalt passt - und das geht ueber die Breite, nicht
     * ueber `justify-content: center`: Ein zentrierter Flex-Container, der
     * ueberlaeuft, schneidet am Anfang ab, und der erste Knopf waere nicht mehr
     * erreichbar. Mit `width: auto` schrumpft die Gruppe stattdessen auf ihren
     * Inhalt und wird von den automatischen Aussenabstaenden zentriert; laeuft
     * sie ueber, fuellt sie die Breite und schiebt von links.
     */
    width: auto;
    margin-inline: auto;
    justify-content: flex-start;
    overflow-x: auto;
    /* Damit der Fokusring des ersten Knopfes nicht abgeschnitten wird -
       overflow-x erzwingt overflow-y: auto. */
    padding-block: 2px;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

.ctp-events__finder-strip--scroll .ctp-events__finder-group::-webkit-scrollbar {
    display: none;
}

/* Ohne diese Zeile schrumpfen die Knoepfe, statt ueberzulaufen - flex-shrink
   steht standardmaessig auf 1, und eine Leiste aus zerquetschten Knoepfen waere
   kein Fortschritt. */
.ctp-events__finder-strip--scroll .ctp-events__finder-btn {
    flex: 0 0 auto;
    scroll-snap-align: start;
}

/*
 * Ueberschriften und Knopfreihen stehen mittig, auf jeder Breite - es gibt hier
 * keine Ausnahme fuer schmale Schirme mehr (Nutzerentscheidung 2026-09-02:
 * „Immer mittig/zentriert"). Zwei Fassungen davor lagen daneben: Zuerst hing
 * die Ausrichtung am Schiebemodus, und seit die Zeitraum-Reihe immer schiebt,
 * traf das immer zu - der ganze Block wurde auch auf dem Desktop linksbuendig.
 * Danach stand hier eine Medienabfrage, die schmale Schirme linksbuendig
 * setzte; auch die ist weg.
 *
 * Eine Leiste, die *ueberlaeuft*, beginnt trotzdem links - anders geht es
 * nicht, ein zentrierter Scrollbereich schneidet seinen Anfang ab. Sichtbar
 * wird der Unterschied nur dort, wo ohnehin geschoben wird.
 */

/*
 * Die Verlaeufe an den Raendern sagen „hier geht es weiter". Sie gehoeren zum
 * Schiebemodus und verschwinden am jeweiligen Anschlag, weil dort nichts mehr
 * liegt - welcher Anschlag erreicht ist, traegt das Skript als Klasse ein.
 */
.ctp-events__finder-strip--scroll::before,
.ctp-events__finder-strip--scroll::after {
    content: '';
    position: absolute;
    inset-block: 0;
    width: 4.5rem;
    pointer-events: none;
    transition: opacity 0.15s ease;
}

.ctp-events__finder-strip--scroll::after {
    inset-inline-end: 0;
    background: linear-gradient(to right, transparent, var(--ctp-color-surface) 55%);
}

.ctp-events__finder-strip--scroll::before {
    inset-inline-start: 0;
    background: linear-gradient(to left, transparent, var(--ctp-color-surface) 55%);
}

.ctp-events__finder-strip--end::after,
.ctp-events__finder-strip--start::before {
    opacity: 0;
}

/* Column direction again: flex-basis is a *height* here, so the plain
   toolbar's "take the whole row" basis has to go, and the message needs its
   own top margin instead of the row gap it used to sit in. */
.ctp-events__eventfinder .ctp-events__toolbar-empty {
    flex-basis: auto;
    margin-block-start: 0.6rem;
}

/* The search field is the eventfinder's third section, so it gets the same
   separator and spacing as the two button rows above it. The flex shorthand
   .ctp-events__search carries for the plain toolbar has to be undone here:
   in this column-direction parent its 16rem basis would be read as a *height*
   and open a large gap under the buttons. */
.ctp-events__eventfinder .ctp-events__search {
    flex: 0 0 auto;
    margin-block-start: 0.95rem;
    padding-block-start: 0.95rem;
    border-block-start: 1px solid var(--ctp-color-border);
}

/* Versalien fuer beide Schaltflaechen des Plugins (Eventfinder-Knoepfe und
   "Weitere Termine laden"): dieselbe Auszeichnung, die .ctp-events__eyebrow,
   .ctp-events__more-label und der Monatstrenner schon tragen - und die
   Schaltflaechen des Themes auf der Live-Seite ebenso. Die Sperrung dazu, weil
   Versalien ohne sie eng wirken. Nicht auf .ctp-events__card-trigger: das ist
   der Titel des Termins in Knopfform, kein Bedienelement mit eigenem Wort. */
.ctp-events__finder-btn {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.45rem 1.05rem;
    border: 1px solid var(--ctp-color-button-border);
    border-radius: var(--ctp-radius-pill);
    background-color: var(--ctp-color-button);
    color: var(--ctp-color-button-text);
    font: inherit;
    font-size: var(--ctp-font-control);
    font-weight: 600;
    line-height: 1.35;
    cursor: pointer;
    /*
     * Nie ein Umbruch im Knopf. Ein Raster aus gleich breiten Spalten stand
     * hier kurz und ist verworfen: Es loeste zwar den einzelnen Knopf in der
     * letzten Zeile, zwang aber lange Beschriftungen in zwei Zeilen, sobald die
     * Spalten schmal wurden. Ungleich breite Knoepfe mit einzeiligem Text lesen
     * sich besser als gleich breite mit umgebrochenem (Nutzerentscheidung
     * 2026-09-02).
     */
    white-space: nowrap;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/*
 * Leichte Fuellung statt Randfaerbung: Der Rand traegt seit dem Umstellen auf
 * weisse Knoepfe schon die Buttonfarbe, ein Hover, der nur ihn einfaerbt,
 * waere ohne Wirkung geblieben. Der gewaehlte Zustand bleibt die volle
 * Fuellung, der Unterschied zwischen „darueber“ und „gewaehlt“ also deutlich.
 */
.ctp-events__finder-btn:hover {
    background-color: color-mix(in srgb, var(--ctp-color-button-strong) 8%, var(--ctp-color-button));
}

/* Focus rings stay on --ctp-accent rather than the button tokens: the filled
   state below is the button tokens' own strong color, and a ring in that same
   color would be invisible exactly when a keyboard user needs it most. */
.ctp-events__finder-btn:focus-visible {
    outline: 2px solid var(--ctp-accent);
    outline-offset: 1px;
}

.ctp-events__finder-btn--active {
    border-color: var(--ctp-color-button-strong);
    background-color: var(--ctp-color-button-strong);
    color: var(--ctp-color-button-strong-text);
}

/*
 * Die Themen-Knoepfe tragen die Farbe ihres Kalenders (das Markup setzt sie je
 * Knopf als --ctp-accent, siehe partials/eventfinder.php). Ein Knopf hier hat
 * damit dieselbe Farbe wie die Kategorie an den Terminen darunter - man findet
 * das Gesuchte im Ergebnis wieder, statt vor einer Reihe gleich aussehender
 * Knoepfe zu stehen. „Alle“ bleibt neutral, es steht fuer keinen Kalender.
 */
.ctp-events__finder-btn--calendar {
    border-color: color-mix(in srgb, var(--ctp-accent) 55%, transparent);
    color: var(--ctp-accent);
}

.ctp-events__finder-btn--calendar:hover {
    border-color: var(--ctp-accent);
    background-color: color-mix(in srgb, var(--ctp-accent) 10%, var(--ctp-color-button));
}

.ctp-events__finder-btn--calendar.ctp-events__finder-btn--active {
    border-color: var(--ctp-accent);
    background-color: var(--ctp-accent);
    color: var(--ctp-color-surface);
}

/* ---------- "load more" paging (list/grid layouts, see partials/load-more.php) ---------- */

.ctp-events__more {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    margin-block-start: var(--ctp-gap);
}

/* Outlined rather than filled: the button sits directly under the last card and
   a solid block there would out-shout the content it belongs to. Inverts to the
   filled "strong" pair on hover, same two-state behavior as the eventfinder
   buttons and the popup's close button. */
.ctp-events__load-more {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.7rem 1.6rem;
    border: 1px solid var(--ctp-color-button-border);
    border-radius: calc(var(--ctp-radius) * 0.6);
    background-color: var(--ctp-color-button);
    color: var(--ctp-color-button-text);
    font: inherit;
    font-size: var(--ctp-font-control);
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.ctp-events__load-more:hover {
    border-color: var(--ctp-color-button-strong);
    background-color: var(--ctp-color-button-strong);
    color: var(--ctp-color-button-strong-text);
}

.ctp-events__load-more:focus-visible {
    outline: 2px solid var(--ctp-accent);
    outline-offset: 2px;
}

/* Only styles the in-flight state; the label stays put (no spinner, no text
   swap) so the button doesn't jump around while a page is loading. */
.ctp-events__load-more[aria-busy='true'] {
    cursor: progress;
    opacity: 0.6;
}

.ctp-events__load-more:disabled {
    cursor: default;
}

.ctp-events__more-error {
    margin: 0;
    color: var(--ctp-color-muted);
    font-size: var(--ctp-font-sm);
}

/* ---------- month dividers (list/grid layouts only, opt-in — see EventFormatter::monthLabel()) ---------- */

/* Sized as a section label rather than a heading that competes with the card
   titles under it: one step below them (--ctp-font-md vs --ctp-font-lg), but
   uppercase and letter-spaced so it still reads as a grouping marker — same
   idiom .ctp-events__eyebrow and .ctp-events__more-label already use.
   Die Grid-Ansicht weicht davon ab, siehe unten. */
.ctp-events__month-divider {
    margin-block: calc(var(--ctp-gap) * 0.7) calc(var(--ctp-gap) * 0.35);
    font-size: var(--ctp-font-md);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ctp-color-text);
}

.ctp-events__month-divider:first-child {
    margin-block-start: 0;
}

/*
 * Im Grid eine Stufe groesser als in der Liste (--ctp-font-lg statt -md).
 * Der Trenner steht dort nicht ueber einer schmalen Zeile, sondern ueber einer
 * kompletten Kachelreihe, die er per `grid-column: 1 / -1` in voller Breite
 * ueberspannt - auf dieser Breite und mit dem groesseren Abstand ringsum wirkte
 * die Listengroesse verloren statt zurueckhaltend. In der Liste bleibt es bei
 * --ctp-font-md: dort sitzt der Trenner direkt auf den Zeilen und wuerde bei
 * gleicher Groesse mit deren Titeln (ebenfalls --ctp-font-lg) konkurrieren.
 */
.ctp-events--grid .ctp-events__month-divider {
    grid-column: 1 / -1;
    font-size: var(--ctp-font-lg);
}

/*
 * Die Ueberleitung ueber dem Ausblick, wenn ein Zeitraum des Eventfinders leer
 * ausgeht (siehe partials/timeframe-outlook.php). Sie steht *anstelle* der
 * Treffer und muss sich deshalb absetzen, ohne selbst wie eine Kachel
 * auszusehen - kein Rahmen, keine Flaeche, nur Text.
 *
 * Der Grundsatz zurueckhaltend (--ctp-color-muted: es ist eine Absage), die
 * Ankuendigung darunter in derselben Form wie ein Monatstrenner - sie tut ja
 * dasselbe, sie ueberschreibt eine Gruppe von Kacheln.
 */
.ctp-events__outlook {
    margin-block: 0 calc(var(--ctp-gap) * 0.35);
}

.ctp-events--grid .ctp-events__outlook {
    grid-column: 1 / -1;
}

.ctp-events__outlook-notice {
    margin: 0;
    font-size: var(--ctp-font-md);
    color: var(--ctp-color-muted);
}

.ctp-events__outlook-heading {
    margin-block: calc(var(--ctp-gap) * 0.35) 0;
    font-size: var(--ctp-font-md);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ctp-color-text);
}

.ctp-events--grid .ctp-events__outlook-heading {
    font-size: var(--ctp-font-lg);
}

/*
 * Bewusst <div role="list"> statt <ul> und <div role="listitem"> statt <li>
 * (siehe die Templates). Das ist kein Geschmack, sondern das Ergebnis eines
 * verlorenen Spezifitaetskampfes: Uncode - das Theme auf der ersten
 * Live-Seite - formatiert jede Liste im Inhalt mit
 *
 *   .post-content ul:not(.no-list):not(.navigation):not(.pagination):not(…)
 *
 * und kommt ueber die sechs :not(.klasse) auf sieben Klassen Spezifitaet.
 * Dagegen gewinnt keine Regel dieses Plugins, die noch zu lesen waere: Vor
 * jeder Kachel stand ein Aufzaehlungspunkt, und die Liste war um 18px
 * eingerueckt. Zwei Anlaeufe haben das ueberschrieben statt abgestellt - ohne
 * <ul>/<li> greifen solche Theme-Regeln gar nicht erst, und zwar in jedem
 * Theme, nicht nur in diesem einen.
 *
 * Die Listen-Semantik bleibt ueber die role-Attribute erhalten. Die braucht es
 * hier ohnehin: Safari erkennt einer Liste mit display: grid oder flex die
 * Listenrolle ab, auch einer echten <ul>.
 */
.ctp-events__list {
    display: flex;
    flex-direction: column;
    gap: 0;
    margin: 0;
    padding: 0;
}

/*
 * Diese Liste ist seit 0.12.7 kein <ul> mehr - aber <ul>/<li> kann sie
 * trotzdem noch sein: in einer Seite, die im Cache eines Optimierungs-Plugins
 * liegt und noch aeltere Ausgabe ausliefert (auf der Live-Seite genau so passiert,
 * mit sichtbaren Aufzaehlungspunkten als Folge), oder in einem Theme, das ein
 * eigenes event-*.php mitbringt. Deshalb bleibt die Abschaltung stehen, auch
 * wenn sie fuer das eigene Markup ohne Wirkung ist. Ueber den Kindselektor,
 * damit Listen im Beschreibungstext ihre Punkte behalten.
 */
.ctp-events .ctp-events__list > * {
    list-style: none;
}

.ctp-events .ctp-events__list > *::marker {
    content: '';
}

.ctp-events__color-dot {
    display: inline-block;
    width: 0.5em;
    height: 0.5em;
    flex-shrink: 0;
    border-radius: 50%;
    background-color: var(--ctp-accent);
}

.ctp-events__icon {
    width: 1em;
    height: 1em;
    flex-shrink: 0;
}

/* Calendar name label (color dot + name) — a full member of the Design tab's
   reorderable element set (--ctp-order-calendar), same as title/subtitle/etc.
   Rendered as an outlined pill tinted in the calendar's own color rather than
   a plain text label, so each calendar still reads as a distinct badge —
   the color dot stays as extra reinforcement inside it. */
.ctp-events__eyebrow {
    order: var(--ctp-order-calendar);
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: 0.4rem;
    padding: 0.2rem 0.65rem;
    border-radius: var(--ctp-radius-pill);
    border: 1px solid color-mix(in srgb, var(--ctp-accent) 40%, transparent);
    background: color-mix(in srgb, var(--ctp-accent) 8%, transparent);
    color: var(--ctp-accent);
    font-size: var(--ctp-font-xs);
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* Description excerpt — likewise a full member of the reorderable set. */
.ctp-events__excerpt {
    order: var(--ctp-order-excerpt);
    margin: 0;
    color: var(--ctp-color-muted);
    font-size: var(--ctp-font-sm);
    line-height: 1.52;
    display: -webkit-box;
    overflow: hidden;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
}

/* Compact rows (list layout + the "further events" list in the upcoming
   layout) have much less room than a grid/hero card — clamp to a single line
   there instead of three. */
.ctp-events__item .ctp-events__excerpt {
    -webkit-line-clamp: 1;
}

/* Spacer/divider — decorative, admin-inserted elements (see
   CardDesign::renderSeparators()). Not part of the six fixed keys: there can
   be any number of them (or none), each with its visual position baked into
   an inline `order` style rather than one of the --ctp-order-* variables
   above, so these two rules only ever supply the *look*, never the position. */
.ctp-events__divider {
    width: 100%;
    margin: 0.15rem 0;
    border: none;
    border-block-start: 1px solid var(--ctp-color-border);
}

.ctp-events__spacer {
    display: block;
    flex: 0 0 auto;
    width: 100%;
    height: 0.75rem;
}

.ctp-events__badge {
    display: inline-flex;
    align-items: center;
    padding: 0.18em 0.6em;
    border-radius: var(--ctp-radius-pill);
    background: color-mix(in srgb, var(--ctp-accent) 14%, transparent);
    color: var(--ctp-accent);
    font-size: var(--ctp-font-2xs);
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

/* frontend.js toggles the native [hidden] attribute on filtered-out items and
 * empty month dividers (see updateMonthDividers()/applyToolbarState()) — the
 * browser's own "[hidden] { display: none }" UA rule normally handles that on
 * its own, but it's the *lowest*-priority origin in the cascade, so any
 * author rule that sets `display` on the same element (e.g. ".ctp-events__item
 * { display: flex }" below) silently wins and the item stays visible despite
 * being "hidden". Restated here as an author rule so it actually takes effect. */
.ctp-events [hidden] {
    display: none;
}

/* ---------- shared row pattern (list layout + the "further events" list in the upcoming layout) ---------- */

.ctp-events__item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 1.1rem;
    padding: 0.95rem 0.2rem;
    border-block-end: 1px solid var(--ctp-color-border);
}

.ctp-events__item:last-child {
    border-block-end: none;
}

.ctp-events__date-chip {
    order: var(--ctp-order-media);
    flex: 0 0 auto;
    width: 3.25rem;
    padding: 0.4rem 0;
    border-radius: calc(var(--ctp-radius) * 0.45);
    background: color-mix(in srgb, var(--ctp-accent) 10%, var(--ctp-color-surface));
    text-align: center;
    line-height: 1.1;
}

.ctp-events__day {
    display: block;
    font-size: var(--ctp-font-lg);
    font-weight: 700;
}

.ctp-events__date-badge .ctp-events__day {
    font-size: calc(var(--ctp-font-lg) * 1.1);
}

.ctp-events__month {
    display: block;
    font-size: var(--ctp-font-2xs);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    opacity: 0.8;
}

.ctp-events__body {
    order: var(--ctp-order-content);
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
}

/* 600 wie die Hero- und die Detail-Ueberschrift: Die drei sind dasselbe -
   der Name des Termins - und sahen in drei verschiedenen Staerken danach aus,
   als waeren sie es nicht. Den Rang untereinander macht der Schriftgrad. */
.ctp-events__title {
    order: var(--ctp-order-title);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    font-size: var(--ctp-font-lg);
    font-weight: 600;
    line-height: 1.3;
}

.ctp-events__subtitle {
    order: var(--ctp-order-subtitle);
    color: var(--ctp-color-muted);
    font-size: var(--ctp-font-sm);
}

/*
 * Date, time and location: one fact per line, each with its own icon, and each
 * its own placeable element in the Design tab (--ctp-order-date/-time/
 * -location). They used to be a single "meta" block with one drag handle and
 * one "20.08.2026 19:30–22:00" string, where the time was the part that got
 * lost. Identical formatting for all three by design — they are three parts of
 * the same statement, not a lead plus footnotes.
 */
.ctp-events__meta-item {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    /* The detail view renders these as <p> (the card layouts as <span>), so
       the theme's paragraph margin has to go or the three drift apart. */
    margin: 0;
    color: var(--ctp-color-text);
    font-size: var(--ctp-font-sm);
    font-weight: 600;
}

.ctp-events__meta-item--date {
    order: var(--ctp-order-date);
}

.ctp-events__meta-item--time {
    order: var(--ctp-order-time);
}

.ctp-events__meta-item--location {
    order: var(--ctp-order-location);
}

@media (max-width: 480px) {
    .ctp-events__item {
        align-items: flex-start;
    }
}

/* ---------- grid layout ---------- */

/*
 * Container-width-driven instead of viewport-width-driven: the old fixed
 * breakpoints (2 columns at 480px, --ctp-columns at 780px) keyed off the
 * *viewport*, so a grid embedded in a narrow column/sidebar still forced
 * the full column count and squeezed each card, even on a wide screen.
 * "RAM" pattern instead — auto-fill with a floor per track, so the actual
 * column count adapts to whatever width the grid really has:
 *   - calc(...) is the width one of exactly --ctp-columns equal tracks
 *     would get in the full container (the "target" size at max columns).
 *   - max(--ctp-card-min, that) never lets a card get narrower than the
 *     floor, which is what makes the grid drop to fewer (wider) columns
 *     once the container can't fit --ctp-columns tracks at the floor.
 *   - min(..., 100%) is pure overflow safety for a container narrower
 *     than --ctp-card-min itself (falls back to one full-width column
 *     instead of forcing horizontal overflow).
 *
 * `auto-fill`, nicht `auto-fit`: Beide rechnen dieselbe Spaltenzahl aus, die
 * drei Punkte oben gelten also für beide. Der Unterschied zeigt sich nur,
 * wenn weniger Kacheln da sind als Spalten — `auto-fit` lässt die leeren
 * Spuren zusammenfallen, und die verbliebene Kachel zieht sich über die
 * ganze Breite. Ein einzelner Suchtreffer war so 1165 statt 367 Pixel breit
 * und sah aus wie ein anderes Layout, nicht wie dieselbe Ansicht mit einem
 * Ergebnis. Mit `auto-fill` behält jede Kachel die eingestellte
 * Spaltenbreite (--ctp-columns), und rechts daneben bleibt Platz frei.
 *
 * Das fiel lange nicht auf, weil fast immer etwas mit `grid-column: 1 / -1`
 * danebensteht — ein Monatstrenner oder die Überleitung eines Ausblicks —
 * und die Spuren dadurch offenhält. Übrig blieb genau der Fall ohne beides:
 * die Suche, die ihre Monatstrenner selbst abschaltet.
 */
.ctp-events--grid .ctp-events__list {
    display: grid;
    grid-template-columns: repeat(
        auto-fill,
        minmax(
            min(
                max(var(--ctp-card-min), calc((100% - (var(--ctp-columns) - 1) * var(--ctp-gap)) / var(--ctp-columns))),
                100%
            ),
            1fr
        )
    );
    gap: var(--ctp-gap);
}

.ctp-events__card {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
    border-radius: var(--ctp-radius);
    background: var(--ctp-color-surface);
    box-shadow: var(--ctp-shadow);
}

.ctp-events__media {
    order: var(--ctp-order-media);
    position: relative;
    overflow: hidden;
    /* --ctp-media-aspect-ratio is only ever set inline (CardDesign::styleAttribute())
       when the admin picked something other than "wide" — see its own fallback rule. */
    aspect-ratio: var(--ctp-media-aspect-ratio, 16 / 9);
    background: linear-gradient(
        135deg,
        color-mix(in srgb, var(--ctp-accent) 45%, transparent),
        color-mix(in srgb, var(--ctp-accent) 12%, transparent)
    );
}

.ctp-events__media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transform: scale(1);
    transition: transform 0.3s ease;
}

.ctp-events__card--clickable:hover .ctp-events__media img {
    transform: scale(1.025);
}

/* Calendar "Standardbild" fallback (see EventListRenderer::withCalendarMeta())
   — a generic photo reused across many events of the same calendar, so a
   subtle color-matched scrim ties it back to that calendar's identity
   instead of looking like an unrelated stock photo. Real per-event photos
   never get this class and render at full color. */
.ctp-events__media--fallback img {
    filter: saturate(0.85);
}

.ctp-events__media--fallback::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        160deg,
        color-mix(in srgb, var(--ctp-accent) 38%, transparent),
        color-mix(in srgb, var(--ctp-accent) 4%, transparent) 70%
    );
    mix-blend-mode: multiply;
}

/* Eine Spur groesser als frueher (Polsterung und Zahl je gut ein Zehntel):
   Auf der Grid-Kachel liegt das Badge ueber dem Bild und musste sich dagegen
   behaupten - mehr als das waere ein Aufkleber. */
.ctp-events__date-badge {
    position: absolute;
    top: 0.85rem;
    left: 0.85rem;
    padding: 0.45rem 0.8rem;
    border-radius: calc(var(--ctp-radius) * 0.55);
    background: var(--ctp-color-surface);
    box-shadow: 0 4px 12px color-mix(in srgb, currentColor 16%, transparent);
    text-align: center;
    line-height: 1.1;
}

/* Derselbe Chip wie in der Liste, nur eine Spur groesser und ohne die
   Stretch-Breite, die ein Flex-Kind in der Spalte sonst bekaeme: Die
   Hero-Kachel ist ein Vielfaches einer Listenzeile, ein Chip in Listengroesse
   verschwindet darin. */
/* Eine Spur groesser als in der Liste - die Hero-Kachel ist ein Vielfaches
   einer Listenzeile, ein Chip in Listengroesse verschwindet darin. Steht in
   seiner eigenen Spalte (siehe oben), deshalb hier keine Ausrichtung mehr. */
.ctp-events__date-chip--hero {
    width: 3.9rem;
    padding: 0.5rem 0;
}

.ctp-events__date-chip--hero .ctp-events__day {
    font-size: var(--ctp-font-xl);
}

.ctp-events__card .ctp-events__content {
    order: var(--ctp-order-content);
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 0.4rem;
    padding: 1.05rem 1.2rem 1.3rem;
}

/* ---------- upcoming layout ---------- */

/*
 * Drei Bereiche nebeneinander: Datums-Chip, die Angaben zum Termin, das Bild.
 * Der Chip steht senkrecht mittig, das Bild rechts. Gestapelt (<768px) rutscht
 * das Bild ueber die volle Breite nach oben, darunter stehen Chip und Angaben
 * nebeneinander - dasselbe Bild, das auch eine Listenzeile abgibt.
 *
 * Innenabstand statt randlos: Vorher lief das Bild bis an die Kante der Kachel
 * und der Chip klebte am linken Rand. Weil die Kachel keinen Rahmen mehr hat
 * (nur noch den Schatten), braucht sie diesen Abstand, damit ihr Inhalt nicht
 * im Nichts steht. Das Bild bekommt dafuer eine eigene Rundung, die vorher das
 * overflow der Kachel besorgt hat.
 */
.ctp-events--upcoming .ctp-events__hero {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.1rem;
    padding: 1.25rem;
    margin-block-end: var(--ctp-gap);
    border-radius: var(--ctp-radius);
    background: var(--ctp-color-surface);
    box-shadow: var(--ctp-shadow);
}

/*
 * Chip und Angaben bilden eine Gruppe. Innerhalb der Gruppe steht der Chip
 * oben, also auf der Linie der ersten Textzeile - er gehoert zum Titel, nicht
 * zur Kachelmitte. Die Gruppe als Ganzes steht ab 768px senkrecht mittig zum
 * Bild (siehe unten). Einzeln im Kachelgitter ging beides nicht zugleich:
 * Zwei Gitterzellen kennen die Hoehe der jeweils anderen nicht, "beide mittig"
 * und "Chip auf der Titelzeile" schliessen sich dort gegenseitig aus.
 */
.ctp-events--upcoming .ctp-events__hero-main {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: inherit;
    align-items: start;
}

/*
 * Zweispaltig erst ab 768px statt ab 640px. Vorher kippte die Kachel schon auf
 * schmalen Tablets in zwei Spalten, in denen dann beides zu eng stand: Der
 * Titel brach mehrzeilig um, waehrend daneben ein hochkantes Flyer-Bild in
 * einer breiten, flachen Zelle schwamm (auf der Live-Seite 1128 Pixel breit, 281
 * hoch - das Bild darin knapp 200 Pixel breit, der Rest leer).
 *
 * Angaben und Bild sind gleich breit (1fr gegen 1fr, vorher 1.35fr gegen 1fr).
 * Der Datums-Chip bleibt bewusst seine eigene, inhaltsbreite Spalte davor: Die
 * Haelften beziehen sich auf Angaben und Bild, nicht auf Chip+Angaben gegen
 * Bild - sonst muesste der Chip in eine gemeinsame Zelle mit den Angaben, und
 * das kostet Markup fuer einen Unterschied von rund 60 Pixeln.
 */
@media (min-width: 768px) {
    .ctp-events--upcoming .ctp-events__hero {
        grid-template-columns: auto minmax(0, 1fr) minmax(0, 1fr);
        gap: 1.5rem;
        padding: 1.5rem;
        align-items: stretch;
    }

    /*
     * subgrid statt eigener Spalten: Die Gruppe uebernimmt die ersten beiden
     * Spuren der Kachel (Chipbreite und die eine Haelfte), damit die Angaben
     * exakt so breit bleiben wie das Bild rechts. Mit eigenen Spalten waere
     * die Textspalte um Chip plus Abstand schmaler.
     *
     * align-self: center stellt Chip und Angaben zusammen mittig zum Bild
     * (Nutzerwunsch 2026-08-28); innerhalb der Gruppe bleibt der Chip oben und
     * damit auf der Titelzeile.
     */
    .ctp-events--upcoming .ctp-events__hero-main {
        grid-column: 1 / 3;
        grid-row: 1;
        grid-template-columns: subgrid;
        align-self: center;
    }
}

/*
 * Image lives on the right at desktop width, shown in full (object-fit:
 * contain, never cropped) regardless of portrait/landscape source — a portrait
 * event photo used to get cropped hard by `cover` against a landscape box. Die
 * Zelle traegt dafuer in beiden Zweigen das im Design-Tab gewaehlte
 * Seitenverhaeltnis (--ctp-media-aspect-ratio): Ein Bild in genau diesem
 * Verhaeltnis fuellt die Zelle damit vollstaendig aus, statt in einer
 * text-hohen Box mit Leerstreifen zu stehen. Der Fallback ist 16/9 wie bei den
 * Kacheln - CardDesign setzt die Variable fuer die Auswahl "Breit" gar nicht
 * erst, und stand hier wie frueher 16/10, waere ausgerechnet die Standardwahl
 * die eine, die nicht aufgeht: ein 16:9-Foto haette in einer 16:10-Zelle oben
 * und unten je einen Streifen Leerraum. Gestapelt (<768px) bestimmt ein vorhandenes Bild
 * seine Hoehe weiterhin selbst (siehe die Regel weiter unten); dort bleibt das
 * feste Verhaeltnis dem Fall ohne Bild.
 */
.ctp-events--upcoming .ctp-events__hero-media {
    order: var(--ctp-order-media);
    grid-column: 1 / -1;
    grid-row: 1;
    position: relative;
    width: 100%;
    aspect-ratio: var(--ctp-media-aspect-ratio, 16 / 9);
    /* Eigene Rundung und eigener Beschnitt: Die Kachel klemmt das Bild nicht
       mehr an ihrer Kante ab, seit sie Innenabstand hat. */
    overflow: hidden;
    border-radius: calc(var(--ctp-radius) * 0.6);
    /*
     * Ruhiger Kachelgrund statt des frueheren Verlaufs in der Kalenderfarbe:
     * Das Bild wird contain eingepasst, also bleibt neben einem hochkanten
     * Flyer viel von diesem Grund sichtbar - als kraeftiger Farbverlauf war das
     * der auffaelligste Teil der Kachel und stand in Konkurrenz zum Flyer
     * selbst. Die Kalenderfarbe bleibt dort, wo sie etwas bedeutet: im
     * Farbpunkt, in den Akzenten und im Scrim des Ersatzbildes unten.
     */
    background: var(--ctp-color-surface);
}

/* Ohne Bildzelle bleiben Chip und Angaben - die bekommen dann die ganze
   Breite, statt die Spalte des fehlenden Bildes leer stehen zu lassen. Nach
   der Spaltenregel oben, weil beide gleich spezifisch sind. */
@media (min-width: 768px) {
    .ctp-events--upcoming .ctp-events__hero--no-media {
        grid-template-columns: auto minmax(0, 1fr);
    }
}

@media (min-width: 768px) {
    .ctp-events--upcoming .ctp-events__hero-media {
        grid-column: 3;
        grid-row: 1;
        /*
         * align-self statt des geerbten stretch: Eine gestreckte Zelle hat eine
         * definite Hoehe, und gegen die kommt aspect-ratio nicht an - die Zelle
         * waere wieder so hoch wie der Text daneben und das Bild stuende mit
         * Leerstreifen darin. So gibt das Verhaeltnis die Hoehe vor, und ist
         * der Text laenger, bleibt unter dem Bild Platz statt im Bild.
         *
         * Vorher stand hier aspect-ratio: auto plus
         * min-height: clamp(260px, 22vw, 400px), also eine text-getriebene
         * Hoehe mit Untergrenze. Beides ist weg: Die Untergrenze wuerde das
         * gewaehlte Verhaeltnis auf schmalen Spalten wieder aushebeln.
         */
        align-self: start;
    }

}

/*
 * Absolutely positioned, not just `height: 100%`: at desktop width the media
 * cell's height is auto (it stretches to the row), so an in-flow image still
 * contributed its *own* scaled height to that row — a 724×1024 portrait photo
 * blew the hero up to ~880px, the very stretching the comment above says
 * doesn't happen. Taken out of flow, the row is decided by hero-body's text
 * alone (min-height 260px as the floor) and the image is contained inside
 * whatever that turns out to be. Same treatment the popup's detail image got
 * for the same reason. Harmless in the mobile branch, where the fixed
 * aspect-ratio box already gives the cell a definite height.
 */
.ctp-events--upcoming .ctp-events__hero-media img {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/*
 * Gestapelt (<768px) bestimmt das Bild seine Hoehe selbst, statt in eine Box
 * mit festem Seitenverhaeltnis eingepasst zu werden: Ein hochkanter Flyer
 * stand darin schmal in der Mitte, mit breiten leeren Streifen links und
 * rechts - auf dem Handy die halbe Kachel. Nach oben gedeckelt, damit ein sehr
 * hohes Bild nicht den ganzen Bildschirm einnimmt. Das feste Seitenverhaeltnis
 * oben bleibt fuer den Fall ohne Bild, wo es die einzige Groesse ist, die die
 * Zelle ueberhaupt hat (deshalb :has(img) und nicht einfach aspect-ratio: auto).
 */
@media (max-width: 767px) {
    .ctp-events--upcoming .ctp-events__hero-media:has(img) {
        aspect-ratio: auto;
    }

    .ctp-events--upcoming .ctp-events__hero-media img {
        position: static;
        width: auto;
        height: auto;
        max-width: 100%;
        max-height: 65vh;
        margin-inline: auto;
    }
}

/* Same calendar-tinted scrim as .ctp-events__media--fallback, for the hero. */
.ctp-events--upcoming .ctp-events__hero-media--fallback img {
    filter: saturate(0.85);
}

.ctp-events--upcoming .ctp-events__hero-media--fallback::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        160deg,
        color-mix(in srgb, var(--ctp-accent) 38%, transparent),
        color-mix(in srgb, var(--ctp-accent) 4%, transparent) 70%
    );
    mix-blend-mode: multiply;
}

/*
 * flex-start statt center: Die Angaben standen senkrecht mittig zur Kachel,
 * der Datums-Chip daneben ebenso - beide zusammen hingen damit in der Luft und
 * die erste Zeile der Angaben lag tiefer als der Chip. Oben ausgerichtet
 * beginnen Chip und Titel auf derselben Linie; ist das Bild hoeher als der
 * Text, bleibt der Platz unter dem Text statt verteilt ueber beide Enden.
 */
.ctp-events--upcoming .ctp-events__hero-body {
    order: var(--ctp-order-content);
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 0.7rem;
}

/* 600 statt 750: In dieser Groesse traegt die Ueberschrift ihr Gewicht schon
   ueber den Schriftgrad - der schwere Schnitt wirkte daneben blockig. Die
   Titel der Listen- und Grid-Kacheln bleiben bei 700, sie sind klein genug,
   dass sie das Gewicht brauchen. Gilt genauso fuer die Ueberschrift der
   Detailansicht weiter unten. */
/*
 * Die Angaben tragen keine eigenen Aussenabstaende mehr, ihr Abstand kommt
 * allein aus dem gap dieser Spalte. Zwei Gruende: Der Titel ist ein <h3> und
 * erbte die Abstaende des Themes (in der Testumgebung 32px oben und unten),
 * waehrend der Chip in seiner eigenen Spalte am oberen Rand der Zeile sitzt -
 * um genau diese 32px stand die Titelzeile tiefer als er. Und die Reihenfolge
 * der Angaben ist im Design-Tab frei einstellbar: Solange jedes Element eigene
 * Abstaende mitbringt, haengt der Abstand zwischen zwei Zeilen davon ab,
 * welche beiden gerade nebeneinander liegen.
 *
 * :first-child waere hier falsch: Die Elemente stehen in fester DOM-Reihenfolge
 * und werden per CSS order sortiert - das erste Kind im Markup ist also nicht
 * das erste im Bild.
 */
.ctp-events--upcoming .ctp-events__hero-body > * {
    margin-block: 0;
}

.ctp-events--upcoming .ctp-events__hero-title {
    order: var(--ctp-order-title);
    font-size: clamp(var(--ctp-font-xl), 1rem + 1.4vw, var(--ctp-font-2xl));
    font-weight: 600;
    line-height: 1.15;
}

.ctp-events--upcoming .ctp-events__more-label {
    margin: 0 0 0.5rem;
    color: var(--ctp-color-muted);
    font-size: var(--ctp-font-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

@media (prefers-reduced-motion: no-preference) {
    .ctp-events__card {
        transition: transform 0.2s ease, box-shadow 0.2s ease;
    }
}

/* ---------- click behavior: "stretched link" trigger (see ClickTrigger.php) ---------- */

.ctp-events__card--clickable,
.ctp-events__item--clickable,
.ctp-events__hero--clickable {
    cursor: pointer;
}

.ctp-events__card-trigger {
    all: unset;
    cursor: pointer;
}

/* Stretches invisibly over the entire card/item/hero (its nearest positioned
   ancestor, not its own small text bounding box) so the whole tile is
   clickable while only the title text is the actual <a>/<button> in the DOM —
   keeps article/h3/p out of interactive content, which <button> forbids. */
.ctp-events__card-trigger::after {
    content: '';
    position: absolute;
    inset: 0;
}

.ctp-events__card-trigger:focus-visible {
    outline: 2px solid var(--ctp-accent);
    outline-offset: 2px;
    border-radius: 2px;
}

@media (prefers-reduced-motion: no-preference) {
    .ctp-events__item--clickable,
    .ctp-events__hero--clickable {
        transition: transform 0.18s ease, box-shadow 0.18s ease;
    }
}

.ctp-events__card--clickable:hover,
.ctp-events__card--clickable:focus-within {
    box-shadow: 0 2px 6px color-mix(in srgb, currentColor 8%, transparent),
        0 26px 48px -20px color-mix(in srgb, var(--ctp-accent) 40%, transparent);
    transform: translateY(-3px);
}

.ctp-events__item--clickable:hover,
.ctp-events__item--clickable:focus-within {
    transform: translateY(-1px);
}

.ctp-events__hero--clickable:hover,
.ctp-events__hero--clickable:focus-within {
    box-shadow: 0 2px 6px color-mix(in srgb, currentColor 8%, transparent),
        0 26px 48px -20px color-mix(in srgb, var(--ctp-accent) 40%, transparent);
}

/* ---------- popup modal (see partials/modal.php, assets/js/frontend.js) ---------- */

.ctp-events__modal {
    max-width: min(640px, calc(100vw - 2rem));
    max-height: calc(100vh - 4rem);
    padding: 0;
    /* Ohne grauen Rahmen wie Kachel und Hero-Kachel auch - der Schatten
       darunter trennt das Fenster genug vom Seiteninhalt. */
    border: none;
    border-radius: var(--ctp-radius);
    background: var(--ctp-color-surface);
    color: var(--ctp-color-text);
    box-shadow: var(--ctp-shadow);
}

.ctp-events__modal::backdrop {
    background: color-mix(in srgb, black 50%, transparent);
}

/* Clicking anywhere in the popup moves focus to the <dialog> itself, and
   WordPress' generated Global Styles put a 2px ring on anything focused inside
   .wp-site-blocks — so the whole popup gained an outline on the first click.
   The dialog is a container, not a control: its focusable children keep their
   own rings (see .ctp-events__modal-close below), so nothing is lost here. */
.ctp-events__modal:focus,
.ctp-events__modal:focus-visible,
.ctp-events__modal-body:focus,
.ctp-events__modal-body:focus-visible {
    outline: none;
}

/* A bare glyph in muted text vanished against whatever the detail view opens
   with — and that is an event photo far more often than not, since "media"
   leads the default detail order. Given its own opaque chip (surface fill,
   border, shadow) it stays readable over any image, and the 2.25rem box is a
   real touch target rather than a 20px glyph. */
.ctp-events__modal-close {
    all: unset;
    position: absolute;
    top: 0.7rem;
    right: 0.7rem;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: 2.25rem;
    height: 2.25rem;
    border: 1px solid var(--ctp-color-button-border);
    border-radius: var(--ctp-radius-pill);
    background: var(--ctp-color-button);
    box-shadow: 0 2px 10px color-mix(in srgb, black 25%, transparent);
    color: var(--ctp-color-button-text);
    font-size: var(--ctp-font-lg);
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/* Hover fills, focus only rings. The two used to share the filled state, so
   the button came up looking pressed as soon as the popup opened. */
.ctp-events__modal-close:hover {
    border-color: var(--ctp-color-button-strong);
    background: var(--ctp-color-button-strong);
    color: var(--ctp-color-button-strong-text);
}

.ctp-events__modal-close:focus-visible {
    outline: 2px solid var(--ctp-accent);
    outline-offset: 2px;
}

.ctp-events__modal-body {
    padding: 1.8rem;
    overflow-y: auto;
    max-height: calc(100vh - 4rem);
}

/* ---------- detail view content (partials/event-detail-content.php), shared by the modal body and the "own page" template ---------- */

/*
 * Row-wrap rather than a plain column: every child claims a full line by
 * default (the flex-basis below), which reproduces the column stack — but it
 * lets date, time and location opt out with an auto basis and share one line
 * while the popup is wide enough for them. A column flex has no equivalent:
 * its children each own a line, unconditionally.
 */
.ctp-events__detail {
    display: flex;
    flex-flow: row wrap;
    align-items: baseline;
    column-gap: 1.25rem;
    row-gap: 0.8rem;
}



/*
 * The detail view emits its elements in the admin-configured order server-side
 * (see DetailDesign) — but .ctp-events__eyebrow/__subtitle/__meta-item carry a CSS
 * `order` for the *card* layouts, and this is a flex column too, so that order
 * was winning here and silently reshuffling the popup: with the default detail
 * order the calendar badge landed below the description instead of above the
 * title. Neutralized for direct children of the detail view only, so the card
 * layouts keep their reordering.
 *
 * The flex basis on the same rule is the other half of the row-wrap layout
 * above: a full line each, which is what the three meta items and the calendar
 * badge below opt out of.
 */
.ctp-events__detail > * {
    order: 0;
    flex: 0 0 100%;
}

/* The calendar badge is a pill — its own line, but hugging its text rather
   than stretched across the full width by the rule above. */
.ctp-events .ctp-events__detail > .ctp-events__eyebrow {
    flex: 0 0 auto;
}

/* One step up from the size the cards use — a detail view has the room, and
   the "when and where" is what most visitors opened it for. */
.ctp-events .ctp-events__detail .ctp-events__meta-item {
    font-size: var(--ctp-font-md);
    /* Auto basis instead of the full-line default below, so date, time and
       location flow onto one line whenever the popup is wide enough for them
       and drop onto their own lines when it is not. */
    flex: 0 1 auto;
}

/* Full-width row; the frame inside it is what hugs the image, so a capped
   portrait sits centred without a frame stretched across the empty space
   beside it. */
.ctp-events__detail-media {
    display: flex;
    justify-content: center;
}

.ctp-events__detail-media-frame {
    position: relative;
    max-width: 100%;
    overflow: hidden;
    border-radius: calc(var(--ctp-radius) * 0.8);
    box-shadow: var(--ctp-shadow);
}

/* ChurchTools event flyers are portrait as often as not (4:5 and taller). At
   the full column width one of those ran well past a screen height on its own,
   so the detail view opened on nothing but image and pushed title, time and
   description out of sight — capped here instead, tighter in the popup than on
   the standalone page, which has a whole screen to spend. */
.ctp-events__detail-media img {
    display: block;
    width: auto;
    max-width: 100%;
    max-height: 60vh;
}

.ctp-events__modal .ctp-events__detail-media img {
    max-height: min(45vh, 24rem);
}

/* Same calendar-tinted scrim as .ctp-events__media--fallback, for detail view. */
.ctp-events__detail-media-frame--fallback img {
    filter: saturate(0.85);
}

.ctp-events__detail-media-frame--fallback::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        160deg,
        color-mix(in srgb, var(--ctp-accent) 38%, transparent),
        color-mix(in srgb, var(--ctp-accent) 4%, transparent) 70%
    );
    mix-blend-mode: multiply;
}

/*
 * Titelzeile der Detailansicht: Datums-Chip und Titel nebeneinander. Die
 * farbige Linie unter dem Titel ist dafuer entfallen - sie trennte den Titel
 * von seinen eigenen Angaben, und die Kalenderfarbe steht ohnehin schon im
 * Chip und in der Kalender-Pille.
 */
.ctp-events__detail-heading {
    display: flex;
    align-items: center;
    gap: 0.85rem;
}

/*
 * Der Chip traegt `order: var(--ctp-order-media)` fuer die Kachel-Layouts, und
 * diese Zeile ist auch ein Flex-Container - steht das Bild im Design-Tab nicht
 * an erster Stelle, rutschte der Chip damit hinter den Titel (der Titel hat
 * kein order und liegt bei 0). Fiel nur deshalb nie auf, weil das Bild in der
 * Standardreihenfolge vorne steht und --ctp-order-media dort 0 ist.
 */
.ctp-events .ctp-events__detail-heading > .ctp-events__date-chip {
    order: 0;
}

.ctp-events__detail-title {
    margin: 0;
    font-size: var(--ctp-font-xl);
    /* Siehe .ctp-events__hero-title: dieselbe Ueberlegung, derselbe Schnitt. */
    font-weight: 600;
    line-height: 1.22;
}

/* Explicitly sized rather than left to inherit the theme's body font — that
   inheritance is what made popup body copy visibly larger than the card text
   it was opened from (see the type scale at the top of this file). */
.ctp-events__detail-description {
    margin-top: 0.4rem;
    font-size: var(--ctp-font-md);
    line-height: 1.6;
}

/*
 * The description arrives as paragraphs now (EventFormatter::descriptionHtml()
 * turns ChurchTools' plain-text line breaks into <p>/<br>), so the spacing
 * between them is this plugin's decision rather than whatever margin the theme
 * happens to put on <p> — which ranged from none at all to a full line.
 */
.ctp-events__detail-description p {
    margin: 0 0 0.75em;
}

.ctp-events__detail-description :first-child {
    margin-top: 0;
}

.ctp-events__detail-description :last-child {
    margin-bottom: 0;
}

/* ---------- "own page" layout (event-detail.php) ---------- */

/*
 * Bis 1.3.x war das hier eine einzige Regel: max-width 42rem, sonst nichts.
 * Zwischen get_header() und get_footer() steht diese Seite ohne den Container
 * des Themes da - es gibt keinen echten Beitrag, um den das Theme einen legen
 * koennte (siehe EventDetailPage) -, und so klebte der Inhalt am linken Rand
 * des Fensters. Der Kasten hier ist also der fehlende Container, nicht
 * Zierrat: mittig, mit Luft ringsum, in der Breite begrenzt.
 *
 * Mit eingestellter Elternseite bringt das Theme seinen eigenen Container mit,
 * und dann liegt hier einer im anderen. Das ist der guenstigere der beiden
 * Fehler: etwas mehr Abstand ist zu verschmerzen, kein Container dagegen
 * nicht.
 */
.ctp-events--detail {
    /*
     * Der Bezugsrahmen fuer die Abfrage weiter unten. Die Aufteilung dieser
     * Seite haengt daran, wie breit sie *hier* ist, und nicht daran, wie breit
     * das Fenster ist: Als Inhalt einer Seite steckt sie im Inhaltsbereich des
     * Themes, und der ist bei manchen Themes 650px breit, auch auf einem
     * 1600px-Bildschirm. Eine Fensterabfrage haette dort zwei Spalten
     * aufgemacht, wo keine hinpassen. Dieselbe Ueberlegung wie beim
     * Grid-Layout weiter oben, nur mit @container statt mit auto-fill.
     */
    container-type: inline-size;
    container-name: ctp-detail;
    max-width: 62rem;
    margin-inline: auto;
    padding-block: clamp(1.75rem, 4vw, 3rem);
    padding-inline: clamp(1.25rem, 5vw, 2.5rem);
}

/*
 * Als Inhalt einer echten Seite (Einstellung „Adresse der Terminseite") legt
 * das Theme seinen Container schon um diesen Block - dann ist der eigene
 * Innenabstand der zweite um denselben Inhalt, und oben stand dadurch ein
 * Streifen Leere, den niemand bestellt hat. Die Breitenbegrenzung bleibt: Sie
 * gilt dem Lesemass und nicht dem Rand.
 */
.ctp-events--detail.ctp-events--hosted {
    padding-block: 0;
    padding-inline: 0;
}

/*
 * Sprungziele des „Zurueck"-Knopfes: Er zeigt auf #ctp-event-<id>, also auf
 * die Kachel, aus der die Detailseite geoeffnet wurde. Der Abstand nach oben
 * haelt sie unter einer angehefteten Kopfzeile des Themes frei - ohne ihn
 * scrollt der Browser die Kachel exakt an die Fensterkante und die Kopfzeile
 * legt sich darueber.
 */
.ctp-events__item,
.ctp-events__cell,
.ctp-events__hero {
    scroll-margin-top: 6rem;
}

/*
 * Ein kurzes Aufleuchten sagt, *welche* der Kacheln es war - nach einer
 * Detailseite und einem Sprung mitten in eine lange Liste ist das nicht
 * selbstverstaendlich. Als Animation und nicht als Dauerzustand, weil
 * `:target` sonst bis zum naechsten Klick bestehen bliebe; wer Bewegung
 * abbestellt hat, bekommt nur den Sprung, und der ist die eigentliche Hilfe.
 */
@media (prefers-reduced-motion: no-preference) {
    .ctp-events__item:target,
    .ctp-events__cell:target > .ctp-events__card,
    .ctp-events__hero:target {
        animation: ctp-events-return 2.4s ease-out 1;
    }
}

@keyframes ctp-events-return {
    from {
        box-shadow: 0 0 0 3px var(--ctp-accent);
    }

    to {
        box-shadow: 0 0 0 3px transparent;
    }
}

/*
 * Form und Groesse wie die Eventfinder-Knoepfe, Verhalten beim Ueberfahren wie
 * „Weitere Termine laden": volle Fuellung statt nur angedeuteter. Die
 * Finder-Knoepfe koennen das nicht, weil bei ihnen die volle Fuellung schon
 * den *gewaehlten* Zustand bedeutet - sie brauchen einen leiseren Hover, um
 * beides auseinanderhalten zu koennen. Dieser Knopf hier hat keinen gewaehlten
 * Zustand, also ist der deutlichere Hover frei, und er ist der bessere: Als
 * graue Textzeile war dies das einzige Bedienelement des Plugins, das nicht
 * wie eines aussah - ausgerechnet das, mit dem man die Seite wieder verlaesst.
 *
 * Hoehere Spezifitaet als die beiden Vorbilder (.ctp-events davor), weil dies
 * hier ein <a> ist: Themes faerben Links und ihren Hover-Zustand, und eine
 * Regel mit nur einer Klasse verliert gegen `.post-content a:hover`.
 */
.ctp-events .ctp-events__back {
    display: inline-flex;
    align-items: center;
    gap: 0.45em;
    margin-bottom: 1.75rem;
    padding: 0.45rem 1.05rem;
    border: 1px solid var(--ctp-color-button-border);
    border-radius: var(--ctp-radius-pill);
    background-color: var(--ctp-color-button);
    color: var(--ctp-color-button-text);
    font-size: var(--ctp-font-control);
    font-weight: 600;
    line-height: 1.35;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/*
 * Dieselbe Umkehr in den gefuellten Zustand wie .ctp-events__load-more:hover.
 * `:focus` ist mit dabei, weil dieser Knopf per Tastatur erreichbar ist und
 * ein Link ohne sichtbare Rueckmeldung beim Fokussieren schlechter zu bedienen
 * waere als ein Button.
 *
 * Und hier stehen die einzigen `!important` dieses Stylesheets. Grund ist eine
 * Regel des Themes der Live-Seite (Uncode, style-custom.css):
 *
 *     .style-dark .style-light a:not(.btn-text-skin):hover { color: #00a19a }
 *
 * Die faerbt *jeden* Link beim Ueberfahren in die Akzentfarbe des Themes - der
 * Knopf wurde also schwarz, seine Schrift aber tuerkis statt weiss (der
 * Hintergrund bleibt unbehelligt, weil Themes Links keine Flaeche geben).
 * Dagegen hilft Spezifitaet nicht: Mit `:hover` und dem `:not()` kommt diese
 * Regel auf (0,4,1), und mehr laesst sich mit den Klassen, die hier
 * verlaesslich zur Verfuegung stehen, nicht erreichen - ein Gleichstand haengt
 * dann an der Ladereihenfolge der Stylesheets, und die ist nicht zugesichert.
 *
 * Alle drei Eigenschaften zusammen sind *ein* Zustand; sie einzeln abzusichern
 * hiesse, auf halbem Weg einen Knopf zu bekommen, den es so nicht geben soll.
 */
.ctp-events .ctp-events__back:hover,
.ctp-events .ctp-events__back:focus {
    border-color: var(--ctp-color-button-strong) !important;
    background-color: var(--ctp-color-button-strong) !important;
    color: var(--ctp-color-button-strong-text) !important;
    text-decoration: none;
}

.ctp-events .ctp-events__back:focus-visible {
    outline: 2px solid var(--ctp-accent);
    outline-offset: 2px;
}

/*
 * Eine Spalte ist der Ausgangszustand, zwei sind die Ausnahme - und nicht
 * umgekehrt. Das ist mehr als Geschmack: In 1.4.0 stand die Zweispaltigkeit
 * in der Grundregel und wurde in einer Medienabfrage zurueckgenommen. Eine
 * Medienabfrage erhoeht die Spezifitaet aber nicht, und die Ruecknahme wog
 * eine Klasse weniger als die Regel, die sie zuruecknehmen sollte: Das Bild
 * behielt sein `grid-column: 2`, das Raster legte eine implizite zweite
 * Spalte an, und auf dem Telefon stand die Seite weiter zweispaltig. Wird die
 * Ausnahme zur Ausnahme, gibt es nichts zurueckzunehmen.
 */
.ctp-events--detail .ctp-events__detail {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    column-gap: 2.75rem;
    row-gap: 1.5rem;
}

/* Auf einer Spalte eroeffnet das Bild die Seite, statt hinter den Eckdaten
   nachzukommen - auf einem Telefon ist es das Erste, was man sieht. */
.ctp-events--detail .ctp-events__detail > .ctp-events__detail-media {
    order: -1;
    justify-content: flex-start;
}

/*
 * Zwei Spalten, sobald der Platz dafuer da ist: Kopf links, Bild rechts -
 * dieselbe Aufteilung, die die Hero-Kachel von „Nächster Termin" ab 768px hat
 * (dort `grid-column: 3`). Damit ist diese Seite auch im Aufbau die grosse
 * Fassung der Kachel, aus der man auf sie geklickt hat, und nicht deren
 * Spiegelbild.
 *
 * Das Popup bleibt ausserhalb dieser Regeln (kein .ctp-events--detail davor):
 * dort ist der Platz zu knapp fuer zwei Spalten, und die Anordnung folgt dort
 * weiter der im Design-Tab eingestellten Reihenfolge.
 */
@container ctp-detail (min-width: 46rem) {
    /* Ohne Bild gibt es nichts, was die zweite Spalte fuellen koennte - dann
       waere sie nur ein breiter leerer Streifen rechts. Die Kennzeichnung
       setzt das Partial, weil nur PHP weiss, ob ein Bild kommt. */
    .ctp-events--detail .ctp-events__detail:not(.ctp-events__detail--no-media) {
        grid-template-columns: minmax(0, 1fr) 1.05fr;
        row-gap: 1.25rem;
    }

    /* Mittig neben dem Bild statt oben buendig: Ein Hochkant-Flyer ist gut
       doppelt so hoch wie der Textblock daneben, und der klebte oben an der
       Kante, waehrend rechts die Haelfte des Bildes ohne Gegenueber stand. */
    .ctp-events--detail .ctp-events__detail > .ctp-events__detail-text {
        grid-column: 1;
        grid-row: 1;
        align-self: center;
    }

    .ctp-events--detail .ctp-events__detail > .ctp-events__detail-media {
        grid-column: 2;
        grid-row: 1;
        order: 0;
        align-self: start;
        justify-content: flex-end;
    }

    .ctp-events--detail .ctp-events__detail > .ctp-events__detail-description {
        grid-column: 1 / -1;
        grid-row: 2;
        margin-top: 1.5rem;
        padding-block-start: 2.25rem;
    }
}

/*
 * Die Trennlinie laeuft ueber die volle Breite, der Text darunter nur bis zum
 * Lesemass: Eine Linie, die mitten auf der Seite aufhoert, sieht aus wie ein
 * Versehen, und ein Absatz ueber 62rem liest sich schlecht.
 */
.ctp-events--detail .ctp-events__detail > .ctp-events__detail-description {
    margin-top: 0.5rem;
    padding-block-start: 1.75rem;
    border-block-start: 1px solid var(--ctp-color-border);
    font-size: var(--ctp-font-lg);
    line-height: 1.68;
}

.ctp-events--detail .ctp-events__detail-description p {
    max-width: 42rem;
}

/*
 * Eine Huelle fuer alles ausser Bild und Beschreibung, in der im Design-Tab
 * eingestellten Reihenfolge. 1.4.0 waren es zwei - „Kopf" und „Eckdaten" -,
 * und diese Sortierung nach Art hat die eingestellte Reihenfolge still
 * ueberstimmt: Ein ans Ende gezogenes Kalender-Etikett stand wieder zwischen
 * Titel und Datum, weil es als Kopf zaehlte.
 */
.ctp-events__detail-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    min-width: 0;
    gap: 0.7rem;
}

/*
 * Der Grundabstand ist der enge der Eckdaten - drei Zeilen, die zusammen eine
 * Angabe sind, stehen dicht beieinander. Alles andere bekommt seine Luft
 * einzeln dazu, statt dass ein weiter Grundabstand die Eckdaten auseinander
 * zieht. Ueber margin und nicht ueber ein zweites `gap`, weil die Reihenfolge
 * frei ist: Welche Elemente nebeneinander zu liegen kommen, steht nicht fest.
 */
.ctp-events__detail-text > .ctp-events__detail-heading,
.ctp-events__detail-text > .ctp-events__subtitle,
.ctp-events__detail-text > .ctp-events__eyebrow {
    margin-block: 0.3rem;
}

/*
 * Derselbe Grund wie bei `.ctp-events__detail > *` weiter oben, eine Ebene
 * tiefer: .ctp-events__eyebrow, .ctp-events__subtitle und die drei
 * .ctp-events__meta-item--* tragen ein CSS-`order` fuer die *Kachel*-Layouts.
 * Als direkte Kinder von .ctp-events__detail waren sie davon befreit - in
 * dieser Huelle sind sie es nicht mehr, und die im Design-Tab gesetzte
 * Kachelreihenfolge wuerde die serverseitig gerenderte Reihenfolge der
 * Detailansicht erneut durcheinanderbringen.
 */
.ctp-events .ctp-events__detail-text > * {
    order: 0;
}

.ctp-events--detail .ctp-events__detail-title {
    font-size: clamp(1.8rem, 1rem + 2.2vw, 2.5rem);
    line-height: 1.12;
    letter-spacing: -0.015em;
}

.ctp-events--detail .ctp-events__detail-heading {
    align-items: flex-start;
    gap: 1rem;
}

/* Auf der Seite ist der Untertitel der Vorspann unter einer 2,5rem hohen
   Ueberschrift, in den Kacheln eine Nebenzeile - in Kachelgroesse verschwand
   er hier unter dem Titel, statt ihn fortzusetzen. */
.ctp-events--detail .ctp-events__subtitle {
    font-size: var(--ctp-font-lg);
}

/* Chip in Hero-Groesse statt in Listengroesse: neben einer 2,5rem hohen
   Ueberschrift verschwindet der kleine aus den Zeilen sonst. */
.ctp-events--detail .ctp-events__date-chip--detail {
    width: 4.1rem;
    padding: 0.55rem 0;
}

.ctp-events--detail .ctp-events__date-chip--detail .ctp-events__day {
    font-size: var(--ctp-font-xl);
}

.ctp-events--detail .ctp-events__detail-text .ctp-events__meta-item {
    gap: 0.6rem;
}

.ctp-events--detail .ctp-events__detail-text .ctp-events__icon {
    color: var(--ctp-accent);
}

/* Unbeschnitten wie in der Hero-Kachel - Hochkant-Flyer sind bei diesen
   Terminen etwa die Haelfte der Bilder, und ein zugeschnittener Flyer ist
   ein unlesbarer Flyer. */
.ctp-events--detail .ctp-events__detail-media img {
    max-height: 24rem;
    object-fit: contain;
}

/* ---------- design presets (siehe DesignPreset.php, Design-Tab „Stil") ---------- */

/*
 * Vier wählbare Stil-Grundlagen. „Standard" ist das Aussehen, das seit dem
 * Facelift ausgeliefert wird, und steht deshalb schon oben in .ctp-events —
 * es bekommt hier bewusst keinen eigenen Block, sonst stünde dort eine leere
 * Regel. Die drei anderen greifen die Richtungen der Prototyp-Runden auf.
 *
 * Zwei Konventionen für alles, was hier folgt:
 *
 *   1. Jeder Selektor beginnt mit `.ctp-events.ctp-events--preset-x`, obwohl
 *      eine der beiden Klassen genügen würde. Das hebt jede Preset-Regel
 *      genau eine Klasse über ihre Grundregel weiter oben, unabhängig davon,
 *      wo im Dokument sie steht — sonst entschiede bei gleichem Gewicht die
 *      Reihenfolge in der Datei, und die ändert sich beim nächsten Einschub.
 *   2. Ein Preset ändert nur Optik. Nichts hier setzt `order`, blendet
 *      Elemente aus oder greift ins Klickverhalten ein — das ist die
 *      Konfiguration der Redaktion (CardDesign), nicht Teil eines Stils.
 *
 * Was ein Preset *nicht* erzwingt: Ecken, Akzentfarbe, Buttonfarbe und
 * Bildformat kommen aus dem Design-Tab als Inline-Style und schlagen jede
 * Regel hier. Wer „Eckig" wählt, bekommt eckige Ecken auch in „Warm".
 */

/*
 * Ruhig — architektonisch. Haarlinie statt Schatten, fast kein Radius, keine
 * Bewegung bei Hover: Die Kachel ist ein gezeichneter Rahmen, kein Objekt, das
 * über dem Papier schwebt. Das Kalender-Label verliert seine Pille und bleibt
 * als farbiger Text stehen.
 */
.ctp-events.ctp-events--preset-ruhig {
    --ctp-radius: 3px;
    --ctp-radius-pill: 3px;
    --ctp-shadow: none;
}

/*
 * box-sizing steht hier und nicht nur der Vollstaendigkeit halber: Die Kachel
 * traegt `height: 100%`, und mit `content-box` - was ein Theme durchaus
 * einstellen kann, das Plugin setzt selbst keine Regel dazu - kaemen die zwei
 * Pixel des Rahmens oben drauf, statt hineinzuzaehlen. Die Kachel stuende dann
 * um zwei Pixel ueber ihrer Zeile.
 */
.ctp-events.ctp-events--preset-ruhig .ctp-events__card,
.ctp-events.ctp-events--preset-ruhig .ctp-events__hero,
.ctp-events.ctp-events--preset-ruhig .ctp-events__detail-media-frame {
    box-sizing: border-box;
    border: 1px solid var(--ctp-color-border);
}

/* Das Datumsschild bringt seinen Schatten selbst mit (es liegt ueber dem
   Bild, nicht auf der Kachelflaeche) - in einem Stil ohne Schatten faellt
   genau das auf. Haarlinie statt Schatten, wie die Kachel darunter. */
.ctp-events.ctp-events--preset-ruhig .ctp-events__date-badge {
    box-shadow: none;
    border: 1px solid var(--ctp-color-border);
}

/*
 * Das Popup behält einen Schatten, obwohl --ctp-shadow hier `none` ist: Es
 * liegt über der Seite statt in ihr, und eine Haarlinie allein trennt es nicht
 * genug vom Inhalt darunter. Zurückhaltender als der Standardschatten, aber
 * vorhanden.
 */
.ctp-events.ctp-events--preset-ruhig .ctp-events__modal {
    border: 1px solid var(--ctp-color-border);
    box-shadow: 0 24px 60px -30px color-mix(in srgb, currentColor 55%, transparent);
}

/* Statt der Anhebung färbt sich der Rahmen — dieselbe Rückmeldung, ohne dass
   sich etwas bewegt. */
.ctp-events.ctp-events--preset-ruhig .ctp-events__card--clickable:hover,
.ctp-events.ctp-events--preset-ruhig .ctp-events__card--clickable:focus-within,
.ctp-events.ctp-events--preset-ruhig .ctp-events__hero--clickable:hover,
.ctp-events.ctp-events--preset-ruhig .ctp-events__hero--clickable:focus-within {
    box-shadow: none;
    transform: none;
    border-color: color-mix(in srgb, var(--ctp-accent) 55%, transparent);
}

.ctp-events.ctp-events--preset-ruhig .ctp-events__item--clickable:hover,
.ctp-events.ctp-events--preset-ruhig .ctp-events__item--clickable:focus-within {
    transform: none;
}

.ctp-events.ctp-events--preset-ruhig .ctp-events__card--clickable:hover .ctp-events__media img {
    transform: none;
}

.ctp-events.ctp-events--preset-ruhig .ctp-events__eyebrow {
    padding: 0;
    border: none;
    background: none;
}

/*
 * Warm — großzügig. Weicher Radius, ein etwas weiterer Schatten und mehr Luft
 * zwischen den Kacheln; das Kalender-Label ist gefüllt statt umrandet. Die
 * Füllung ist bewusst eine Mischung mit der Kachelfläche und nicht die
 * Akzentfarbe selbst: Kalenderfarben reichen von dunkelblau bis hellgelb, und
 * eine voll gefüllte Pille wäre bei der Hälfte davon unlesbar.
 */
.ctp-events.ctp-events--preset-warm {
    --ctp-radius: 22px;
    --ctp-gap: clamp(1.6rem, 1.8vw + 0.9rem, 2.8rem);
    --ctp-shadow: 0 2px 6px color-mix(in srgb, currentColor 6%, transparent),
        0 28px 56px -26px color-mix(in srgb, #8a6a3a 42%, transparent);
}

.ctp-events.ctp-events--preset-warm .ctp-events__eyebrow {
    border-color: transparent;
    background: color-mix(in srgb, var(--ctp-accent) 18%, var(--ctp-color-surface));
}

.ctp-events.ctp-events--preset-warm .ctp-events__card--clickable:hover,
.ctp-events.ctp-events--preset-warm .ctp-events__card--clickable:focus-within {
    transform: translateY(-5px);
}

.ctp-events.ctp-events--preset-warm .ctp-events__card--clickable:hover .ctp-events__media img {
    transform: scale(1.05);
}

/*
 * Strukturiert — redaktionell. Kein Schatten, sondern eine kräftige Kante in
 * der Kalenderfarbe an der Oberkante; Kanten und Trennlinien sind deutlicher
 * als sonst, die Ecken praktisch rechtwinklig. Das Kalender-Label wird zum
 * Balken vor dem Namen statt zur Pille.
 */
.ctp-events.ctp-events--preset-strukturiert {
    --ctp-radius: 2px;
    --ctp-radius-pill: 0px;
    --ctp-shadow: none;
    --ctp-color-border: color-mix(in srgb, currentColor 22%, transparent);
}

/* box-sizing: siehe die Begruendung bei „Ruhig" weiter oben. */
.ctp-events.ctp-events--preset-strukturiert .ctp-events__card,
.ctp-events.ctp-events--preset-strukturiert .ctp-events__hero {
    box-sizing: border-box;
    border: 1px solid var(--ctp-color-border);
    border-block-start: 3px solid var(--ctp-accent);
}

.ctp-events.ctp-events--preset-strukturiert .ctp-events__detail-media-frame {
    box-sizing: border-box;
    border: 1px solid var(--ctp-color-border);
}

/* Siehe „Ruhig": derselbe Schatten am selben Element, hier zusaetzlich
   rechtwinklig statt abgerundet. */
.ctp-events.ctp-events--preset-strukturiert .ctp-events__date-badge {
    box-shadow: none;
    border: 1px solid var(--ctp-color-border);
}

/* Siehe die Begründung beim Popup von „Ruhig" — hier zusätzlich mit der
   Akzentkante, die in diesem Stil jede Fläche trägt. */
.ctp-events.ctp-events--preset-strukturiert .ctp-events__modal {
    border: 1px solid var(--ctp-color-border);
    border-block-start: 3px solid var(--ctp-accent);
    box-shadow: 0 24px 60px -30px color-mix(in srgb, currentColor 55%, transparent);
}

/* Ueber :not(:last-child) statt ueber die Grundregel plus deren
   :last-child-Ausnahme: Die Ausnahme wiegt eine Klasse weniger als diese Regel
   und wuerde sonst verlieren - die letzte Zeile bekaeme einen Trenner, unter
   dem nichts mehr folgt. */
.ctp-events.ctp-events--preset-strukturiert .ctp-events__item:not(:last-child) {
    border-block-end: 1px solid color-mix(in srgb, currentColor 25%, transparent);
}

.ctp-events.ctp-events--preset-strukturiert .ctp-events__title {
    font-weight: 700;
}

.ctp-events.ctp-events--preset-strukturiert .ctp-events__eyebrow {
    padding: 0 0 0 0.55rem;
    border: none;
    border-inline-start: 3px solid var(--ctp-accent);
    background: none;
}

/* Keine Bewegung, stattdessen faerbt sich die Flaeche eine Spur in der
   Kalenderfarbe und die Oberkante wird kraeftiger. */
.ctp-events.ctp-events--preset-strukturiert .ctp-events__card--clickable:hover,
.ctp-events.ctp-events--preset-strukturiert .ctp-events__card--clickable:focus-within,
.ctp-events.ctp-events--preset-strukturiert .ctp-events__hero--clickable:hover,
.ctp-events.ctp-events--preset-strukturiert .ctp-events__hero--clickable:focus-within {
    box-shadow: none;
    transform: none;
    background: color-mix(in srgb, var(--ctp-accent) 5%, var(--ctp-color-surface));
}

.ctp-events.ctp-events--preset-strukturiert .ctp-events__item--clickable:hover,
.ctp-events.ctp-events--preset-strukturiert .ctp-events__item--clickable:focus-within {
    transform: none;
    background: color-mix(in srgb, var(--ctp-accent) 5%, transparent);
}

.ctp-events.ctp-events--preset-strukturiert .ctp-events__card--clickable:hover .ctp-events__media img {
    transform: none;
}
