/* ------------------------------------------------------------------
   a plus a studio — site styles

   Metrics taken off the design screenshots:
     content column 977px, 4 columns, 23px column gap, 29.5px row gap
     type: Outfit — body 13.5/17, titles 17/20, nav 16.5, footer 12
     body copy is justified; every image is greyscale until hovered
------------------------------------------------------------------ */

:root {
  --content: 977px;
  --col-gap: 23px;
  --row-gap: 29.5px;

  --ink: #111111;      /* headings, active nav */
  --body: #3a3a3a;     /* body copy */
  --muted: #9b9b9b;    /* inactive nav */
  --rule: #c2c2c2;     /* footer hairline */

  --fs-body: 13.5px;
  --lh-body: 17px;
  --fs-title: 17px;
  --lh-title: 20px;
  --fs-nav: 16.5px;
  --fs-foot: 12px;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* Always reserve the scrollbar gutter. Without it a short page (Projekte)
     has no scrollbar while a long one does, and the centred column jumps
     sideways by half a scrollbar width when navigating between them. */
  scrollbar-gutter: stable;
}

@supports not (scrollbar-gutter: stable) {
  html { overflow-y: scroll; }
}

body {
  margin: 0;
  background: #ffffff;
  color: var(--body);
  font-family: 'Outfit', 'Century Gothic', 'Futura', 'Trebuchet MS', sans-serif;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

/* ---------- page shell — footer is pushed to the bottom of the window ---------- */

.page {
  width: min(var(--content), calc(100% - 48px));
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* ---------- header ----------
   Pinned while scrolling. The space above the logo lives in the header's own
   padding, and the negative `top` lets exactly that padding scroll away before
   the bar sticks — so the resting layout is untouched, the pinned bar is only
   as tall as it needs to be, and nothing reflows when it sticks. */

.site-head {
  position: sticky;
  top: -45px;              /* 57px padding − 12px kept above the logo */
  z-index: 10;
  padding: 57px 0 16px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;

  background: transparent;
}

/* Frosted glass spanning the full window width, so nothing shows through
   sharp beside the 977px column.
   It is always on rather than toggled by a class: against the white page a
   34% white tint over white *is* white, so it is invisible at rest — and
   being CSS-only, a script failure can never leave the nav text sitting
   unreadable on a photograph.
   The bottom third fades out via a mask, so the blur has no hard edge where
   it meets the sharp content below. */
.site-head::before {
  content: "";
  position: absolute;
  top: 0;
  /* reaches past the bar so the fade happens *below* the menu rather than
     across it — the logo and links sit in the fully opaque part. At rest this
     overhang lands in the empty margin above the content, so it is invisible. */
  bottom: -54px;
  left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  z-index: -1;
  pointer-events: none;
  background: rgba(255, 255, 255, 0.58);
  -webkit-backdrop-filter: saturate(180%) blur(22px);
  backdrop-filter: saturate(180%) blur(22px);

  /* Fully opaque across the bar itself, then an ease-out dissolve through the
     overhang. A two-stop gradient would leave a visible knee where the ramp
     starts; these stops read as a smooth falloff. */
  -webkit-mask-image: linear-gradient(to bottom,
      #000 0%, #000 64%, rgba(0,0,0,0.96) 70%, rgba(0,0,0,0.88) 76%,
      rgba(0,0,0,0.73) 82%, rgba(0,0,0,0.54) 87%, rgba(0,0,0,0.34) 92%,
      rgba(0,0,0,0.17) 96%, rgba(0,0,0,0.05) 98.5%, rgba(0,0,0,0) 100%);
  mask-image: linear-gradient(to bottom,
      #000 0%, #000 64%, rgba(0,0,0,0.96) 70%, rgba(0,0,0,0.88) 76%,
      rgba(0,0,0,0.73) 82%, rgba(0,0,0,0.54) 87%, rgba(0,0,0,0.34) 92%,
      rgba(0,0,0,0.17) 96%, rgba(0,0,0,0.05) 98.5%, rgba(0,0,0,0) 100%);
}

/* without backdrop-filter, translucency would just look washed out */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .site-head::before {
    background: #ffffff;
    -webkit-mask-image: none;
    mask-image: none;
  }
}

/* No hairline: the glass now fades out well below the bar, so a line at the
   bar's own edge would cut straight through the gradient. */

.logo { display: block; }
.logo img { width: 115px; height: 56px; }

.site-nav {
  position: relative;    /* anchors the language switch above the last item */
  display: flex;
  gap: 26px;
  font-size: var(--fs-nav);
  line-height: var(--lh-title);
  margin-bottom: -5px;   /* nav baseline sits just below the logo */
}

/* Every item is black; the current page is distinguished by weight alone.
   Each link also carries a hidden bold copy of its own label, so the box is
   always as wide as the bold version — the nav therefore occupies identical
   space on every page and nothing shifts when the active item changes. */
.site-nav a {
  display: inline-grid;
  color: var(--ink);
  font-weight: 300;
  transition: opacity 0.25s ease;
}

.site-nav a > span,
.site-nav a::after { grid-area: 1 / 1; }

.site-nav a::after {
  content: attr(data-label);
  font-weight: 500;
  visibility: hidden;
  pointer-events: none;
}

.site-nav a:hover { opacity: 0.55; }

.site-nav a.is-active { font-weight: 500; }

/* Language switch: DE and EN together, right-aligned above the menu so it
   sits over the last item. Smaller than the menu; the current language is the
   bold one (a span, not a link), the other is a light link. The hidden bold
   copy that every .site-nav link carries keeps both the same width either
   way, so nothing moves when the language changes. */
.lang-switch {
  position: absolute;
  right: 0;
  bottom: 100%;
  display: flex;
  gap: 5px;
  font-size: 0.56em;        /* DE EN together about as wide as the last menu item */
  line-height: 1;
  letter-spacing: 0.03em;
  margin-bottom: 9px;
}

.lang-switch > span {
  display: inline-grid;
  color: var(--ink);
  font-weight: 600;
}

.lang-switch > span > span,
.lang-switch > span::after { grid-area: 1 / 1; }

.lang-switch > span::after {
  content: attr(data-label);
  visibility: hidden;
}

.site-nav .lang-switch a { font-weight: 300; }
.lang-switch > span::after,
.site-nav .lang-switch a::after { font-weight: 600; }

/* ---------- main ---------- */

/* 16px of that gap is the header's padding-bottom — together they keep the
   first row of content at the same y as the design */
main { margin-top: 54px; flex: 1 0 auto; }

/* ---------- the grid ---------- */

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: var(--col-gap);
  row-gap: var(--row-gap);
}

/* ---------- shared image behaviour: greyscale, colour on hover ---------- */

.shot {
  width: 100%;
  height: auto;
  object-fit: cover;
  filter: grayscale(1);
  transition: filter 0.45s ease;
}

.card:hover .shot,
.row:hover .shot,
.is-tapped .shot { filter: grayscale(0); }

.card--project .shot {
  filter: grayscale(1);
  transition: none;
}

.card--project:hover .shot,
.card--project.is-tapped .shot { filter: grayscale(0); }

/* ---------- headings + copy ---------- */

h1, h2, h3 {
  margin: 0;
  font-size: var(--fs-title);
  line-height: var(--lh-title);
  font-weight: 400;
  color: var(--ink);
}

p {
  margin: 0;
  text-align: justify;
  /* German compounds otherwise leave wide gaps in justified lines; the
     dictionary comes from <html lang="de"> */
  -webkit-hyphens: auto;
  hyphens: auto;
}

/* ---------- project / team card ---------- */

.card { display: block; }

.card .shot { aspect-ratio: 227 / 165; }
.project-image { width: 100%; aspect-ratio: 227 / 165; overflow: hidden; background: #fff; }
.project-image .shot { display: block; width: 100%; height: 100%; }

.card h2,
.card h3 { margin-top: 7.5px; }

.card p {
  margin-top: 5px;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* project data, not prose: two short lines, set quieter than the title so the
   image and name stay dominant in the grid */
.card-meta {
  color: var(--muted);
  text-align: left;
  overflow: visible;
  display: block;
}

/* team members are portraits and carry role lines instead of copy; the role
   block always reserves three lines so the rows stay on the grid */
.card--person .shot { aspect-ratio: 227 / 283; }

.card--person p {
  display: block;
  overflow: visible;
  min-height: 51px;
  text-align: left;
}

/* members without a photo yet share one portrait-sized slot: the grid row
   stretches it to the neighbouring card's height, and the names spread from
   the top of the image to the bottom of the role lines. On a phone there is
   no neighbour, so the gap keeps them apart. */
.card--names {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 14px;
}

.card--names h3 { margin-top: 0; }

.card--names p {
  margin-top: 5px;
  display: block;
  overflow: visible;
}

/* same three-line reserve as a portrait card, so the last name lines up with
   the name under the neighbouring photo */
.card--names > div:last-child p { min-height: 51px; }

/* ---------- two-column rows (services, office intro) ---------- */

.row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: var(--col-gap);
  align-items: end;          /* copy sits on the baseline of the image */
  margin-bottom: 18.5px;     /* 23px from image bottom to the next image */
}

/* the copy runs 4.5px past the bottom of the image, as in the design */
.row .shot {
  aspect-ratio: 477 / 256;
  margin-bottom: 4.5px;
}

.row h2 { margin-bottom: 5px; }

/* ---------- Leistungen: services and skills as text columns ----------
   Two columns on the same lines as the two-column rows elsewhere; the skills
   repeat the layout under a heading. */
.text-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: var(--col-gap);
  row-gap: var(--row-gap);
}

main > .text-section:first-child { margin-top: calc(5px + 3 * var(--lh-body)); }

.text-cols h2 { margin-bottom: 5px; }

.skills { margin-top: 60px; }

.section-head { margin-bottom: 18px; }

/* planned area under an LPH title: a figure, not prose, so never justified
   or hyphenated */
.service-area {
  margin-bottom: 5px;
  text-align: left;
  -webkit-hyphens: manual;
  hyphens: manual;
  font-variant-numeric: tabular-nums;
}

main > .row:first-child { margin-top: 5px; }

.row--intro {
  margin-bottom: 0;
}

.row--intro .shot { aspect-ratio: 477 / 283; }

/* the office text has two paragraphs: one blank line between them */
.row--intro p + p { margin-top: var(--lh-body); }

.row--intro + .grid { margin-top: 110.5px; }

/* ---------- project detail ---------- */

.hero {
  width: 100%;
  aspect-ratio: 976 / 548;
  object-fit: cover;
}

.detail h1 { margin-top: 43.5px; }

.facts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: var(--col-gap);
  margin-top: 15px;
}

/* The design's 79px label column was sized for "abc" and "abcde"; real labels
   like "Leistungsphasen" overrun it and collide with the value. Each group
   sizes its own label column to its longest label instead. */
.facts .fact {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 12px;
  margin: 0;
}

.facts dt {
  font-weight: 500;
  color: var(--ink);
}

.facts dd { margin: 0; }

.detail > p { margin-top: 17px; }

.detail .grid { margin-top: 37.5px; }

/* ---------- project images ----------
   One large image with arrows, and a strip of small thumbnails below the facts
   that selects which image is shown. */

.stage { position: relative; aspect-ratio: 976 / 548; overflow: hidden; background: #fff; }
.stage .hero { display: block; height: 100%; aspect-ratio: auto; }

.hero { transition: opacity 0.22s ease; }
.hero.is-swapping { opacity: 0; }

/* Controls over the picture — the close mark and the arrows — are bare
   strokes with no box behind them. They are white by default; tint() in
   site.js sets data-tone="dark" where the picture under them is light, and
   they turn black. Each carries a soft glow in the opposite colour as a
   safety net where the patch is mixed. The button itself is a generous,
   invisible hit area around the glyph. */
.stage-nav,
.stage-close {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  padding: 0;
  cursor: pointer;
  background: none;
  color: #ffffff;
  transition: opacity 0.25s ease, color 0.25s ease;
}

.stage-nav svg,
.stage-close svg {
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: butt;
  stroke-linejoin: miter;
  filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.45));
  transition: filter 0.25s ease;
}

.stage-nav[data-tone="dark"],
.stage-close[data-tone="dark"] { color: #000000; }

.stage-nav[data-tone="dark"] svg,
.stage-close[data-tone="dark"] svg { filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.7)); }

/* arrows: two strokes of an arrowhead, shown while the pointer is over the picture */
.stage-nav {
  top: 50%;
  transform: translateY(-50%);
  width: 56px;
  height: 96px;
  opacity: 0;
}

.stage-nav svg { width: 14px; height: 26px; }

/* the way back to the grid: an X in the top-left corner, always visible */
.stage-close {
  top: 0;
  left: 0;
  width: 56px;
  height: 56px;
  text-decoration: none;
}

.stage-close svg { width: 14px; height: 14px; }

.stage-close:hover { opacity: 0.6; }

.stage:hover .stage-nav,
.stage-nav:focus-visible { opacity: 1; }
.stage-nav:hover { opacity: 0.6 !important; }
.stage-nav[disabled] { opacity: 0 !important; pointer-events: none; }
.stage-prev { left: 0; }
.stage-next { right: 0; }

/* the strip sits right under the main image and selects it: small, quiet, and
   clearly a control rather than content, centred on the image above it */
.thumbbar {
  display: flex;
  justify-content: center;
  margin-top: 10px;
}

/* centre while short; once the thumbnails overflow, fall back to scrolling
   from the left so the first one is never cut off */
.thumbs { justify-content: safe center; }

/* the title needs its usual distance from whatever precedes it */
.thumbbar + h1 { margin-top: 33px; }

.thumbs {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scroll-behavior: smooth;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

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

.thumb {
  flex: 0 0 auto;
  overflow: hidden;
  border: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  line-height: 0;
}

.thumb img {
  width: 114px;
  height: 64px;
  object-fit: cover;
  filter: grayscale(1);
  opacity: 0.7;
  transition: filter 0.3s ease, opacity 0.3s ease;
}

.thumb:hover img,
.thumb:focus-visible img { opacity: 1; }

/* the selected image is the one in colour — the same language as the grid */
.thumb.is-current img {
  filter: grayscale(0);
  opacity: 1;
}



@media (max-width: 560px) {
  .thumb img { width: 92px; height: 52px; }
  .stage-nav { width: 44px; height: 80px; opacity: 1; }
  .stage-close { width: 48px; height: 48px; }
}

/* ---------- footer ---------- */

.site-foot {
  margin-top: 24px;
  padding: 10.5px 0 52.5px;
  border-top: 1px solid var(--rule);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: var(--col-gap);
  font-size: var(--fs-foot);
  line-height: 16px;
  color: var(--body);
  flex-shrink: 0;
}

.site-foot .foot-name { grid-column: 1 / span 2; }
.site-foot .foot-tel  { grid-column: 3; text-align: right; }
.site-foot .foot-mail { grid-column: 4; text-align: right; }

.site-foot a { transition: color 0.25s ease; }
.site-foot a:hover { color: var(--ink); }

/* ------------------------------------------------------------------
   Narrow screens

   The design only specifies desktop. Below 900px the four-up grid and
   the side-by-side rows stop working, so they collapse; below 560px the
   header stacks and the type steps up a little for phone reading.
------------------------------------------------------------------ */

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

  /* image over copy — side by side leaves the text far taller than the image */
  .row {
    grid-template-columns: 1fr;
    row-gap: 12px;
    margin-bottom: 44px;
  }
  .row .shot { margin-bottom: 0; }
  .row--intro { margin-bottom: 44px; }
  .row--intro + .grid { margin-top: 0; }

  .facts { grid-template-columns: repeat(2, 1fr); row-gap: 14px; }

  .site-foot .foot-tel  { grid-column: 3 / span 2; }
  .site-foot .foot-mail { grid-column: 3 / span 2; }
}

@media (max-width: 560px) {
  :root {
    --fs-body: 15px;
    --lh-body: 21px;
    --fs-title: 18px;
    --lh-title: 22px;
    --fs-nav: 17px;
    --fs-foot: 13px;
  }

  /* a stacked header would eat a sixth of a phone screen once pinned, so the
     logo steps down and the nav comes back onto one line */
  .site-head {
    padding: 30px 0 12px;
    top: -20px;            /* 30px padding − 10px kept above the logo */
    flex-wrap: nowrap;
    align-items: center;
  }
  .logo { flex: 0 0 auto; }
  .logo img { width: 84px; height: 41px; }
  .site-nav {
    gap: 13px;
    font-size: 15.5px;
    margin-bottom: 0;
    line-height: 1.2;
  }
  /* the language switch floats above the menu, so the header keeps its
     one-line width; a touch tighter than on desktop */
  .lang-switch { gap: 4px; margin-bottom: 5px; }

  main { margin-top: 40px; }

  /* justification opens ugly gaps in a narrow measure */
  p { text-align: left; }

  .grid { grid-template-columns: 1fr; row-gap: 34px; }
  .text-cols { grid-template-columns: 1fr; row-gap: 34px; }
  .card p { -webkit-line-clamp: none; line-clamp: none; }
  .card--person p,
  .card--names > div:last-child p { min-height: 0; }

  .row, .row--intro { margin-bottom: 34px; }

  /* Stacked on a phone, each group would size its own label column and the
     values would land at three different x-positions. Dissolving the groups
     into one grid gives every row a single shared label column, so all values
     sit on one vertical line. */
  .facts {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 14px;
    row-gap: 0;
  }

  .facts .fact { display: contents; }

  /* keep the groups visually apart — both cells of the row, or the value
     would ride up while the label sits lower */
  .facts .fact:not(:first-child) > dt:first-of-type,
  .facts .fact:not(:first-child) > dd:first-of-type { margin-top: 12px; }

  .detail h1 { margin-top: 28px; }
  .detail .grid { margin-top: 30px; }

  .site-foot { grid-template-columns: 1fr; row-gap: 4px; padding-bottom: 36px; }
  .site-foot .foot-name,
  .site-foot .foot-tel,
  .site-foot .foot-mail { grid-column: 1; text-align: left; }
}

/* very narrow phones: keep the one-line header from crowding */
@media (max-width: 380px) {
  .logo img { width: 76px; height: 37px; }
  .site-nav { gap: 10px; font-size: 15px; }
}

/* 320px-class devices: the header needs ~280px, so reclaim the side margins */
@media (max-width: 340px) {
  .page { width: calc(100% - 32px); }
  .logo img { width: 70px; height: 34px; }
  .site-nav { gap: 8px; font-size: 13.5px; }
}

/* Touch devices have no hover, so a tap stands in for it: the first tap
   colours the image, a second tap on the same card follows the link
   (see enableTapToColour in site.js). */
@media (hover: none) {
  .card, .row { -webkit-tap-highlight-color: transparent; }
}
