/* ==========================================================================
   Christian Stieben — Filmmaker Portfolio
   Design tokens
   Paper:        #EEEEE7  soft, cool off-white (not the templated warm cream)
   Paper-deep:   #E3E2D9  card / recessed surface
   Ink:          #16160F  near-black text
   Ink-muted:    #6E6E62  secondary text
   Line:         #C9C7BA  hairline borders
   Signature:    #16160F  letterbox bars use ink, not a bright accent —
                 the signature is the cinema-frame + running timecode motif,
                 not a color.
   ========================================================================== */

:root{
  --paper: #EEEEE7;
  --paper-deep: #E3E2D9;
  --ink: #16160F;
  --ink-muted: #6E6E62;
  --line: #C9C7BA;

  --font-display: "Bricolage Grotesque", "Inter", sans-serif;
  --font-body: "Inter", sans-serif;
  --font-mono: "IBM Plex Mono", monospace;

  --container: 1240px;
  --gutter: clamp(20px, 5vw, 64px);

  /* --- Hero portrait tuning ---
     Turn these two knobs to reposition the photo without hunting
     through the stylesheet:
     --hero-image-width  bigger = bigger photo
     --hero-image-offset distance from the right edge —
                          SMALLER number = photo moves further left
                          (more overlap with the name), BIGGER number
                          = photo moves right (less/no overlap). */
  --hero-image-width: clamp(230px, 30vw, 400px);
  --hero-image-offset: calc(clamp(20px, 3.2vw, 60px) + 110px);

  /* Shifts name + role + photo left together as one group (px, positive = left). */
  --hero-shift-x: 100px;

  color-scheme: light;
}

*, *::before, *::after{ box-sizing: border-box; }

html{
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }
  *, *::before, *::after{ animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
}

body{
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

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

h1, h2, h3{
  font-family: var(--font-display);
  margin: 0;
  letter-spacing: -0.02em;
}

p{ margin: 0; }

.eyebrow{
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 1rem;
}
.eyebrow--light{ color: rgba(238,238,231,0.6); }

/* Scoped to the About section only — Work/Contact eyebrows stay as-is. */
.about .eyebrow{
  color: #b3402c;
}

.muted{ color: var(--ink-muted); font-weight: 400; }

/* subtle film-grain overlay for atmosphere, purely decorative */
.grain{
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 999;
  opacity: 0.035;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ==========================================================================
   Placeholder media blocks — clearly marked, easy to swap for real assets
   ========================================================================== */
.placeholder-media{
  position: relative;
  background:
    repeating-linear-gradient(135deg, var(--paper-deep), var(--paper-deep) 12px, var(--paper) 12px, var(--paper) 24px);
  border: 1px solid var(--line);
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  overflow: hidden;
}

/* Work-section placeholders get the same phone frame as finished clips
   (see .project__still--video and .phone-frame__screen) — the striped
   pattern and border move to the inner content box (.phone-frame__inner
   --placeholder, defined further down), since this outer box is now the
   full frame shape, not the visible content area. */
.placeholder-media.project__still{
  aspect-ratio: 4 / 5;
  overflow: visible;
  border: none;
  background: none;
  transition: transform 0.25s ease, filter 0.3s ease, opacity 0.4s ease, translate 0.4s cubic-bezier(.22,1,.36,1);
}
.placeholder-media__mark{
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
  background: var(--paper);
  padding: 0.3em 0.6em;
  margin: 0.75rem;
  border: 1px solid var(--line);
}

/* ==========================================================================
   Nav
   ========================================================================== */
.nav{
  position: sticky;
  top: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.25rem var(--gutter);
  background: linear-gradient(to bottom, rgba(238,238,231,0.92), rgba(227,226,217,0.92));
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}

.nav__mark{
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}

.nav__links{
  display: flex;
  gap: 2rem;
  font-size: 0.9rem;
}
.nav__links a{
  position: relative;
  padding-bottom: 2px;
}
.nav__links a::after{
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: 0;
  height: 1px;
  background: var(--ink);
  transition: right 0.25s ease;
}
.nav__links a:hover::after{ right: 0; }

.nav__right{
  display: flex;
  align-items: center;
  gap: 1rem;
}

.nav__rec{
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--ink-muted);
}
.nav__dot{
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #b3402c;
  animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse{
  0%, 100%{ opacity: 1; }
  50%{ opacity: 0.25; }
}

.nav__toggle{
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.5rem;
}
.nav__toggle span{
  width: 22px; height: 1.5px;
  background: var(--ink);
}

/* Language toggle — shows the language you'd switch TO, not the current
   one (so "DE" while browsing in English, "EN" while browsing in German). */
.lang-toggle{
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  background: none;
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0.3em 0.6em;
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.lang-toggle:hover{
  color: var(--ink);
  border-color: var(--ink);
}
.lang-toggle--mobile{ margin-top: 0.5rem; }

/* ==========================================================================
   Hero — cinema letterbox frame is the signature element
   ========================================================================== */
.hero{
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0;
  overflow: hidden;
}

.hero__bar{
  background: var(--ink);
  color: var(--paper);
  z-index: 3;
}
.hero__bar--top{ height: clamp(14px, 3vw, 28px); }
.hero__bar--bottom{
  height: clamp(34px, 5vw, 48px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--gutter);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
}

.hero__frame{
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 4rem var(--gutter);
}

.hero__portrait{
  position: absolute;
  /* Horizontal position (left) is computed and kept in sync with the
     title's actual rendered edge by main.js — title font-size and this
     image's own width each scale with vw independently, so a fixed
     right-edge offset let the gap between them drift depending on the
     viewport width. Right stays as a fallback for the instant before JS runs. */
  right: var(--hero-image-offset);
  top: 50%;
  transform: translateY(calc(-50% - 20px));
  z-index: 0;
  width: var(--hero-image-width);
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: top center;
}

.hero__title{
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  font-weight: 800;
  font-size: clamp(3.2rem, 12vw, 9rem);
  line-height: 0.92;
  mix-blend-mode: difference;
  color: #fff;
  text-align: center;
  transform: translateX(calc(-1 * var(--hero-shift-x)));
}

.hero__role{
  position: relative;
  z-index: 2;
  margin-top: 1.5rem;
  text-align: center;
  transform: translateX(calc(-1 * var(--hero-shift-x)));
  font-family: var(--font-mono);
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  color: var(--ink);
  background: var(--paper);
  display: inline-block;
  align-self: center;
  padding: 0.4em 0.9em;
  border: 1px solid var(--line);
}

.hero__cta{
  position: relative;
  z-index: 2;
  margin-top: 1.25rem;
  transform: translateX(calc(-1 * var(--hero-shift-x) + 10px));
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  color: var(--paper);
  background: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 8px;
  padding: 0.7em 1.4em;
  transition: color 0.2s ease, background 0.2s ease;
}
.hero__cta:hover{ color: var(--ink); background: var(--paper); }
.hero__cta span{ transition: transform 0.2s ease; display: inline-block; }
.hero__cta:hover span{ transform: translateY(2px); }

/* ==========================================================================
   About + Stats
   ========================================================================== */
.about{
  padding: clamp(1.75rem, 4vw, 3rem) var(--gutter) clamp(1rem, 3vw, 1.75rem);
  max-width: var(--container);
  margin: 0 auto;
  /* Leaves the hero's "SCENE 01" bar visible above the fold, and the
     section a bit of breathing room, when jumped to via the About nav link. */
  scroll-margin-top: clamp(70px, 10vh, 130px);
}

.about__sheet{
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: clamp(2rem, 6vw, 5rem);
}

.about__intro h2{
  font-size: clamp(1.4rem, 2.8vw, 2rem);
  font-weight: 600;
  line-height: 1.2;
  margin-bottom: 1rem;
}

.about__bio{
  color: var(--ink-muted);
  font-size: 0.96rem;
  line-height: 1.6;
  max-width: 46ch;
}

.about__portrait{
  width: min(160px, 45%);
  aspect-ratio: 4 / 5;
  margin-top: 1.25rem;
}

.stats{
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  align-self: stretch;
  gap: clamp(0.75rem, 1.5vw, 1.25rem);
  border-left: 1px solid var(--line);
  padding-left: clamp(1.5rem, 3vw, 3rem);
}

.stat{ text-align: center; }

.stat__value{
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(1.8rem, 3.6vw, 2.6rem);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  min-width: 4ch;
}

.stat__label{
  display: block;
  margin-top: 0.3rem;
  font-size: 0.8rem;
  color: var(--ink-muted);
  line-height: 1.3;
}

/* ==========================================================================
   Brands / Clients — placeholder logo wall
   Kept inside .about (not its own section) so intro copy, stats and logos
   all read as one screenful instead of requiring extra scrolling.
   ========================================================================== */
.about__brands{
  margin-top: clamp(1.25rem, 3vw, 2rem);
}

.about__brands .eyebrow{
  display: block;
  margin-bottom: 1rem;
}

/* One row that scrolls itself, endlessly — the track holds the logo set
   twice back to back, so looping at -50% is seamless. */
.brands__marquee{
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  margin: 0 calc(-1 * var(--gutter));
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%);
}

.brands__track{
  display: flex;
  width: max-content;
  animation: brands-marquee 30s linear infinite;
}
.brands__marquee:hover .brands__track{ animation-play-state: paused; }

.brands__set{ display: flex; }

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

.brand-logo{
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: clamp(90px, 10.5vw, 128px);
  height: clamp(48px, 5.25vw, 63px);
  border-right: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
  filter: grayscale(1);
  opacity: 0.7;
  transition: color 0.2s ease, opacity 0.2s ease;
}
.brand-logo:hover{ color: var(--ink); opacity: 1; filter: grayscale(0); }

.brand-logo__mark{
  max-width: 80%;
  max-height: 65%;
  object-fit: contain;
}

/* Scoped to the image, not the box — the logo bar's grid stays identical
   across all entries, only this one mark renders smaller within it. */
.brand-logo__mark--sm{
  max-width: 40%;
  max-height: 32.5%;
}
.brand-logo__mark--sm-slight{
  max-width: 64%;
  max-height: 52%;
}

/* ==========================================================================
   What I Bring — service pillars
   ========================================================================== */
.about__services{
  margin-top: clamp(1rem, 2.5vw, 1.5rem);
}

.about__services .eyebrow{
  display: block;
  margin-bottom: 0.75rem;
}

.services__grid{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(0.6rem, 1.5vw, 1rem);
}

.service{
  background: var(--paper-deep);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: clamp(1.1rem, 2vw, 1.5rem) clamp(0.9rem, 1.8vw, 1.25rem);
  text-align: center;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.service:hover{
  transform: translateY(-6px);
  box-shadow: 0 12px 24px -12px rgba(22,22,15,0.25);
}

.service__icon{
  display: flex;
  justify-content: center;
  color: var(--ink);
  margin-bottom: 0.9rem;
}
.service__icon svg{
  width: clamp(20px, 2.2vw, 26px);
  height: clamp(20px, 2.2vw, 26px);
  transition: transform 0.35s ease;
}
.service:hover .service__icon svg{ transform: scale(1.15) rotate(-6deg); }

.service__label{
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(0.88rem, 1.3vw, 1.02rem);
  letter-spacing: -0.01em;
  margin-bottom: 0.5rem;
}

.service__tagline{
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--ink-muted);
}

/* ==========================================================================
   Work / Projects grid
   ========================================================================== */
.work{
  padding: clamp(3rem, 8vw, 6rem) var(--gutter) clamp(5rem, 10vw, 8rem);
  max-width: var(--container);
  margin: 0 auto;
}

.work__head{
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.work__head h2{
  font-size: clamp(1.8rem, 4vw, 2.6rem);
  font-weight: 700;
}

/* Three independently swipeable rows of 9:16 video placeholders.
   .work itself is a centered, max-width reading column (like .about), but
   the rows break out of that to span the full viewport — otherwise, on a
   wide monitor, the reel sits in a narrow strip with a wall of empty page
   on either side, which reads as exactly the kind of "gap" this section is
   built to avoid. */
.work__rows{
  margin-top: 3rem;
  display: flex;
  flex-direction: column;
  /* The real separation lives here, between one row's group and the next —
     .work__group below keeps its own title snug against its own row, so
     the two never read as equally-spaced/ambiguous again. */
  gap: clamp(2.75rem, 6vw, 4.5rem);
  width: 100vw;
  margin-left: calc(-50vw + 50%);
}

.work__group{
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  /* A hairline + the row's own background tint visually bracket each
     group, reinforcing the title-to-row pairing beyond just spacing. */
  border-top: 1px solid var(--line);
  padding-top: clamp(1rem, 2.5vw, 1.5rem);
}
.work__group:first-child{ border-top: none; padding-top: 0; }

/* Styled like the section eyebrows (small, mono, muted) rather than a
   heading competing with "From the Cutting Room" — reads as a tag for
   the row directly beneath it, not a headline of its own. */
.work__row-title{
  margin: 0;
  padding: 0 var(--gutter);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* The row is a fixed-size window (overflow hidden); .work__track inside it
   holds the card set twice back-to-back and loops with the exact same
   technique as the logo marquee: a CSS keyframe animation to translateX(-50%).
   Since the two halves are identical, that loop point is mathematically
   exact — no JS-measured reset, so no risk of a visible seam. Hovering or
   dragging fully disables the animation and hands position to an inline
   transform (see main.js), then hands it back with a matching animation-delay
   so playback resumes from the exact same spot with no jump. */
.work__row{
  overflow: hidden;
  cursor: grab;
  -webkit-user-select: none;
  user-select: none;
  /* Extra top padding so the views badge (which already pokes slightly
     above its clip) doesn't get clipped when the whole card also lifts
     on hover — the row still needs overflow:hidden for the endless
     horizontal loop, so this headroom is the fix, not a looser overflow. */
  padding: 1rem var(--gutter) 0.75rem;
}
.work__row.is-dragging{ cursor: grabbing; }
.work__row.is-dragging .project{ pointer-events: none; }

.work__track{
  display: flex;
  --card-gap: clamp(0.5rem, 1.25vw, 0.75rem);
  width: max-content;
  will-change: transform;
  animation-name: work-marquee;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

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

.project{
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  width: 220px; /* fallback; JS sizes this so exactly 4 cards fill the row on wider screens */
  /* Spacing between cards lives on each card itself (like .brand-logo's
     border-right), not as a flex `gap` on the track — a `gap` would add
     one extra gap's worth of width between the doubled sets that -50%
     doesn't account for, causing a visible jump at the loop point. */
  margin-right: var(--card-gap, 1.5rem);
}
/* .work__track defaults to align-items: stretch, so a landscape card
   sharing a row with taller portrait ones would otherwise get stretched
   to match them, leaving dead space below its own (shorter) content. */
.project:has(.project__still--landscape){ align-self: flex-start; }

/* One-off: the first Recaps card sits bigger and lower than its row
   neighbors — a deliberate visual break from the otherwise-uniform grid. */
/* !important because .reveal.is-visible (this card is also a scroll-reveal
   target) sets its own transform at higher specificity once it scrolls
   into view, which would otherwise silently cancel this out. */
.project--featured{ transform: translateY(0) !important; }
.project--featured .project__title{ transform: translateY(-30px); }

.project__still{
  position: relative;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  border-radius: 14px;
  transition: filter 0.3s ease, opacity 0.4s ease, translate 0.4s cubic-bezier(.22,1,.36,1);
  -webkit-user-select: none;
  user-select: none;
}
.project__still img{ pointer-events: none; }

/* Cards start faded/dropped and pop up into place as they're swiped into
   the row's visible window (see the IntersectionObserver in main.js) —
   a separate `translate` (not `transform`) so it never fights with the
   hover-lift transform below. */
.project__still--pending{
  opacity: 0;
  translate: 0 18px;
}

.project__still--video{
  /* The clip now sits inside a phone frame image rather than filling this
     whole box edge-to-edge, so it takes the frame artwork's own 4:5 shape
     instead of the plain 9:16 still used elsewhere, and no longer clips or
     rounds itself — the frame image's own art supplies that outline. */
  aspect-ratio: 4 / 5;
  overflow: visible;
  border-radius: 0;
  background: none;
  -webkit-user-select: auto;
  user-select: auto;
  transition: transform 0.25s ease, box-shadow 0.25s ease, opacity 0.4s ease, translate 0.4s cubic-bezier(.22,1,.36,1);
}

/* Inset to match the phone-frame PNG's actual transparent "screen" cutout
   (measured directly from the artwork) so the clip lines up behind the
   bezel instead of just sitting somewhere inside it. */
/* A plain border-radius rectangle could never quite match the frame PNG's
   actual corner curve (gentle at the top, much sharper at the bottom) —
   too tight and the video pokes out past the bezel at the corners, too
   loose and a gap of background shows between video and bezel along the
   flat edges. Fixed properly instead: this mask is a same-size (1200x1500)
   black/white cutout of the frame's own screen shape (generated once from
   the PNG's actual alpha channel — see the project notes), so masking
   with it clips to the *exact* screen outline, corners included, with
   neither gap nor overflow regardless of how the curve behaves. */
.phone-frame__screen{
  position: absolute;
  inset: 0;
  -webkit-mask-image: url("../assets/images/iphone-frame-screen-mask.png");
  mask-image: url("../assets/images/iphone-frame-screen-mask.png");
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  /* Explicit, rather than relying on each browser's own default —
     Safari's -webkit-mask has always read the alpha channel; some other
     engines default new-spec mask-image to luminance instead. The asset
     itself now carries real alpha (not just grayscale) so both read it
     identically, and this pins that down further. */
  mask-mode: alpha;
}

/* The actual video/placeholder content sits in the true flat-edge screen
   rect (measured from the same artwork); the mask above then trims its
   square corners down to the real curve, so this box itself needs no
   border-radius of its own. */
.phone-frame__inner{
  position: absolute;
  top: 12%;
  left: 27.83%;
  right: 27.67%;
  bottom: 11.13%;
  background: #000;
}
.phone-frame__inner video{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Placeholders keep their striped "not-a-real-clip-yet" pattern, just
   inside the phone screen cutout instead of filling a plain 9:16 box. */
.phone-frame__inner--placeholder{
  background:
    repeating-linear-gradient(135deg, var(--paper-deep), var(--paper-deep) 12px, var(--paper) 12px, var(--paper) 24px);
  border: 1px solid var(--line);
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
}

/* Long Form clips are shot landscape (interviews/doku, not phone reels) —
   rather than cramming them into the portrait frame, the same frame is
   rotated 90° (both the artwork and its mask, generated the same way as
   the portrait one) so the phone lies on its side. Insets below are that
   rotated mask's own true flat-edge screen bounds, not a guess. */
.project__still--landscape{ aspect-ratio: 5 / 4; }
.phone-frame__screen--landscape{
  -webkit-mask-image: url("../assets/images/iphone-frame-screen-mask-landscape.png");
  mask-image: url("../assets/images/iphone-frame-screen-mask-landscape.png");
}
.phone-frame__inner--landscape{
  top: 27.67%;
  right: 12%;
  bottom: 27.83%;
  left: 12%;
}
/* Long Form's own footage isn't always cut to this exact 5:4 window —
   contain (not cover) so the top/bottom of the shot never gets cropped
   off; any leftover space lands on the sides as plain black bars instead,
   against the same #000 .phone-frame__inner already sits on. */
.phone-frame__inner--landscape video{ object-fit: contain; }

.phone-frame__image{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* Paint order against the masked video/controls doesn't actually matter
     anymore: .phone-frame__screen's mask already confines that content to
     the screen cutout, and this image is opaque only over the bezel — the
     two never occupy the same pixels. Kept above 0 mainly for clarity. */
  z-index: 1;
  pointer-events: none;
  user-select: none;
}

/* Custom, deliberately minimal controls: a centered play/pause button, a
   seek bar (no time readout), mute, and fullscreen — the native
   <video controls> bar also exposes a download option we don't want here.
   Both only appear on hover, and the clip keeps its color while hovered
   (no grayscale) so it reads as playable footage, not a dimmed thumbnail. */
.video-controls,
.video-controls__play--center{
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}
.project__still--video:hover .video-controls,
.project__still--video:hover .video-controls__play--center{
  opacity: 1;
  pointer-events: auto;
}

.video-controls{
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.65rem;
  background: linear-gradient(to top, rgba(0,0,0,0.65), rgba(0,0,0,0));
}

.video-controls__btn{
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  color: #fff;
  background: none;
  border: none;
  cursor: pointer;
}
.video-controls__btn svg{ width: 16px; height: 16px; }
/* Explicit class instead of the HTML [hidden] attribute — some browsers
   don't reliably apply [hidden]'s display:none to inline <svg> icons. */
.icon-hidden{ display: none !important; }

.video-controls__play--center{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgba(0,0,0,0.45);
}
.video-controls__play--center svg{ width: 22px; height: 22px; }

.video-controls__seek{
  position: relative;
  flex: 1 1 auto;
  height: 4px;
  background: rgba(255,255,255,0.35);
  border-radius: 2px;
  cursor: pointer;
}
.video-controls__seek-fill{
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: 0%;
  background: #fff;
  border-radius: 2px;
  pointer-events: none;
}

/* Instagram-style view count: an eye icon + abbreviated number in a small
   chip that sits right at the phone frame's own outer corner (not the still
   element's corner — that box is much bigger than the frame image drawn
   inside it, thanks to the transparent margin the frame PNG has around the
   phone shape), its own edge just overlapping past it so it visibly stands
   proud of the frame. */
/* Groups the views count and the Instagram link into one corner-anchored
   unit — sizing either badge individually never throws off their spacing
   or the group's overall position, since the wrapper is what's actually
   anchored to the phone's corner (see .project__views for each child's
   own look). */
.project__badges{
  position: absolute;
  top: calc(11.13% - 0.6rem);
  left: calc(26.9% - 0.6rem);
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.4em;
  transition: transform 0.25s ease;
}
.project__views{
  display: flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.3em 0.55em;
  background: rgba(238, 238, 231, 0.87);
  border: 1px solid var(--ink);
  border-radius: 6px;
  font-family: var(--font-body);
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--ink);
  transition: box-shadow 0.25s ease;
}
.project__instagram{
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.15rem;
  height: 2.15rem;
  flex: 0 0 auto;
  background: rgba(238, 238, 231, 0.87);
  border: 1px solid var(--ink);
  border-radius: 6px;
  color: var(--ink);
  transition: box-shadow 0.25s ease;
}
.project__instagram svg{ width: 16px; height: 16px; }
.project:hover .project__badges{ transform: translateY(-6px); }
.project:hover .project__views,
.project:hover .project__instagram{
  box-shadow: 0 12px 24px -12px rgba(22,22,15,0.25);
}
.project:hover .project__still--video,
.project:hover .placeholder-media.project__still{
  transform: translateY(-6px);
}
.project:hover .project__still--video{
  /* box-shadow would be clipped by this element's own overflow:hidden
     (needed to keep the video's corners rounded) — filter's drop-shadow
     is computed after that clipping, so it isn't cut off. */
  filter: drop-shadow(0 12px 20px rgba(22,22,15,0.35));
}
.project:hover .placeholder-media.project__still{
  /* Keeps its own grayscale-on-hover cue (it's not real footage yet) and
     adds the same drop-shadow lift as the framed videos. */
  filter: contrast(1.05) saturate(0) drop-shadow(0 12px 20px rgba(22,22,15,0.35));
}
.project__views-icon{ width: 17px; height: 17px; flex: 0 0 auto; }

/* Long Form's rotated frame puts its bezel corner at different fractions
   than the portrait one (see .phone-frame__inner--landscape) — the badge
   needs the same swap to still land on the actual corner. */
.project__badges--landscape{
  top: calc(26.67% - 0.6rem);
  left: calc(11.13% - 0.6rem);
}

/* Title + location placeholder under each card — swap the text for the
   real clip title and shoot location once known (see .project__title /
   .project__location in the markup). */
.project__meta{
  margin-top: -55px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.3rem;
}
.project__title{
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink);
}
.project__location{
  display: flex;
  align-items: center;
  gap: 0.35em;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--ink-muted);
}
.project__location-icon{ width: 13px; height: 13px; flex: 0 0 auto; }

/* "Fullscreen" focus mode for Work clips — a custom in-page lightbox
   instead of the real Fullscreen API: the clip grows and centers itself
   over a dimmed backdrop, then shrinks back into its row slot on toggle. */
.video-focus-overlay{
  position: fixed;
  inset: 0;
  z-index: 150;
  background: rgba(20, 20, 20, 0.78);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.video-focus-overlay.is-active{
  opacity: 1;
  pointer-events: auto;
}

.project__still--video.is-focused{
  z-index: 200;
  transition: top 0.32s ease, left 0.32s ease, width 0.32s ease, height 0.32s ease;
}

/* The view-count/Instagram badge group rides along with its clip into/out
   of focus mode, at the same corner-anchored offset (see enterFocus/
   exitFocus in main.js), so it stays visible over the enlarged video too. */
.project__badges.is-focused-badge{
  transition: top 0.32s ease, left 0.32s ease;
}

/* Mobile focus mode is true edge-to-edge fullscreen, not the enlarged
   phone-mockup desktop gets — you're already looking at a phone, so a
   phone-shaped preview of the video doesn't add anything there. Scoped to
   the same breakpoint main.js uses for its own mobile check, and only to
   the *focused* state, so the normal in-row card look is untouched. */
@media (max-width: 860px){
  .project__still--video.is-focused .phone-frame__image{ display: none; }
  .project__still--video.is-focused .phone-frame__screen{
    -webkit-mask-image: none;
    mask-image: none;
  }
  .project__still--video.is-focused .phone-frame__inner{
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
  }
  .project__badges.is-focused-badge{ display: none; }
}

.project__play{
  position: absolute;
  right: 0.75rem;
  bottom: 0.75rem;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 8px 0 8px 13px;
  border-color: transparent transparent transparent var(--ink);
  opacity: 0;
  transform: translateX(6px);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.project__still .project__year{
  position: absolute;
  top: 0.6rem;
  left: 0.6rem;
}

.project:hover .project__still:not(.project__still--video):not(.placeholder-media){ filter: contrast(1.05) saturate(0); }
.project:hover .project__play{ opacity: 0.85; transform: translateX(0); }

.project__year{
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  background: var(--paper);
  border: 1px solid var(--line);
  padding: 0.2em 0.5em;
}

/* ==========================================================================
   Contact — inverted letterbox bookend to mirror the hero
   ========================================================================== */
.contact{
  position: relative;
  background: var(--ink);
  color: var(--paper);
  padding: clamp(5rem, 12vw, 9rem) var(--gutter);
  text-align: center;
  overflow: hidden;
}

.contact__bar{
  position: absolute;
  left: 0; right: 0;
  height: clamp(14px, 3vw, 28px);
  background: var(--paper);
}
.contact__bar--top{ top: 0; }
.contact__bar--bottom{ bottom: 0; }

.contact__title{
  font-size: clamp(2.4rem, 7vw, 4.5rem);
  font-weight: 800;
  line-height: 1.02;
  margin-bottom: 2rem;
}

.contact__email{
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: clamp(0.75rem, 1.65vw, 0.975rem);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--paper);
  border-radius: 8px;
  padding: 0.45em 0.975em;
  transition: color 0.2s ease, background 0.2s ease;
}
.contact__email:hover{ color: var(--paper); background: transparent; }

.contact__socials{
  margin-top: 2.5rem;
  display: flex;
  justify-content: center;
  gap: 2rem;
  font-size: 0.85rem;
  letter-spacing: 0.03em;
}
.contact__socials a{ opacity: 0.7; transition: opacity 0.2s ease; }
.contact__socials a:hover{ opacity: 1; }

/* ==========================================================================
   Footer
   ========================================================================== */
.footer{
  display: flex;
  justify-content: space-between;
  padding: 1.5rem var(--gutter);
  font-size: 0.78rem;
  color: var(--ink-muted);
  background: var(--paper);
}

/* ==========================================================================
   Scroll reveal
   ========================================================================== */
.reveal{
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.reveal.is-visible{
  opacity: 1;
  transform: translateY(0);
}

/* ==========================================================================
   Focus visibility (accessibility floor)
   ========================================================================== */
a:focus-visible, button:focus-visible{
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* ==========================================================================
   Responsive
   ========================================================================== */
/* Mobile menu overlay — a sibling of .nav (not nested in it), so the
   header's position:sticky never becomes its containing block. */
.nav__mobile{
  display: none;
}

@media (max-width: 860px){
  .nav__links{ display: none; }

  .nav__mobile{
    display: flex;
    position: fixed;
    top: 4.2rem;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--paper);
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2rem;
    font-size: 1.4rem;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.25s ease;
    z-index: 90;
  }
  .nav__mobile.is-open{
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
  }

  .nav__right{ display: none; }
  .nav__toggle{ display: flex; }

  .about__sheet{ grid-template-columns: 1fr; }
  .stats{ border-left: none; border-top: 1px solid var(--line); padding-left: 0; padding-top: 2rem; flex-direction: row; flex-wrap: wrap; }

  .services__grid{ grid-template-columns: repeat(2, 1fr); }

  .brand-logo{ width: clamp(90px, 25.5vw, 120px); height: clamp(53px, 13.5vw, 68px); }

  .project{ width: min(48vw, 200px); }

  /* Titles 25% smaller on mobile; pulled down 20px, but only for portrait
     (Recaps / Cinematic Reels) cards — Long Form's landscape cards keep
     their original tighter pull-up untouched. */
  .project__title{ font-size: 0.7125rem; }
  .project:not(:has(.project__still--landscape)) .project__meta{ margin-top: -35px; }

  /* Landscape (phone-framed) cards, mobile only: Long Form's row 25%
     smaller; the one landscape card in Recaps (.project--featured) 50%
     smaller. */
  [data-row="3"] .project{ width: calc(min(48vw, 200px) * 0.75 * 0.75); }
  .project--featured{ width: calc(min(48vw, 200px) * 0.5 * 0.5); }

  .hero__bar--bottom{ font-size: 0.62rem; }

  /* Stack portrait above the name instead of overlapping it beside/behind it */
  .hero__frame{
    flex-direction: column;
    gap: 1.5rem;
    padding: 2.5rem var(--gutter) 3rem;
  }
  .hero__portrait{
    position: static;
    transform: none;
    width: min(58vw, 260px);
    margin: 0 auto;
    border: 1px solid var(--line);
  }
  .hero__title{ order: 2; transform: none; }
  .hero__role{ order: 3; transform: none; }
  .hero__cta{ order: 4; transform: none; }
}

/* ==========================================================================
   Legal (Impressum / Datenschutz)
   ========================================================================== */
.legal{
  padding: clamp(6rem, 10vw, 8rem) var(--gutter) 4rem;
}
.legal__sheet{
  max-width: 72ch;
  margin: 0 auto;
}
.legal__back{
  display: inline-block;
  margin-bottom: 2.5rem;
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--ink-muted);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.legal__back:hover{
  color: var(--ink);
  border-color: var(--ink);
}
.legal__back--bottom{ margin-top: 3rem; margin-bottom: 0; }

.legal h1{
  font-size: clamp(1.8rem, 4vw, 2.5rem);
  margin-bottom: 0.5rem;
}
.legal__lead{
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--ink-muted);
  margin-bottom: 2.5rem;
}
.legal h2{
  font-family: var(--font-display);
  font-size: 1.1rem;
  letter-spacing: -0.01em;
  margin-top: 2.5rem;
  margin-bottom: 0.75rem;
}
.legal p{
  margin-bottom: 1rem;
  line-height: 1.7;
  color: var(--ink);
}
.legal ul{
  margin: 0 0 1rem;
  padding-left: 1.25rem;
  line-height: 1.7;
}
.legal li{ margin-bottom: 0.35rem; }
.legal a{
  text-decoration: underline;
  text-underline-offset: 2px;
}
.legal__rule{
  border: none;
  border-top: 1px solid var(--line);
  margin: 3.5rem 0;
}
.legal__note{
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: 0.85rem;
  color: var(--ink-muted);
}

@media (max-width: 640px){
  .legal{ padding-top: 7rem; }
}
