/* Marker-Klassen entfernt (2026-08-10). Der Inhalt kommt jetzt als EIN RTE;
 * die Typografie liefern die Basis-Absatzstile (h3/h4, p, caption,
 * caption-sub). Grund siehe TEMPL_MASTER: Typografie-Variation innerhalb
 * eines Content-Blocks gehoert nicht in getrennte Marker-Slots, weil TipTap
 * Custom-Klassen beim Reinklicken re-normalisiert.
 * Die Patterns waren 2026-07-24 migriert worden, die Molecules nicht — das
 * hat der Drift-Abgleich heute aufgedeckt. */
/* Molecule: article-card
 * Blog-/Artikel-Card mit Cover-Bild, Kategorie, Titel, Excerpt, Meta.
 */

.mypage .molecule.article-card {
  /* Kein Padding (2026-08-10): das Bild soll buendig an die Kartenkante
   * reichen, den Innenabstand bringt `article-card-body` mit. Ohne diese
   * Zeile greift `.card { padding: 1.25rem 1.5rem }` aus em-components.
   * Gleiche Begruendung wie bei team-card. */
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  height: 100%;
}

.mypage .molecule.article-card > picture[type='picture'] {
  /* Ohne `!important` (Stufe 4, Batch 4e, 2026-08-09): am DOM gemessen auf der
   * All-Pattern-Seite (6 Elemente in story_3cards und story_featured_3cards) —
   * `block` vor wie nach dem Entflaggen. Kein Gegenspieler. */
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.mypage .molecule.article-card > picture[type='picture'] img,
.mypage .molecule.article-card .article-card-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.mypage .molecule.article-card .article-card-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  /* Der Innenabstand der Karte (2026-08-10). Seit die Karte selbst
   * `padding: 0` traegt (damit das Cover buendig an die Kante reicht), MUSS
   * ihn der Body zurueckholen — sonst laeuft der Text bis an den Kartenrand.
   * Genau das war der Fall: der Kommentar oben versprach den Innenabstand,
   * die Regel lieferte ihn nie, und die Templates brachten nur `py-3` mit
   * (vertikal). Gemessen in story_featured_3cards: padding 24px 0px, Headline
   * buendig mit der Bildkante.
   * Der Wert ist bewusst derselbe wie in `.card` (em-components) — die Karte
   * gibt ihr Padding nach innen weiter, statt einen zweiten Wert zu erfinden. */
  padding: 1.25rem 1.5rem;
}






/* ─────────────────────────────────────────────────────────────────
 * Variante: compact
 * Bild 3:2 (weniger Vertikalraum), Excerpt ausgeblendet.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.article-card--compact > picture[type='picture'] {
  aspect-ratio: 3 / 2;
}



/* ─────────────────────────────────────────────────────────────────
 * Variante: minimal
 * Kein Bild, kein Card-Rahmen. Akzent: linker Balken in Primärfarbe.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.article-card--minimal {
  background: transparent;
  box-shadow: none;
  border-radius: 0;
  border-left: 3px solid var(--primary-base);
  padding-left: 1rem;
}

/* off-screen statt display:none — lazy-loaded Bilder müssen sichtbar
 * sein um zu laden; chromedp wartet auf naturalWidth > 0, sonst Timeout
 * im Preview-Renderer. */
.mypage .molecule.article-card--minimal > picture[type='picture'] {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}


/* padding ohne Flag (Stufe 4c, Rest, 2026-07-30): die Basis-Regel
 * `.molecule.article-card .article-card-body` setzt gar kein padding (nur
 * flex-Eigenschaften) — kein Gegenspieler auf dieser Property. Geprueft:
 * story_3cards definiert eine eigene `.article-card-body` mit padding, aber
 * in einem anderen Namespace (`.story_3cards .article-card`, kein
 * `.molecule.avatar...`-Bezug) — betrifft nie dasselbe Element. Flag war
 * reine Vorsicht. */
.mypage .molecule.article-card--minimal .article-card-body {
  padding: 0.5rem 0;
}


/* avatar-stack — überlappende Kreis-Avatare + optionale Trust/Rating-Zeile.
 * Kanonische Quelle (Backport 2026-07-28, gehoben aus trust_avatars_stars).
 * Patterns kopieren die Struktur + reusen diese Klassen (class="molecule avatar-stack"). */
.mypage .molecule.avatar-stack {
  text-align: center;
  /* Groesse und Overlap als Variablen (2026-08-10). Der Overlap ist jetzt ein
   * ANTEIL der Avatar-Breite, kein absoluter Wert mehr. Vorher stand ein fixes
   * `-0.4rem` am Bild: bei 3rem grossen Avataren sind das 13% Ueberlappung,
   * bei den 5rem grossen von trust_avatars_color nur 6,7% — dieselbe
   * Deklaration, zwei verschiedene Optiken, und die groesseren sahen aus als
   * wuerden sie sich bloss beruehren. Der Kommentar in
   * trust_avatars_color/pattern.css hatte genau davor gewarnt und die
   * Entscheidung offen gelassen.
   * Ein Pattern setzt jetzt nur noch `--avatar-size`; der Overlap folgt
   * proportional und kann nicht mehr auseinanderlaufen. */
  --avatar-size: 3rem;
  --avatar-overlap: 0.25;
}

/* avatar-row: horizontale Reihe, Overlap via negativem Margin am img (unten).
 *
 * `display` braucht hier KEIN !important (Stand Batch 4e, 2026-08-07). Kurz
 * zuvor trug es eines, weil die Basis-Regel der Molecule-Engine
 *   `.mypage .molecule > section[type='layer'] { display: block !important }`
 * (em-components.css) diese Reihe als `section[type="layer"]` direkt unter
 * `.molecule` mit erfasste — und ein !important schlaegt ein nicht-!important
 * unabhaengig von der Spezifitaet. In Batch 4e ist dieses Basis-Flag gefallen,
 * seither gewinnt diese Deklaration per Spezifitaet allein: (0,4,0) gegen
 * (0,3,1). Deshalb hier ersatzlos entfernt.
 *
 * Warum das ueberhaupt wichtig ist: als Block-Container waren `gap` UND
 * `justify-content` wirkungslos (beide gelten nur in Flex-/Grid-Containern).
 * Sichtbar wurde es an trust_avatars_color, das den Overlap aufhob und den
 * Abstand ueber `gap` wollte — gemessen 0px, die Avatare standen auf Kante.
 * Die Overlap-Varianten fielen nicht auf, weil ihr Abstand aus
 * `margin-right: -0.4rem` am Bild kommt und Margins auch im Block-Container
 * wirken. Belegt in tools/avatar-gap-lab.html.
 *
 * Setzt jemand das Basis-Flag wieder, faellt diese Reihe still auf Block
 * zurueck und der Fehler ist zurueck. Der Kommentar an der Basis-Regel warnt
 * entsprechend. */
.mypage .molecule.avatar-stack .avatar-row {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0;
  padding: 1rem 0;
}
/* Picture-Wrapper kollabieren, damit die IMG-Regeln pur greifen. */
.mypage .molecule.avatar-stack .avatar-row picture { display: contents; }

/* Mini-Kreis-Thumbnails, überlappend. Klasse+Element-Selektor schlägt .mypage img
 * ohne !important (höhere Spezifität). Leere Slots rendern kein <img> → kein Loch. */
.mypage .molecule.avatar-stack img.trust-avatar,
.mypage .molecule.avatar-stack .trust-avatar {
  width: var(--avatar-size);
  height: var(--avatar-size);
  min-width: var(--avatar-size);
  max-width: var(--avatar-size);
  /* max-height mitgesetzt: em-components cappt Bilder in dieser Umgebung auf
   * 3rem — ohne das Override werden groessere Avatare oval. Bisher musste das
   * jedes Pattern selbst nachziehen (trust_avatars_color tat es). */
  max-height: var(--avatar-size);
  border-radius: 50%;
  object-fit: cover;
  display: inline-block;
  margin: 0 calc(var(--avatar-size) * var(--avatar-overlap) * -1) 0 0;
  border: 2px solid var(--color-bg, #fff);
  box-shadow: 0 2px 6px color-mix(in srgb, var(--shade-dark-base, #1a3453) 12%, transparent);
  vertical-align: middle;
}

/* Trust-Strip: Sterne + Rating/Count-Zeile. */
.mypage .molecule.avatar-stack .scene-trust-strip { margin-top: .25rem; }
.mypage .molecule.avatar-stack .stars {
  color: var(--star-color, #f5a623);
  letter-spacing: 2px;
  font-size: 1.1rem;
  line-height: 1;
}
.mypage .molecule.avatar-stack .trust-strip-text {
  color: var(--text-muted, #5b6b7f);
  font-size: .95rem;
}

/* Marker-Klassen entfernt (2026-08-10). Der Inhalt kommt jetzt als EIN RTE;
 * die Typografie liefern die Basis-Absatzstile (h3/h4, p, caption,
 * caption-sub). Grund siehe TEMPL_MASTER: Typografie-Variation innerhalb
 * eines Content-Blocks gehoert nicht in getrennte Marker-Slots, weil TipTap
 * Custom-Klassen beim Reinklicken re-normalisiert.
 * Die Patterns waren 2026-07-24 migriert worden, die Molecules nicht — das
 * hat der Drift-Abgleich heute aufgedeckt. */
/* Molecule: benefit-item */
.mypage .molecule.benefit-item {
  display: flex;
  flex-direction: column;
  align-items: center;   /* zentriert die (jetzt direkten) Flex-Kinder inkl. Icon
                            — nötig seit dem Flatten (wie step-card); text-align allein
                            zentriert nur Inline-Text, nicht die Flex-Items selbst. */
  height: 100%;
  text-align: center;
}

.mypage .molecule.benefit-item .benefit-icon {
  margin-bottom: 1rem;
  flex-shrink: 0;
  color: var(--primary-base);    /* currentColor for the inline SVG */
}



/* ─────────────────────────────────────────────────────────────────
 * Variante: icon-left
 * Icon links neben dem Text (horizontal). Text wird links-bündig.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.benefit-item--icon-left {
  flex-direction: row;
  align-items: flex-start;
  text-align: left;
  gap: 1rem;
}

.mypage .molecule.benefit-item--icon-left .benefit-icon {
  margin-bottom: 0;
  flex-shrink: 0;
  width: 2.5rem;
}

/* Body bekommt eigene flex-column für headline + desc */
.mypage .molecule.benefit-item--icon-left .benefit-icon ~ * {
  text-align: left;
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: numbered
 * Icon-Bereich wird zur Zahl-Bubble in Primärfarbe.
 * (Das Icon-Slot bleibt im Template — falls nur Text/Symbol drin steht,
 *  wirkt es als Number; das Icon-SVG wird durch CSS umgestaltet.)
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.benefit-item--numbered .benefit-icon {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--primary-base);
  color: var(--text-light);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 1rem;
  font-family: var(--h2-font-family, inherit);
  font-size: 1.5rem;
  font-weight: 700;
}

/* Wenn ein inline-SVG drin ist (Icon-Slot mit echtem Icon-Key): Größe
 * anpassen, weiße Füllung erzwingen. */
.mypage .molecule.benefit-item--numbered .benefit-icon svg {
  width: 1.5rem;
  height: 1.5rem;
  fill: var(--text-light);
  color: var(--text-light);
}

/* Molecule: cta-block
 *
 * Aufraeumung 2026-08-10. Vorher enthielt diese Datei drei Parallel-
 * Implementierungen, die alle gegen die Basis gearbeitet haben:
 *
 * 1. H-Typografie: `.cta-content h2, h3 { font-size: clamp(1.75rem, 4vw,
 *    3.5rem) }`. Damit war eine H3 im CTA-Block groesser als die H2 der
 *    Section darueber — in cta_block_split sichtbar geworden. H-Groessen
 *    gehoeren nach em-base (CLAUDE.md: „H-Tag-Typografie gehoert NICHT in
 *    pattern.css"). Ersatzlos entfallen.
 * 2. Fliesstext: `p { font-size: 1.25rem }` hat die Absatzstile der Basis
 *    ueberschrieben, inklusive `subline`. Entfallen; geblieben ist nur die
 *    Zeilenlaengen-Begrenzung, die eine Layout- und keine Typo-Entscheidung
 *    ist.
 * 3. Button: `.cta-action .btn-primary` hat `.btn-wrap` aus em-components
 *    nachgebaut, mit anderem Radius (0.5rem statt --radius-md), anderer
 *    Farbquelle (--primary-base statt der CTA-Kette der ProjectSettings) und
 *    eigener Schriftgroesse. Entfallen — die Patterns nutzen jetzt den
 *    echten `.btn-wrap`.
 *
 * Die Legacy-Klassen `.cta-headline`/`.cta-subtext` sind ebenfalls raus:
 * kein Template referenziert sie.
 */
.mypage .molecule.cta-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 100%;
  text-align: center;
}

/* Zeilenlaenge: zentrierter Text ueber die volle Spaltenbreite ist nicht
 * lesbar. Die Begrenzung gilt fuer den Fliesstext, nicht fuer die
 * Ueberschrift — die darf breiter laufen. */
.mypage .molecule.cta-block .cta-content p {
  max-width: 34em;
  margin-left: auto;
  margin-right: auto;
}

/* Abstandskette: Text -> Button -> Hinweiszeile. Der Button bringt aus
 * `.btn-wrap` bereits 0.25rem Eigenabstand mit, deshalb hier 1.25rem
 * statt der vollen Leiterstufe. */
/* Abstand entfaellt hier (2026-08-10): er kommt jetzt aus `--cta-gap` in
 * em-components (`.col-12:has(> a.btn-wrap) { margin-top: var(--cta-gap, 2rem) }`),
 * damit „Inhalt -> Handlung" ueberall dasselbe Mass hat. Blieben die 1.25rem
 * hier stehen, addierten sie sich auf 52px. Wer fuer diese Molecule ein
 * anderes Mass will, setzt `--cta-gap` — nicht wieder ein eigenes margin. */

.mypage .molecule.cta-block .cta-secondary {
  margin-top: 0.5rem;
  color: var(--text-muted);
}

.mypage .molecule.cta-block .cta-secondary a {
  color: inherit;
  text-decoration: underline;
}

/* Flex-item shrink safety: align-items:center on the parent would
 * leave direct children at their intrinsic (content) width, which breaks
 * long headlines inside narrow grid columns (e.g. col-8 at desktop). The
 * combination below lets text wrap while keeping the visual centering. */
.mypage .molecule.cta-block > * {
  max-width: 100%;
  min-width: 0;
}

/* Molecule: download-card
 * Layout: Icon links | Titel/Meta mittig | Button rechts.
 * Variants: default (card), compact (listenzeile), highlight (akzent).
 */

/* CSS Grid statt Flex: deterministische 3-Spalten Anordnung
 * (Icon | Body | Action). Width-Verteilung explizit via grid-template-columns,
 * keine flex-basis-Berechnungen die mit inline-block-Defaults aus
 * em-components kollidieren. */
.mypage section[type='layer'].molecule.download-card {
  /* Zeile aus Icon | Text | Button — als FLEX, nicht als Grid (2026-08-09).
   *
   * Vorgeschichte, damit niemand auf Grid zurueckbaut: die Karte war als
   * `display: grid !important` mit `grid-template-columns: auto minmax(0,1fr)
   * auto` gebaut. Das funktioniert NUR ausserhalb des Rasters. Sobald ein
   * Pattern die Karte normal einsetzt, traegt sie eine `col-N`-Klasse, und
   * dann greift Regel 3 der Grid-Engine (em-components.css):
   *   `.mypage section[type='layer'].col-12:has(> …col-N) > section[type='layer'].col-N
   *    { display: flex !important; flex-direction: column }`
   * Deren Spezifitaet liegt bei rund (0,7,3) — gegen (0,3,1) hier hilft auch
   * ein eigenes !important nicht, weil dann die Spezifitaet entscheidet.
   * Ergebnis war: Karte gestapelt statt dreispaltig. Aufgefallen erst, als
   * content_downloads_3 die Molecule zum ersten Mal wirklich im Raster nutzte.
   *
   * Loesung: mit der Engine arbeiten statt gegen sie. `display: flex` ist
   * ohnehin das, was sie erzwingt — und `flex-direction` traegt sie NICHT
   * geflaggt, dort gewinnt die Molecule per !important. Die Spaltenbreiten
   * uebernehmen die Kinder per flex (unten): auto | 1fr | auto, also genau
   * das, was grid-template-columns vorher beschrieb.
   * Gleicher Kniff wie bei social-strip und team-card--landscape. */
  display: flex;
  flex-direction: row !important;
  align-items: center;
  gap: 1rem;
  text-align: left;
  width: 100%;
}


.mypage section[type='layer'].molecule.download-card > section[type='layer'].download-card-icon,
.mypage section[type='layer'].molecule.download-card > section[type='layer'].download-card-action {
  /* Ohne `!important` (Batch 4e, im echten Raster nachgemessen): `flex` vor wie
   * nach dem Entflaggen. Der Flex-Container darueber blockifiziert seine Kinder
   * ohnehin, die inline-block-Defaults aus em-components greifen hier also nicht. */
  display: flex;
  align-items: center;
  /* Spalte 1 und 3 des frueheren Grids: inhaltsbreit, nicht mitwachsend.
   * `width: auto` ist dabei Pflicht: die Layer-Kinder erben `width: 100%`,
   * und als Flex-Item heisst das 100% der KARTE — der Action-Container war
   * dadurch 320px breit (bei 127px Buttoninhalt) und quetschte den Text auf
   * Breite 0. Im Grid fiel das nicht auf, weil sich 100% dort auf die
   * Grid-Zelle bezog, nicht auf den Container. */
  flex: 0 0 auto;
  width: auto;
}

.mypage section[type='layer'].molecule.download-card > section[type='layer'].download-card-body {
  /* Ohne `!important` (Batch 4e, gemessen auf /molecules-check): `block` vor wie
   * nach dem Entflaggen. */
  display: block;
  /* Spalte 2 des frueheren Grids: nimmt den Rest. `flex-basis: 0` statt `auto`,
   * damit die Verteilung vom freien Raum ausgeht und nicht von der
   * Inhaltsbreite — sonst konkurriert der Titel mit dem Button um Platz. */
  flex: 1 1 0;
  min-width: 0;
  width: auto;
}

.mypage .molecule.download-card .download-card-icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  color: var(--primary-base);
}

.mypage .molecule.download-card .download-card-icon .icon {
  width: 1.75rem;
  height: 1.75rem;
  fill: currentColor;
}

.mypage .molecule.download-card .download-card-body {
  flex: 1 1 auto;
  min-width: 0;
}

.mypage .molecule.download-card .download-card-body-text .caption {
  font-family: var(--h5-font-family, inherit);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.3;
  /* margin entfaellt (2026-08-10): hier standen 0.15rem = 2,4px, der einzige
   * typografische Abstand im ganzen System, der nach der Abstands-Runde noch
   * neben der Leiter lag (0.15em statt 0.25em, in acht Captions der drei
   * Download-Patterns). Der Basis-Default `.mypage p.caption` liefert die
   * 0.25em selbst — eine Quelle statt eines rem-Rests. */
  /* Lange Dateinamen umbrechen statt überlaufen */
  word-break: break-word;
}

.mypage .molecule.download-card .download-card-body-text .caption-sub {
  font-size: 0.8rem;
  color: var(--text-muted);
  letter-spacing: 0.02em;
  margin: 0;
}

.mypage .molecule.download-card .download-card-action {
  flex: 0 0 auto;
}

.mypage .molecule.download-card .download-card-btn {
  white-space: nowrap;
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: compact — Listen-Zeile ohne Card-Hülle, Meta versteckt,
 * Button wird zu kleinem Pfeil-Icon.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.download-card--compact {
  background: transparent;
  box-shadow: none;
  border-radius: 0;
  border-bottom: 1px solid color-mix(in srgb, currentColor 10%, transparent);
  padding: 0.75rem 0;
  gap: 0.75rem;
}

.mypage .molecule.download-card--compact .download-card-icon {
  width: 2rem;
  height: 2rem;
}

.mypage .molecule.download-card--compact .download-card-icon .icon {
  width: 1.25rem;
  height: 1.25rem;
}

/* Die compact-Variante blendet die Format-/Groessenzeile aus. Nach der
 * Migration auf einen RTE ist das die caption-sub-Zeile darin — der Selektor
 * musste mitwandern, sonst zeigt compact ploetzlich die Meta-Angabe. */
.mypage .molecule.download-card--compact .download-card-body-text .caption-sub {
  display: none;
}

.mypage .molecule.download-card--compact .download-card-btn {
  /* Kleiner Pfeil-Look statt Primary-Button. Reine CSS, kein Markup-
   * Wechsel — der Anchor bleibt strukturell der gleiche. */
  background: transparent;
  color: var(--primary-base);
  padding: 0.25rem 0.5rem;
  font-weight: 600;
}

.mypage .molecule.download-card--compact .download-card-btn::after {
  content: ' →';
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: highlight — Akzent-Hintergrund (Primärfarbe sehr hell),
 * gewichtigerer Button.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.download-card--highlight {
  background: var(--primary-light);
  border: 1px solid color-mix(in srgb, var(--primary-base) 20%, transparent);
}

.mypage .molecule.download-card--highlight .download-card-body-text .caption {
  font-size: 1.05rem;
}

.mypage .molecule.download-card--highlight .download-card-btn {
  padding: 0.625rem 1.25rem;
  font-size: 0.95rem;
}

/* Schmal-Breakpoint: bei Container < 320 px stapelt sich Icon | Body
 * über den Button — Button füllt die volle Breite (mobil-freundlich). */
@container (max-width: 320px) {
  .mypage .molecule.download-card {
    flex-wrap: wrap;
  }
  .mypage .molecule.download-card .download-card-action {
    flex-basis: 100%;
  }
  .mypage .molecule.download-card .download-card-btn {
    width: 100%;
    text-align: center;
  }
}

/* Molecule: faq-row
 * Frage + Antwort, akkordeon-fähig (visuell). Per Default ist die
 * Antwort sichtbar — eine optionale Section-Klasse `.faq-collapsed`
 * blendet alle Antworten aus und das Klick-Toggle (eg. via Mini-JS
 * an der Section) entscheidet wer offen ist.
 */
.molecule.faq-row {
  border-top: 1px solid var(--shade-lightgray);
  padding-top: 1rem;
  padding-bottom: 1rem;
}

.molecule.faq-row:first-child {
  border-top: none;
}

.molecule.faq-row .faq-question {
  display: block;
  font-family: var(--h4-font-family, inherit);
  font-size: var(--h4-font-size, 1.05rem);
  font-weight: var(--h4-font-weight, 600);
  line-height: 1.35;
  color: var(--text-dark);
  position: relative;
}

/* Das "+" und der Zeiger-Cursor sind an den Akkordeon-Modus gebunden
 * (2026-08-10). Vorher trug JEDE faq-row ein "+" und `cursor: pointer`, auch
 * die statischen Zeilen-Patterns, in denen die Antwort ohnehin offen steht:
 * ein Klick-Versprechen, das nichts einloest. Aufgefallen an
 * faq_rows_stacked/faq_rows_2col — dort war das "+" reine Dekoration.
 * Wer ein Akkordeon will, nimmt faq_collapsible / faq_2col_collapsible; die
 * bauen auf nativem <details>/<summary> und brauchen kein JS. Die Regeln hier
 * bleiben fuer Patterns, die `.faq-collapsed` setzen und das Auf-/Zuklappen
 * selbst steuern. */
.faq-collapsed .molecule.faq-row .faq-question {
  cursor: pointer;
  padding-right: 2rem;
}

.faq-collapsed .molecule.faq-row .faq-question::after {
  content: "+";
  position: absolute;
  right: 0;
  top: 0;
  font-weight: 400;
  font-size: 1.4em;
  line-height: 1;
  opacity: 0.5;
  transition: transform 0.18s ease;
}

.faq-collapsed .molecule.faq-row.open .faq-question::after {
  content: "−";
  opacity: 1;
}

.molecule.faq-row .faq-answer {
  margin-top: 0.6rem;
  font-family: var(--bodytext-font-family, inherit);
  line-height: 1.65;
  color: var(--text-muted);
}

.molecule.faq-row .faq-answer p:first-child {
  margin-top: 0;
}
.molecule.faq-row .faq-answer p:last-child {
  margin-bottom: 0;
}

/* Collapsed-mode (Section trägt .faq-collapsed) — Antworten standardmäßig
 * versteckt; nur expandiert wenn .faq-row .open gesetzt ist (per JS oder
 * statisch im Markup). */
.faq-collapsed .molecule.faq-row .faq-answer {
  display: none;
}
.faq-collapsed .molecule.faq-row.open .faq-answer {
  display: block;
}

/* Molecule: feature-card */
.mypage .molecule.feature-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  /* Kein Padding auf der Karte (2026-08-10) — dieselbe Doktrin wie
   * article-card und team-card: das Cover reicht buendig an die Kante, den
   * Innenabstand bringen die Textkinder mit. Der Beleg, dass die Karte es
   * ohnehin nie brauchte: das Bild trug bereits `border-radius: 8px 8px 0 0`,
   * also die Rundung der Kartenoberkante — gedacht war es immer buendig, das
   * Padding von `.card` hat es nur um 16/24px nach innen geschoben.
   * Das `py-2` im Template ist dabei mit entfallen: Utilities tragen
   * !important und haetten diese Zeile ueberstimmt. */
  padding: 0;
}

/* Innenabstand der Textkinder, gleicher Wert wie `.card` in em-components.
 * `.card-image`/`.card-body` gibt es nur in diesem einen Pattern
 * (offer_services_slider) — die Molecule-Regeln darunter sprechen noch von
 * `.feature-image`/`.feature-content` und greifen dort nie. */
.mypage .molecule.feature-card > .card-body {
  padding: 1.25rem 1.5rem 0;
}
.mypage .molecule.feature-card > .btn-wrap {
  margin-left: 1.5rem;
  margin-right: 1.5rem;
  margin-bottom: 1.25rem;
}

.mypage .molecule.feature-card .feature-image {
  flex-shrink: 0;
  margin-bottom: 1rem;
}

.mypage .molecule.feature-card .feature-image img {
  width: 100%;
  height: auto;
  aspect-ratio: 16/9;
  object-fit: cover;
  border-radius: 0.5rem;
}

/* RTE content container */
.mypage .molecule.feature-card .feature-content h3,
.mypage .molecule.feature-card .feature-content h4 {
  font-family: var(--h4-font-family);
  font-size: var(--h4-font-size);
  font-weight: var(--h4-font-weight);
  line-height: var(--h4-font-lineheight);
  margin-bottom: 0.5rem;
}

.mypage .molecule.feature-card .feature-content p {
  font-family: var(--bodytext-font-family);
  line-height: 1.6;
  color: var(--text-muted);
}

/* Legacy class support */
.mypage .molecule.feature-card .feature-headline {
  font-family: var(--h4-font-family);
  font-size: var(--h4-font-size);
  font-weight: var(--h4-font-weight);
  line-height: var(--h4-font-lineheight);
  margin-bottom: 0.5rem;
}

.mypage .molecule.feature-card .feature-desc {
  font-family: var(--bodytext-font-family);
  line-height: 1.6;
  color: var(--text-muted);
}

/* Molecule: footer-block */
.mypage .molecule.footer-block {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-align: center;
  padding: var(--space-lg, 3rem) 0;
  gap: 1rem;
  /* Haarlinie aus `currentColor`, nicht aus `--text-dark` (2026-08-10). Auf
   * dunklem Grund (sc-dark, foot_block_dark) war eine Linie aus 8% Dunkelgrau
   * praktisch unsichtbar — dieselbe Ueberlegung, die beim Link-Hover unten
   * schon dokumentiert ist. `currentColor` folgt der Textfarbe, die das
   * sc-*-Paar kontextkorrekt setzt, und funktioniert damit auf beiden Gruenden. */
  border-top: 1px solid color-mix(in srgb, currentColor 14%, transparent);
  line-height: 1.6;
}

.mypage .molecule.footer-block .footer-company {
  /* font-size via txt-lg Klasse im JSON */
  font-weight: 700;
  margin-bottom: 0.25rem;
}

.mypage .molecule.footer-block .footer-desc {
  font-size: 0.9rem;
  color: var(--text-muted);
  max-width: 500px;
  margin: 0 auto;
  line-height: 1.5;
}

.mypage .molecule.footer-block .footer-links {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1.5rem;
  padding: 0.5rem 0;
}

.mypage .molecule.footer-block .footer-links a {
  font-size: 0.9rem;
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.15s;
}

.mypage .molecule.footer-block .footer-links a:hover {
  /* Hover = volle Section-Textfarbe (sc-* setzt sie kontextkorrekt).
   * inherit statt text-dark, sonst dunkler Hover auf dunklem Footer. */
  color: inherit;
}

.mypage .molecule.footer-block .footer-copyright {
  margin-top: 0.5rem;
  padding-top: 1rem;
  font-size: 0.8rem;
  color: var(--text-muted);
  /* siehe oben: currentColor statt --text-dark, sonst auf dunkel unsichtbar */
  border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent);
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: split — Identitaet links, Rechtslinks rechts.
 *
 * WICHTIG: setzt die Basisklasse voraus (`molecule footer-block
 * footer-block--split`). Gleiche Konvention wie team-card--circle und
 * logo-row--color; mit der Variante allein greift keine Basis-Regel.
 *
 * Warum die Variante existiert (2026-08-10): die Basis-Molecule ist fuer EINE
 * zentrierte Spalte gebaut — `text-align: center`, `.footer-desc { margin: 0
 * auto }`, `.footer-links { justify-content: center }`. `foot_block_dark`
 * wollte laut Beschreibung linksbuendig sein, hatte aber keine einzige Regel
 * dafuer. Ergebnis: Firmenname und Copyright standen links, Beschreibung und
 * Linkzeile zentriert — zwei der vier Zeilen setzten sich durch, zwei nicht.
 * Zentrieren per text-align laesst sich naemlich nicht durch Vererbung
 * zuruecknehmen, wenn die Kinder ihre Mitte ueber `margin: auto` bzw.
 * `justify-content` selbst herstellen. Beides muss explizit gekippt werden.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.footer-block--split {
  text-align: left;
}
.mypage .molecule.footer-block--split .footer-desc {
  /* `margin: 0 auto` der Basis zuruecknehmen — sonst bleibt der Textblock
   * mittig, obwohl text-align links steht. */
  margin-left: 0;
  margin-right: 0;
}
.mypage .molecule.footer-block--split .fb-split-row {
  align-items: baseline;
}
.mypage .molecule.footer-block--split .footer-links {
  /* Linkzeile an die rechte Kante, rechtsbuendig umbrechend. Die Basis
   * zentriert; hier nutzt die Zeile die Breite, die der Firmenblock uebrig
   * laesst. `padding: 0.5rem 0` der Basis entfaellt, weil die Zeile jetzt
   * neben dem Firmennamen sitzt und nicht darunter. */
  justify-content: flex-end;
  padding: 0;
}

/* Molecule: footer-legal — die Rechtsleiste jedes Footers.
 *
 * WARUM ES DIESE MOLECULE GIBT (Konsolidierung 2026-08-10):
 * Impressum und Datenschutz sind in jedem Footer Pflicht — sie entstehen beim
 * Anlegen eines Projekts als Seed-Seiten (/impressum, /datenschutz). Vorher war
 * diese Zeile in dreizehn Templates dreizehnmal von Hand gebaut, und zwei davon
 * hatten sie gar nicht (foot_3col, foot_horizontal_compact). Als Molecule ist
 * die Regel eine Eigenschaft des Systems: ein neuer Footer kann sie nicht mehr
 * vergessen, und eine Aenderung an der Leiste gilt sofort ueberall.
 *
 * GESTALTUNGSABSICHT: das ist die LEISESTE Stufe des Footers und seine letzte
 * Zeile. Sie ist durch eine Haarlinie abgesetzt, klein gesetzt und gedaempft.
 * Links stehen die Pflichtangaben (das Handlungsfaehige, wird zuerst gelesen),
 * rechts das Copyright (die Fussnote). Auf schmalen Breiten stapelt sie und
 * bleibt linksbuendig — rechtsbuendiger Text unter linksbuendigem Text liest
 * sich als Fehler.
 *
 * Alle Farben aus `currentColor`, nie aus `--text-dark`: die Leiste muss auf
 * hellem UND dunklem Grund funktionieren, weil „dunkel" eine Einstellung am
 * Abschnitt ist (sc-dark) und kein eigenes Pattern. Genau daran ist die
 * Haarlinie der footer-block-Molecule vorher gescheitert (8% Dunkelgrau auf
 * dunklem Grund = unsichtbar).
 */
.mypage .molecule.footer-legal {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 2rem;
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid color-mix(in srgb, currentColor 12%, transparent);
  font-size: 0.8rem;
  line-height: 1.5;
}

/* Pflichtangaben links. `flex: 1 1 auto` mit min-width 0, damit lange Listen
 * umbrechen statt die Zeile zu sprengen. */
.mypage .molecule.footer-legal .footer-legal-links {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
}

.mypage .molecule.footer-legal .footer-legal-links a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, currentColor 30%, transparent);
  padding-bottom: 1px;
}
.mypage .molecule.footer-legal .footer-legal-links a:hover {
  border-bottom-color: currentColor;
}

/* Copyright und optionale Notiz rechts, in Leserichtung: Notiz, dann
 * Copyright als letztes. `flex: 0 1 auto` — sie geben Platz ab, bevor die
 * Pflichtangaben umbrechen muessen. */
.mypage .molecule.footer-legal .footer-legal-meta,
.mypage .molecule.footer-legal .footer-legal-note {
  flex: 0 1 auto;
  text-align: right;
  opacity: 0.75;
}

/* Leere Notiz nimmt keinen Platz und erzeugt keine Luecke im gap. */
.mypage .molecule.footer-legal .footer-legal-note:empty {
  display: none;
}

@media (max-width: 640px) {
  .mypage .molecule.footer-legal {
    flex-direction: column;
    align-items: flex-start;
  }
  .mypage .molecule.footer-legal .footer-legal-meta,
  .mypage .molecule.footer-legal .footer-legal-note {
    text-align: left;
  }
}

/* Molecule: header-nav — Navigation plus das MOBILE Menü.
 *
 * WARUM ES DIESE MOLECULE GIBT (2026-08-10):
 * Fünf der sechs Header-Patterns versteckten ihre Navigation unter 767px per
 * `display: none` und holten sie nur über `.head-mobile-open` zurück — eine
 * Klasse, die NIEMAND gesetzt hat. Sie kam in beiden Repos ausschliesslich in
 * CSS vor: kein Burger-Markup, kein JavaScript. Auf dem Telefon hatten diese
 * Header also keine erreichbare Navigation, und jeder von ihnen trug seine
 * eigene Kopie dieser toten Mechanik (fuenfmal derselbe Media-Query).
 *
 * Jetzt liegt beides an einer Stelle: das Aussehen hier, das Verhalten in
 * `renderer/headnav.go` (`headNavJS`, konditional emittiert, sobald die Seite
 * eine header-nav enthaelt). Damit kann kein neuer Header das Mobilmenü
 * vergessen — dieselbe Ueberlegung wie bei footer-legal.
 *
 * Der Zustand haengt an der MOLECULE (`.head-nav-open`), nicht an der
 * Pattern-Wurzel. Vorher war er an die Wurzelklasse gebunden
 * (`.head_simple.head-mobile-open`) und musste deshalb pro Pattern erneut
 * geschrieben werden.
 *
 * MARKUP, das ein Pattern kopiert (Struktur im Template, Klassen von hier):
 *   <layer class="molecule header-nav">
 *     <button class="head-nav-toggle" aria-label="Menü" aria-expanded="false">
 *     <html  class="head-nav-slot" slot="menu-h">
 *   </layer>
 */
.mypage .molecule.header-nav {
  /* `relative` ist tragend: das Mobil-Panel haengt sich per `absolute` an DIESE
   * Box. Das alte CSS ankerte an der Header-Sektion und funktionierte nur,
   * solange die zufaellig positioniert war (bei den Overlay-Headern war sie es,
   * bei den anderen nicht). */
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: 1rem;
}

/* Der Umschalter ist ab Desktop unsichtbar — die Navigation steht ja da.
 *
 * Er steckt in einem html-Knoten (`.head-nav-toggle-wrap`) und NICHT in einem
 * `key: "button"`-Knoten: das ist im Renderer kein einfacher Knopf, sondern ein
 * PLUGIN-AUSLOESER — er bekommt ein `onclick`, das ein `data`-Attribut per fetch
 * nachlaedt und sich selbst durch die Antwort ersetzt. Als Burger unbrauchbar.
 * Der Wrapper wird per `display: contents` durchsichtig, damit der Knopf
 * direktes Flex-Kind der Molecule bleibt. */
.mypage .molecule.header-nav .head-nav-toggle-wrap,
.mypage .molecule.header-nav .head-nav-toggle {
  display: none;
}

/* ── Mobil ─────────────────────────────────────────────────────────
 * Unter 767px: Navigation zu, Umschalter da. Offen wird sie als Panel
 * unter dem Header eingehaengt.
 * ────────────────────────────────────────────────────────────────── */
@media (max-width: 767px) {
  .mypage .molecule.header-nav .head-nav-toggle-wrap {
    display: contents;
  }
  .mypage .molecule.header-nav .head-nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    border: 0;
    border-radius: var(--radius-md, 8px);
    background: transparent;
    color: inherit;
    cursor: pointer;
  }
  .mypage .molecule.header-nav .head-nav-toggle:hover {
    background: color-mix(in srgb, currentColor 8%, transparent);
  }
  /* Burger aus drei Linien — kein Icon-Asset, damit die Molecule ohne
   * Abhaengigkeit zum Icon-Dienst funktioniert. `currentColor` traegt sie auf
   * hellem wie dunklem Grund. */
  .mypage .molecule.header-nav .head-nav-toggle::before {
    content: '';
    width: 1.125rem;
    height: 2px;
    background: currentColor;
    box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor;
  }

  .mypage .molecule.header-nav .head-nav-slot {
    /* `!important` ist hier NOETIG und am DOM belegt (2026-08-10). Gegenspieler
     * ist `[slot="menu-h"] { display: flex !important }` in em-base.css — ein
     * Flag auf einem Attributselektor. Ohne eigenes Flag blieb die Navigation
     * bei 390px SICHTBAR und der Burger stand daneben: schlechter als vorher.
     * Flag gegen Flag entscheidet die Spezifitaet, und (0,3,0) hier schlaegt die
     * (0,1,0) dort. Die em-base-Regel selbst zu entflaggen ist keine Option —
     * sie traegt 31 Menue-Slots und darf bewusst kein `.mypage`-Prefix haben
     * (Editor-Preview), siehe die Begruendung dort. */
    display: none !important;
  }
  .mypage .molecule.header-nav.head-nav-open .head-nav-slot {
    /* Ebenfalls geflaggt, sonst gewinnt die Zeile darueber (gleiche Datei,
     * spaeter waere hier egal — die Regel oben traegt ein Flag, also braucht
     * die Gegenregel auch eines; ihre (0,4,0) schlaegt dann die (0,3,0)). */
    display: flex !important;
    flex-direction: column;
    align-items: stretch;
    gap: 0.25rem;
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    z-index: 50;
    min-width: 12rem;
    padding: 0.75rem 1rem;
    border-radius: var(--radius-md, 8px);
    /* Eigener Grund, nicht durchscheinend: das Panel liegt oft ueber einem
     * Hero-Bild. `--color-bg` folgt dem Farbpaar des Abschnitts. */
    background: var(--color-bg, #fff);
    box-shadow: 0 8px 24px color-mix(in srgb, currentColor 18%, transparent);
    text-align: left;
  }
  .mypage .molecule.header-nav.head-nav-open .head-nav-slot a,
  .mypage .molecule.header-nav.head-nav-open .head-nav-slot .nav-demo {
    display: block;
    padding: 0.375rem 0;
  }
}

/* Bewegungsempfindlichkeit respektieren: kein Einblenden, nur da oder weg.
 * (Das Panel hat ohnehin keine Animation — die Regel haelt das fest, damit
 * niemand spaeter eine ohne Ruecksicht ergaenzt.) */
@media (prefers-reduced-motion: reduce) {
  .mypage .molecule.header-nav .head-nav-slot {
    transition: none;
  }
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: center — Navigation mittig statt rechts.
 *
 * WICHTIG: setzt die Basisklasse voraus (`molecule header-nav
 * header-nav--center`), wie bei team-card--circle und logo-row--color.
 *
 * Fuer Kopfzeilen, deren Navigation UNTER der Marke steht und dort mittig
 * sitzt (head_centered_logo_nav). Ohne diese Variante zieht die Basis sie per
 * `justify-content: flex-end` an die rechte Kante.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.header-nav--center {
  justify-content: center;
}
@media (max-width: 767px) {
  /* Das Panel haengt dann mittig unter dem Umschalter statt rechtsbuendig. */
  .mypage .molecule.header-nav--center.head-nav-open .head-nav-slot {
    right: auto;
    left: 50%;
    transform: translateX(-50%);
  }
}

/* Molecule: hero-block */
.mypage .molecule.hero-block {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 200px;
}

/* RTE content container
 * Default size is h-md. Size-Modifier (h-xl/h-lg/h-md/h-sm) are applied by
 * the author or the AI-assistant on .molecule.hero-block itself, based on
 * headline length. Each stop is fluid within its own clamp() range so a
 * short heading on a narrow viewport still scales down gracefully.
 *
 * Brand override: set --hero-h1-* CSS variables on a parent scope
 * (e.g. .mypage { --hero-h1-md: clamp(2.5rem, 6vw, 5rem); }) to retheme
 * without touching the molecule stylesheet.
 */
.mypage .molecule.hero-block .hero-content h1,
.mypage .molecule.hero-block .hero-content h2 {
  font-size: var(--hero-h1-md, clamp(2rem, 5vw, 4rem));
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin-bottom: 0.5em;
  text-wrap: balance;
}
.mypage .molecule.hero-block.h-xl .hero-content h1,
.mypage .molecule.hero-block.h-xl .hero-content h2 {
  font-size: var(--hero-h1-xl, clamp(2.5rem, 8vw, 6rem));
}
.mypage .molecule.hero-block.h-lg .hero-content h1,
.mypage .molecule.hero-block.h-lg .hero-content h2 {
  font-size: var(--hero-h1-lg, clamp(2.25rem, 6vw, 5rem));
}
.mypage .molecule.hero-block.h-sm .hero-content h1,
.mypage .molecule.hero-block.h-sm .hero-content h2 {
  font-size: var(--hero-h1-sm, clamp(1.5rem, 3.5vw, 2.75rem));
  line-height: 1.15;
}

.mypage .molecule.hero-block .hero-content .subline {
  font-size: 1.125rem;
  line-height: 1.7;
  color: var(--text-muted);
  max-width: 600px;
  margin-bottom: 0.5em;
}

.mypage .molecule.hero-block .hero-content .eyebrow {
  margin-bottom: 0.75em;
}

/* Legacy class support (pre-RTE content pattern). Mirrors the default
 * h-md stop so existing pages stay visually identical until they migrate
 * to the RTE content-slot. New molecules should NOT use .hero-headline. */
.mypage .molecule.hero-block .hero-headline {
  font-size: var(--hero-h1-md, clamp(2rem, 5vw, 4rem));
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.mypage .molecule.hero-block .hero-subtext {
  font-size: 1.125rem;
  line-height: 1.7;
  color: var(--text-muted);
  max-width: 600px;
}

/* Button-Nachbau entfallen (2026-08-10): `.hero-cta .btn-primary` hat
 * `.btn-wrap` aus em-components dupliziert — anderer Radius (0.5rem statt
 * --radius-md), Farbe direkt aus --primary-base statt aus der CTA-Kette der
 * ProjectSettings, eigene Schriftgroesse. Die Patterns nutzen jetzt den
 * echten `.btn-wrap` am Anker. Abstand ueber dem Button bleibt hier. */
/* Abstand entfaellt hier (2026-08-10) — siehe cta-block: er kommt jetzt
 * zentral aus `--cta-gap` in em-components. Sonst 20px + 32px = 52px. */

/* Flex-item shrink safety: align-items:center on the parent would
 * leave direct children at their intrinsic (content) width, which breaks
 * long headlines inside narrow grid columns (e.g. col-8 at desktop). The
 * combination below lets text wrap while keeping the visual centering. */
.mypage .molecule.hero-block > * {
  max-width: 100%;
  min-width: 0;
}

/* Molecule: image-block */
.mypage .molecule.image-block {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.mypage .molecule.image-block picture img {
  width: 100%;
  height: auto;
  border-radius: 0.75rem;
  object-fit: cover;
}

.mypage .molecule.image-block .image-caption {
  font-size: 0.85rem;
  color: var(--text-muted);
  text-align: center;
  padding-top: 0.5rem;
}

/* Flex-item shrink safety: align-items:center on the parent would
 * leave direct children at their intrinsic (content) width, which breaks
 * long headlines inside narrow grid columns (e.g. col-8 at desktop). The
 * combination below lets text wrap while keeping the visual centering. */
.mypage .molecule.image-block > * {
  max-width: 100%;
  min-width: 0;
}

/* Molecule: logo-row */
.mypage .molecule.logo-row {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 120px;            /* keep the band readable even with tiny logos */
  padding: 1rem 0;
  gap: 0;
}

/* The html-slot renders <img>s as direct children of the rich-text
 * wrapper, so we target those too — not just a named .logo-row-inner. */
.mypage .molecule.logo-row > div[type="rich"],
.mypage .molecule.logo-row .logo-row-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1.5rem 2.5rem;
}

.mypage .molecule.logo-row > div[type="rich"] img,
.mypage .molecule.logo-row .logo-row-inner img {
  height: 56px;                 /* fixed → consistent, not dependent on sample size */
  width: auto;
  max-width: 160px;
  object-fit: contain;
  object-position: center;  /* kein Beschnitt -> mittig, nicht 30% */
  opacity: 0.65;
  filter: grayscale(100%);
  transition: opacity 0.2s, filter 0.2s;
}

.mypage .molecule.logo-row > div[type="rich"] img:hover,
.mypage .molecule.logo-row .logo-row-inner img:hover {
  opacity: 1;
  filter: grayscale(0%);
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: color
 *
 * WICHTIG fuer Template-Autoren: die Variante setzt die Basisklasse voraus,
 * also `molecule logo-row logo-row--color`. Mit `molecule logo-row--color`
 * allein greift KEINE der Basis-Regeln oben — gemessen lief das Band dann als
 * Block statt als Flex, ohne gap und ohne min-height (Fehler beim Anlegen von
 * trust_logos_color, 2026-08-10). Gleiche Konvention wie bei
 * team-card/team-card--circle.
 * Logos in Originalfarbe statt in Graustufen. Fuer Kundenlisten, in denen
 * die Markenfarben Teil der Aussage sind (Partner-Logos, Zertifikate,
 * Presse-Marken) — die Graustufen-Default passt dort, wo die Logos eine
 * ruhige Leiste bilden sollen und der Text die Hauptrolle hat.
 * Kein Hover-Wechsel: bei vollfarbigen Logos gibt es nichts aufzudecken,
 * und ein Zustandswechsel ohne Zielzustand liest sich als Fehler.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.logo-row--color > div[type="rich"] img,
.mypage .molecule.logo-row--color .logo-row-inner img {
  filter: none;
  opacity: 1;
}
.mypage .molecule.logo-row--color > div[type="rich"] img:hover,
.mypage .molecule.logo-row--color .logo-row-inner img:hover {
  filter: none;
  opacity: 1;
}

@media (max-width: 768px) {
  .molecule.logo-row > div[type="rich"],
  .molecule.logo-row .logo-row-inner {
    gap: 1.25rem 2rem;
  }
  .molecule.logo-row > div[type="rich"] img,
  .molecule.logo-row .logo-row-inner img {
    height: 40px;
  }
}

/* Flex-item shrink safety: align-items:center on the parent would
 * leave direct children at their intrinsic (content) width, which breaks
 * long headlines inside narrow grid columns (e.g. col-8 at desktop). The
 * combination below lets text wrap while keeping the visual centering. */
.mypage .molecule.logo-row > * {
  max-width: 100%;
  min-width: 0;
}

/* Grid-Variante (4×2) für glogo_wall02 + längere Logo-Listen. Erzwingt
 * CSS-Grid statt Flex-Wrap — alle Logos exakt gleich groß und auf
 * Spalten ausgerichtet. */
.mypage .molecule.logo-row .logo-grid-4x2 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem 2rem;
  justify-items: center;
  align-items: center;
}
.mypage .molecule.logo-row .logo-grid-4x2 img {
  height: 64px;
  max-width: 100%;
}
@media (max-width: 768px) {
  .molecule.logo-row .logo-grid-4x2 {
    grid-template-columns: repeat(2, 1fr);
    gap: 1rem 1.5rem;
  }
}

/* map Molecule — Anfahrtskarte als content-addressed PNG unter
 * images/map-<hash>.png (reguläre Projekt-Ressource, internal:-Ref).
 * EmPages-Save-Hook + em-mapgen-Worker erzeugen das Bild asynchron; bis
 * dahin (oder bei Fehler) zeigt .map-frame einen neutralen Lade-
 * Platzhalter (kein Stock-Asset mehr). Optional darunter ein hover-
 * eingeblendetes Overlay mit Adresse + Google-Maps-Link (data-map-overlay
 * / data-map-gmaps auf dem Wrapper). */
.mypage .molecule.map-block {
  display: block;
  width: 100%;
  position: relative;
  overflow: hidden;
  border-radius: 8px;
}

.mypage .molecule.map-block img {
  display: block;
  width: 100%;
  height: auto;
  max-width: 100%;
  object-fit: cover;
}

/* Hover-Overlay — slidet von unten ein. Pointer-events bleiben aktiv
 * damit der Gmaps-Link klickbar ist. backdrop-filter blurt das Karten-
 * Bild leicht für bessere Text-Lesbarkeit; fallback auf solide bg-Farbe
 * wenn der Browser kein backdrop-filter kann. */
.mypage .molecule.map-block .map-overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2; /* above .map-frame img (z-index 1) + .map-pending-ph (z-index 0) */
  padding: 0.75rem 1rem;
  background: rgba(15, 23, 42, 0.78);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #fff;
  transform: translateY(100%);
  transition: transform 0.22s ease-out;
  pointer-events: none;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 1rem;
}

.mypage .molecule.map-block:hover .map-overlay,
.mypage .molecule.map-block:focus-within .map-overlay {
  transform: translateY(0);
  pointer-events: auto;
}

.mypage .molecule.map-block .map-address {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.35;
  color: #fff;
}

.mypage .molecule.map-block .map-gmaps-link {
  margin: 0;
  font-size: 0.8125rem;
  color: #93c5fd;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  white-space: nowrap;
}

.mypage .molecule.map-block .map-gmaps-link:hover,
.mypage .molecule.map-block .map-gmaps-link:focus-visible {
  color: #bfdbfe;
}

/* Frame + neutraler Lade-Platzhalter (löst map-fallback.png ab).
 * .map-frame hält via aspect-ratio die Höhe, auch wenn das <img> (noch)
 * fehlt. Der Platzhalter liegt dahinter (z-index 0); das geladene Bild
 * verdeckt ihn (z-index 1). 404 → onerror blendet das img aus →
 * Platzhalter erscheint. Rein transient (Reload nach Worker-Fertigstellung
 * zeigt die echte Karte). */
.mypage .molecule.map-block .map-frame {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
}
.mypage .molecule.map-block .map-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: 100%;
  object-fit: cover;
  z-index: 1;
}
.mypage .molecule.map-block .map-pending-ph {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  background: #eef1f5;
  color: #64748b;
}
.mypage .molecule.map-block .map-pending-icon {
  opacity: 0.7;
}
.mypage .molecule.map-block .map-pending-label {
  font-size: 0.875rem;
  letter-spacing: 0.01em;
}

/* Molecule: menu
 * Generischer Nav-Renderer — list-reset + Hover + is-current-marker.
 * Wird über em-nav / em-nav-header / em-nav-footer / em-nav-sidebar
 * Klassen vom Renderer gewrappt (siehe BE renderMenuBlock). Demo-Fallback
 * rendert als <span class="nav-demo">…</span>, Live-Items als <a>.
 */
.mypage .molecule.menu {
  display: block;
}

.mypage .molecule.menu .menu-list {
  display: block;
}

/* Live-Items: <a> oder verschachtelte <div class="nav-item"> (für children).
 * Demo-Items: <span class="nav-demo">. Beide gleicher Look. */
.mypage .em-nav a,
.mypage .em-nav .nav-demo {
  display: inline-block;
  text-decoration: none;
  color: inherit;
  padding: 0.25rem 0.5rem;
  transition: opacity 0.15s ease;
  /* Crop lange Titel — 'Quality Test v23 — proc_arrows_vertical + social-pill'
   * wuerde sonst die Nav-Bar mehrzeilig sprengen. 20ch ist Tablet-tauglich,
   * Patterns koennen via spezifischerem Selektor ueberschreiben. */
  max-width: 20ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

/* .nav-demo Universal-Fallback: Patterns rendern Demo-Items oft direkt
 * in `<div type="rich" slot="menu-h">` ohne em-nav-Wrapper (Live-Items
 * werden vom BE applyMenuConfigToTree erst zur Render-Zeit gewrappt).
 * Damit "Seite 1 Seite 2 Seite 3" im Editor + in Patterns ohne Menu-
 * Konfig nicht zusammenkleben, gilt das Padding+Opacity auch ohne
 * em-nav-Vorfahre. Greift nicht in .em-nav (gleiche Specificity, gleich
 * fokussierter Selector → wer zuerst dorthin matched gewinnt). */
.mypage .nav-demo {
  display: inline-block;
  padding: 0.25rem 0.5rem;
  color: var(--menu-link-color, var(--text-muted));
  cursor: default;
}

.mypage .em-nav a:hover {
  opacity: 0.7;
}

.mypage .em-nav a.active {
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Demo-Items sind nicht klickbar — visuell etwas dimmer, kein hover */
.mypage .em-nav .nav-demo {
  color: var(--menu-link-color, var(--text-muted));
  cursor: default;
}

/* Vertical-Variante via em-nav-footer-Sidebar-Default */
.mypage .em-nav-sidebar a,
.mypage .em-nav-sidebar .nav-demo {
  display: block;
}

/* Children (depth > 1) — versteckt als Dropdown beim Hover.
 * Im Footer immer sichtbar (Sitemap-Stil) — kann durch Pattern-CSS überschrieben werden. */
.mypage .em-nav .nav-sub {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  background: var(--color-bg);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--shade-dark-base) 12%, transparent);
  min-width: 12rem;
  padding: 0.5rem 0;
  z-index: 50;
}

.mypage .em-nav .nav-item:hover .nav-sub {
  display: block;
}

.mypage .em-nav-footer .nav-sub,
.mypage .em-nav-sidebar .nav-sub {
  display: block;
  position: static;
  background: transparent;
  box-shadow: none;
  padding: 0;
  min-width: 0;
}

/* Molecule: pricing-card */
.mypage .molecule.pricing-card {
  background: var(--card-bg, var(--color-bg));
  border-radius: 1rem;
  box-shadow: 0 2px 20px rgba(0,0,0,0.06);
  display: flex;
  flex-direction: column;
  height: 100%;
  transition: transform 0.2s, box-shadow 0.2s;
}

.mypage .molecule.pricing-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 30px rgba(0,0,0,0.1);
}

.mypage .molecule.pricing-card .pricing-title {
  /* font-size via txt-lg Klasse im JSON — pricing-title trägt nur Layout. */
  font-weight: 600;
  letter-spacing: 0.01em;
}

.mypage .molecule.pricing-card .pricing-price {
  /* font-size + font-weight werden über txt-* Klassen im RTE gesetzt —
     pricing-price ist nur noch der Farb-Slot. Konsistent mit dem
     txt-*-System: eine Quelle für alle Größen, kein molekül-fester Wert. */
  line-height: 1.2;
  color: var(--primary-base);
}

.mypage .molecule.pricing-card .pricing-desc {
  font-size: 0.95rem;
  color: var(--text-muted);
}

.mypage .molecule.pricing-card .pricing-features {
  flex: 1;
}

.mypage .molecule.pricing-card .pricing-features ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.mypage .molecule.pricing-card .pricing-features li {
  /* Kein vertikales Padding mehr (2026-08-10) — der Abstand zwischen den
   * Punkten kommt jetzt aus der Basis-Regel `li + li`. Vorher 0.4rem oben und
   * unten, also 12.8px zwischen zwei Punkten bei 15.2px Schrift (0.84em) —
   * fast der Absatzabstand, die Liste fiel dadurch auseinander. */
  font-size: 0.95rem;
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

.mypage .molecule.pricing-card .pricing-features li::before {
  content: '✓';
  color: var(--primary-base);
  font-weight: 700;
  flex-shrink: 0;
}

.mypage .molecule.pricing-card .pricing-cta .btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 0.75rem 1.5rem;
  background: var(--primary-base);
  color: var(--text-light);
  border-radius: 0.5rem;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.2s;
}

.mypage .molecule.pricing-card .pricing-cta .btn-primary:hover {
  background: var(--primary-dark);
}

/* Flex-item shrink safety: align-items:center on the parent would
 * leave direct children at their intrinsic (content) width, which breaks
 * long headlines inside narrow grid columns (e.g. col-8 at desktop). The
 * combination below lets text wrap while keeping the visual centering. */
.mypage .molecule.pricing-card > * {
  max-width: 100%;
  min-width: 0;
}

/* Molecule: quote-card */
.mypage .molecule.quote-card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  gap: 1rem;
  height: 100%;
  min-height: 12rem;
  padding: 1.25rem 1.5rem;
  text-align: center;
}
/* author wird nicht mehr per margin-top:auto an den Boden gedrueckt —
 * verursachte riesige Leerstelle zwischen Quote und Avatar bei kurzen
 * Zitaten. justify-content:center auf dem Parent + gap:1rem haelt die
 * Bloecke zentriert + sauber im Abstand. */

/* Zitat-Marker. Der icon-Node rendert als <svg class="icon quote-mark"> — das svg
 * IST .quote-mark (kein Wrapper), daher `svg.quote-mark` (nicht `.quote-mark svg`).
 * Dezente Deko-Optik, ueberschreibbar via --icon-color.
 *
 * (2026-07-28: der frühere html-Slot-Pfad `.quote-mark p` (getipptes „ mit
 * 6rem/Lato) ist entfernt — alle voice_*-Patterns nutzen den icon-Node, und es
 * existieren keine Alt-Instanzen mehr in den Seiten-Daten. Wieder-Einführen
 * würde nur einen zweiten Renderpfad für dasselbe Element schaffen.) */
.mypage .molecule.quote-card svg.quote-mark {
  width: 4rem;
  height: 4rem;
  fill: var(--apostrophy, var(--icon-color, var(--primary-base)));
  opacity: 0.2;
  line-height: 1;
}

.mypage .molecule.quote-card .quote-text {
  /* Zitat-Serifenschrift, faellt auf Body-Schrift zurueck wenn kein --quote-font
   * gesetzt ist (heutiges Verhalten). */
  font-family: var(--quote-font, var(--copytext-font));
  /* Überschreibbarer Default (KEIN !important) — so kann das RTE-Größen-
   * Dropdown per txt-* Klasse (die IST !important) die Größe frei
   * steuern. Früher stand txt-2xl fest im Slot-JSON → !important-Konflikt,
   * Größenänderung im RTE griff nicht. */
  font-size: 1.25rem;
  /* 1.35 statt 1.6 (2026-08-10). 1.6 ist der Wert fuer Fliesstext; ein
   * kursiv gesetztes Zitat in Zitatgroesse ist Display-Satz und faellt damit
   * auseinander. Gemessen im 325px-Kartenzitat: 27,6px Schrift auf 44,2px
   * Zeile. Das Portrait-Pattern hatte 1.35 laengst pattern-lokal gesetzt und
   * sah dadurch besser aus als die Karten — jetzt ein Wert fuer alle Zitate. */
  line-height: 1.35;
  font-style: italic;
  /* min-height verhindert dass die TipTap-Edit-Mode das Element auf 0px
   * collapsed (innerHTML wird beim Mount geleert) — dann wuerde die
   * Edit-Toolbar floaten ohne Anker. */
  min-height: 3rem;
}

.mypage .molecule.quote-card .quote-author {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding-top: 1rem;
}

.mypage .molecule.quote-card .quote-author img {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  object-fit: cover;
}

/* Name + Rolle zueinander linksbuendig (2026-08-08). Die Karte ist
 * `text-align: center` (Zitat und Anfuehrungszeichen sollen mittig stehen),
 * und der Autoren-Textblock hat keine eigene Ausrichtung — er ERBT die
 * Zentrierung. Solange Avatar und Text uebereinander standen, fiel das nicht
 * auf; seit sie nebeneinander sitzen (Batch 4e), flattern Name und Rolle
 * gegeneinander, weil beide Zeilen unterschiedlich lang sind.
 *
 * Nur der Textblock wird umgestellt, nicht die Karte: `justify-content:
 * center` an `.quote-author` bleibt, die Gruppe aus Avatar + Text steht also
 * weiter mittig in der Karte, und das Zitat darueber bleibt zentriert.
 *
 * Kein Flag noetig und keine hohe Spezifitaet: ein geerbter Wert verliert
 * gegen JEDE Regel, die die Property am Element selbst setzt. */
.mypage .molecule.quote-card .quote-author > div[type='rich'] {
  text-align: left;
}

/* (2026-07-28: .quote-name/.quote-role entfernt. Name+Rolle sind jetzt EIN RTE mit
 * den Absatzstilen .caption/.caption-sub (em-base.css) — Projekt-B-Doktrin: Typografie-
 * Variation innerhalb eines Content-Blocks gehört nicht in Marker-Slots. Damit sind die
 * hardcodierten Größen der AUTOR-Slots weg; die verbleibenden font-size-Werte betreffen
 * nur `.quote-text` und sind bewusste, überschreibbare Defaults ohne !important (s.
 * Kommentar dort). Migriert: voice_3cards, voice_3row, voice_slider (Vorbild voice_single). */

/* Flex-item shrink safety: align-items:center on the parent would
 * leave direct children at their intrinsic (content) width, which breaks
 * long headlines inside narrow grid columns (e.g. col-8 at desktop). The
 * combination below lets text wrap while keeping the visual centering. */
.mypage .molecule.quote-card > * {
  max-width: 100%;
  min-width: 0;
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: blockquote
 * Reduziertes Editorial-Format. Kein Card-Rahmen, Akzentbalken links,
 * Text und Author links-bündig. Großes Anführungszeichen wird unterdrückt.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.quote-card--blockquote {
  background: transparent;
  box-shadow: none;
  border-radius: 0;
  text-align: left;
  padding: 0.5rem 0 0.5rem 1.5rem;
  border-left: 4px solid var(--primary-base);
}

.mypage .molecule.quote-card--blockquote .quote-mark {
  display: none;
}

.mypage .molecule.quote-card--blockquote .quote-text {
  font-size: 1.25rem;
  font-style: italic;
  text-align: left;
}

.mypage .molecule.quote-card--blockquote .quote-author {
  justify-content: flex-start;
  padding-top: 0.75rem;
}

.mypage .molecule.quote-card--blockquote .quote-author img {
  width: 36px;
  height: 36px;
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: speech-bubble
 * Abgerundete Bubble mit Tail. Tail sitzt am Bubble-Unterrand und
 * zeigt nach unten — rein dekorativ. Author bleibt innerhalb der
 * Bubble unten (Struktur unverändert, nur CSS-Modifier).
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.quote-card--speech-bubble {
  background: var(--primary-light);
  box-shadow: none;
  border-radius: 1.25rem;
  padding: 1.5rem 1.5rem 1.5rem;
  position: relative;
  margin-bottom: 1rem;
}

/* Tail am Bubble-Unterrand, nach unten zeigend.
 * Drei Border-Tricks für CSS-Dreieck:
 *  - left/right transparent → seitliche Schrägen
 *  - top farbig → die nach unten zeigende Spitze
 *    (border-top wirkt aus Sicht des Punkts in y-negativer Richtung,
 *    visuell aber als nach-unten-deutender Pfeil mit Basis oben). */
.mypage .molecule.quote-card--speech-bubble::after {
  content: '';
  position: absolute;
  bottom: -14px;
  left: 2rem;
  width: 0;
  height: 0;
  border-left: 14px solid transparent;
  border-right: 14px solid transparent;
  border-top: 14px solid var(--primary-light);
}

.mypage .molecule.quote-card--speech-bubble .quote-text {
  font-style: normal;
  font-size: 1.05rem;
  line-height: 1.55;
}

.mypage .molecule.quote-card--speech-bubble .quote-author {
  padding-top: 1rem;
}

.mypage .molecule.quote-card--speech-bubble .quote-author img {
  width: 40px;
  height: 40px;
}

/* Molecule: social-strip
 * Reihe von Social-Media-Icons in hellen Kreis-Bubbles.
 * Icon-Farbe = Primärfarbe (via .icon default in em-components.css).
 * Hintergrund = helle Primärvariante für sanften Kontrast.
 */
.mypage .molecule.social-strip {
  display: flex;
  /* Socials = eine horizontale Reihe, kein Umbruch.
   *
   * Das `!important` auf `flex-direction` ist am 2026-08-11 ENTFALLEN. Es kämpfte
   * gegen Regel 4 der Grid-Engine (`col-12:has(> col-N) … > .molecule
   * { flex-direction: column }`) — dieselbe Regel, die auch die header-nav auf
   * die Seite gelegt hat. Statt jede waagrechte Molecule einzeln zu flaggen,
   * steht die Ausnahme jetzt EINMAL an der Quelle: Regel 4b in
   * em-components.css nennt `header-nav` und `social-strip` und dreht dort
   * `flex-direction` zurück. Damit gewinnt hier die normale Kaskade.
   *
   * `flex-wrap` hatte sein Flag schon vorher verloren (gemessen: `nowrap` vor wie
   * nach) — es war mit dem flex-direction-Flag mitgewandert. */
  flex-direction: row;
  flex-wrap: nowrap;
  gap: 0.75rem;
  align-items: center;
  justify-content: center;
}

.mypage .molecule.social-strip .social-icon-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: var(--primary-light);
  color: var(--primary-base);
  text-decoration: none;
  transition: background 0.15s, transform 0.15s;
  flex-shrink: 0;
}

.mypage .molecule.social-strip .social-icon-wrap:hover {
  background: color-mix(in hsl, var(--primary-base) 20%, white 80%);
  transform: scale(1.08);
}

.mypage .molecule.social-strip .social-icon-wrap .icon {
  width: 1.4rem;
  height: 1.4rem;
  fill: var(--primary-base);
  color: var(--primary-base);
}

/* Auf dunklen Sektionen: weiße Bubbles mit Primärfarbe */
.mypage .sc-dark .molecule.social-strip .social-icon-wrap,
.mypage .sc-pri .molecule.social-strip .social-icon-wrap {
  background: rgba(255, 255, 255, 0.15);
  color: var(--text-light);
}
.mypage .sc-dark .molecule.social-strip .social-icon-wrap .icon,
.mypage .sc-pri .molecule.social-strip .social-icon-wrap .icon {
  fill:  var(--text-light);
  color: var(--text-light);
}
.mypage .sc-dark .molecule.social-strip .social-icon-wrap:hover,
.mypage .sc-pri .molecule.social-strip .social-icon-wrap:hover {
  background: rgba(255, 255, 255, 0.25);
}

/* Molecule: stat-item */
.mypage .molecule.stat-item {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100%;
  text-align: center;
  padding: 1rem;
}

.mypage .molecule.stat-item .stat-icon {
  color: var(--primary-base);   /* themes the inline SVG */
  margin-bottom: 0.5rem;
  align-self: center;
}

.mypage .molecule.stat-item .stat-value {
  /* font-size via txt-* Klasse im JSON (txt-3xl) — stat-value ist Farb-Slot */
  font-weight: 700;
  line-height: 1.1;
  color: var(--primary-base);
}

.mypage .molecule.stat-item .stat-label {
  font-size: 0.95rem;
  color: var(--text-muted);
  margin-top: 0.25rem;
}

/* Marker-Klassen entfernt (2026-08-10). Der Inhalt kommt jetzt als EIN RTE;
 * die Typografie liefern die Basis-Absatzstile (h3/h4, p, caption,
 * caption-sub). Grund siehe TEMPL_MASTER: Typografie-Variation innerhalb
 * eines Content-Blocks gehoert nicht in getrennte Marker-Slots, weil TipTap
 * Custom-Klassen beim Reinklicken re-normalisiert.
 * Die Patterns waren 2026-07-24 migriert worden, die Molecules nicht — das
 * hat der Drift-Abgleich heute aufgedeckt. */
/* Molecule: step-card
 * Numerierter Prozessschritt mit Kreis-Bubble, Headline, Beschreibung.
 * Verwendet in gproc_steps01 (horizontal) + gproc_steps02 (Karten).
 */
.mypage .molecule.step-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  height: 100%;
}

.mypage .molecule.step-card .step-bubble {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background: var(--primary-base);
  color: var(--text-light);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1rem;
  flex-shrink: 0;
  box-shadow: 0 4px 12px color-mix(in srgb, var(--shade-dark-base) 18%, transparent);
  font-family: var(--h2-font-family, inherit);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
}

/* Step-Number-Slot rendert als <div type="rich"><p>1</p></div>. Der
 * Wrapper-Div nimmt im flex-Container nur Content-Breite ein, sodass
 * schmale Glyphen ("1") optisch nicht perfekt mittig sitzen. Den
 * Wrapper-Div + dessen <p> auf 100%/100% mit flex-centering zwingen
 * → Zahl sitzt unabhängig vom Glyph-Maß dead-center.
 * Vorher per pattern.css-Override in einzelnen Patterns; jetzt am
 * Molecule, damit alle Step-Card-Verwendungen den Fix mitbekommen. */
.mypage .molecule.step-card .step-bubble .step-num,
.mypage .molecule.step-card .step-bubble > div[type="rich"] {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  line-height: 1;
}
.mypage .molecule.step-card .step-bubble p {
  margin: 0;
  padding: 0;
  line-height: 1;
}



/* Optionale Variante: Connector-Linie zwischen Bubbles in horizontalen
 * Reihen. Per Pattern aktivierbar via .step-with-connector auf der
 * äußeren Section. */
/* Positionierungs-Kontext für die Connector-Linie. Zwei Selektor-Formen,
 * damit sowohl das alte verschachtelte Layout (col-N > .step-card) als
 * auch das Model-B-gemergte Layout (col-N.step-card auf EINEM Node) den
 * position:relative-Kontext bekommt. */
.step-with-connector .col-4:not(:last-child) .step-card,
.step-with-connector .col-3:not(:last-child) .step-card,
.step-with-connector .col-4.step-card:not(:last-child),
.step-with-connector .col-3.step-card:not(:last-child) {
  position: relative;
}
.step-with-connector .col-4:not(:last-child) .step-bubble::after,
.step-with-connector .col-3:not(:last-child) .step-bubble::after,
.step-with-connector .col-4.step-card:not(:last-child) .step-bubble::after,
.step-with-connector .col-3.step-card:not(:last-child) .step-bubble::after {
  content: '';
  position: absolute;
  top: 50%;
  left: calc(100% + 1rem);
  width: calc(100vw / 12 * 4 - 100%);
  height: 2px;
  background: var(--primary-base);
  opacity: 0.3;
  transform: translateY(-50%);
  z-index: -1;
}

/* Kontrast-Variante für Karten auf farbigem Hintergrund */
.mypage .sc-pri .molecule.step-card .step-bubble,
.mypage .sc-acc .molecule.step-card .step-bubble {
  background: var(--color-bg);
  color: var(--primary-base);
}

/* Molecule: team-card
 * Portrait-Card mit Bild oben (4:3 Aspect), Name, Rolle, optionalem CTA.
 * Passt in Carousel-Slots (col-3 bis col-6).
 */

/* Portrait-Bild: volle Breite, 4:3, abgerundete Oberkanten */
/* Die Karte selbst traegt KEIN Padding (2026-08-10). Das Bild soll buendig an
 * die Kartenkante reichen; den Innenabstand bringt `team-card-body` mit
 * (px-4 py-4 im Template). Ohne diese Zeile greift `.card { padding: 1.25rem
 * 1.5rem }` aus em-components und rueckt das Bild 20px von oben ein.
 * Spezifitaet: (0,3,0) gegen (0,1,0) — reicht ohne Flag.
 * Die 16px links/rechts kommen NICHT von hier, sondern von der Grid-Engine,
 * wenn die Karte selbst das col-N-Element ist. Dagegen hilft nur die
 * Template-Struktur: col-N-Wrapper aussen, Karte innen. */
.mypage .molecule.team-card {
  padding: 0;
}

.mypage .molecule.team-card > picture[type='picture'] {
  /* Ohne `!important` (Stufe 4, Batch 4e, 2026-08-09): gemessen auf
   * /molecules-check — `block` vor wie nach. Randbefund: die Patterns
   * team_3persons und team_leadership_bio setzen `class="… team-card"` OHNE die
   * `molecule`-Klasse, dieser Selektor trifft dort also gar nicht. Erreichbar ist
   * die Regel nur ueber den Baustein-Picker. */
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
}

.mypage .molecule.team-card > picture[type='picture'] img,
.mypage .molecule.team-card .team-card-photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* object-position entfaellt (2026-08-10): der Basis-Default 50% 30%
   * uebernimmt. Vorher stand hier center 20% — dieselbe Idee, aber nur
   * fuer dieses eine Molecule. */
}

/* Text-Bereich */
.mypage .molecule.team-card .team-card-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  /* Innenabstand der Karte (2026-08-10), analog article-card: die Karte traegt
   * `padding: 0`, damit das Portrait buendig sitzt — der Body holt den
   * Abstand zurueck, mit demselben Wert wie `.card`. Bis heute stand er als
   * `px-4 py-4` in den drei Templates (32px statt 20/24) und fehlte jedem
   * neuen Pattern, das ihn zu setzen vergisst. Jetzt eine Quelle. */
  padding: 1.25rem 1.5rem;
}

/* `.c-name`/`.c-role` entfernt (2026-08-10). Name und Rolle sind jetzt EIN
 * RTE mit den Absatzstilen .caption/.caption-sub — dieselbe Doktrin, nach der
 * die voice_*-Patterns 2026-07-24 migriert wurden: Typografie-Variation
 * INNERHALB eines Content-Blocks gehoert nicht in getrennte Marker-Slots.
 * Die verbleibenden h3/h4-Regeln gelten fuer Karten, die eine echte
 * Ueberschrift statt einer Attributions-Zeile tragen. */
.mypage .molecule.team-card .team-card-body h3,
.mypage .molecule.team-card .team-card-body h4 {
  font-weight: 700;
  font-size: 1.05rem;
  margin: 0 0 0.25rem;
}

.mypage .molecule.team-card .team-card-body .role {
  color: var(--primary-base);
  font-size: 0.9rem;
  margin: 0;
}

.mypage .molecule.team-card .team-card-cta {
  margin-top: auto;
  display: flex;
  justify-content: center;
}

/* Schmale Columns (< 200px): CTA ausblenden */
@container (max-width: 200px) {
  .mypage .molecule.team-card .team-card-cta { display: none; }
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: landscape
 * Bild links (40% Breite), Text + CTA rechts. Funktioniert ab col-6.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.team-card--landscape {
  /* Ohne `!important` (Batch 4e, gemessen auf /molecules-check mit der Variante
   * team-card--landscape): `flex` vor wie nach dem Entflaggen. */
  display: flex;
  /* `flex-direction` braucht hier ein !important (2026-08-09, am DOM gemessen).
   * VORBESTEHENDER Defekt, aufgedeckt durch das neue Pattern
   * team_cards_landscape: dieselbe Grid-Engine-Regel, die der download-card das
   * `display: grid` nimmt, setzt zusaetzlich `flex-direction: column` — und
   * gewinnt hier per Spezifitaet. Die Landscape-Variante rendert dadurch
   * gestapelt statt Bild-links-Text-rechts, also genau nicht das, was die
   * Variante ausmacht. Gemessen: Bild und Body untereinander (gleiches left,
   * unterschiedliches top) statt nebeneinander.
   * `display` daneben braucht KEIN Flag: die Engine setzt dort ebenfalls `flex`,
   * es gibt also nichts zu ueberstimmen. */
  flex-direction: row !important;
  align-items: stretch;
}

.mypage .molecule.team-card--landscape > picture[type='picture'] {
  width: 40%;
  flex-shrink: 0;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-xl) 0 0 var(--radius-xl);
}

.mypage .molecule.team-card--landscape .team-card-body {
  width: 60%;
  justify-content: center;
}

/* ─────────────────────────────────────────────────────────────────
 * Variante: circle
 * Rundes Avatar-Foto zentriert oben, kein Card-Rand, kompakte Stack.
 * ───────────────────────────────────────────────────────────────── */
.mypage .molecule.team-card--circle {
  /* Die Variante aendert die BILDFORM (rundes Portrait), nicht die Karte.
   * Bis 2026-08-10 entfernte sie hier zusaetzlich background, box-shadow und
   * border-radius — die Karte war damit unsichtbar, obwohl das Pattern
   * `card card-elev-sm rounded-xl` vergibt. Ein Widerspruch zwischen Molecule
   * und Pattern, im Editor nur an den Hilfsrahmen erkennbar.
   * Wer die Portraits OHNE Karte will, laesst im Template einfach die
   * card-Klassen weg — dafuer braucht es keine Variante, die sie wieder
   * abraeumt. */
  text-align: center;
  /* Das runde Portrait ist das einzige Element, das NICHT buendig sein soll —
   * ein Kreis an der Kartenoberkante sieht wie ein Fehler aus. Es bekommt
   * deshalb oben denselben Abstand, den der Body seitlich hat. */
  padding-top: 1.5rem;
}

.mypage .molecule.team-card--circle > picture[type='picture'] {
  width: 120px;
  height: 120px;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  /* Kein margin-bottom mehr (2026-08-10): der Abstand zum Namen kam bisher
   * hier her (12px) UND aus dem padding-top des Body (32px) — zusammen 44px,
   * fast doppelt so viel wie zwischen Rolle und Button. Zwei Quellen fuer
   * einen Abstand ergeben immer den falschen Abstand; jetzt liefert ihn nur
   * noch der Body. */
  margin: 0 auto;
  border: 3px solid var(--color-bg, white);
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}

.mypage .molecule.team-card--circle .team-card-cta {
  padding-top: 0.5rem;
}

/* Molecule: text-block */
.mypage .molecule.text-block {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.mypage .molecule.text-block .text-content {
  font-family: var(--bodytext-font-family);
  line-height: 1.7;
  hyphens: auto;
  -webkit-hyphens: auto;
}

.mypage .molecule.text-block .text-content p {
  margin-bottom: 1em;
}

.mypage .molecule.text-block .text-content ul,
.mypage .molecule.text-block .text-content ol {
  padding-left: 1.5em;
  margin-bottom: 1em;
}

.mypage .molecule.text-block .text-content li {
  margin-bottom: 0.25em;
}

/* Two-column layout when in wide columns */
@container (min-width: 600px) {
  .molecule.text-block.two-col .text-content {
    column-count: 2;
    column-gap: 3em;
  }
}

