/* Grundverhalten der zuschaltbaren Funktionen
   ───────────────────────────────────────────
   Die Laufzeitbibliothek setzt beim Scrollen und Klicken Klassen: .gescrollt,
   .kopf--weg, .offen, .sichtbar. Was diese Klassen bewirken, stand bisher nur
   im erzeugten Stylesheet – und das schreibt das Modell.

   Vergisst es eine Regel, passiert schlicht nichts. Genau so war es bei
   „Kopfzeile beim Scrollen ausblenden": der Schalter stand auf an, die
   Bibliothek setzte brav .kopf--weg, und in keinem einzigen erzeugten
   Stylesheet gab es eine Regel dafür. Die Funktion war seit jeher tot.

   Deshalb liegt das Grundverhalten jetzt hier, im System. Diese Datei wird
   VOR stil.css geladen: das Modell darf jede Regel überschreiben und eigene
   Bewegungen gestalten – aber wenn es nichts schreibt, funktioniert die
   Funktion trotzdem. */

/* ---------- Kopfzeile beim Scrollen ausblenden ------------------------- */

[data-kopf] { transition: transform .25s ease; }

[data-kopf].kopf--weg {
  /* 110 % statt 100 %, damit ein Schatten nicht als Streifen stehenbleibt. */
  transform: translateY(-110%);
}

/* Ist die Kopfzeile nicht klebend, wäre das Wegschieben sinnlos – dann
   scrollt sie ohnehin aus dem Bild. */
@media (prefers-reduced-motion: reduce) {
  [data-kopf] { transition: none; }
}

/* ---------- Kopfzeile oben festhalten oder loslassen (Schalter) --------- */

/* Der Schalter „Kopfzeile beim Scrollen" steht als data-kopf-fest am <html>:
   „ja" = bleibt oben, „nein" = scrollt mit. Hier die Vorgabe fürs erste
   Zeichnen; durchgesetzt wird sie von der Laufzeit (laufzeit.js, Abschnitt
   2b) mit !important am Element – dort kennt sie auch die Sonderfälle
   (Kopf als Überlagerung, innere klebende Leiste, eingesperrt durch
   overflow). */
html[data-kopf-fest="ja"] [data-kopf] { position: sticky; top: 0; z-index: 900; }
/* Der Kopf liegt immer ueber dem Inhalt - auch wenn der Entwurf ihm nichts
   oder wenig gibt und Abschnitten viel (Aashir: Untermenue „behind menu"). */
[data-kopf] { z-index: 900; }
html[data-kopf-fest="nein"] [data-kopf] { position: relative; top: auto; }
[data-kopf-platz] { display: block; }

/* ---------- Aufklappmenüs offen halten (Schreibtisch) ------------------ */

/* laufzeit.js setzt pano-offen auf die Menügruppe, solange die Maus darin
   ist – und noch 450 ms danach. So überlebt die Tafel den Weg über die
   Lücke zwischen Menüpunkt und Tafel. Lage und Bewegung (transform) bleiben
   dem Entwurf; hier nur Sichtbarkeit. */
@media (hover: hover) and (min-width: 901px) {
  .pano-offen > ul, .pano-offen > [class*="unter"], .pano-offen > [class*="dropdown"],
  .pano-offen > [class*="submenu"], .pano-offen > [class*="mega"], .pano-offen > [class*="flyout"] {
    opacity: 1 !important; visibility: visible !important; pointer-events: auto !important;
    clip-path: none !important; max-height: none !important;
  }
}

/* ---------- Mobilmenü --------------------------------------------------- */

/* Die Bibliothek setzt beide Klassen; welche das Stylesheet kennt, ist ihr
   egal. Hier die Rückfallebene für beide. */
@media (max-width: 900px) {
  .nav.offen,
  .nav.nav--open { display: block; }
}

/* ---------- Vorschaltbild ---------------------------------------------- */

/* .laedt liegt auf <html>, bis die Seite steht. Fehlt die Regel, bleibt die
   Seite unter Umständen dauerhaft verdeckt – deshalb hier die Sicherung:
   ohne Vorschaltbild ist nichts verdeckt. */
html.laedt body { visibility: visible; }

/* ── Logo im Kopf ──────────────────────────────────────────────────────
   Steht ein Logo im Markenelement, ist der Schriftzug daneben doppelt – das
   Logo trägt den Namen ja schon. Er bleibt trotzdem im Dokument stehen, für
   Vorlesehilfen und Suchmaschinen, und wird nur ausgeblendet.

   Die Unterzeile („GmbH · Wesel · seit 1979") ist Geschmackssache: manche
   Logos enthalten sie, manche nicht. Deshalb ein Schalter statt einer
   Entscheidung – siehe Funktion „Unterzeile neben dem Logo". */

/* ── Was im Kopf zu sehen ist ──────────────────────────────────────────
   Vier Dinge können dort stehen: das hochgeladene Logo, ein Kürzel im
   Kreis („PS"), der Firmenname und die Ortszeile darunter. Welche davon,
   ist eine Entscheidung – und die trifft der Schalter „Marke im Kopf".

   Angesprochen werden die Teile über data-marke, das beim Aufbau gesetzt
   wird (siehe server/marke.js). Vorher standen hier Klassennamen: __name,
   __wort, __zusatz. Die Physiotherapie-Seite nannte ihre Teile aber
   marke__zeichen und marke__text – nichts davon traf zu, und neben dem
   frisch hochgeladenen Logo blieb das erfundene Kürzel stehen. Das Modell
   erfindet die Klassen jedes Mal neu; nach Namen zu greifen geht schief. */

/* Ein hochgeladenes Logo schlägt das Kürzel. Immer und ohne Ausnahme –
   ein echtes Zeichen neben einem erfundenen Kürzel sieht nach Versehen aus. */
/* „Es gibt ein Logo" heisst: im Markenelement steckt ein Bild – nicht:
   die Klasse hat-logo ist gesetzt. Die Klasse kommt nur vom Hochladen;
   erzeugt das Modell das Logo gleich ins Markup, fehlt sie. Genau deshalb
   stand bei EIMS SHOT „Fotostudio Eimsbüttel" weiter neben dem Zeichen,
   obwohl „Nur das Logo" gewählt war: die Regeln hingen an der Klasse und
   nicht am Bild. */
/* Und umgekehrt: die Klasse allein ist kein Logo. Fällt das Bild später
   weg (Wunsch-Feld, Entfernen), bleibt hat-logo manchmal stehen - dann
   stand die Kopfzeile leer da, nur mit dem Menüknopf (MIO Sushibar). Also
   greift alles nur, wenn wirklich ein Bild im Markenelement steckt. */
:where(.hat-logo:has(> img), [data-kopf] a:has(> [data-marke="bild"])) [data-marke="zeichen"] {
  display: none;
}

/* Ohne ausdrückliche Wahl gilt: das Logo ersetzt den Schriftzug.
   Auch der Umschlag verschwindet, sonst bleibt seine Lücke stehen. */
body:not([class*="marke--"]) :where(.hat-logo:has(> img), [data-kopf] a:has(> [data-marke="bild"])) > :not([data-marke="bild"], img),
.marke--nur-bild :where(.hat-logo:has(> img), [data-kopf] a:has(> [data-marke="bild"])) > :not([data-marke="bild"], img) {
  display: none;
}

/* Nur der Name. */
.marke--name [data-marke="zeichen"],
.marke--name [data-marke="zusatz"] { display: none; }

/* Name mit Unterzeile. */
.marke--name-zusatz [data-marke="zeichen"] { display: none; }

/* Kürzel und Name – die Fassung für Seiten ohne eigenes Logo. */
.marke--zeichen [data-marke="zusatz"] { display: none; }

/* ── Symbole ───────────────────────────────────────────────────────────
   Alle aus einem Satz: 24er Raster, Strich 1.7, keine Füllung. Sie richten
   sich nach der Schriftgröße und der Farbe daneben – ein Symbol, das aus
   der Zeile fällt oder eine eigene Farbe mitbringt, sieht aufgeklebt aus. */

.symbol-halter { display: inline-flex; align-items: center; justify-content: center;
  flex: none; line-height: 0; }
.symbol { width: 1.15em; height: 1.15em; display: block; }
/* Der Satz ist reine Strichzeichnung. Eine Regel wie
   `[data-symbol] svg { fill: currentColor }` aus dem Entwurf machte daraus
   Kleckse (Sanitas). Farbe und Größe bleiben frei – nur die Füllung nicht. */
.symbol-halter svg { fill: none !important; }
/* Marken-Zeichen (Facebook, Instagram …) sind gefuellte Flaechen, keine
   Striche - fuer die gilt das Gegenteil. */
.symbol-halter svg.symbol--gefuellt { fill: currentColor !important; stroke: none !important; }

/* Im Knopf folgt das Symbol beim Ueberfahren und Klicken der Schrift.
   Entwuerfe faerben gern jedes <span> im Aufmacher fest ein (.hero span
   { color: var(--hell) }) - der Halter ist ein span, und beim Hover blieb
   das Symbol hell, waehrend der Knopf dunkel wurde (Jacob, Sanitas: „beim
   rechten Button greift die Farbaenderung des Icons beim Hover nicht").
   Nur fuer Hover und Aktiv, damit die Ruhelage des Entwurfs bleibt; ein
   Symbol mit eigener Farbe (data-farbe) behaelt sie. */
:is(a, button, [class*="knopf"], [class*="button"]):is(:hover, :active) .symbol-halter:not([data-farbe]):not([data-symbol-eigen]):not([data-symbol-eigen] *) { color: inherit !important; }

/* Neben Text: auf die optische Mitte der Zeile, in jeder Schriftgroesse -
   auch in Ueberschriften und bei eigener Symbolgroesse (Aashir: „whenever
   I add an icon to text or button, make sure it's vertically aligned").
   In Flex-Knoepfen (align-items: center) ist vertical-align egal. */
.symbol-halter { vertical-align: middle; }
:is(h1, h2, h3, h4, h5, h6, p, li, a, span, dt, dd, small, strong, em, b, label, summary, figcaption, td, th, button, blockquote) > .symbol-halter {
  margin-right: .45em;
}
/* Hinter dem Text eingefuegt (Werkzeug „Symbol", Lage „nach"): Luft links. */
.symbol-halter.symbol--nach { margin-right: 0; margin-left: .45em; }
.symbol-halter[style*="--symbol-groesse"] { vertical-align: middle !important; }

/* Größer, wenn ein Symbol allein über einer Überschrift steht. */
.symbol-halter--gross .symbol { width: 2em; height: 2em; }
/* Eigene Größe aus der Oberfläche („Symbol ändern"): steht als Variable am
   Halter und schlägt jede Regel des Entwurfs. */
.symbol-halter[style*="--symbol-groesse"] .symbol { width: var(--symbol-groesse) !important; height: var(--symbol-groesse) !important;
  max-width: none !important; max-height: none !important; }
/* Der Halter wächst mit - Entwürfe geben ihm gern eine feste Breite
   ([data-symbol] { width: 1.15em }), und svg { max-width: 100% } würde
   das Symbol darauf stauchen. Ein größerer Halter (Kreis dahinter) bleibt. */
.symbol-halter[style*="--symbol-groesse"] { min-width: var(--symbol-groesse) !important; min-height: var(--symbol-groesse) !important; }

/* ── Herkunftszeile ────────────────────────────────────────────────────
   Ganz am Ende, leise. Sie soll dastehen, nicht auffallen – die Seite
   gehört dem Kunden, nicht uns. Farben kommen von der Fußzeile, damit sie
   sich in jedes Erscheinungsbild fügt. */
.pano-herkunft {
  display: flex; align-items: center; justify-content: center; gap: .55rem;
  flex-wrap: wrap; padding: 1.1rem 1rem;
  font-size: .72rem; line-height: 1.5; opacity: .55;
  border-top: 1px solid currentColor;
  border-image: linear-gradient(to right, transparent, currentColor 30%, currentColor 70%, transparent) 1;
}
/* Text und Zeichen gehoeren zusammen und stehen in EINEM Verweis - sonst
   bricht die Zeile zwischen „von" und der Marke um, und das Zeichen steht
   allein in der naechsten Zeile. */
.pano-herkunft a {
  color: inherit; text-decoration: none;
  display: inline-flex; align-items: center; gap: .5rem;
}
.pano-herkunft a:hover { opacity: 1; }
.pano-herkunft a:hover img { opacity: .85; }
.pano-herkunft__mit { display: inline-flex; align-items: center; gap: .35rem; }
/* max-width:none, weil "img { max-width: 100% }" aus dem Reset die Zeichen
   in einer schmalen Fußspalte sonst zusammendrückt. */
.pano-herkunft img { width: auto; max-width: none; display: block; }
/* Das Panolocal-Zeichen traegt seinen Namen mit - es darf deshalb etwas
   groesser stehen als das frueher hier verwendete Wortbild. */
.pano-herkunft img { height: 21px; }

/* ── Seitenrand auf schmalen Schirmen ──────────────────────────────────
   Das Modell baut die meisten Abschnitte mit einem inneren Kasten, der den
   Seitenrand setzt – oft „.innen". Beim Aufmacher lässt es diesen Kasten
   gelegentlich weg, und dann klebt die Überschrift am Displayrand: bei
   Thiessen stand die H1 auf dem Handy bei x=0, Text an Text mit der Kante.

   Deshalb hier ein Auffangnetz: Abschnitte, die KEINEN inneren Kasten haben,
   bekommen selbst einen Rand. Die anderen bleiben unberührt – sonst stünde
   der Rand doppelt. Das entscheidet :has(), nicht eine Vermutung. */

@media (max-width: 760px) {
  section:not(:has(> [class*="innen"], > [class*="inner"], > [class*="container"],
                   > [class*="wrap"], > [class*="inhalt"])),
  header:not(:has(> [class*="innen"], > [class*="inner"], > [class*="container"],
                  > [class*="wrap"], > [class*="inhalt"])),
  footer:not(:has(> [class*="innen"], > [class*="inner"], > [class*="container"],
                  > [class*="wrap"], > [class*="inhalt"])) {
    padding-inline: clamp(16px, 5vw, 26px);
  }

  /* Bilder, die im Aufmacher über die Kante ragen sollen, dürfen das weiter. */
  section > picture, section > img, section > figure > img { margin-inline: 0; }
}

/* Ohne :has() – ältere Browser – bleibt wenigstens der Text vom Rand weg. */
@supports not selector(:has(*)) {
  @media (max-width: 760px) {
    section > h1, section > h2, section > p,
    section > * > h1, section > * > h2, section > * > p { padding-inline: 16px; }
  }
}

/* ── Kopfzeile: Beschriftungen brechen nicht ───────────────────────────
   Bei CarWasher standen sieben Menüpunkte nebeneinander, zwei davon
   zweiteilig. Ohne Vorgabe bricht der Browser mitten in der Beschriftung um:
   „Programme“ / „& Preise“, „Anfahrt &“ / „Zeiten“, und die Rufnummer im
   Knopf riss zwischen Vorwahl und Anschluss auseinander.

   Ein Menüpunkt ist eine Einheit. Er bricht nicht – er wird schmaler, und
   wenn der Platz wirklich nicht reicht, schiebt sich die Leiste seitlich.
   Das ist unauffälliger als eine zweizeilige Navigation, die die Kopfzeile
   doppelt so hoch macht. */

[data-kopf] nav a,
[data-kopf] .nav a,
[data-kopf] nav button,
[data-kopf] a.knopf,
[data-kopf] [class*="tel"] {
  white-space: nowrap;
}

/* Enger werden, bevor etwas umbricht. */
@media (min-width: 901px) and (max-width: 1280px) {
  [data-kopf] nav ul, [data-kopf] .nav ul { gap: clamp(.7rem, 1.4vw, 1.6rem); }
  [data-kopf] nav a, [data-kopf] .nav a { font-size: .88rem; }
}

/* Reicht es trotzdem nicht, schiebt sich die Leiste – sie bricht nicht. */
@media (min-width: 901px) {
  [data-kopf] nav ul, [data-kopf] .nav ul {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  [data-kopf] nav ul::-webkit-scrollbar, [data-kopf] .nav ul::-webkit-scrollbar { display: none; }
}

/* Die Zeile unter dem Firmennamen darf umbrechen – aber nicht mitten im Ort. */
[data-kopf] [class*="__zusatz"] { text-wrap: balance; }

/* ── Lange Wörter brechen, statt zu überlaufen ─────────────────────────
   Deutsch baut Komposita: „Waschprogramme", „Saugerplätze",
   „Trinkwasserhygiene". In einer schmalen Rasterspalte bei 46 Pixeln
   Schriftgröße ist so ein Wort dreimal breiter als seine Spalte – und ohne
   Umbrucherlaubnis läuft es einfach weiter, quer über die Nachbarspalte.

   Bei CarWasher stand deshalb „3 Waschprogramme" mitten in „4 SB-Boxen".
   Das ist kein Einzelfall, sondern die Regel bei deutschen Seiten: englische
   Entwürfe rechnen mit kurzen Wörtern.

   overflow-wrap bricht nur, wenn es sonst nicht passt. hyphens trennt dabei
   an der richtigen Stelle – die Seite trägt lang="de", also weiß der Browser,
   wie deutsche Silben laufen. */

/* Eine Liste von Elementen reicht nicht: bei Bedachungen Kreft stand
   „GmbH · Dachdeckermeisterbetrieb" in einem <span> in der Fusszeile und
   lief 31 Pixel aus seinem Kasten - span war in der Aufzaehlung nicht
   dabei. overflow-wrap wird vererbt, also gilt es ab body fuer alles;
   gebrochen wird ohnehin nur, wenn ein Wort sonst nicht passt, und bei
   white-space:nowrap (Menue, Rufnummer) greift es gar nicht erst. */
body { overflow-wrap: break-word; }

/* Anzeigengrößen zusätzlich sauber trennen statt hart abschneiden. */
/* Nicht die H1. Eine Trennung mitten im Ortsnamen – „Ham-burg-Eimsbüttel“ –
   liest sich wie ein Fehler, und der Aufmacher ist das Erste, was ein
   Besucher sieht. Ohne hyphens bricht die Zeile am Bindestrich oder am
   Leerzeichen; passt ein Wort wirklich nicht, greift overflow-wrap oben
   und bricht ohne Trennstrich. Für Zwischenüberschriften und Kennzahlen
   bleibt die Trennung – dort sind die deutschen Komposita das Problem. */
.zahl, [data-zaehler] { hyphens: auto; }
/* Seit 2.5.5 auch keine H2 mehr: „Bewegungskonzept statt Trainings-gerät"
   liest sich als Fehler, nicht als Typografie (Panolocal-Geschaeftsfuehrung:
   „keine komischen oder unpassenden Unterbrechungen bei den Woertern").
   Ueberschriften brechen am Leerzeichen; text-wrap: balance (base.css)
   verteilt die Zeilen dann gleichmaessig. */
h1, h2, h3 { hyphens: manual; }
/* Auf dem Handy passt ein langes Wort in Versalien oft nicht in die Zeile
   („PFERDELAUFBÄNDER" bei 360 px). Ohne Trennung bricht es dann irgendwo
   mitten durch, ohne Strich - schlimmer als eine Silbentrennung. Also dort,
   und nur dort, trennen lassen; der Browser kennt die deutschen Silben. */
@media (max-width: 600px) { h1, h2 { hyphens: auto; } }

/* Der Textkasten des Aufmachers war oft zu schmal fuer seine eigene
   Ueberschrift: max-width: 40ch sind bei 17 px Grundschrift 415 px, und
   „PFERDELAUFBÄNDER" in 49 px Versalien braucht 500 - also brach das Wort
   mitten durch (Horse Treadmill). Ein Kasten, der eine H1 traegt, ist
   mindestens 40rem breit - oder so breit wie sein Platz, wenn der kleiner
   ist (Handy). min-width schlaegt max-width, das ist so gewollt. */
:is(div, header, article):has(> h1) { min-width: min(100%, 40rem); }

/* Nicht an jeder beliebigen Silbe trennen.

   Ohne Untergrenze bricht der Browser auch dann, wenn nur zwei oder drei
   Buchstaben übrig bleiben: gemeldet wurde „LANDSCHAFTSGÄRTNERMEIS-" mit
   einem einsamen „TER" in der nächsten Zeile. Das liest sich wie ein
   Fehler, obwohl es technisch eine korrekte Trennung ist.

   Die drei Zahlen bedeuten: das Wort muss mindestens 8 Zeichen haben, vor
   dem Trennstrich stehen mindestens 4, danach ebenfalls 4. Kurze Wörter
   werden damit gar nicht mehr getrennt.

   Gilt für alles, nicht nur für Überschriften - ein Rollenzusatz unter
   einem Zitat wird genauso getrennt und sieht genauso falsch aus. */
* {
  hyphenate-limit-chars: 8 4 4;
  -webkit-hyphenate-limit-before: 4;
  -webkit-hyphenate-limit-after: 4;
  -webkit-hyphenate-limit-chars: 8 4 4;
}

/* Raster- und Flexkinder müssen schrumpfen dürfen. Ohne min-width:0 behält
   ein Kind seine Inhaltsbreite und drückt aus der Spalte heraus. */
[class*="raster"] > *, [class*="gitter"] > *, [class*="zahlen"] > *,
[class*="karten"] > *, [class*="spalten"] > * { min-width: 0; }

/* ── Platzhalter, die man nicht übersieht ──────────────────────────────
   Alle sechs Vorbildseiten haben einen Abschnitt mit Kundenstimmen, keine
   einzige unserer Seiten hatte einen – weil das Modell zu Recht nichts
   erfinden darf und im Briefing keine echten Zitate stehen.

   Also wird der Platz gebaut und der Inhalt offen gelassen. Damit das
   niemandem durchgeht, ist der leere Zustand deutlich markiert: gestrichelt,
   gedämpft, mit einem Hinweis davor. Wer das übersieht, will es übersehen.
   Beim Ausliefern zählt der Aufbau die Platzhalter und meldet sie. */
/* Jacob: „der Platzhalter ‚noch einzusetzen' soll komplett entfernt
   werden." Platzhalter sehen jetzt aus wie die anderen Karten - die
   Klasse bleibt, damit der Aufbau sie weiter zaehlt und meldet. */
[data-platzhalter] .platzhalter { position: relative; }

/* Grundgestalt für die Stimmen – das Raster, nicht das Aussehen.
   Farben und Schrift bestimmt der Entwurf der jeweiligen Seite. */
.stimmen__liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
.stimme__text { margin: 0 0 .7rem; }
.stimme__wer { margin: 0; font-size: .88rem; opacity: .78; }

/* ── Bildwechsel an einem Bild (Werkzeug „Bildwechsel“) ────────────────
   Jacob: „das statische Bild in einen Slider umwandeln". Der Behaelter
   stapelt seine Bilder in einer Rasterzelle; welches gerade zu sehen ist,
   regelt der Takt-Block im Stylesheet der Website (Bildwechsel: #id).
   Ohne diesen Block (z. B. im Editor) bleibt das erste Bild stehen. */
.pano-wechsel { position: relative; display: grid; overflow: hidden; isolation: isolate; }
.pano-wechsel > * { grid-area: 1 / 1; width: 100%; height: 100%; object-fit: cover; display: block; max-width: none; margin: 0; }
.pano-wechsel > :not(:first-child) { opacity: 0; pointer-events: none; }   /* Klick trifft das erste Bild, nicht ein unsichtbares */

/* ── Einbettung (Werkzeug „Einbettung“: 360°-Rundgang, Kalender, Video) ──
   Der Kasten haelt seine Hoehe (--einbettung-hoehe), die Einwilligung
   setzt darin das <iframe> ein - es fuellt den Kasten. Ohne Adresse steht
   ein stiller Hinweis darin. */
.pano-einbettung { position: relative; display: block; width: 100%; min-height: var(--einbettung-hoehe, 460px); border-radius: 12px; overflow: hidden; background: rgba(127,127,127,.08); }
.pano-einbettung iframe { position: absolute; inset: 0; width: 100% !important; height: 100% !important; min-height: 0 !important; border: 0; }
.pano-einbettung .ew-sperre { position: absolute; inset: 0; }
.pano-einbettung .ew-leer { position: absolute; inset: 0; display: grid; place-items: center; margin: 0; padding: 1rem; text-align: center; font-size: .9rem; opacity: .6; }

/* ── Karussell (Kundenstimmen) ─────────────────────────────────────────
   Jacob: „Testimonials standardmäßig als Karussell, idealerweise zehn."
   data-karussell an der Liste genügt: die Spur wischt per Scroll-Snap,
   laufzeit.js hängt Pfeile, Punkte und das Weiterblättern dazu. Die
   Spur-Regeln sind !important, damit ein Raster aus dem Entwurf
   (.stimmen__liste{display:grid}) sie nicht überstimmt – Farben, Schrift
   und die Karten selbst gestaltet weiterhin der Entwurf. */
.pano-karussell { position: relative; }
/* Alle Karten passen nebeneinander: keine Leiste, keine Wisch-Spur. */
.pano-karussell--statisch .pano-karussell__leiste { display: none; }
[data-karussell] {
  display: flex !important;
  grid-template-columns: none !important;
  overflow-x: auto !important;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  gap: var(--karussell-abstand, 1.25rem);
  padding: .25rem .15rem .6rem;
  margin: 0;
  list-style: none;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  outline: none;
}
[data-karussell]::-webkit-scrollbar { display: none; }
/* Ein eigenes „Laufband" des Entwurfs (Animation, Versatz) stoert die Spur. */
[data-karussell] { animation: none !important; transform: none !important; width: auto !important; }
/* Jacob: „Der Text soll außerdem immer kursiv dargestellt werden." Das
   Zitat kursiv, Name und Ort nicht. */
[data-karussell] p:not([class*="wer"]):not([class*="name"]):not([class*="autor"]):not([class*="quelle"]):not([class*="ort"]),
[data-karussell] blockquote, [data-karussell] q { font-style: italic; }
[data-karussell] > * {
  flex: 0 0 100% !important;
  max-width: 100%;
  min-width: 0;
  scroll-snap-align: start;
  box-sizing: border-box;
}
@media (min-width: 700px) {
  [data-karussell] > * { flex-basis: calc((100% - var(--karussell-abstand, 1.25rem)) / 2) !important; }
}
@media (min-width: 1040px) {
  [data-karussell] > * { flex-basis: calc((100% - 2 * var(--karussell-abstand, 1.25rem)) / 3) !important; }
}
/* Karten je Ansicht (Werkzeug „Spalten" -> Karussell, data-karussell="1|2"):
   Jacob: „nur ein Testimonial gleichzeitig sichtbar" - fuer wenige oder
   lange Kundenstimmen. Ohne Wert bleibt es bei 1/2/3 nach Breite. */
[data-karussell="1"] > * { flex-basis: 100% !important; }
@media (min-width: 700px) {
  [data-karussell="2"] > * { flex-basis: calc((100% - var(--karussell-abstand, 1.25rem)) / 2) !important; }
}
.pano-karussell__leiste {
  display: flex; align-items: center; justify-content: center; gap: .9rem;
  margin-top: .9rem;
}
.pano-karussell__pfeil {
  width: 2.5rem; height: 2.5rem; border-radius: 50%;
  border: 1px solid currentColor; background: transparent; color: inherit;
  cursor: pointer; position: relative; opacity: .8; padding: 0; font: inherit;
}
.pano-karussell__pfeil:hover, .pano-karussell__pfeil:focus-visible { opacity: 1; }
.pano-karussell__pfeil::before {
  content: ""; position: absolute; top: 50%; left: 50%; width: .55rem; height: .55rem;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translate(-30%, -50%) rotate(-45deg);
}
.pano-karussell__pfeil--zurueck::before { transform: translate(-70%, -50%) rotate(135deg); }
.pano-karussell__punkte { display: flex; gap: .45rem; align-items: center; }
.pano-karussell__punkt {
  width: .55rem; height: .55rem; border-radius: 50%; padding: 0; border: 0;
  background: currentColor; opacity: .3; cursor: pointer; transition: opacity .2s, transform .2s;
}
.pano-karussell__punkt.ist-aktiv { opacity: .95; transform: scale(1.25); }
@media (prefers-reduced-motion: reduce) {
  [data-karussell] { scroll-behavior: auto; }
}

/* ── Flächenbilder dürfen die Seite nicht aufschieben ──────────────────
   Ein Bild, das als Fläche hinter dem Inhalt liegt, bekommt oft eine
   langsame Zufahrt: transform: scale(1.05) über zwanzig Sekunden. Damit
   ist es fünf Prozent breiter als sein Kasten – auf dem Handy elf Pixel
   links und elf rechts. Der Aufmacher fängt das mit overflow:hidden ab,
   der Seitenkopf der Kontaktseite tat es nicht, und die ganze Seite ließ
   sich seitlich schieben.

   Die Entwürfe nennen solche Bilder durchgehend *__bild – hero__bild,
   seitenkopf__bild, bildflaeche__bild. Der Kasten darum klemmt sie ab.

   overflow:hidden allein genügt dabei nicht. Ein absolut gesetztes Bild
   hängt an seinem nächsten POSITIONIERTEN Vorfahren; steht der Abschnitt auf
   position:static, ist er gar nicht sein Kasten und klemmt folglich auch
   nichts ab. Erst beides zusammen wirkt. */
:is(section, header, article, aside, div, figure):has(> img[class*="bild"]),
:is(section, header, article, aside, div, figure):has(> video[class*="bild"]) {
  position: relative;
  overflow: hidden;
}

/* ── Rasterkinder dürfen die Seite nicht aufschieben ───────────────────
   Ein min-width auf einem Rasterkind ist stärker als die Spalte: die Spur
   kann nicht schmaler werden, und bei fester Spaltenzahl läuft das Raster
   aus dem Bild. Bei EIMS SHOT waren es vier Spalten à 14rem – auf dem
   Tablet 226 Pixel zu viel, die Seite ließ sich seitlich schieben.

   min(…, 100%) hält die gewünschte Mindestbreite auf breiten Schirmen und
   gibt sie auf schmalen auf. Wirkt nur dort, wo ohnehin ein min-width in
   rem steht – Layouts ohne diese Angabe bleiben unberührt. */
@media (max-width: 900px) {
  [class*="zahlen"] > *, [class*="raster"] > *, [class*="gitter"] > *,
  [class*="karten"] > *, [class*="kacheln"] > * {
    min-width: 0;
  }
}


/* ---------- Lichtkasten der Galerie -------------------------------------
   Zwei Fehler, beide beim Kunden gelandet - gemessen an der fertigen
   Schluesseldienst-Seite: der Kasten sass bei 0,0 statt in der Mitte, und
   das Bild war 141x235 gross.

   1. NICHT ZENTRIERT. Einen Modal-Dialog zentriert der Browser mit
      margin:auto. Im Entwurf steht *{margin:0} - eine Autorenregel, und
      die schlaegt die Browserregel. Also klebte der Dialog in der Ecke.
      Deshalb wird hier gar nicht ueber margin zentriert: der Dialog fuellt
      das Fenster und setzt das Bild per grid in die Mitte. Das kann kein
      Reset mehr aushebeln.

   2. WINZIG. max-height vergroessert nichts, es begrenzt nur - ein kleines
      Motiv blieb klein. min-height hebt es auf eine ansehnliche Groesse;
      object-fit haelt dabei das Seitenverhaeltnis, damit nichts verzerrt.

   Die Klasse steht doppelt, weil stil.css NACH dieser Datei geladen wird.
   Bei gleicher Spezifitaet gewaenne der Entwurf - derselbe Stolperstein
   wie in medienregeln.js. */
dialog.lichtkasten.lichtkasten {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  display: grid;
  place-items: center;
  overflow: visible;
}
dialog.lichtkasten.lichtkasten::backdrop { background: rgba(0, 0, 0, .9); }

dialog.lichtkasten.lichtkasten img {
  display: block;
  grid-area: 1 / 1;
  width: auto;
  height: auto;
  max-width: min(92vw, 1600px);
  max-height: 88%;
  /* Die tatsaechliche Groesse rechnet laufzeit.js - es kennt als
     einziges die echte Bildgroesse. Hier stehen nur die Obergrenzen als
     Netz, falls das JavaScript ausfaellt. Kein min-height: min schlaegt
     max, das wuerde die 2x-Grenze wieder aushebeln. */
  object-fit: contain;
  border-radius: 4px;
}

dialog.lichtkasten.lichtkasten button {
  position: absolute;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
}
dialog.lichtkasten.lichtkasten button:hover,
dialog.lichtkasten.lichtkasten button:focus-visible { background: rgba(0, 0, 0, .85); }
dialog.lichtkasten.lichtkasten .lk-zu { top: 1rem; right: 1rem; font-size: 1.6rem; }
dialog.lichtkasten.lichtkasten .lk-vor { left: 1rem; top: 50%; transform: translateY(-50%); }
dialog.lichtkasten.lichtkasten .lk-nach { right: 1rem; top: 50%; transform: translateY(-50%); }

/* ── Logo nicht verzerren ──────────────────────────────────────────────
   Gemessen auf der Gästehaus-Seite: die Datei ist 767 × 247 (Verhältnis
   3,11), angezeigt wurde sie mit 105 × 40 (Verhältnis 2,64). Das Logo war
   also um 15 % in die Breite gestaucht - bei einem Schriftzug sieht man
   das sofort, und es ist das Erste, was ein Kunde im Kopf anschaut.

   Ursache ist nicht das Bild, sondern die Kombination aus fester Breite
   UND fester Höhe im Markup. Ohne object-fit füllt das Bild dann stur
   beide Maße aus. `contain` behält das Seitenverhältnis; das Bild wird
   kleiner statt schief. */
[data-marke="bild"],
.marke img,
.marke__logo,
[data-kopf] .marke img {
  object-fit: contain;
  object-position: left center;
}

/* ── Jeder Abschnitt ist ein Bezugsrahmen ──────────────────────────────
   Ohne diese Zeile rutschen absolut gesetzte Kästen aus ihrem Abschnitt
   heraus. Gemessen auf der Back-Bistro-Seite:

     DIV.flaeche__bild, position:absolute, gehört zu Abschnitt 6
     Abschnitt 6 liegt bei y=1895 und ist 1440x505 groß
     der Kasten landete aber bei 0,0 und war 1440x760 groß

   Der Grund ist die CSS-Regel selbst: ein absolut gesetzter Kasten sucht
   sich den nächsten positionierten Vorfahren. Gibt es keinen, nimmt er den
   Anfang des Dokuments. Das Foto aus Abschnitt 6 legte sich damit über den
   Aufmacher - und in Abschnitt 6 blieb ein Loch.

   Sichtbar war das als „das Hero-Bild lässt sich nicht abdunkeln": jede
   Reparatur traf brav das echte Aufmacherbild, während oben ein ganz
   anderes Foto lag.

   position:relative kostet nichts und schließt die Lücke für alle
   Abschnitte auf einmal. */
main > section,
main > article,
.abschnitt {
  position: relative;
}

/* ---------- Einwilligungszeile im Kontaktformular ----------

   Ein <label> mit Kontrollkästchen und Fließtext darf KEIN Flex-Container
   sein. In einem Flex-Container wird jeder Textabschnitt zwischen zwei
   Elementen zu einem eigenen anonymen Element - aus

     <label><input type="checkbox"> Ich habe die <a>Datenschutz</a> gelesen …</label>

   werden vier nebeneinanderstehende Spalten. Gemessen bei „AJ
   Schlüsseldienst": das Wort „Ich habe die" stand in einer 33 px schmalen
   Spalte über drei Zeilen, daneben die Verlinkung als eigener Kasten.
   Genau das ist der gemeldete Style-Fehler.

   Deshalb hier ein Netz: hängendes Kästchen, fließender Text. Das gilt
   auch für Formulare, die heute zufällig gut aussehen - dort ändert sich
   nichts Sichtbares. */
form label:has(> input[type="checkbox"]) {
  display: block;
  position: relative;
  padding-left: 1.9em;
  line-height: 1.5;
  /* Ein Flex- oder Grid-Elternteil darf die Zeile nicht wieder zerlegen. */
  flex: 1 1 100%;
}
form label:has(> input[type="checkbox"]) > input[type="checkbox"] {
  position: absolute;
  left: 0;
  top: .25em;
  margin: 0;
  flex: none;
}

/* Galeriebilder ohne Link müssen trotzdem als anklickbar erkennbar sein -
   der Lichtkasten öffnet sie jetzt auch ohne <a> darum herum. */
[data-galerie] img { cursor: zoom-in; }
[data-galerie] a img { cursor: pointer; }

/* Ein Absatz, der nur einen Knopf enthaelt, ist keine Textzeile - die
   Lesebreite (p{max-width:68ch}) gilt fuer ihn nicht. Sonst sitzt ein
   „zentrierter" Knopf in einem 68ch breiten Kasten links und wirkt wie
   angeklebt (Studio Boetel, Galerie: drei Prompts, dreimal daneben). */
main p:has(> a.knopf:only-child), main p:has(> button.knopf:only-child) { max-width: none; }

/* Ueberlagerung von Hand (Werkzeug „Überlagerung"): letztes Kind des
   Abschnitts, liegt ueber Foto oder Slider; der Inhalt wird eine Ebene
   hoeher gehoben - Bildtraeger bleiben unten. */
main :is(section, div, article):has(> .pano-schleier) { position: relative; isolation: isolate; }
.pano-schleier { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
/* WELCHE Kinder gehoben werden, entscheidet seit dem 15.9. die Oberflaeche
   beim Setzen (hebbar in app.js: im Fluss, kein Bildgrund) und der Server
   schreibt es als style mit der Marke data-pano-gehoben. Die blinde Regel
   hier gilt nur noch fuer Abschnitte von frueher, in denen kein Kind die
   Marke traegt. Blind war sie gefaehrlich: ein absolut gesetzter Bildkasten
   (Grit Eisenblaetter: .hero__bild mit inset:0 in einem Flex-Aufmacher)
   wurde position:relative und damit zum Flex-Kind neben dem Text - Foto
   links, rechts ein harter, deckender Block in der Grundfarbe. */
main :is(section, div, article):has(> .pano-schleier):not(:has(> [data-pano-gehoben])) > :not(.pano-schleier):not(img):not(video):not(picture):not([role="img"]):not([aria-hidden="true"]):not([class*="bild-hg"]):not([class*="hintergrund"]):not([class*="slider"]):not([data-pano-wechsel]) { position: relative; z-index: 1; }
/* Der Entwurf legt ueber solche Fotos meist selbst schon einen Schleier
   als ::before/::after mit inset:0 und rgba. Die Ueberlagerung von Hand kam
   obendrauf - der Regler bewegte nur die obere von zwei Schichten, bei 0 %
   blieb der Entwurfsschleier stehen (Jacob: „the image becomes paler, the
   overlay color lighter"). Solange .pano-schleier im Abschnitt liegt, sind
   diese Schichten aus; welche es sind, hat die Oberflaeche gemessen und
   steht in data-pano-eigen (siehe direktbearbeiten.js - ein Verlauf VOR dem
   Foto in background-image wird dort als style ersetzt). Ohne .pano-schleier
   gilt der Entwurf wieder. :not(#pano-nie) hebt die Spezifitaet ueber eine
   Kennung im Entwurf, !important ueber dessen eigenes !important. */
main :is(section, div, article)[data-pano-eigen~="before"]:not(#pano-nie):has(> .pano-schleier)::before,
main :is(section, div, article)[data-pano-eigen~="after"]:not(#pano-nie):has(> .pano-schleier)::after { background: transparent !important; }

/* ── Untermenues in der Kopfzeile ──────────────────────────────────────
   Ein Menuepunkt mit einer Liste darin (<li><a>Geraete</a><ul>…</ul></li>)
   klappt am PC beim Ueberfahren oder per Tastatur auf; auf dem Handy steht
   die Liste eingerueckt unter dem Punkt im Hamburger-Menue. Traegt ein
   Unterpunkt selbst eine Liste, wird aus dem Aufklapper ein Mega-Menue mit
   Spalten (Motorgeraete Freitag: zwoelf Bereiche mit ihren Geraeten).
   Bisher musste das Modell so etwas je Website selbst schreiben - und tat
   es nicht (Jacob: Untermenue per Prompt bestellt, nie bekommen). Die
   Farben kommen vom Kopf selbst: laufzeit.js setzt data-kopf-dunkel, wenn
   der Kopf dunkel ist. Spezifitaet [data-kopf] + Elemente schlaegt die
   ueblichen .nav-Regeln des Entwurfs; wo der Entwurf haerter zieht,
   !important. */
[data-kopf] nav li:has(> ul) { position: relative !important; }
/* Die Menueleiste selbst darf nichts abschneiden - manche Entwuerfe geben
   ihr overflow: auto (Motorgeraete Freitag), und das Untermenue war weg. */
[data-kopf] nav ul:has(> li > ul), [data-kopf] nav:has(li > ul) { overflow: visible !important; }
@media (max-width: 900px) { [data-kopf] nav:has(li > ul) { overflow: auto !important; } }
[data-kopf] nav li:has(> ul) > a::after { content: ""; display: inline-block; width: .42em; height: .42em; margin-left: .38em; border: solid currentColor; border-width: 0 1.6px 1.6px 0; transform: translateY(-.15em) rotate(45deg); opacity: .7; }
[data-kopf] nav li > ul {
  position: absolute !important; top: 100%; left: 0; z-index: 70;
  display: block !important; min-width: 230px; margin: 0; padding: .5rem 0; list-style: none;
  flex-direction: column; gap: 0;
  background: var(--pano-menue-hg, #fff); color: var(--pano-menue-farbe, #1a1d21);
  border-radius: 10px; box-shadow: 0 14px 36px rgba(0,0,0,.16), 0 0 0 1px rgba(0,0,0,.06);
  opacity: 0; visibility: hidden; transform: translateY(6px); transition: opacity .16s ease, transform .16s ease, visibility .16s;
  text-align: left;
}
[data-kopf][data-kopf-dunkel] { --pano-menue-hg: #1b1e22; --pano-menue-farbe: #f2f3f4; }
[data-kopf] nav li:is(:hover, :focus-within, .pano-offen) > ul { opacity: 1; visibility: visible; transform: none; }
/* Ragt ein Menue rechts oder links aus dem Fenster, schiebt laufzeit.js es
   zurueck (--pano-menue-versatz) - ein reines CSS-Kriterium gibt es dafuer nicht. */
[data-kopf] nav li > ul { left: var(--pano-menue-versatz, 0px); }
[data-kopf] nav li > ul li { display: block; margin: 0; padding: 0; }
[data-kopf] nav li > ul a { display: block; padding: .5rem 1.1rem; color: inherit !important; text-decoration: none; white-space: nowrap; border: 0 !important; font-size: .95em; line-height: 1.35; }
[data-kopf] nav li > ul a:hover, [data-kopf] nav li > ul a:focus-visible { background: rgba(127,127,127,.12); }
/* Mega-Menue: Unterpunkte mit eigener Liste werden zu Spalten. */
[data-kopf] nav li > ul:has(> li > ul) { display: grid !important; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: .6rem 1.4rem; min-width: min(780px, calc(100vw - 2rem)); padding: 1.1rem 1.2rem; }
[data-kopf] nav li > ul > li > ul { position: static !important; opacity: 1; visibility: visible; transform: none; box-shadow: none; background: transparent; border-radius: 0; min-width: 0; padding: .15rem 0 0; margin: 0; }
[data-kopf] nav li > ul > li:has(> ul) > a { font-weight: 700; padding-bottom: .2rem; }
[data-kopf] nav li > ul > li:has(> ul) > a::after { content: none; }
[data-kopf] nav li > ul > li > ul a { padding: .32rem 1.1rem; opacity: .9; font-size: .92em; white-space: normal; }
[data-kopf] nav li > ul:has(> li > ul) > li > a { white-space: normal; }
/* Handy und Tablet: im aufgeklappten Menue alles untereinander, eingerueckt. */
@media (max-width: 900px) {
  [data-kopf] nav li > ul, [data-kopf] nav li > ul:has(> li > ul) {
    position: static !important; display: block !important; opacity: 1; visibility: visible; transform: none;
    min-width: 0; padding: 0 0 .25rem .9rem; margin: 0; box-shadow: none; background: transparent; color: inherit; border-radius: 0;
  }
  [data-kopf] nav li:has(> ul) > a::after { content: none; }
  [data-kopf] nav li > ul a { white-space: normal; padding: .4rem .6rem; }
}

/* Effekte fuer Hintergruende (Werkzeug „Effekt", data-effekt am Abschnitt).
   fest: das Foto bleibt stehen, der Inhalt schiebt sich darueber (Vorhang).
   parallax: Foto bewegt sich langsamer (Versatz aus laufzeit.js).
   zoom: langsames Heranfahren des Fotos. */
/* !important: „Hintergrund setzen" schreibt background-position als style an
   den Abschnitt - ohne Vorrang verloere die Effekt-Regel dagegen. */
[data-effekt="fest"] { background-attachment: fixed !important; }
/* Vorhang auch fuer ein Foto als Bildelement: das Bild haengt fest am
   Fenster, der Abschnitt schneidet es zu (clip-path bildet den Rahmen).
   So geht „fest" auch bei Entwuerfen, die das Foto als <img> legen. */
[data-effekt="fest"]:has(> img, > [class*="bild"] > img, > [class*="hg"] > img, > [role="img"]) { clip-path: inset(0); position: relative; isolation: isolate; }
[data-effekt="fest"] > img, [data-effekt="fest"] > [class*="bild"] > img, [data-effekt="fest"] > [class*="hg"] > img,
[data-effekt="fest"] > [role="img"] { position: fixed !important; inset: 0 !important; width: 100% !important; height: 100vh !important; height: 100lvh !important;
  object-fit: cover !important; z-index: -100 !important; animation: none !important; transform: none !important; }
/* z-index -100, nicht -1: Entwuerfe legen ihre Abdunklung (::before) gern auf
   -1 und das Foto auf -2. Mit -1 lag das festgehaltene Foto auf gleicher
   Hoehe wie der Schleier und wurde spaeter gemalt - der Schleier war weg
   (Jacob: „Vorhang deaktiviert die Overlay-Farbe"). Ganz unten bleibt das
   Foto unter jeder Schicht, die der Entwurf darueber legt. */
@media (hover: none), (max-width: 900px) {
  [data-effekt="fest"] { background-attachment: scroll !important; }
  [data-effekt="fest"] > img, [data-effekt="fest"] > [class*="bild"] > img, [data-effekt="fest"] > [class*="hg"] > img,
  [data-effekt="fest"] > [role="img"] { position: absolute !important; height: 100% !important; }
}
/* Kein Kacheln: der Versatz schiebt das Foto aus der Flaeche, und ohne
   no-repeat kam von der anderen Seite die naechste Kopie herein (Jacob:
   „the picture is displayed repeating" - auf dem Handy, wo ein
   Querformat die hohe Flaeche gerade so deckt). Auf schmalen Schirmen
   bleibt das Foto ganz stehen: dort gibt es keine Reserve zum Schieben. */
[data-effekt="parallax"] { background-position: center calc(50% + var(--pano-versatz, 0px)) !important; background-repeat: no-repeat !important; overflow: hidden; }
@media (max-width: 900px) { [data-effekt="parallax"]:not([data-effekt-traeger]) { background-position: center !important; } }
/* !important auch hier: Entwuerfe animieren das Aufmacherfoto gern selbst
   (transform-Zoom mit „both"). Eine Animation schlaegt jede normale Regel,
   also blieb Parallax stumm (Jacob: „der Effekt ist plötzlich nicht mehr
   aktiv"). Nur !important steht ueber einer Animation. */
[data-effekt="parallax"] > img, [data-effekt="parallax"] > [class*="bild"] > img, [data-effekt="parallax"] > [class*="hg"] > img,
[data-effekt="parallax"] > [role="img"] { transform: translateY(var(--pano-versatz, 0px)) scale(1.18) !important; will-change: transform; animation: none !important; }
[data-effekt="zoom"] { overflow: hidden; }
[data-effekt="zoom"] > img, [data-effekt="zoom"] > [class*="bild"] > img, [data-effekt="zoom"] > [class*="hg"] > img,
[data-effekt="zoom"] > [role="img"] { animation: panoZoom 18s ease-out forwards !important; }
@keyframes panoZoom { from { transform: scale(1); } to { transform: scale(1.12); } }
@media (prefers-reduced-motion: reduce) { [data-effekt="zoom"] > *, [data-effekt="parallax"] > * { animation: none !important; transform: none !important; } }
/* Traeger fuer CSS- und Pseudo-Hintergruende (laufzeit.js legt .pano-hg an,
   wenn ein Abschnitt mit Effekt sein Foto nicht als Bildelement hat). Er
   liegt unter allem Inhalt (z-index -10 im eigenen Stapel des Abschnitts)
   und ueber dem statischen Hintergrund; ein Pseudo-Foto wird darunter
   ausgeblendet, sonst laege es doppelt. So bewegen, zoomen und halten sich
   alle Fotos gleich - egal wie der Entwurf sie gelegt hat. */
[data-effekt-traeger] { position: relative; isolation: isolate; overflow: hidden; }
[data-effekt-traeger] > .pano-hg { position: absolute; inset: 0; z-index: -10; pointer-events: none;
  background-repeat: no-repeat; background-size: cover; background-position: center; }
[data-effekt-traeger="before"]::before, [data-effekt-traeger="after"]::after { background-image: none !important; animation: none !important; }
[data-effekt="parallax"] > .pano-hg { transform: translateY(var(--pano-versatz, 0px)) scale(1.3) !important; will-change: transform; }
[data-effekt="zoom"] > .pano-hg { animation: panoZoom 18s ease-out forwards !important; }
[data-effekt="fest"] > .pano-hg { background-attachment: fixed !important; }
@media (hover: none), (max-width: 900px) { [data-effekt="fest"] > .pano-hg { background-attachment: scroll !important; } }
@media (prefers-reduced-motion: reduce) { [data-effekt] > .pano-hg { animation: none !important; transform: none !important; } }

/* Werkzeug „Ausrichten" nimmt Symbole und Bilder mit (Jacob: „Momentan muss
   man Icons separat ausrichten"): blockartige Symbolhalter, Kaesten, die nur
   ein Symbol enthalten, und Bilder direkt im ausgerichteten Baustein
   folgen der Textausrichtung. Inline-Symbole neben Text folgen ohnehin dem
   text-align; ihre Auto-Raender wirken nicht (inline), also stoert das nicht. */
/* Nur der aeussere Kasten wandert - nie das Zeichen IN seinem Kasten: das
   sass sonst seitlich in der Farbflaeche (Jacob, Kinderarztpraxis). Ein
   Halter, der allein in einem Kasten steckt, bleibt darin mittig. */
[data-ausrichtung="mitte"] > .symbol-halter:not(:only-child), [data-ausrichtung="mitte"] > :is(div, span, figure):has(> [data-symbol]:only-child), [data-ausrichtung="mitte"] > img { margin-left: auto !important; margin-right: auto !important; }
[data-ausrichtung="rechts"] > .symbol-halter:not(:only-child), [data-ausrichtung="rechts"] > :is(div, span, figure):has(> [data-symbol]:only-child), [data-ausrichtung="rechts"] > img { margin-left: auto !important; margin-right: 0 !important; }
[data-ausrichtung="links"] > .symbol-halter:not(:only-child), [data-ausrichtung="links"] > :is(div, span, figure):has(> [data-symbol]:only-child), [data-ausrichtung="links"] > img { margin-left: 0 !important; margin-right: auto !important; }
/* Und grundsaetzlich: ein Zeichen allein in seinem Kasten sitzt mittig -
   waagerecht und senkrecht, egal was ein Entwurf am Kasten macht. Den
   Kasten markiert laufzeit.js (data-symbol-kasten = block/inline/grid);
   eine eigene Ausrichtung im Kasten (Werkzeug „Ausrichten" am Symbol)
   steht als style am Kasten und gewinnt. */
[data-symbol-kasten="block"] { display: flex; }
[data-symbol-kasten="inline"] { display: inline-flex; }
[data-symbol-kasten="grid"] { display: grid; }
[data-symbol-kasten] { align-items: center; justify-content: center; place-items: center; }
[data-symbol-kasten] > .symbol-halter { margin: 0 !important; }

/* Werkzeug „Symbol": Flaeche hinter dem Symbol weg (data-pano-flaeche="ohne"
   am Halter - und am Kasten darum, wenn er nur das Symbol enthaelt). Der
   Kasten behaelt seine Masse, damit nichts verrutscht; nur Farbe, Rand und
   Schatten gehen. */
[data-pano-flaeche="ohne"] { background: none !important; border-color: transparent !important; box-shadow: none !important; outline: 0 !important; }

/* Abstand je Geraet (Werkzeug „Abstand"): die Werte stehen als Variablen
   am Element - Basis fuer alle Geraete, dazu Tablet (601-960 px) und Handy
   (bis 600 px). Die Reihenfolge entscheidet: die Geraeteregeln stehen
   spaeter und gewinnen bei gleicher Staerke (Aashir: „adjust mobile
   separately, tablet separately and web separately"). */
/* In einer Kaskadenschicht: !important-Regeln einer benannten Schicht
   gewinnen gegen !important-Regeln ausserhalb jeder Schicht - egal wie
   spezifisch der Entwurf sie schreibt (.kopf .nav .knopf { padding …
   !important }). Der alte Weg (inline !important) schlug alles; das hier
   muss genauso verlaesslich sein. */
@layer pano-werkzeug {
  [data-pano-abstand][style*="--pano-p:"] { padding: var(--pano-p) !important; }
  [data-pano-abstand][style*="--pano-m:"] { margin: var(--pano-m) !important; }
  @media (min-width: 601px) and (max-width: 960px) {
    [data-pano-abstand][style*="--pano-p-tablet:"] { padding: var(--pano-p-tablet) !important; }
    [data-pano-abstand][style*="--pano-m-tablet:"] { margin: var(--pano-m-tablet) !important; }
  }
  @media (max-width: 600px) {
    [data-pano-abstand][style*="--pano-p-handy:"] { padding: var(--pano-p-handy) !important; }
    [data-pano-abstand][style*="--pano-m-handy:"] { margin: var(--pano-m-handy) !important; }
  }
  /* Seitenabstand + feste Breite: mittig halten, nie enger als eingestellt
     (Merker setzt der Bau, siehe mitteSichern in freibauen.js). Sonst
     klebte z. B. die Kopfzeile auf breiten Schirmen links. */
  @media (min-width: 961px) {
    [data-pano-abstand][style*="--pano-mx:"][style*="--pano-breite:"] {
      margin-left: max(var(--pano-mx), (100% - var(--pano-breite)) / 2) !important;
      margin-right: max(var(--pano-mx), (100% - var(--pano-breite)) / 2) !important;
    }
  }
}

/* Galerie je Geraet (Werkzeug „Galerie", data-pano-galeriemass am Raster):
   Spalten, Bildhoehe und Abstand getrennt fuer Handy (bis 600 px), Tablet
   (601-960), PC (ab 961) und grossen Bildschirm (ab 1440) - Aashir: „control
   gallery responsiveness on each layout". Die Werte stehen als Variablen am
   Behaelter (--pg-sp-*, --pg-h-*, --pg-abst-*); fehlt eine, bleibt es wie
   gestaltet. Grosser Bildschirm ohne eigene Werte erbt den PC (die PC-Regel
   gilt ab 961 px, die fuer gross steht spaeter und gewinnt). In der
   Werkzeug-Schicht, damit sie gegen „Spalten" und Entwurfs-!important
   gewinnt (siehe Abstand oben). */
@layer pano-werkzeug {
  [data-pano-galeriemass] > * { min-width: 0; }
  @media (max-width: 600px) {
    [data-pano-galeriemass][style*="--pg-sp-handy:"] { display: grid !important; grid-template-columns: repeat(var(--pg-sp-handy), minmax(0, 1fr)) !important; }
    [data-pano-galeriemass][style*="--pg-sp-handy:"] > * { grid-column: auto !important; grid-row: auto !important; }
    [data-pano-galeriemass][style*="--pg-abst-handy:"] { gap: var(--pg-abst-handy) !important; }
    [data-pano-galeriemass][style*="--pg-h-handy:"] > * { height: auto !important; min-height: 0 !important; max-height: none !important; aspect-ratio: auto !important; }
    [data-pano-galeriemass][style*="--pg-h-handy:"] img { position: relative !important; inset: auto !important; width: 100% !important; height: var(--pg-h-handy) !important; max-height: none !important; aspect-ratio: auto !important; object-fit: cover; }
  }
  @media (min-width: 601px) and (max-width: 960px) {
    [data-pano-galeriemass][style*="--pg-sp-tablet:"] { display: grid !important; grid-template-columns: repeat(var(--pg-sp-tablet), minmax(0, 1fr)) !important; }
    [data-pano-galeriemass][style*="--pg-sp-tablet:"] > * { grid-column: auto !important; grid-row: auto !important; }
    [data-pano-galeriemass][style*="--pg-abst-tablet:"] { gap: var(--pg-abst-tablet) !important; }
    [data-pano-galeriemass][style*="--pg-h-tablet:"] > * { height: auto !important; min-height: 0 !important; max-height: none !important; aspect-ratio: auto !important; }
    [data-pano-galeriemass][style*="--pg-h-tablet:"] img { position: relative !important; inset: auto !important; width: 100% !important; height: var(--pg-h-tablet) !important; max-height: none !important; aspect-ratio: auto !important; object-fit: cover; }
  }
  @media (min-width: 961px) {
    [data-pano-galeriemass][style*="--pg-sp-pc:"] { display: grid !important; grid-template-columns: repeat(var(--pg-sp-pc), minmax(0, 1fr)) !important; }
    [data-pano-galeriemass][style*="--pg-sp-pc:"] > * { grid-column: auto !important; grid-row: auto !important; }
    [data-pano-galeriemass][style*="--pg-abst-pc:"] { gap: var(--pg-abst-pc) !important; }
    [data-pano-galeriemass][style*="--pg-h-pc:"] > * { height: auto !important; min-height: 0 !important; max-height: none !important; aspect-ratio: auto !important; }
    [data-pano-galeriemass][style*="--pg-h-pc:"] img { position: relative !important; inset: auto !important; width: 100% !important; height: var(--pg-h-pc) !important; max-height: none !important; aspect-ratio: auto !important; object-fit: cover; }
  }
  @media (min-width: 1440px) {
    [data-pano-galeriemass][style*="--pg-sp-gross:"] { display: grid !important; grid-template-columns: repeat(var(--pg-sp-gross), minmax(0, 1fr)) !important; }
    [data-pano-galeriemass][style*="--pg-sp-gross:"] > * { grid-column: auto !important; grid-row: auto !important; }
    [data-pano-galeriemass][style*="--pg-abst-gross:"] { gap: var(--pg-abst-gross) !important; }
    [data-pano-galeriemass][style*="--pg-h-gross:"] > * { height: auto !important; min-height: 0 !important; max-height: none !important; aspect-ratio: auto !important; }
    [data-pano-galeriemass][style*="--pg-h-gross:"] img { position: relative !important; inset: auto !important; width: 100% !important; height: var(--pg-h-gross) !important; max-height: none !important; aspect-ratio: auto !important; object-fit: cover; }
  }
}

/* Spalten-Regeln in der Werkzeug-Schicht. Vorher standen sie ausserhalb
   jeder Schicht in funktionen.css, und die Datei laedt VOR stil.css: jede
   Galerie-Regel des Entwurfs mit !important schlug die gewaehlte
   Spaltenzahl (Jacob, Nuad: „die Spalten wirken nicht auf die Galerie").
   !important in einer benannten Schicht gewinnt gegen jedes !important
   ausserhalb - wie bei Abstand und „Galerie je Geraet". */
@layer pano-werkzeug {
  /* Feste Spaltenzahl (Werkzeug „Spalten", data-pano-spalten am Behaelter):
     am PC genau so viele Spalten, darunter zwei, auf dem Handy eine. */
  [data-pano-spalten] { display: grid !important; }
  [data-pano-spalten] > * { min-width: 0; }
  [data-pano-spalten="1"] { grid-template-columns: minmax(0, 1fr) !important; }
  [data-pano-spalten="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  [data-pano-spalten="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
  [data-pano-spalten="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }
  [data-pano-spalten="5"] { grid-template-columns: repeat(5, minmax(0, 1fr)) !important; }
  [data-pano-spalten="6"] { grid-template-columns: repeat(6, minmax(0, 1fr)) !important; }
  @media (max-width: 960px) { [data-pano-spalten="3"], [data-pano-spalten="4"], [data-pano-spalten="5"], [data-pano-spalten="6"] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; } }
  /* Tablet (601-960 px) ausdruecklich (Jacob: „Desktop und Tablet: 3 Bilder pro
     Reihe"): ohne Angabe bleibt es bei hoechstens zwei, siehe oben. */
  @media (min-width: 601px) and (max-width: 960px) {
    [data-pano-spalten-tablet="1"] { grid-template-columns: minmax(0, 1fr) !important; }
    [data-pano-spalten-tablet="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
    [data-pano-spalten-tablet="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
    [data-pano-spalten-tablet="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }
  }
  @media (max-width: 600px) { [data-pano-spalten] { grid-template-columns: minmax(0, 1fr) !important; } }
  /* Spalten auf dem Handy (Werkzeug „Spalten", zweite Reihe): auch ohne
     feste PC-Spalten anwendbar - eine Galerie darf auf dem Handy zwei oder
     drei Spalten haben (Jacob). */
  @media (max-width: 600px) {
    [data-pano-spalten-mobil] { display: grid !important; }
    [data-pano-spalten-mobil="1"] { grid-template-columns: minmax(0, 1fr) !important; }
    [data-pano-spalten-mobil="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
    [data-pano-spalten-mobil="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
    [data-pano-spalten-mobil] > * { min-width: 0; }
  }
  /* Galerien auf dem Handy: zwei Spalten als Vorgabe (Jacob/Aashir,
     28.09.2026). data-pano-galerie-auto setzt der Bau nur an echte
     Bilderreihen (galerienMarkieren). Eine eigene Wahl - „Spalten" Handy
     oder „Galerie je Geraet" Handy - geht vor. Gilt auch fuer Galerien,
     die als Spalten-Satz (column-count) gebaut sind. */
  @media (max-width: 600px) {
    [data-pano-galerie-auto]:not([data-pano-spalten-mobil]):not([style*="--pg-sp-handy:"]) {
      display: grid !important; grid-template-columns: repeat(2, minmax(0, 1fr)) !important; column-count: auto !important;
    }
    [data-pano-galerie-auto]:not([data-pano-spalten-mobil]):not([style*="--pg-sp-handy:"]) > * {
      min-width: 0; grid-column: auto !important; grid-row: auto !important; width: auto !important; margin-left: 0 !important; margin-right: 0 !important;
    }
  }
}

/* Fotostrecke hinter einem Bild (data-pano-bilder, laufzeit.js 6b): das
   Bild laedt zum Anklicken ein, der Hinweis „5 Fotos" sitzt unten rechts. */
img[data-pano-bilder] { cursor: zoom-in; }
img[data-pano-bilder]:focus-visible { outline: 3px solid rgba(255,255,255,.9); outline-offset: -6px; }
.pano-bildzahl { position: absolute; right: 10px; bottom: 10px; z-index: 2; display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px 5px 8px; border-radius: 999px; background: rgba(18,18,18,.66); color: #fff;
  font: 600 12px/1.2 system-ui, -apple-system, "Segoe UI", sans-serif; letter-spacing: .01em; cursor: zoom-in;
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); box-shadow: 0 2px 8px rgba(0,0,0,.18); }
.pano-bildzahl svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; }

/* Schriftart aus der Leiste (Werkzeug „Schriftart"): die Familie steht als
   Variable am Baustein (--pano-ff), die Marke sagt wie weit sie reicht.
   „ja" = der Baustein samt allem darin (eine Ueberschrift mit einem
   hervorgehobenen Wort wird ganz umgestellt). „selbst" = nur der Baustein
   und was von ihm erbt - so ersetzt „diesen Abschnitt angleichen" eine
   fremde Schrift, ohne ein absichtlich anders gesetztes Wort mitzureissen.
   In der Werkzeug-Schicht wie „Abstand": schlaegt jede Regel des Entwurfs,
   auch mit !important. Zeichen (svg) bleiben unberuehrt. */
@layer pano-werkzeug {
  [data-pano-schriftart][style*="--pano-ff:"] { font-family: var(--pano-ff) !important; }
  [data-pano-schriftart="ja"][style*="--pano-ff:"] :where(:not([data-pano-schriftart]):not(svg, svg *)) { font-family: var(--pano-ff) !important; }
}
