*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
img { max-width: 100%; height: auto; display: block; }
img:not([src]), img[src=""] { visibility: hidden; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

:root {
  --font-display: "Helvetica Neue", Helvetica, "Inter Tight", Arial, sans-serif;
  --font-sans: "Helvetica Neue", Helvetica, "Inter Tight", Arial, sans-serif;
  --shell-pad-x: clamp(20px, 4vw, 56px);
  --shell-pad-y: 22px;
}

body {
  background: var(--theme-bg);
  color: var(--theme-text);
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 13px;
  line-height: 1.55;
  letter-spacing: 0.01em;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  transition: background-color 240ms ease, color 240ms ease;
  -webkit-font-smoothing: antialiased;
}

body.body--home { min-height: 0; }

body > main,
body > article,
body > section:not(.site-header):not(.site-footer):not(.hero) {
  flex: 1 0 auto;
}

.site-footer { margin-top: auto; }

/* ---------- Header / nav ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  padding: var(--shell-pad-y) var(--shell-pad-x);
  background: var(--theme-bg);
}

.site-nav {
  display: contents;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.site-nav__group {
  display: flex;
  gap: clamp(28px, 6vw, 96px);
  align-items: center;
}

.site-nav__group--left { justify-content: flex-start; }
.site-nav__group--center { justify-content: center; }
.site-nav__group--right { justify-content: flex-end; }

.site-nav__link {
  color: var(--theme-text);
  opacity: 1;
  white-space: nowrap;
  /* Website menu: Helvetica bold, compact (per brand font spec). Font + size
     are overridable via Management > Typography (--type-menu-*). */
  font-family: var(--type-menu-font, var(--font-sans));
  font-weight: 700;
  font-size: var(--type-menu-size, clamp(10px, 0.8vw, 11px));
  transition: color 200ms ease;
}

.site-nav__link[aria-current="page"] {
  color: var(--theme-highlight, var(--theme-accent));
  font-style: italic;
}

.site-nav__link:hover {
  color: var(--theme-highlight, var(--theme-accent));
}

/* ---------- Hero / homepage ---------- */

.hero {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  /* Names sit a bit further to the side now (wider column-gap), and the
     whole hero starts higher on the page (smaller padding-top). */
  column-gap: clamp(56px, 9vw, 140px);
  padding: clamp(110px, 18vh, 200px) var(--shell-pad-x) clamp(42px, 7vh, 84px);
  max-width: 1320px;
  margin: 0 auto;
  width: 100%;
  /* Clip the stack layers' translated overflow so the carousel preview frames
     don't extend the document's scroll height (which was creating empty space
     below the footer on home). */
  overflow: hidden;
}

.hero__name {
  font-family: "Inter Tight", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 900;
  font-size: clamp(36px, 3.6vw, 64px);
  letter-spacing: -0.005em;
  line-height: 1;
  color: var(--theme-text);
  font-synthesis: none;
}

.hero__name__i {
  font-style: italic !important;
  font-weight: 900;
  display: inline-block;
}

.hero__name__u {
  font-style: normal !important;
  font-weight: 900;
  display: inline-block;
}

/* The outward push uses vw for proportionality at mid widths but is clamped
   so the letters never travel further than ~100px past the grid cell — at
   1920+ viewports the previous -10vw was pushing the K/E off-screen. */
.hero__name--left  { justify-self: end;   transform: translate(clamp(-100px, -6vw, -32px), 20vh); }
.hero__name--right { justify-self: start; transform: translate(clamp(32px, 6vw, 100px),   20vh); }

.hero__column {
  display: flex;
  flex-direction: column;
  gap: clamp(12px, 1.6vh, 22px);
  align-items: center;
  position: relative;
  width: 100%;
  min-height: clamp(438px, 48vw, 637px);
}

.hero__frame {
  position: relative;
  margin: 0;
  background: rgba(255, 255, 255, 0.04);
  min-height: 60px;
  transition: filter 160ms ease, opacity 160ms ease, transform 160ms ease;
}

.hero__frame--small {
  filter: blur(0);
  opacity: 1;
  transform: scale(0.95);
  transform-origin: center center;
}

.hero__frame--main {
  filter: none;
  opacity: 1;
  transform: none;
}

/* Coverflow-style stack carousel (built dynamically by hero-carousel.js) */
.hero__stack {
  position: relative;
  width: clamp(260px, 28vw, 380px);
  aspect-ratio: 4 / 5;
  margin: 0 auto;
  overflow: visible;
  isolation: isolate;
}

.hero__stack__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: center center;
  transition: transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1),
              opacity 700ms ease,
              filter 700ms ease;
  pointer-events: none;
  opacity: 0;
  filter: blur(0);
  transform: scale(0.3);
  will-change: transform, opacity, filter;
}

.hero__stack__layer[data-rel="0"] {
  opacity: 1;
  filter: none;
  transform: scale(1) translateY(0);
  z-index: 3;
}

/* The focused layer is clickable when it represents a work item with a
   resolved link (set as data-href by hero-carousel.js). */
.hero__stack__layer[data-rel="0"][data-href] {
  pointer-events: auto;
  cursor: pointer;
}

.hero__stack__layer[data-rel="-1"] {
  opacity: 1;
  filter: blur(0);
  transform: scale(0.55) translateY(-150%);
  z-index: 2;
}

.hero__stack__layer[data-rel="1"] {
  opacity: 1;
  filter: blur(0);
  transform: scale(0.55) translateY(150%);
  z-index: 2;
}

.hero__frame img {
  width: 100%;
  height: auto;
  display: block;
}

.hero__frame--small {
  width: clamp(110px, 15vw, 170px);
}

.hero__frame--small.hero__frame--top {
  width: clamp(105px, 14vw, 155px);
}

.hero__frame--main {
  width: clamp(220px, 30vw, 340px);
  z-index: 1;
  min-height: 280px;
}

.hero__tagline {
  position: relative;
  /* Sits ~15 px under the bottom carousel preview. The preview is
     transform: scale(0.55) translateY(150%) — its bottom edge ends at
     stack_centre + 1.1 × stack_h, which is 0.6 × stack_h below the
     stack's own bottom box. clamp keeps the gap consistent across
     viewports. */
  margin-top: clamp(230px, 19vw, 305px);
  z-index: 3;
  font-size: clamp(15px, 1.4vw, 19px);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-align: center;
  color: var(--theme-text);
  font-weight: 700;
  line-height: 1.35;
}

.hero__tagline em {
  font-style: italic;
  font-weight: 700;
}

.hero__frame--main .hero__caption {
  position: absolute;
  right: clamp(-200px, -50%, -150px);
  top: -8px;
  width: 180px;
  font-size: 10.5px;
  font-style: italic;
  color: var(--theme-text-soft);
  line-height: 1.5;
  text-align: left;
  pointer-events: none;
}

.hero__side-caption {
  position: absolute;
  top: 50%;
  left: calc(50% + clamp(150px, 16vw, 220px));
  transform: translateY(-110%);
  width: clamp(160px, 14vw, 220px);
  font-size: 11px;
  font-style: italic;
  color: var(--theme-text-soft);
  line-height: 1.45;
  text-align: left;
  pointer-events: none;
  z-index: 4;
}

@media (max-width: 900px) {
  .hero__side-caption { display: none; }
}

@media (max-width: 900px) {
  :root {
    --shell-pad-x: clamp(10px, 2.5vw, 22px);
  }
  .site-header {
    padding: 12px var(--shell-pad-x);
    gap: 6px;
  }
  .site-nav {
    font-size: clamp(10px, 2.8vw, 12px);
    letter-spacing: 0.04em;
  }
  .site-nav__group {
    gap: clamp(14px, 4vw, 24px);
  }
  .site-nav__link {
    white-space: nowrap;
  }
  .hero {
    grid-template-columns: 1fr auto 1fr;
    column-gap: clamp(8px, 2vw, 14px);
    padding: clamp(120px, 26vh, 220px) var(--shell-pad-x) 40px;
  }
  .hero__name {
    font-size: clamp(13px, 4.2vw, 22px);
  }
  .hero__name--left,
  .hero__name--right { transform: none; }
  .hero__stack {
    width: clamp(190px, 58vw, 290px);
  }
  .hero__stack__layer[data-rel="-1"],
  .hero__stack__layer[data-rel="1"] {
    transform: scale(0.5) translateY(var(--ty));
  }
  .hero__stack__layer[data-rel="-1"] { --ty: -145%; }
  .hero__stack__layer[data-rel="1"] { --ty: 145%; }
  .hero__tagline {
    font-size: clamp(11px, 2.6vw, 14px);
    margin-top: clamp(101px, 32vw, 155px);
  }
  .hero__column {
    min-height: clamp(279px, 91vw, 438px);
  }
  .hero__caption {
    position: static;
    width: auto;
    margin: 8px 0;
    text-align: center;
  }
}

/* ---------- Global page tagline ----------
   "Worldwide Stylist" sits in the empty space to the right of the
   top-row covers, vertically at ~75% of the rightmost cover's height,
   and at editorial-size type (almost as big as the country labels on
   the main cover). The 21vw / 22vw clamps track the cover-block size
   so the position stays anchored to slot 2 across viewport widths.
   Mobile keeps it small and tucked into the top-right corner. */
.global-tagline {
  /* Lives INSIDE the cover-block grid so its left edge sits exactly on
     cover image #5 (slot 4 = grid-column 16) at every width, including the
     max-width:1400px capped/centred wide layout where a viewport-based calc
     would drift. Column 16 spans to the block's right edge (16..24). It sits
     in the empty top-row band to the right of the three top covers. */
  grid-column: 16 / span 9;
  grid-row: 1;
  align-self: end;
  justify-self: start;
  margin-bottom: clamp(4px, 2vh, 22px);
  /* "Worldwide Stylist": Helvetica Neue bold. Upright by default; the italic
     on/off toggle in Management > Typography drives --type-tagline-style. */
  font-family: var(--type-tagline-font, var(--font-sans));
  font-style: var(--type-tagline-style, normal);
  font-weight: 700;
  font-size: var(--type-tagline-size, clamp(18px, 2.1vw, 30px));
  letter-spacing: 0.02em;
  color: var(--theme-text);
  pointer-events: none;
  white-space: nowrap;
  z-index: 5;
}
@media (max-width: 720px) {
  /* Mobile composition: vertical italic running up the right margin,
     aligned with the main cover's midline. Functions as an editorial
     marginalia — text becomes a graphic element instead of a label
     pinned to a corner. See STYLE.md §2 (Typography as object) and
     §4 (Mobile is its own composition).
     The right margin is sized to absorb the element's post-rotation
     horizontal extension (≈ font-size + padding), so the bounding box
     never spills past the viewport edge and triggers horizontal scroll. */
  .global-tagline {
    /* Mobile is its own composition: break out of the grid flow and pin the
       rotated marginalia to the block's right edge. */
    position: absolute;
    grid-column: auto;
    grid-row: auto;
    margin-bottom: 0;
    top: 50%;
    left: auto;
    right: clamp(26px, 7vw, 36px);
    transform-origin: right center;
    transform: translateY(-50%) rotate(-90deg) translateY(50%);
    font-size: clamp(13px, 3.4vw, 17px);
    font-weight: 400;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-style: var(--type-tagline-style, normal);
    white-space: nowrap;
    opacity: 1;
  }
  /* Hard stop against any horizontal scroll the rotated tagline (or any
     other off-grid element) might introduce on narrow phones. */
  .body--global { overflow-x: hidden; }
}

/* ---------- Cover grid (Global) ---------- */

.cover-grid-wrap {
  padding: clamp(60px, 10vh, 160px) var(--shell-pad-x) clamp(80px, 12vh, 180px);
}
/* Global page — pull the first block up so the main cover lands at viewport
   centre on load (so it can be focus-locked sharp via data-lead). Also keep
   bottom padding tight so the footer sits flush after the carousel. */
.body--global .cover-grid-wrap {
  padding-top: clamp(20px, 3vh, 56px);
  padding-bottom: clamp(16px, 2vh, 32px);
}

.cover-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(20px, 3vw, 56px) clamp(16px, 2vw, 32px);
  align-items: start;
}

.cover-card {
  --focus-w: 0;
  position: relative;
  filter: blur(0);
  opacity: 1;
  transform: scale(calc(0.96 + 0.04 * var(--focus-w)));
  transform-origin: center center;
  grid-column: span 4;
}

.cover-card:nth-child(7n+1) { grid-column: 1 / span 3; }
.cover-card:nth-child(7n+2) { grid-column: 4 / span 3; }
.cover-card:nth-child(7n+3) { grid-column: 7 / span 5; }
.cover-card:nth-child(7n+4) { grid-column: 5 / span 4; }
.cover-card:nth-child(7n+5) { grid-column: 9 / span 3; }
.cover-card:nth-child(7n+6) { grid-column: 1 / span 5; }
.cover-card:nth-child(7n)   { grid-column: 7 / span 4; }

/* ---------- Global page (uses .cover-grid + .cover-card)  ---------- */

.body--global .cover-grid {
  display: flex;
  flex-direction: column;
  gap: clamp(80px, 14vh, 160px);
  grid-template-columns: none;
  max-width: 1400px;
  margin: 0 auto;
}

/* 7-cover block — matches Keynote layout (page 10):
   Row 1 — 3 small covers tightly packed top-left, ending around 58% of page.
           The 3rd cover sits horizontally centred above the main cover.
   Row 2 — main (focal) cover centred at 50% of the page; 2 small covers
           directly to its right with the same gap as between the top 3;
           a thin "→" arrow at the far right edge.
   Row 3 — a single cover photo centred under the main cover.
   Row 4 — a thin "↓" arrow centred under that cover.
   The country label of the main cover sits at its bottom-left, outside,
   right-aligned against the main cover's left edge. */
.body--global .cover-block {
  display: grid;
  grid-template-columns: repeat(24, 1fr);
  grid-auto-rows: auto;
  /* Single gap value — c3-to-main vertical gap matches main-to-side1 horizontal gap. */
  column-gap: clamp(14px, 1.4vw, 26px);
  row-gap: clamp(14px, 1.4vw, 26px);
  align-items: start;
  position: relative;
  /* Clip the off-screen buffer covers so their translateY(160%/180%) doesn't
     extend the document's scroll height — that was creating phantom empty
     space below the footer. The covers still slide in/out smoothly because
     the FLIP animation simply enters/exits across the block's edge. */
  overflow: hidden;
}

.body--global .cover-card {
  filter: blur(0);
  opacity: 1;
  /* Render every cover at an integer 1:1 scale. A fractional scale (the old
     0.98x on non-focus covers) forces the browser to resample the bitmap,
     which is what made the smaller covers look slightly soft. The main cover
     still dominates through its larger grid span, not a scale-up. */
  transform: scale(1);
  transition: filter 140ms ease, opacity 140ms ease, transform 140ms ease;
  overflow: visible;
  grid-column: auto;
}
/* Lead cover (main of first block) starts sharp before scroll-focus runs */
.body--global .cover-card[data-lead] { --focus-w: 1; }

/* Force a uniform 3:4 aspect ratio on every cover so all 7 visually match
   despite different source crops; object-fit: cover preserves the centre. */
.body--global .cover-card .cover-card__media {
  display: block;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  width: 100%;
  cursor: pointer;
}
.body--global .cover-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Carousel slot positioning — covers move between slots as the wheel scrolls.
   Slot 0..2 = top row; slot 3 = main (sharp); slot 4..5 = side; slot 6 = bottom.
   Slot "-1" = hidden (just behind the visible pool, ready to rotate in). */
.body--global .cover-block .cover-card[data-slot="0"] { grid-column: 3  / span 4; grid-row: 1; }
.body--global .cover-block .cover-card[data-slot="1"] { grid-column: 7  / span 4; grid-row: 1; }
.body--global .cover-block .cover-card[data-slot="2"] { grid-column: 11 / span 4; grid-row: 1; }
.body--global .cover-block .cover-card[data-slot="3"] {
  grid-column: 10 / span 6;
  grid-row: 2;
  position: relative;
}
.body--global .cover-block .cover-card[data-slot="4"] { grid-column: 16 / span 4; grid-row: 2; align-self: center; }
.body--global .cover-block .cover-card[data-slot="5"] { grid-column: 20 / span 4; grid-row: 2; align-self: center; }
.body--global .cover-block .cover-card[data-slot="6"] {
  grid-column: 11 / span 4;
  grid-row: 3;
  /* No extra margin: the row-gap alone sets the gap to the main cover, so it
     matches the main-to-top-row and main-to-side gaps (all ~20px). */
}
/* Buffer slot "-1" — sits at slot 0's grid cell but translated off-screen
   left. Used for the cover that's about to slide in to top1 from the left. */
.body--global .cover-block .cover-card[data-slot="-1"] {
  grid-column: 3 / span 4;
  grid-row: 1;
  transform: translateX(-160%);
  opacity: 0;
  pointer-events: none;
}
/* Buffer slot "7" — sits at slot 6's grid cell but translated off-screen
   below. Used for the cover that just left the bottom slot, sliding down. */
.body--global .cover-block .cover-card[data-slot="7"] {
  grid-column: 11 / span 4;
  grid-row: 3;
  margin-top: clamp(8px, 1.5vh, 24px);
  transform: translateY(160%);
  opacity: 0;
  pointer-events: none;
}
/* Fully hidden — not in transition, just dormant in the pool. */
.body--global .cover-block .cover-card[data-slot="hidden"] {
  display: none;
}

/* Slot 3 is the "focus" slot — full sharpness + country label visible. */
.body--global .cover-block .cover-card[data-slot="3"] { --focus-w: 1; }
.body--global .cover-block .cover-card[data-slot="3"] .cover-card__caption { opacity: 1; }
/* All other visible slots: fixed soft blur (the carousel manages focus, not
   scroll-focus, so the side covers don't go sharp when in the row centre). */
.body--global .cover-block .cover-card[data-slot="0"],
.body--global .cover-block .cover-card[data-slot="1"],
.body--global .cover-block .cover-card[data-slot="2"],
.body--global .cover-block .cover-card[data-slot="4"],
.body--global .cover-block .cover-card[data-slot="5"],
.body--global .cover-block .cover-card[data-slot="6"] { --focus-w: 0.4; }

/* Smooth FLIP-driven animation: cards translate from old → new on phase
   change. The transform is intentionally longer than opacity so the slide
   is the dominant motion — opacity fades in quickly at the START of an
   entry (slot -1 → slot 0) so the incoming card is visible during its
   slide from off-screen left. Same applies in reverse for the exit
   (slot 6 → slot 7): the card stays mostly opaque while sliding down,
   then fades out near the end. */
.body--global .cover-block .cover-card.is-animating {
  transition: transform 560ms cubic-bezier(0.22, 0.61, 0.36, 1),
              opacity 180ms ease,
              filter 320ms ease;
  z-index: 1;
}

/* Arrows — thin line-style hints (→ next to side covers, ↓ under bottom cover) */
.body--global .cover-block__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  color: var(--theme-text);
  opacity: 0.85;
  font-weight: 300;
  font-size: clamp(20px, 2.2vw, 32px);
  line-height: 1;
}
.body--global .cover-block__arrow--right {
  grid-column: 24 / span 1;
  grid-row: 2;
  align-self: center;
  justify-self: center;
}
.body--global .cover-block__arrow--right::before { content: "\2192"; } /* → */
.body--global .cover-block__arrow--down {
  grid-column: 11 / span 4;
  grid-row: 4;
  justify-self: center;
  margin-top: clamp(8px, 1.5vh, 24px);
}
.body--global .cover-block__arrow--down::before { content: "\2193"; } /* ↓ */

/* Country label — rendered on every cover but only visible when the cover is
   currently in the main slot (3 desktop, 1 mobile). Desktop: sits at the
   cover's bottom-left, OUTSIDE the image, right-aligned against the cover's
   left edge — no shadow needed because it's against the theme background.
   Mobile: overlays INSIDE the main cover (the only place it fits in the
   staggered 3/1/3 grid without colliding with the bottom row) and uses a
   layered text-shadow for legibility against any image. */
/* Caption = country name + a short description, stacked to the LEFT of the
   featured cover, right-aligned against its left edge. Moved higher up the
   cover so the description has room underneath. */
.body--global .cover-card__caption {
  position: absolute;
  right: calc(100% + clamp(16px, 2vw, 36px));
  /* Top-align the title with the top of the side cover (slot 4), which sits
     centred in the row and so starts ~18.4% down the main cover. */
  top: 18.4%;
  /* Fixed caption column so the description reads at a consistent width instead
     of collapsing to the (often short) country title. Only the active/centre
     cover shows a caption, so a fixed width is safe. */
  width: 14em;
  margin: 0;
  text-align: right;
  opacity: 0;
  transition: opacity 280ms ease;
  pointer-events: none;
}
.body--global .cover-card__caption .cover-card__country {
  position: static;
  margin: 0 0 0 auto;
  /* Right edge is a hard boundary (the description's edge); the box never
     shrinks below its longest word, so a long single word like PORTUGAL can
     never spill right behind the cover, it grows left instead. Multi-word
     titles still wrap within this narrow column. */
  display: block;
  min-width: min-content;
  max-width: 8.5em;
  /* Country names: Helvetica, regular (NOT bold). Upright by default; the
     italic toggle in Management > Typography drives --type-title-style. */
  font-family: var(--type-title-font, var(--font-sans));
  font-size: var(--type-title-size, clamp(20px, 2.2vw, 32px));
  font-style: var(--type-title-style, normal);
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: normal;
  word-break: keep-all;
  line-height: 1.05;
  color: var(--theme-text);
  opacity: 1;
}
/* Description under the country name: Helvetica, normal, small. */
.body--global .cover-card__caption .cover-card__desc {
  margin: clamp(8px, 1vh, 14px) 0 0 auto;
  /* Fills the fixed caption column so the description is a consistent width
     regardless of how short the country title is. Right edge stays on the
     boundary. */
  width: 100%;
  font-family: var(--type-description-font, var(--font-sans));
  font-style: var(--type-description-style, normal);
  font-weight: 400;
  font-size: var(--type-description-size, clamp(13px, 1.1vw, 15px));
  line-height: 1.5;
  color: var(--theme-text-soft);
  /* Justified so both left and right edges sit flush; the fixed caption width
     above keeps the word spacing even. */
  text-align: justify;
}

/* Keep oversized desktop titles anchored to the caption's right edge. */
@media (min-width: 721px) {
  .body--global .cover-card__caption {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
  }
  .body--global .cover-card__caption .cover-card__country {
    width: max-content;
    margin: 0;
    text-align: right;
  }
}

/* ---------- Mobile (≤720px) — stacked 3-slot mini-version ---------- */
@media (max-width: 720px) {
  /* ---------- Mobile homepage hero ----------
     Hero height = 100svh − 2 × header (≈88 px). The hero's vertical centre
     therefore lands on the viewport centre — Ellen / Mirck / main cover
     all align there. Column min-height is sized so the bottom preview +
     the tagline (a few px under the bottom preview) fit fully within
     the hero without being clipped by the carousel layer transforms. */
  .hero {
    align-items: center;
    column-gap: clamp(4px, 1.5vw, 10px);
    padding: 0 4px;
    min-height: calc(100vh - 88px);
    min-height: calc(100svh - 88px);
    /* Allow the top/bottom carousel previews to bleed slightly past the
       hero box on short phones. They're covered by the header (z-index 50,
       opaque background) and the footer (below), so they don't visually
       leak into other UI — just into negative space. */
    overflow: visible;
  }
  .hero__column {
    justify-content: center;
    min-height: clamp(572px, 174vw, 780px);
  }
  /* Stack ~10 % bigger than before (49.5vw). Column min-height scales
     in lock-step so the bottom preview + tagline still fit inside the
     hero on typical phones. Max stack width caps so on wide phones
     (480 px+) the column doesn't overshoot the viewport height. */
  .hero__stack {
    width: clamp(176px, 49.5vw, 230px);
  }
  .hero__tagline {
    position: absolute;
    bottom: clamp(8px, 2vh, 22px);
    left: 50%;
    transform: translateX(-50%);
    margin-top: 0;
    text-align: center;
    width: max-content;
    max-width: 90vw;
  }
  .hero__stack__layer[data-rel="-1"],
  .hero__stack__layer[data-rel="1"] {
    transform: scale(0.5) translateY(var(--ty));
  }
  /* translate 170% × scale 0.5 puts the preview edge ~10 % of stack_h
     away from the main image (visible separation, no overlap). 135 %
     was actually overlapping the main image when scale 0.5 was applied
     — the visible preview top after the scale lands at 0.925h, BELOW
     the main bottom (1.0h). */
  .hero__stack__layer[data-rel="-1"] { --ty: -170%; }
  .hero__stack__layer[data-rel="1"] { --ty: 170%; }
  /* Names ~22% larger to balance the bigger stack — still nowrap so
     MIRCK doesn't clip off the right edge next to a 62vw cover. */
  .hero__name {
    font-size: clamp(13px, 4.4vw, 22px);
    white-space: nowrap;
  }
  .hero__tagline {
    font-size: clamp(12px, 3vw, 16px);
  }

  /* ---------- Mobile global — staggered 7-cover carousel ----------
     The desktop block layout is replaced by a tighter 8-column grid:
       Row 1 — three small soft covers, left-aligned, columns 1–6 (75%);
               column 7–8 stays empty so the row leans toward the left.
       Row 2 — one big sharp main cover, full width.
       Row 3 — three small soft covers, right-aligned, columns 3–8;
               columns 1–2 stay empty so the row leans toward the right.
     A swipe / wheel over the block advances the carousel, just like
     desktop. The exact same data-slot attribute drives both layouts —
     only the grid placement differs per breakpoint. */
  .body--global .cover-grid-wrap {
    padding: clamp(24px, 5vh, 56px) clamp(8px, 3vw, 20px) clamp(20px, 4vh, 40px);
  }
  .body--global .cover-grid { gap: 0; }
  .body--global .cover-block {
    display: grid !important;
    grid-template-columns: repeat(8, 1fr);
    grid-template-rows: auto auto auto;
    column-gap: clamp(4px, 1.2vw, 10px);
    row-gap: clamp(10px, 2vh, 20px);
    width: 100%;
    overflow: hidden;
    align-items: start;
    justify-items: stretch;
  }
  /* Reset every desktop slot rule before re-mapping for mobile. */
  .body--global .cover-block .cover-card,
  .body--global .cover-block .cover-card[data-slot] {
    grid-column: auto;
    grid-row: auto;
    width: 100%;
    max-width: none;
    margin: 0;
    position: relative;
    transition: transform 320ms cubic-bezier(0.4,0,0.2,1),
                opacity 200ms ease,
                filter 200ms ease;
  }
  /* Top row — three small left-aligned soft covers (data-slot 0,1,2). */
  .body--global .cover-block .cover-card[data-slot="0"] { grid-column: 1 / span 2; grid-row: 1; --focus-w: 0.4; }
  .body--global .cover-block .cover-card[data-slot="1"] { grid-column: 3 / span 2; grid-row: 1; --focus-w: 0.4; }
  .body--global .cover-block .cover-card[data-slot="2"] { grid-column: 5 / span 2; grid-row: 1; --focus-w: 0.4; }
  /* Main — sharp cover, 75% of viewport width (centred, leaving an even
     gutter on each side). */
  .body--global .cover-block .cover-card[data-slot="3"] {
    grid-column: 2 / span 6;
    grid-row: 2;
    --focus-w: 1;
  }
  /* Bottom row — three small right-aligned soft covers (data-slot 4,5,6). */
  .body--global .cover-block .cover-card[data-slot="4"] { grid-column: 3 / span 2; grid-row: 3; --focus-w: 0.4; }
  .body--global .cover-block .cover-card[data-slot="5"] { grid-column: 5 / span 2; grid-row: 3; --focus-w: 0.4; }
  .body--global .cover-block .cover-card[data-slot="6"] { grid-column: 7 / span 2; grid-row: 3; --focus-w: 0.4; }
  /* Buffer slots: incoming from off-screen left at row 1 / leaving off-screen
     right at row 3. Mirrors the desktop carousel's slide-in/out direction. */
  .body--global .cover-block .cover-card[data-slot="-1"] {
    grid-column: 1 / span 2; grid-row: 1;
    transform: translateX(-160%); opacity: 0; pointer-events: none;
  }
  .body--global .cover-block .cover-card[data-slot="7"] {
    grid-column: 7 / span 2; grid-row: 3;
    transform: translateX(160%); opacity: 0; pointer-events: none;
  }
  .body--global .cover-block .cover-card[data-slot="hidden"] { display: none; }
  /* Hide arrows on mobile — the swipe/wheel on the carousel handles it. */
  .body--global .cover-block__arrow { display: none; }
  /* Country label only on the main slot. Lives INSIDE the main cover at
     the bottom — overlaid on the image like a magazine credit line.
     Layered text-shadow (mobile-only) keeps it legible against any
     cover. Previously this used translate(0, 40%) which pushed the
     label OUT of the cover and made it collide with the bottom row of
     small covers in the staggered mobile grid. */
  .body--global .cover-card__caption {
    position: absolute;
    right: auto;
    left: 50%;
    bottom: clamp(12px, 3vw, 22px);
    top: auto;
    transform: translateX(-50%);
    margin: 0;
    max-width: 86%;
    text-align: center;
    opacity: 0;
    z-index: 5;
  }
  .body--global .cover-card__caption .cover-card__country {
    /* Reset the desktop right-anchored box: mobile centres the overlay. */
    min-width: 0;
    max-width: none;
    margin: 0;
    font-size: clamp(15px, 4.6vw, 24px);
    line-height: 1.05;
    /* Always pure white on mobile — overlaid on a varying-colour image,
       white + layered shadow guarantees legibility regardless of theme. */
    color: #ffffff;
    text-shadow:
      0 1px 2px rgba(0, 0, 0, 0.55),
      0 0 12px rgba(0, 0, 0, 0.35),
      0 0 24px rgba(0, 0, 0, 0.25);
  }
  /* Description on mobile: a small, shadowed line under the title, overlaid on
     the bottom of the main cover. White + layered shadow stays legible on any
     background. Clamped to 3 lines so it never swamps the image; adding it
     under the title pushes the title upward (the block is bottom-anchored). */
  .body--global .cover-card__caption .cover-card__desc {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    max-width: none;
    margin: clamp(4px, 1.4vw, 8px) 0 0;
    font-size: clamp(10.5px, 3vw, 13px);
    line-height: 1.35;
    color: #ffffff;
    text-shadow:
      0 1px 2px rgba(0, 0, 0, 0.6),
      0 0 10px rgba(0, 0, 0, 0.4),
      0 0 22px rgba(0, 0, 0, 0.25);
  }
  .body--global .cover-block .cover-card[data-slot="3"] .cover-card__caption { opacity: 1; }
}

@media (max-width: 720px) {
  .cover-grid {
    grid-template-columns: 1fr;
    gap: clamp(36px, 8vh, 64px);
  }
  .cover-card,
  .cover-card:nth-child(n) {
    grid-column: 1 / -1;
    max-width: 72vw;
    justify-self: center;
  }
  .cover-grid-wrap {
    padding: clamp(40px, 8vh, 80px) var(--shell-pad-x);
  }
}

.cover-card__media img { width: 100%; }

.cover-card__country {
  margin-top: 8px;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--theme-text-soft);
  font-style: italic;
}

/* ---------- Services page (coverflow) ----------
   The page scrolls normally so the footer (and anything else below) is
   reachable. The carousel only hijacks the wheel/touch when the pointer
   is over the central image+title columns — left text gutter and the
   space to the right of the titles let the page scroll naturally. */
.body--services { min-height: 100vh; }
/* Three columns: description (left), image stack (centre), title list (right).
   All three rotate together — same pattern as the homepage hero, but driven
   by the active service slug. Wheel/touch over the centre strip steps
   forward/backward; the gutters stay free for normal page scrolling. */

.services-page {
  display: grid;
  /* Tighter centre column (hugs the image) so the description (left) and the
     titles (right) sit closer to the main image with symmetric gaps, and the
     1fr side columns get more width so long titles never clip. */
  grid-template-columns: 1fr minmax(300px, 380px) 1fr;
  gap: clamp(18px, 2.6vw, 40px);
  padding: clamp(40px, 7vh, 100px) var(--shell-pad-x) clamp(30px, 5vh, 80px);
  max-width: 1400px;
  margin: 0 auto;
  width: 100%;
  align-items: center;
  min-height: calc(100vh - 80px);
  overflow: hidden;
}

.services__text {
  align-self: center;
  max-width: 36ch;
  justify-self: end;
}
.services__blurb {
  font-family: var(--type-serviceintro-font, inherit);
  font-style: var(--type-serviceintro-style, normal);
  font-size: var(--type-serviceintro-size, clamp(11.5px, 0.95vw, 13.5px));
  line-height: 1.65;
  color: var(--theme-text);
  margin: 0;
  transition: opacity 220ms ease;
  /* Justify so each line ends flush against the right edge — same clean
     paragraph treatment used on /about-me. Hyphens auto lets the browser
     break long words to avoid ugly word-spacing gaps. */
  text-align: justify;
  text-justify: inter-word;
  hyphens: auto;
  -webkit-hyphens: auto;
  word-spacing: 0.02em;
}

/* Image stack — central coverflow column */
.services__stack {
  position: relative;
  width: clamp(200px, 22vw, 320px);
  aspect-ratio: 4 / 5;
  margin: 0 auto;
  isolation: isolate;
  overflow: visible;
}

.services__layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform-origin: center center;
  transition: transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1),
              opacity 700ms ease,
              filter 700ms ease;
  pointer-events: none;
  opacity: 0;
  filter: blur(0);
  transform: scale(0.3);
  will-change: transform, opacity, filter;
  background: rgba(0, 0, 0, 0.04);
}
.services__layer img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.services__layer[data-rel="0"] {
  opacity: 1;
  filter: none;
  transform: scale(1) translateY(0);
  z-index: 5;
  pointer-events: auto;
  cursor: pointer;
}
.services__layer[data-rel="-1"],
.services__layer[data-rel="1"] {
  opacity: 1;
  filter: blur(0);
  z-index: 4;
}
/* Closer to the main than before but still with a small gap (no overlap).
   scale 0.65 + translate 130% places the preview's edge ~2% of stack
   height (~10 px on a 525 px stack) below/above the main. */
.services__layer[data-rel="-1"] { transform: scale(0.65) translateY(-130%); }
.services__layer[data-rel="1"]  { transform: scale(0.65) translateY(130%); }
/* Rel ±2 layers are not part of the desktop composition — only show 3
   images at a time (main + one above + one below). Hidden via opacity so
   they still participate in the smooth fade transitions when cycling. */
.services__layer[data-rel="-2"],
.services__layer[data-rel="2"] {
  opacity: 0;
  filter: blur(0);
  z-index: 3;
  transform: scale(0.5) translateY(-205%);
}
.services__layer[data-rel="2"] { transform: scale(0.5) translateY(205%); }

/* Title list — right coverflow column. justify-self: center positions the
   block in the right gutter; padding-right pushes the visible text LEFT
   so there's a clear margin between the categories and the page edge —
   the right gutter is wider than the left one for editorial breathing
   room. max-width removed because the longest title ("Fashion
   Consultancy") was being clipped against the page edge. */
.services__titles {
  position: relative;
  align-self: stretch;
  min-height: clamp(540px, 62vh, 760px);
  justify-self: start;
  width: 100%;
  max-width: none;
  /* Small right margin only, so the title has the full side column to grow
     into and starts close to the image (symmetric with the left text). */
  padding-right: clamp(8px, 1.4vw, 22px);
  /* One vertical step between adjacent titles. Computed so that rel ±2
     lands at ±2 × step from the active title — which matches the visible
     centre of the top/bottom preview images in the central image stack
     (stack height × 0.845 / 2 ≈ 11.6vw). All five titles end up evenly
     distributed across the same vertical extent as the image stack. */
  --title-step: clamp(105px, 11.6vw, 170px);
}
.services__title {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  /* Category names: Arial (per brand font spec). */
  font-family: Arial, "Helvetica Neue", sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
  line-height: 1;
  cursor: pointer;
  transition: transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1),
              opacity 700ms ease,
              font-size 700ms ease,
              color 700ms ease;
  pointer-events: none;
  opacity: 0;
  font-size: 11px;
  color: var(--theme-text-faint);
}
.services__title[data-rel="0"] {
  /* Sized so the longest category ("EDITORIAL ART DIRECTION") fits the side
     column without clipping. */
  font-size: clamp(16px, 1.5vw, 22px);
  font-weight: 600;
  font-style: normal;
  color: var(--theme-text);
  opacity: 1;
  transform: translateY(-50%);
  pointer-events: auto;
  cursor: default;
}
/* All four neighbour titles (rel ±1 and ±2) share the same calmer
   secondary size — desktop shows ALL five services at once. Mobile
   collapses this to 3 visible via the @media override below. */
.services__title[data-rel="-1"],
.services__title[data-rel="1"],
.services__title[data-rel="-2"],
.services__title[data-rel="2"] {
  font-size: clamp(13px, 1.1vw, 16px);
  font-weight: 400;
  color: var(--theme-text-faint);
  opacity: 1;
  pointer-events: auto;
}
/* Equal rhythm across all five titles using --title-step. Rel ±2 land at
   ±2 × step — same y as the top/bottom preview image centres. Rel ±1 sit
   exactly halfway. The active title (rel 0) stays at centre. */
.services__title[data-rel="-1"] { transform: translateY(calc(-50% - var(--title-step))); }
.services__title[data-rel="1"]  { transform: translateY(calc(-50% + var(--title-step))); }
.services__title[data-rel="-2"] { transform: translateY(calc(-50% - var(--title-step) * 2)); }
.services__title[data-rel="2"]  { transform: translateY(calc(-50% + var(--title-step) * 2)); }
.services__title:not([data-rel="0"]):hover { opacity: 1; color: var(--theme-text); }

/* Mobile: stack the three columns vertically; coverflow keeps working but
   smaller, with text below the images. Titles row becomes a horizontally
   scrolling pager-style row of small chips. */
@media (max-width: 720px) {
  .services-page {
    grid-template-columns: 1fr;
    gap: clamp(20px, 4vh, 36px);
    padding: clamp(20px, 4vh, 40px) var(--shell-pad-x) clamp(20px, 4vh, 40px);
    min-height: calc(100svh - 80px);
    align-items: start;
  }
  .services__text {
    order: 3;
    /* ~75% of the width, centred. */
    max-width: 75%;
    justify-self: center;
    /* Reserve enough space for the longest blurb (~5 lines at this width)
       so the layout doesn't jump as the user swipes between services. */
    min-height: calc(5 * 1.6em + 4px);
  }
  .services__blurb {
    font-size: 12.5px;
    line-height: 1.6;
    /* On mobile keep text-align: justify (inherited from desktop rule)
       — flush-edge paragraphs read tighter than centred and hide the
       ragged right edge that made the swipe-jump more obvious. */
  }
  /* ---------- Mobile services overview (editorial recomposition) ----------
     Per STYLE.md §4 mobile is its own composition. Instead of trying to
     squeeze the desktop coverflow onto a phone (which had previews bleeding
     over titles and blurb), we show only the main image and let the titles
     and description breathe below it on their own rows.
     Active title sits OVER the bottom of the image as an italic poster
     caption, in pure white with a layered shadow for legibility against
     any cover. Neighbour titles sit beneath the image in their own rows
     with no overlap. */
  .services__stack {
    order: 1;
    width: clamp(180px, 50vw, 260px);
  }
  /* Only the active layer is visible on mobile — preview rotation happens
     by fading layers in/out at the same spot, not by stacking them
     vertically above and below (which broke the layout on phones). */
  .services__layer:not([data-rel="0"]) {
    opacity: 0;
    transform: scale(0.95) translateY(0);
  }
  .services__titles {
    order: 2;
    align-self: stretch;
    justify-self: stretch;
    min-height: clamp(110px, 16vh, 150px);
    max-width: none;
    text-align: center;
  }
  .services__title {
    left: 0;
    right: 0;
    text-align: center;
    color: var(--theme-text);
  }
  /* Active title — upright, full-strength black, no shadow. Matches the
     desktop treatment (bigger + heavier than neighbours, but same colour
     family) so the carousel reads as one consistent style across breakpoints. */
  .services__title[data-rel="0"] {
    font-size: clamp(18px, 5vw, 24px);
    font-weight: 600;
    font-style: normal;
    color: var(--theme-text);
    transform: translateY(calc(-50% - clamp(80px, 18vw, 130px)));
    text-shadow: none;
  }
  /* Neighbour titles on mobile: muted grey so they read as a calmer
     secondary group beneath the bold active title (same colour-token as
     desktop's text-faint). */
  .services__title[data-rel="-1"],
  .services__title[data-rel="1"] {
    color: var(--theme-text-faint);
    opacity: 1;
    font-size: clamp(11px, 3vw, 14px);
    text-shadow: none;
  }
  .services__title[data-rel="-1"] { transform: translateY(calc(-50% - clamp(12px, 2.4vh, 22px))); }
  .services__title[data-rel="1"]  { transform: translateY(calc(-50% + clamp(12px, 2.4vh, 22px))); }
  /* Rel ±2 stay invisible (already opacity 0 from the base + the global
     rule); explicit here for safety. */
  .services__title[data-rel="-2"],
  .services__title[data-rel="2"] {
    opacity: 0;
    pointer-events: none;
  }
}

/* ---------- Service detail page (e.g. /services/art-direction) ----------
   Layout, anchored on Img 4 (the tall portrait on the right):
     - Img 4 top  → 10% of viewport below the header.
     - Img 4 right → flush with the page right edge.
     - Img 4 bottom → defines the baseline for Img 1 and Img 2.
     - Img 1 and Img 2 → 3:4 portrait, height = 60% of Img 4's height,
       bottom-aligned with Img 4's bottom; sit next to the label on the left.
     - Label "ART DIRECTION" → on the left, vertically centred against Img 1.
   The grid is built with three rows: a top-gap row (10vh), a "filler" row
   that takes up the part of Img 4 above the small images (40% of Img 4),
   and a bottom row that holds the small images (60% of Img 4). Img 4 spans
   the latter two rows so its top sits at 10vh from container top and its
   bottom sits at the bottom of the bottom row — exactly Img 1/2's bottom. */

.service-detail {
  --top-gap: 10vh;
  --img4-w: clamp(240px, 28vw, 420px);
  --img4-h: calc(var(--img4-w) * 1.5);          /* 3 : 4.5 → h = 1.5 × w */
  --small-h: calc(var(--img4-h) * 0.6);
  --small-w: calc(var(--small-h) * 3 / 4);       /* 3 : 4 portrait */
  --col-gap: clamp(14px, 2vw, 36px);

  /* Five columns. Col 3 holds Img 2; col 1 is sized so Img 2's centre
     lands exactly at 50% of the grid (= page centre, since the grid is
     itself centred via max-width + auto margins). Col 5 (1fr) absorbs
     the remainder on the right.
       50%  =  col1  +  gap  +  W1  +  gap  +  W2/2
       col1 =  50%   -  2·gap  -  W1  -  W2/2                              */
  display: grid;
  grid-template-columns:
    calc(50% - 2 * var(--col-gap) - var(--small-w) - var(--small-w) / 2)  /* col 1 — left buffer (label sits here) */
    var(--small-w)                                                          /* col 2 — Img 1 */
    var(--small-w)                                                          /* col 3 — Img 2 / Img 3 */
    var(--img4-w)                                                           /* col 4 — Img 4 */
    minmax(0, 1fr);                                                          /* col 5 — right buffer */
  grid-template-rows:
    var(--top-gap)
    calc(var(--img4-h) - var(--small-h))         /* part of Img 4 above the smalls */
    var(--small-h)                                /* Img 1 + Img 2 + Img 4 bottom */
    var(--col-gap)                                /* gap between Img 2 and Img 3 */
    var(--small-h);                               /* Img 3 (directly below Img 2) */
  column-gap: var(--col-gap);
  padding: 0 var(--shell-pad-x) clamp(30px, 5vh, 80px);
  max-width: 1500px;
  margin: 0 auto;
  width: 100%;
  min-height: calc(var(--top-gap) + var(--img4-h) + var(--col-gap) + var(--small-h));
  align-items: stretch;
}

/* Intro = label + short blurb stacked together in the left buffer column,
   vertically aligned with the small images on desktop. */
.service-detail__intro {
  grid-column: 1;
  /* Vertically centred against the small images (their row), left-aligned.
     The narrow max-width keeps the gap between the text and the first image
     roughly equal to the gap between the images (symmetric rhythm). */
  grid-row: 3;
  align-self: center;
  justify-self: start;
  display: flex;
  flex-direction: column;
  gap: clamp(9px, 1.3vh, 15px);
  max-width: 28ch;
}

/* Subtitle: the elegant serif ("writing" typeface), kept compact so it reads
   as a refined accent under the title rather than dominating the block. */
.service-detail__subtitle {
  margin: 0;
  font-family: var(--type-subtitle-font, "Instrument Serif", Georgia, serif);
  font-style: var(--type-subtitle-style, italic);
  font-weight: 400;
  font-size: var(--type-subtitle-size, clamp(15px, 1.5vw, 19px));
  line-height: 1.2;
  color: var(--theme-text);
  opacity: 0.9;
}

/* Paragraph 2 (optional). Desktop: rendered inline in the text column,
   directly under paragraph 1 (see .service-detail__more-inline). The separate
   bottom block is only used on mobile. */
.service-detail__more { display: none; }

.service-detail__label {
  color: var(--theme-text);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 200ms ease;
  padding-bottom: 2px;
  /* Wrap long category names (e.g. "EDITORIAL ART DIRECTION") instead of
     overflowing the narrow column. */
  white-space: normal;
  line-height: 1.2;
  /* Category caption: Arial. Overridable via Management > Typography. */
  font-family: var(--type-category-font, Arial, "Helvetica Neue", sans-serif);
  font-style: var(--type-category-style, normal);
  font-size: var(--type-category-size, clamp(13px, 1.1vw, 15px));
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  align-self: start;
}
.service-detail__label:hover { border-bottom-color: var(--theme-text); }

.service-detail__blurb {
  margin: 0;
  font-size: clamp(11.5px, 0.95vw, 13.5px);
  line-height: 1.65;
  color: var(--theme-text);
  opacity: 0.85;
  /* Match the /about-me paragraph treatment — fully justified so the left
     and right edges align, with hyphens enabled so long words break cleanly
     instead of leaving ragged word-space gaps. */
  text-align: justify;
  text-justify: inter-word;
  hyphens: auto;
  -webkit-hyphens: auto;
  word-spacing: 0.02em;
}
/* Portfolio-request line under the description. */
.service-detail__contact {
  margin: clamp(14px, 1.6vh, 22px) 0 0;
  font-size: clamp(11.5px, 0.95vw, 13.5px);
  line-height: 1.6;
  color: var(--theme-text);
  opacity: 0.85;
}
.service-detail__contact a {
  color: var(--theme-text);
  font-weight: 700;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
  white-space: nowrap;
}
.service-detail__contact a:hover { color: var(--theme-accent, currentColor); }

.service-detail__tile {
  position: relative;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.04);
  /* Reset <button> defaults — tiles are clickable to open the lightbox.
     The 1px outline (uses currentColor at low opacity) marks the box edge
     even when the image content is mostly the same colour as the page
     background, so two tiles with very different content still read as
     equally sized. */
  border: 0;
  outline: 1px solid color-mix(in srgb, currentColor 12%, transparent);
  outline-offset: -1px;
  padding: 0;
  margin: 0;
  cursor: zoom-in;
  font: inherit;
  color: inherit;
  display: block;
}
.service-detail__tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 320ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.service-detail__tile:hover img { transform: scale(1.03); }
.service-detail__tile--p3-45 { aspect-ratio: 3 / 4.5; }
.service-detail__tile--p34   { aspect-ratio: 3 / 4; }
.service-detail__tile--empty { background: rgba(0,0,0,0.03); opacity: 0.4; }

/* ---------- Service detail — GALLERY variant (6-7+ images) ----------
   When a service has its own image gallery, replace the bespoke 4-image grid
   with a simple, robust layout: the intro column on the left and a responsive
   grid of all images on the right. Overrides the 5-column template above. */
.service-detail--gallery {
  display: grid;
  grid-template-columns: minmax(230px, 320px) 1fr;
  grid-template-rows: auto;
  gap: clamp(24px, 4vw, 72px);
  align-items: start;
  max-width: 1400px;
  margin: 0 auto;
  padding: clamp(80px, 12vh, 160px) var(--shell-pad-x) clamp(60px, 10vh, 120px);
}
.service-detail--gallery .service-detail__intro {
  position: static;
  grid-column: 1;
  grid-row: 1;
  align-self: start;
}
/* Pin the image grid to the right column (auto-placement was landing it in
   column 1, on top of the intro). */
.service-detail--gallery .service-detail__gallery {
  grid-column: 2;
  grid-row: 1;
}
.service-detail__gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: clamp(12px, 1.4vw, 22px);
}
.service-detail__gtile {
  margin: 0;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--theme-bg, #efe9e0);
}
.service-detail__gtile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
@media (max-width: 800px) {
  .service-detail--gallery { grid-template-columns: 1fr; }
  .service-detail__gallery { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}

/* Img 1, 2 and 3 share an explicit fixed box (--small-w × --small-h). The
   redundant min/max + aspect-ratio: auto guards override the
   `service-detail__tile--p34` aspect-ratio class so the box is always
   exactly the same regardless of which image happens to load. */
.service-detail__tile[data-slot="1"],
.service-detail__tile[data-slot="2"],
.service-detail__tile[data-slot="3"] {
  width: var(--small-w);
  height: var(--small-h);
  min-width: var(--small-w);
  min-height: var(--small-h);
  max-width: var(--small-w);
  max-height: var(--small-h);
  aspect-ratio: auto;
}
.service-detail__tile[data-slot="1"] {
  grid-column: 2;
  grid-row: 3;
  justify-self: end;
}
.service-detail__tile[data-slot="2"] {
  grid-column: 3;
  grid-row: 3;
  justify-self: start;
}
.service-detail__tile[data-slot="3"] {
  grid-column: 3;
  grid-row: 5;
  justify-self: start;
}
.service-detail__tile[data-slot="4"] {
  grid-column: 4;
  grid-row: 2 / 4;
  width: var(--img4-w);
  height: var(--img4-h);
  min-width: var(--img4-w);
  max-width: var(--img4-w);
  aspect-ratio: auto;
  justify-self: start;
}

@media (max-width: 720px) {
  /* Mobile layout (top-to-bottom):
       row 1 →  ART DIRECTION label (centred, full width)
       row 2 →  [ Img 1 ][ Img 2 ]   .   .   ← pair pushed LEFT, tight gap
       row 3 →  [          Img 4 (big)         ]   ← full width, dominant
       row 4 →  .   .   [ Img 3 ]                  ← bottom image flush RIGHT
     Three-column grid: two fixed small-image columns on the left, a
     flexible buffer on the right. Slot 3 sits in the buffer column with
     justify-self: end so its right edge aligns with the page's right
     content edge. */
  .service-detail {
    /* Lower floor (80 vs 120) + minmax columns means the grid can keep
       shrinking past its preferred small-image size when the viewport gets
       narrow. Before this, --small-w bottomed out at 120 and the grid
       refused to shrink below 246px wide — which is why the big image (at
       100% of grid content) stopped getting smaller around 320px viewport. */
    --small-w: clamp(80px, 32vw, 180px);
    grid-template-columns:
      minmax(0, var(--small-w))
      minmax(0, var(--small-w))
      minmax(0, 1fr);
    grid-template-rows: auto auto auto auto;
    column-gap: clamp(6px, 1.5vw, 12px);
    row-gap: clamp(10px, 2.4vw, 18px);
    padding: clamp(20px, 4vh, 40px) calc(var(--shell-pad-x) * 2);
    min-height: calc(100svh - 80px);
    align-content: start;
  }
  /* Mobile: intro (label + blurb) stacks in row 1, centred. */
  .service-detail__intro {
    grid-column: 1 / -1;
    grid-row: 1;
    justify-self: center;
    align-items: center;
    /* ~75% of the width so the description breathes without being too narrow. */
    max-width: 75%;
    gap: clamp(6px, 1vh, 10px);
    margin-bottom: clamp(4px, 1.2vh, 12px);
  }
  .service-detail__label {
    align-self: center;           /* override desktop align-self: start */
    font-size: clamp(14px, 4vw, 22px);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-align: center;
  }
  .service-detail__blurb {
    font-size: clamp(12px, 3.2vw, 14px);
    line-height: 1.55;
    /* Keeps the justified treatment from the base rule, but on mobile we
       also accept centred fallback if the last line ends up too short. */
  }
  .service-detail__subtitle {
    font-size: clamp(15px, 4vw, 19px);
    text-align: center;
  }
  /* Mobile: paragraph 2 sits to the LEFT of the bottom image (slot 3, row 4),
     top-aligned with it. It spans the full row but reserves the image's width
     (+ a gap) as right padding so the justified text never runs under the
     image. The inline copy in the intro is hidden here. */
  .service-detail__more-inline { display: none; }
  .service-detail__more {
    display: block;
    grid-column: 1 / -1;
    grid-row: 4;
    align-self: start;
    justify-self: stretch;
    padding-right: calc(var(--small-w) + clamp(14px, 4vw, 24px));
  }
  /* Slots 1 and 2 fill their (shrinkable) small-image column, so they
     scale all the way down with the viewport. Slot 3 sits in the right
     buffer column with justify-self:end and a fixed width matching slots
     1+2 so its right edge lines up with the page's content edge. */
  .service-detail__tile[data-slot="1"],
  .service-detail__tile[data-slot="2"] {
    width: 100%;
    height: auto;
    min-width: 0;
    max-width: var(--small-w);
    min-height: 0;
    max-height: none;
    aspect-ratio: 3 / 4;
  }
  .service-detail__tile[data-slot="3"] {
    width: var(--small-w);
    height: auto;
    min-width: 0;
    max-width: var(--small-w);
    min-height: 0;
    max-height: none;
    aspect-ratio: 3 / 4;
  }
  .service-detail__tile[data-slot="1"] { grid-column: 1; grid-row: 2; justify-self: start; }
  .service-detail__tile[data-slot="2"] { grid-column: 2; grid-row: 2; justify-self: start; }
  .service-detail__tile[data-slot="3"] { grid-column: 3; grid-row: 4; justify-self: end;   }
  /* Img 4 fills the full grid content width so its left and right edges
     line up exactly with slot 1's left edge and slot 3's right edge. No
     bleed: the doubled padding stays consistent across all images. The
     min-width/min-height resets override the desktop fixed-size rules so
     the image actually shrinks with the viewport (was causing horizontal
     scroll on narrow screens). */
  .service-detail__tile[data-slot="4"] {
    grid-column: 1 / -1;
    grid-row: 3;
    width: 100%;
    min-width: 0;
    max-width: 100%;
    height: auto;
    min-height: 0;
    aspect-ratio: 3 / 4.5;
    margin-left: 0;
    justify-self: start;
  }
}

/* ---------- Lightbox (shared by work-detail + service-detail) ---------- */
.lightbox { position: fixed; inset: 0; z-index: 100; background: rgba(0,0,0,0.92); display: none; align-items: center; justify-content: center; }
.lightbox[aria-hidden="false"] { display: flex; }
.lightbox__stage { margin: 0; max-width: 92vw; max-height: 92vh; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.lightbox__img { max-width: 92vw; max-height: 86vh; width: auto; height: auto; object-fit: contain; user-select: none; -webkit-user-drag: none; }
.lightbox__counter { color: rgba(255,255,255,0.7); font-size: 12px; letter-spacing: 0.18em; text-transform: uppercase; font-family: var(--font-sans); }
.lightbox__btn { position: absolute; background: transparent; border: 0; color: #fff; font-size: 28px; line-height: 1; padding: 12px 16px; cursor: pointer; opacity: 0.75; transition: opacity 160ms ease; }
.lightbox__btn:hover { opacity: 1; }
.lightbox__btn--close { top: 16px; right: 16px; font-size: 32px; }
.lightbox__btn--prev { left: 16px; top: 50%; transform: translateY(-50%); }
.lightbox__btn--next { right: 16px; top: 50%; transform: translateY(-50%); }
@media (max-width: 720px) {
  .lightbox__btn--prev, .lightbox__btn--next { font-size: 24px; padding: 10px 12px; }
}

/* ---------- Footer ----------
   Single horizontal row on every viewport: copyright pinned to the left,
   the three links clustered on the right. About-me was removed (it
   duplicated the header nav link). On very narrow screens the items wrap
   onto a second line; flex-wrap keeps them readable instead of
   overflowing. */

.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px clamp(20px, 4vw, 40px);
  padding: 28px var(--shell-pad-x);
  /* Bottom menu: Helvetica regular, small. Editable via Management > Typography
     (--type-footer-*). Requested 6, applied a touch larger so it stays legible. */
  font-family: var(--type-footer-font, var(--font-sans));
  font-style: var(--type-footer-style, normal);
  font-size: var(--type-footer-size, 9px);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--theme-text-soft);
}

.site-footer > * { white-space: nowrap; }
.site-footer__copyright { margin-right: auto; }
.site-footer a:hover { color: var(--theme-text); }

@media (max-width: 720px) {
  .site-footer {
    gap: 6px clamp(14px, 4.5vw, 24px);
    padding: 14px var(--shell-pad-x) 12px;
    font-size: 9.5px;
    letter-spacing: 0.1em;
  }
  .site-footer__copyright {
    font-size: 9px;
    letter-spacing: 0.12em;
    opacity: 0.85;
  }
}

/* ---------- Generic page padding ---------- */

.page {
  padding: clamp(60px, 12vh, 140px) var(--shell-pad-x);
  max-width: 1240px;
  margin: 0 auto;
  min-height: 70vh;
}

.page h1 {
  /* Brand titles are Helvetica Neue bold. Editable via Management > Typography
     (--type-privacytitle-*). Size sits halfway between our earlier size and the
     small requested 16.5. */
  font-family: var(--type-privacytitle-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-style: var(--type-privacytitle-style, normal);
  font-weight: 700;
  font-size: var(--type-privacytitle-size, clamp(20px, 2.4vw, 28px));
  margin: 0 0 28px;
  letter-spacing: -0.01em;
}

.page p {
  max-width: 62ch;
  /* Editable via Management > Typography (--type-privacydesc-*). 2px smaller. */
  font-family: var(--type-privacydesc-font, "Helvetica Neue", Helvetica, Arial, sans-serif);
  font-style: var(--type-privacydesc-style, normal);
  font-size: var(--type-privacydesc-size, clamp(12px, 0.9vw, 13px));
  line-height: 1.8;
  color: var(--theme-text);
  margin: 0 0 18px;
}

.page a {
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}
.page a:hover { color: var(--theme-accent, currentColor); }

/* ---------- Work / Global image popup (shared) ----------
   Used by /work (feed) and / (Global covers). Left/right page a project's
   images; up/down move between projects (covers). See work-gallery-popup.js. */
.work-popup { position: fixed; inset: 0; z-index: 1000; background: rgba(10,8,8,0.94); display: flex; align-items: center; justify-content: center; }
.work-popup[hidden] { display: none; }
.work-popup__stage { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 14px; }
.work-popup__img { max-width: 90vw; max-height: 78vh; object-fit: contain; display: block; box-shadow: 0 20px 60px rgba(0,0,0,0.5); }
.work-popup__meta { display: flex; gap: 14px; align-items: baseline; color: rgba(255,255,255,0.85); font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; }
.work-popup__title { font-weight: 600; }
.work-popup__counter { color: rgba(255,255,255,0.6); }
.work-popup__btn, .work-popup__nav { position: absolute; background: transparent; border: 0; color: #fff; cursor: pointer; opacity: 0.72; transition: opacity 160ms ease; display: flex; align-items: center; justify-content: center; }
.work-popup__btn:hover, .work-popup__nav:hover { opacity: 1; }
.work-popup__btn--close { top: 18px; right: 24px; font-size: 34px; line-height: 1; }
.work-popup__btn--prev, .work-popup__btn--next { top: 50%; transform: translateY(-50%); font-size: 40px; width: 60px; height: 60px; }
.work-popup__btn--prev { left: 16px; }
.work-popup__btn--next { right: 16px; }
.work-popup__nav { left: 50%; transform: translateX(-50%); font-size: 28px; width: 52px; height: 52px; }
.work-popup__nav--up { top: 12px; animation: work-bob-up 1.8s ease-in-out infinite; }
.work-popup__nav--down { bottom: 12px; animation: work-bob-down 1.8s ease-in-out infinite; }
.work-popup__nav[disabled] { display: none; }
@keyframes work-bob-up { 0%,100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, -5px); } }
@keyframes work-bob-down { 0%,100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 5px); } }
@media (prefers-reduced-motion: reduce) { .work-popup__nav--up, .work-popup__nav--down { animation: none; } }
@media (max-width: 720px) {
  .work-popup__btn--prev, .work-popup__btn--next { width: 44px; height: 44px; font-size: 30px; }
  .work-popup__btn--prev { left: 4px; } .work-popup__btn--next { right: 4px; }
}
