:root {
  --slate: #1d252d;  /* page, overlay, letters, dots */
  --beige: #eee7db;  /* stage, cards, page text */
  --shadow: #bcb3a4; /* extruded edge behind each letter */
  --hover: #6c7a88;  /* caption on hover */
  --line: rgb(238 231 219 / .22);
  --dot: var(--slate);
  --gutter: 1rem;
  --font-display: "Archivo", "Arial Black", Impact, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

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

html { background: var(--slate); }

body {
  margin: 0;
  background: var(--slate);
  color: var(--beige);
  font: 500 14px/1.45 var(--font-mono);
  -webkit-font-smoothing: antialiased;
}

.page {
  padding-inline: var(--gutter);
  overflow-x: clip;
}

.label {
  font: 700 11px/1 var(--font-mono);
  letter-spacing: .15em;
  text-transform: uppercase;
}

/* ———————————————————— Intro / outro ———————————————————— */

.intro,
.outro {
  position: relative;
  min-height: 100vh;
  min-height: 100lvh;
  background:
    linear-gradient(to right, var(--line) 1px, transparent 1px) 0 0 / calc(100% / 12) 100%,
    linear-gradient(to bottom, var(--line) 1px, transparent 1px) 0 0 / 100% 10vh;
}

.intro {
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding-block: 1.25rem;
}

.intro__bar {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
}

.intro__body {
  align-self: center;
  display: grid;
  gap: 1.5rem;
}

.intro__title,
.outro__title {
  margin: 0;
  font: 900 min(12.5vw, 14rem)/.82 var(--font-display);
  font-stretch: 112%;
  letter-spacing: -.02em;
  text-transform: uppercase;
}

.intro__text {
  /* max-width: 30ch; */
  margin: 0;
}

.outro {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 2rem;
  text-align: center;
}

.outro .label { margin: 0; }

.outro__link {
  color: inherit;
  text-underline-offset: .4em;
}

.outro__social {
  display: grid;
  place-items: center;
  width: 3.5rem; /* comfortable tap target around the icon */
  height: 3.5rem;
  color: inherit;
  transition: opacity .2s;
}

.outro__social svg {
  width: 24px;
  height: 24px;
}

.outro__social:hover { opacity: .6; }

.outro__social:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 2px;
}

/* ———————————————————— Work ———————————————————— */

.work {
  --n: 2;    /* number of cards, set from JS */
  --rows: 4; /* number of title letters, set from JS */
  --fit: 1;  /* title shrink factor, set from JS */
  --sp: 0; /* -1 → 0 while entering, 0 while pinned, 0 → 1 while leaving */
  position: relative;
  z-index: 2;
  height: calc(var(--n) * 50vh);
  height: calc(var(--n) * 50lvh);
  background: var(--slate);
}

.work::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  width: 100%;
  height: 1px;
  background: var(--beige);
}

.work__outer {
  position: relative;
  height: 100%;
  /* Clips the fixed stage to the section (and lets it bleed over the page gutter) */
  clip-path: inset(0 calc(var(--gutter) * -1));
}

.work__stage {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--beige);
  color: var(--slate);
  clip-path: inset(0 var(--gutter));
  transform: translate3d(0, calc(var(--sp) * -15%), 0);
  will-change: transform, clip-path;
}

.work:not(.is-near) .work__stage { visibility: hidden; }

.work__title,
.work__scene {
  font-weight: 900;
  /* Sized so the stacked letters fill ~85% of the screen height; --fit shrinks it on tall, narrow screens */
  font-size: calc(min(75rem, 100vh) / var(--rows) * var(--fit));
  font-size: calc(min(75rem, 100lvh) / var(--rows) * var(--fit));
  font-family: var(--font-display);
  font-stretch: 100%;
  line-height: 1;
  text-align: center;
  text-transform: uppercase;
}

/* Invisible: only used to measure where each letter sits */
.work__title {
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.work__title-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0;
  line-height: .85;
}

.work__scene {
  --state: 0; /* 0 = letters stacked, 1 = letters spread across the screen */
  position: absolute;
  inset: 0;
  z-index: 2;
  perspective: 40rem;
  transform: scale(.75);
  will-change: transform;
}

.work__dots {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  transform: translate3d(0, calc(var(--sp) * -5%), 0);
}

/* Letter copies: --head runs ~1.3 (right) → -1.56 (left) as they stream across */
.work__ghost {
  --head: 0;
  --head2: calc(var(--head) * var(--head));
  position: absolute;
  display: block;
  line-height: .85;
  white-space: nowrap;
  pointer-events: none;
  transform:
    rotateY(calc(var(--head) * var(--state) * -10deg))
    translate3d(
      calc(var(--head) * var(--state) * 50vw),
      calc(var(--iy) * var(--head2) * var(--state) * 50%),
      0);
  will-change: transform;
}

/* Darker copy behind each letter, skewed sideways to fake an extruded edge */
.work__ghost::before {
  content: attr(data-letter);
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  color: var(--shadow);
  opacity: min(calc(var(--state) * 2), 1);
  transform-origin: calc(50% - var(--head) * 50%) -50%;
  transform:
    scale(1.05, 1.02)
    translate3d(calc(var(--head) * var(--state) * var(--state) * .1rem), 0, 0);
}

/* ——— Mask ——— */

.work__mask-outer {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100lvh;
  overflow: hidden;
  pointer-events: none;
}

.work__mask {
  position: absolute;
  inset: 0;
  will-change: transform;
}

.work__mask-svg {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  overflow: visible;
}

.work__mask-frame,
.work__mask-inner {
  fill: var(--slate);
  fill-rule: evenodd;
  stroke: var(--beige);
  stroke-width: 1px;
}

.work__mask-inner {
  transform: translate3d(0, calc(var(--sp) * 48px), 0);
  will-change: transform;
}

.work__mask-lines {
  fill: none;
  stroke: var(--line);
  stroke-width: 1px;
}

.work__ruler {
  --w: min(16.6667%, 19.625rem);
  position: absolute;
  top: 10vh;
  top: 10lvh;
  left: calc(50% - var(--w) / 2);
  width: var(--w);
  height: 80vh;
  height: 80lvh;
  visibility: hidden;
  pointer-events: none;
}

/* ——— Cards ——— */

/* --p runs 1 (off right) → 0 (centre) → -1 (off left) */
.card {
  --p: 1;
  --size: 1;
  --y: 0;
  --scale: var(--size);
  --lift: 50%;
  --fit-y: 1; /* scales the offset back on short screens, set from JS */
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  display: block;
  padding: .5rem .5rem 0;
  background: var(--beige);
  color: var(--slate);
  font: 700 11px/1 var(--font-mono);
  letter-spacing: .15em;
  text-align: left;
  text-transform: uppercase;
  transform:
    rotateY(calc(var(--p) * -20deg))
    translate3d(
      calc(var(--p) * (50vw + 100%) - 50%),
      calc(var(--y) * var(--lift) * var(--fit-y) - 50%),
      calc(var(--p) * var(--p) * -5rem))
    scale(var(--scale));
  visibility: hidden;
  will-change: transform;
}

.card.is-inview { visibility: visible; }

/* Frame takes the photo's own shape (--ratio = width / height, set from JS) and fits inside
   a box at most 50vw wide and 55vh tall, so portrait and landscape photos are never cropped */
.card__media {
  --ratio: .6667;
  position: relative;
  display: block;
  width: min(50vw, 55vh * var(--ratio));
  width: min(50vw, 55svh * var(--ratio));
  aspect-ratio: var(--ratio);
  overflow: hidden;
}

.card__media picture,
.card__media img {
  display: block;
  width: 100%;
  height: 100%;
}

.card__media img {
  object-fit: cover;
  opacity: 0;
  transition: opacity .5s;
  /* The shield above takes all clicks; these stop selection, drag and the iOS save sheet */
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
}

.card__shield {
  position: absolute;
  inset: 0;
  z-index: 1;
  -webkit-touch-callout: none;
}

.card__media img.is-loaded { opacity: 1; }

.card__caption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .5rem;
}

.card:hover .card__caption { color: var(--hover); }

/* ——— Responsive ——— */

@media (max-width: 987px) {
  .work__ruler { --w: 33.3333%; }
  /* Cards are all full size here, so lift them less to keep them in frame */
  .card { --scale: 1; --lift: 30%; }
}

@media (max-width: 576px), (max-width: 767px) and (orientation: landscape) {
  .work__ruler { --w: 50%; }
  .work__stage,
  .work__dots { transform: none; }
  .card { --lift: 35%; padding: .25rem; }
  /* At most 65vw wide, to stay on screen while the card slows down through the centre,
     and half the visible height (svh = with browser toolbars showing) */
  .card__media {
    width: min(65vw, 50vh * var(--ratio));
    width: min(65vw, 50svh * var(--ratio));
  }
  .card__caption {
    gap: .5rem;
    padding: .45rem .25rem .2rem;
    font-size: 10px;
  }
  /* Give the caption the full width on narrow cards */
  .card__key { display: none; }
}
