/* 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 0;
}

/* 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;
}

@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: 1em;
}

/* 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: var(--bg-dark);
}

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,
.dark #next-album {
	background: var(--bg-dark);
}

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, 3vw, 7rem);
	line-height: 1.25;
	mix-blend-mode: normal;
}

#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;
  padding-block: 7rem 4rem;
}

/* 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;
  margin-bottom: 1.5rem;
  font-size: clamp(1.35rem, 3vw, 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;
}

.dark .marquee-run {
  color: #f0f0f0;
}

/* 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;
}




/* 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 {
  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, opacity 0.6s ease, filter 0.6s ease, margin 0.6s 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 {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
  }
  body:has(.grid-item:hover) #custom-cursor::before,
  body:has(.hero-link: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>");
  }
}

.grid-item img.lazy:not(.loaded) {
  filter: blur(20px);
  opacity: 0;
  margin-top: 50px;
}

.grid-item img.lazy.loaded {
  opacity: 1;
  margin-top: 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; }
}

/* Album name under the cover (home overview). Hidden by default: on desktop the
   name rides along with the custom cursor on hover, so printing it under every
   thumbnail as well would only repeat it. */
.grid-caption {
  display: none;
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 400;
  font-size: 1.15rem;
  line-height: 1.2;
  color: #000;
}

.dark .grid-caption {
  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 on purpose — measureSpan() reserves
   image height + padding-bottom only, so a masonry row would cut the caption
   off. In block layout the inline grid-row-end it writes is simply inert. */
@media only screen and (max-width: 569px) {
  body.home .grid {
    display: block;
  }

  /* Eigener Blockkontext, sonst tritt der margin-top des noch nicht geladenen
     Bildes (.lazy:not(.loaded), 50px) oben aus der Kachel aus: im Blockfluss
     kollabiert er durch Link und Kachel bis ans Raster und schiebt die ganze
     Spalte 50px nach unten — bis das erste Bild geladen ist, also genau beim
     ersten Blick. Im Grid-Layout oberhalb 570px kann er das nicht. */
  body.home .grid-item {
    display: flow-root;
    padding-bottom: 5rem;
  }

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

  body.home .grid-caption {
    display: block;
    margin-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;
  }
}
