/* Jost: free Futura-like font for visitors without Futura installed (Windows,
   Android). Served from this site, not Google, so no visitor data goes to
   third parties. Licence: src/fonts/Jost-OFL.txt */
@font-face {
  font-family: "Jost";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/fonts/jost-latin-300-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Jost";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/jost-latin-400-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Jost";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/jost-latin-500-normal.woff2") format("woff2");
}

:root {
  --black: #0d0d0d;
  --white: #fafafa;
  --grey: #707070; /* 4.7:1 on the page background, enough for small text */
  --line: #d9d9d9;
  --font: "Futura", "Futura PT", "Jost", "Century Gothic", sans-serif;
  --gutter: clamp(1rem, 4vw, 3rem);
  --section: clamp(4rem, 10vw, 8rem);
  --header-h: 5.25rem;
}

@media (min-width: 700px) {
  :root { --header-h: 6rem; }
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* scroll-padding keeps anchor targets from ending up under the fixed header */
html { scroll-behavior: smooth; scroll-padding-top: var(--header-h); }

body {
  font-family: var(--font);
  font-weight: 400;
  background: var(--white);
  color: var(--black);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

/* Placeholder until real photos are added: replace .ph elements with <img> */
.ph {
  aspect-ratio: var(--ar, 3 / 4);
  background: linear-gradient(160deg, #3a3a3a 0%, #121212 60%, #000 100%);
  width: 100%;
}

/* Header */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 10;
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: var(--header-h);
  padding: 0 var(--gutter);
  mix-blend-mode: difference;
  color: var(--white);
}

/* White bar under the header, faded in after the hero. The header's blend
   turns logo and links black over it by itself, so only opacity animates,
   which stays smooth on phones. */
.header-bg {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 9;
  height: var(--header-h);
  background: var(--white);
  opacity: 0;
  transition: opacity 0.6s ease;
  will-change: opacity;
  pointer-events: none;
}

.past-hero .header-bg { opacity: 1; }

.logo { display: block; line-height: 0; position: relative; z-index: 2; }

/* Logo files are black; invert to white so the header's difference blend
   shows them black on light sections and white on dark ones */
.logo img {
  height: 2.75rem;
  width: auto;
  filter: invert(1);
}

@media (min-width: 700px) {
  .logo img { height: 3.5rem; }
}

.nav { display: flex; gap: clamp(1rem, 3vw, 2.5rem); }

/* Background photo for the phone menu, only shown there */
.nav-bg { display: none; }

.nav a {
  font-size: 0.75rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
}

.nav a:hover { opacity: 0.6; }

/* Burger button, only shown on small screens */
.menu-toggle {
  display: none;
  position: relative;
  z-index: 2;
  width: 2rem;
  height: 2rem;
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
}

.menu-toggle span {
  position: absolute;
  left: 0.25rem;
  right: 0.25rem;
  height: 1px;
  background: currentColor;
  transition: transform 0.3s;
}

.menu-toggle span:first-child { transform: translateY(-4px); }
.menu-toggle span:last-child { transform: translateY(4px); }

.menu-open .menu-toggle span:first-child { transform: rotate(45deg); }
.menu-open .menu-toggle span:last-child { transform: rotate(-45deg); }

/* Hero */
.hero {
  position: relative;
  height: 100vh;
  min-height: 32rem;
  overflow: hidden;
  background: var(--black);
}

.hero-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* keep the face in frame when the screen crops the photo */
  object-position: 50% 30%;
}

/* Darkens the lower left so the headline stays readable */
.hero-shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0) 45%);
}

.hero-text {
  position: absolute;
  left: var(--gutter);
  bottom: clamp(3rem, 10vh, 6rem);
  color: var(--white);
  /* Hides the text where it slides under the menu row, so only the photo
     shows behind the logo. --cut is set by script while scrolling. */
  --cut: -2rem;
  -webkit-mask-image: linear-gradient(to bottom, transparent var(--cut), #000 calc(var(--cut) + 1.5rem));
  mask-image: linear-gradient(to bottom, transparent var(--cut), #000 calc(var(--cut) + 1.5rem));
}

.eyebrow {
  display: block;
  font-size: 0.75rem;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  margin-bottom: 1.25rem;
  opacity: 0.8;
}

/* Inside the heading (home page) it keeps its own small type */
h1 .eyebrow { font-weight: 400; line-height: 1.5; }

h1 {
  font-weight: 400;
  font-size: clamp(2.2rem, 6vw, 4.5rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin-bottom: 2.5rem;
}

h1 .line { display: block; }
h1 .word { display: inline-block; }

/* Slogan intro, played once on load: "Licht", "Schatten", "und dazwischen",
   then "du." on its own, each word growing in; then everything stays still.
   The line above and the button are shown right away. */
@keyframes grow-in {
  from { opacity: 0; transform: scale(0.9); }
  to { opacity: 1; transform: none; }
}

/* Each word sets its own start time with --delay in the HTML */
.hero-text .word {
  animation: grow-in 1.4s cubic-bezier(0.22, 1, 0.36, 1) var(--delay, 0s) both;
  transform-origin: left center;
}

/* "du." arrives last and a little slower */
.hero-text .word-du { animation-duration: 1.5s; }

/* Already seen during this visit (set in the page head) */
.slogan-seen .hero-text .word { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .hero-text .word { animation: none; }
}

.button {
  display: inline-block;
  padding: 0.9rem 2.2rem;
  border: 1px solid currentColor;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.3s, color 0.3s;
}

.hero .button:hover { background: var(--white); color: var(--black); }

/* Weihnachtsshooting button fills white once the slogan has finished (class set by script) */
.button-xmas { transition: background 1.2s ease, color 1.2s ease; }
.button-xmas.is-settled { transition-duration: 0.3s; }

.button-xmas.is-highlighted { background: var(--white); color: var(--black); }

/* Filled already, so hover does the opposite of the other buttons: back to outline */
.button-xmas.is-highlighted:hover { background: transparent; color: var(--white); }

@media (prefers-reduced-motion: reduce) {
  .button-xmas { transition: none; }
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

/* Sections */
section:not(.hero) { padding: var(--section) var(--gutter); }

.section-title {
  font-weight: 400;
  font-size: 0.8rem;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  margin-bottom: 3rem;
}

/* Statement */
.statement p {
  max-width: 44rem;
  margin: 0 auto;
  text-align: center;
  font-size: clamp(1.3rem, 2.6vw, 1.9rem);
  font-weight: 300;
  line-height: 1.5;
}

/* The name below the statement, set like the name under the quote */
.statement .statement-signature {
  margin-top: 1.5rem;
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--grey);
}

/* Gallery */
.work-title {
  font-weight: 300;
  font-size: clamp(1rem, 2vw, 1.4rem);
  letter-spacing: 0.25em;
  line-height: 1.3;
}

.gallery {
  --row: 14rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

/* Justified rows in list order: each image grows in proportion to its width
   to height ratio, so all images in a row end up the same height */
.gallery figure {
  flex: var(--ratio, 0.75) 1 calc(var(--ratio, 0.75) * var(--row));
  margin: 0;
  overflow: hidden;
  transition: opacity 0.6s;
}

/* Keeps the images of a short last row from stretching across the whole width */
.gallery::after {
  content: "";
  flex: 1000 1 0;
}

/* Fade in when scrolled into view (the class is set by main.js) */
.gallery.reveal picture {
  display: block;
  opacity: 0;
  transition: opacity 1.2s ease-out;
}

.gallery.reveal .is-visible picture { opacity: 1; }

.gallery img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 0.8s ease-out;
}

/* Hover: the image grows slowly inside its frame, the others step back */
@media (hover: hover) {
  .gallery figure:hover img { transform: scale(1.03); }
  .gallery:has(figure:hover) figure:not(:hover) { opacity: 0.55; }
}

/* Keyboard focus: a clear outline, and the same highlight as on hover */
.gallery figure:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: 4px;
}

.gallery figure:focus-visible img { transform: scale(1.03); }
.gallery:has(figure:focus-visible) figure:not(:focus-visible) { opacity: 0.55; }

/* The focused image always stays at full strength, even when the mouse rests
   on another image or the row is still fading in after scrolling */
.gallery:has(figure:focus-visible) figure:focus-visible,
.gallery.reveal figure:focus-visible picture { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .gallery img { transition: none; }
  .gallery figure:hover img { transform: none; }
  .gallery.reveal picture { opacity: 1; transition: none; }
}

/* Call to action below the gallery: one calm line and the usual button,
   black on white; fades in like the images (class set by main.js) */
.work-cta {
  margin-top: clamp(3.5rem, 8vw, 6rem);
  text-align: center;
}

.work-cta p {
  max-width: 44rem;
  margin: 0 auto 2rem;
  text-wrap: balance; /* even lines, no single word left over */
  font-size: clamp(1.3rem, 2.6vw, 1.9rem);
  font-weight: 300;
  line-height: 1.5;
}

.work-cta .button:hover { background: var(--black); color: var(--white); }

.work-cta.reveal {
  opacity: 0;
  transition: opacity 1.2s ease-out;
}

.work-cta.reveal.is-visible { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .work-cta.reveal { opacity: 1; transition: none; }
}

/* "Zum Ende / Zum Anfang der Galerie": floats at the bottom while the
   gallery is on screen (classes set by main.js) */
.gallery-skip {
  position: fixed;
  left: 50%;
  bottom: calc(1.25rem + env(safe-area-inset-bottom));
  z-index: 8; /* below the header, so the phone menu covers it */
  padding: 0.7rem 1.4rem;
  border: 1px solid var(--black);
  background: rgb(250 250 250 / 0.85);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: var(--black);
  font: inherit;
  font-size: 0.7rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 0.5rem);
  transition: opacity 0.6s, transform 0.6s, visibility 0s 0.6s, background 0.3s, color 0.3s;
}

.gallery-skip.is-shown {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition: opacity 0.6s, transform 0.6s, visibility 0s, background 0.3s, color 0.3s;
}

.gallery-skip:hover { background: var(--black); color: var(--white); }

.gallery-skip-label { transition: opacity 0.2s; }
.gallery-skip-label.is-switching { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  .gallery-skip, .gallery-skip.is-shown { transition: none; transform: translate(-50%, 0); }
}

/* Lightbox: large view of a gallery image */
.gallery figure:not(.ph) { cursor: zoom-in; }

html:has(.lightbox[open]) { overflow: hidden; }

.lightbox {
  /* Fill exactly the visible area: 100vw would include the parts of an iPhone
     screen in landscape that sit beside the notch, outside the page */
  inset: 0;
  width: 100%;
  height: 100%;
  container-type: size;
  overflow: hidden; /* nothing in the large view scrolls, not even by a pixel */
  overscroll-behavior: contain;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: #1c1c1c;
  color: var(--white);
}

.lightbox[open] { animation: lightbox-in 0.4s ease-out; }
.lightbox::backdrop { background: #1c1c1c; }

@keyframes lightbox-in { from { opacity: 0; } }

.lightbox-image {
  display: grid;
  place-items: center;
  height: 100%;
  cursor: zoom-out;
}

/* End card after the last image: a contact sheet in the frame. The film
   strips lie a little crooked on the paper, as laid by hand; the exposed
   paper around them prints black, the rebate dark grey, the sprocket holes
   deep black, the edge numbers white.
   The empty frame stays paper white and is circled in grease pencil.
   Sizes follow the frame (cqw). */
.lightbox-end {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.6cqw;
  padding: 3cqw 6cqw;
  background: #efede7; /* photographic paper */
  color: var(--black);
  text-align: center;
  container-type: size;
}

/* The exposed part of the photo paper prints black around and between the
   strips; the white paper margin around it stayed covered */
.contact-sheet {
  display: flex;
  flex-direction: column;
  gap: 1.2cqw;
  padding: 1.8cqw 2.2cqw;
  background: #030303;
  /* A first estimate that keeps text and button below in view even before
     main.js has measured; main.js then fits it exactly */
  width: min(100%, 106cqh);
}

/* One strip of 35mm film per row. The outer element is measured, so --f
   (one frame plus its gap) can size everything in real film proportions:
   eight sprocket holes per frame, taller than wide, right above and below
   the image; the edge numbers outside the holes */
.film-strip { container-type: inline-size; }

.strip-film {
  --f: calc(100cqw / var(--cols, 5));
  --hole: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='42' height='24'%3E%3Crect x='12' width='18' height='24' rx='3' fill='%23080808'/%3E%3C/svg%3E");
  display: grid;
  /* minmax(0, …): a column never grows past its share, whatever is inside */
  grid-template-columns: repeat(var(--cols, 5), minmax(0, 1fr));
  align-items: start;
  column-gap: calc(var(--f) * 0.045);
  padding: calc(var(--f) * 0.16) calc(var(--f) * 0.022) calc(var(--f) * 0.175);
  background:
    var(--hole) 0 calc(var(--f) * 0.075) / calc(var(--f) / 8) calc(var(--f) * 0.072) repeat-x,
    var(--hole) 0 calc(100% - var(--f) * 0.09) / calc(var(--f) / 8) calc(var(--f) * 0.072) repeat-x,
    #2b2a27;
}

/* Laid by hand: each strip slightly off */
.film-strip:nth-child(4n + 1) { transform: translateX(-0.5cqw) rotate(-0.35deg); }
.film-strip:nth-child(4n + 2) { transform: translateX(0.6cqw) rotate(0.25deg); }
.film-strip:nth-child(4n + 3) { transform: translateX(-0.2cqw) rotate(-0.15deg); }
.film-strip:nth-child(4n + 4) { transform: translateX(0.4cqw) rotate(0.3deg); }

/* Each frame takes its size from the column width (some browsers, Safari,
   would otherwise derive it from the row height or the image's own size) */
.sheet-frame {
  position: relative;
  display: block;
  width: 100%;
  min-width: 0;
  aspect-ratio: 3 / 2;
}

.sheet-frame picture {
  position: absolute;
  inset: 0;
}

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

/* Edge print in white, in a narrow technical type like on real film: the
   frame number at the frame's right end above the holes; below them "→17A"
   and the number again */
.edge-top,
.edge-bottom {
  position: absolute;
  line-height: 1;
  font-family: "Arial Narrow", "Helvetica Neue", Arial, sans-serif;
  font-stretch: condensed;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: #ececec;
  white-space: nowrap;
  /* Slightly soft, as edge print is on a contact print */
  filter: blur(max(calc(var(--f) * 0.002), 0.2px));
}

.edge-top {
  bottom: calc(100% + var(--f) * 0.087);
  right: 3%;
  font-size: max(calc(var(--f) * 0.07), 4px);
}

.edge-bottom {
  top: calc(100% + var(--f) * 0.096);
  left: 0;
  right: 0;
  font-size: max(calc(var(--f) * 0.07), 4px);
}

.edge-bottom i {
  position: absolute;
  left: 30%;
  top: 0;
  font-style: normal;
  font-size: 0.75em;
}

.edge-bottom b {
  position: absolute;
  right: 3%;
  top: 0;
}

/* The empty frame prints paper white, a blank waiting for the next picture */
.sheet-empty { background: #efede7; }

/* Grease-pencil circle around the empty frame */
.grease-mark {
  position: absolute;
  inset: -16% -9%;
  width: 118%;
  height: 132%;
  overflow: visible;
  pointer-events: none;
}

/* The brush shapes (width changing along the line, built by main.js) */
.grease-ink { fill: #c4362c; }

/* Their reveal masks: a line along each stroke that draws itself */
.grease-reveal {
  fill: none;
  stroke: #fff;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Drawn on stroke by stroke each time the end card appears */
.grease-reveal {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  opacity: 0; /* hidden until its turn; rounded ends would otherwise show a dot */
  animation: grease-draw var(--for) ease-in-out var(--at) forwards;
}

@keyframes grease-draw {
  from { opacity: 1; }
  to { stroke-dashoffset: 0; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .grease-reveal { animation: none; stroke-dashoffset: 0; opacity: 1; }
}

/* Compact form for very little height: no film strips, only the empty frame
   with its circled "Du?" (paper white on paper, so just the pencil shows) */
.lightbox-end.is-compact .contact-sheet {
  max-width: 55%;
  padding: 0;
  background: none;
}

.lightbox-end.is-compact .film-strip:not(:has(.sheet-empty)),
.lightbox-end.is-compact .strip-film > :not(.sheet-empty),
.lightbox-end.is-compact .edge-top,
.lightbox-end.is-compact .edge-bottom { display: none; }

.lightbox-end.is-compact .film-strip { transform: none; }

.lightbox-end.is-compact .strip-film {
  display: block;
  padding: 0;
  background: none;
}

.lightbox-end p {
  margin: 0;
  text-wrap: balance; /* even lines, no single word left over */
  font-size: clamp(0.9rem, 3.4cqw, 1.7rem);
  font-weight: 300;
  line-height: 1.4;
  /* Appears slowly, a moment after "Du?" has been written (it keeps its
     space meanwhile) */
  animation: end-text-in 1.6s ease-in-out 2.9s both;
}

@keyframes end-text-in { from { opacity: 0; } }

/* The button is there from the start, as an outline; it fills black later (below) */
@media (prefers-reduced-motion: reduce) {
  .lightbox-end p { animation: none; }
}

.lightbox-end .button { padding: clamp(0.5rem, 1.5cqw, 0.9rem) clamp(1rem, 4cqw, 2.2rem); }
.lightbox-end .button:hover { background: var(--black); color: var(--white); }

/* Lights up shortly after the card appears (classes set by main.js), with
   the same slow fade as the Weihnachtsshooting button; on paper it fills black */
.lightbox-end .button { transition: background 1.2s ease, color 1.2s ease; }
.lightbox-end .button.is-settled { transition-duration: 0.3s; }
.lightbox-end .button.is-highlighted { background: var(--black); color: var(--white); }

/* Filled already, so hover does the opposite: back to outline */
.lightbox-end .button.is-highlighted:hover { background: transparent; color: var(--black); }

/* Darkroom print with the film rebate printed along: a black frame whose long
   sides taper towards the corners, triangle marks on one long side and edge
   code on the other. Landscape: marks on top, code at the bottom. */
.print {
  --paper: clamp(1rem, 3vh, 1.8rem);
  padding: var(--paper);
  background: #f3f1ec;
  box-shadow: 0 0.5rem 2rem rgb(0 0 0 / 0.5);
  cursor: default;
  transition: padding 0.5s ease;
}

/* The end card is a print of its own (the contact sheet on its paper), so
   paper margin and film frame step back and it can use the space */
.print.is-plain { padding: 0; }

.print.is-plain .negative { border-width: 0; }

@media (min-width: 700px) {
  .print.is-plain .negative {
    --max-w: calc(100cqw - 9rem);
    --max-h: calc(100cqh - 4rem);
  }
}

.negative::before,
.negative::after,
.neg-mark,
.neg-code,
.neg-number { transition: opacity 0.5s ease; }

.print.is-plain .negative::before,
.print.is-plain .negative::after,
.print.is-plain .neg-mark,
.print.is-plain .neg-code,
.print.is-plain .neg-number { opacity: 0; }

.print.is-instant { transition: none; }

.negative {
  --thin: 0.3rem;
  --side: 0.7rem;
  --code: 1.5rem;
  --bar: 0.45rem;
  --taper: 1.6rem;
  --ink: #0a0a0a;
  --mark: #8c8c8c;
  /* Largest space the photo may take on screen */
  --max-w: calc(100cqw - 9rem - 2 * var(--paper) - 2.2rem);
  --max-h: calc(100cqh - 4rem - 2 * var(--paper) - 2.2rem);
  position: relative;
  border: 0 solid var(--ink);
  border-width: var(--side) var(--thin) var(--code);
  transition: border-width 0.5s ease;
}

.negative.is-portrait { border-width: var(--thin) var(--code) var(--thin) var(--side); }

/* The print stays and resizes smoothly to the proportions (--ratio) of the
   next photo, while the photos crossfade inside it */
.neg-photos {
  position: relative;
  width: min(var(--max-w), var(--max-h) * var(--ratio));
  height: min(var(--max-h), var(--max-w) / var(--ratio));
  overflow: hidden;
  transition: width 0.5s ease, height 0.5s ease;
  cursor: e-resize;
}

/* Measures the size the photo area is heading for (read by main.js) */
.neg-probe {
  position: absolute;
  width: min(var(--max-w), var(--max-h) * var(--ratio));
  height: min(var(--max-h), var(--max-w) / var(--ratio));
  visibility: hidden;
  pointer-events: none;
}

.neg-photos.is-back { cursor: w-resize; }

.neg-photos > * {
  position: absolute;
  inset: 0;
  animation: photo-in 0.5s ease-out;
}

.neg-photos > .is-leaving { animation: photo-out 0.5s ease-out forwards; }

/* The end card keeps its final size (set by main.js) while the area around
   it resizes, so its film strips and holes do not move during the change */
.neg-photos > .lightbox-end {
  inset: auto;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
}

.neg-photos img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: center / cover no-repeat; /* small preview, set by main.js while loading */
}

@keyframes photo-in { from { opacity: 0; } }
@keyframes photo-out { to { opacity: 0; } }

/* Opening the view or reduced motion: no resizing or fading */
.print.is-instant *,
.print.is-instant *::before,
.print.is-instant *::after { transition: none !important; animation: none !important; }

/* Wedges on the long sides: widest in the middle, running out at the corners */
.negative::before,
.negative::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 0.3rem;
  background: var(--ink);
  z-index: 1;
}

.negative::before { top: 0; clip-path: polygon(0 0, 100% 0, calc(100% - var(--taper)) 100%, var(--taper) 100%); }
.negative::after { bottom: 0; clip-path: polygon(var(--taper) 0, calc(100% - var(--taper)) 0, 100% 100%, 0 100%); }

.negative.is-portrait::before,
.negative.is-portrait::after {
  top: 0;
  bottom: 0;
  width: 0.3rem;
  height: auto;
}

.negative.is-portrait::before { left: 0; right: auto; clip-path: polygon(0 0, 100% var(--taper), 100% calc(100% - var(--taper)), 0 100%); }
.negative.is-portrait::after { left: auto; right: 0; clip-path: polygon(0 var(--taper), 100% 0, 100% 100%, 0 calc(100% - var(--taper))); }

/* Triangle marks in the narrower long side, pointing along the film */
.neg-mark {
  position: absolute;
  top: calc(var(--side) * -0.8);
  width: calc(var(--side) * 0.7);
  height: calc(var(--side) * 0.6);
  background: var(--mark);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

.neg-mark:nth-of-type(1) { left: 18%; }
.neg-mark:nth-of-type(2) { left: 80%; }

.is-portrait .neg-mark {
  top: auto;
  left: calc(var(--side) * -0.8);
  width: calc(var(--side) * 0.6);
  height: calc(var(--side) * 0.7);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}

.is-portrait .neg-mark:nth-of-type(1) { top: 18%; }
.is-portrait .neg-mark:nth-of-type(2) { top: 80%; }

/* Edge code in the wider long side: groups of short bars */
.neg-code {
  position: absolute;
  bottom: calc((var(--code) + var(--bar)) / -2);
  left: max(14%, 5.5rem); /* leaves room for the number */
  right: 8%;
  height: var(--bar);
  background: repeating-linear-gradient(to right, var(--mark) 0 0.22rem, transparent 0.22rem 0.42rem);
  mask-image: linear-gradient(to right, #000 0 34%, transparent 34% 52%, #000 52% 56%, transparent 56% 70%, #000 70% 100%);
}

.is-portrait .neg-code {
  top: max(14%, 5.5rem);
  bottom: 8%;
  left: auto;
  right: calc((var(--code) + var(--bar)) / -2);
  width: var(--bar);
  height: auto;
  background: repeating-linear-gradient(to bottom, var(--mark) 0 0.22rem, transparent 0.22rem 0.42rem);
  mask-image: linear-gradient(to bottom, #000 0 34%, transparent 34% 52%, #000 52% 56%, transparent 56% 70%, #000 70% 100%);
}

/* Image number, printed in the wide side of the frame like film edge numbering */
.neg-number {
  --size: 0.7rem;
  position: absolute;
  bottom: calc((var(--code) + var(--size)) / -2);
  left: 3%;
  font-size: var(--size);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.2em;
  color: #bdbdbd;
  white-space: nowrap;
}

.is-portrait .neg-number {
  top: 3%;
  bottom: auto;
  left: auto;
  right: calc((var(--code) + var(--size)) / -2);
  writing-mode: vertical-rl;
}

/* Phones: the photo alone, full width, without paper and film frame;
   paging by swiping, the number shown below the photo */
@media (max-width: 699px) {
  .print {
    padding: 0;
    background: none;
    box-shadow: none;
  }

  .negative,
  .negative.is-portrait {
    --max-w: 100cqw;
    --max-h: calc(100cqh - 8rem);
    border-width: 0;
  }

  .negative::before,
  .negative::after,
  .neg-mark,
  .neg-code,
  .neg-number,
  .lightbox-prev,
  .lightbox-next { display: none; }

  .lightbox .lightbox-count {
    bottom: 2rem;
    left: 50%;
    translate: -50% 0;
    width: auto;
    height: auto;
    margin: 0;
    clip-path: none;
    font-size: 0.75rem;
    font-weight: 300;
    letter-spacing: 0.25em;
    opacity: 0.6;
  }
}

/* Read out by screen readers only; the visible number sits on the frame */
.lightbox-count {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.lightbox button {
  position: absolute;
  padding: 0.5rem 1rem;
  border: 0;
  background: none;
  color: var(--white);
  font: 300 2.5rem/1 var(--font);
  opacity: 0.6;
  cursor: pointer;
  transition: opacity 0.3s;
}

/* A focused button shows at full brightness; keyboard users also get a thin
   ring, mouse users do not */
.lightbox button:focus { outline: none; }

.lightbox button:hover,
.lightbox button:focus-visible { opacity: 1; }

.lightbox button:focus-visible {
  outline: 1px solid var(--white);
  outline-offset: 2px;
}

.lightbox-prev { left: 1rem; top: 50%; translate: 0 -50%; }
.lightbox-next { right: 1rem; top: 50%; translate: 0 -50%; }
.lightbox-close { right: 1rem; top: 1rem; }

@media (prefers-reduced-motion: reduce) {
  .lightbox[open] { animation: none; }
}

/* About */
.about {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: clamp(2rem, 6vw, 6rem);
  align-items: center;
  max-width: 72rem;
  margin: 0 auto;
}

.about-text p { max-width: 32rem; margin-bottom: 1.25rem; color: #333; }

.about-image { margin: 0; }
.about-image img { display: block; width: 100%; height: auto; }

/* Small caption, set like the names under the quotes */
.about-image figcaption {
  margin-top: 0.75rem;
  font-size: 0.75rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--grey);
}

/* Services: on the paper tone of the contact sheet, set apart from the
   white page but as easy to read as the rest */
.services { background: #efede7; color: var(--black); }

/* The small grey type needs a little more contrast on the paper tone */
.services { --grey: #666; }

.service-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 3rem;
}

.service {
  border-top: 1px solid #cfccc4;
  padding-top: 1.5rem;
}

.service-no {
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  color: var(--grey);
}

.service h3 {
  font-weight: 400;
  font-size: 1.6rem;
  margin: 0.5rem 0 1rem;
}

.service p { color: #333; }

.service .service-meta {
  margin-top: 1.25rem;
  font-size: 0.75rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--grey);
}

/* Small print below the offers: what the prices include */
.service-note {
  margin-top: 3rem;
  font-size: 0.9rem;
  color: var(--grey);
}

/* "Gut zu wissen": the main points of the contract, four short notes,
   in a row on wide screens, two by two in between, stacked on phones */
.good-to-know {
  margin-top: clamp(3.5rem, 8vw, 5rem);
  padding-top: 2.5rem;
  border-top: 1px solid #cfccc4;
}

.good-to-know h3 {
  margin-bottom: 2rem;
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--grey);
}

.good-to-know dl { display: grid; gap: 2rem 2.5rem; }

@media (min-width: 40rem) { .good-to-know dl { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .good-to-know dl { grid-template-columns: repeat(4, 1fr); } }

.good-to-know dt { margin-bottom: 0.5rem; font-weight: 500; color: var(--black); }

.good-to-know dd { margin: 0; color: #333; }

.good-to-know-note { margin-top: 2.5rem; font-size: 0.9rem; color: var(--grey); }

/* Process */
.process { max-width: 72rem; margin: 0 auto; }

.steps {
  list-style: none;
  counter-reset: step;
  display: grid;
  gap: 2.5rem;
}

/* All four in a row, or two and two – never three plus one left alone */
@media (min-width: 40rem) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .steps { grid-template-columns: repeat(4, 1fr); } }

.steps li {
  counter-increment: step;
  color: #444;
}

.steps li::before {
  content: counter(step, decimal-leading-zero);
  display: block;
  font-size: 2.5rem;
  font-weight: 300;
  color: var(--line);
  margin-bottom: 0.5rem;
}

.steps strong { display: block; font-weight: 500; color: var(--black); }

/* Scrolled into view, the steps fade in one after the other (class set by main.js) */
.steps li:nth-child(2) { --i: 1; }
.steps li:nth-child(3) { --i: 2; }
.steps li:nth-child(4) { --i: 3; }

.steps.reveal li {
  opacity: 0;
  transform: translateY(1rem);
  transition: opacity 1s ease-out, transform 1s ease-out;
  transition-delay: calc(var(--i, 0) * 0.3s);
}

.steps.reveal.is-visible li { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .steps.reveal li { opacity: 1; transform: none; transition: none; }
}

/* Quote */
.quote { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }

/* Short voices side by side, wrapping into centred rows, one below the
   other on narrow screens */
.quote-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 5rem 2.5rem;
  max-width: 72rem;
  margin: 0 auto;
}

.quote blockquote { flex: 0 1 12rem; margin: 0; text-align: center; }

.quote p {
  font-size: clamp(1.2rem, 2.4vw, 1.6rem);
  font-weight: 300;
  line-height: 1.5;
  margin-bottom: 0.4rem;
}

/* The name sits right below its quote: a block of its own, without extra line height */
.quote cite {
  display: block;
  line-height: 1;
  font-style: normal;
  font-size: 0.75rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--grey);
}

/* Contact */
.contact { max-width: 40rem; margin: 0 auto; text-align: center; }

.contact-lead { color: #444; margin: -1.5rem 0 3rem; }
.contact-lead a { white-space: nowrap; }

.contact-form { display: grid; gap: 1.5rem; text-align: left; }

.contact-form label {
  display: grid;
  gap: 0.4rem;
  font-size: 0.7rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--grey);
}

.contact-form input,
.contact-form textarea {
  font: inherit;
  font-size: 1rem;
  letter-spacing: normal;
  text-transform: none;
  color: var(--black);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--line);
  padding: 0.5rem 0;
  resize: vertical;
}

.contact-form input:focus,
.contact-form textarea:focus { outline: none; border-color: var(--black); }

.contact-form .button { justify-self: center; margin-top: 1rem; }

.contact-form .button:hover { background: var(--black); color: var(--white); }

.contact-form .button:disabled { opacity: 0.5; cursor: default; }

/* Arriving at the contact section: the field lines and labels darken one
   after the other and fade back, so the eye finds the form (class set by main.js) */
@keyframes field-call {
  0%, 35% { border-color: var(--black); box-shadow: 0 1px 0 var(--black); }
  100% { border-color: var(--line); box-shadow: 0 1px 0 transparent; }
}

@keyframes label-call {
  0%, 35% { color: var(--black); }
  100% { color: var(--grey); }
}

.contact-form.is-called label { animation: label-call 2.4s ease-out backwards; }
.contact-form.is-called input,
.contact-form.is-called textarea { animation: field-call 2.4s ease-out backwards; }

.contact-form.is-called label:nth-of-type(2),
.contact-form.is-called label:nth-of-type(2) input { animation-delay: 0.15s; }
.contact-form.is-called label:nth-of-type(3),
.contact-form.is-called label:nth-of-type(3) input { animation-delay: 0.3s; }
.contact-form.is-called label:nth-of-type(4),
.contact-form.is-called label:nth-of-type(4) textarea { animation-delay: 0.45s; }

.contact-form .form-trap { position: absolute; left: -9999px; }

.form-status { text-align: center; color: #444; }
.form-status:empty { display: none; }
.form-status a { border-bottom: 1px solid var(--line); }

/* Offer subpage (Weihnachtsshooting) */
/* section.offer to outrank the general section padding; the top leaves room for the fixed header */
section.offer {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: clamp(2rem, 6vw, 6rem);
  align-items: center;
  max-width: 72rem;
  margin: 0 auto;
  padding-top: calc(var(--header-h) + var(--section) / 2);
}

.offer-title {
  font-size: clamp(2rem, 5vw, 3.5rem);
  margin-bottom: 1.5rem;
}

.offer-text p { max-width: 32rem; margin-bottom: 1.25rem; color: #333; }

.offer-text .offer-lead { font-size: 1.2rem; font-weight: 300; color: var(--black); }

.offer-text .button { margin-top: 1rem; }

.offer .button:hover { background: var(--black); color: var(--white); }

.offer-details,
.offer-dates { max-width: 72rem; margin: 0 auto; }

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

.facts div { border-top: 1px solid var(--line); padding-top: 1rem; }

.facts dt {
  font-size: 0.7rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--grey);
}

.facts dd { font-size: 1.2rem; font-weight: 300; margin-top: 0.25rem; }

.offer-dates p { max-width: 40rem; margin-bottom: 3rem; color: #333; }

.back-link {
  font-size: 0.75rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--grey);
}

.back-link:hover { color: var(--black); }

/* Legal pages (Impressum); section.legal outranks the general section
   padding, the top leaves room for the fixed header */
section.legal {
  max-width: 44rem;
  margin: 0 auto;
  padding-top: calc(var(--header-h) + var(--section) / 2);
}

.legal-title {
  font-size: clamp(2rem, 5vw, 3.5rem);
  margin-bottom: 2rem;
}

.legal h2 {
  margin: 2.5rem 0 0.75rem;
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--grey);
}

.legal p { line-height: 1.7; color: #333; }
.legal p + p { margin-top: 1rem; }
.legal .legal-date { margin-top: 2.5rem; font-size: 0.85rem; color: var(--grey); }

.legal a[data-mail-user] { border-bottom: 1px solid var(--line); }

.legal .back-link { display: inline-block; margin-top: 3rem; }

/* Error page: a large, pale number above the usual legal-page title */
.legal .not-found-code {
  font-size: clamp(4rem, 14vw, 9rem);
  font-weight: 300;
  line-height: 1;
  color: var(--line);
  margin-bottom: 1rem;
}

.legal.not-found p a { border-bottom: 1px solid var(--line); }

/* Footer */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding: 2rem var(--gutter);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--grey);
}

.site-footer a:hover { color: var(--black); }

/* Small screens */
@media (max-width: 600px) {
  .menu-toggle { display: block; }

  /* Full-screen menu overlay */
  .nav {
    position: fixed;
    inset: 0;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 2.5rem;
    background: var(--black);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s, visibility 0.3s;
  }

  .nav a { font-size: 1rem; letter-spacing: 0.35em; }

  /* Hero photo behind the menu at 40% over black, so the links stay readable */
  .nav-bg {
    display: block;
    position: absolute;
    inset: 0;
    z-index: -1;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 30%;
    opacity: 0.4;
  }

  .menu-open { overflow: hidden; }
  .menu-open .nav { opacity: 1; visibility: visible; }

  /* The blend would invert the black overlay, so switch it off while open */
  .menu-open .site-header { mix-blend-mode: normal; }
}
