/* ===========================================================
   YANNICK SUTTER — Photo & Video
   Brutalist: neo-grotesque, one signal colour, oversized type,
   hairline grid, register mark (+).
   No build, no framework.  Rebranding: change --red only.
   =========================================================== */

:root {
  --red:    #d21e1e;            /* surface colour — change here */
  --ink:    #000000;
  --dark:   #1e1e1e;            /* menu / footer panel */
  --light:  #ECEBE7;            /* light theme ground (About / Contact) */
  --white:  #f0f0f0;            /* hover / active */
  --grey:   #828282;
  --hair:   #1e1e1e;            /* hairlines */

  --gutter: clamp(2.75rem, 5vw, 4rem);   /* left bar — fluid, no breakpoint jump */
  --colA:   24%;               /* left hairline / content edge */
  --colB:   70%;               /* right hairline / label edge */
  --pad:    1.25rem;
  --edge:   calc(var(--colA) + var(--pad));
  --panelw: 50vw;              /* menu panel width */

  --ease: cubic-bezier(0.23, 1, 0.32, 1);
  --dur:  0.75s;

  --font: "Helvetica Neue", Helvetica, "Arial Nova", Arial,
          "Inter", system-ui, sans-serif;
}

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

html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;   /* no blue flash on tap (mobile WebKit) */
  /* NEUTRAL, not red: this is what iOS Safari paints behind the status bar / in
     the over-scroll area. Red here = the "red top & bottom" bug. The red band is
     now an explicit <footer> background instead. */
  background: var(--light);
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  background: var(--light);        /* neutral surface (see html note above) */
  color: var(--ink);
  font: 400 16px/1.4 var(--font);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* keep the red band at the bottom of content pages: a real footer bar that
   sticks to the bottom edge even when the page is short */
.wrapper {
  min-height: 100vh;
  min-height: 100lvh;
  display: flex;
  flex-direction: column;
}
.wrapper > main { flex: 1 0 auto; }

a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; }

/* etwas grössere Hand über interaktiven Flächen */
a[href], button, summary, [role="button"],
.clip, .menu-plus, .menu__close, .menu__scrim,
.archive tbody tr, .archive tbody tr td {
  -webkit-tap-highlight-color: transparent;
  cursor:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='34' height='34' viewBox='0 0 44 44'%3E%3Cpath d='M15 4c-1.7 0-3 1.3-3 3v13l-3-3c-1.2-1.2-3.1-1.2-4.3 0s-1.2 3.1 0 4.3l8 8c1.3 1.3 3 2 4.9 2H30c3.3 0 6-2.7 6-6v-9c0-1.7-1.3-3-3-3s-3 1.3-3 3c0-1.7-1.3-3-3-3s-3 1.3-3 3c0-1.7-1.3-3-3-3s-3 1.3-3 3V7c0-1.7-1.3-3-3-3z' fill='%23fff' stroke='%23000' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E") 11 3,
    pointer;
}
.sr-only {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* ---------- grid overlay: left bar + register mark ---------- */
.frame { position: fixed; inset: 0; z-index: 40; pointer-events: none; }
.frame::before {
  content: "";
  position: fixed; left: 0; top: 0;
  width: var(--gutter);
  height: 100vh;
  height: 100lvh;      /* large viewport: stays full-bleed behind the iOS toolbar */
  background: #304454;
  z-index: 40;
}
/* register mark = menu trigger (on the left bar) */
.menu-plus {
  position: fixed;
  left: calc(var(--gutter) / 2);
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 46;
  width: var(--gutter); height: var(--gutter);
  display: grid; place-items: center;
  background: none; border: 0; padding: 0;
  -webkit-appearance: none; appearance: none;
  transition: opacity 0.2s ease;
}
body.menu-open .menu-plus { opacity: 0; pointer-events: none; }
.menu-plus:focus { outline: none; }
.menu-plus:focus-visible { outline: 2px solid var(--red); outline-offset: -10px; }

/* shared icon for "+" (trigger) and "x" (close) — identical, only rotated.
   Sized as a fraction of the bar so it keeps the same fill at every width. */
.menu-icon {
  position: relative;
  width: calc(var(--gutter) * 0.55); height: calc(var(--gutter) * 0.55);
  transition: transform var(--dur) var(--ease);
}
.menu-icon::before, .menu-icon::after {
  content: ""; position: absolute; background: #fff;
}
.menu-icon::before { left: 0; right: 0; top: 50%; height: 2px; transform: translateY(-50%); }
.menu-icon::after  { top: 0; bottom: 0; left: 50%; width: 2px; transform: translateX(-50%); }
.menu-plus:hover .menu-icon { transform: rotate(90deg); }

/* Vertical hairlines: continuous only in the intro header and the text pages.
   In the work list the line is split per clip (border-left on each .clip). */
section { position: relative; isolation: isolate; }
.intro::before,
.intro::after,
.archive::before,
.light::before {
  content: "";
  position: absolute;
  width: 1px; background: var(--hair);
  z-index: -1; pointer-events: none;
}
/* Intro: light hairlines over the video, inset equally top and bottom */
.intro { --hair: rgba(255, 255, 255, 0.55); }
.intro::before,
.intro::after { top: 2rem; bottom: 2rem; }
.archive::before,
.light::before { top: 0; bottom: 0; }

.intro::before,
.archive::before,
.light::before { left: var(--colA); }
.intro::after { left: var(--colB); }

/* header video as background — full colour, no overlay */
.intro__bg {
  position: absolute; inset: 0;
  z-index: -2;
  overflow: hidden;
  background: var(--red);
}
.intro__video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}


/* ---------- Intro ---------- */
.intro { min-height: 100vh; min-height: 100lvh; overflow: hidden; }  /* 100lvh: full-bleed video behind the iOS status bar + toolbar */
.intro__cats {
  position: absolute; top: 2rem;
  left: calc(var(--colB) + var(--pad));
  list-style: none;
  font: 700 0.9rem/1.2 var(--font);
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: #fff;
}
.intro__huge {
  position: absolute;
  left: calc(var(--colB) + var(--pad));   /* left edge flush with the category row */
  bottom: 0.3rem;                          /* just above the edge -> no clipping, no detachment */
  line-height: 1;
  color: #fff;
}
.intro__huge span {
  display: block;
  font: 700 clamp(5rem, 22vw, 17rem)/1 var(--font);
  letter-spacing: -0.045em;
  white-space: nowrap;
}

/* Off-canvas push: the menu doesn't overlay, it slides the whole page to the
   right into the free half. Done with `transform` (not `padding-left`) so the
   content keeps its width — otherwise the narrower box re-wraps the justified
   About text every frame of the animation. */
.wrapper {
  transition: transform var(--dur) var(--ease);
}
/* hint the compositor only while the push is actually in play */
body.menu-open .wrapper,
body:not(.menu-open) .menu-plus:hover ~ .wrapper { will-change: transform; }
body.menu-open .wrapper { transform: translateX(calc(50% - var(--edge) + var(--pad))); }

/* hover over "+": small peek — content shifts 1rem right */
body:not(.menu-open) .menu-plus:hover ~ .wrapper { transform: translateX(1rem); }

/* ---------- work (video stack) ---------- */
.work { padding: 5rem var(--pad) 4rem var(--colA); background: var(--red); }

.clip {
  display: block;
  border-left: 1px solid var(--hair);   /* line per clip -> with gaps between */
  padding-left: var(--pad);
  margin-bottom: 10rem;
}
/* start page = showreel: the video surface keeps the hand cursor (hover plays it),
   but the caption is inert — plain cursor, no slide, no click-through */
#clips .clip__cap, #clips .clip__cap * { cursor: default; }
.clip__media {
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  background: center / cover no-repeat;
  background-color: var(--dark);
  overflow: hidden;
}
.clip--more { display: none; }   /* reachable via the index only */

/* Sub-pages (Archive / About / Contact): not on the home page,
   reachable only via the side bar (index -> big nav) */
#archive-film, #archive-photo, #about, #contact, #imprint, #project { display: none; }
body.view-archive-film  #archive-film,
body.view-archive-photo #archive-photo,
body.view-about   #about,
body.view-contact #contact,
body.view-imprint #imprint,
body.view-project #project { display: block; }
body.view-archive-film  #intro,  body.view-archive-film  #work,
body.view-archive-photo #intro,  body.view-archive-photo #work,
body.view-about   #intro,  body.view-about   #work,
body.view-contact #intro,  body.view-contact #work,
body.view-imprint #intro,  body.view-imprint #work,
body.view-project #intro,  body.view-project #work { display: none; }


/* the imprint page carries its own © line — keep the red footer bar,
   just hide its text/link (the bar's red background stays) */
/* on Imprint the footer's own © line + Imprint link are redundant — hide them
   (keep the red bar). visibility:hidden also drops the link from hit-testing so
   a sticky :hover can't flash it back. */
body.view-imprint footer { color: transparent; }
body.view-imprint footer a { visibility: hidden; }

.clip__media::before {         /* fallback without image */
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(135deg, #000 0%, #5c0a15 55%, #000 100%);
}
.clip__media::after {          /* light red veil while not hovered */
  content: "";
  position: absolute; inset: 0; z-index: 2;
  background: var(--red);
  mix-blend-mode: multiply;
  opacity: 0.4;
  transition: opacity var(--dur) var(--ease);
  pointer-events: none;
}
.clip.is-hot .clip__media::after { opacity: 0; }

.clip__media iframe,
.clip__media video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0; z-index: 1;
  pointer-events: none;
}
.clip__media iframe { transform: scale(1.04); }  /* verdeckt Vimeo-Ränder */
.clip__media video  { object-fit: contain; background: #000; }  /* ganzes Bild sichtbar */

/* caption slides right on hover only in the Film archive (clips open a project
   there). On the start page the caption is inert, so it stays put. */
.archive-grid .clip__meta { transition: transform var(--dur) var(--ease); }
.archive-grid .clip:hover .clip__meta { transform: translateX(1.25rem); }

.clip__play {
  position: absolute; left: 1rem; bottom: 1rem; z-index: 3;
  width: 2.5rem; height: 2.5rem;
  border: 1px solid #fff; border-radius: 50%;
  display: grid; place-items: center; color: #fff;
  transition: opacity var(--dur) var(--ease);
}
.clip.is-hot .clip__play { opacity: 0; }
.clip__play::before {
  content: "";
  border-left: 0.66rem solid currentColor;
  border-top: 0.4rem solid transparent;
  border-bottom: 0.4rem solid transparent;
  margin-left: 0.18rem;
}

.clip__cap {
  display: flex; justify-content: space-between; gap: 1.5rem;
  margin-top: 0.7rem;
  text-transform: uppercase;
}
.clip__cap .t { display: block; font-weight: 700; font-size: 0.95rem; }
.clip__cap .c { display: block; font-weight: 400; font-size: 0.95rem; opacity: 0.82; }
.clip__cat {
  flex: 0 0 auto;
  font-weight: 700; font-size: 0.72rem;
  text-align: right; white-space: nowrap;
}

/* ---------- archive grid ---------- */
.archive-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2.5rem 1.5rem;
  margin: 2.5rem 0 4.5rem;
}
.archive-grid .clip {
  margin: 0;
  border-left: 0;
  padding-left: 0;
}
.archive-grid .clip__cap { margin-top: 0.55rem; }
.archive-grid .clip__cap .t,
.archive-grid .clip__cap .c { font-size: 0.85rem; }
.archive-grid .clip__cat { font-size: 0.65rem; }
/* film archive: veil in the page tone instead of red */
#archive-film .clip__media::after {
  background: #ecebe7;
  mix-blend-mode: normal;
  opacity: 0.42;
}
#archive-film .clip.is-hot .clip__media::after { opacity: 0; }
/* 3 cols on desktop → 2 on a narrow / half window → 1 on phones (2-up is too tight) */
@media (max-width: 60rem) {
  .archive-grid { grid-template-columns: repeat(2, 1fr); gap: 2rem 1.25rem; }
}
@media (max-width: 32rem) {
  .archive-grid { grid-template-columns: 1fr; gap: 2.5rem; }
}
@media (max-width: 32rem) {
  .archive-grid { gap: 1.5rem 0.75rem; }
}

/* ---------- photo archive: category filter + shoot tiles ---------- */
.photo-filter {
  display: flex; flex-wrap: wrap;
  gap: 1.75rem 2rem;
  margin: -0.5rem 0 2.5rem;
  padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--hair);
}
.photo-filter__chip {
  position: relative;
  padding: 0 0 0.65rem;
  background: none; border: 0;
  font: 700 0.78rem/1 var(--font);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--grey);
  transition: color 0.2s ease;
}
.photo-filter__chip::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -1.1rem;
  height: 2px;
  background: var(--red);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s var(--ease);
}
@media (hover: hover) { .photo-filter__chip:hover { color: var(--ink); } }
.photo-filter__chip.is-active { color: var(--ink); }
.photo-filter__chip.is-active::after { transform: scaleX(1); }

/* No click-through to a separate project page for these categories — each
   shoot is its own section stacked vertically (title, location, then every
   one of its photos), grouped/filtered by category the same [hidden] way
   tiles used to be. Swiping happens directly on each section's own photo
   row (.photo-feed-item__gallery), a horizontal drag/swipe filmstrip same
   as everywhere else on the Photo page — there's nothing to "go into". */
.photo-grid {
  display: block;
  margin: 2.5rem 0 4.5rem;
}
.photo-grid[hidden] { display: none; }
.photo-feed-item { margin: 0 0 4rem; }
.photo-feed-item[hidden] { display: none; }
.photo-feed-item:last-child { margin-bottom: 0; }
.photo-feed-item__title {
  font: 700 clamp(1.3rem, 3vw, 1.8rem)/1.1 var(--font);
  text-transform: uppercase; letter-spacing: -0.01em;
  margin: 0 0 0.3rem;
}
.photo-feed-item__loc {
  font: 400 0.85rem/1.4 var(--font);
  color: var(--grey);
  margin: 0;
}
.photo-feed-item__gallery {
  display: flex;
  height: 26rem;
  gap: 0.5rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  cursor: grab;
  /* flush with the normal content edge on the left, bled to the viewport's
     own right edge — same asymmetric bleed as the other filmstrips on this
     page (bleeding past --edge on the left would spill into the reserved
     sidebar gutter behind the hairline, a mistake made and fixed earlier
     in this project); bottom margin is the gap to this section's own
     caption below it. */
  margin: 0 calc(var(--pad) * -1) 1.75rem 0;
  scrollbar-width: none;
}
.photo-feed-item__gallery::-webkit-scrollbar { display: none; }
.photo-feed-item__gallery.is-dragging { cursor: grabbing; }
.photo-feed-item__gallery img,
.photo-feed-item__gallery video {
  flex: 0 0 auto;
  height: 100%;
  width: auto;
  /* No max-width: every photo — portrait or landscape — renders at exactly
     the row's height with its own natural proportional width, so all of
     them line up at the same height with zero distortion. A capped
     max-width here would force a wide landscape photo's box narrower than
     its natural width at full height, and (via object-fit or otherwise)
     either crop it or shrink it — both make it visibly shorter than the
     portraits next to it, which is the opposite of what a uniform-height
     filmstrip should look like. The gallery already scrolls horizontally,
     so an extra-wide photo just takes more scroll room — that's fine.
     Explicit `none` (not just omitted) because the base `img{max-width:
     100%}` reset is a real, separate rule that still applies to any
     property this one doesn't itself set — omitting it here does NOT
     cancel it. */
  max-width: none;
  pointer-events: none;
  -webkit-user-drag: none;
}
@media (max-width: 48rem) {
  .photo-feed-item__gallery { height: 16rem; }
}

/* People category: shown instead of the tile grid when the People chip is
   active. Decorative only — no links; the People shoots themselves stay
   reachable only by direct URL. Uses the exact same .photo-feed-item /
   .photo-feed-item__gallery markup and CSS as every other category (see
   above) — same sizing, spacing and drag mechanic, nothing collage-specific
   left to maintain in parallel. */

/* ---------- archive ---------- */
.archive {
  padding: 5rem var(--pad) 5rem var(--edge);
  background: #ecebe7;
  color: var(--ink);
}
.archive h2 {
  font: 700 clamp(2.4rem, 8vw, 5rem)/1 var(--font);
  text-transform: uppercase; letter-spacing: -0.02em;
  margin-bottom: 1.5rem;
}
.archive table {
  width: 100%; border-collapse: collapse;
  table-layout: fixed;
  text-transform: uppercase;
  font: 400 0.78rem/1.4 var(--font);
  margin-bottom: 4.5rem;
}
.archive .c-project { width: 38%; }
.archive .c-client { width: 22%; }
.archive .c-prod { width: 16%; }
.archive .c-type { width: 16%; }
.archive .c-year { width: 8%; }
.archive th {
  text-align: left;
  font: 700 0.66rem/1 var(--font); letter-spacing: 0.08em;
  opacity: 0.5;
  border-bottom: 1px solid var(--hair);
  padding: 0 1.5rem 0.7rem 0;
}
.archive td {
  vertical-align: middle;
  border-bottom: 1px solid var(--hair);
  padding: 0.9rem 1.5rem 0.9rem 0;
}
.archive td:first-child { font-weight: 700; }
/* dim via colour, NOT opacity — opacity would also fade the row's hover
   background and make it look striped */
.archive td.dim { color: var(--grey); }
.archive .yr { text-align: right; padding-right: 0; }
.archive .type { color: var(--grey); }
@media (hover: hover) { .archive tbody tr:hover td { background: rgba(0, 0, 0, 0.05); } }
.archive a { text-decoration: none; }
.archive td:first-child a:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 60rem) {
  .archive table { display: block; overflow-x: auto; }
}

/* ---------- about / contact (light ground) ---------- */
.light {
  background: var(--light);
  color: var(--ink);
  --hair: rgba(0, 0, 0, 0.5);
  padding: 5rem var(--pad) 5rem var(--edge);
}

.about__lead {
  font: 400 clamp(1.5rem, 3vw, 2.4rem)/1.15 var(--font);
  max-width: 24ch;
  margin-bottom: 2rem;
}
.about p, .contact p { max-width: 52ch; margin-bottom: 1rem; }
.about p:not(.about__lead) { text-align: justify; hyphens: auto; }

/* Text + portrait live in one capped band so on a big display the portrait stays
   next to the text instead of drifting to the far-right edge with a huge gap.
   The band is left-aligned under the section's fluid --edge padding. */
.about__inner { max-width: 52rem; display: flow-root; }   /* flow-root contains the float */
/* The text block sits beside the floated portrait as ONE column of constant
   width (own block-formatting context) — it never re-widens where the image
   ends, so the justified text keeps a single, even measure. */
.about { overflow: hidden; }
.about__body { overflow: hidden; }

.about__portrait {
  float: right;
  width: min(34%, 18rem); height: auto;
  margin: 0.25rem 0 1.25rem 2rem;   /* flush to the band's right edge */
}
/* only stack it on phone-width screens — centred above the text */
@media (max-width: 30rem) {
  .about, .about__body { overflow: visible; }
  .about__inner { display: block; }
  .about__portrait { float: none; display: block; width: 100%; max-width: 18rem; margin: 0 auto 1.5rem; }
}
.light h3 {
  font: 700 0.78rem/1 var(--font);
  text-transform: uppercase; letter-spacing: 0.06em;
  margin: 2rem 0 0.4rem;
}
.about a { text-decoration: underline; text-underline-offset: 3px; }
@media (hover: hover) { .about a:hover { background: var(--ink); color: var(--light); text-decoration: none; } }

.contact__intro { max-width: 46ch; margin-bottom: 2.5rem; }
.contact__intro a { text-decoration: underline; text-underline-offset: 3px; }

/* imprint */
.imprint__title {
  font: 700 clamp(2rem, 6vw, 3.5rem)/1 var(--font);
  letter-spacing: -0.02em;
  text-transform: uppercase;
  margin-bottom: 2rem;
}
.imprint p { max-width: 62ch; margin-bottom: 1rem; line-height: 1.5; text-align: justify; hyphens: auto; }
.imprint a { text-decoration: underline; text-underline-offset: 3px; }
@media (hover: hover) { .imprint a:hover { background: var(--ink); color: var(--light); text-decoration: none; } }
.imprint__copy {
  margin-top: 2.5rem;
  font: 700 0.72rem/1.5 var(--font);
  text-transform: uppercase; letter-spacing: 0.02em;
}

/* project detail page */
.project__nav { margin-bottom: 2.5rem; }
.project__nav--bottom {
  max-width: 64rem;            /* arrows line up with the video's edges */
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem;
  margin: 2.5rem 0 0;
}
.project__nav a {
  font: 700 0.78rem/1 var(--font);
  letter-spacing: 0.06em; text-transform: uppercase;
  text-decoration: underline; text-underline-offset: 3px;
}
/* hover-only: on touch, mobile Safari keeps :hover stuck on the tapped link and —
   because the nav is one persistent element (hash routing) — the black fill would
   carry over to the next project. */
@media (hover: hover) {
  .project__nav a:hover { background: var(--ink); color: var(--light); text-decoration: none; }
}
.project__prev[hidden], .project__next[hidden] { display: none; }
.project__prev[hidden] + .project__next { margin-left: auto; }
.project__meta {
  font: 700 0.72rem/1 var(--font);
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: 0.6; margin-bottom: 0.7rem;
}
.project__title {
  font: 700 clamp(2rem, 6vw, 3.6rem)/1 var(--font);
  letter-spacing: -0.02em; text-transform: uppercase;
  margin-bottom: 1.8rem;
}
/* stylised lowercase names (e.g. sun.set) — keep their case in uppercased text */
.nocaps, .project__title.nocaps { text-transform: none; }
.project__media {
  position: relative; aspect-ratio: 16 / 9;
  background: #000; margin-bottom: 2rem;
  max-width: 64rem;
}
/* a phone-shot portrait hero video (e.g. Lidon) — 16:9 would letterbox it
   down to a sliver in the middle of a wide black box. Transparent (not the
   usual solid black) and centered — but centered within the SAME 64rem
   reading column as .project__cols/.project__stills below it (which stay
   flush-left, never centered), not within the full page width: on a wide
   viewport those two centering contexts differ, and centering against the
   wrong one is what made the video visually drift off to the right of the
   title/text column. A flush-left 64rem row with justify-content:center
   keeps both contexts identical. */
.project__media.is-portrait {
  aspect-ratio: auto;
  max-width: 64rem;
  display: flex;
  justify-content: center;
  background: transparent;
}
.project__media.is-portrait video {
  position: static;
  width: 24rem;
  max-width: 100%;
  aspect-ratio: 1080 / 2294;
  height: auto;
  object-fit: contain;
  /* the source export was a phone mockup on a flat black canvas well beyond
     the phone's own silhouette — that dead margin is cropped out of the file
     itself (tools/lidon masters), not hidden with CSS. What's left is the
     phone's own rounded screen corners meeting a rectangular video frame,
     which still leaves a few px of true black in each corner — radius clips
     those away so nothing black shows at all. */
  border-radius: 1.4rem;
}
.project__media video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
/* buffering hint while the clip loads (removed on the video's canplay) */
.project__media.is-loading::after {
  content: "";
  position: absolute; top: 50%; left: 50%;
  width: 2rem; height: 2rem; margin: -1rem;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) {
  .project__media.is-loading::after { animation: none; border-top-color: rgba(255, 255, 255, 0.35); }
}
/* the spinner is white for contrast against the usual solid-black box — on
   the transparent portrait variant that's nearly invisible against the page */
.project__media.is-portrait.is-loading::after {
  border-color: rgba(0, 0, 0, 0.15);
  border-top-color: var(--ink, #000);
}

/* two columns: description left, facts right; Selected Stills spans below */
.project__cols {
  max-width: 64rem;
  margin-top: 2rem;
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: 0 3rem;
  align-items: start;
}
@media (max-width: 48rem) {
  .project__cols { grid-template-columns: 1fr; gap: 2rem; }
}
.project__cols[hidden] { display: none; }   /* photo shoots skip this — no facts/body */
.project__col > :first-child { margin-top: 0; }

.project__facts {
  display: grid; grid-template-columns: max-content 1fr;
  gap: 0.35rem 1.25rem; margin: 0;
}
/* One face + size for the whole detail page — labels, values and body text.
   #project prefix so it beats the generic `.light h3` rule. */
#project .project__facts dt,
#project .project__facts dd,
#project .project__body-h,
#project .project__stills-h,
#project .project__body p {
  font: 400 0.9rem/1.55 var(--font);
  letter-spacing: 0;
}
/* labels only: bold + uppercase + dimmed (same size as everything else) */
#project .project__facts dt,
#project .project__body-h,
#project .project__stills-h {
  font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em;
  opacity: 0.55;
}
.project__facts dt { align-self: start; }
.project__facts dd { margin: 0; }
.project__body p { margin-bottom: 1rem; text-align: justify; hyphens: auto; }
#project .project__body-h { margin: 0 0 0.6rem; }
#project .project__stills-h { margin: 2.5rem 0 0.6rem; }
.project__body-h[hidden],
.project__stills-h[hidden] { display: none; }
.project__stills {
  max-width: 64rem;              /* same total width as .project__media */
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.4rem;
}
.project__stills:empty { display: none; }
.project__stills img { display: block; width: 100%; height: auto; }
@media (max-width: 48rem) { .project__stills { grid-template-columns: 1fr; } }

/* Photo-shoot galleries (not Film stills): a horizontally scrollable/
   draggable filmstrip, same mechanic as the People collage — touch swipes
   natively, script.js adds pointer-drag-to-scroll for mouse. A shared height
   with width:auto means landscape photos are simply wider than portraits,
   no per-image span logic needed (data-orientation is still set on the <img>
   but no longer read by CSS — kept for potential future use/debugging). */
.project__stills.is-photo-gallery {
  display: flex;
  height: 30rem;
  gap: 0.5rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  cursor: grab;
  max-width: none;
  margin: 0 calc(var(--pad) * -1) 0 0;
  scrollbar-width: none;
}
.project__stills.is-photo-gallery::-webkit-scrollbar { display: none; }
.project__stills.is-photo-gallery.is-dragging { cursor: grabbing; }
.project__stills.is-photo-gallery img,
.project__stills.is-photo-gallery video {
  flex: 0 0 auto;
  height: 100%;
  width: auto;
  /* no max-width — see .photo-feed-item__gallery img for why a capped
     max-width here would make landscape photos visibly shorter than
     portraits instead of equal height; the base `img{max-width:100%}`
     reset needs an explicit override, not just omission, since it's a
     lower-specificity rule that still applies to any property this rule
     doesn't set itself. */
  max-width: none;
  pointer-events: none;   /* image itself never intercepts the drag */
  -webkit-user-drag: none;
}
@media (max-width: 48rem) {
  .project__stills.is-photo-gallery { height: 18rem; }
}

/* A "gallery" Further-Project with p.stillsGrid (e.g. Lidon, exactly 9
   items) uses a fixed 3x3 grid instead of the swipeable filmstrip — a
   tidy showcase grid rather than an ever-scrolling strip, fitting since
   it's a one-off rather than an open-ended shoot. Square cells with
   object-fit:cover crop each photo/video uniformly (unlike the filmstrip's
   height-only sizing, which would leave gaps between cells of different
   aspect ratios here). */
.project__stills.is-grid3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.5rem;
  max-width: 64rem;   /* same width as .project__media / .project__cols */
}
.project__stills.is-grid3 img,
.project__stills.is-grid3 video {
  width: 100%; height: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  pointer-events: none;
  -webkit-user-drag: none;
}

.rows { border-top: 1px solid var(--hair); }
.rows > * {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 2rem;
  border-bottom: 1px solid var(--hair);
  font: 400 clamp(2rem, 6.5vw, 4.4rem)/1.1 var(--font);
  letter-spacing: -0.02em;
  padding: 0.12em 0;
}
.rows a:hover { padding-left: 0.08em; }
.rows .val {
  flex: 0 0 auto;
  font-size: 0.8rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.02em;
  opacity: 0.65; align-self: center;
}

/* ---------- Fuss ---------- */
footer {
  position: relative; z-index: 1;
  background: var(--red);           /* THE red band — an explicit bar now, not the body bg */
  color: var(--ink);
  padding: 1.4rem var(--pad) 1.4rem var(--edge);
  font: 700 0.72rem/1.5 var(--font);
  text-transform: uppercase; letter-spacing: 0.03em;
}
footer a { text-decoration: underline; text-underline-offset: 2px; }
@media (hover: hover) { footer a:hover { color: #fff; } }

/* ---------- menu overlay (slides in from the left) ---------- */
.menu {
  position: fixed; inset: 0; z-index: 50;
  pointer-events: none;
}
.menu.open { pointer-events: auto; }

.menu__scrim {
  position: absolute; inset: 0;
  background: #000;
  border: 0;
  opacity: 0; transition: opacity var(--dur) var(--ease);
}
.menu.open .menu__scrim { opacity: 0.8; }

/* the sliding element: panel + close column together */
.menu__shell {
  position: absolute; left: 0; top: 0;
  width: var(--panelw); height: 100%;
  display: flex; flex-direction: row;
  transform: translateX(-100%);
  transition: transform var(--dur) var(--ease);
}
.menu.open .menu__shell { transform: none; }

.menu__panel {
  flex: 1 1 auto; min-width: 0;
  background: var(--dark); color: var(--red);
  --hair: #000;
  --px: 2rem;                            /* horizontaler Innenabstand */
  /* clear the iOS status bar (viewport-fit=cover puts the panel behind it) */
  padding: max(2rem, calc(1.25rem + env(safe-area-inset-top, 0px))) var(--px)
           max(2rem, calc(2rem + env(safe-area-inset-bottom, 0px)));
  overflow-y: auto;
  display: flex; flex-direction: column;
}

.menu__mark { font: 700 0.8rem/1 var(--font); letter-spacing: 0.05em; margin-bottom: 3rem; }

/* work list: flex-wrap into two columns, line ABOVE each item */
.menu__list {
  flex: none; list-style: none;
  display: flex; flex-wrap: wrap;
  margin-bottom: 1rem;
}
.menu__list li {
  width: calc(50% - 1rem);
  margin: 0 2rem 1.25rem 0;
  padding-top: 0.9rem;
  border-top: 1px solid var(--hair);
}
.menu__list a {
  display: block;
  text-transform: uppercase;
  transition: color 0.2s, border-color 0.2s, padding-left 0.2s;
}
.menu__list .t { display: block; font-weight: 700; font-size: 0.9rem; line-height: 1.2; }
.menu__list .c { display: block; font-weight: 400; font-size: 0.9rem; line-height: 1.2; opacity: 0.72; }
.menu__list a:hover,
.menu__list a:focus-visible {
  outline: none;
  color: var(--white);
  box-shadow: inset 3px 0 0 var(--white);
  padding-left: 1rem;
}

.menu__home {
  align-self: flex-start;
  font: 700 0.9rem/1 var(--font);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 2rem;   /* == panel padding-top, so equal gap above and below */
  /* JS (alignMenuText) sets a precise per-letter text-indent so HOME lines up
     with the big links below; this is just a no-JS fallback */
  text-indent: -0.05em;
}
.menu__home:hover { color: var(--white); }
/* opening the menu focuses the panel itself (not a link) — kill its ring; the
   nav items keep a branded ring only when reached by keyboard */
.menu__panel:focus { outline: none; }
.menu__home:focus, .menu__nav a:focus { outline: none; }
.menu__home:focus-visible,
.menu__nav a:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }

/* big navigation: fixed size, full-bleed lines to the panel edges */
.menu__nav {
  margin: 0 calc(var(--px) * -1);
  border-top: 1px solid var(--hair);
}
.menu__nav a {
  display: block;
  padding: 0.75rem var(--px) 1rem;
  border-bottom: 1px solid var(--hair);
  font: 700 clamp(2.25rem, 9.5vw, 7rem)/0.95 var(--font);
  letter-spacing: -0.04em; text-transform: uppercase;
  text-indent: -0.045em;   /* the big glyphs sit optically inset — pull them back
                              to line up with HOME (scales with the font) */
}
.menu__nav a:hover { color: var(--white); }

/* Close column: mirror of the left bar, slides out with the panel.
   Icon = the same "+" as the trigger, just rotated 45deg (= x). */
.menu__close {
  flex: 0 0 var(--gutter);
  background: var(--dark);
  border: 0; border-left: 1px solid #000;
  padding: 0;
  -webkit-appearance: none; appearance: none;
  display: flex; align-items: center; justify-content: center;
}
.menu__close:focus { outline: none; }
.menu__close:focus-visible { outline: 2px solid var(--red); outline-offset: -6px; }
.menu__close .menu-icon { transform: rotate(45deg); }
.menu__close:hover .menu-icon { transform: rotate(135deg); }

/* ---------- Mobil ---------- */
@media (max-width: 60rem) {
  :root {
    --colA: 0px; --colB: 100%;
    --pad: 1rem;                          /* --gutter keeps its fluid clamp */
    --edge: calc(var(--gutter) + 0.9rem);
  }
  .intro::before, .intro::after,
  .archive::before, .light::before { display: none; }

  /* intro brand mark: no right-hand column on mobile — pin "YS" to the top-right
     corner and scale it down (the full-bleed desktop size is far too big here) */
  .intro__cats { display: none; }
  .intro__huge { left: auto; right: var(--pad); top: 1.25rem; bottom: auto; }
  .intro__huge span { font-size: clamp(2.5rem, 9vw, 6.5rem); }

  /* work stack: clear the fixed side bar, tighten the gaps */
  .work { padding-left: var(--edge); }
  .clip { border-left: 0; padding-left: 0; margin-bottom: 4.5rem; }
  .clip__cap { flex-direction: column; gap: 0.15rem; }
  .clip__cat { text-align: left; }
  /* Film archive: the caption is a left-aligned column now, so the category
     slides with the rest on hover — no risk of running off the right edge */
  .archive-grid .clip__cat { transition: transform var(--dur) var(--ease); }
  .archive-grid .clip:hover .clip__cat { transform: translateX(1.25rem); }

  .menu { --panelw: 100%; }
  /* panel covers the whole screen here → the page-slide would just be motion
     with nothing to reveal; skip it */
  body.menu-open .wrapper { transform: none; }
  .menu__list li { width: 100%; margin-right: 0; }
  .menu__close { flex-basis: 3.5rem; }
  .rows > * { flex-direction: column; align-items: flex-start; gap: 0.1rem; }
  .rows .val { align-self: flex-start; }

  /* viewport-fit=cover lets the intro video fill the whole screen (no red strip
     top/bottom). Keep the actual page content out of the iOS status bar / home
     indicator. max() → a no-op on devices without safe-area insets. */
  #work, #archive-film, #archive-photo, .light {
    padding-top: max(5rem, calc(3.5rem + env(safe-area-inset-top, 0px)));
  }
  .intro__huge { top: calc(1.25rem + env(safe-area-inset-top, 0px)); }
  footer { padding-bottom: max(0.4rem, calc(0.4rem + env(safe-area-inset-bottom, 0px))); }
}

/* ---------- touch devices (no hover) ---------- */
@media (hover: none) {
  /* Clips can't be hovered: the ▶ button is how you start a preview. Lighten the
     idle veil so the posters read, and keep the button on-screen while a clip
     plays (it toggles to a pause icon) so it can be stopped again. */
  .clip__media::after { opacity: 0.24; }
  #archive-film .clip__media::after { opacity: 0.3; }

  /* keep the same hairline circle as desktop — just a drop-shadow so the white
     ring holds up over bright posters. No fill, no blur. */
  .clip__play {
    width: 2.6rem; height: 2.6rem;
    filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.55));
  }
  .clip__play:focus { outline: none; }              /* no ring on tap */
  .clip__play:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
  .clip.is-hot .clip__play { opacity: 1; }          /* stays tappable to pause */
  .clip.is-hot .clip__play::before,                 /* triangle → two pause bars */
  .clip.is-hot .clip__play::after {
    content: "";
    grid-area: 1 / 1;                               /* stack both in the grid centre */
    width: 0.17rem; height: 0.86rem;
    border: 0; margin: 0;
    background: currentColor;
  }
  .clip.is-hot .clip__play::before { transform: translateX(-0.13rem); }
  .clip.is-hot .clip__play::after  { transform: translateX(0.13rem); }

  /* comfortable ~44px tap targets for the small text links */
  footer a,
  .menu__home,
  .project__nav a,
  .archive table td a,
  .imprint h3 + p a {
    display: inline-block;
    padding-block: 0.85rem;
  }
  .project__nav a { padding-inline: 0.5rem; margin-inline: -0.5rem; }
  .menu__home { padding-inline: 0.4rem; margin-left: -0.4rem; }
  footer { padding-top: 0.4rem; padding-bottom: 0.4rem; }
  .imprint h3 + p { margin-top: -0.5rem; }   /* soak up the added link padding */
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
