/* ============================================================
   Timm Pfennings — Studio site
   Classic premium build. Hero · Selected Work · Statement.
   ============================================================ */

:root {
  --ink:        #17130f;   /* warm near-black */
  --ink-2:      #221c16;   /* raised surface  */
  --cream:      #ede7de;   /* primary text on dark */
  --cream-soft: rgba(237, 231, 222, 0.55);
  --terra:      #c05f3c;   /* signature terracotta */
  --terra-lt:   #dd7c56;
  --peach:      #ff9f65;   /* work section field   */
  --sand:       #ffc79c;
  --cocoa:      #3a1608;   /* text on peach        */

  /* One typeface across the whole site: Manrope (variable, 200–800). The old
     families are kept only as fallbacks; Manrope is self-hosted and always
     loads, so it wins everywhere. Weights are set per-element as before — only
     the family changed — and nothing is italic anymore. */
  --font-display: "Manrope", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono:    "Manrope", "Space Grotesk", ui-monospace, monospace;
  --font-serif:   "Manrope", "Newsreader", Georgia, serif;

  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);

  /* THE page viewport inset — one shared left/right margin for the whole
     content column: the peach video, the intro paragraph, the portfolio
     gallery, the studio cards, the showreel and the moodboard all read this,
     so every section lines up on the same vertical edges. On large screens it
     widens; on phones and tablets it drops to the tighter value (see the
     max-width:1024px override right below). */
  /* Hard cap on the content column: past this width the page stops widening and
     the side margins take the extra space instead, so the studio card (and every
     other section that reads --page-inset) never grows beyond the intended size
     on big monitors — the type is already capped, so nothing scales past what it
     is at this width. Backgrounds still run full-bleed; only the inset grows. */
  --content-max: 1480px;
  --page-inset: max(
    clamp(40px, 8.5vw, 170px),
    calc((100vw - var(--content-max)) / 2)
  );

  /* Vertical framing inset for the studio card deck ONLY (its top/bottom margin
     and height). Kept separate from --page-inset so widening the page's side
     margins never squashes the cards' vertical frame. */
  --edge-inset: clamp(20px, 3.2vw, 46px);
}

/* Phones + tablets share the tighter viewport inset — the wide desktop margin
   would eat too much of a narrow screen. This one line keeps the whole page's
   side margins in step at every width. */
@media (max-width: 1024px) {
  :root { --page-inset: clamp(20px, 4vw, 44px); }
}

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

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* Sticky-heavy pages can trigger scroll-anchoring jumps as layout settles
     (e.g. images loading behind the stacked cards); disable it for stability. */
  overflow-anchor: none;
}

body {
  font-family: var(--font-display);
  background: var(--ink);
  color: var(--cream);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* `clip` (not `hidden`) contains horizontal overflow WITHOUT turning body
     into a scroll container — otherwise it would break `position: sticky`
     used by the stacking studio cards. */
  overflow-x: clip;
}

::selection { background: var(--terra); color: var(--ink); }

a { color: inherit; }

/* ------------------------------------------------------------
   NAVIGATION
   ------------------------------------------------------------ */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  /* Horizontal padding follows the shared page inset so the logo and nav links
     sit on the same left/right edge as the capped content column, instead of
     hugging the far viewport edges on wide monitors. */
  padding: clamp(18px, 3vw, 26px) var(--page-inset);
  color: var(--cream);
  mix-blend-mode: normal;
  transition: opacity 0.35s ease, visibility 0.35s ease,
              transform 0.5s var(--ease);
}
/* Hidden while the stacking studio deck owns the top edge, so the first
   heading (1 · Who am I?) can sit flush against the screen top. */
.nav.is-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
/* Glides away while scrolling down; slides back in on the first upward turn. */
.nav--away {
  transform: translateY(-110%);
  pointer-events: none;
}

.nav__brand {
  text-decoration: none;
  line-height: 0;
  display: inline-flex;
  align-items: center;
}
.nav__logo {
  height: clamp(31px, 3.5vw, 40px);
  width: auto;
  display: block;
  object-fit: contain;
}

.nav__links {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(18px, 3vw, 46px);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 500;
  justify-content: flex-end;
}
/* Each pair (Portfolio/Journal, About Me/Contact, Brands/Agencies) is a small
   vertical column so the top and bottom words look grouped but are two fully
   independent links with their own hit-area and href. */
.nav__group { display: flex; flex-direction: column; }
.nav__links a {
  text-decoration: none;
  display: block;
  color: inherit;
  transition: opacity 0.25s var(--ease);
}
.nav__links a:hover { opacity: 0.7; }
.nav__link--sub { opacity: 0.55; }
.nav__link--sub:hover { opacity: 0.9; }

/* Text nav only on desktop; tablet & below fall back to the burger. */
@media (max-width: 1024px) { .nav__links { display: none; } }

/* Burger */
.burger {
  position: relative;
  z-index: 61;
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px; height: 44px;
  padding: 0 8px;
  background: transparent;
  border: none;
  cursor: pointer;
}
@media (max-width: 1024px) { .burger { display: inline-flex; } }

.burger span {
  display: block;
  height: 2px; width: 28px;
  background: var(--cream);
  border-radius: 2px;
  transition: transform 0.3s var(--ease), opacity 0.2s ease;
}
.burger.is-open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger.is-open span:nth-child(2) { opacity: 0; }
.burger.is-open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ------------------------------------------------------------
   FULLSCREEN MENU
   ------------------------------------------------------------ */
.menu {
  position: fixed;
  inset: 0;
  z-index: 55;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 clamp(28px, 8vw, 64px);
  background: var(--ink);
  background-image: radial-gradient(120% 80% at 80% 0%, rgba(192, 95, 60, 0.32), transparent 55%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.4s ease, visibility 0.4s ease;
}
.menu.is-open { opacity: 1; visibility: visible; pointer-events: auto; }

.menu__list {
  display: flex;
  flex-direction: column;
  gap: clamp(10px, 2vh, 20px);
  transform: translateY(24px);
  transition: transform 0.45s var(--ease);
}
.menu.is-open .menu__list { transform: translateY(0); }

.menu__link {
  display: flex;
  align-items: baseline;
  gap: 16px;
  text-decoration: none;
  color: var(--cream);
  font-size: clamp(34px, 8vw, 60px);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
  transition: color 0.25s var(--ease);
}
.menu__link:hover { color: var(--terra-lt); }
.menu__index {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  opacity: 0.4;
}

/* ------------------------------------------------------------
   HERO
   ------------------------------------------------------------ */
.hero {
  position: relative;
  height: 100vh;
  min-height: 560px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  text-align: center;
  padding: 0 clamp(20px, 5vw, 24px) clamp(64px, 9vh, 84px);
  background: var(--ink);
  color: var(--cream);
  overflow: hidden;
}

.hero__video {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center bottom;
  z-index: 0;
}
/* Seam blend — fades the video's bottom into background.jpg's top-row gradient.
   Same orange, so it reads as the floor continuing, not as an overlay effect. */
.hero__blend {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 20%;
  z-index: 1;
  pointer-events: none;
  background-image: linear-gradient(
    90deg,
    #e17141 0%,
    #eb7945 25%,
    #ef8048 50%,
    #fa894f 75%,
    #ff9251 100%
  );
  -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000 100%);
          mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000 100%);
}

/* Loader */
.loader {
  position: absolute;
  inset: 0;
  z-index: 6;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 18px;
  background: var(--ink);
  transition: opacity 0.6s ease;
  pointer-events: none;
}
.loader.is-hidden { opacity: 0; visibility: hidden; }
.loader svg { transform: rotate(-90deg); }
.loader__pct {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.24em;
  color: var(--cream);
  opacity: 0.65;
}

/* Hero content */
.hero__content {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0;
  transition: opacity 1s ease 0.4s, transform 1s var(--ease) 0.4s;
  transform: translateY(14px);
}
.hero.is-ready .hero__content { opacity: 1; transform: translateY(0); }

.hero__title {
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.3vw, 4rem);
  line-height: 1.04;
  font-weight: 500;
  letter-spacing: -0.025em;
  max-width: 12.5em;   /* breaks after "…that", like the reference */
}
/* The intro reveal wraps each title line in an `overflow: clip` mask (SplitText,
   see makeLineReveal) whose box is exactly one line tall, so it trims the
   descenders of the RESTING text — the "g" in "Designer" ends flat. Let each mask
   paint a little past its bottom edge again. overflow-clip-margin only widens the
   visible area of an already-clipping box: zero layout impact (line-height and
   spacing are untouched), and 0.3em (~17px) is far less than the line's 120%
   start offset, so the rising line still stays fully hidden during the reveal. */
.hero__title > div { overflow-clip-margin: 0.3em; }

.btn {
  margin-top: 40px;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 16px 30px;
  border: 1px solid rgba(237, 231, 222, 0.5);
  border-radius: 100px;
  text-decoration: none;
  color: var(--cream);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  backdrop-filter: blur(2px);
  transition: background 0.25s var(--ease), color 0.25s var(--ease),
              border-color 0.25s var(--ease), transform 0.25s var(--ease);
}
.btn:hover {
  background: var(--terra);
  border-color: var(--terra);
  color: var(--ink);
  transform: translateY(-2px);
}
.btn span { font-size: 16px; transition: transform 0.25s var(--ease); }
.btn:hover span { transform: translateX(4px); }

.hero__meta {
  position: absolute;
  bottom: 30px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: clamp(13px, 0.9vw, 14px);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 1s ease 0.7s;
}
.hero.is-ready .hero__meta { opacity: 0.85; }
.hero__meta--left  { left: var(--page-inset); color: #fff7d9; }
.hero__meta--right { right: var(--page-inset); }

/* ------------------------------------------------------------
   SECTION 2 — scroll-scrubbed showcase collage
   Pinned stage on the seamless background still. Intro text
   (label / heading / pill) mirrors the reference layout, then
   portfolio cards zoom through, driven by scroll.
   ------------------------------------------------------------ */
/* ------------------------------------------------------------
   TRAILER — showreel between the hero and the work stage
   ------------------------------------------------------------ */
/* The hero's blend dissolves its video into background.jpg's TOP row, and the
   work stage below starts that same image at its top row again. So this strip
   holds exactly that top row — sampled straight from the file — constant down
   its height: it continues the hero's floor and hands off to work with no seam
   at either edge, at any viewport size. */
.trailer {
  position: relative;
  background-image: linear-gradient(
    90deg,
    #e17141 0%,
    #eb7945 25%,
    #ef8048 50%,
    #fa894f 75%,
    #ff9251 100%
  );
  padding: clamp(32px, 5vw, 80px) 0;
  /* The 16/9 frame gives this section a fractional height, so its bottom edge
     lands mid-device-pixel on non-integer DPRs. Chrome antialiases the edge
     against whatever is behind it — the near-black body — which reads as a
     hairline across the seam. Overlapping the next section by a pixel removes
     the shared edge: the blend happens orange-on-orange instead. */
  margin-bottom: -1px;

  /* Both the frame and the credit line below it read this ONE value so they
     share an edge — and it is the page-wide viewport inset, so the video lines
     up with the paragraph, the gallery, the cards and the moodboard. */
  --trailer-inset: var(--page-inset);
}

/* Light variant — the showreel between the studio deck and the testimonials.
   Same frame and inset; only the ground and the text colour change, because
   here it sits on the cream. Its bottom ramps cream→white so it hands over
   seamlessly to the white testimonials below (this used to be the Mood
   section's job; Mood was removed). z-index lifts it over the sticky studio
   cards. */
.trailer--dark {
  z-index: 2;
  background-image: none;
  background: linear-gradient(180deg, #ede7de 0%, #ede7de 82%, #fff 100%);
  margin-bottom: 0;              /* no orange-on-orange seam to hide here */
  color: var(--ink);
  /* Flush with the studio cards above; reads the shared page inset so it stays
     aligned with every other section at any width. */
  --trailer-inset: var(--page-inset);
}
.trailer--dark .trailer__meta { color: var(--ink); }
.trailer--dark .trailer__credit-label,
.trailer--dark .trailer__bts { opacity: 0.55; }

.trailer__frame {
  position: relative;
  margin: 0 var(--trailer-inset);
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #000;
}

/* Credit line under the video: tools on the left, "behind the scenes" on the
   right, both flush with the frame's edges and sharing a baseline. */
.trailer__meta {
  position: relative;   /* anchor for the top-right gallery nav (.trailer__nav) */
  margin: clamp(14px, 1.5vw, 26px) var(--trailer-inset) 0;
  color: var(--cream);
}
.trailer__meta-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: clamp(16px, 3vw, 40px);
}
.trailer__credit-label {
  font-size: clamp(14px, 1vw, 17px);
  line-height: 1.4;
  opacity: 0.6;
}
/* The "+" separators are set in Inter, the one self-hosted family that carries
   a real thin cut (100–900 variable). The surrounding Helvetica stack has no
   thin weight at all, so a low font-weight there would be faked or ignored. */
.trailer__plus {
  font-family: var(--font-display);
  font-weight: 200;
  padding: 0 0.04em;
}
.trailer__credit-tools {
  display: block;
  font-style: normal;
  font-size: clamp(16px, 1.5vw, 26px);
  line-height: 1.25;
  letter-spacing: -0.01em;
}
/* Matches .trailer__credit-label exactly — same size, same colour, same row.
   It is a <button> for the keyboard and screen readers, so the browser's
   control styling has to be stripped back to plain text. */
.trailer__bts {
  flex: 0 0 auto;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: clamp(14px, 1vw, 17px);
  line-height: 1.4;
  color: inherit;
  opacity: 0.6;
  cursor: pointer;
  transition: opacity 0.25s var(--ease);
}
.trailer__bts:hover,
.trailer__bts:focus-visible { opacity: 1; }
.trailer__video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The YouTube iframe fills the frame like the <video> does; it has no intrinsic
   object-fit, so the 16/9 frame + 100%/100% keep it edge-to-edge. */
.trailer__yt { border: 0; }

/* Facade poster — the self-hosted thumbnail plus a centred play glyph. It IS the
   play control (a full-frame button), so the whole frame is one large hit target
   and nothing loads from YouTube until it is pressed. */
.trailer__poster {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: #000;
  cursor: pointer;
  overflow: hidden;
}
/* A hair of overscan even at rest: YouTube thumbnails ship with a thin (~3px)
   black border baked in, and the frame's overflow:hidden then clips it away so
   the still sits edge-to-edge with no faint black rule top and bottom. */
.trailer__poster .trailer__video {
  transform: scale(1.035);
  transition: transform 0.6s var(--ease);
}
.trailer__poster:hover .trailer__video,
.trailer__poster:focus-visible .trailer__video { transform: scale(1.06); }

.trailer__play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(64px, 6vw, 92px);
  height: clamp(64px, 6vw, 92px);
  border-radius: 100px;
  border: 1px solid rgba(237, 231, 222, 0.6);
  background: rgba(23, 19, 15, 0.4);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  color: var(--cream);
  transition: background 0.25s var(--ease), border-color 0.25s var(--ease),
              transform 0.25s var(--ease);
}
.trailer__poster:hover .trailer__play,
.trailer__poster:focus-visible .trailer__play {
  background: rgba(23, 19, 15, 0.62);
  border-color: var(--cream);
  transform: translate(-50%, -50%) scale(1.06);
}
.trailer__play svg {
  width: 40%;
  height: 40%;
  fill: currentColor;
  margin-left: 6%;   /* optical centre — the triangle's mass sits left */
}
/* Fallback stand-in when a gallery video has no thumbnail yet (e.g. the CMS
   could not fetch one) — a plain black fill so the play button still reads. */
.trailer__poster-blank { background: #000; }

/* Gallery nav — the two round arrows plus the counter. It renders twice (see
   the JSX): the copy inside the credit block is pinned to its top-right so the
   arrows' top edge lines up with the top of "created with", right-aligned to the
   frame's right edge, with the counter directly under the right arrow. Only
   rendered when there is >1 film. */
.trailer__nav {
  position: absolute;
  top: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: clamp(8px, 0.8vw, 12px);
}
/* The second copy is a direct section child, used only on phones (see the
   max-width rule below). Hidden on wider screens, where the in-credit copy wins. */
.trailer > .trailer__nav { display: none; }
.trailer__nav-arrows {
  display: flex;
  gap: 12px;
}
.trailer__count {
  font-size: clamp(13px, 0.95vw, 15px);
  opacity: 0.55;
  font-variant-numeric: tabular-nums;
}
.trailer__arrow {
  width: clamp(38px, 2.7vw, 45px);
  height: clamp(38px, 2.7vw, 45px);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #000;
  border: 1px solid #000;
  color: #fff;
  cursor: pointer;
  transition: transform 0.25s var(--ease), background 0.25s var(--ease),
              color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.trailer__arrow:hover { transform: scale(1.07); }
/* On the peach trailer ground the black pills would clash; invert them there.
   The showreel gallery sits on the cream .trailer--dark ground, where black
   reads correctly, so only the light (peach) variant needs the flip. */
.trailer:not(.trailer--dark) .trailer__arrow {
  background: rgba(23, 19, 15, 0.35);
  border-color: rgba(237, 231, 222, 0.6);
  color: var(--cream);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
}
/* On phones the credit tools can wrap to two lines and run under the pinned
   top-right nav, so there the in-credit copy is hidden and the section-level
   copy is shown instead — back above the video, as it originally was: a single
   row with the counter on the left and the two arrows on the right. */
@media (max-width: 600px) {
  .trailer__meta .trailer__nav { display: none; }
  .trailer > .trailer__nav {
    display: flex;
    position: static;
    flex-direction: row;
    align-items: center;
    justify-content: flex-end;
    gap: 12px;
    margin: 0 var(--trailer-inset) clamp(12px, 3vw, 16px);
  }
  .trailer > .trailer__nav .trailer__count {
    order: -1;                 /* counter sits left of the arrows */
    margin-right: auto;        /* pushes the arrows to the right edge */
  }
}

/* Sound toggle — autoplay is muted by browser policy, so this is the gesture
   that grants audio. Sits inside the frame, quiet until hovered. */
.trailer__sound {
  position: absolute;
  right: clamp(14px, 1.6vw, 24px);
  bottom: clamp(14px, 1.6vw, 24px);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(40px, 3.4vw, 54px);
  height: clamp(40px, 3.4vw, 54px);
  padding: 0;
  border: 1px solid rgba(237, 231, 222, 0.5);
  border-radius: 100px;
  background: rgba(23, 19, 15, 0.35);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  color: var(--cream);
  cursor: pointer;
  opacity: 0.65;
  transition: opacity 0.25s ease, background 0.25s ease, border-color 0.25s ease;
}
.trailer__frame:hover .trailer__sound,
.trailer__sound:focus-visible { opacity: 1; }
.trailer__sound:hover {
  background: rgba(23, 19, 15, 0.6);
  border-color: var(--cream);
}
.trailer__sound.is-on { opacity: 1; }
.trailer__sound svg {
  width: 55%;
  height: 55%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The speaker cone reads as a solid shape; only the state glyph is stroked. */
.trailer__sound svg > path:first-child {
  fill: currentColor;
  stroke-width: 1.2;
}

/* Fullscreen toggle — same pill as the sound button, sits to its left.
   Hidden on desktop where the frame is already wide; shown on tablet and
   mobile so viewers can rotate the device for a landscape view. On iOS
   Safari, the click routes to video.webkitEnterFullscreen(), which is the
   API that triggers the OS-level rotation. */
.trailer__fs {
  display: none;
  position: absolute;
  z-index: 2;
  bottom: clamp(14px, 1.6vw, 24px);
  right: calc(clamp(14px, 1.6vw, 24px) + clamp(40px, 3.4vw, 54px) + 10px);
  width: clamp(40px, 3.4vw, 54px);
  height: clamp(40px, 3.4vw, 54px);
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid rgba(237, 231, 222, 0.5);
  border-radius: 100px;
  background: rgba(23, 19, 15, 0.35);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  color: var(--cream);
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 0.25s var(--ease), background 0.25s var(--ease),
              border-color 0.25s var(--ease);
}
.trailer__fs:hover {
  background: rgba(23, 19, 15, 0.6);
  border-color: var(--cream);
  opacity: 1;
}
.trailer__fs svg {
  width: 55%;
  height: 55%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
@media (max-width: 1024px) {
  .trailer__fs { display: inline-flex; }
}

/* When the frame is the fullscreen root on Android / desktop, the video needs
   to actually fill it. */
.trailer__frame:fullscreen {
  width: 100vw;
  height: 100vh;
  aspect-ratio: auto;
  margin: 0;
  background: #000;
}
.trailer__frame:fullscreen .trailer__video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.work {
  position: relative;
  height: 100vh;                   /* pinned stage */
  overflow: hidden;
  color: var(--ink);
  /* A clean white card, like the reference — the images and dark type read
     against it exactly as in the design. */
  background: #ffffff;
}

/* Intro text — laid out like the reference: tiny label hugging the
   left edge, heading + pill starting at roughly a third of the width. */
.work__intro {
  position: absolute;
  top: 6%;
  left: 0; right: 0;
  z-index: 40;
}

/* Fine hairline under the intro text — the carousel plays beneath it. */
.work__rule {
  display: none;
}
.work__intro-main {
  position: absolute;
  left: var(--page-inset);
  right: var(--page-inset);
  top: 0;
}
.work__intro-text {
  font-family: var(--font-display);
  font-size: clamp(26px, 3.05vw, 50px);   /* a touch smaller — more room to breathe */
  /* Line-height set in EM (a length), not unitless: the computed pixel value is
     inherited unchanged by every child, so the plain lines and the larger
     Caliway script lines all get the EXACT same spacing. The script's tall
     swashes may then overhang a neighbouring line a little — that trade is
     deliberate; even line rhythm matters more here than zero overlap. */
  line-height: 1.32em;
  font-weight: 700;
  color: #fff7f2;
  text-align: justify;
  margin: 0;
}
/* Phones: left-aligned, never justified. Justification stretches the
   word-gaps to force a flush right edge, and on a narrow column a line
   holding one long word ("technology", "superpower") gets pulled wide open —
   the "shot to pieces" look. Left keeps every gap at the font's own natural
   width, identical at any screen size. The size is tied to viewport WIDTH (not
   clamped to a fixed px) so the line breaks scale with the screen and the
   wrapping stays the same shape whether the window is dragged wider or
   narrower. */
@media (max-width: 600px) {
  .work__intro-text {
    text-align: left;
    font-size: 7.7vw;
  }
  /* The paragraph's left/right edge now comes from --page-inset (shared with
     the video above and the gallery below), so no per-phone override is needed
     here anymore. */
}
/* Letter-by-letter reveal. The word wrapper stays inline-block so words never
   break mid-cascade and the justified spacing between them is untouched; each
   letter inside is its own inline-block that lifts + fades in. */
/* "creative vision, art direction" AND "taste" — both set in Caliway orange.
   .hi and .cal share every declaration; the two classes still exist so the
   JavaScript that groups them can stay unchanged and either one can drift on
   its own later.
   Slightly larger than the body copy. Deliberately NO own line-height: it
   inherits the paragraph's fixed spacing so its line sits exactly as tall as
   every other. Its ink is taller than Helvetica's, so the swashes overhang a
   little — accepted in exchange for a perfectly even line rhythm. */
.work__intro-text .cal,
.work__intro-text .hi {
  color: #d55e16;
  font-family: var(--font-display);
  font-weight: 400;
  font-style: normal;
  font-size: 1.1em;
  vertical-align: -0.04em;
}
.work__intro-text .hi {
  margin-left: 0.12em;
}
/* Phones: the left-aligned column is narrow and the script words each take a
   whole line. Set them at the SAME size as the body copy so, with the inherited
   fixed line-height, the script lines are exactly as tall as the plain ones —
   perfectly even rhythm and no overhang on the tight mobile column. */
@media (max-width: 600px) {
  .work__intro-text .cal,
  .work__intro-text .hi {
    font-size: 1em;
  }
}
/* Desktop only: left-aligned instead of justified. Justification stretched the
   word gaps to force a flush right edge; left keeps every gap at its natural
   width, so the kerning and spacing read clean and the block sits compact at the
   top-left. The Caliway script is also nudged up a hair — against Helvetica's
   baseline it otherwise hangs a touch low. Phones/tablets keep their treatment. */
@media (min-width: 1025px) {
  /* The paragraph is capped to a narrow left-hand column: its right edge stops
     at 60% of the viewport, so the block never runs more than 10% past the
     centre line no matter how wide the screen. Percentage-based (not a fixed
     px) so the 60% limit holds at every desktop width. */
  .work__intro-main {
    right: 40%;
    max-width: none;
  }
  .work__intro-text {
    text-align: left;
    /* A touch smaller so the narrow column stays a calm ~6 lines rather than
       a tall stack, and still clears the cube below. */
    font-size: clamp(22px, 2vw, 36px);
  }
  .work__intro-text .cal,
  .work__intro-text .hi {
    vertical-align: 0;
  }
}
.work__intro-text .word {
  display: inline-block;
  white-space: nowrap;
}
.work__intro-text .char {
  display: inline-block;
  will-change: transform, opacity;
}
/* Sign-off mark at the bottom-right corner of the whole Work section; GSAP
   breathes it in once the word cascade has finished. It also fades out with
   the rest of the intro when the statement takes over. */
.work__signoff {
  position: absolute;
  right: clamp(20px, 4vw, 44px);
  bottom: clamp(24px, 3.5vw, 44px);
  height: clamp(44px, 4.8vw, 72px);
  width: auto;
  z-index: 40;
  pointer-events: none;
  opacity: 0;               /* pre-GSAP state — no flash before JS runs */
  will-change: transform, opacity;
}
/* Hand-drawn "Click!" cue — mirrors the sign-off, bottom-LEFT corner. */
.work__click {
  position: absolute;
  left: clamp(20px, 4vw, 44px);
  bottom: clamp(20px, 3vw, 40px);
  width: clamp(46px, 5.4vw, 79px);
  z-index: 40;
  pointer-events: none;
  opacity: 0;               /* pre-GSAP state — no flash before JS runs */
  will-change: transform, opacity;
}
.work__click img {
  display: block;
  width: 100%;
  height: auto;
  transform-origin: 50% 85%;   /* pivots near the base — a natural little wag */
  will-change: transform;
}
.work__pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 22px;
  padding: 9px 16px;
  background: #fff;
  border-radius: 100px;
  text-decoration: none;
  color: #17130f;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition: transform 0.25s var(--ease);
}
.work__pill:hover { transform: translateY(-2px); }
.work__pill span { font-size: 9px; }

/* ── "See some work" — single-row infinite accordion ─────────────
   The pinned white card (.work) holds one overlay (.gal): a big heading
   top-left, a short intro top-right, the accordion row bleeding off the right
   edge, and a "Handcrafted" card bottom-left. Panels are placed and sized
   imperatively every frame (see buildAccordion in app.jsx); the CSS only sets
   the field, the type and the row's box. */
.gal {
  position: absolute;
  inset: 0;
  z-index: 45;
  opacity: 0;                 /* JS fades it in as the section rises / pins */
  will-change: opacity;
  color: var(--ink);
}

.gal__title {
  position: absolute;
  left: var(--page-inset);
  top: clamp(64px, 11vh, 160px);
  margin: 0;
  max-width: 5.5em;           /* wraps "See some work" onto two lines */
  font-family: "Manrope", var(--font-display);
  font-weight: 700;
  font-size: clamp(40px, 6vw, 104px);
  line-height: 0.96;
  letter-spacing: -0.025em;
}

.gal__intro {
  position: absolute;
  right: var(--page-inset);
  top: clamp(72px, 13vh, 170px);
  width: min(34vw, 460px);
  margin: 0;
  font-family: "Manrope", var(--font-display);
  font-weight: 500;
  font-size: clamp(16px, 1.12vw, 20px);
  line-height: 1.5;
}

/* The row starts a third of the way across and runs past the right edge; the
   section's own overflow:hidden crops the overhang, so the strip appears to
   continue off-screen. */
.gal__row {
  position: absolute;
  left: 36%;
  right: -22vw;
  top: clamp(220px, 39vh, 540px);
  height: clamp(300px, 48vh, 640px);
  /* Clip the strip to the row box: panels to the left of the focus stop cleanly
     at the row's left edge instead of spilling out under the heading and card,
     and the right side keeps bleeding off-screen (its box edge is past the
     viewport). */
  overflow: hidden;
}
.gal__track {
  position: absolute;
  inset: 0;
}
.gal__panel {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  cursor: pointer;
  will-change: transform, width;
}
.gal__panel:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: -3px;
}

.gal__card {
  position: absolute;
  /* Indented a touch more than the heading, matching the reference. Built on the
     capped page inset, so on wide screens the whole block stays pulled into the
     content column and never drifts outward past the viewport. */
  left: calc(var(--page-inset) + clamp(24px, 3.6vw, 68px));
  top: clamp(300px, 46vh, 560px);
  width: min(22vw, 270px);
}
.gal__card-title {
  margin: 0 0 14px;
  font-family: "Manrope", var(--font-display);
  font-weight: 600;
  font-size: clamp(22px, 2vw, 34px);
  letter-spacing: -0.01em;
}
.gal__card-text {
  /* Large bottom gap so "View project" drops toward the lower third of the
     card, matching the reference. */
  margin: 0 0 clamp(56px, 10vh, 120px);
  font-family: "Manrope", var(--font-display);
  font-weight: 500;
  font-size: clamp(15px, 1.05vw, 17px);
  line-height: 1.5;
}
/* Tool names highlighted inline in the "Handcrafted" copy (see highlightTools
   in app.jsx). Bold on the Manrope variable axis. */
.gal__tool { font-weight: 700; }
.gal__cta {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  text-decoration: none;
  color: var(--ink);
  font-family: "Manrope", var(--font-display);
  font-weight: 600;
  font-size: clamp(15px, 1.1vw, 19px);
}
.gal__cta-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: clamp(40px, 3.4vw, 52px);
  height: clamp(40px, 3.4vw, 52px);
  border: 1.5px solid currentColor;
  border-radius: 50%;
  transition: transform 0.3s var(--ease);
}
.gal__cta:hover .gal__cta-arrow { transform: translateX(4px); }
.gal__cta-arrow svg { width: 40%; height: 40%; }

/* Tablet + phone: the four blocks stack into a single column and the accordion
   sits below the copy, still bleeding off the right edge. */
@media (max-width: 900px) {
  .gal {
    display: flex;
    flex-direction: column;
    padding: clamp(74px, 10vh, 110px) var(--page-inset) clamp(24px, 4vh, 40px);
  }
  .gal__title,
  .gal__intro,
  .gal__card {
    position: static;
    left: auto;
    right: auto;
    top: auto;
    width: auto;
  }
  .gal__title {
    max-width: 9em;
    font-size: clamp(34px, 10vw, 68px);
    margin-bottom: 0.4em;
  }
  .gal__intro {
    width: min(100%, 460px);
    margin-bottom: clamp(16px, 3vh, 32px);
  }
  .gal__row {
    /* relative, NOT static: the track/panels are absolutely positioned, so the
       row must stay their containing block. As `static` it wasn't positioned,
       the panels escaped up to the full-height .gal and covered the heading,
       intro and card — the "fullscreen gallery, no text" bug on tablet. */
    position: relative;
    left: auto;
    right: auto;
    top: auto;
    width: auto;
    margin-right: calc(-1 * var(--page-inset));   /* bleed only off the right */
    height: clamp(220px, 34vh, 400px);
    flex: 0 0 auto;
  }
  .gal__card {
    margin-top: clamp(16px, 3vh, 30px);
    width: min(100%, 340px);
  }
  /* The big desktop gap under the card text would blow up the stacked column. */
  .gal__card-text { margin-bottom: clamp(18px, 3vh, 28px); }
}

@media (max-width: 600px) {
  /* Centre the stacked column inside the pinned stage so the gap above "See some
     work" matches the gap below "View project" — otherwise the block hangs from
     the top (big gap up top, none at the bottom). With justify-content:center the
     free space splits evenly top/bottom, but ONLY if the top and bottom padding
     are equal, so both are set to the same clamp here. */
  .gal {
    justify-content: center;
    padding-top: clamp(40px, 6vh, 60px);
    padding-bottom: clamp(40px, 6vh, 60px);
  }
  .gal__row { height: 32vh; }
}

/* Short phones (iPhone SE-class): the four stacked blocks plus a full-height
   accordion no longer fit a 100vh pin, so pull everything in tighter. */
@media (max-width: 600px) and (max-height: 720px) {
  /* Keep the padding symmetric (smaller here so the crammed content still fits
     the short pin) — the centring above relies on top == bottom. */
  .gal { padding-top: clamp(28px, 4vh, 44px); padding-bottom: clamp(28px, 4vh, 44px); }
  .gal__title { font-size: 30px; margin-bottom: 0.3em; }
  .gal__intro { font-size: 14px; margin-bottom: 12px; }
  .gal__row { height: 25vh; }
  .gal__card-text { margin-bottom: 14px; }
}

/* Fullscreen lightbox: click a carousel card to see it at full viewport size. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(24px, 4vw, 60px);
  background: rgba(17, 12, 8, 0.92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: zoom-out;
  animation: lb-fade 0.28s ease;
}
@keyframes lb-fade { from { opacity: 0; } to { opacity: 1; } }
.lightbox__img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  display: block;
  object-fit: contain;
  border-radius: 6px;
  box-shadow: 0 40px 120px rgba(0, 0, 0, 0.6);
  cursor: default;
  animation: lb-in 0.35s var(--ease);
}
@keyframes lb-in {
  from { transform: scale(0.96); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
.lightbox__close {
  position: absolute;
  top: clamp(18px, 2.4vw, 32px);
  right: clamp(18px, 2.4vw, 32px);
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(237, 231, 222, 0.14);
  border: 1px solid rgba(237, 231, 222, 0.25);
  color: var(--cream);
  cursor: pointer;
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
}
.lightbox__close:hover { background: rgba(237, 231, 222, 0.28); transform: scale(1.05); }

/* Gallery paging — only rendered when the lightbox was opened with prev/next
   handlers, so the trailer's single still keeps a clean, arrow-free view. */
.lightbox__arrow {
  position: absolute;
  top: 50%;
  z-index: 2;
  width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(237, 231, 222, 0.14);
  border: 1px solid rgba(237, 231, 222, 0.25);
  color: var(--cream);
  cursor: pointer;
  /* translateY carries the centring, so every hover state has to repeat it */
  transform: translateY(-50%);
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
}
.lightbox__arrow--prev { left: clamp(12px, 2.4vw, 32px); }
.lightbox__arrow--next { right: clamp(12px, 2.4vw, 32px); }
.lightbox__arrow:hover {
  background: rgba(237, 231, 222, 0.28);
  transform: translateY(-50%) scale(1.05);
}
.lightbox__arrow:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 3px;
}

/* Phones: the image fills almost the whole screen, so the arrows have to sit
   ON it rather than beside it. A translucent cream disc would vanish over a
   light picture — they get a dark scrim here instead of the backdrop tint. */
@media (max-width: 600px) {
  .lightbox__arrow {
    width: 40px;
    height: 40px;
    background: rgba(17, 12, 8, 0.55);
    border-color: rgba(237, 231, 222, 0.35);
  }
  .lightbox__arrow:hover { background: rgba(17, 12, 8, 0.7); }
  .lightbox__arrow--prev { left: 8px; }
  .lightbox__arrow--next { right: 8px; }
}

/* Fullscreen portfolio PDF viewer — opened from the nav "Portfolio" link.
   One page at a time, flipped with the arrows or ←/→; Escape closes. */
.pdfview {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(17, 12, 8, 0.96);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  animation: lb-fade 0.28s ease;
}
.pdfview__canvas {
  display: block;
  border-radius: 4px;
  background: #fff;
  box-shadow: 0 40px 120px rgba(0, 0, 0, 0.6);
  animation: lb-in 0.35s var(--ease);
}
.pdfview__close {
  position: absolute;
  top: clamp(18px, 2.4vw, 32px);
  right: clamp(18px, 2.4vw, 32px);
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(237, 231, 222, 0.14);
  border: 1px solid rgba(237, 231, 222, 0.25);
  color: var(--cream);
  cursor: pointer;
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
}
.pdfview__close:hover { background: rgba(237, 231, 222, 0.28); transform: scale(1.05); }
.pdfview__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 52px;
  height: 52px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(237, 231, 222, 0.12);
  border: 1px solid rgba(237, 231, 222, 0.25);
  color: var(--cream);
  cursor: pointer;
  transition: background 0.25s var(--ease), transform 0.25s var(--ease), opacity 0.25s ease;
}
.pdfview__arrow--prev { left: clamp(12px, 2.2vw, 34px); }
.pdfview__arrow--next { right: clamp(12px, 2.2vw, 34px); }
.pdfview__arrow:hover:not(:disabled) {
  background: rgba(237, 231, 222, 0.28);
  transform: translateY(-50%) scale(1.07);
}
.pdfview__arrow:disabled { opacity: 0.22; cursor: default; }
.pdfview__counter {
  position: absolute;
  bottom: clamp(16px, 3vh, 30px);
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  color: var(--cream);
  opacity: 0.85;
}
.pdfview__counter span { opacity: 0.45; margin: 0 4px; }
.pdfview__loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--cream);
  opacity: 0.9;
}
.pdfview__loading em { font-style: normal; font-size: 22px; letter-spacing: 0.06em; }

/* ------------------------------------------------------------
   STATEMENT REVEAL — sits inside .work as an overlay and glides
   up over the carousel on scroll, once the last card has left.
   ------------------------------------------------------------ */
.work__reveal {
  position: absolute;
  inset: 0;
  z-index: 50;                    /* above the cards, below the lightbox */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(60px, 10vw, 140px) clamp(24px, 5vw, 80px);
  background: linear-gradient(180deg, #ff9f65 0%, #ffc79c 30%, var(--cream) 68%);
  will-change: transform;
  pointer-events: none;           /* let clicks reach cards while off-screen */
}
/* Statement copy — a small "Hello stranger," label over a left-set Manrope
   paragraph. work__reveal-text is now just the wrapper the scroll fade targets;
   all the type lives on the two children below. */
.work__reveal-text {
  margin: 0;
  color: var(--cocoa);
}
.statement-copy__hello {
  font-family: "Manrope", var(--font-display);
  font-weight: 500;
  font-size: clamp(13px, 0.83vw, 16px);
  letter-spacing: 0.005em;
  margin: 0 0 clamp(22px, 2.6vh, 40px);
}
.statement-copy__body {
  font-family: "Manrope", var(--font-display);
  font-weight: 500;
  /* Matched to the reference: ~48px on a 1920 canvas, and a measure tuned so it
     wraps to the same six lines (line 1 ends on "…craft using"). */
  font-size: clamp(20px, 2.5vw, 48px);
  line-height: 1.35;
  letter-spacing: -0.01em;
  /* Wider measure matching the reference art: the copy breaks airily (line 1 ends
     on "…design craft using"). em-based, so the wrap holds as the vw font scales. */
  max-width: 27.5em;
  margin: 0;
}
/* Inline brand logos dropped into the copy (see renderStatementBody). Sized in
   `em` so they track the paragraph at every breakpoint with no extra queries.
   The PNGs already carry their own rounded backgrounds, so no radius is set. */
.statement-copy__ico {
  height: 1.12em;
  width: auto;
  margin: 0 0.14em;
  vertical-align: -0.26em;      /* sits centred on the line, a touch above baseline */
  /* Light drop shadow so each logo lifts a touch off the peach ground. drop-shadow
     (not box-shadow) follows the PNG's alpha, so it hugs the rounded plates and the
     Claude burst's rays rather than a rectangle. Blur/offset in em → scales too. */
  filter: drop-shadow(0 0.055em 0.11em rgba(60, 30, 10, 0.32));
  -webkit-user-drag: none;
  user-select: none;
}
/* ARTHAUS is a wide wordmark, so ride it at cap height rather than icon height. */
.statement-copy__ico--wide {
  height: 0.82em;
  margin: 0 0.18em;
  vertical-align: -0.06em;
}
/* The Claude burst is a bare shape (transparent, no rounded plate); a hair
   larger so it reads at the same visual weight as the plated icons. */
.statement-copy__ico--bare {
  height: 1.32em;
  margin: 0 0.1em;
  vertical-align: -0.4em;
  /* Slow, continuous clockwise spin. transform applies to the replaced <img>
     without disturbing the surrounding text layout; the origin is the icon's
     centre by default, so it turns in place. */
  animation: statement-burst-spin 8s linear infinite;
}
@keyframes statement-burst-spin {
  to { transform: rotate(360deg); }
}
/* Honour a reduced-motion preference — hold the burst still. */
@media (prefers-reduced-motion: reduce) {
  .statement-copy__ico--bare { animation: none; }
}
/* Mobile: the statement owns a whole viewport, so scale the copy up for
   comfortable reading — each size × 1.618 (golden ratio) over its mobile floor
   (13 → 21, 20 → 32). Line-height tightened a touch so the taller block still
   sits fully on screen. Desktop keeps its pixel-tuned sizes. */
/* Mobile: size the statement copy off the viewport HEIGHT (vh), so the whole
   block — the "Hello stranger" line plus the long paragraph — always fits one
   screen on ANY phone: it scales down on short phones and up (to a cap) on tall
   ones, and never overflows the panel. Desktop keeps its pixel-tuned sizes. */
@media (max-width: 600px) {
  .statement-copy__hello { font-size: clamp(15px, 2.05vh, 21px); }
  .statement-copy__body {
    /* Big on phones — the copy nearly fills the screen. Sized off viewport HEIGHT
       (capped) so it fills ~one screen on the pinned panel without overflowing on
       taller or shorter phones. The inline logos are em-based, so they scale up
       with it and keep sitting between the words. Line-height tightened a touch to
       buy the extra size its room. */
    font-size: clamp(20px, 3.35vh, 27px);
    line-height: 1.18;
  }
  /* Trim the panel's vertical breathing room so the copy has the whole screen. */
  .studio--statement .studio__inner {
    padding-top: clamp(16px, 2.2vh, 26px);
    padding-bottom: clamp(16px, 2.2vh, 26px);
  }
}

/* Tablet: the copy was falling to the desktop floor sizes here (13px / 20px),
   which read too small on a big tablet panel. Scale every size × 1.618 (golden
   ratio) over that floor — 13 → 21, 20 → 32 — matching the mobile treatment, and
   ease the line-height a touch for the larger block. Desktop (≥1025) is untouched
   and keeps its pixel-tuned sizes. */
@media (min-width: 601px) and (max-width: 1024px) {
  .statement-copy__hello { font-size: clamp(21px, 1.34vw, 26px); }
  .statement-copy__body {
    font-size: clamp(32px, 4.04vw, 48px);
    line-height: 1.3;
  }
}

/* ------------------------------------------------------------
   STUDIO — numbered about / CV sections
   ------------------------------------------------------------ */
.studio-stack {
  position: relative;
  background: #ede7de;   /* fills the gap above the stuck cards */
  /* Pulled up so the statement panel begins rising OVER the tail of the
     carousel (right as the intro text fades) instead of waiting for the whole
     work section to scroll away — kills the long empty-orange stretch. */
  margin-top: -95vh;
  /* Vertical framing (top/bottom margin + height) stays on the narrow inset so
     the pinned deck keeps its shape; the horizontal margin uses the shared page
     inset so the cards' left/right edges line up with every other section. */
  --studio-inset: var(--edge-inset);
  --studio-inset-x: var(--page-inset);
  /* Frame geometry, hoisted here so the statement panel can align its copy to
     the exact line where the numbered cards' headers begin. Mobile/tablet: the
     frame sticks flush at the inset. Desktop overrides both below. */
  --frame-h: calc(100vh - 2 * var(--studio-inset));
  --frame-top: var(--studio-inset);
}
.studio {
  /* Full-viewport stacking deck: every card pins flush to the top edge, so the
     active card always owns the WHOLE viewport (its content never gets clipped).
     The next card slides up over it, and its heading briefly queues under the
     current one before it takes the screen and pushes the previous card away.
     The generous height beyond 100vh gives each card a comfortable rest — the
     user must scroll several ticks with the card fully on screen before the
     next one starts creeping in, so you can never over- or under-shoot. */
  position: sticky;
  top: 0;
  min-height: 175vh;
  background: #ede7de;
  border-top: 1px solid rgba(23, 19, 15, 0.15);
  box-shadow: 0 -18px 50px rgba(23, 19, 15, 0.10);
  color: #17130f;
  font-family: var(--font-display);
}
/* Content is vertically centred within one viewport so the top and bottom
   breathing room is exactly equal — the premium, balanced look. The card's
   extra height (128vh) is empty space below, giving each card its rest beat. */
.studio__inner {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(40px, 6vh, 80px) clamp(20px, 4vw, 44px);
}

/* Framed deck: a single sticky cream frame sits centred over the statement
   background; the numbered cards are absolute-positioned inside and slide UP
   from the frame's bottom edge one over the other — the frame's overflow:hidden
   clips the incoming slide so it never leaks into the peach margin. */
.studio-frame-slot {
  position: relative;
  /* Slot provides the scroll runway that drives the deck. The transitions and
     between-card holds fit in the base N viewports; the extra viewport is split
     between the two ends — a short settle at the top and a trailing pause on
     the last card at the bottom, so it too gets its couple of held scroll
     notches before the section releases. */
  min-height: calc((var(--n, 3) + 1) * 100vh);
}
.studio-frame {
  position: sticky;
  top: var(--frame-top);
  height: var(--frame-h);
  margin: 0 var(--studio-inset-x);
  background: transparent;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 30px 80px rgba(23, 19, 15, 0.18);
  z-index: 3;
}
/* Desktop: on a tall screen the full-viewport card left a huge dead gap between
   the copy (top) and the image (bottom). Cap the card height so it stops growing
   past what its content needs — the big image stays big, but the gap above it
   shrinks to something calm — and centre the shorter card in the stage. Below
   the cap (normal/short screens) it stays full-height as before. */
@media (min-width: 1025px) {
  /* Set on the stack (the shared ancestor) so both the frame AND the statement
     panel read the same centred-frame geometry. */
  .studio-stack {
    --frame-h: min(calc(100vh - 2 * var(--studio-inset)), 950px);
    --frame-top: max(var(--studio-inset), calc((100vh - var(--frame-h)) / 2));
  }
}
.studio-frame .studio {
  position: absolute;
  inset: 0;
  height: 100%;
  min-height: 0;
  margin: 0;
  padding: 0;
  background: #ede7de;
  border-top: none;
  box-shadow: none;
  transform: translateY(100%);
  will-change: transform;
}
.studio-frame .studio:first-child { transform: translateY(0); }
.studio-frame .studio__inner {
  min-height: 100%;
  max-height: 100%;
  background: transparent;
  border-radius: 0;
  overflow: hidden;
  box-shadow: none;
}
/* Desktop only: header + list pinned to the top of the full-height card, image
   pinned to the bottom — a big calm gap between them. The desktop frame height is
   CAPPED (see --frame-h above), so on a laptop the frame is short; a fixed 400px
   image then overflowed the frame's bottom edge and got clipped by its
   overflow:hidden. Fix: the figure fills the remaining height under the header and
   bottom-aligns the image, and the image slot may SHRINK (flex-shrink) while
   keeping its 16/10 ratio — so a short frame scales the picture down proportionally
   instead of clipping it. On tall screens the slot stays at its full 400px
   (max-height), so the original calm-gap layout is unchanged.
   Tablet/phone keep their own single-column spacing. */
@media (min-width: 1025px) {
  .studio-frame .studio__inner { justify-content: flex-start; }
  .studio-frame .studio__top { flex: 0 0 auto; }
  .studio-frame .studio__figure {
    flex: 1 1 0;                 /* fill the height left under the header */
    min-height: 0;              /* ...and be allowed to shrink below content size */
    display: flex;
    flex-direction: column;
    justify-content: flex-end;   /* the image hugs the frame's bottom edge */
  }
  .studio-frame .studio__caption { flex: 0 0 auto; }
  .studio-frame .studio__slot {
    flex: 0 1 auto;             /* shrink to fit a short (capped) frame */
    min-height: 0;
    height: 400px;             /* full design height on tall screens */
    max-height: 400px;
    width: auto;               /* width follows the shrinking height via the ratio */
    aspect-ratio: 16 / 10;
    max-width: 100%;
    margin-left: auto;         /* stay right-aligned as it narrows */
  }
}
/* Tablet/phone: top-align the card content so EVERY heading sits at the same
   position no matter how many list items a card has. The base rule centres the
   content vertically, which let a short card like "Who am I?" (fewer lines) drift
   lower than "Tools" / "History". Top-aligning pins all headings to the same
   top padding; the extra room just falls below each card as its rest space. */
@media (max-width: 1024px) {
  .studio-frame .studio__inner { justify-content: flex-start; }
}

/* Statement base card — the "I make brands…" panel, full viewport, that the
   numbered studio cards slide up over one by one.
   Its rise over the empty orange stage must be seamless: no shadow, no border,
   and an eased gradient so there is never a visible line — the cream light
   simply grows out of the orange. */
.studio--statement {
  background: linear-gradient(
    180deg,
    #ff9f65 0%,
    #ffa872 12%,   /* eased ramp start — no gradient kink at the leading edge */
    #ffc79c 32%,
    #f2d9bc 50%,
    var(--cream) 68%
  );
  border-top: none;
  box-shadow: none;   /* the card shadow would smear a dark edge onto the stage */
}
/* Sticky runway of the statement panel. Its height beyond one viewport is the
   scroll distance it stays pinned BEFORE the first numbered card slides up to
   cover it — inherited from .studio (175vh). On tablet/phone the copy uses its
   compact size, so that long pinned stretch read as a big empty gradient below
   the text. Shorten it so the text lands, holds a short beat, then the card
   comes in. (The card sequence is driven by the frame-slot, not this height, so
   this only moves the deck up earlier — it doesn't change the card timing.) */
@media (max-width: 1024px) {
  .studio--statement { min-height: 120vh; }
}
/* The feathered apron that used to lead the rising edge is gone: the work stage
   below is now a white card, so a transparent→orange veil read as a soft blend.
   The panel's own top edge (solid #ff9f65) makes the clean, hard cut we want as
   it slides up over the card. */
.studio--statement .studio__inner {
  /* Left-set copy that lines up with the gallery/every other section's left
     edge (--page-inset), top-set on every breakpoint so the statement reads
     from the top. The old "void below the text" on tablet is not fixed by
     centring the copy but by shortening the panel's sticky runway (see the
     .studio--statement min-height override below) so the first card slides up
     to cover it sooner instead of holding on an empty gradient. */
  align-items: flex-start;
  justify-content: flex-start;
  text-align: left;
  padding-left: var(--page-inset);
  padding-right: var(--page-inset);
}
@media (min-width: 1025px) {
  /* Anchor the statement copy to the exact line where the card deck sticks —
     the frame's sticky top EDGE (--frame-top), the same line the cream card
     pins to as it slides up. (Below 1025px the cards centre their content, so
     the panel keeps the base centred layout.) */
  .studio--statement .studio__inner {
    justify-content: flex-start;
    padding-top: var(--frame-top);
  }
}

.studio__top {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(32px, 5vw, 64px);
  align-items: baseline;
  justify-content: space-between;
}

.studio__idx {
  display: flex;
  gap: clamp(48px, 8vw, 150px);
  flex: 0 1 auto;
  min-width: 240px;
  align-items: baseline;
}
.studio__num {
  font-size: clamp(22px, 2.5vw, 37px);
  font-weight: 400;
  line-height: 1;
  color: #97938b;
}
.studio__label {
  font-size: clamp(22px, 2.5vw, 37px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.01em;
}

.studio__body {
  flex: 1 1 480px;
  max-width: 640px;
}
.studio__h2 {
  font-size: clamp(22px, 2.5vw, 37px);
  line-height: 1.08;
  font-weight: 500;
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: pretty;
}
.studio__muted {
  font-size: clamp(15px, 1.55vw, 22px);
  color: rgba(23, 19, 15, 0.4);
  font-weight: 400;
  letter-spacing: -0.02em;
}
/* Phones: the h2 column is narrow, so the muted qualifier ("basic",
   "grafikdesigner", "content manager") stops fitting on the same visual line
   as its heading and wraps unpredictably. Force each pair to render as
   heading over qualifier — the same shape "IBB Highschool / mediengestalter"
   already falls into naturally. */
@media (max-width: 600px) {
  /* Clear hierarchy on the narrow card: the label is the card's TITLE, the
     number a quiet index in the corner, and the list sits a step below both — so
     it reads title → list, not one wall of same-size text. Dialled DOWN from the
     earlier ×1.618 pass, which made the list LARGER than its own heading and
     forced ugly two-line wraps ("Adobe creative / cloud"). */
  .studio__label { font-size: 30px; font-weight: 600; line-height: 1.05; }
  .studio__num   { font-size: 20px; }
  .studio__h2 { font-size: 24px; line-height: 1.25; }
  .studio__muted {
    display: block;
    margin-left: 0;
    font-size: 16px;
    line-height: 1.2;
    margin-bottom: 0;   /* no pair-to-pair gap — every line sits tight */
  }
  /* .studio ancestor raises specificity above the base .studio__more rule,
     which is declared later in the file. */
  .studio .studio__more { font-size: 15px; }
  /* The h2 puts a <br> after each pair to separate them on desktop. Once the
     muted span is block-level, that <br> renders as an extra empty line and
     opens up a visible gap between pairs — kill it so nothing is spaced out. */
  .studio__muted + br { display: none; }
}
.studio__more {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
  text-decoration: none;
  color: rgba(23, 19, 15, 0.4);
  font-size: clamp(15px, 1.55vw, 22px);
  font-weight: 500;
  letter-spacing: -0.01em;
  transition: color 0.25s ease;
}
.studio__more:hover { color: #17130f; }
.studio__more span { font-size: 0.9em; }

.studio__figure {
  width: 100%;
  max-width: 640px;
  margin-left: auto;
  /* Kept modest so the whole card (heading + list + image) fits within one
     viewport — the card is full-screen, so nothing may spill past the fold. */
  margin-top: clamp(28px, 4vw, 56px);
}
.studio__caption {
  display: flex;
  align-items: baseline;
  justify-content: flex-start;   /* year now sits on the left, note removed */
  gap: 16px;
  margin-bottom: 18px;
}
.studio__year {
  font-size: clamp(14px, 1.2vw, 17px);
  color: rgba(23, 19, 15, 0.4);
}

.studio__slot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: 6px;
  overflow: hidden;
  background: #e3ddd2;
}
.studio__slot img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.studio__ph {
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(23, 19, 15, 0.35);
}

/* Tablet and below — single column, label left and number right.
   The wide card reads as two columns (index | copy) and stays aligned only
   because the copy and the figure are both right-pushed and capped at 640px.
   Once that row wraps, the copy drops to the container's left edge while the
   figure stays right, and the two lose the shared column the design relies on.
   Below 1024px the card becomes one column instead: the label and the number
   split a single header row, and everything below runs the full content width. */
@media (max-width: 1024px) {
  /* Block, not flex — the stack must not depend on flex-basis arithmetic
     deciding where to wrap. */
  .studio__top { display: block; }

  .studio__idx {
    min-width: 0;
    gap: clamp(16px, 3vw, 32px);
    justify-content: space-between;
  }
  /* The number is first in the DOM so it keeps reading as the index; on this
     layout it belongs on the right, against the figure's edge. */
  .studio__label { order: -1; }
  .studio__num { flex: 0 0 auto; }

  .studio__body,
  .studio__figure {
    /* width:auto is load-bearing: the figure's width:100% would overflow once
       the auto side margin is dropped. */
    width: auto;
    max-width: none;
    margin-left: 0;
    margin-right: 0;
  }
  .studio__body { margin-top: clamp(48px, 9vh, 120px); }

  /* Air below the copy block. The card centres its content vertically, so
     widening this gap lifts the whole label/list group instead of only
     pushing the figure down — which is what gives "Learn More" its breathing
     room away from the caption. */
  .studio__figure { margin-top: clamp(48px, 8.5vh, 120px); }
}

/* Phones: the numbered card carries a big (×1.618) heading, a multi-line list
   AND the image inside one viewport-tall card, so at the tablet gaps the block
   overflowed — the header clipped against the top edge and the image ran off
   the bottom. Drop the year caption and trim the two large gaps so the whole
   group fits and centres: the header pulls down off the top edge and the image
   sits fully on screen. (Placed after the max-width:1024px block so these
   smaller gaps win the source-order tie.) */
@media (max-width: 600px) {
  .studio__caption { display: none; }               /* remove the "2026" year */
  .studio__body   { margin-top: clamp(24px, 4vh, 40px); }
  /* Sit the card image a little lower — a larger gap between the list/"Learn
     More" and the picture. Kept modest so the fullest card (Tools/History) still
     fits its viewport-tall card without the image running off the bottom. */
  .studio__figure { margin-top: clamp(40px, 6.5vh, 60px); }
}


/* ------------------------------------------------------------
   TESTIMONIALS — "What People Say About Working With Me"
   Pixel rebuild of the Section-16 design (reference: 1440×826).
   All key measures derive from that frame and scale with vw.
   ------------------------------------------------------------ */
.testi {
  position: relative;
  /* Top ramps cream→white so it hands over seamlessly from the cream studio deck
     above (the removed video section used to bridge this). Rest of the section is
     white. */
  background: linear-gradient(180deg, #ede7de 0, #fff clamp(120px, 16vw, 260px));
  color: #071a34;
  font-family: var(--font-display);
  padding: clamp(56px, 7.5vw, 130px) 0 clamp(48px, 7.2vw, 124px);
}
.testi__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  /* Same capped content inset as every other section (was a section-local
     clamp that ran wider than the rest on big screens). */
  margin: 0 var(--page-inset) clamp(26px, 3.6vw, 60px);
}
.testi__title {
  /* Min raised so the heading doesn't collapse to ~26px on tablet/phone, where
     the vw term is tiny — keeps it clearly the section headline. */
  font-size: clamp(28px, 4vw, 54px);
  line-height: 1.12;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: #071a34;
  margin: 0;
}
.testi__nav {
  display: flex;
  gap: 12px;
  margin-bottom: 6px;   /* arrows ride on the headline's second line */
  flex: 0 0 auto;
}
.testi__arrow {
  width: clamp(38px, 2.7vw, 45px);
  height: clamp(38px, 2.7vw, 45px);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #000;
  border: 1px solid #000;
  color: #fff;
  cursor: pointer;
  transition: transform 0.25s var(--ease), background 0.25s var(--ease),
              color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.testi__arrow:hover:not(:disabled) { transform: scale(1.07); }
.testi__arrow:disabled {
  background: #fff;
  border-color: #d9d9d9;
  color: #071a34;
  cursor: default;
}
.testi__viewport {
  margin-left: var(--page-inset);
  overflow: hidden;
}
.testi__track {
  display: flex;
  gap: clamp(16px, 3vw, 52px);
  transition: transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}
.testi__card {
  /* Width floor raised to 400px: the person photo sits absolutely in the
     bottom-right corner, so a card that is too narrow forces the long German
     quotes to wrap into many full-width lines that run down UNDER the photo
     (and push the name/role behind it). At >=400px every quote wraps to a few
     short lines that end well above the photo, matching the desktop look. The
     vw term still scales up to the 456px cap on wide screens; below 700px the
     mobile rule takes over with one near-full-width card. */
  --testi-card-w: clamp(400px, 26.5vw, 456px);
  position: relative;
  flex: 0 0 auto;
  width: var(--testi-card-w);
  /* The reference card's proportions are a FLOOR, not a fixed height: the
     min-height keeps the desktop proportions while a long quote lets the card
     grow taller instead of pushing text under the name. */
  min-height: calc(var(--testi-card-w) * 427 / 448);
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid #e9e9e9;
  border-radius: 16px;
  overflow: hidden;
  padding: clamp(20px, 2.35vw, 40px) clamp(20px, 2.35vw, 40px) 0;
}
/* A card that links to the person's profile (opens in a new tab). Keeps the
   card's own type colours (no default link blue/underline) and lifts slightly
   on hover so it reads as clickable. */
.testi__card--link {
  text-decoration: none;
  color: inherit;
  cursor: pointer;
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}
.testi__card--link:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 44px rgba(7, 26, 52, 0.12);
}
.testi__card--link:focus-visible {
  outline: 2px solid #071a34;
  outline-offset: 3px;
}
.testi__glow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  user-select: none;
}
.testi__stars {
  position: relative;
  display: flex;
  gap: 6px;
  margin-bottom: clamp(12px, 1.3vw, 20px);
}
.testi__stars svg {
  width: clamp(13px, 1.22vw, 19px);
  height: auto;
}
.testi__quote {
  position: relative;
  /* Min 16 so the quote never drops below comfortable reading size on
     tablet/phone (the vw term bottoms out well below that there). */
  font-size: clamp(16px, 1.3vw, 18px);
  line-height: 1.58;
  font-style: normal;
  font-weight: 500;
  color: #1a2d47;
  margin: 0;
  max-width: 92%;
}
.testi__meta {
  position: relative;
  /* In flow and pushed to the card's bottom, so it can never collide with a
     long quote — on a roomy card `auto` reproduces the old absolute offset. */
  margin-top: auto;
  /* Guaranteed minimum gap to the quote. Capped at 15px because that is all
     the slack the 448/427 card has left at desktop — any more and the card
     would grow past its designed proportions. */
  padding-top: clamp(12px, 1vw, 15px);
  padding-bottom: clamp(16px, 1.9vw, 32px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.testi__name,
.testi__role {
  font-size: clamp(13px, 0.95vw, 15px);
  line-height: 1.55;
  color: #8b8b8b;
}
/* Fixed-height slot so name/role stay on the SAME baseline across cards,
   regardless of each logo's own height; logos bottom-align within it. */
.testi__logoslot {
  margin-top: clamp(10px, 1.1vw, 18px);
  height: clamp(32px, 2.85vw, 44px);
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
}
.testi__logo {
  display: block;
  width: auto;
}
.testi__photo {
  position: absolute;
  right: 0;
  bottom: 0;
  height: 48%;
  width: auto;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
}

/* Mobile: one card fills most of the width; everything else scales down. */
@media (max-width: 700px) {
  /* Retuning the width variable carries through to the min-height floor; the
     card grows past it on its own when the quote needs the room. */
  .testi__card { --testi-card-w: 82vw; }
  .testi__quote { font-size: 16px; max-width: 100%; }
  .testi__name, .testi__role { font-size: 13px; }
  .testi__stars svg { width: 17px; }
  .testi__photo { height: 40%; }
  .testi__logoslot { height: 34px; }
  .testi__logo { max-height: 34px; }
}

/* ------------------------------------------------------------
   FOOTER — "Let`s talk" contact close (dark stage)
   ------------------------------------------------------------ */
.footer {
  position: relative;
  background: var(--ink);
  color: var(--cream);
  font-family: var(--font-display);
  padding: clamp(38px, 4.2vw, 68px) clamp(20px, 4vw, 64px) clamp(30px, 3.2vw, 52px);
}
.footer__contact {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding-top: clamp(22px, 2.8vw, 44px);
  border-top: 1px solid rgba(237, 231, 222, 0.14);
}
/* Dead-centre on the row, regardless of the side items' widths. */
.footer__link--center {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
}
.footer__link {
  font-size: clamp(14px, 1.15vw, 20px);
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--cream);
  text-decoration: none;
  transition: opacity 0.25s var(--ease);
}
.footer__link:hover { opacity: 0.65; }

.footer__mid {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(20px, 3vw, 56px);
  margin: clamp(54px, 7.6vw, 134px) 0 clamp(42px, 5.2vw, 82px);
}
.footer__cta {
  display: inline-flex;
  align-items: center;
  gap: clamp(16px, 2.2vw, 42px);
  color: var(--cream);
  text-decoration: none;
  font-size: clamp(58px, 12.6vw, 236px);
  line-height: 0.9;
  font-weight: 500;
  letter-spacing: -0.02em;
  white-space: nowrap;
  transition: opacity 0.3s var(--ease);
}
.footer__cta:hover { opacity: 0.8; }
.footer__cta:hover .footer__arrow { transform: translateX(0.09em); }
.footer__arrow {
  width: clamp(52px, 8vw, 150px);
  height: auto;
  flex: 0 0 auto;
  transition: transform 0.35s var(--ease);
}
/* The portrait is a pre-cut circle with transparent corners, so it needs no
   masking of its own — it just sits at the end of the "Let`s talk" row. */
.footer__photo {
  width: clamp(110px, 21vw, 420px);
  height: auto;
  flex: 0 0 auto;
  user-select: none;
  -webkit-user-drag: none;
}

.footer__meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-top: clamp(16px, 1.9vw, 30px);
  border-top: 1px solid rgba(237, 231, 222, 0.14);
  font-family: var(--font-mono);
  font-size: clamp(12px, 0.83vw, 14px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(237, 231, 222, 0.55);
}
.footer__meta a {
  color: inherit;
  text-decoration: none;
  transition: color 0.25s var(--ease);
}
.footer__meta a:hover { color: var(--cream); }
.footer__ig { text-align: center; }
.footer__legal { text-align: right; }

/* Mobile-only row that carries LinkedIn onto the hairline between the CTA and
   the meta strip. Hidden on wider screens because the top contact row hosts
   the same link there. */
.footer__linkedin-mobile {
  display: none;
  color: var(--cream);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  transition: opacity 0.25s var(--ease);
}
.footer__linkedin-mobile:hover { opacity: 0.65; }

@media (max-width: 760px) {
  /* The top contact row shrinks to phone + email; LinkedIn moves down onto
     the new hairline row so nothing gets crushed between the two. */
  .footer__contact .footer__link--center { display: none; }

  .footer__linkedin-mobile {
    display: block;
    padding: clamp(14px, 4vw, 22px) 0;
    border-top: 1px solid rgba(237, 231, 222, 0.14);
    margin-top: clamp(18px, 4vw, 32px);
  }
  /* The LinkedIn row already draws the separating line — the meta row must
     not double it up. */
  .footer__meta { border-top: 0; padding-top: 0; }

  .footer__mid { flex-direction: column; align-items: flex-start; gap: clamp(28px, 8vw, 48px); }
  .footer__photo { align-self: flex-end; }
  .footer__meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    text-align: left;
  }
  .footer__ig, .footer__legal { text-align: left; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition-duration: 0.01ms !important; }
  html { scroll-behavior: auto; }
}
