/* Space Grotesk (SIL OFL, github.com/floriankarsten/space-grotesk) als eine
   variable Datei für alle Schnitte 300–700 — kleiner als zwei statische und nur
   ein Request. Die Stärke kommt deshalb über font-weight (700 = fett, 400 =
   normal), nicht mehr wie bei Borna über eine eigene Familie je Schnitt. */
@font-face {
    font-family: 'Space Grotesk';
    src: url('../fonts/SpaceGrotesk-Variable.woff2') format('woff2');
    font-weight: 300 700;
    font-style: normal;
    font-display: swap;
    }

/* Fraunces (SIL OFL, github.com/undercasetype/Fraunces) als Serif — zwei
   variable Dateien, aufrecht und kursiv. Aus den Original-TTFs gebaut: die
   Achsen SOFT und WONK auf den Design-Vorgaben festgezurrt (0 / 1), opsz und
   wght (100–900) bleiben variabel, Zeichensatz auf Latin beschnitten — sonst
   wären es 2 × 400 kB statt 72 + 87 kB. Weitere Achsen oder Zeichen brauchen
   deshalb einen neuen Build, nicht nur eine CSS-Zeile.
   Die aufrechte Datei wird vorgeladen (index.php / album.php / 404.php, neben
   Space Grotesk): sie trägt die Unterzeile der Wortmarke, also Text ganz oben
   auf jeder Seite — ohne preload blitzt dort erst die Fallback-Serif auf. Die
   Kursive nicht, die kommt bislang in keinem sichtbaren Text vor. */
@font-face {
    font-family: 'Fraunces';
    src: url('../fonts/Fraunces-Variable.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    }

@font-face {
    font-family: 'Fraunces';
    src: url('../fonts/Fraunces-Italic-Variable.woff2') format('woff2');
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
    }

html, body, div, span, applet, object,
iframe, h1, h2, h3, h4, h5, h6, p, blockquote,
pre, a, abbr, acronym, address, big, cite,
code, del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var, b,
u, i, center, dl, dt, dd, ol, ul, li, fieldset,
form, label, legend, table, caption, tbody,
tfoot, thead, tr, th, td, article, aside,
canvas, details, embed, figure, figcaption,
footer, header, hgroup, menu, nav, output, ruby,
section, summary, time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	vertical-align: baseline;
}

article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
	display: block;}

body {
	line-height: 1em;
	padding: 1em !important;
	background: #fff;
}

ol, ul {
	list-style: none;
}

blockquote, q {
	quotes: none;
}

	blockquote:before, blockquote:after, q:before, q:after {
		content: '';
		content: none;
	}

table {
	border-collapse: collapse;
	border-spacing: 0;
}

body {
	-webkit-text-size-adjust: none;
}

mark {
	background-color: transparent;
	color: inherit;
}





:root {
  --clip-x: calc(100vw - 1rem - 0.6rem);
  --clip-y: 1.6rem;
  /* Anthrazit: Grund der dauerhaft dunklen Seite (<html class="dark"> steht fest
     im Markup). Ersetzt das Schwarz des früheren Dark Mode überall, wo es Fläche
     war — Seite, Bühne, Sektionen, Footer, Lightbox. */
  --bg-dark: #2b2b2b;
	--accent: #ff0050;

  /* Serif-Tokens (Fraunces). Ein Token je Schnitt, als font-Kurzschreibweise,
     damit Familie + Schnitt + Stärke in einer Deklaration stecken:

         .zitat { font: var(--serif-italic); }
         .lead  { font: var(--serif); font-size: 1.6rem; }

     Die 1em darin heißt "Größe des Elternelements", das Token erbt die Größe
     also von selbst; eine eigene font-size muss NACH dem font: stehen, sonst
     räumt die Kurzschreibweise sie wieder ab. Für Markup ohne eigene Regel
     gibt es die Klassen .serif / .serif-italic / .serif-bold weiter unten. */
  --serif-family: 'Fraunces', Georgia, 'Times New Roman', serif;
  --serif:        400 1em/1.2 var(--serif-family);
  --serif-italic: italic 400 1em/1.2 var(--serif-family);
  --serif-bold:   700 1em/1.2 var(--serif-family);
}

.font-accent {
	color: var(--accent);
}



/* Cross-document (home ↔ album) view transitions. */
@view-transition { navigation: auto; }

/* Theme-toggle circle reveal — scoped to its own type so it does NOT fire on
   page navigations (those get a plain cross-fade + the thumb→hero morph). */
:root:active-view-transition-type(theme)::view-transition-old(root) {
  animation-delay: 500ms;
}
:root:active-view-transition-type(theme)::view-transition-new(root) {
  animation: circle-in 500ms;
}

/* Shared element that morphs from a home gallery thumb into the album hero. */
.vt-hero { view-transition-name: album-hero; }

::view-transition-group(album-hero) {
  animation-duration: 0.45s;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

@keyframes move-in {
  from { translate: 0 -100%; }
  to { translate: 0  0; }
}

@keyframes circle-in {
  from { clip-path: circle(0% at var(--clip-x) var(--clip-y)); }
  to { clip-path: circle(120% at 50% 0%); }
}







* {
	font-family: 'Space Grotesk', sans-serif;
	font-weight: 700;
	font-size: 1rem;
	line-height: 1.2em;
	color: #000;
}

/* Dieselben drei Schnitte als Klassen. Die zweite Regel ist Pflicht, nicht
   Kosmetik: die *-Regel darüber trifft jedes Element einzeln, ein <em> oder
   <strong> in einem .serif-Absatz fiele sonst auf Space Grotesk 700 zurück.
   Deshalb erben Nachfahren Familie, Stärke und Schnitt ausdrücklich. */
.serif        { font: var(--serif); }
.serif-italic { font: var(--serif-italic); }
.serif-bold   { font: var(--serif-bold); }

.serif *, .serif-italic *, .serif-bold * {
	font-family: inherit;
	font-weight: inherit;
	font-style: inherit;
}

/* Aus demselben Grund die Größe für Inline-Auszeichnungen: die *-Regel setzt
   jedem Element 1rem, ein <em> in einer 2rem-Serifzeile fiele auf Kleinschrift
   zurück. Bewusst nur diese Tags — ein .serif auf einem Container darf einer
   Überschrift darin nicht die Größe wegnehmen. */
.serif a, .serif em, .serif i, .serif b, .serif strong, .serif span, .serif cite, .serif q,
.serif-italic a, .serif-italic em, .serif-italic i, .serif-italic b, .serif-italic strong,
.serif-italic span, .serif-italic cite, .serif-italic q,
.serif-bold a, .serif-bold em, .serif-bold i, .serif-bold b, .serif-bold strong,
.serif-bold span, .serif-bold cite, .serif-bold q {
	font-size: inherit;
}

h1 {
	font-size: 1.5rem;
	/* padding-block: 0.5em; */
}



/* Header is a sticky overlay pinned on top of the scrolling content.
   top:1em matches the body's 1em frame so it doesn't jump when it sticks. */
#header {
	position: sticky;
	top: 1em;
	z-index: 2000;
}



/* The title is the home link; re-enable clicks (header disables pointer events)
   and keep it looking like the heading (no underline, inherit the header's
   white text). block + fit-content so the click area stays tight to the text
   instead of spanning the whole row. */
#titlelink {
	display: block;
	width: fit-content;
	pointer-events: auto;
	cursor: pointer;
	text-decoration: none;
	color: inherit;
	padding: 1rem 0 0 1em;
}

/* Unterzeile der Wortmarke in Fraunces — der Serif-Gegensatz zur Grotesk in der
   ersten Zeile. Das Token bringt Familie, 400 und Zeilenhöhe mit; die 1em darin
   nimmt die Größe der h1, die *-Regel würde das span sonst auf 1rem stauchen.
   color: inherit aus demselben Grund, und hier nicht kosmetisch: die *-Regel
   färbt jedes Element #000, das #fff der Kopfzeile gilt nur der h1 selbst — und
   Schwarz auf Anthrazit ist unter mix-blend-mode: difference schlicht unsichtbar
   (die Zeile war es, bis das hier stand). */
#titlelink .brand-sub {
	font: var(--serif);
	color: inherit;
}

/* Bildmarke oben rechts, auf allen Seiten mit Kopfzeile. Sie steht bewusst
   NEBEN dem <header> und nicht darin: dessen mix-blend-mode: difference gilt
   für die ganze Gruppe (siehe unten), das Rot der Marke käme über jedem Bild
   anders heraus. Koordinaten und z-index sind die des früheren Theme-Knopfes,
   der genauso als fixiertes Geschwister in dieser Ecke saß — nur eine Stufe
   höher, damit sie auch über der Kopfzeile liegt, falls der Schriftzug einmal
   bis dorthin reicht. Lightbox (100000) und Zoom (9000) bleiben darüber. */
#logo {
	position: fixed;
	top: 2rem;
	right: 1rem;
	width: 2.75rem;
	height: auto;
	z-index: 2001;
	display: block;
}

/* #logo ist der Home-Link, das Bild darin füllt ihn. */
#logo img {
	display: block;
	width: 100%;
	height: auto;
}

@media only screen and (max-width: 569px) {
	#logo {
		width: 2.25rem;
	}
}

/* The blend has to stay on #header itself. position: sticky always creates a
   stacking context, so moving mix-blend-mode down to the children isolates
   them inside it — they lose the page as their backdrop and #fff text just
   renders white. */
header {
	mix-blend-mode: difference;
}

/* Title + tagline fade out once the intro text nears the top (toggled in JS). */
#header h1,
#header p {
	color: #fff;
	visibility: visible;
	transition: opacity 0.4s ease, visibility 0s;
}

/* visibility flips only after the fade has run (0.4s delay), so it doesn't cut
   the animation short. It's what actually guarantees the taglines are gone:
   a stale blended layer can keep painting a faded-out opacity, but a
   visibility change forces the layer to be re-rendered. Showing again is
   instant — the delay lives on the hidden state only. */
#header.hide-taglines h1,
#header.hide-taglines p {
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.4s ease, visibility 0s linear 0.4s;
}

/* When the title is faded out, don't leave an invisible clickable area over the
   content. */
#header.hide-taglines #titlelink {
	pointer-events: none;
}

/* Black footer, sticky at the bottom and revealed as the content scrolls up
   off it (mirrors the slideshow reveal at the top). Always black, full-bleed
   to the viewport edges past the body's 1em frame. */
footer {
	position: sticky;
	bottom: 0;
	z-index: 0;
	background: #000;
	margin-inline: -1em;
	margin-bottom: -1em;
	padding-block: 6rem 5rem;
	padding-inline: 2em;
}

/* Dunkel: Anthrazit wie der Rest, damit der Footer nahtlos anschließt — so wie
   er im früheren Dark Mode schwarz auf Schwarz anschloss. */
.dark footer {
	background: #000;
}

footer,
footer p,
footer a,
.dark footer,
.dark footer p,
.dark footer a {
	color: #fff;
}

/* Opaque layers that scroll up over the sticky slideshow and footer.
   z-index 2 sits above the slideshow (1)/footer (0) and below the header (2000). */
#intro-text,
#team,
#clients,
#gallery-section,
#next-album {
	position: relative;
	z-index: 2;
	background: #fff;
}

.dark #intro-text,
.dark #team,
.dark #clients,
.dark #gallery-section {
	background: var(--bg-dark);
}

.dark #gallery-section,
.dark #next-album  {
	background: #242424;
}

body.home header p {
	color: #000;
	font-weight: normal;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.dark body.home header p {
	color: #f0f0f0;
}

header,
header * {
	pointer-events: none;
	user-select: none;
	-webkit-user-select: none;
}

@media (hover: none) { 
	main {
		user-select: none;
		-webkit-user-select: none;
	}
}
	
footer p,
footer a {
	mix-blend-mode: normal;
}

footer span {
	display: block;
	/* margin-top: 3rem; */
}

footer span a {
	font-family: sans-serif;
	font-weight: 400;   /* sonst greift die 700 aus der *-Regel */
	font-size: 0.6rem;
}

body.txt p {
	font-family: sans-serif;
	font-weight: 400;   /* sonst greift die 700 aus der *-Regel */
	margin-bottom: 1em;
	hyphens: auto;
}

body.txt p a {
	mix-blend-mode: normal;
}

 .slideshow {
  position: relative;
  width: 100%;
  height: 70vh;
  overflow: hidden;
  z-index: -10;
	display: none;
  transform: scale(var(--slide-scale, 1));
  transform-origin: top center;
}

.slideshow.visible {
	display: block;
}

.slideshow .slide {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  animation-play-state: running;
}

/* Startseite: das Bild füllt die randabfallende Bühne aus und wird dabei
   beschnitten, statt mit Balken hineingerechnet zu werden. Bewusst nur hier —
   der Album-Hero (.single) zeigt sein Foto weiterhin vollständig.
   Achtung: damit ist die angezeigte Breite die Fensterbreite, nicht mehr die
   eingepasste Bildbreite. Die Slides brauchen deshalb den xl-Zuschnitt und
   sizes: 100vw (index.php), sonst wird das Bild hochskaliert und matschig. */
.slideshow:not(.single) .slide {
  object-fit: cover;
}

/* Album hero: a single, static image (no fade animation). */
.slideshow.single .slide {
  opacity: 1;
  animation: none;
}

main {
	cursor: none;
	position: sticky;
	top: var(--header-h, 8rem);
	z-index: 1;
	margin-inline: -1em;
	margin-top: 1em;
	background: #fff;
}

.dark main {
	background: var(--bg-dark);
}

/* Once the content has fully scrolled over the slideshow, hide it (keeping its
   layout box so the page doesn't jump) and pause the animation. */
main.is-covered  {
	visibility: hidden;
}

main.is-covered .slide {
	animation-play-state: paused !important;
}

/*
main:hover {
  cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><circle cx='16' cy='16' r='15' fill='black'/><rect x='13' y='11' width='2' height='10' fill='white'/><rect x='17' y='11' width='2' height='10' fill='white'/></svg>") 16 16, auto;
}

main.paused:hover {
  cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><circle cx='16' cy='16' r='15' fill='black'/><polygon points='13,11 13,21 21,16' fill='white'/></svg>") 16 16, auto;
}
*/   


#themebutton {
	font-size: 0;
	width: 1.2rem;
	height: 1.2rem;
	background: transparent;
	border: none;
	position: fixed;
	right: 1rem;
	top: 1rem;
	z-index: 2000;
	cursor: pointer;
	padding: 0;
	overflow: visible;
	display: grid;
	place-items: center;
}

#themebutton svg {
	display: block;
}

#themebutton #moon { width: 100%; height: 100%; }
#themebutton #sun  { width: 207%; height: 207%; }

/* Light mode shows the (black) moon; dark mode swaps in the (white) sun. */
#themebutton #sun  { display: none; }
.dark #themebutton #moon { display: none; }
.dark #themebutton #sun  { display: block; }


.dark {
  body {
	background-color: var(--bg-dark);
	color: #f0f0f0;
  }

  h1, p, p strong, a:not(.segment, .back-button) {
	color: #f0f0f0;
  }



	.segmented-control {
	    background: rgba(255, 255, 255, 0.5);
	}
	
}


/* Custom Cursor */
#custom-cursor {
  position: fixed;
  width: 32px;
  height: 32px;
  pointer-events: none;
  z-index: 1000000;
  transform: translate(-50%, -50%) scale(0);
  transition: transform 0.3s ease, opacity 0.3s ease;
  opacity: 0;
}

/* Inhalt über CSS-Hintergrund – Standard: Pause */
#custom-cursor::before {
  content: '';
  display: block;
  width: 100%;
  height: 100%;
  background-size: contain;
  background-repeat: no-repeat;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><circle cx='16' cy='16' r='15' fill='black'/><rect x='13' y='11' width='2' height='10' fill='white'/><rect x='17' y='11' width='2' height='10' fill='white'/></svg>");
}

/* Beim Hover aktivieren */
main:hover + #custom-cursor {
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
}

/* Klasse für "Play"-Symbol */
#custom-cursor.playing::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><circle cx='16' cy='16' r='15' fill='black'/><polygon points='13,11 13,21 21,16' fill='white'/></svg>");
}

/* + cursor over gallery thumbnails */
#custom-cursor.gallery {
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
}
#custom-cursor.gallery::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><circle cx='16' cy='16' r='15' fill='black'/><rect x='15' y='10' width='2' height='12' fill='white'/><rect x='10' y='15' width='12' height='2' fill='white'/></svg>");
}

/* Album name that sticks left-aligned next to the custom cursor (home hover).
   Text set by JS; shown while hovering a gallery thumbnail with a data-title. */
.cursor-label {
  position: absolute;
  left: 100%;
  top: 50%;
  transform: translateY(-50%);
  margin-left: 8px;
  width: 20ch;
  /*white-space: normal;
  overflow-wrap: break-word;*/
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 400;
  font-size: 1.275rem;
  line-height: 1.1;
  color: #fff;
  /*text-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);*/
  opacity: 0;
  transition: opacity 0.15s ease;
}
#custom-cursor.has-label .cursor-label {
  opacity: 1;
}

/* × cursor when zoom lightbox is open */
#custom-cursor.zoom-close {
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
}
#custom-cursor.zoom-close::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><circle cx='16' cy='16' r='15' fill='black'/><rect x='15' y='9' width='2' height='14' fill='white' transform='rotate(45 16 16)'/><rect x='15' y='9' width='2' height='14' fill='white' transform='rotate(-45 16 16)'/></svg>");
}

/* Hide default cursor on zoom overlay and zoomed image */
.medium-zoom-overlay,
.medium-zoom-image--opened {
  cursor: none !important;
}

/* Deaktiviert auf Touch-Geräten */
@media (hover: none) {
  main {
    cursor: default;
  }
  #custom-cursor {
    display: none;
  }
}






.segmented-wrapper {
  max-width: calc(100vw - 10px);
  overflow-x: auto;
  overflow-y: hidden;
  padding: 0 10px;
  -webkit-overflow-scrolling: touch;
  position: fixed;
  bottom: 10px;
  left: 50%;
  translate: -50%;
  scrollbar-width: none; /* Firefox */
  z-index: 1000;
}
.segmented-wrapper::-webkit-scrollbar {
  display: none; /* Chrome/Safari */
}

.segmented-control {
  display: inline-flex;
  position: relative;
  background: rgba(255,255,255,0.85);
  border-radius: 999px;
  padding: 4px;
  backdrop-filter: blur(15px) saturate(150%);
  -webkit-backdrop-filter: blur(15px) saturate(150%);
  white-space: nowrap;
  gap: 4px;
}

.segment {
  display: inline-block;
  text-decoration: none;
  color: #000;
  background: transparent;
  padding: 12px 24px;
  border-radius: 999px;
  transition: color 0.3s ease, background 0.3s ease;
  cursor: pointer;
}

.segment:hover {
  background: rgba(0,0,0,0.05);
}

.segment.active {
  color: #fff;
}

/* Album page back button — standalone floating pill, same position/shape as
   the genre nav but its own markup so no tab JS runs on it. */
.back-nav {
  position: fixed;
  bottom: 15px;
  left: 50%;
  translate: -50%;
  z-index: 1000;
}
.back-button {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 12px 24px;
  border-radius: 999px;
  background: #000;
  color: #fff;
  text-decoration: none;
  transition: opacity 0.3s ease;
}
.dark .back-button { background: #fff; color: #000; }

/* Bouncy grow on hover, shared by the floating buttons. */
.back-button,
#scrolltop,
#themebutton {
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.back-button:hover,
#scrolltop:hover {
  transform: scale(1.12);
}
#themebutton:hover {
  transform: scale(1.25);
}

/* Scroll-to-top button — same solid black pill as the back button, with the
   same arrow rotated 90° to point up. */
#scrolltop {
  position: fixed;
  bottom: 4.5rem;
  right: 1rem;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  border: none;
  background: #000;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  z-index: 1500;
}

body.album #scrolltop {
  bottom: 1rem;
}

#scrolltop.visible {
  opacity: 1;
  pointer-events: auto;
}
#scrolltop::before {
  content: "←";
  display: block;
  line-height: 1;
  transform: rotate(90deg);
}
.dark #scrolltop { background: #fff; color: #000; }

/* "Tidy up" toggle — floating black pill at bottom-left, mirroring #scrolltop.
   Only on the home page, and only revealed once the thumbnail gallery is in
   view (see scripts.js). Toggles the gallery between the free and tidy layouts. */
#tidybtn {
  position: fixed;
  bottom: 4.5rem;
  left: 1rem;
  height: 2.6rem;
  padding: 0 1.1rem;
  border-radius: 999px;
  border: none;
  background: #000;
  color: #fff;
  font: inherit;
  font-size: 0.85rem;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  display: none;
  align-items: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  z-index: 1500;
}
/* Toggle retired: the tidy masonry is the default and the loose scatter layout
   is opt-in via the URL (?loose). Keep the element but hide it everywhere. */
body.home #tidybtn {
  display: none;
}
/* Mobile uses the original tidy layout only — no free/tidy toggle. */
@media only screen and (max-width: 569.98px) {
  #tidybtn { display: none !important; }
}
#tidybtn.visible {
  opacity: 1;
  pointer-events: auto;
}
#tidybtn:hover {
  transform: scale(1.08);
}
.dark #tidybtn { background: #fff; color: #000; }

.segment:focus {
  outline: none;
}

.segment:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.slider {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;
  width: 0;
  border-radius: 999px;
  background: rgba(0,0,0,0.9);
  box-shadow: inset 0 0 15px rgba(0,0,0,0.05);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: all 0.3s ease;
  z-index: -1;
  pointer-events: none;
}




@media only screen and (max-width: 569px) {
  .slideshow {
    height: auto;
    aspect-ratio: 2 / 3;
    margin-inline: 1em;
    width: calc(100% - 2em);
  }

  /* … die Startseiten-Bühne aber nicht mehr: randabfallend heißt auch hier bis
     an beide Fensterkanten. Der Album-Hero behält seinen Rahmen. */
  .slideshow:not(.single) {
    margin-inline: 0;
    width: 100%;
  }
}

@media only screen and (min-width: 570px) {
	footer {
		padding-block-start: 8rem;
	}
}




/* Intro text */

#intro-text {
  margin-inline: -1em;
  padding: 4rem 2em 3rem;
}

#intro-text p,
#intro-text p a,
#intro-text p strong {
	font-family: 'Space Grotesk', sans-serif;
	font-weight: 400;
	font-size: clamp(1.35rem, 2vw, 7rem);
	line-height: 1.45;
	mix-blend-mode: normal;
	hyphens: auto;
}

#intro-text p a,
#intro-text p strong {
	font-family: 'Space Grotesk', sans-serif;
	font-weight: 700;
}

#intro-text p strong {
	padding-inline-end: 2em;
}



/* Team unter dem Intro-Text (Teil von "Wir"): Porträts im 3:4-Hochformat mit
   Name und Rolle darunter. Dieselben Spalten wie das Arbeiten-Raster darunter —
   drei ab 570px, eine auf dem Handy —, damit die Porträts so breit sind wie die
   Kacheln dort. Die 3:4-Fläche steht auch ohne Bild (Platzhalter, und solange
   das Lazy-Bild lädt, springt nichts). */
#team {
  margin-inline: -1em;
  padding: 0 2em 2rem;
  display: grid;
  grid-template-columns: 1fr;
  row-gap: 3rem;
}

@media only screen and (min-width: 570px) {
  #team {
    grid-template-columns: repeat(3, 1fr);
    column-gap: 2rem;
  }
}

.team-photo {
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.05);
}

.dark .team-photo {
  background: rgba(255, 255, 255, 0.05);
}

.team-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.team-member figcaption {
  margin-top: 1.25rem;
}

/* Beide Zeilen einzeln färben: die *-Regel setzt color auf jedes Element
   direkt, vom figcaption würde also nichts geerbt. */
.team-name,
.team-role {
  display: block;
  font-size: 1.15rem;
  line-height: 1.3;
  color: #000;
}

.team-role {
  font-weight: 400;
}

.dark .team-name,
.dark .team-role {
  color: #f0f0f0;
}


/* Kundenband unter dem Team: ein Lauftext mit den im CMS gepflegten Namen,
   randlos von Fensterkante zu Fensterkante (margin-inline: -1em hebt den
   1em-Rahmen des body auf). Der Track besteht aus zwei identischen Durchläufen
   und wandert um genau einen davon (-50%) — an dieser Stelle sieht das Bild
   wieder aus wie am Anfang, die Schleife ist deshalb nahtlos. Markup und Dauer
   kommen aus index.php.

   .marquee trägt overflow und Maske, nicht die Sektion: die Maske würde sonst
   auch deren Hintergrund an den Rändern durchsichtig machen, und dahinter
   klebt die Slideshow. */
#clients {
  margin-inline: -1em;
  margin-block: 7rem 0;
  padding-block: 7rem 7rem;
}

/* Anlauf über dem Band, in derselben Optik wie das "Das Büro — " im Intro:
   Fraunces kursiv in der Akzentfarbe (beides kommt über die Klassen im Markup)
   und dieselbe Schriftgröße wie der Intro-Absatz. Die Größe steht hier und
   nicht am span: dessen `font: var(--serif-italic)` bringt 1em mit, erbt sie
   also von diesem Absatz — genauso wie im Intro. Das padding-inline holt die
   Zeile aus dem randlosen Streifen zurück auf die Textkante von Intro und Team,
   während das Band selbst weiter bis an die Fensterkanten läuft — dort steht
   2em, hier muss dasselbe Maß rem heißen: die Sektionen haben Grundschrift,
   dieser Absatz trägt seine eigene, sehr große, und 2em davon wären das
   Doppelte. */

.clients-lead {
  padding-inline: 2rem;
}

.clients-lead, 
.gallery-lead {
  font-size: clamp(1.35rem, 2vw, 7rem);
  line-height: 1.25;
}

.marquee {
  overflow: hidden;
  /* Ein- und Auslauf weich ausblenden, damit die Namen nicht hart an der
     Fensterkante abgeschnitten wirken. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee-scroll var(--marquee-duration, 40s) linear infinite;
}

/* Beim Überfahren anhalten — bei dieser Größe liest man sonst nur Fragmente. */
.marquee:hover .marquee-track {
  animation-play-state: paused;
}

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.marquee-run {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: clamp(2.5rem, 9vw, 9rem);
  line-height: 1.1;
  white-space: nowrap;
  color: #000;
}

.home h2,
footer h2 {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: clamp(2.5rem, 5vw, 9rem);
  line-height: 1.1;
  /* white-space: nowrap; */
  color: #000;
}

.dark .marquee-run,
.home h2,
footer h2 {
  color: #ffffff;
  margin-block-end: 7rem;
}

/* Der Gedankenstrich als eigenes Element: so lässt sich die Luft um ihn herum
   hier einstellen, statt sie im Markup aus Leerzeichen zu bauen (die HTML
   ohnehin zu einem zusammenzieht). */
.marquee-sep {
  padding-inline: 0.4em;
  color: inherit;
  font: inherit;
}

/* Wer Animationen abbestellt hat, bekommt das Band still — und darf es dann
   von Hand schieben, sonst wäre die Hälfte der Namen unerreichbar. */
@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
  }
  .marquee {
    overflow-x: auto;
  }
  /* Das Duplikat trägt dann nichts bei außer doppelter Scrollbreite. */
  .marquee-run[aria-hidden="true"] {
    display: none;
  }
}



/* "Next album" section — sits below the album grid, before the floating
   back button. Quietly invites the visitor to the next album of the genre. */
#next-album {
  padding: 3rem 2em 8rem;
  margin-inline: -1em;
  display: grid;
}
.next-album-link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  color: inherit;
  margin-inline: auto;
	
}
.next-album-cover {
  display: block;
  width: clamp(180px, 30vw, 300px);
  aspect-ratio: 2 / 3;
  object-fit: cover;
  transition: scale 0.3s ease;
}
.next-album-label {
  /* Pull left so the text overlaps the right edge of the cover image. */
  margin-left: -1.5em;
  font-size: clamp(1.35rem, 3.5vw, 4rem);
  line-height: 1.1;
  transition: scale 0.3s ease;
  mix-blend-mode: difference;
  color: #fff;
}
.next-album-link:hover .next-album-cover,
.next-album-link:hover .next-album-label {
  scale: 1.08;
}



/* ── Projektseite (album.php) ────────────────────────────────────────────────
   Kopf in #intro-text — dieselbe Sektion und Schriftgröße wie der Intro-Text der
   Startseite, damit scripts.js die Kopfzeile genauso ausblendet —, darunter die
   Blöcke in #gallery-section (an dessen Unterkante hängt das Einblenden des
   Footers). */

/* Titel groß; die Kund:in darunter nimmt die Optik von "Das Büro — " auf. */
#intro-text .project-title {
  font-weight: 700;
  font-size: clamp(2.5rem, 8vw, 10rem);
  line-height: 1;
  margin: 0 0 0.2em;
  color: #000;
}

.dark #intro-text .project-title {
  color: #f0f0f0;
}

#intro-text .project-client {
  margin: 0;
}

#intro-text .project-intro {
  margin: 1.5rem 0 0;
}

/* Titelbild im Kopf, zwischen Titel/Kund:in und Introtext (album.php). */
#intro-text .project-cover {
  margin: 2.5rem 0 0;
}

/* Höchstens 80vh hoch, zentriert. Die Breite folgt aus der Höhe über das
   Seitenverhältnis (--ar aus agp_project_block()), so bleibt der Link — und mit
   ihm die Lightbox-Fläche und der Cursor — genau so breit wie das Bild. Fehlen
   die Maße, ist max-width ungültig (= keine Grenze) und object-fit fängt es ab. */
#intro-text .project-cover .block-image {
  max-width: min(100%, calc(80vh * var(--ar)));
  margin-inline: auto;
}

#intro-text .project-cover .block-image img {
  max-height: 80vh;
  object-fit: contain;
}

#intro-text .project-cover + .project-intro {
  margin-top: 2.5rem;
}

/* Leistungen als Pillen. Jede Pille färbt sich selbst: die *-Regel setzt color
   an jedem Element, von der Liste würde nichts geerbt. */
.project-services {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.project-services li {
  font-weight: 400;
  font-size: clamp(0.9rem, 1.1vw, 1.25rem);
  line-height: 1;
  padding: 0.55em 1.1em;
  border: 1px solid rgba(0, 0, 0, 0.35);
  border-radius: 999px;
  color: #000;
}

.dark .project-services li {
  color: #f0f0f0;
  border-color: rgba(240, 240, 240, 0.4);
}

/* "Entstanden in Zusammenarbeit mit …" unter den Leistungen: kleiner, gedämpft. */
#intro-text .project-coop {
  margin: 1.5rem 0 0;
  font-size: clamp(0.85rem, 1vw, 1.1rem);
  line-height: 1.4;
  color: rgba(0, 0, 0, 0.55);
}

.dark #intro-text .project-coop {
  color: rgba(240, 240, 240, 0.55);
}

/* Blöcke: ein Raster mit zwei Spalten ab 570px, eine darunter. 100 %-Blöcke und
   Abstände laufen über beide Spalten, zwei 50 %-Blöcke stehen nebeneinander, ein
   einzelner lässt die zweite Hälfte frei. min-width: 0, weil #gallery-section
   ein Grid-Container ist und das Raster sonst an seinem breitesten Inhalt
   aufginge. */
.blocks {
  --block-gap: 2rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--block-gap);
  align-items: start;
  min-width: 0;
}

@media only screen and (min-width: 570px) {
  .blocks {
    --block-gap: 2rem;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .block-w100,
  .block-spacer {
    grid-column: 1 / -1;
  }
}

.block {
  margin: 0;
  min-width: 0;
}

/* Der Abstand-Block fügt 100px ein — zusätzlich zum normalen Blockabstand. Er
   selbst erzeugt aber zwei Lücken (davor und danach), deshalb ist er um eine
   davon kürzer. */
.block-spacer {
  height: max(0px, calc(100px - var(--block-gap)));
}

.block-image a {
  display: block;
  cursor: none;
}

.block-image img,
.block-image video {
  display: block;
  width: 100%;
  height: auto;
}

/* Text aus dem Quill-Editor des CMS (h2, h3, fett, Links, Listen). Die *-Regel
   gibt jedem Element 1rem, Grotesk 700 und Schwarz; hier erbt alles vom Block. */
.block-text {
  font-weight: 400;
  font-size: clamp(1.1rem, 1.7vw, 2.1rem);
  line-height: 1.35;
  color: #000;
}

.dark .block-text {
  color: #f0f0f0;
}

.block-text * {
  font-family: inherit;
  font-weight: inherit;
  font-size: inherit;
  line-height: inherit;
  color: inherit;
}

/* Über die volle Breite würden die Zeilen unlesbar lang. */
.block-text.block-w100 > * {
  max-width: 40em;
}

.block-text p,
.block-text ul,
.block-text ol {
  margin: 0 0 0.8em;
}

.block-text h2 {
  font-weight: 700;
  font-size: 1.6em;
  line-height: 1.1;
  margin: 2em 0 0.5em;
  padding-block-start: 2em;
}

.block-text h3 {
  font-weight: 700;
  margin: 1.2em 0 0.4em;
}

.block-text > :first-child { margin-top: 0; }
.block-text > :last-child  { margin-bottom: 0; }

.block-text strong,
.block-text b {
  font-weight: 700;
}

.block-text em,
.block-text i {
  font-style: italic;
}

.block-text a {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.block-text ul,
.block-text ol {
  padding-left: 1.2em;
}

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

/* Checklisten schreibt Quill als <li data-list="checked|unchecked">. */
.block-text li[data-list="checked"],
.block-text li[data-list="unchecked"] {
  list-style: none;
}

.block-text li[data-list="checked"]::before,
.block-text li[data-list="unchecked"]::before {
  display: inline-block;
  width: 1.2em;
  margin-left: -1.2em;
}

.block-text li[data-list="checked"]::before   { content: "☑"; }
.block-text li[data-list="unchecked"]::before { content: "☐"; }

.block-text .ql-indent-1 { margin-left: 1.5em; }
.block-text .ql-indent-2 { margin-left: 3em; }
.block-text .ql-indent-3 { margin-left: 4.5em; }
.block-text .ql-indent-4 { margin-left: 6em; }
.block-text .ql-indent-5 { margin-left: 7.5em; }
.block-text .ql-indent-6 { margin-left: 9em; }
.block-text .ql-indent-7 { margin-left: 10.5em; }
.block-text .ql-indent-8 { margin-left: 12em; }




/* Thumbnail gallery */

/* medium-zoom appends its overlay + zoomed clone to <body> with no z-index,
   so they must be forced above the positioned content layers (z-index 2)
   and the sticky header (z-index 2000), or the zoom hides behind them. */
.medium-zoom-overlay {
  z-index: 9000 !important;
}
.medium-zoom-image--opened {
  z-index: 9001 !important;
}

#gallery-section {
	max-width: 1920px;
	padding-block: 5rem;
	padding-inline: 2em;
	margin-inline: -1em;
  /* Grid-Container, damit der Whitespace zwischen den Genre-Galerien nicht
     zählt: die nicht aktiven .gallery-Divs stehen auf display:none, ihre
     Zeilenumbrüche im Quelltext blieben aber als Zeilenboxen stehen — rund
     25px pro Genre vor dem aktiven, also umso mehr Leerraum, je weiter rechts
     der Tab sitzt. In einem Grid-Container werden reine Whitespace-Knoten
     verworfen. */
	display: grid;
}

.gallery {
  display: none;
}

.gallery.visible {
  display: block;
}

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 4px;
  column-gap: 1.5rem;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.grid.is-ready {
  opacity: 1;
}

.grid-item {
  display: block;
  padding-bottom: 1.5rem;
  cursor: none;
  /* leave room for the sticky header when jumping back to a thumb via #anchor */
  scroll-margin-top: calc(var(--header-h, 7rem) + 2rem);
}

.grid-item .album-link,
.grid-item .pswp-item {
  display: block;
  cursor: none;
  /* The link wraps the caption too, and an underline propagated from here can't
     be switched off further down — it has to go at the source. */
  text-decoration: none;
}

/* Hero image on album pages is a PhotoSwipe item — make the whole hero clickable. */
.hero-link {
  position: absolute;
  inset: 0;
  display: block;
  cursor: none;
}

/* PhotoSwipe theme follows the site theme. Light default: white background,
   black icons with a white halo so they stay visible over dark photos. The
   .dark class lives on <html>, above the body-appended .pswp, so .dark .pswp
   flips it to a dark surround with white icons in dark mode. */
.pswp {
  --pswp-bg: #fff;
  --pswp-icon-color: #000;
  --pswp-icon-color-secondary: #fff;
  --pswp-icon-stroke-color: #fff;
  --pswp-icon-stroke-width: 2px;
}
.dark .pswp {
  --pswp-bg: var(--bg-dark);
  --pswp-icon-color: #fff;
  --pswp-icon-color-secondary: #000;
  --pswp-icon-stroke-color: #000;
}

/* No zoom in the lightbox: hide the magnifier button (top right). Click/tap
   zoom is also switched off via the lightbox options in album.php. */
.pswp__button--zoom { display: none !important; }

.grid-item img {
  width: 100%;
  height: auto;
  display: block;
  cursor: none;
  transform-origin: center;
  transition: transform 0.3s ease;
}

/* Hover scale lives on the img (not the wrapper) so medium-zoom,
   which controls the img's transform on open, isn't fighting an
   ancestor transform that would break its centering.
   Pointer-gated: a tap leaves :hover stuck on touch devices, where the grown
   image would then sit on top of the caption underneath it. */
@media (hover: hover) {
  .grid-item img:hover {
    transform: scale(1.08);
    position: relative;
    z-index: 2;
  }
}

/* CSS-driven + cursor — :has() is supported in all modern browsers.
   This fires directly on CSS hover state so JS timing is irrelevant.
   .hero-link is the album page's hero: it opens PhotoSwipe just like a thumb
   does, so it gets the + too — not the play/pause of a real slideshow. It sits
   inside <main>, so without this it would inherit the default pause icon, and
   the .playing class that scripts.js adds on any <main> mousedown would flip it
   to play on click. Both are outranked here (the :has() takes .grid-item:hover
   /.hero-link:hover as its specificity, beating #custom-cursor.playing). */
@media (hover: hover) {
  body:has(.grid-item:hover) #custom-cursor,
  body:has(.hero-link:hover) #custom-cursor,
  body:has(.block-image a:hover) #custom-cursor {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
  }
  body:has(.grid-item:hover) #custom-cursor::before,
  body:has(.hero-link:hover) #custom-cursor::before,
  body:has(.block-image a:hover) #custom-cursor::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><circle cx='16' cy='16' r='15' fill='black'/><rect x='15' y='10' width='2' height='12' fill='white'/><rect x='10' y='15' width='12' height='2' fill='white'/></svg>");
  }
}

/* ── Platzhalter und Einblenden ──────────────────────────────────────────────
   Solange ein Bild lädt, steht an seiner Stelle eine dezente Fläche mit einem
   langsam durchlaufenden Schimmer — in der Größe des Bildes, die width/height am
   <img> schon vorher festlegen. Ist es da, blendet es weich ein: aus leichter
   Unschärfe, eine Spur zu groß. Kacheln der Startseite: .img-frame um das Bild,
   "geladen" meldet LazyLoad (.loaded). Projektblöcke: der Link um das Bild,
   "lädt noch" setzt scripts.js (.ph am Link, .is-loading am Bild) — ohne
   JavaScript bleibt es beim normalen Bildaufbau.
   Die Fläche ist durchscheinendes Weiß statt einer festen Farbe, damit sie auf
   jeder Projektfarbe (--bg-dark) funktioniert. Die Einblend-Animation füllt
   bewusst nicht nach (kein "both"/"forwards"): ihr Endzustand würde sonst das
   transform des Hover-Zooms dauerhaft überstimmen. */
.img-frame {
  display: block;
}

.img-frame:has(> img.lazy:not(.loaded)),
.block-image .ph {
  background-color: rgba(255, 255, 255, 0.05);
  background-image: linear-gradient(100deg, transparent 35%, rgba(255, 255, 255, 0.06) 50%, transparent 65%);
  background-size: 250% 100%;
  background-repeat: no-repeat;
  animation: img-shimmer 1.8s ease-in-out infinite;
}

html:not(.dark) .img-frame:has(> img.lazy:not(.loaded)),
html:not(.dark) .block-image .ph {
  background-color: rgba(0, 0, 0, 0.05);
  background-image: linear-gradient(100deg, transparent 35%, rgba(0, 0, 0, 0.05) 50%, transparent 65%);
}

@keyframes img-shimmer {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}

.grid-item img.lazy:not(.loaded),
.block-image img.is-loading {
  opacity: 0;
}

.grid-item img.lazy.loaded,
.block-image img.is-loaded {
  animation: img-in 0.8s cubic-bezier(0.2, 0.7, 0.2, 1);
}

@keyframes img-in {
  from { opacity: 0; transform: scale(1.03); filter: blur(10px); }
  to   { opacity: 1; transform: none; filter: none; }
}

@media (prefers-reduced-motion: reduce) {
  .img-frame:has(> img.lazy:not(.loaded)),
  .block-image .ph {
    animation: none;
    background-image: none;
  }
  .grid-item img.lazy.loaded,
  .block-image img.is-loaded {
    animation: img-fade 0.4s ease-out;
  }
}

@keyframes img-fade {
  from { opacity: 0; }
}

/* While medium-zoom is measuring/animating, neutralize the hover scale so the
   thumbnail is measured and restored at its true 1:1 size (kills the bounce). */
.grid-item img.zooming {
  transform: none !important;
  transition: none !important;
}

@media only screen and (min-width: 570px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
    column-gap: 2rem;
  }

  .grid-item {
    padding-bottom: 2rem;
  }
}

/* "Free" gallery layout (opt-in via ?loose on the home page): images scattered
   in loose bands of at most three — varied sizes, uneven positions and generous
   whitespace, with no visible grid. JS absolutely-positions each item
   (left/top/width) so nothing overlaps, and sets the container height. Whenever
   .free is absent (the default, album pages, or mobile) the masonry grid above
   applies instead. */
.grid.free {
  display: block;
  position: relative;
}

.grid.free .grid-item {
  position: absolute;
  top: 0;
  left: 0;
  padding-bottom: 0;
}

/* Album page: doubled whitespace between images (always tidy masonry).
   Horizontal gap = column-gap; vertical gap = grid-item padding-bottom, which
   setSpan() reads via getComputedStyle so the row heights follow automatically. */
@media only screen and (max-width: 569px) {
  body.album .grid { column-gap: 1rem; }
  body.album .grid-item { padding-bottom: 1rem; }
}

/* Kund:in + Projekttitel unter dem Cover (Startseite), auf jeder Breite. Am
   Cursor steht der Name nicht mehr, dort bleibt nur das +. Beide Zeilen tragen
   ihre Farbe selbst — die *-Regel färbt jedes Element, von der Unterschrift
   würde nichts geerbt. Die Höhe rechnet scripts.js (captionHeight()) in die
   Kachel ein.
   Sie liegt über dem Bild und trägt den Seitengrund: das Cover wächst beim
   Hover um 8 % und schöbe seine Unterkante sonst über den Text. Der Abstand ist
   deshalb padding, nicht margin — so deckt er die Fuge mit ab. */
.grid-caption {
  position: relative;
  z-index: 1;
  display: block;
  padding-top: 0.75rem;
  font-size: 1.15rem;
  line-height: 1.2;
  background: #fff;
}

/* = Grund von .dark #gallery-section — ändert sich der, muss das hier mit. */
.dark .grid-caption {
  background: #242424;
}

.grid-caption-client,
.grid-caption-title {
  display: block;
}

/* Die Kund:in: Fraunces kursiv in --accent (Klassen im Markup), Größe der
   Unterschrift über das 1em im Token. */
.grid-caption-title {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 400;
  font-size: inherit;
  line-height: inherit;
  color: #000;
}

.dark .grid-caption-title {
  color: #f0f0f0;
}

/* Home overview on phones: one album per row, its name underneath, and room to
   breathe on both sides of that name. Two columns left the covers too small to
   read and the titles nowhere to go.
   Block flow rather than a one-column grid: a single column needs no masonry,
   and in block layout the inline grid-row-end measureSpan() writes is inert. */
@media only screen and (max-width: 569px) {
  body.home .grid {
    display: block;
  }

  /* Eigener Blockkontext, sonst tritt ein margin-top im Inneren oben aus der
     Kachel aus: im Blockfluss kollabiert er durch Link und Kachel bis ans Raster
     und schiebt die ganze Spalte nach unten. So geschehen mit dem 50px-Versatz,
     den noch nicht geladene Bilder früher trugen; im Grid-Layout oberhalb 570px
     kann das nicht passieren. */
  body.home .grid-item {
    display: flow-root;
    padding-bottom: 5rem;
  }

  body.home .grid-item:last-child {
    padding-bottom: 0;
  }

  body.home .grid-caption {
    padding-top: 1.25rem;
  }
}

@media only screen and (min-width: 570px) {
  body.album .grid { column-gap: 4rem; }
  body.album .grid-item { padding-bottom: 4rem; }
}




/* Contact form */

.footer-body {
  display: flex;
  gap: 4em;
  align-items: flex-start;
  margin-bottom: 4rem;
}

.footer-body section {
  flex-shrink: 0;
}

.footer-cta {
  flex-shrink: 0;
}

.footer-cta p {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: clamp(1.5rem, 4vw, 5rem);
  line-height: 1.1;
  color: #fff;
}

#contact-wrap {
  flex: 1;
}

#contact-form input[type="text"],
#contact-form input[type="email"],
#contact-form textarea {
  display: block;
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: 1px solid rgba(255,255,255,0.25);
  color: #fff;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 400;
  font-size: 1rem;
  padding: 0.5em 0;
  outline: none;
  -webkit-text-fill-color: #fff;
}

#contact-form input[type="text"]:focus,
#contact-form input[type="email"]:focus,
#contact-form textarea:focus {
  border-bottom-color: #fff;
}

#contact-form ::placeholder {
  color: rgba(255,255,255,0.35);
  opacity: 1;
}

/* Override browser autofill background */
#contact-form input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 100px #000 inset;
  -webkit-text-fill-color: #fff;
}
.dark #contact-form input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 100px var(--bg-dark) inset;
}

.cf-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1em;
}

#contact-form textarea {
  resize: vertical;
  min-height: 80px;
  margin-top: 1.5em;
}

.cf-legal {
  display: flex;
  align-items: flex-start;
  gap: 0.6em;
  margin-top: 1.5em;
  cursor: pointer;
}

.cf-legal input[type="checkbox"] {
  margin-top: 0.15em;
  flex-shrink: 0;
  accent-color: #fff;
}

.cf-legal span,
.cf-legal a {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 400;
  font-size: 0.75rem;
  color: rgba(255,255,255,0.5);
}

#contact-submit {
  display: inline-block;
  margin-top: 1.5em;
  background: #fff;
  color: #000;
  border: none;
  padding: 0.55em 1.8em;
  border-radius: 999px;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 700;
  font-size: 1rem;
  cursor: pointer;
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

#contact-submit:hover {
  transform: scale(1.08);
}

#contact-submit:disabled {
  opacity: 0.5;
  cursor: default;
  transform: none;
}

#contact-success {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 400;
}

/* Fehlermeldung des Kontaktformulars (von scripts.js eingehängt, wenn
   send.php ein echtes Scheitern zurückmeldet). */
.cf-error {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 400;
  margin-top: 0.75em;
  color: #c0392b;
}

footer {
  visibility: hidden;
}

footer.visible {
  visibility: visible;
}

@media only screen and (max-width: 569px) {
  .grid {
    column-gap: 0.5rem;
  }

  .grid-item {
    padding-bottom: 0.5rem;
  }

  .footer-body {
    flex-direction: column;
    gap: 2.5em;
  }

  .cf-row {
    grid-template-columns: 1fr;
  }
}
