/* ==========================================================================
   Luc Hochstrasser — Portfolio
   Design tokens
   ========================================================================== */

:root {
  --c-white: #ffffff;
  --c-black: #000000;
  --c-pink: #fb80ff;
  --c-lime: #9eff64;
  --c-red: #ff0000;
  --c-gray: #d8d8d8;

  /* Active/hover state of the header links, per background brightness */
  --c-nav-active-on-light: #8a8a8a;
  --c-nav-active-on-dark: #d8d8d8;

  --font: "Helvetica Neue", Helvetica, Arial, sans-serif;

  /* Vier Schriftgrössen für die ganze Website — mehr gibt es nicht.
     Display für Titel, Title für Zwischentitel, Body für Fliesstext,
     Micro für Navigation, Labels und Bildlegenden. */
  --fs-display: clamp(2.4rem, 5vw, 4rem);
  --fs-title: clamp(1.35rem, 2.2vw, 1.85rem);
  --fs-body: 15px;
  --fs-micro: 12px;

  /* Haarlinie: das durchgehende Ordnungselement dieser Version */
  --hair: 1px solid currentColor;
  --hair-alpha: 0.28;

  --pad-x: 100px;
  --pad-x-tablet: 48px;
  --pad-x-mobile: 20px;

  --section-pad-y: 140px;
  --section-pad-y-mobile: 64px;

  /* Height reserved for the fixed, transparent header. */
  --nav-h: 66px;

  /* Ein Vollbild-Abschnitt ist absichtlich etwas kuerzer als das Fenster.
     Der Anschnitt des naechsten Abschnitts am unteren Rand zeigt, dass die
     Seite weitergeht — sonst wirkt jeder Bildschirm wie das Ende. */
  --screen: 88svh;

  /* Space above the title on every sub page, holding the image carousel.
     Not applied to the home page. */
  --carousel-space: clamp(180px, 32vh, 380px);
}

@media (max-width: 1100px) {
  :root {
    --pad-x: var(--pad-x-tablet);
  }
}

@media (max-width: 640px) {
  :root {
    --pad-x: var(--pad-x-mobile);
    --section-pad-y: var(--section-pad-y-mobile);
  }
}

* {
  box-sizing: border-box;
}


body {
  margin: 0;
  font-family: var(--font);
  background: var(--c-white);
  color: var(--c-black);
  -webkit-font-smoothing: antialiased;
}

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

a {
  color: inherit;
}

.container {
  padding-left: var(--pad-x);
  padding-right: var(--pad-x);
}

/* ==========================================================================
   Navigation
   ========================================================================== */

/* The header floats above the page: no background of its own, and its text
   colour flips to match whichever section is currently behind it
   (see assets/js/nav.js — sections carry a data-nav-theme attribute). */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: clamp(18px, 2.6vw, 40px);
  padding: 22px var(--pad-x);
  background: transparent;
  color: var(--c-black);
  flex-wrap: wrap;
  transition: transform 0.3s ease, color 0.2s ease;
}

/* Dark backgrounds (pink, black) → white header text */
.nav--dark {
  color: var(--c-white);
}

.nav--hidden {
  transform: translateY(-100%);
}

/* Haarlinie unter der Navigation, bündig mit dem Inhaltsraster */
.nav::after {
  content: "";
  position: absolute;
  left: var(--pad-x);
  right: var(--pad-x);
  bottom: 0;
  height: 1px;
  background: currentColor;
  opacity: var(--hair-alpha);
}

.nav--hidden::after {
  opacity: 0;
}

.nav__link {
  font-weight: 500;
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
  transition: color 0.15s ease;
}

/* On light backgrounds the current page reads as dark grey,
   on dark backgrounds as light grey. */
.nav__link:hover,
.nav__link.is-active {
  color: var(--c-nav-active-on-light);
}

.nav--dark .nav__link:hover,
.nav--dark .nav__link.is-active {
  color: var(--c-nav-active-on-dark);
}

/* ==========================================================================
   Type
   ========================================================================== */

h1,
h2,
h3 {
  margin: 0;
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: -0.025em;
  text-transform: none;
}

.h-hero,
.h-section {
  font-size: var(--fs-display);
}

.h-sub {
  font-size: var(--fs-title);
}

/* Kleines Label über einem Titel, angeschrieben von einer Haarlinie */
.eyebrow {
  font-weight: 500;
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: 0.13em;
  margin: 0 0 18px;
  padding-top: 14px;
  border-top: var(--hair);
  display: inline-block;
}

.tagline {
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.55;
  margin: 22px 0 0;
  max-width: 46ch;
}

/* Rechteckiger Rahmen statt Unterstreichung — harte Kanten, kein Radius */
.cta {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  width: fit-content;
  gap: 14px;
  margin-top: 36px;
  padding: 13px 20px;
  border: var(--hair);
  font-weight: 500;
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  text-decoration: none;
  color: inherit;
  background: transparent;
  transition: background-color 0.18s ease, color 0.18s ease;
}

/* Beim Hover kehrt sich der Button um: Schrift wird Fläche, Fläche wird Schrift */
.cta:hover {
  background: var(--ink);
  color: var(--paper);
}

.cta__label {
  text-decoration: none;
}

.cta__arrow {
  transition: transform 0.2s ease;
}

.cta:hover .cta__arrow {
  transform: translateX(6px);
}

.copy {
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.6;
  margin: 0;
  max-width: 52ch;
}

.copy--right {
  margin-left: auto;
}

.copy--right {
  text-align: right;
}

/* ==========================================================================
   Hero (home)
   ========================================================================== */

.hero {
  padding: calc(var(--nav-h) + 32px) var(--pad-x) 80px;
  background: var(--c-white);
  color: var(--c-black);
  min-height: 88vh;
  min-height: var(--screen);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.hero__title {
  margin-top: 0;
}

/* ==========================================================================
   Section blocks (home teaser sections)
   Every section fills exactly one screen, so only one is visible at a time
   and the next one appears on scroll.
   ========================================================================== */

.section {
  padding: calc(var(--nav-h) + 32px) var(--pad-x) 80px;
  position: relative;
  overflow: hidden;
  min-height: 88vh;
  min-height: var(--screen);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.section--pink {
  background: var(--c-pink);
  color: var(--c-white);
}

.section--black {
  background: var(--c-black);
  color: var(--c-white);
}

.section--lime {
  background: var(--c-lime);
  color: var(--c-black);
}

.section__head {
  position: relative;
  z-index: 2;
}

/* Motion graphics ball — hidden until "Mehr dazu" drops it, then it falls in
   from above and bounces itself to a stop (see assets/js/dropball.js). */
.dropball {
  position: absolute;
  left: 0;
  top: 0;
  width: clamp(36px, 4.4vw, 58px);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  background: var(--c-red);
  opacity: 0;
  pointer-events: none;
  z-index: 1;
  /* squashes onto the ground, so its underside stays put */
  transform-origin: 50% 100%;
  will-change: transform;
}

.dropball.is-dropping {
  opacity: 1;
}

.dropball.is-exploding {
  opacity: 0;
}

/* The dot bursts out of the page and floods the screen before the
   motion-graphics page opens (see assets/js/dropball.js). */
.burst {
  position: fixed;
  z-index: 999;
  border-radius: 50%;
  background: var(--c-red);
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0);
  transition: transform 460ms cubic-bezier(0.4, 0, 0.2, 1);
}

.burst.is-on {
  transform: translate(-50%, -50%) scale(1);
}

/* Photography teaser image. Per the PDF it sits flush with the bottom of
   the black section, starting 19.6% in from the left. */
.photo-frame {
  position: absolute;
  left: 19.6%;
  bottom: 0;
  margin: 0;
  width: min(50%, calc(48vh * 1.647));
  aspect-ratio: 1087 / 660;
  overflow: hidden;
}

.photo-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  color: transparent;
}

/* A second copy of the photo, masked down to the shutter finger, so it can
   dip on its own when the shutter is pressed. The soft mask edge blends the
   movement into the rest of the hand instead of cutting it. */
.photo-frame__press {
  position: absolute;
  inset: 0;
  background-image: url("../img/photographie-teaser.png");
  background-size: cover;
  background-position: center;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(
    ellipse 11% 13% at 32% 10%,
    #000 0%,
    #000 26%,
    transparent 100%
  );
  mask-image: radial-gradient(
    ellipse 11% 13% at 32% 10%,
    #000 0%,
    #000 26%,
    transparent 100%
  );
  transform: translateY(0);
  transition: transform 150ms cubic-bezier(0.4, 0, 0.6, 1);
}

.photo-frame.is-pressing .photo-frame__press {
  transform: translateY(0.85%);
}

/* ---- Vertical A4 carousel in the photography teaser ---- */

.vcarousel {
  --vcarousel-gap: 12px;
  position: absolute;
  left: 74.5%;
  right: var(--pad-x);
  top: calc(var(--nav-h) + 8px);
  bottom: 3%;
  overflow: hidden;
  z-index: 2;
}

.vcarousel__track {
  display: flex;
  flex-direction: column;
  gap: var(--vcarousel-gap);
  animation: vcarousel-scroll 38s linear infinite;
}

.vcarousel:hover .vcarousel__track {
  animation-play-state: paused;
}

@keyframes vcarousel-scroll {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(calc(-50% - var(--vcarousel-gap) / 2));
  }
}

.vcarousel__item {
  flex: 0 0 auto;
  width: 100%;
  aspect-ratio: 210 / 297;
  background: var(--c-gray);
}

@media (max-width: 900px) {
  .vcarousel {
    display: none;
  }
}

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

  .photo-frame__press {
    transition: none;
  }
}

/* Keep the heading clear of the photo in the black section. */
.section--black {
  justify-content: flex-start;
  padding-top: calc(var(--nav-h) + 32px + 6vh);
}

@media (max-width: 760px) {
  .photo-frame {
    left: var(--pad-x);
    width: min(74%, calc(34vh * 1.647));
  }
}

/* ---- Word burst (Zu mir teaser) ----
   Sits to the right of the title. Only "Luc" shows at first; once the
   section has fully covered the screen for two seconds, assets/js/wordburst.js
   adds .is-exploded and the words fly out from the centre to their spots.
   Their inward offsets (--dx/--dy) are measured by that script. */

.wordburst {
  position: absolute;
  left: 34%;
  right: var(--pad-x);
  top: 50%;
  transform: translateY(-50%);
  height: min(560px, 74%);
  z-index: 1;
  pointer-events: none;
  font-size: var(--fs-body);
}

.wordburst__seed,
.wordburst__word {
  position: absolute;
  font-weight: 400;
  white-space: nowrap;
}

/* the single word shown before the burst */
.wordburst__seed {
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-size: var(--fs-display);
  font-weight: 600;
  letter-spacing: -0.02em;
  transition: transform 700ms cubic-bezier(0.16, 0.84, 0.44, 1),
    opacity 450ms ease;
}

.wordburst.is-exploded .wordburst__seed {
  opacity: 0;
  transform: translate(-50%, -50%) scale(2.6);
}

/* resting state: each word centred on its own left/top anchor */
.wordburst__word {
  transform: translate(-50%, -50%) rotate(var(--r, 0deg));
  opacity: 1;
  transition: transform 900ms cubic-bezier(0.16, 0.84, 0.44, 1),
    opacity 600ms ease;
  transition-delay: var(--d, 0ms);
}

/* before the burst: parked on the centre, invisible */
.wordburst:not(.is-exploded) .wordburst__word {
  transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, 0px)))
    rotate(0deg) scale(0.3);
  opacity: 0;
  transition-delay: 0ms;
}

@media (max-width: 760px) {
  .section--lime {
    justify-content: flex-start;
  }

  .wordburst {
    left: var(--pad-x);
    right: var(--pad-x);
    top: auto;
    bottom: 6%;
    height: 46%;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .wordburst__seed,
  .wordburst__word {
    transition: none;
  }
}

/* ==========================================================================
   Shutter flash — covers the screen white before leaving for the
   photography page (see assets/js/flash.js)
   ========================================================================== */

.flash {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: var(--c-white);
  opacity: 0;
  pointer-events: none;
}

.flash.is-on {
  opacity: 1;
  transition: opacity 130ms ease-out;
}

/* ==========================================================================
   Horizontal image carousel (title screen of the sub pages)
   Sits in the space reserved above the title.
   ========================================================================== */

.carousel {
  --carousel-gap: 20px;
  position: absolute;
  top: calc(var(--nav-h) + 20px);
  left: var(--pad-x);
  right: 0;
  overflow: hidden;
  scrollbar-width: none;
}

.carousel::-webkit-scrollbar {
  display: none;
}

/* The track holds the items twice, so shifting it by half its width
   (plus half a gap) loops seamlessly. */
.carousel__track {
  display: flex;
  gap: var(--carousel-gap);
  width: max-content;
  animation: carousel-scroll 48s linear infinite;
}

.carousel:hover .carousel__track {
  animation-play-state: paused;
}

@keyframes carousel-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(-50% - var(--carousel-gap) / 2));
  }
}

/* A4 portrait */
.carousel__item {
  flex: 0 0 auto;
  height: clamp(150px, 28vh, 340px);
  aspect-ratio: 210 / 297;
  background: var(--c-gray);
}

@media (max-height: 780px) {
  .carousel {
    top: calc(var(--nav-h) + 8px);
  }
}

/* No auto-scroll — let people scroll the strip themselves instead. */
@media (prefers-reduced-motion: reduce) {
  .carousel {
    overflow-x: auto;
  }

  .carousel__track,
  .carousel--free .carousel__track {
    animation: none;
  }
}

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  background: var(--c-black);
  color: var(--c-white);
  padding: 56px var(--pad-x) 48px;
  display: grid;
  grid-template-columns: repeat(4, minmax(140px, 1fr));
  gap: 32px;
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.6;
}

.footer p {
  margin: 0;
}

@media (max-width: 900px) {
  .footer {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 500px) {
  .footer {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   Detail pages — shared
   ========================================================================== */

/* The title screen of each sub page fills exactly one screen too.
   The extra top padding keeps the title clear of the carousel band. */
.page-head {
  position: relative;
  padding: calc(var(--nav-h) + 32px + var(--carousel-space)) var(--pad-x) 80px;
  min-height: 88vh;
  min-height: var(--screen);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.page-head__eyebrow {
  margin-top: 0;
}

/* Variante ohne Bilderband. Der Platz ueber dem Titel wird ueber
   --carousel-space reserviert, deshalb genuegt es, die Variable hier auf
   null zu setzen — das greift auch in der Regel fuer niedrige Fenster. */
.page-head--plain {
  --carousel-space: 0px;
}

/* On short screens tighten the vertical rhythm so a section stays
   within one screen height. */
@media (max-height: 780px) {
  .hero,
  .section,
  .page-head {
    padding-top: calc(var(--nav-h) + 12px);
    padding-bottom: 40px;
  }

  /* keep the reserved carousel space on sub pages */
  .page-head {
    padding-top: calc(var(--nav-h) + 12px + var(--carousel-space));
  }

  /* keep the heading clear of the camera photo */
  .section--black {
    padding-top: calc(var(--nav-h) + 12px + 4vh);
  }

  .photo-frame {
    width: min(50%, calc(42vh * 1.647));
  }
}

.divider {
  border: none;
  border-top: 1px solid currentColor;
  opacity: 0.5;
  margin: 0;
}

.placeholder {
  background: var(--c-gray);
  width: 100%;
}

.placeholder--photo {
  aspect-ratio: 4 / 5;
}

.placeholder--wide {
  aspect-ratio: 16 / 9;
}

.placeholder--square {
  aspect-ratio: 1 / 1;
}

.placeholder--circle {
  aspect-ratio: 1 / 1;
  border-radius: 50%;
}

.placeholder--star {
  background: transparent;
}

/* ---- Poster page ---- */

.poster-block {
  padding: 90px var(--pad-x);
}

.poster-block + .poster-block {
  border-top: 1px solid rgba(0, 0, 0, 0.5);
}

/* Heading on the left, its note set against the right edge. */
.poster-head {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: 40px;
  align-items: start;
}

/* One row of equally sized posters, all sharing a top edge, with the
   longer note in the last column. */
.poster-shelf {
  display: grid;
  grid-template-columns: repeat(3, 1fr) 1.3fr;
  gap: 40px;
  align-items: start;
  margin-top: 56px;
}

/* Both paragraphs share one column, one edge and one measure, so the head
   reads as a single block of text beside the heading. */
.poster-head__text {
  display: flex;
  flex-direction: column;
  gap: 26px;
}

/* the line that introduces the row below, set apart by a rule */
.poster-head__lead {
  padding-top: 22px;
  border-top: 1px solid currentColor;
}

/* Variant where each poster carries its own note instead of one shared
   column. The posters sit in equal A4 slots, so every note starts on the
   same line. */
.poster-shelf--captioned {
  grid-template-columns: repeat(3, 1fr);
}

.work {
  margin: 0;
  display: flex;
  flex-direction: column;
}

.work__note {
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid currentColor;
}

.work__title {
  display: block;
  font-weight: 600;
  font-size: var(--fs-body);
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin-bottom: 10px;
}

.work__text {
  display: block;
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: 1.5;
}

@media (max-width: 900px) {
  .poster-shelf--captioned {
    grid-template-columns: 1fr 1fr;
  }
}

@media (max-width: 560px) {
  .poster-shelf--captioned {
    grid-template-columns: 1fr;
  }
}

.placeholder--tall {
  aspect-ratio: 3 / 4;
}

.placeholder--short {
  aspect-ratio: 4 / 3;
}

/* ---- Real content in place of the placeholders ---- */

.media {
  display: block;
  width: 100%;
  height: auto;
  background: var(--c-gray);
  object-fit: cover;
}

.media--a4 {
  aspect-ratio: 1 / 1.414;
}

/* Posters are shown whole rather than cropped to the grid slot. */
.media--fit {
  object-fit: contain;
  background: transparent;
}

.media--tall {
  aspect-ratio: 3 / 4;
}

.media--portrait {
  aspect-ratio: 2 / 3;
}

.media--wide {
  aspect-ratio: 16 / 9;
}

.media--square {
  aspect-ratio: 1 / 1;
}

@media (max-width: 900px) {
  .poster-head {
    grid-template-columns: 1fr;
  }

  .poster-head .copy--right {
    text-align: left;
  }

  .poster-shelf {
    grid-template-columns: 1fr 1fr;
  }

  .poster-shelf .copy--right {
    grid-column: 1 / -1;
    text-align: left;
  }
}

@media (max-width: 560px) {
  .poster-shelf {
    grid-template-columns: 1fr;
  }
}

/* ---- Motion graphics page ---- */

.mg-block {
  padding: 80px var(--pad-x);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
}

.mg-block__caption {
  margin-top: 16px;
  font-weight: 400;
  font-size: var(--fs-body);
}

.plan {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.plan__title {
  font-size: var(--fs-title);
  font-weight: 600;
}

.plan-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 32px;
  margin-top: 32px;
}

.plan__shape {
  width: 96px;
  height: 96px;
  margin-top: 16px;
}

@media (max-width: 900px) {
  .mg-block,
  .plan-grid {
    grid-template-columns: 1fr;
  }
}

/* ---- Fotografie page ---- */

/* Sits inside .poster-block, which already supplies the page gutter —
   so no horizontal padding here, or the images would be double-indented. */
.foto-row {
  padding: 64px 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr) 2.2fr;
  gap: 40px;
  align-items: start;
}

.foto-row--two {
  grid-template-columns: 1.4fr 1fr;
  align-items: start;
}

.foto-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 4px;
}

.foto-grid + .foto-grid {
  margin-left: 24px;
}

.foto-pairs {
  display: flex;
  gap: 54px;
  flex-wrap: wrap;
}

/* ---- Before/after slider ----
   The graded shot lies underneath; the raw one sits on top like a foil and
   is clipped away from the divider rightwards. Pushing the divider right
   peels the raw off, pushing it left lays it back on. */

.ba {
  --split: 50%;
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--c-gray);
}

.ba__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ba__layer--raw {
  clip-path: inset(0 0 0 var(--split));
}

.ba__divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--split);
  width: 2px;
  margin-left: -1px;
  background: var(--c-black);
  pointer-events: none;
}

/* A real range input drives it, so dragging, tapping and the arrow keys
   all work without extra code. It covers the picture but stays invisible. */
.ba__range {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: none;
  background: transparent;
  opacity: 0;
  cursor: ew-resize;
  -webkit-appearance: none;
  appearance: none;
}

.ba__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 44px;
  height: 100%;
}

.ba__range::-moz-range-thumb {
  width: 44px;
  height: 100%;
  border: none;
  border-radius: 0;
}

.ba__range:focus-visible {
  opacity: 1;
  outline: 3px solid var(--c-white);
  outline-offset: -3px;
}

.ba__tag {
  position: absolute;
  top: 14px;
  font-weight: 400;
  font-size: var(--fs-micro);
  padding: 5px 9px;
  background: rgba(0, 0, 0, 0.62);
  color: var(--c-white);
  pointer-events: none;
}

.ba__tag--left {
  left: 14px;
}

.ba__tag--right {
  right: 14px;
}

@media (max-width: 760px) {
  .ba {
    flex: 1 1 100%;
  }
}

@media (max-width: 900px) {
  .foto-row {
    grid-template-columns: 1fr;
  }
}

/* ---- Records on the Musik squares ----
   The square is the mat; the record sits on it and spins when dragged
   (see assets/js/records.js). */

/* A wooden deck to set the record on. The grain is layered gradients:
   fine lines, broader streaks, then the colour variation of the board. */
.turntable {
  display: grid;
  place-items: center;
  /* Blackened wood. It stays a step lighter than the vinyl, so the record
     still reads as a distinct disc against the board. */
  background-color: #242424;
  background-image:
    /* three grain layers on periods that do not divide into each other,
       so the pattern never visibly repeats */
    repeating-linear-gradient(
      0deg,
      rgba(0, 0, 0, 0.34) 0 1px,
      rgba(255, 255, 255, 0.045) 1px 2px,
      rgba(0, 0, 0, 0) 2px 9px
    ),
    repeating-linear-gradient(
      0deg,
      rgba(0, 0, 0, 0.24) 0 2px,
      rgba(0, 0, 0, 0) 2px 23px
    ),
    /* broader streaks */
      repeating-linear-gradient(
        0deg,
        rgba(255, 255, 255, 0.03) 0 4px,
        rgba(0, 0, 0, 0) 4px 37px
      ),
    /* the board itself, lifted a little towards the middle */
      linear-gradient(
        180deg,
        #2e2e2e 0%,
        #202020 26%,
        #2a2a2a 52%,
        #1c1c1c 76%,
        #292929 100%
      );
  box-shadow: inset 0 0 30px rgba(0, 0, 0, 0.55),
    inset 0 0 0 1px rgba(0, 0, 0, 0.6);
}

.record {
  width: 88%;
  aspect-ratio: 1 / 1;
  position: relative;
  container-type: inline-size;
  cursor: grab;
  touch-action: none; /* let the drag spin instead of scrolling the page */
  user-select: none;
  -webkit-user-select: none;
}

.record:active {
  cursor: grabbing;
}

.record:focus-visible {
  outline: 3px solid var(--c-black);
  outline-offset: 6px;
  border-radius: 50%;
}

.record__disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  will-change: transform;
  background:
    /* grooves */
    repeating-radial-gradient(
      circle at 50% 50%,
      rgba(255, 255, 255, 0.055) 0 1px,
      rgba(0, 0, 0, 0) 1px 5px
    ),
    /* vinyl, lit from the upper left and darker than the board it sits on */
    radial-gradient(circle at 32% 28%, #2b2b2b 0%, #101010 45%, #050505 100%);
  /* hairline rim keeps the edge legible against the dark wood */
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.6), 0 3px 8px rgba(0, 0, 0, 0.5),
    0 0 0 1px rgba(255, 255, 255, 0.11);
}

.record__label {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 38%;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* title above the spindle hole, artist below it */
  justify-content: space-between;
  padding: 11% 7%;
  text-align: center;
  line-height: 1.15;
  /* The sleeve is set as background-image in the markup, so its path stays
     relative to the page. Missing file → the colour below shows instead. */
  background-color: var(--label-bg, var(--c-gray));
  background-size: cover;
  background-position: center;
}

.record__title {
  font-weight: 600;
  font-size: clamp(6px, 6cqw, 19px);
}

.record__artist {
  font-weight: 400;
  font-size: clamp(5px, 4cqw, 13px);
  opacity: 0.75;
}

/* the spindle hole, dark so it reads on any label colour */
.record__hole {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 4.5%;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #0b0b0b;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.22);
}

/* once the sleeve artwork loads it replaces the stand-in type */
.record.is-covered .record__title,
.record.is-covered .record__artist {
  display: none;
}

/* The rectangle is a window; the strip of faces rides past behind it. */
.panel {
  position: relative;
  overflow: hidden;
}

.panel__track {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  display: flex;
  will-change: transform;
  /* the strip only ever moves a whole picture at a time */
  transition: transform 420ms cubic-bezier(0.4, 0, 0.2, 1);
}

.panel__face {
  flex: 0 0 auto;
  height: 100%;
  background-color: var(--c-black);
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

/* ---- Draggable globe ---- */

.globe {
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  cursor: grab;
  touch-action: none; /* let the drag rotate instead of scrolling the page */
  user-select: none;
  -webkit-user-select: none;
}

.globe:active {
  cursor: grabbing;
}

.globe:focus-visible {
  outline: 3px solid var(--c-black);
  outline-offset: 4px;
}

.globe__canvas {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  pointer-events: none;
  /* shows through until the texture has loaded */
  background: radial-gradient(
    circle at 32% 27%,
    #4b5f7a 0%,
    #24354b 62%,
    #0e1723 100%
  );
  box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.5);
}


/* ==========================================================================
   Version 2 — Raster und Haarlinien
   Gleicher Aufbau wie Version 1, aber die Seite wird von durchgehenden
   Linien und einem einzigen Satz Schriftgrössen zusammengehalten.
   ========================================================================== */

/* Schrift- und Flächenfarbe je Abschnitt, damit sich Buttons und Linien
   ohne Sonderregeln in jede Farbfläche einfügen. */
:root {
  --ink: var(--c-black);
  --paper: var(--c-white);
}

body {
  --ink: var(--c-black);
  --paper: var(--c-white);
}

.hero,
.section--lime {
  --ink: var(--c-black);
  --paper: var(--c-white);
}

.section--lime {
  --paper: var(--c-lime);
}

.section--pink {
  --ink: var(--c-white);
  --paper: var(--c-pink);
}

.section--black,
.footer {
  --ink: var(--c-white);
  --paper: var(--c-black);
}

/* Auf der grünen Fläche endet die Linie vor den Eigenschaftswörtern */
.section--lime .section__head {
  max-width: min(30ch, 30%);
}

/* Farbige Unterseiten setzen ihre Werte über das body-Attribut */
body[data-nav-theme="dark"] {
  --ink: var(--c-white);
}

/* --------------------------------------------------------- Abschnittsköpfe */

/* Jeder Titel steht auf einer Linie, die über die Spaltenbreite läuft.
   Das ist das wiederkehrende Motiv dieser Version. */
.section__head {
  padding-top: 26px;
  border-top: var(--hair);
  max-width: min(52ch, 100%);
}

.section--black .section__head,
.section--pink .section__head {
  position: relative;
  z-index: 2;
}

/* ------------------------------------------------------------- Zwischenteile */

/* Inhaltsblöcke werden durch Linien getrennt statt durch Abstand allein */
.poster-block + .poster-block,
.mg-block + .mg-block,
.sheet {
  border-top: var(--hair);
}

.poster-head {
  padding-bottom: 22px;
}

/* Bildlegenden und Notizen bekommen dieselbe Linienlogik */
.work__note {
  border-top: var(--hair);
}

.work__title {
  font-weight: 500;
  letter-spacing: 0;
}

/* --------------------------------------------------------------- Karussell */

/* Bilder stehen in einem gerahmten Band statt frei im Raum */
.carousel,
.vcarousel {
  border-top: var(--hair);
  border-bottom: var(--hair);
}

/* Variante fuer "Zu mir": kein A4-Raster. Alle Bilder sind gleich hoch, die
   Breite richtet sich nach dem Bild selbst. Dadurch bleibt jedes Format
   erhalten und es wird nichts weggeschnitten — und weil kein fester Rahmen
   ausgefuellt werden muss, entstehen auch keine leeren Balken. */
.carousel--free .carousel__item {
  width: auto;
  aspect-ratio: auto;
  background: var(--c-black);
}

.carousel--free .carousel__item .media {
  width: auto;
  height: 100%;
  aspect-ratio: auto;
  object-fit: contain;
}

/* Weil die Breiten jetzt unterschiedlich sind, traegt das Band den Satz
   dreimal statt zweimal — sonst reicht eine Haelfte auf breiten Bildschirmen
   nicht mehr ueber die ganze Fensterbreite und beim Rundenwechsel blitzt der
   Hintergrund durch. Verschoben wird um genau einen Satz:
   ein Drittel der Bandbreite plus ein Drittel Abstand. */
.carousel--free .carousel__track {
  animation-name: carousel-scroll-thirds;
}

@keyframes carousel-scroll-thirds {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(calc(-100% / 3 - var(--carousel-gap) / 3));
  }
}

/* ------------------------------------------------------------------ Fusszeile */

.footer {
  border-top: var(--hair);
  font-size: var(--fs-micro);
  line-height: 1.7;
  letter-spacing: 0.02em;
}

/* ------------------------------------------------------------- Wortexplosion */

/* Alle Eigenschaften in derselben Grösse — den Rhythmus machen Lage und
   Drehung, nicht die Schriftgrösse. */
.wordburst__word {
  font-size: var(--fs-body);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.09em;
}

.wordburst__seed {
  font-weight: 600;
}


/* ==========================================================================
   Zu mir — Version 2
   Zwei Bögen unter dem Titelbildschirm. Beide beginnen mit derselben
   Kopfzeile: Titel links, Notiz rechts, Linie darunter.
   ========================================================================== */

.sheet {
  padding: clamp(70px, 9vh, 110px) var(--pad-x);
}

.sheet__head {
  display: grid;
  grid-template-columns: 1fr minmax(0, 44ch);
  gap: clamp(24px, 4vw, 64px);
  align-items: end;
  padding-bottom: 24px;
  border-bottom: var(--hair);
}

.sheet__note {
  text-align: right;
  margin-left: auto;
  max-width: 44ch;
}

/* ------------------------------------------------------------------ Musik */

/* Drei gleich grosse Decks statt der wachsenden Reihe. Jede Platte trägt
   ihre Angaben unter sich, auf einer gemeinsamen Linie. */
.tracks {
  margin-top: clamp(40px, 6vh, 72px);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 3vw, 56px);
}

.track {
  margin: 0;
  display: flex;
  flex-direction: column;
}

.track__deck {
  aspect-ratio: 1 / 1;
  width: 100%;
}

.track__caption {
  margin-top: 20px;
  padding-top: 14px;
  border-top: var(--hair);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 14px;
  align-items: start;
}

.track__num,
.track__artist {
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: 0.13em;
  opacity: 0.6;
}

.track__title {
  display: block;
  font-size: var(--fs-body);
  font-weight: 500;
}

.track__artist {
  display: block;
  margin-top: 7px;
}

/* Titel und Interpret stehen jetzt unter der Platte, nicht mehr auf ihr */
.tracks .record__title,
.tracks .record__artist {
  display: none;
}

/* --------------------------------------------------------------- Freunde */

/* Das Fenster nimmt die ganze Spaltenbreite ein und liegt quer. */
/* Das Fenster ist eine schwarze Bühne: das Bild wird ganz hineingelegt
   (contain), nie beschnitten. Wo das Seitenverhältnis nicht aufgeht, bleibt
   Schwarz stehen — dasselbe Schwarz, das die beiden Bildschirmfotos schon
   mitbringen, darum fällt der Rand nicht als Balken auf. */
.window {
  margin-top: clamp(40px, 6vh, 72px);
  width: min(100%, 760px);
  margin-inline: auto;
  /* Quadratisch, weil die zehn Bilder gemischt hoch und quer sind: so wird
     kein Format stark benachteiligt. Ein Querformat waere fuer die sechs
     Hochkant-Aufnahmen zu breit, ein Hochformat fuer die vier Querformate
     zu schmal — im Quadrat fuellt das schwaechste Bild noch 56% der Flaeche. */
  aspect-ratio: 1 / 1;
  background: var(--c-black);
}

/* Darunter das Bedienelement: Globus links, Hinweis am rechten Rand. */
.console {
  margin-top: 26px;
  padding-top: 26px;
  border-top: var(--hair);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: clamp(24px, 4vw, 64px);
  align-items: center;
}

.console__globe {
  width: clamp(140px, 16vw, 224px);
}

.console__hint {
  text-align: right;
  margin-left: auto;
}

@media (max-width: 900px) {
  .sheet__head {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .sheet__note {
    text-align: left;
    margin-left: 0;
  }
}

@media (max-width: 640px) {
  .tracks {
    grid-template-columns: 1fr;
    gap: 40px;
  }

  .console {
    grid-template-columns: 1fr;
    justify-items: start;
    gap: 22px;
  }

  .console__hint {
    text-align: left;
    margin-left: 0;
  }
}

/* ==========================================================================
   Website — die Seite über diese Seite
   Graue Fläche als Arbeitspapier: ruhiger als die Farbseiten, damit die
   Skizzen selbst die Farbe machen. Aufbau wie "Zu mir": Bogen mit Kopfzeile,
   Titel links, Notiz rechts, Haarlinie darunter.
   ========================================================================== */

.section--gray {
  background: var(--c-gray);
  color: var(--c-black);
}

.section--gray {
  --ink: var(--c-black);
  --paper: var(--c-gray);
}

/* Eine Skizze mit ihrem Text daneben. Das Blatt steht links und bekommt die
   breitere Spalte — es ist das Belegstück, der Text kommentiert es nur. */
.sketch {
  margin-top: clamp(40px, 6vh, 72px);
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}

/* Umgekehrte Leserichtung, damit zwei Skizzen hintereinander nicht
   gleich aussehen. */
.sketch--flip .sketch__figure {
  order: 2;
}

.sketch__figure {
  margin: 0;
}

/* Weisse Fläche hinter dem Blatt: das Papier steht damit auch dann als
   Blatt im Raum, wenn ein Scan einen hellen Rand hat. */
.sketch__img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--c-white);
}

/* Zwei Blätter nebeneinander, wenn eine Skizze zwei Seiten zeigt */
.sketch__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(12px, 1.6vw, 24px);
}

.sketch__caption {
  margin-top: 18px;
  padding-top: 14px;
  border-top: var(--hair);
  font-weight: 500;
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
}

.sketch__text {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* Der Gedanke dahinter, abgesetzt von der Beschreibung durch eine Linie */
.sketch__thought {
  padding-top: 22px;
  border-top: var(--hair);
}

.sketch__label {
  display: block;
  font-weight: 500;
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  margin-bottom: 10px;
}

@media (max-width: 900px) {
  .sketch {
    grid-template-columns: 1fr;
  }

  .sketch--flip .sketch__figure {
    order: 0;
  }
}

/* ==========================================================================
   Komposition — die roten Raster über den drei Fotos
   Jedes Bild bekommt sein eigenes Raster als SVG darüber: Leading Lines,
   Drittelregel, Goldener Schnitt. Der Schalter darüber blendet alle ein.
   ========================================================================== */

.raster-toggle {
  appearance: none;
  background: transparent;
  border: 0;
  border-top: var(--hair);
  color: inherit;
  cursor: pointer;
  font-family: inherit;
}

.raster-toggle[aria-pressed="true"] {
  color: var(--c-red);
}

.komp {
  margin: 0;
  display: flex;
  flex-direction: column;
}

/* Das SVG liegt deckungsgleich über dem Bild. Weil .media--portrait den
   Ausschnitt auf 2:3 festlegt, passt die viewBox 200x300 exakt darauf. */
.komp__frame {
  position: relative;
}

.komp__grid {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 0.22s ease;
  pointer-events: none;
  fill: none;
  stroke: var(--c-red);
  stroke-width: 1.4;
}

.komp__grid circle {
  fill: var(--c-red);
  stroke: none;
}

/* Die Hilfslinien des Goldenen Schnitts dünner als die Spirale selbst */
.komp__grid .komp__hair {
  stroke-width: 0.8;
}

.is-raster .komp__grid {
  opacity: 1;
}

.komp__name {
  margin-top: 14px;
  padding-top: 12px;
  border-top: var(--hair);
  font-weight: 500;
  font-size: var(--fs-micro);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  transition: color 0.22s ease;
}

.is-raster .komp__name {
  color: var(--c-red);
}

@media (prefers-reduced-motion: reduce) {
  .komp__grid,
  .komp__name {
    transition: none;
  }
}

/* ==========================================================================
   Rechtstexte (Datenschutz)
   Fliesstext in zwei Spalten unter der Kopfzeile — dieselbe Logik wie die
   Bögen auf "Zu mir", nur ohne Bild.
   ========================================================================== */

.page-head--kurz {
  min-height: 0;
  padding-bottom: 0;
}

.legal {
  margin-top: clamp(32px, 5vh, 56px);
  columns: 2 34ch;
  column-gap: clamp(28px, 4vw, 64px);
}

.legal > * {
  break-inside: avoid;
  margin-bottom: 20px;
}

.legal .copy {
  max-width: none;
}

.legal__list {
  margin: 0 0 20px;
  padding-left: 1.1em;
  font-size: var(--fs-body);
  line-height: 1.6;
}

.legal__list li {
  margin-bottom: 6px;
}

@media (max-width: 640px) {
  .legal {
    columns: 1;
  }
}
