/* ==========================================================================
   KB Immobilien - Basis-Stylesheet
   --------------------------------------------------------------------------
   Diese Datei gilt fuer ALLE Seiten. Wer hier etwas aendert, aendert es
   ueberall. Farben, Abstaende und Schriftgroessen stehen gesammelt ganz oben
   unter ":root" - das ist normalerweise die einzige Stelle, die man anfasst.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Grundeinstellungen (Farben, Masse)
   -------------------------------------------------------------------------- */

:root {
  color-scheme: light dark;

  /* Neutrale Farben */
  --bg:          #f5f6f7;
  --surface:     #ffffff;
  --surface-alt: #eef0f2;
  --ink:         #15181b;
  --ink-muted:   #5b636a;
  --line:        #e0e4e7;

  /* Akzentfarbe - wird je Bereich ueberschrieben (siehe Abschnitt 2) */
  /* Koenigsblau, gewaehlt am 09.08.2026. Vorher stand hier das Indigo
     #3b2a9a aus dem Altlogo von 1989 - das Logo fuehrt diese Farbe seit
     dem 07.08.2026 nicht mehr, es ist schwarz. Die Werte stammen aus
     logo/werkzeug/farbwahl.py, Kontrast auf Weiss 9,0:1.
     Sie gilt fuer die Startseite und alle gemeinsamen Seiten. Die beiden
     Geschaeftsbereiche ueberschreiben sie weiter unten. */
  --accent:      #1c3faa;
  --accent-dark: #163185;
  --accent-tint: #edf0f8;
  --on-accent:   #ffffff;
  --kopfband:    #163185;

  /* Masse */
  --page:   1140px;
  --radius: 10px;

  /* Schrift: bewusst Systemschriften. Keine Google Fonts - die wuerden
     Besucherdaten an Google senden und sind in Deutschland abmahnbar. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;
}

/* Dunkles Design, wenn der Besucher es an seinem Geraet eingestellt hat */
@media (prefers-color-scheme: dark) {
  :root {
    --bg:          #131619;
    --surface:     #1b1f23;
    --surface-alt: #232830;
    --ink:         #eceef0;
    --ink-muted:   #a2abb4;
    --line:        #2e343b;
    /* Koenigsblau auf dunklem Grund aufgehellt, sonst bliebe es unleserlich.
       Kontrast auf dem dunklen Grund 5,7:1. */
    --accent:      #798ecd;
    --accent-dark: #6779ae;
    --accent-tint: #151e36;
  }
}

/* --------------------------------------------------------------------------
   2. Akzentfarbe je Bereich
   Wird ueber die Klasse im <body>-Tag gesteuert.
   -------------------------------------------------------------------------- */

body.bereich-immobilien {
  --accent:      #0e5c4f;
  --accent-dark: #0a4539;
  --accent-tint: #e4efec;
  --kopfband:    #0a4539;
}
body.bereich-hausverwaltung {
  /* Die Hausverwaltung traegt die Hausfarbe unveraendert. */
  --accent:      #1c3faa;
  --accent-dark: #163185;
  --accent-tint: #edf0f8;
  --kopfband:    #163185;
}

/* --kopfband ist die Flaeche hinter der Ueberschrift einer Unterseite
   (Abschnitt 6b2). Sie ist ABSICHTLICH in beiden Designs dieselbe und folgt
   nicht --accent-dark: Auf dunklen Bildschirmen wird --accent-dark
   aufgehellt, und weisse Schrift darauf kaeme nur noch auf gut 3:1 Kontrast.
   Dieser feste Wert traegt Weiss mit ueber 10:1 - und die Bereichsfarbe
   bleibt trotzdem erkennbar. */

@media (prefers-color-scheme: dark) {
  body.bereich-immobilien      { --accent: #3d9e8a; --accent-dark: #2f8271; --accent-tint: #172b27; }
  body.bereich-hausverwaltung  { --accent: #798ecd; --accent-dark: #6779ae; --accent-tint: #151e36; }
}

/* --------------------------------------------------------------------------
   3. Grundlagen
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

img { max-width: 100%; height: auto; display: block; }

a { color: var(--accent); }

h1, h2, h3 {
  line-height: 1.2;
  letter-spacing: -0.015em;
  margin: 0 0 0.6em;
  font-weight: 650;
}
h1 { font-size: clamp(2rem, 1.4rem + 2.4vw, 3.1rem); }
h2 { font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.1rem); }
h3 { font-size: 1.2rem; }

p, ul, ol { margin: 0 0 1.1em; }

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: 1.5rem;
}

.muted { color: var(--ink-muted); }
.lead  { font-size: 1.2rem; color: var(--ink-muted); max-width: 62ch; }

/* Sprungmarke fuer Tastatur- und Screenreader-Nutzer */
.skip {
  position: absolute; left: -9999px;
  background: var(--accent); color: var(--on-accent);
  padding: 0.7rem 1.1rem; border-radius: 0 0 var(--radius) 0; z-index: 100;
}
.skip:focus { left: 0; top: 0; }

:where(a, button, summary):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* --------------------------------------------------------------------------
   4. Platzhalter-Markierung
   Alles, was noch mit echten Firmendaten gefuellt werden muss, ist gelb
   hinterlegt. Sobald der Text eingetragen ist, einfach das <span> entfernen.
   -------------------------------------------------------------------------- */

.todo {
  background: #ffe680;
  color: #4a3b00;
  padding: 0 0.3em;
  border-radius: 3px;
  font-style: normal;
}

/* --------------------------------------------------------------------------
   5. Kopfbereich und Menue
   -------------------------------------------------------------------------- */

.site-header {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 50;
}

/* Die Kopfzeile darf breiter sein als der Text darunter. Der Lesebereich ist
   bewusst auf 1140 Punkte begrenzt - lange Zeilen liest niemand gern. Fuer
   ein Menue gilt das nicht: Dort stehen kurze Woerter nebeneinander, und mit
   dem casavi-Eintrag sind es im HV-Bereich acht. In 1140 Punkten ueberlappten
   Logo und Menuepunkte. Nur die Kopfzeile bekommt deshalb mehr Platz. */
.site-header .wrap { max-width: 1320px; }

.header-inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 76px;
}

/* Firmenlogo in der Kopfzeile. Die Datei ist zweifarbig wie das Original;
   fuer dunkle Bildschirme laedt der Browser ueber <picture> eine
   aufgehellte Fassung. */
.brand {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.75rem;
  text-decoration: none;
  color: var(--ink);
  margin-right: auto;
  min-width: 0;
}
/* Das <picture> ist das Kind von .brand und damit das Flex-Element - NICHT
   das <img> darin. Wer nur dem Bild ein flex-shrink gibt, aendert nichts:
   Gequetscht wird die Huelle. Ohne diese Zeile schrumpfte das Logo auf den
   Immobilienseiten auf Briefmarkengroesse. Es ist eine Bildmarke, keine
   Ziehharmonika. */
.brand picture {
  display: block;
  flex-shrink: 0;
}
.brand-logo {
  height: 40px;
  width: auto;
  display: block;
}
/* Bezeichnung des Geschaeftsbereichs, nur auf den Bereichsseiten */
.brand-sub {
  font-size: 0.72rem;
  color: var(--accent);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding-left: 0.75rem;
  border-left: 1px solid var(--line);
  line-height: 1.3;
}

/* Das Logo braucht mehr Platz als der fruehere Schriftzug. Solange das Menue
   noch ausgeklappt danebensteht, muss die Bereichsangabe weichen, sobald es
   eng wird - sonst laeuft die Kopfzeile ueber. Welcher Bereich gemeint ist,
   sagen die Menuepunkte ohnehin.
   Am 17.08.2026 von 1040 auf 1340 angehoben: Das HV-Menue hat mit
   "casavi Kundenportal" einen achten und dazu breiten Punkt bekommen. */
@media (max-width: 1340px) {
  .brand-sub { display: none; }
}
@media (max-width: 640px) {
  .brand-logo { height: 34px; }
}

.nav { display: flex; align-items: center; gap: 0.35rem; }

.nav a {
  text-decoration: none;
  color: var(--ink-muted);
  font-size: 0.97rem;
  font-weight: 550;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  /* Ein Menuepunkt bricht nicht mitten im Wort um. Vorher stand dort
     "WEG-" / "Verwaltung" untereinander, und die Kopfzeile wurde hoeher als
     der Rest. Passt nicht mehr alles nebeneinander, gehoert das Klappmenue
     her - siehe Haltepunkt weiter unten. */
  white-space: nowrap;
}
.nav a:hover { color: var(--ink); background: var(--surface-alt); }
.nav a[aria-current="page"] { color: var(--accent); background: var(--accent-tint); }

/* Der Wechsel-Link in den jeweils anderen Bereich */
.nav-switch {
  margin-left: 0.5rem;
  border: 1px solid var(--line);
  color: var(--ink) !important;
}
.nav-switch:hover { border-color: var(--accent); color: var(--accent) !important; }

.nav-toggle {
  display: none;
  font: inherit;
  font-weight: 600;
  padding: 0.55rem 0.9rem;
  background: var(--surface-alt);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 6px;
  cursor: pointer;
}

/* Ab hier klappt das Menue hinter den Knopf "Menü".
   Am 17.08.2026 von 860 auf 1180 angehoben. Grund: Das HV-Menue hat mit
   "casavi Kundenportal" acht Punkte, und darunter schob sich das Logo ueber
   den ersten Menuepunkt. Nachgemessen passt die Zeile ab etwa 1180
   nebeneinander - darunter gehoert sie zusammengeklappt.
   WER EINEN MENUEPUNKT ERGAENZT, muss diesen Wert und den fuer .brand-sub
   oben neu ausmessen. Das Menue ist am Anschlag. */
@media (max-width: 1180px) {
  .nav-toggle { display: block; }
  .nav {
    display: none;
    position: absolute;
    inset: 76px 0 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    padding: 0.5rem 1.5rem 1rem;
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.08);
  }
  .nav.open { display: flex; }
  .nav a { padding: 0.75rem 0.5rem; font-size: 1.05rem; }
  .nav-switch { margin: 0.5rem 0 0; text-align: center; }
}

/* --------------------------------------------------------------------------
   6. Inhaltsbereiche
   -------------------------------------------------------------------------- */

main { flex: 1; }

.section { padding: clamp(3rem, 6vw, 5rem) 0; }
.section + .section { padding-top: 0; }
.section-alt { background: var(--surface-alt); }
.section-alt + .section { padding-top: clamp(3rem, 6vw, 5rem); }

.hero {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: clamp(3rem, 7vw, 6rem) 0;
}
.hero .eyebrow {
  color: var(--accent);
  font-weight: 650;
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.9rem;
}
.hero h1 { max-width: 20ch; }

/* --------------------------------------------------------------------------
   6b. Bildband im Kopf einer Bereichsseite
   --------------------------------------------------------------------------
   Die Startseite traegt ein Foto, die Bereichsseiten fingen bisher direkt mit
   Text an - nebeneinander wirkte das karg. Ein .hero mit der Zusatzklasse
   .hero-bild bekommt deshalb ein Foto hinterlegt.

   Zwei Lagen liegen darueber:
     1. ein Verlauf von dunkel nach unten, damit weisse Schrift sicher lesbar
        bleibt, egal wie hell das Foto an der Stelle ist;
     2. ein Hauch der Bereichsfarbe (--accent-dark), der Immobilien und
        Hausverwaltung auch im Bild auseinanderhaelt - gruen hier, indigo dort.

   Das Foto steht als --foto und --foto-klein im style-Attribut der Seite.
   So bleibt diese Regel fuer beide Bereiche dieselbe.

   Anders als das Band der Startseite laeuft die Bildfarbe hier NICHT nach
   unten aus. Dort steht das Band allein auf einer sonst leeren Seite, hier
   folgt sofort ein Textabschnitt mit eigener Flaeche - ein Verlauf dazwischen
   waere nur Unruhe.
   -------------------------------------------------------------------------- */

.hero-bild {
  position: relative;
  border-bottom: 0;
  padding: clamp(4rem, 11vw, 8rem) 0 clamp(3rem, 8vw, 6rem);
  background: var(--foto) center 55% / cover no-repeat;
}
.hero-bild::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(rgba(12, 16, 20, 0.34) 0%,
                    rgba(12, 16, 20, 0.58) 60%,
                    rgba(12, 16, 20, 0.74) 100%),
    linear-gradient(var(--accent-dark), var(--accent-dark));
  background-blend-mode: normal, color;
}
.hero-bild > * { position: relative; }

/* Auf dem Foto steht alles in Weiss - unabhaengig davon, ob der Besucher sein
   Geraet hell oder dunkel eingestellt hat. Die Akzentfarbe waere auf dem
   abgedunkelten Bild zu dunkel, deshalb bekommt der Kicker hier Weiss. */
.hero-bild .eyebrow { color: rgba(255, 255, 255, 0.88); }
.hero-bild h1 {
  color: #fff;
  text-shadow: 0 2px 22px rgba(0, 0, 0, 0.45);
}
.hero-bild .lead { color: rgba(255, 255, 255, 0.92); }
.hero-bild .btn-ghost {
  color: #fff !important;
  border-color: rgba(255, 255, 255, 0.55);
}
.hero-bild .btn-ghost:hover { background: rgba(255, 255, 255, 0.14); }

/* Am Handy die kleinere Fassung des Fotos - rund 100 statt 400 Kilobyte.
   Auf einem schmalen Bildschirm sieht man den Unterschied nicht, im
   Mobilfunknetz schon. */
@media (max-width: 720px) {
  .hero-bild { background-image: var(--foto-klein); }
}

/* --------------------------------------------------------------------------
   6b2. Farbiger Kopf einer Unterseite (22.08.2026)
   --------------------------------------------------------------------------
   Die beiden Bereichsstartseiten tragen ein Foto im Kopf (6b), die zehn
   Unterseiten fingen mit schwarzer Schrift auf Weiss an. Nebeneinander
   gesehen wirkte das wie zwei verschiedene Websites.

   .hero-farbe legt statt des Fotos eine ruhige Flaeche in der Bereichsfarbe
   darunter. Damit entsteht eine Rangfolge, die man ohne Nachdenken liest:

     Foto        -> Startseite eines Bereichs
     Farbflaeche -> Unterseite darin
     Weiss       -> Rechtstexte, wo Schmuck nichts zu suchen hat

   Kein Foto, weil zehn zusaetzliche Motive die Seite schwer machen und
   nirgends echte Objekte der Firma zeigen wuerden.
   -------------------------------------------------------------------------- */

.hero-farbe {
  border-bottom: 0;
  background: var(--kopfband);
  padding: clamp(3.5rem, 9vw, 6.5rem) 0 clamp(3rem, 7vw, 5rem);
}
.hero-farbe .eyebrow { color: rgba(255, 255, 255, 0.82); }
.hero-farbe h1       { color: #fff; }
.hero-farbe .lead    { color: rgba(255, 255, 255, 0.92); }
.hero-farbe strong   { color: #fff; }

/* Der Preis im Kopf einer Exposeseite. Ohne diese Zeile erbte er die normale
   Textfarbe - fast schwarz auf dunkelgruen, praktisch unlesbar. */
.hero-farbe .objekt-preis { color: #fff; }
.hero-farbe .objekt-preis .preis-zusatz { color: rgba(255, 255, 255, 0.82); }

/* Die farbige Schaltflaeche wuerde auf der farbigen Flaeche verschwinden -
   gruen auf dunkelgruen. Deshalb dreht sie sich hier um: weiss mit farbiger
   Schrift. */
.hero-farbe .btn {
  background: #fff;
  color: var(--kopfband);
  border-color: #fff;
}
.hero-farbe .btn:hover { background: rgba(255, 255, 255, 0.88); }
.hero-farbe .btn-ghost {
  background: transparent;
  color: #fff !important;
  border-color: rgba(255, 255, 255, 0.55);
}
.hero-farbe .btn-ghost:hover { background: rgba(255, 255, 255, 0.14); }

/* --------------------------------------------------------------------------
   6c. Bildtafel - ein Foto mitten im Text
   --------------------------------------------------------------------------
   Fuer Bilder, auf denen etwas zu erkennen sein muss. Anders als das
   Kopfband (6b) liegt hier keine Abdeckung darueber und steht keine Schrift
   darauf - eine dunkle Lage wuerde genau das schlucken, worauf es ankommt.

   Das Bild ist Inhalt, kein Schmuck, deshalb steht es als <img> im Markup
   und nicht als Hintergrund im Stylesheet: So bekommt es einen Alternativtext
   fuer Vorleseprogramme und laesst sich am Handy durch die kleinere Fassung
   ersetzen. Aufbau:

     <figure class="bildtafel">
       <picture>
         <source media="(max-width: 720px)" srcset="…-klein.jpg">
         <img src="….jpg" alt="…" width="2000" height="1125" loading="lazy">
       </picture>
       <figcaption>Bildunterschrift</figcaption>
     </figure>

   width und height gehoeren ins Markup, damit der Browser den Platz schon
   kennt, bevor das Bild geladen ist - sonst springt der Text beim Laden.
   -------------------------------------------------------------------------- */

.bildtafel { margin: 0; }
.bildtafel img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 14px;
  background: var(--surface-alt);
}
.bildtafel figcaption {
  margin-top: 0.9rem;
  max-width: 68ch;
  color: var(--ink-muted);
  font-size: 0.93rem;
  line-height: 1.5;
}

/* --------------------------------------------------------------------------
   6d. Abfolge - Bilder, die beim Scrollen wechseln
   --------------------------------------------------------------------------
   Mehrere Aufnahmen derselben Stelle in verschiedenen Zustaenden. Beim
   Herunterscrollen schiebt sich jede ueber die vorige, das Bild wechselt also
   in Ruhe, ohne dass der Besucher etwas anklicken muesste.

   Das braucht KEIN JavaScript. Der Kniff steckt in position: sticky:

     Jeder Schritt klebt am selben Abstand von der Fensteroberkante. Schritt 1
     bleibt dort haengen, waehrend der Text weiterlaeuft. Kommt Schritt 2
     heran, klebt er an derselben Stelle - und weil er im Markup spaeter steht,
     liegt er darueber und verdeckt Schritt 1 vollstaendig. So weiter bis zum
     letzten. Der Abstand margin-bottom bestimmt, wie weit man zwischen zwei
     Wechseln scrollt.

   Ohne CSS bleibt eine schlichte Folge von Bildern mit Beschriftung uebrig -
   die Reihenfolge steht im Markup, nicht in einem Skript. Das ist der Grund
   fuer diese Loesung: Sie faellt nirgends aus.

   Warum ueberhaupt einzelne Bilder und nicht eines mit Verlauf darin: Am
   07.08.2026 sind sechs Anlaeufe gescheitert, den Bauverlauf in ein einziges
   Bild zu legen - das Bildmodell setzte den fertigen Teil verlaesslich in die
   Mitte und kippte am rechten Rand zurueck in den Rohbau.
   -------------------------------------------------------------------------- */

.abfolge { position: relative; }

.abfolge-schritt {
  position: sticky;
  top: clamp(1rem, 7vh, 4.5rem);
  margin: 0 0 55vh;
}
/* Der letzte Schritt braucht keine Scrollstrecke mehr hinter sich. */
.abfolge-schritt:last-child { margin-bottom: 0; }

.abfolge-bild {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.13);
}
.abfolge-bild img {
  display: block;
  width: 100%;
  /* Bild und Beschriftung muessen zusammen ins Fenster passen, sonst klebt
     nie der ganze Schritt gleichzeitig. Deshalb Hoehe statt Seitenverhaeltnis. */
  height: min(62vh, 58vw);
  object-fit: cover;
  background: var(--surface-alt);
}

/* Die Beschriftung liegt im Bild, damit der klebende Block kompakt bleibt.
   Der Verlauf darunter macht weisse Schrift auf jedem Foto lesbar. */
.abfolge-text {
  position: absolute;
  inset: auto 0 0;
  padding: 3.5rem 1.6rem 1.4rem;
  color: #fff;
  background: linear-gradient(rgba(12, 16, 20, 0) 0%,
                              rgba(12, 16, 20, 0.55) 45%,
                              rgba(12, 16, 20, 0.86) 100%);
}
.abfolge-text p { margin: 0; max-width: 60ch; }
.abfolge-text .schritt {
  display: block;
  margin-bottom: 0.35rem;
  font-weight: 650;
  font-size: 0.78rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
}

@media (max-width: 720px) {
  .abfolge-schritt { margin-bottom: 40vh; }
  .abfolge-bild img { height: min(52vh, 76vw); }
  .abfolge-text { padding: 3rem 1.2rem 1.1rem; }
}

/* Wer sich weniger Bewegung wuenscht, bekommt die Bilder schlicht
   untereinander - ohne Kleben, ohne Uebereinanderschieben. */
@media (prefers-reduced-motion: reduce) {
  .abfolge-schritt { position: static; margin-bottom: 1.5rem; }
}

/* --------------------------------------------------------------------------
   6e. Derselbe Bauverlauf ueber die ganze Seite (22.08.2026)

   Gewuenscht am 22.08.2026: Der Bauverlauf soll das Fenster fuellen und beim
   Scrollen durchlaufen statt umzuspringen, mit kurzen Textzeilen darin.

   Das ist eine ZUSAETZLICHE Schicht ueber 6d, keine Ablösung:

     ohne JavaScript  -> alles bleibt wie in 6d: klebende Bilder in der
                         Textspalte, harte Schnitte. Faellt nicht aus.
     mit JavaScript   -> assets/js/bauverlauf.js haengt die Schritte in eine
                         Buehne, setzt data-lauf="an", und ab hier greifen
                         die Regeln unten.

   Warum ueberhaupt Skript: Ein weiches Ueberblenden verlangt einen
   Deckkraftwert, der sich mit der Scrollstrecke stetig aendert. Reines CSS
   kann nur umschalten, nicht ueberblenden - ausser mit scroll-getriebenen
   Animationen, die Safari noch nicht ueberall koennen. Deshalb Skript, aber
   nur als Zugabe.

   Warum Einzelbilder und kein Video: siehe README, Abschnitt zum Bauverlauf.
   -------------------------------------------------------------------------- */

/* Ohne Skript sitzt die Abfolge in der Textspalte wie bisher. Sie steht im
   Markup absichtlich AUSSERHALB von .wrap, damit sie im ganzseitigen Zustand
   ohne negative Raender bis an den Rand reicht. */
.abfolge {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: 1.5rem;
}

/* Die kurze Zeile gilt auch ohne Skript - nur kleiner. */
.abfolge-text .zeile {
  margin: 0 0 0.4rem;
  font-size: 1.15rem;
  font-weight: 620;
  line-height: 1.2;
}

/* --- Ab hier der ganzseitige Zustand ------------------------------------- */

.abfolge[data-lauf="an"] {
  max-width: none;
  padding-inline: 0;
  /* Scrollstrecke: ein Fenster fuer den ersten Schritt, danach je Schritt
     eine Strecke. --schritte setzt das Skript. */
  /* Wie weit man je Schritt scrollt. Bei acht Stufen summiert sich das:
     70vh waeren 5,6 Bildschirmhoehen und ermuedend, 60vh sind 4,8. */
  --strecke: 60vh;
  /* --kopf setzt das Skript auf die gemessene Hoehe der Kopfzeile. Die klebt
     naemlich selbst oben und wuerde sonst den oberen Bildrand verdecken.

     Eine Strecke JE SCHRITT, nicht je Wechsel: die letzte gehoert dem letzten
     Bild. Ohne sie waere der letzte Schritt genau in dem Augenblick fertig
     eingeblendet, in dem die Buehne schon wieder nach oben wegrollt - man
     saehe ihn nie in Ruhe. */
  height: calc(100vh - var(--kopf, 0px) + var(--schritte) * var(--strecke));
  height: calc(100svh - var(--kopf, 0px) + var(--schritte) * var(--strecke));
}

/* Die Buehne klebt am oberen Fensterrand und fuellt es ganz. Das Skript baut
   sie und haengt die Schritte hinein. */
.abfolge[data-lauf="an"] .abfolge-buehne {
  position: sticky;
  top: var(--kopf, 0px);
  height: calc(100vh - var(--kopf, 0px));
  height: calc(100svh - var(--kopf, 0px));
  overflow: hidden;
  background: #0c1014;
}

/* Alle Schritte liegen uebereinander. Sichtbar sind hoechstens zwei: der
   untere deckt, der obere blendet sich darueber ein. Den Rest stellt das
   Skript auf .ruht, damit das Geraet ihn gar nicht erst zeichnet. */
.abfolge[data-lauf="an"] .abfolge-schritt {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  will-change: opacity;
}
.abfolge[data-lauf="an"] .abfolge-schritt.ruht { visibility: hidden; }

.abfolge[data-lauf="an"] .abfolge-bild {
  height: 100%;
  border-radius: 0;
  box-shadow: none;
}
.abfolge[data-lauf="an"] .abfolge-bild picture { display: contents; }
.abfolge[data-lauf="an"] .abfolge-bild img {
  height: 100%;
  /* Das hereinkommende Bild setzt sich von 1,03 auf 1,00 - es kommt zur Ruhe,
     statt einfach da zu sein. Nur transform und opacity, beides auf der
     Grafikeinheit. */
  transform: scale(var(--zoom, 1));
}

/* Die Textzeile sitzt unten links im Bild, ueber einem Verlauf. Sie wechselt
   frueher als das Bild: erst geht die alte Zeile, dann kommt die neue. Zwei
   Zeilen gleichzeitig waeren unlesbar. */
.abfolge[data-lauf="an"] .abfolge-text {
  padding: 6rem clamp(1.5rem, 6vw, 5rem) clamp(3rem, 8vh, 6rem);
  background: linear-gradient(rgba(12, 16, 20, 0) 0%,
                              rgba(12, 16, 20, 0.20) 22%,
                              rgba(12, 16, 20, 0.68) 52%,
                              rgba(12, 16, 20, 0.93) 100%);
}
.abfolge[data-lauf="an"] .abfolge-text > * {
  opacity: var(--text-deckung, 1);
  transform: translateY(var(--text-hub, 0));
}
.abfolge[data-lauf="an"] .abfolge-text .zeile {
  margin: 0 0 0.5rem;
  max-width: 24ch;
  font-size: clamp(1.6rem, 4.4vw, 3rem);
  font-weight: 620;
  line-height: 1.12;
  letter-spacing: -0.02em;
  /* Der Verlauf allein reicht auf einer hellen Betonwand nicht. Der Schatten
     ist weich und dunkel, damit er nicht als Schatten auffaellt, sondern die
     Buchstabenkanten nur abgrenzt. */
  text-shadow: 0 1px 14px rgba(8, 11, 14, 0.55);
}
.abfolge[data-lauf="an"] .abfolge-text p:not(.zeile) {
  max-width: 46ch;
  font-size: clamp(0.95rem, 1.6vw, 1.05rem);
  color: rgba(255, 255, 255, 0.86);
}

/* Punkte am rechten Rand: sie sagen, wie viele Schritte kommen und wo man
   gerade steht. Ohne sie weiss niemand, ob nach dem Scrollen noch etwas
   folgt. */
.abfolge-punkte {
  position: absolute;
  right: clamp(0.9rem, 2.5vw, 1.8rem);
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.abfolge-punkte span {
  width: 6px;
  height: 6px;
  border-radius: 99px;
  background: rgba(255, 255, 255, 0.45);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.45);
  transition: height 220ms cubic-bezier(0.23, 1, 0.32, 1),
              background-color 220ms ease;
}
.abfolge-punkte span.hier {
  height: 20px;
  background: rgba(255, 255, 255, 0.92);
}

@media (max-width: 720px) {
  .abfolge[data-lauf="an"] { --strecke: 54svh; }
  .abfolge[data-lauf="an"] .abfolge-text { padding-bottom: clamp(2.5rem, 6vh, 4rem); }
}

.section-head { max-width: 64ch; margin-bottom: 2.5rem; }

/* --------------------------------------------------------------------------
   7. Karten und Raster
   -------------------------------------------------------------------------- */

.grid {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.6rem;
}
.card h3 { margin-bottom: 0.4rem; }
.card p:last-child { margin-bottom: 0; }

a.card {
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s, transform 0.15s;
}
a.card:hover { border-color: var(--accent); transform: translateY(-2px); }
a.card .more { color: var(--accent); font-weight: 600; }

/* Objektkarten (Seite "Aktuelle Objekte") */
.badge {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.2rem 0.6rem;
  border-radius: 100px;
  background: var(--accent-tint);
  color: var(--accent);
  margin-bottom: 0.8rem;
}
.badge-reserviert { background: #fff0d6; color: #8a5a00; }
.badge-verkauft   { background: var(--surface-alt); color: var(--ink-muted); }

.objekt-daten {
  list-style: none;
  padding: 0;
  margin: 1rem 0 0;
  border-top: 1px solid var(--line);
  font-size: 0.95rem;
}
.objekt-daten div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--line);
}
.objekt-daten dt { color: var(--ink-muted); }
/* Der Wert bleibt in einer Zeile. In schmalen Karten brach sonst "je 3,57 %"
   auseinander - das "je" stand oben, die Zahl darunter. Werte sind hier immer
   kurz: eine Flaeche, ein Preis, ein Satz. */
.objekt-daten dd { margin: 0; font-weight: 600; white-space: nowrap; }

/* --------------------------------------------------------------------------
   Kategorien der Angebotsseite (Verkauf / Vermietung / Projekte)

   Ohne JavaScript gebaut: drei Radiofelder liegen unsichtbar vor der Leiste,
   ihre Beschriftungen sind die Reiter. Das hat zwei Gruende. Erstens braucht
   die Seite sonst kein JavaScript und soll auch keins bekommen. Zweitens
   laeuft die Vorschaudatei in einem <iframe srcdoc> - dort greifen Anker
   (:target) nicht, Radiofelder schon.

   Der gleitende Balken unter dem aktiven Reiter ist ein einzelnes Element,
   das verschoben wird. Zwei Reiter gleichzeitig einzufaerben und die Farbe zu
   ueberblenden sieht immer nach zwei Farben aus; ein bewegter Balken sieht
   nach einem Gegenstand aus.
   -------------------------------------------------------------------------- */

.kategorien { margin-top: 0.5rem; }

/* Die Radiofelder selbst sieht niemand - sie bleiben aber bedienbar und
   werden von der Tastatur und vom Screenreader gefunden. Nicht auf
   display:none setzen, das nimmt sie aus der Tastaturfolge. */
.kategorien > input {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; white-space: nowrap;
  clip-path: inset(50%);
}

.kat-leiste {
  position: relative;
  display: flex;
  gap: 0.25rem;
  padding: 0.3rem;
  background: var(--surface-alt);
  border: 1px solid var(--line);
  border-radius: 100px;
  /* Feste Breite, drei gleich breite Faecher. Der gleitende Balken ist
     genau ein Drittel breit - waeren die Reiter unterschiedlich breit,
     saesse er nach dem Umschalten neben der Beschriftung. */
  width: min(100%, 420px);
}
.kat-leiste::-webkit-scrollbar { display: none; }

/* Der gleitende Balken. Liegt hinter den Beschriftungen. */
.kat-balken {
  position: absolute;
  top: 0.3rem;
  left: 0.3rem;
  width: calc((100% - 0.6rem - 0.5rem) / 3);
  height: calc(100% - 0.6rem);
  background: var(--accent);
  border-radius: 100px;
  transition: transform 220ms cubic-bezier(0.23, 1, 0.32, 1);
  pointer-events: none;
}

.kat-leiste label {
  position: relative;
  z-index: 1;
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  padding: 0.62rem 1.35rem;
  border-radius: 100px;
  font-weight: 620;
  font-size: 0.97rem;
  color: var(--ink-muted);
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
  transition: color 160ms ease, transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

/* Ein Druck auf den Reiter soll sich anfuehlen wie ein Druck. */
.kat-leiste label:active { transform: scale(0.97); }

/* Zeigegeraete mit Mauszeiger: leichte Aufhellung. Auf dem Telefon nicht,
   dort loest die Beruehrung sonst faelschlich einen Hover-Zustand aus. */
@media (hover: hover) and (pointer: fine) {
  .kat-leiste label:hover { color: var(--ink); }
}

/* Tastaturbedienung sichtbar machen: Der Ring gehoert an die Beschriftung,
   nicht an das versteckte Radiofeld. */
.kategorien > input:focus-visible + label {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Aktiver Reiter: heller Text auf dem Balken */
#kat-verkauf:checked    ~ .kat-leiste label[for="kat-verkauf"],
#kat-vermietung:checked ~ .kat-leiste label[for="kat-vermietung"],
#kat-projekte:checked   ~ .kat-leiste label[for="kat-projekte"] {
  color: var(--on-accent);
}

/* Der Balken wandert um seine eigene Breite - unabhaengig davon, wie breit
   die Reiter tatsaechlich sind. */
#kat-vermietung:checked ~ .kat-leiste .kat-balken {
  transform: translateX(calc(100% + 0.25rem));
}
#kat-projekte:checked ~ .kat-leiste .kat-balken {
  transform: translateX(calc(200% + 0.5rem));
}

/* Die drei Bereiche darunter */
.kat-inhalt { display: none; margin-top: 2rem; }

#kat-verkauf:checked    ~ .kat-inhalt[data-kat="verkauf"],
#kat-vermietung:checked ~ .kat-inhalt[data-kat="vermietung"],
#kat-projekte:checked   ~ .kat-inhalt[data-kat="projekte"] {
  display: block;
  animation: kat-auf 200ms cubic-bezier(0.23, 1, 0.32, 1) both;
}

/* Bewusst zurueckhaltend: 6 Pixel Versatz, keine Skalierung. Der Wechsel
   soll den Blick fuehren, nicht auffallen. */
@keyframes kat-auf {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Wenn eine Kategorie nichts enthaelt: ein ehrlicher Hinweis statt einer
   leeren Flaeche oder erfundener Musterkarten. */
.kat-leer {
  background: var(--surface);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  padding: 2.2rem 1.8rem;
  text-align: center;
}
.kat-leer p { margin-bottom: 0; color: var(--ink-muted); }
.kat-leer p + p { margin-top: 0.6rem; }

@media (max-width: 560px) {
  .kat-leiste label { padding: 0.62rem 0.5rem; font-size: 0.9rem; }
}

/* --------------------------------------------------------------------------
   7a. Schaufenster: Objektkarten mit Bild und die Exposeseite
   --------------------------------------------------------------------------
   Gebaut am 25.08.2026. Zwei Dinge haengen hier zusammen:

     1. Das "Kaestchen" im Raster der Angebotsseite - Bild, harte Daten,
        ein Klick.
     2. Die Exposeseite dahinter unter immobilien/objekt/.

   BEIDES WIRD ERZEUGT, NICHT VON HAND GESCHRIEBEN. Quelle sind die Ordner
   unter objekte/, das Werkzeug ist werkzeug/objekte.py. Wer hier eine Klasse
   umbenennt, muss sie auch dort umbenennen - sonst faellt die Gestaltung beim
   naechsten Lauf auseinander.

   Die alten Klassen .badge und .objekt-daten aus Abschnitt 7 bleiben in
   Gebrauch; sie sind hier nur um das Bild herum ergaenzt.
   -------------------------------------------------------------------------- */

/* --- Das Raster --------------------------------------------------------- */

/* Eigenes Raster statt des allgemeinen .grid, und zwar wegen auto-FILL statt
   auto-fit: Bei auto-fit fallen leere Spalten in sich zusammen, ein einzelnes
   Objekt zoege sich dann ueber die volle Breite und stuende als 1140 Punkte
   breites Foto da. auto-fill laesst die leeren Spalten stehen - das erste
   Objekt ist genauso breit wie spaeter das dritte. */
.objekt-raster {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
}

/* --- Das Kaestchen im Raster --------------------------------------------- */

a.card.objekt-karte {
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.objekt-bild {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--surface-alt);
  overflow: hidden;
}
.objekt-bild img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  /* 300 ms und die starke Ausklingkurve: Das Bild soll dem Zeiger sofort
     folgen und dann weich stehenbleiben. Nur transform wird bewegt, nicht
     "all" - das laeuft auf der Grafikeinheit und kostet nichts. */
  transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1);
}

/* Nur auf Geraeten mit echtem Zeiger. Auf dem Telefon loest eine Beruehrung
   sonst den Schwebezustand aus, und das Bild bleibt vergroessert stehen. */
@media (hover: hover) and (pointer: fine) {
  a.card.objekt-karte:hover .objekt-bild img { transform: scale(1.04); }
}

/* Das Kaestchen gibt beim Druecken nach - dieselbe Sprache wie .btn. */
a.card.objekt-karte:active { transform: scale(0.99); }

/* Steht noch kein Foto bereit, bleibt die Flaeche trotzdem stehen. Ohne das
   waeren die Kaestchen im Raster unterschiedlich hoch. */
.objekt-bild-leer {
  display: grid;
  place-items: center;
  background: var(--accent-tint);
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* Das Statuskennzeichen liegt auf dem Foto. Auf einem hellen Himmel waere
   die Akzentfarbe allein zu schwach - deshalb traegt es hier die
   Oberflaechenfarbe als Grund und einen leichten Schatten. */
.objekt-bild .badge {
  position: absolute;
  top: 0.8rem;
  left: 0.8rem;
  margin: 0;
  background: var(--surface);
  color: var(--accent);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}
.objekt-bild .badge-reserviert { color: #8a5a00; }
.objekt-bild .badge-verkauft,
.objekt-bild .badge-vermietet  { color: var(--ink-muted); }

.badge-vermietet { background: var(--surface-alt); color: var(--ink-muted); }

/* Das bernsteinfarbene Kennzeichen stammt aus dem hellen Design: dunkles
   Braun auf hellem Gelb. Auf dunklem Grund kehrt sich das um, sonst steht
   #8a5a00 auf fast schwarzem Grund - gemessen 2,4:1, also unlesbar. */
@media (prefers-color-scheme: dark) {
  .badge-reserviert { background: #3b2f12; color: #f0c464; }
  .objekt-bild .badge-reserviert { background: var(--surface); color: #f0c464; }
}

.objekt-text {
  padding: 1.25rem 1.4rem 1.4rem;
  display: flex;
  flex-direction: column;
  flex: 1;
}
.objekt-ort {
  font-size: 0.85rem;
  color: var(--ink-muted);
  margin: 0 0 0.3rem;
}
.objekt-karte h3 { font-size: 1.15rem; margin: 0 0 0.55rem; }

.objekt-preis {
  font-weight: 700;
  font-size: 1.15rem;
  margin: 0 0 0.9rem;
}
.objekt-preis .preis-zusatz {
  font-weight: 400;
  font-size: 0.85rem;
  color: var(--ink-muted);
}

.objekt-eckdaten {
  list-style: none;
  padding: 0;
  margin: 0 0 1.1rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.1rem;
  font-size: 0.9rem;
  color: var(--ink-muted);
}
/* Bewusst OHNE Trennpunkte zwischen den Angaben: Im Kaestchen brechen die
   drei Werte auf zwei Zeilen um, und ein Trennzeichen landete dann als
   herrenloser Punkt am Anfang der zweiten Zeile. Der Abstand trennt genug. */

/* margin-top:auto schiebt die Zeile an den unteren Rand. Damit stehen die
   Pfeile aller Kaestchen einer Reihe auf einer Linie, auch wenn der eine
   Titel zweizeilig ist und der andere nicht. */
.objekt-karte .more { margin-top: auto; margin-bottom: 0; }

/* --- Kopf der Exposeseite ------------------------------------------------ */

.objekt-kopf { display: flex; flex-wrap: wrap; gap: 0.8rem 1.5rem; align-items: baseline; }
.objekt-kopf .objekt-preis { font-size: 1.6rem; margin: 0; }

/* --- Bilder -------------------------------------------------------------- */

.objekt-titelbild {
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface-alt);
  margin-bottom: 0.8rem;
}
.objekt-titelbild img { width: 100%; height: auto; display: block; }

.bilder-raster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: 0.8rem;
}
.bilder-raster a {
  display: block;
  aspect-ratio: 4 / 3;
  border-radius: calc(var(--radius) - 3px);
  overflow: hidden;
  background: var(--surface-alt);
}
.bilder-raster img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1);
}
@media (hover: hover) and (pointer: fine) {
  .bilder-raster a:hover img { transform: scale(1.04); }
}

/* Auf dem Telefon zwei Vorschaubilder nebeneinander statt untereinander.
   Sonst stehen vier grosse Fotos hintereinander, und wer die Wohnfläche
   sucht, muss an allen vorbeiscrollen. Angetippt wird das Bild ohnehin gross
   geöffnet - hier genügt die Vorschau. */
@media (max-width: 700px) {
  .bilder-raster { grid-template-columns: 1fr 1fr; gap: 0.5rem; }
}

/* --- Zwei Spalten: Text links, harte Daten rechts ------------------------ */

.objekt-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 2.5rem;
  align-items: start;
}

/* Die Datenspalte laeuft beim Blaettern mit. 7rem, weil die Kopfzeile selbst
   klebt (76 px) - ohne den Abstand schoebe sie sich darunter. */
.objekt-spalte { position: sticky; top: 7rem; display: grid; gap: 1.25rem; }

@media (max-width: 900px) {
  .objekt-layout { grid-template-columns: 1fr; gap: 2rem; }
  /* Auf dem Telefon stehen Preis und Flaeche VOR der Beschreibung. Wer ein
     Objekt sucht, entscheidet zuerst an den Zahlen. */
  .objekt-spalte { position: static; order: -1; }
}

.objekt-block {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.4rem 1.5rem;
}
.objekt-block h2, .objekt-block h3 { font-size: 1.05rem; margin: 0 0 0.9rem; }
.objekt-block .objekt-daten { margin-top: 0; }

/* In der Datentafel der Hausverwaltung sind die Werte immer kurz, deshalb
   steht dort white-space:nowrap (Abschnitt 7). Im Expose sind sie es nicht:
   "3,57 % inkl. MwSt., je Seite" oder "saniert 2018-2023" wuerden die Spalte
   auf dem Telefon breiter machen als den Bildschirm - und dann laesst sich die
   ganze Seite seitwaerts schieben. Hier duerfen die Werte also umbrechen und
   bleiben dabei rechtsbuendig. */
.objekt-block .objekt-daten dd { white-space: normal; text-align: right; }
.objekt-block .btn { width: 100%; text-align: center; }

/* --- Energieausweis ------------------------------------------------------ */

.energie-klasse {
  display: inline-block;
  min-width: 2.1rem;
  text-align: center;
  padding: 0.15rem 0.5rem;
  border-radius: 5px;
  font-weight: 700;
  /* Feste dunkle Schrift: Die Bandfarben sind in beiden Designs dieselben,
     eine mitlaufende Textfarbe wuerde auf Gelb oder Hellgruen verschwinden. */
  color: #15181b;
}
.klasse-ap, .klasse-a { background: #7fd08a; }
.klasse-b { background: #a8dc7c; }
.klasse-c { background: #d3e57a; }
.klasse-d { background: #f2e06e; }
.klasse-e { background: #f5c368; }
.klasse-f { background: #f0a061; }
.klasse-g { background: #e8785c; }
.klasse-h { background: #dd5a5a; }

/* --- Anhaenge zum Herunterladen ------------------------------------------ */

.dateien { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.6rem; }
.dateien a {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  text-decoration: none;
  color: inherit;
  transition: border-color 150ms ease, transform 150ms cubic-bezier(0.23, 1, 0.32, 1);
}
.dateien a:hover { border-color: var(--accent); }
.dateien a:active { transform: scale(0.99); }
.dateien .art {
  flex: none;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  background: var(--accent-tint);
  color: var(--accent);
  padding: 0.22rem 0.45rem;
  border-radius: 4px;
}
.dateien .groesse { margin-left: auto; color: var(--ink-muted); font-size: 0.85rem; white-space: nowrap; }

/* --- Bereits vermittelt --------------------------------------------------
   Eigener Abschnitt unter den Reitern, nicht ein vierter Reiter: Vier Reiter
   wurden auf dem Telefon zu schmal (gemessen: je 80 px statt 107 px), und
   verkaufte Objekte sollen die Liste der verfuegbaren nicht verlaengern.
   Kleiner gesetzt als die Kaestchen oben - es ist Beleg, kein Angebot. */

.vermittelt-raster {
  display: grid;
  /* auto-fill wie beim Objektraster, aus demselben Grund: Ein einzelnes
     vermitteltes Objekt zoege sich sonst ueber die volle Breite. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
  gap: 0.9rem;
}
.vermittelt-karte {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.7rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.vermittelt-karte img {
  flex: none;
  width: 72px;
  height: 60px;
  object-fit: cover;
  border-radius: 6px;
  /* Vermittelt heisst: nicht mehr zu haben. Die Entsaettigung sagt das,
     bevor man das Kennzeichen gelesen hat. */
  filter: saturate(0.35);
}
.vermittelt-karte p { margin: 0; font-size: 0.9rem; }
.vermittelt-karte .titel { font-weight: 600; }
.vermittelt-karte .wann { color: var(--ink-muted); font-size: 0.82rem; }

/* --- Hinweis auf ein Beispielobjekt --------------------------------------
   Das Werkzeug erzeugt diesen Streifen, solange ein Ordner unter objekte/
   den Status "beispiel" traegt. Er ist absichtlich haesslich; er soll vor
   dem Hochladen auffallen. Dieselbe gelbe Sprache wie .todo. */

.beispiel-hinweis {
  background: #fff6d6;
  border: 1px solid #e0c66a;
  border-radius: var(--radius);
  color: #6b5200;
  padding: 0.9rem 1.2rem;
  margin-bottom: 1.5rem;
  font-size: 0.92rem;
}
.beispiel-hinweis strong { color: #6b5200; }

/* Nummerierte Ablaufschritte */
.steps { counter-reset: schritt; list-style: none; padding: 0; display: grid; gap: 1.25rem; }
.steps li {
  counter-increment: schritt;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 1.3rem 1.5rem 1.3rem 3.9rem;
  position: relative;
}
.steps li::before {
  content: counter(schritt);
  position: absolute;
  left: 1.4rem;
  top: 1.25rem;
  width: 1.7rem; height: 1.7rem;
  display: grid; place-items: center;
  background: var(--accent-tint);
  color: var(--accent);
  border-radius: 50%;
  font-weight: 700;
  font-size: 0.9rem;
}
.steps strong { display: block; margin-bottom: 0.15rem; }
.steps p { margin: 0; color: var(--ink-muted); }

/* Hakenliste */
.checks { list-style: none; padding: 0; display: grid; gap: 0.6rem; }
.checks li { padding-left: 1.9rem; position: relative; }
.checks li::before {
  content: "";
  position: absolute; left: 0.25rem; top: 0.55rem;
  width: 0.45rem; height: 0.8rem;
  border: solid var(--accent);
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg);
}

/* --------------------------------------------------------------------------
   7b. Kontaktformular
   --------------------------------------------------------------------------
   Bewusst schlicht: ein Feld je Zeile, grosse Klickflaechen, Beschriftung
   ueber dem Feld.

   KEIN "placeholder" als Beschriftung. Der Text darin verschwindet beim
   ersten Zeichen - wer beim Ausfuellen unterbrochen wird, weiss dann nicht
   mehr, was in das Feld gehoerte. Ausserdem lesen Vorleseprogramme ihn
   unzuverlaessig vor.

   Die Fehlermarkierung haengt an :user-invalid, nicht an :invalid. Sonst
   waeren alle Pflichtfelder schon rot, bevor der Besucher ein Zeichen
   getippt hat.
   -------------------------------------------------------------------------- */

.formular { max-width: 40rem; }

.feld { margin-bottom: 1.35rem; }

.feld > label,
.wahl > legend {
  display: block;
  margin-bottom: 0.45rem;
  font-weight: 620;
}

.feld input,
.feld textarea {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.75rem 0.9rem;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.feld textarea { min-height: 9.5rem; resize: vertical; }

.feld input:focus-visible,
.feld textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-tint);
}
.feld input:user-invalid,
.feld textarea:user-invalid { border-color: #b4232a; }

/* Bewusst NICHT ".hinweis" - so heisst der Hinweiskasten in Abschnitt 11
   (Rechtstexte), ein blau hinterlegter Block mit Balken links. Der gehoert
   nicht unter jedes Eingabefeld. */
.feldhinweis {
  margin: 0.4rem 0 0;
  max-width: 60ch;
  color: var(--ink-muted);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* Auswahl des Bereichs. fieldset/legend, damit Vorleseprogramme die Frage
   zu den beiden Knoepfen vorlesen und nicht nur "Immobilien, Hausverwaltung". */
.wahl {
  margin: 0 0 1.35rem;
  padding: 0;
  border: 0;
}
.wahl .auswahl { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.wahl .auswahl label {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.7rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  cursor: pointer;
}
.wahl .auswahl label:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-tint);
}
.wahl .auswahl input { accent-color: var(--accent); }

/* Pflichtfelder werden benannt, nicht nur mit einem Sternchen markiert -
   ein Sternchen allein erklaert nichts. */
.pflicht { color: var(--ink-muted); font-weight: 400; }

/* Honigtopf: ein Feld, das nur Maschinen ausfuellen. Es steht ausserhalb des
   Bildschirms statt auf display:none - manche Spamprogramme pruefen genau
   darauf und lassen versteckte Felder dann aus. */
.honigtopf {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   7c. Querverweis in den anderen Geschaeftsbereich
   --------------------------------------------------------------------------
   Eine schmale Zeile ganz am Ende einer Seite: "Uebrigens machen wir auch
   das hier."

   Warum ein eigenes Bauteil und nicht .cta: Der Querverweis darf dem
   eigentlichen Handlungsaufruf darueber NICHT die Aufmerksamkeit wegnehmen.
   .cta ist ein Kasten in der Hausfarbe - zwei davon untereinander heben sich
   gegenseitig auf, und der Besucher weiss nicht mehr, was er tun soll.
   Deshalb hier nur eine Trennlinie, gedaempfte Schrift und ein Knopf mit
   Umriss statt gefuellt. Es ist ein Nachsatz, kein zweiter Ruf.
   -------------------------------------------------------------------------- */

.querverweis {
  border-top: 1px solid var(--line);
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem 2.5rem;
}
.querverweis p { margin: 0; max-width: 56ch; color: var(--ink-muted); }
.querverweis strong {
  display: block;
  margin-bottom: 0.3rem;
  color: var(--ink);
  font-size: 1.05rem;
  font-weight: 640;
}
/* Der Knopf soll nicht ueber die halbe Zeile wachsen, wenn Platz da ist. */
.querverweis .btn { flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   8. Schaltflaechen
   -------------------------------------------------------------------------- */

.btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 2rem; }

/* Die Schaltflaeche gibt es auch als <button> (Kontaktformular). Ein Knopf
   erbt Schriftart und -groesse nicht von selbst, das muss gesagt werden. */
button.btn { font-family: inherit; font-size: inherit; cursor: pointer; }
/* Kurzes Eindruecken beim Klick - die einzige Rueckmeldung, dass der Knopf
   den Klick gehoert hat. Bei "weniger Bewegung" faellt es weg (Abschnitt 13). */
.btn:active { transform: scale(0.98); }

.btn {
  display: inline-block;
  font-weight: 620;
  text-decoration: none;
  padding: 0.8rem 1.5rem;
  border-radius: 7px;
  border: 1px solid transparent;
  background: var(--accent);
  color: var(--on-accent);
  transition: background 0.15s, transform 0.16s cubic-bezier(0.23, 1, 0.32, 1);
}
.btn:hover { background: var(--accent-dark); }

.btn-ghost {
  background: transparent;
  color: var(--accent);
  border-color: var(--line);
}
.btn-ghost:hover { background: var(--accent-tint); border-color: var(--accent); }

/* Hervorgehobener Kontaktblock am Seitenende */
.cta {
  background: var(--accent);
  color: var(--on-accent);
  border-radius: var(--radius);
  padding: clamp(2rem, 5vw, 3.2rem);
}
.cta h2 { margin-bottom: 0.4rem; }
.cta p  { opacity: 0.9; max-width: 55ch; }
.cta .btn { background: var(--surface); color: var(--accent); }
.cta .btn:hover { background: var(--surface-alt); }

/* --------------------------------------------------------------------------
   9. Kontaktdaten-Block
   -------------------------------------------------------------------------- */

.kontaktdaten { list-style: none; padding: 0; display: grid; gap: 0.5rem; }
.kontaktdaten dt { font-weight: 600; }
.kontaktdaten dd { margin: 0 0 0.9rem; color: var(--ink-muted); }

/* Hinweis auf computererzeugte Bilder (22.08.2026)
   --------------------------------------------------------------------------
   Die Stimmungsbilder der Seite sind maschinell erzeugt und zeigen kein
   bestimmtes Objekt der Firma. Seit dem 02.08.2026 gelten die
   Transparenzpflichten aus Artikel 50 der EU-KI-Verordnung; unabhaengig
   davon koennte der Bauverlauf sonst wie eine Referenz gelesen werden, die
   er nicht ist.

   Der Hinweis soll erkennbar sein, aber nicht auffallen - so hat der Inhaber
   es entschieden. Deshalb: klein, leise, direkt beim Bild. Kein Kasten, kein
   Banner. Auf dem Foto im Kopf steht er in gedaempftem Weiss, im Text in der
   gedaempften Textfarbe.
   -------------------------------------------------------------------------- */

.bildhinweis {
  font-size: 0.74rem;
  line-height: 1.4;
  color: var(--ink-muted);
  margin: 1rem 0 0;
}
.hero-bild .bildhinweis {
  margin-top: 1.8rem;
  color: rgba(255, 255, 255, 0.6);
}
/* In der Fusszeile der Startseite steht er zwischen Anschrift und
   Rechtslinks und muss deren Abstaende mitmachen. */
.gate-foot .bildhinweis {
  margin: 0.1rem 0 0.6rem;
  color: rgba(255, 255, 255, 0.5);
  font-size: 0.72rem;
}

/* QR-Code mit den Kontaktdaten (22.08.2026)
   --------------------------------------------------------------------------
   Wozu: Wer am Rechner sitzt, kann eine Rufnummer nicht antippen. Code
   scannen, Kontakt steht im Adressbuch. Am Handy ist die Nummer ohnehin ein
   Verweis - dort waere der Code sinnlos und nimmt nur Platz weg, deshalb
   blendet ihn die letzte Regel dort aus.

   Der weisse Grund unter dem Bild ist kein Schmuck: Die SVG-Datei enthaelt
   schwarze Pfade auf durchsichtigem Grund. Auf einer dunklen Karte waere der
   Code sonst unsichtbar.

   150 Punkte Kantenlaenge sind die Untergrenze. Der Code hat 53 Module plus
   Rand; darunter wird ein Modul schmaler als zweieinhalb Punkte, und das
   Scannen vom Bildschirm wird unzuverlaessig. Erzeugt von
   werkzeug/qr-kontakt.py.
   -------------------------------------------------------------------------- */

.qr-block {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-top: 1.3rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
}
.qr-block img {
  display: block;
  flex: 0 0 auto;
  width: 150px;
  height: 150px;
  background: #fff;
  border-radius: 8px;
  padding: 6px;
}
.qr-block p {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--ink-muted);
}

@media (max-width: 720px) {
  .qr-block { display: none; }
}

/* --------------------------------------------------------------------------
   10. Fussbereich
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--surface);
  border-top: 1px solid var(--line);
  margin-top: clamp(3rem, 6vw, 5rem);
  padding-top: 3rem;
  font-size: 0.95rem;
}

.footer-grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  padding-bottom: 2.5rem;
}
.footer-head {
  font-weight: 650;
  font-size: 0.82rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 0.7rem;
}
.footer-brand { font-weight: 700; font-size: 1.05rem; margin-bottom: 0.4rem; }
.site-footer nav a { color: var(--ink-muted); text-decoration: none; display: block; padding: 0.15rem 0; }
.site-footer a { color: var(--ink-muted); }
.site-footer a:hover { color: var(--accent); }

/* Instagram in der Fusszeile
   --------------------------------------------------------------------------
   Nur ein VERWEIS, kein eingebetteter Inhalt. Es wird nichts von Meta
   nachgeladen, es fliesst nichts ab, bevor der Besucher klickt - deshalb
   bleibt die Seite ohne Einwilligungsbanner. Ein eingebetteter Feed waere
   etwas voellig anderes und wuerde eines erzwingen.

   Das Symbol ist selbst gezeichnet und steckt im Markup, nicht in einer
   Bilddatei: kein zusaetzlicher Abruf, und es nimmt ueber "currentColor"
   die Farbe des Textes an - auch beim Ueberfahren.
   -------------------------------------------------------------------------- */

.folgen { margin-top: 0.85rem; }

.instagram {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  text-decoration: none;
  /* Nur die beiden Eigenschaften, die sich wirklich aendern - kein "all". */
  transition: color 160ms ease,
              transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
}

/* Gibt beim Druecken nach, dieselbe Sprache wie .btn und die Kacheln. */
.instagram:active { transform: scale(0.97); }

.instagram svg {
  flex: 0 0 auto;          /* schrumpft nicht, wenn der Platz eng wird */
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linejoin: round;
}
.instagram svg .punkt { fill: currentColor; stroke: none; }

/* Auf der Startseite steht die Fusszeile ueber dem Foto: dort sind die
   Verweise weiss, nicht gedaempft. Die Farbe kommt aus gate.css, hier ist
   nur der Zeilenumbruch zu verhindern - Symbol und Wort gehoeren zusammen. */
.gate-foot .instagram { white-space: nowrap; }

.footer-bottom {
  border-top: 1px solid var(--line);
  padding-block: 1.2rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  color: var(--ink-muted);
  font-size: 0.88rem;
}
.footer-bottom p { margin: 0; }

/* --------------------------------------------------------------------------
   11. Rechtstexte (Impressum, Datenschutz)
   -------------------------------------------------------------------------- */

.rechtstext { max-width: 72ch; }
.rechtstext h2 { font-size: 1.35rem; margin-top: 2.5rem; }
.rechtstext h3 { font-size: 1.05rem; margin-top: 1.6rem; }

.hinweis {
  background: var(--accent-tint);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 1.2rem 1.4rem;
  margin-bottom: 2rem;
}
.hinweis p:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   12. Drucken
   -------------------------------------------------------------------------- */

@media print {
  .site-header, .site-footer, .btn-row, .cta { display: none; }
  body { background: #fff; color: #000; }

  /* Ein Expose wird ausgedruckt und mitgenommen. Die Datenspalte darf dabei
     nicht kleben bleiben, und das Anfrageformular hat auf Papier nichts
     verloren - die Rufnummer steht daneben. */
  .objekt-layout { display: block; }
  .objekt-spalte { position: static; }
  .objekt-anfrage, .beispiel-hinweis { display: none; }
  .objekt-block, .dateien a { break-inside: avoid; }

  /* Beim Ausdruck sieht man nicht, wohin ein Link fuehrt - deshalb die
     Adresse hinter den Linktext setzen. Interne Verweise bleiben aussen vor. */
  .rechtstext a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.85em; }
}

/* --------------------------------------------------------------------------
   13. Weniger Bewegung
   Wer an seinem Geraet "Bewegung reduzieren" eingestellt hat, bekommt keine
   Animationen. Das ist eine Einstellung fuer Menschen, denen davon schwindelig
   wird - die Seite funktioniert unveraendert weiter.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  a.card:hover { transform: none; }
  .btn:active     { transform: none; }
  .instagram:active { transform: none; }

  /* Schaufenster: Der Bildzoom ist reine Zierde und faellt ersatzlos weg.
     Der Rahmen faerbt sich weiter ein - das ist Information, keine Bewegung. */
  a.card.objekt-karte:hover .objekt-bild img,
  .bilder-raster a:hover img { transform: none; }
  a.card.objekt-karte:active,
  .dateien a:active { transform: none; }
}
