/* Reibel & Co. — Design-Werte exakt aus mockup/UEBERGABE-Claude-Code.md, Abschnitt 5. */

/* General Sans, lokal eingebunden (siehe CLAUDE.md für Herkunft/Lizenz).
   Alle sechs aufrechten Schnitte (200/300/400/500/600/700) lokal verfügbar,
   damit die Dicke pro Element frei wählbar ist – aktuell tatsächlich
   verwendet: 200 (.gh-bottom-left a/.gh-bottom-right a), 400 (Standardtext),
   600 (<strong>), 700 (.gh-bottom-brand).
   Keine Kursiven, keine Variable-Datei. Pfade relativ wie bei den
   Icon-Masken (assets/css/ → assets/fonts/), da {{asset}} ein Ghost-
   Handlebars-Helfer ist und in .css-Dateien nicht ausgewertet wird. */
@font-face {
  font-family: 'General Sans';
  src: url('../fonts/GeneralSans-Extralight.woff2') format('woff2');
  font-weight: 200;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: 'General Sans';
  src: url('../fonts/GeneralSans-Light.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: 'General Sans';
  src: url('../fonts/GeneralSans-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: block;
}

/* .gh-bottom-left a nutzt tatsächlich font-weight 200 (gh-bottom-brand: 700),
   nicht 500 - dieser Schnitt wird aktuell nirgends im Theme angewendet. */
@font-face {
  font-family: 'General Sans';
  src: url('../fonts/GeneralSans-Medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: 'General Sans';
  src: url('../fonts/GeneralSans-Semibold.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: block;
}

@font-face {
  font-family: 'General Sans';
  src: url('../fonts/GeneralSans-Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: block;
}

:root {
  --bild-h: min(219.375px, calc((100vw - 40px) * 0.5625));
  --oben: 48px;
  --bg: #000000;
  --fg: #f4f4f2;
  /* Flaeche hinter Bildern: Reines Weiss/Schwarz, invertiert zur Textfarbe. */
  --media-bg: #ffffff;
  --placeholder: #999999;
  /* Zentrale Animationsdauer/-kurve, einheitlich für alle Übergänge/
     Animationen der Seite (Seitenwechsel, Hover, Cursor-Blinken) - theme-
     unabhängig, daher nur hier einmal definiert, nicht in den drei Theme-
     Blöcken unten. */
  --dauer: 0.8s;
  --kurve: ease-in-out;
  /* Platzhalter für den Rahmen-Farbwechsel der E-Mail-Box (.gh-ctaform,
     .gh-cta-button) - werden später durch Farben aus einem GIF ersetzt. */
  color-scheme: dark;
}

/* Ohne JavaScript: Fallback auf die Systemeinstellung, solange kein
   data-theme-Attribut gesetzt ist (siehe Inline-Script in default.hbs). */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --bg: #FFFFFF;
    --fg: #111111;
    --media-bg: #000000;
    color-scheme: light;
  }
}

/* Mit JavaScript: Tageszeit-abhängig per data-theme auf <html>, siehe
   default.hbs (Inline-Script) und site.js (minütlicher Re-Check). Die
   color-scheme-Eigenschaft hier übernimmt dieselbe Unterscheidung wie
   --bg/--fg – zusätzlich zum color-scheme, das das Kopf-Skript direkt als
   Inline-Style setzt (siehe default.hbs), damit der Browser schon vor dem
   Laden dieser Datei die richtige Grundfarbe/UI-Einfärbung kennt. */
:root[data-theme="dark"] {
  --bg: #000000;
  --fg: #f4f4f2;
  --media-bg: #ffffff;
  color-scheme: dark;
}

:root[data-theme="light"] {
  --bg: #FFFFFF;
  --fg: #111111;
  --media-bg: #000000;
  color-scheme: light;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  background: var(--bg);
  overscroll-behavior-y: none;
}

body {
  font-family: 'General Sans', sans-serif;
  color: var(--fg);
}

/* Kein grauer/blauer Browser-Standard-Tipp-Schimmer beim Antippen (Safari:
   rgba(0,0,0,.4), Chrome: rgba(51,181,229,.4)) - betrifft alle Links (inkl.
   .gh-icon, .gh-quiet-link, die beide <a> sind) und den einzigen Button
   (.gh-cta-button). Kein eigener :active-Effekt ergänzt, da keiner der
   Mockups einen vorsieht. */
a,
button {
  -webkit-tap-highlight-color: transparent;
}

a {
  color: var(--fg);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

/* Eigener Tastaturfokus-Rahmen statt Browser-Standard: dünn, in Textfarbe,
   mit kleinem Abstand zum Element. :focus-visible erscheint nur bei
   Tastaturbedienung (Tab), nicht bei Maus-/Touch-Klick - genau wie vom
   Browser-Standard-Outline ohnehin schon gehandhabt, hier nur optisch an das
   Theme angepasst statt dem Browser-Blau/-Grau überlassen. Gilt für alle
   Links (deckt .gh-icon und .gh-quiet-link mit ab, beides <a>-Elemente) -
   Buttons sind hier bewusst nicht eingeschlossen (Auftrag beschränkt den
   eigenen Fokus-Stil auf "Links und Icons"), .gh-cta-button behält seinen
   Browser-Standard-Fokusrahmen. */
a:focus-visible {
  outline: 1.5px solid var(--fg);
  outline-offset: 3px;
}

::placeholder {
  color: var(--placeholder);
}

/* Seiten-Rahmen */

.gh-page {
  min-height: 100vh;
  min-height: 100dvh;
  padding: 24px 28px;
  background: var(--bg);
  color: var(--fg);
  font-family: 'General Sans', sans-serif;
  font-size: 14px;
  line-height: 1.35;
  letter-spacing: -.005em;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

/* Nur Blog, nur oberhalb des Mobile-Breakpoints (dort regelt .gh-frame per
   min-height bereits korrekt, siehe @media max-width:640px unten): .gh-page
   braucht hier eine definite (nicht nur Mindest-)Höhe, sonst leitet WebKit
   (iPad Safari, 768-1024px) die Höhe von .gh-blog-feed (flex:1 1 0) aus dem
   Inhalt statt aus dem Viewport ab - alle drei Beiträge landen dann
   nebeneinander auf einer "Seite" statt einzeln einrastend im Feed zu
   scrollen (Chromium zeigt den Bug nicht). Betrifft ausschließlich die
   Blogseite, da nur dort ein Flex-Kind mit height:100% von dieser Höhe
   abhängt. */
@media (min-width: 641px) {
  .gh-page--blog {
    height: 100vh;
    height: 100dvh;
  }
}

.gh-frame {
  display: contents;
}

/* Obere Zeile */

.gh-top {
  display: flex;
  justify-content: space-between;
  align-items: last baseline;
  gap: 24px;
  height: 24px;
  box-sizing: border-box;
  /* Sichtbare Oberkante der Schrift = sichtbare Unterkante der Fußzeile (je ~24px). */
  position: relative;
  top: -10px;
}

.gh-top-left {
  display: flex;
}

.gh-bottom .gh-top-left {
  align-self: flex-end;
}

.gh-social {
  display: flex;
  gap: 0;
  align-items: center;
}

.gh-icon {
  position: relative;
  display: flex;
  align-items: center;
  height: 15.48px;
}

.gh-icon:hover {
  text-decoration: none;
}

/* Unsichtbare Tippfläche für Touch (::after, rein geometrisch). Seitlich 6px,
   damit die schmalsten Icons (12px, LinkedIn/X) die 24px-Untergrenze erreichen
   – bei gap:8px (s. u.) reicht der sichtbare Abstand dafür nicht mehr aus,
   das erzeugt eine bewusst in Kauf genommene ~4px-Überlappung zwischen den
   Tippflächen (24px-Untergrenze wiegt schwerer, Details: CLAUDE-HISTORY.md).
   Oben/unten 15,5px → 44px Gesamthöhe (kein Nachbar in der Zeile). */
.gh-icon::after {
  content: "";
  position: absolute;
  top: -14.26px;
  bottom: -14.26px;
  left: -6px;
  right: -6px;
}

/* Social-Logos (offizielle simple-icons-SVGs aus assets/images/, E-Mail-Icon
   als Glyphen-Kontur aus Inter Regular, SIL OFL 1.1), einfarbig per
   CSS-Maske in Textfarbe. LinkedIn: nachgezeichnet aus der offiziellen PNG von
   brand.linkedin.com (Quadrat mit ausgeschnittenem "in"). YouTube und Instagram:
   SVGs aus den offiziellen Marken-Downloads. */

.gh-icon-glyph {
  display: block;
  background-color: var(--fg);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

.gh-icon-glyph--linkedin {
  width: 12.73px;
  height: 12.73px;
  position: relative;
  top: 1px;
  -webkit-mask-image: url("../images/linkedin.svg");
  mask-image: url("../images/linkedin.svg");
}

.gh-icon-glyph--youtube {
  width: 18.12px;
  height: 12.69px;
  position: relative;
  top: 1px;
  -webkit-mask-image: url("../images/youtube.svg");
  mask-image: url("../images/youtube.svg");
}

.gh-icon-glyph--x {
  width: 12.20px;
  height: 12.46px;
  position: relative;
  top: 0.71px;
  -webkit-mask-image: url("../images/x.svg");
  mask-image: url("../images/x.svg");
}

.gh-icon-glyph--instagram {
  width: 13.83px;
  height: 13.83px;
  position: relative;
  top: 1px;
  -webkit-mask-image: url("../images/instagram.svg");
  mask-image: url("../images/instagram.svg");
}

/* Social-Icons unten links (.gh-social) auf Wunsch verkleinert (Faktor 11/13,
   ≈87%, auf YouTube/LinkedIn/Instagram angewendet). Höhe/Tippfläche hier
   gezielt nur für .gh-social überschrieben (höhere Spezifität schlägt die
   .gh-icon-Basisregeln oben). */
.gh-social .gh-icon {
  height: 15.28px;
}

/* Sichtbare Abstände zwischen den Icon-Grafiken (nicht den Boxen): exakt
   8px zwischen den Tinten-Rändern jedes Paars. Jedes Logo füllt seine Box
   praktisch randlos aus (per Bounding-Box-Berechnung aus den SVG-Pfaden
   geprüft), nur LinkedIn (1.0917px Leerraum je Seite, eigener Pfad) hat
   nennenswerten internen Leerraum - margin-right gleicht das aus, damit
   trotzdem überall 8px sichtbarer Abstand ankommt. YouTubes Tinte reicht bis
   an den Rand seiner Box (kein Leerraum), die Box selbst sitzt ohne
   Zusatz-Margin an der Containerkante, damit die linke Kante weiterhin
   bündig mit dem Bild-Kasten ist. X (SVG-Maske, randlos wie die anderen
   Logos) ist jetzt das letzte Element, braucht also kein eigenes
   margin-right. */
.gh-social .gh-icon:nth-child(1) {
  margin-right: 8px;
}

.gh-social .gh-icon:nth-child(2) {
  margin-right: 8px;
}

.gh-social .gh-icon:nth-child(3) {
  margin-right: 8px;
}

.gh-social .gh-icon::after {
  top: -14.36px;
  bottom: -14.36px;
  left: 0;
  right: 0;
}

.gh-top-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: flex-start;
  gap: 8px;
}

.gh-blog-link {
  font-size: 14px;
  font-style: italic;
  font-family: "Times New Roman", Times, serif;
  text-decoration: none;
}

/* Mitte */

/* .gh-middle zentriert sich als normales Flex-Kind von .gh-page zwischen
   oberer und unterer Zeile (margin: auto 0 – Flexbox verteilt übrigen Platz
   gleichmäßig auf beide Seiten, das ist immer exakt symmetrisch). Reicht der
   Platz nicht, fallen die auto-Margins auf 0 zurück statt negativ zu werden –
   der Block kann die Zeilen dadurch nie überlappen. padding: 24px 0 sichert
   zusätzlich einen garantierten Mindestabstand von 24px zu beiden Zeilen,
   auch in diesem Fall (0 Margin + 24px Padding = 24px sichtbarer Abstand).
   Padding statt zusätzlichem festen margin, damit die Regel ausschließlich
   .gh-middle betrifft und nicht in .gh-top/.gh-bottom (von allen Seiten
   geteilt) oder .gh-page hineinwirkt. Kein Rahmen/Hintergrund auf .gh-middle,
   daher optisch nicht von margin zu unterscheiden. */

/* gap:12.25px traf auf der Startseite den sichtbaren Abstand Bildkasten-
   Unterkante -> Tinte der ersten Textzeile (17.5px, wie der Absatzabstand,
   siehe .gh-body margin unten). .gh-middle-body beginnt ohne eigenes Padding
   direkt mit der ersten Zeile, daher gilt dieselbe Rechnung (Box-Abstand +
   Halbfuehrung der 21px-Zeilenbox bei line-height:1.5/font-size:14px) fuer
   jede Seite, deren erste Zeile nach dem Bildkasten mit dieser Zeilenhoehe
   gesetzt ist (Startseite) - bewusst als Basisregel
   statt Seiten-Override. Impressum/
   Datenschutz haben dort eine fette Zwischenueberschrift mit abweichender
   Zeilenhoehe (18px statt 21px, siehe .gh-page--serif-headings .gh-body
   strong) und bekommen deshalb einen eigenen, groesseren Wert weiter unten
   (.gh-page--heading-media). */
.gh-middle {
  position: static;
  width: min(390px, 70vw);
  padding: 24px 0;
  margin: auto 0;
  align-self: center;
  display: flex;
  flex-direction: column;
  gap: 12.25px;
}

/* .gh-page--heading-media (Impressum, Datenschutz): erste Zeile nach dem
   Bildkasten ist eine fette <strong>-Zwischenueberschrift mit line-height:
   18px statt der sonst ueblichen 21px (1.5 * 14px) - die Halbfuehrung
   oberhalb der Tinte ist dadurch um 1.5px kleiner (haelftig von den fehlenden
   3px Zeilenhoehe). 12.25px (Basisregel oben) + 1.5px = 13.75px gleicht das
   aus, damit der sichtbare Abstand ebenfalls 17.5px betraegt. */
.gh-page--heading-media .gh-middle {
  gap: 8px;
  padding: 0;
  margin: max(0px, calc(50vh - var(--bild-h) / 2 - var(--oben))) 0 auto;
  margin-top: max(0px, calc(50dvh - var(--bild-h) / 2 - var(--oben)));
  padding-bottom: 24px;
}

/* Datenschutz: zu viel Text, um zu zentrieren (wie im Mockup) – normaler
   Textfluss mit margin:40px auto statt Zentrierung. padding:0 hebt das
   .gh-middle-Padding wieder auf. Nur hier verwendet (datenschutz.hbs). */

.gh-middle--flow {
  padding: 0;
  margin: 40px auto;
}

.gh-media {
  display: block;
  width: 100%;
  height: var(--bild-h);
  flex-shrink: 0;
  background: #000000;
  object-fit: cover;
  object-position: 50% 17%;
  filter: grayscale(1);
}

:root[data-theme="dark"] .gh-media {
  background: #ffffff;
}

/* GIFs (Impressum, Datenschutz): keine weiße/schwarze Fläche dahinter, damit beim
   Laden nichts aufblitzt. */
.gh-media--gif,
:root[data-theme="dark"] .gh-media--gif {
  background: transparent;
}

/* Impressum/Datenschutz: Die Seite erscheint erst, wenn das Bild da ist (alles
   gleichzeitig, kein Aufbau in Stufen). Klasse setzt das Skript im Kopf der Seite,
   spätestens nach 2s fällt sie wieder weg. */
html.gh-wartet .gh-page {
  visibility: hidden;
}

/* Startseite: Umschliesst nur das Bild (nicht .gh-middle-body), damit die
   Beschriftung "Philip Reibel" exakt relativ zum Bild positioniert werden
   kann. Bekommt selbst keine eigene Breite/Hoehe - .gh-media bestimmt
   weiterhin beides unveraendert, der Rahmen passt sich automatisch an dessen
   Groesse an. flex-shrink:0 wiederholt hier, da jetzt dieser Rahmen (nicht
   mehr .gh-media direkt) das Flex-Kind von .gh-middle ist. */
.gh-media-frame {
  position: relative;
  flex-shrink: 0;
}

/* Echter Text (Barrierefreiheit, nicht im Bild selbst), liegt direkt in der
   Bildbox, buendig an der unteren linken Ecke (Wunsch Philip, gilt fuer alle
   Seiten mit .gh-media-frame: Startseite, Blog).
   Farbe var(--bg) statt var(--fg), da das genau die Kontrastfarbe zur
   Bildbox-Flaeche (--media-bg) ergibt - in beiden Themes ist --media-bg
   jeweils exakt invertiert zu --bg. */
.gh-media-caption {
  position: absolute;
  left: 3px;
  bottom: 2.5px;
  display: block;
  text-align: left;
  margin: 0;
  font-family: 'General Sans', sans-serif;
  font-size: 14px;
  font-weight: 400;
  line-height: 1;
  color: var(--bg);
}

/* Blog: Navigations-Zeile unter dem Beitragstext, zwei reine Pfeil-Icons ohne
   Text (.gh-blog-nav-row hat dieselbe Breite wie .gh-blog-post-content,
   min(390px,70vw), kein eigenes Padding) - dadurch stehen die Pfeile ohne
   jeden Trick buendig an der linken/rechten Kante von GIF/Text. Links Pfeil
   runter ("weiter"), rechts Pfeil hoch ("zurück"). An den Enden (Beitrag 1
   ohne "vorher", Beitrag 3 ohne "weiter") bleibt die Gegenseite als
   unsichtbarer, nicht fokussierbarer Platzhalter stehen
   (gh-blog-nav-link--hidden), damit die jeweils sichtbare Seite nicht durch
   justify-content:space-between an den Rand "springt" und die Zeilenhoehe
   konstant bleibt. Barrierefreier Name kommt ausschließlich vom aria-label
   am <a> (siehe blog.hbs), das SVG selbst ist aria-hidden. */
.gh-blog-nav-row {
  width: 100%;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Sichtbarer Abstand Text-Grundlinie -> Pfeil-Oberkante soll wie sonst auf
     der Seite 17,5px betragen (gemessen 13,5px bei 10px margin-top, also
     +4px). Keine eigene Mobile-Regel noetig: weder Zeilenhoehe/-groesse des
     Texts noch Pfeilgroesse/-position skalieren mit der Viewport-Breite,
     die +4px wirken daher auf beiden Breakpoints gleich 1:1 durch. */
  margin-top: 8px;
}

.gh-blog-nav-link {
  position: relative;
  display: inline-flex;
  color: var(--fg);
}

/* Pfeil-SVGs haben beidseitig 2px Leerraum im Pfad (viewBox 0 0 10 14,
   sichtbare Tinte bei x=2..8) - per Negativ-Margin nach aussen gezogen,
   damit die Pfeilspitze buendig mit der Kante von Bild/Text abschliesst
   (gleiche Breite wie .gh-blog-post-content). Die Tippflaeche (::after)
   verschiebt sich automatisch mit, da relativ zur Link-Box positioniert. */
.gh-blog-nav-link--next {
  margin-left: -2px;
}

.gh-blog-nav-link--prev {
  margin-right: -2px;
}

.gh-blog-nav-link svg {
  display: block;
  height: 14px;
  width: auto;
}

.gh-blog-nav-link--hidden {
  visibility: hidden;
  pointer-events: none;
}

/* Unsichtbare Tippfläche, Ziel 44x44px (wie bei den Social-Icons oben,
   siehe .gh-icon::after) - ragt dafür bewusst über den sichtbaren
   Pfeil (10x14px) hinaus. */
.gh-blog-nav-link::after {
  content: "";
  position: absolute;
  top: -15px;
  bottom: -15px;
  left: -17px;
  right: -17px;
}

.gh-middle-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Bildkasten exakt vertikal mittig, der Text hängt darunter. */
.gh-page--home .gh-middle,
.gh-page--serif-headings:not(.gh-page--heading-media) .gh-middle {
  position: relative;
  padding: 0;
  gap: 8px;
}

.gh-page--home .gh-middle-body,
.gh-page--serif-headings:not(.gh-page--heading-media) .gh-middle-body {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 8px;
}

.gh-page--home .gh-slogan,
.gh-page--serif-headings:not(.gh-page--heading-media) .gh-middle-body .gh-body {
  margin-bottom: 0;
}

.gh-page--home .gh-middle-body,
.gh-page--serif-headings:not(.gh-page--heading-media) .gh-middle-body {
  gap: 8px;
}

/* Bei sehr niedrigem Fenster (kleine Handys) würde der Text in die Fußzeile
   ragen - dort bleibt es bei der gemeinsamen Zentrierung von Bild und Text. */
@media (max-height: 600px) {
  .gh-page--home .gh-middle,
  .gh-page--serif-headings:not(.gh-page--heading-media) .gh-middle {
    position: static;
    padding: 24px 0;
  }

  .gh-page--home .gh-middle-body,
  .gh-page--serif-headings:not(.gh-page--heading-media) .gh-middle-body {
    position: static;
    margin-top: 0;
  }
}

@media (max-height: 600px) and (max-width: 640px) {
  .gh-page--home .gh-middle,
  .gh-page--serif-headings:not(.gh-page--heading-media) .gh-middle {
    padding: 12px 0;
  }
}

/* Blog-Feed (nur blog.hbs): eigener, senkrecht scrollender Beitragsbereich
   statt .gh-middle - betrifft ausschliesslich diese eine Seite. flex:1 1 auto
   + min-height:0 lässt den Feed exakt den Platz zwischen oberer Reihe und
   Fusszeile füllen (min-height:0 ist in Flexbox nötig, damit ein Flex-Kind
   unter seine Inhaltshöhe schrumpfen und selbst scrollen kann). Scrollbar
   bleibt funktional (Maus/Trackpad/Touch/Tastatur), nur optisch ausgeblendet. */
.gh-blog-feed {
  /* flex-basis:0 statt auto: verhindert, dass der Browser die Höhe des
     Feeds zirkulär aus dem Inhalt (den Beiträgen mit height:100%) ableitet
     - sonst kollabiert jeder Beitrag auf seine Inhaltshöhe statt die volle
     Feed-Höhe einzunehmen (beobachtet auf Desktop, wo .gh-frame
     display:contents ist). */
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  /* overflow-x explizit hidden: ohne das zwingt die Spec overflow-x auf
     "auto", sobald overflow-y einen Scroll-Wert hat - die unsichtbare
     44x44px-Tippfläche der Blog-Pfeile (.gh-blog-nav-link::after) ragt an
     den Rändern bündig über die Feed-Breite hinaus und würde sonst
     horizontales Ziehen/Scrollen ermöglichen, ohne optisch sichtbar zu sein. */
  overflow-x: hidden;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.gh-blog-feed::-webkit-scrollbar {
  display: none;
}

/* Weiches Einrasten nur ohne reduzierte-Bewegung-Präferenz - ohne JavaScript,
   rein über Anker-Links (href="#N") + scroll-behavior gelöst. */
@media (prefers-reduced-motion: no-preference) {
  .gh-blog-feed {
    scroll-behavior: smooth;
  }
}

/* Jeder Beitrag exakt so hoch wie der sichtbare Feed-Bereich (height:100%
   löst gegen die Content-Box von .gh-blog-feed auf, nicht gegen dessen
   scrollHeight) - rastet dadurch immer randgenau ein. */
.gh-blog-post {
  position: relative;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

.gh-blog-post .gh-body > * {
  margin: 0;
}

.gh-blog-post .gh-body > * + * {
  margin-top: 4px;
}

.gh-video-play {
  position: absolute;
  inset: 0;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.gh-video-play::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  border-radius: 50%;
  background: var(--fg);
}

.gh-video-play::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  margin: -8px 0 0 -5px;
  border-style: solid;
  border-width: 8px 0 8px 14px;
  border-color: transparent transparent transparent var(--bg);
}

/* Der Player liegt 1px innerhalb des Vorschaubilds, damit sein dunkler Rand
   nicht an der Bildkante durchscheint; beim Abspielen füllt er die ganze Box. */
.gh-video-frame {
  position: absolute;
  inset: 1px;
}

.gh-media-frame.is-playing .gh-video-frame {
  inset: 0;
}

/* Der Player bleibt unsichtbar, bis das Video wirklich läuft (.is-playing), damit er
   nie unter/über dem Vorschaubild aufblitzt (mobiles Safari malt Iframes sonst kurz
   obenauf). opacity statt display, damit der Tipp weiterhin im Player landet
   (iPhone-Ton). */
.gh-media-frame.has-video:not(.is-playing) .gh-video-frame {
  opacity: 0;
}

.gh-video-frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* YouTube-Video im Blog: Vorschaubild, Play-Knopf und (unsichtbarer) Player liegen
   deckungsgleich in einer Box. Vorschaubild und Play-Knopf erscheinen sofort, sobald
   das Bild geladen ist (blog.hbs setzt .gh-thumb und .is-da). Beim Abspielen (.is-playing)
   blenden beide aus und der Player ist sichtbar. */
.gh-media-frame.has-video .gh-media,
:root[data-theme="dark"] .gh-media-frame.has-video .gh-media {
  background: transparent;
}

.gh-media-frame.has-video .gh-media {
  position: relative;
  z-index: 1;
  pointer-events: none;
}

.gh-media.gh-thumb,
.gh-media-frame.has-video .gh-video-play {
  opacity: 0;
}

.gh-media.gh-thumb.is-da,
.gh-media-frame.has-video .gh-media.gh-thumb.is-da ~ .gh-video-play {
  opacity: 1;
}

.gh-media-frame.has-video .gh-video-play {
  position: absolute;
  z-index: 2;
  pointer-events: none;
}

.gh-media-frame.is-playing .gh-media,
.gh-media-frame.is-playing .gh-video-play,
.gh-media-frame.is-playing .gh-media.gh-thumb.is-da ~ .gh-video-play {
  opacity: 0;
}

.gh-blog-anchor {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
}

.gh-blog-post-content {
  width: min(390px, 70vw);
  height: 100%;
  display: grid;
  grid-template-rows: calc((100% - var(--bild-h)) / 2) auto auto auto 1fr;
}

.gh-blog-post-content > .gh-media-frame {
  grid-row: 2;
  margin-bottom: 8px;
}

.gh-blog-post-content > .gh-body {
  grid-row: 3;
  margin-bottom: 0;
}

.gh-blog-post-content > .gh-blog-nav-row {
  grid-row: 4;
}

/* Startseiten-Slogan (fester Text, ein Absatz mit Zeilenumbruch + 7px-Lücke) */

.gh-slogan {
  font-size: 12px;
  line-height: 1.5;
  margin: 0 0 8.25px;
}

.gh-slogan a,
.gh-body a {
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 0.7px;
  transition: color var(--dauer) var(--kurve), text-decoration-color var(--dauer) var(--kurve);
}

.gh-slogan a:hover,
.gh-body a:hover {
  color: var(--placeholder);
  text-decoration-color: transparent;
}

/* Fließtext der Unterseiten (Impressum/Datenschutz:
   mehrere Abschnitte, je Überschrift fett + Zeilenumbruch + Text) */

.gh-body {
  font-size: 12px;
  line-height: 1.5;
  margin: 0 0 9px;
}

.gh-sections {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.gh-body strong {
  font-weight: 600;
}

/* Nur auf Impressum/Datenschutz (.gh-page--serif-headings
   am jeweiligen Seiten-Root): fette Zwischenueberschriften in Times New Roman
   kursiv statt General Sans, wie beim "blog"-Link oben rechts. font-weight
   bleibt unveraendert (erbt 600 von .gh-body strong oben), Startseite/Blog
   sind nicht betroffen (kein <strong> dort). */
.gh-page--serif-headings .gh-body strong {
  font-family: 'Times New Roman', Times, serif;
  font-style: italic;
  font-size: 14px;
  line-height: 18px;
}

/* Von Ghost für alle Themes vorausgesetzte Koenig-Editor-Klassen (aktuell ungenutzt,
   da keine Inhalte mehr über den Ghost-Editor gepflegt werden). */

.kg-width-wide,
.kg-width-full {
  width: 100%;
}

/* E-Mail-Box (Startseite) */

.gh-ctaform {
  position: relative;
  display: flex;
  gap: 0;
  width: 100%;
  border: 0.5px solid var(--fg);
  height: 26px;
  box-shadow: 0 0 0 0 var(--fg);
  transition: box-shadow var(--dauer) var(--kurve);
}

/* Beim Darüberfahren wird die Kante von 0,5px auf 1,5px dick (ein zusätzlicher
   1px-Ring ohne Unschärfe, dadurch verschiebt sich nichts im Layout). */
@media (hover: hover) {
  .gh-ctaform:hover {
    box-shadow: 0 0 0 1px var(--fg);
  }
}

/* Steht irgendetwas im Feld (egal ob gültige Adresse), bleibt die Kante dick,
   auch wenn die Maus wieder weggeht. */
.gh-ctaform:has(.gh-cta-input:not(:placeholder-shown)) {
  box-shadow: 0 0 0 1px var(--fg);
}

.gh-cta-input {
  caret-color: var(--fg);
  caret-animation: manual; /* Standard-Blinken des Browsers aus, sonst stört es die eigene Animation */
  animation: gh-caret-blink calc(3 * var(--dauer)) var(--kurve) infinite;
  flex: 0 0 50%;
  box-sizing: border-box;
  min-width: 0;
  padding: 4.9px 8px 4.9px 8px;
  font: inherit;
  font-family: 'General Sans', sans-serif;
  font-size: 12px;
  font-weight: 400;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--fg);
  outline: none;
}

.gh-cta-placeholder {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 50%;
  padding: 0 9.7px 0 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'General Sans', sans-serif;
  font-size: 12px;
  font-weight: 400;
  color: var(--fg);
  pointer-events: none;
  white-space: nowrap;
  opacity: 1;
  transition: opacity var(--dauer) var(--kurve);
}

.gh-cta-input:not(:placeholder-shown) ~ .gh-cta-placeholder {
  display: none !important;
}

/* Fokus (auch bei leerem Feld): Platzhalter bleibt ausgeblendet, damit nie
   Platzhalter und echter Cursor gleichzeitig sichtbar sind. */
.gh-cta-input:focus ~ .gh-cta-placeholder {
  opacity: 0;
}

@media (hover: hover) {
  /* Hover ueber der ganzen Box (Eingabefeld und Button), Feld leer und
     nicht fokussiert: Platzhalter blendet aus. */
  .gh-ctaform:hover .gh-cta-input:placeholder-shown:not(:focus) ~ .gh-cta-placeholder {
    opacity: 0;
  }
}

/* Im leeren, unfokussierten Feld bleibt der echte Textcursor unsichtbar -
   gh-caret-blink würde caret-color sonst wieder auf var(--fg) animieren.
   Bei Fokus (auch leer) ist der echte Cursor wieder sichtbar und blinkt
   normal ueber gh-caret-blink auf .gh-cta-input. */
.gh-cta-input:placeholder-shown:not(:focus) {
  animation: none;
  caret-color: transparent;
}

/* Fokus durch Autofokus beim Hover (siehe email-form.hbs): Platzhalter
   blendet erst über var(--dauer) aus, deshalb bleibt auch der echte Cursor
   für var(--dauer) unsichtbar, bevor er zu blinken beginnt. Bei Fokus durch
   Klick/Tastatur (keine is-hover-focus-Klasse) entfällt die Verzögerung. */
.gh-cta-input.is-hover-focus:focus {
  caret-color: transparent;
  animation-delay: var(--dauer);
}

@keyframes gh-caret-blink {
  0%, 100% { caret-color: var(--fg); }
  50% { caret-color: transparent; }
}

.gh-cta-button {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 50%;
  box-sizing: border-box;
  min-width: 0;
  padding: 4.9px 1.7px 4.9px 0;
  font: inherit;
  font-size: 14px;
  font-weight: 400;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--fg);
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition: text-decoration-color var(--dauer) var(--kurve);
  -webkit-user-select: none;
  user-select: none; /* Text nicht markierbar, sonst wird der unsichtbare Strich beim Markieren sichtbar */
}

/* Ohne gültige E-Mail-Adresse ist der Button nicht anklickbar. */
.gh-cta-input:not(:valid) ~ .gh-cta-button {
  pointer-events: none;
}

.gh-cta-button:hover {
  text-decoration-color: transparent;
}

@media (hover: hover) {
  /* Strich nur bei gültiger E-Mail-Adresse (type=email + pattern, siehe email-form.hbs). */
  .gh-cta-input:valid ~ .gh-cta-button:hover .gh-cta-label {
    text-decoration-color: currentColor;
  }
}

.gh-cta-button:focus-visible .gh-cta-label {
  text-decoration-color: currentColor;
}

.gh-cta-label {
  display: inline-block;
  min-width: 0;
  text-align: center;
  font-family: 'General Sans', sans-serif;
  font-size: 12px;
  font-weight: 400;
  color: var(--fg);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 0.7px;
  text-underline-offset: 2px;
  transition: text-decoration-color var(--dauer) var(--kurve);
}

.gh-cta-arrow {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  transform: translateX(-50%);
  pointer-events: none;
  display: inline-flex;
  align-items: center;
  font-family: 'General Sans', sans-serif;
  font-size: 12px;
  font-weight: 300;
  color: var(--fg);
  margin: 0;
  opacity: 0.75;
}

/* Untere Zeile */

.gh-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 32px;
  flex-wrap: wrap;
  height: 24px;
  box-sizing: border-box;
}

.gh-bottom-left {
  display: flex;
  gap: 8px;
  align-items: baseline;
  margin-left: -1.1px;
}

.gh-bottom-left a {
  font-size: 14px;
  font-weight: 200;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

/* "Reibel & Co." bekommt denselben Hover-Strich wie "Blog" oben
   rechts (identische Technik/Werte: sichtbare Basis-Unterstreichung, beim
   Hover/Fokus transparent). "Reibel & Co." (.gh-bottom-brand) bleibt
   ausgenommen. .gh-quiet-link:hover setzt text-decoration:none (siehe dort)
   - hier mit hoeherer Spezifitaet ueberschrieben. */
.gh-bottom-left a:not(.gh-bottom-brand) {
  font-size: 12px;
  text-decoration: none;
}

.gh-bottom-left a.gh-bottom-brand {
  font-size: 16px;
  font-weight: 700;
  position: relative;
  top: 0.5px;
}

/* Kopfzeile: gesamte Link-Reihe (Reibel & Co., Blog)
   gemeinsam nach unten, damit die Unterlaengen des "g" bei
   Blog auf bzw. knapp ueber der Unterkante der 24px-Zeile
   liegen (gemessen: g-Unterkante vorher 3,44px bzw. 2,87px darueber).
   Gemeinsame Grundlinie bleibt erhalten. */
.gh-top > .gh-bottom-left,
.gh-top > .gh-top-right {
  position: relative;
  top: 2.8px;
}

.gh-bottom-right {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  align-items: flex-end;
  align-self: stretch;
  gap: 8px;
}

.gh-bottom-right a {
  font-size: 8px;
  font-weight: 200;
  line-height: 1;
}

.gh-quiet-link:hover {
  text-decoration: none;
}

/* Unsichtbare Tippfläche für Touch (wie bei .gh-icon, s. o.), pro Gruppe
   anders bemessen, weil der Link-Text (57-75px links, 51-57px rechts) selbst
   schon breiter als 44px ist – seitlich reicht der jeweils halbe Link-Abstand
   (.gh-bottom-left gap:12px, .gh-bottom-right gap:8px). Senkrecht bis 44px
   Gesamthöhe, begrenzt durch den Abstand zum Inhalt darüber (mind. 24px,
   siehe .gh-middle) bzw. zum Seiten-Rand darunter (24px Padding) – auf
   Desktop reichlich Platz. */
.gh-quiet-link {
  position: relative;
}

.gh-bottom-left .gh-quiet-link::after {
  content: "";
  position: absolute;
  top: -12.55px;
  bottom: -12.55px;
  left: -6px;
  right: -6px;
}

.gh-bottom-right .gh-quiet-link::after {
  content: "";
  position: absolute;
  top: -14.5px;
  bottom: -14.5px;
  left: -4px;
  right: -4px;
}

/* "blog" (14px, wie die Fußzeilen-Links links) hat keinen Nachbarn in seiner
   Spalte, dieselbe Untergrenzen-Berechnung wie .gh-bottom-left gilt 1:1. */
.gh-top-right .gh-quiet-link::after {
  content: "";
  position: absolute;
  top: -12.55px;
  bottom: -12.55px;
  left: -6px;
  right: -6px;
}

/* Mobile */

@media (max-width: 640px) {
  :root {
    --oben: 60px;
  }

  .gh-page {
    /* min-height kommt jetzt von der Basisregel (100vh/100dvh, ohne feste
       Untergrenze) – hier nur noch Padding/Ausrichtung, siehe CLAUDE.md. */
    padding: 24px 20px;
    display: flex;
    flex-direction: row;
    justify-content: center;
  }

  .gh-frame {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    max-width: 390px;
    min-height: calc(100vh - 48px);
    min-height: calc(100dvh - 48px);
  }

  .gh-top {
    gap: 16px;
  }

  /* "blog" hat als Text (anders als die randlosen Icons) unsichtbaren
     Zeilenraum oberhalb der eigentlichen Tinte - ohne Ausgleich wirkt es
     dadurch tiefer als die Icon-Oberkante, obwohl die Box-Oberkante gleich
     ist. Pixelgenau gemessen und ausgeglichen. */
  .gh-blog-link {
    margin-top: -1.8px;
  }

  .gh-middle {
    /* .gh-middle ist jetzt (seit der Flex-Zentrierung) ein normales Kind von
       .gh-frame, das selbst schon korrekt auf min(390px, 100vw-40px) begrenzt
       ist. width:100% übernimmt exakt diese Breite – bündig mit .gh-top/
       .gh-bottom, die als Geschwister ohne eigene Breite ganz normal auf die
       volle Frame-Breite gestreckt werden (align-items:stretch). Der alte
       Wert "min(390px, calc(100% - 40px))" war ein Rest aus der Zeit vor der
       Flex-Umstellung, als % noch gegen das Fenster statt gegen .gh-frame
       aufgelöst wurde – er zog dadurch 40px zu viel ab und machte den Block
       schmaler als Kopf-/Fußzeile. */
    width: 100%;
    padding: 12px 0;
  }

  .gh-blog-post-content {
    /* Gleicher Grund/gleiche Lösung wie bei .gh-middle oben: ohne diese
       Regel bleibt Bild/Text auf Mobil bei min(390px,70vw) stehen und wirkt
       schmaler/eingerückt im Vergleich zu Kopf-/Fußzeile und den anderen
       Seiten. */
    width: 100%;
  }

  .gh-bottom {
    align-items: center;
    gap: 16px;
  }

  .gh-bottom-left a {
    line-height: 1;
  }

  /* "Reibel & Co." und "Blog" stehen mobil weiterhin wie auf dem Desktop
     nebeneinander, brauchen daher keinen eigenen Mobile-Wert (die
     Basis-Regel oben gilt unverändert weiter, inkl. der dortigen
     Tippflächen-Insets). "Impressum"/"Datenschutz" stehen inzwischen auf
     Desktop und Mobil gleich übereinander mit gleicher Zeilenhöhe
     (Basisregel .gh-bottom-right a). */
}

/* Frueherer Fold-Fix fuer sehr schmale Viewports (Galaxy Z Fold, 280px) ist mit
   der Uhr entfernt worden: Der Platzmangel entstand ausschliesslich durch die
   ca. 107,7px breite Uhr neben den Icons - "Blog" ist so kurz, dass selbst bei
   280px (240px verfuegbare .gh-top-Breite) reichlich Platz bleibt, auch mit dem
   normalen mobilen Abstand (.gh-top{gap:16px} oben). Mit Playwright erneut
   gegen 280-1280px geprueft: kein horizontales Scrollen. */
