/* -----------------------------------------------------------
   DE QUEIROZ VON BREMEN
   Reset & base
------------------------------------------------------------ */
@font-face {
  font-family: "ABC Schengen Mono";
  src: url("fonts/ABCSchengenAMono-Thin.woff2") format("woff2");
  font-weight: 100;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "ABC Schengen Mono";
  src: url("fonts/ABCSchengenAMono-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

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

::selection {
  background: rgba(255, 255, 255, 0.50);
  color: inherit;
}

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #000;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  font-family: "ABC Schengen Mono", ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Monaco, Consolas, monospace;
  font-size: 11px;
  font-weight: 100;
  line-height: 1.3;
  /* 90% instead of solid white — every text element inherits this
     (color cascades, unlike opacity), so it's a touch softer everywhere
     without dimming non-text content (images, blend-mode boxes) too. */
  color: rgba(255, 255, 255, 0.9);
  -webkit-font-smoothing: antialiased;
  cursor: pointer;
}

button {
  font-family: inherit;
  font-weight: inherit;
  font-size: inherit;
  color: inherit;
  border: none;
  background: none;
  cursor: pointer;
}

a {
  color: inherit;
}

/* -----------------------------------------------------------
   About zone (top strip) — wraps the studio name and the About
   content. On desktop, hovering just the studio name (see the
   mousemove-based trigger logic in script.js) opens it; on touch,
   tapping it does. Purely a layout container otherwise — it no
   longer drives the hover/open state itself.
------------------------------------------------------------ */
#about-zone {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 40;
  max-width: 1200px;
  padding: max(20px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-right))
    26px max(20px, env(safe-area-inset-left));
}

/* Positioned absolutely (out of #about-zone's flow) so #about-content
   below can start flush with it — its INFO/CLIENTS/SERVICES column
   headings sit on the same line as the studio name, rather than below
   it. Column 1 (which the name visually sits above) clears it via its
   own padding-top instead. */
#studio-name {
  position: absolute;
  top: max(20px, env(safe-area-inset-top));
  left: max(20px, env(safe-area-inset-left));
  /* #about-content comes after it in the DOM and, once open, its column
     1 padding-top (there to visually clear the name) still overlaps
     this box for hit-testing purposes — without a z-index, that later
     paint order would put the (now interactive) content on top and
     swallow hover/touch meant for the name underneath it. */
  z-index: 1;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-align: left;
  mix-blend-mode: difference;
  user-select: text;
  pointer-events: auto;
  transition: opacity 0.4s ease-out;
}

/* Scoped to real hover so tapping on touch can't trigger this via
   mobile Safari's "sticky :hover after tap" — there's no active/press
   dimming there at all now, only this genuine mouse-hover fade. */
@media (hover: hover) and (pointer: fine) {
  #studio-name:hover {
    opacity: 0.5;
  }
}

/* Difference blend inverts per-channel against whatever color sits behind
   the text, so the result can read as tinted even though the text itself
   is achromatic. backdrop-filter samples the already-composited pixels
   (media ⊕ difference-text) in this exact box and desaturates only that —
   the difference blend mode itself is left completely untouched.
   (#project-info's title/subtitle/description use filter:grayscale(1)
   on their shared parent instead — see there for why.) */
#studio-name::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  backdrop-filter: saturate(0);
  -webkit-backdrop-filter: saturate(0);
}

span.kern {
  letter-spacing: 1px;
}

/* Studio name starts out reduced to its initials; the remaining letters
   fade in together with the About content. opacity (not display/visibility)
   keeps their width reserved so the initials don't shift when revealed. */
#studio-name .label-default .letter-rest {
  opacity: 0;
  transition: opacity 0.9s ease-out;
}

/* #about-content stays in the layout (visibility:hidden, not display:none)
   even while closed, so script.js can always read its real geometry —
   but that box can reach almost full height, and would otherwise
   silently swallow clicks/hovers meant for the stage (gallery
   navigation) or #project-info (description reveal) underneath it.
   Make the zone click/hover-through by default and only opt back in
   the pieces that must stay interactive: the studio name always (it's
   the only thing that opens About, on both hover and tap), and the
   About content once it's actually open. */
#about-zone {
  pointer-events: none;
    -webkit-user-drag: none;
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
}

body.about-open #studio-name .label-default .letter-rest {
  opacity: 1;
}

/* -----------------------------------------------------------
   Stage — full viewport container for current + peek media
------------------------------------------------------------ */
/* No explicit height here on purpose: a position:fixed element with
   inset:0 and no explicit height/width resolves to the full (large)
   viewport in Safari, bleeding under the toolbar even when it's shown.
   An explicit height (including 100dvh) ties sizing to whatever the
   toolbar's current state is instead, and since this page never
   scrolls, that toolbar never auto-collapses — so the stage would
   stay stuck at the shorter height forever. */
#stage {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: #000;
  touch-action: none;
}

/* Each stop is a persistent, permanently-mounted media layer.
   Position/size/z-index are driven by script.js; nothing here
   animates or transitions — only the entering stop's own filter/
   opacity is animated (via the Web Animations API in script.js),
   so every other layer stays instantly sharp and in place. */
.media-stop {
  position: absolute;
  top: 0;
  left: 0;
}

.media-stop img,
.media-stop video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center; /* keep the subject centred when cropped */
  display: block;
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
}

/* -----------------------------------------------------------
   Project title / subtitle — vertically centered, left edge
------------------------------------------------------------ */
/* mix-blend-mode lives on the title/subtitle/description themselves
   (below), not here — filter:grayscale(1) on this shared parent then
   desaturates their already-differenced result as a unit. This is the
   part that actually keeps them colourless: backdrop-filter (used for
   the same purpose on #studio-name) turned out not to reliably sample
   the composited result when nested inside an ancestor that itself has
   mix-blend-mode — it was leaving the difference blend's raw colour
   (e.g. bright orange backdrops differencing to a vivid blue) showing
   straight through. filter, applied one level up from the blend, does
   not have that problem. */
#project-info {
  position: fixed;
  left: max(20px, env(safe-area-inset-left));
  top: 50%;
  transform: translateY(-50%);
  z-index: 30;
  max-width: 40vw;
  filter: grayscale(1);
  transition: opacity 0.5s ease;
  cursor: crosshair;
}

#project-title,
#project-subtitle {
  mix-blend-mode: difference;
}

#project-info h1,
#project-info p {
  font-size: 11px;
  font-weight: 100;
  line-height: 1.3;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

#project-info.description-open #project-title,
#project-info.description-open #project-subtitle {
  font-weight: 500;
}

@media (hover: hover) and (pointer: fine) {
  #project-info:hover #project-title,
  #project-info:hover #project-subtitle {
    font-weight: 500;
  }
}

/* Short project description — hidden until #project-info is hovered
   (desktop) or tapped, toggling the .description-open class (touch —
   see script.js). No blur here, just a quick reveal (unlike the
   About content).
   Positioned absolutely, directly under the title/subtitle with no
   gap, so it doesn't add to #project-info's own height — title and
   subtitle stay put instead of shifting as the description reveals.
   width is set to #project-info's own max-width (40vw) explicitly,
   rather than 100% of it — #project-info itself shrinks to fit the
   title/subtitle (often much narrower than 40vw), which was capping
   the description to that same narrow width and cutting words off
   mid-wrap; this lets it run wider, independent of how short the
   title happens to be. */
/* Opacity always fades over 1s, in both directions. max-height instead
   snaps — but WHEN it snaps depends on direction, via transition-delay:
   opening (below) snaps it to 220px instantly, before the fade-in even
   starts, so every line is already laid out while still invisible
   (rather than the multi-line text revealing top-to-bottom as a growing
   max-height would otherwise uncover each line in turn). Closing snaps
   it back to 0 only once the fade-out's 1s has fully elapsed (the delay
   here), so the box doesn't clip the text away mid-fade — it just
   collapses after it's already invisible. */
#project-description {
  position: absolute;
  top: 100%;
  left: 0;
  width: 40vw;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  mix-blend-mode: difference;
  transition: opacity 1s ease, max-height 0s ease 1s;
}

#project-description:empty {
  display: none;
}

#project-description a {
  text-decoration: none;
  transition: opacity 0.4s ease;
}

#project-description a:hover {
  opacity: 0.5;
}

#project-info.description-open #project-description {
  max-height: 220px;
  opacity: 1;
  transition: opacity 1s ease, max-height 0s ease;
}

/* Scoped to real hover for the same reason as #studio-name above: on
   touch, tapping #project-info can leave CSS in a "stuck" :hover state
   until the next tap lands elsewhere, which — if this rule applied
   unconditionally — would keep the description visibly open even after
   the JS toggle (touchend, below) has already removed .description-open,
   making a second tap on the same spot look like it did nothing. Touch
   devices rely entirely on the JS-driven class instead. */
@media (hover: hover) and (pointer: fine) {
  #project-info:hover #project-description {
    max-height: 220px;
    opacity: 1;
    transition: opacity 1s ease, max-height 0s ease;
  }
}

body.about-open #project-info {
  opacity: 0;
  pointer-events: none;
}

/* -----------------------------------------------------------
   About backdrop — full-screen blur/dim layer shown behind the
   About content while it's open. Purely visual; also catches
   outside clicks/taps to close on touch devices.
------------------------------------------------------------ */
#about-backdrop {
  position: fixed;
  inset: 0;
  z-index: 20;
  background: rgba(10, 10, 10, 0.45);
  backdrop-filter: blur(28px) saturate(120%);
  -webkit-backdrop-filter: blur(28px) saturate(120%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.8s ease, visibility 0s linear 0.8s;
}

body.about-open #about-backdrop {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 1.2s ease-out, visibility 0s linear 0s;
}

/* -----------------------------------------------------------
   About content — 4-column grid inside #about-zone. Columns 1, 3 and
   4 shrink-to-fit their own widest line (the email address, longest
   client, longest service — so the gap to the next column always
   reads as the same 30px, not that plus whatever slack a fixed
   fraction left over); column 2 (the intro text) takes the rest.
   Hidden via opacity/visibility rather than display:none so it
   still has real, measurable geometry the instant it opens (the
   hover logic in script.js reads its bounding box).
------------------------------------------------------------ */
/* max-height lets it use effectively the full viewport height (not
   the old, tightly-capped band) — on narrow/short screens it must
   not be cropped. Content that doesn't fit simply scrolls, and
   scrolling all the way through it closes About (see script.js). */
#about-content {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr) max-content max-content;
  column-gap: 40px;
  row-gap: 14px;
  width: 100%;
  max-height: calc(100vh - 56px);
  overflow-y: auto;
  /* Reserves room for the scrollbar (Safari's classic, non-overlay
     style is ~15px) so it sits in its own gutter at the true right
     edge instead of overlapping the last column's text. */
  scrollbar-gutter: stable;
  padding-right: 16px;
  text-transform: uppercase;
  align-items: start;
  opacity: 0;
  visibility: hidden;
  /* Pointer here (not crosshair) — clicking this empty space closes
     About (see script.js); .about-col overrides back to crosshair for
     the actual text, matching the rest of the site's reading cursor. */
  cursor: pointer;
  pointer-events: none;
  transition: opacity 1.2s ease-out, visibility 0s linear 1.2s;
  user-select: text;
  -webkit-user-select: text;
}

body.about-open #about-content {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 1.2s ease-out, visibility 0s linear 0s;
}

/* Column 1 sits below the studio name, which is positioned
   absolutely above it — clear its height instead of the flow
   margin the other columns use to align with it. */
.about-col-1 {
  padding-top: 24px;
}

.about-col p,
.about-col li {
  font-size: 11px;
  font-weight: 100;
  line-height: 1.3;
  letter-spacing: 0.02em;
}

.about-col {
  margin-bottom: 14px;
}

.about-col p:last-child {
  margin-bottom: 0;
}

.about-col .about-col-label {
  letter-spacing: 0.02em;
  margin-bottom: 10px;
}

.about-col ul {
  list-style: none;
  padding: 0;
}

.about-col a {
  text-decoration: none;
  opacity: 1;
  transition: opacity 0.4s ease;
}

.about-col a:hover {
  opacity: 0.5;
}

/* -----------------------------------------------------------
   Legal toggle
------------------------------------------------------------ */
/* One line of space above the button, separating it from the contact
   block above it — desktop only, since #legal-group instead sits after
   Services on mobile, where its usual .about-col spacing already
   applies (see the mobile media query, which zeroes this back out). */
#legal-group {
  margin-top: 14px;
}

#legal-toggle {
  cursor: pointer;
  display: flex;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: 11px;
  line-height: 1.3;
  opacity: 1;
  transition: opacity 0.4s ease;
}

#legal-toggle:hover {
  opacity: 0.5;
}

/* Only opacity transitions — height/margin snap to their final value
   instantly, so the text has no position/size transition, just a fade.
   contain:inline-size keeps its longest line (e.g. "Represented by:
   ...", wider than the email address) from ever counting toward
   column 1's max-content grid sizing, expanded or not — without it,
   opening Legal Notice would widen column 1 (and shove every column
   after it sideways) the moment its full-width line became part of
   the layout again. */
#legal-text {
  max-height: 0;
  margin-top: 0;
  contain: inline-size;
  opacity: 0;
  overflow: hidden;
  font-size: 11px;
  line-height: 1.3;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  transition: opacity 0.5s ease;
}

#legal-text.visible {
  max-height: 200px;
  margin-top: 14px;
  width: auto;
  opacity: 1;
}

#legal-text a {
  text-decoration: none;
  transition: opacity 0.4s ease;
}

#legal-text a:hover {
  opacity: 0.5;
}

/* -----------------------------------------------------------
   Mobile
------------------------------------------------------------ */
@media (max-width: 900px) {
  #project-info {
    max-width: 70vw;
  }

  /* Matches the About intro text's own right boundary — same left
     offset (#project-info sits at the same max(20px, safe-area) inset
     as #about-zone) and the same 36px + safe-area-inset-right margin
     #about-content keeps on the right — so the description can run
     exactly as wide as that column, not an arbitrary vw fraction. */
  #project-description {
    width: calc(
      100vw - max(20px, env(safe-area-inset-left)) - env(safe-area-inset-right) -
        36px
    );
  }

  /* About: Spalten untereinander */
  /* padding-top and padding-right have no 20px floor (unlike the other
     two sides) — #studio-name is positioned absolutely and already
     keeps its own max(20px, safe area) offset independently, but
     #about-content is a normal-flow child, so whatever padding sits
     here is where its (masked) top edge, and its scrollbar's right
     edge, actually land. Only the safe-area inset remains on both, so
     the top fade genuinely begins at the screen edge instead of 20px
     below it, and — more importantly — the scrollbar renders flush
     against the true right edge instead of sitting 20px in from it.
     #about-content's own padding-right (below) restores the visual
     margin between the text and that edge. */
  #about-zone {
    padding-top: env(safe-area-inset-top);
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: env(safe-area-inset-right);
    padding-bottom: 20px;
  }

  #studio-name {
    top: max(20px, env(safe-area-inset-top));
    left: max(20px, env(safe-area-inset-left));
  }

  #about-content {
    grid-template-columns: 1fr;
    /* Restores the ~20px right-hand margin #about-zone no longer
       provides (see above) on top of the scrollbar's own 16px gutter,
       so the text still sits comfortably clear of the edge while the
       scrollbar itself renders flush against it. */
    padding-right: 36px;
    /* Fades scrolled content out at the top and bottom edge of the box
       instead of letting it cut off hard right under the (sticky,
       absolutely-positioned) studio name — it stays legible on top
       rather than visually colliding with the text scrolling past it.
       #about-zone's padding-top is now just the safe-area inset (see
       above), so this box's top edge — and this fade — starts right at
       the screen edge; the fade still resolves to fully opaque by 20px,
       inside column 1's own 24px clearance above its text, so nothing
       looks faded before any scrolling happens. */
    -webkit-mask-image: linear-gradient(
      to bottom,
      transparent 0,
      black 64px,
      black calc(100% - 56px),
      transparent 100%
    );
    mask-image: linear-gradient(
      to bottom,
      transparent 0,
      black 64px,
      black calc(100% - 56px),
      transparent 100%
    );
  }

  /* More headroom than the desktop 24px: #about-zone's padding-top is
     just the safe-area inset here (see above), so #studio-name (still
     at its own ~20-34px offset) and the top fade (opaque by 56px) both
     need column 1's text pushed further down to clear them, instead of
     landing right underneath the name. */
  .about-col-1 {
    padding-top: 60px;
  }

  /* #legal-group sits after Services here (see script.js), so its own
     .about-col spacing is what separates it from the column above —
     the extra desktop-only gap above the button would be redundant. */
  #legal-group {
    margin-top: 0;
  }

  /* Its space is already reserved at rest — scrolling to the bottom
     reaches exactly as far as it would once expanded, so there's
     already room waiting the moment Legal Notice is tapped, instead of
     the scrollable area growing only after the fact. Only opacity
     toggles the text itself in and out within that space. */
  #legal-text {
    max-height: 200px;
    margin-top: 14px;
    width: auto;
    margin-bottom: 28px;
  }
}
