/* ==========================================================================
   Jwm.nyc — 2026 redesign
   Dark and light sections alternate. Every section inherits its palette from
   tokens, so adding `.light` to a section flips the whole thing.
   ========================================================================== */

:root {
  /* Dark palette (the default) */
  --bg:        #0b0b0b;
  --bg-2:      #0b0b0b;
  --bg-3:      #161616;
  --line:      rgba(255, 255, 255, .12);
  --line-2:    rgba(255, 255, 255, .22);
  --head:      #ffffff;
  --text:      #e8e8e8;
  --muted:     #9b9b9b;
  --dim:       #6e6e6e;
  --tint:      rgba(255, 255, 255, .07);
  --tint-2:    rgba(255, 255, 255, .34);

  --red:       #dd0808;
  --red-lift:  #ff1f1f;

  --radius:    1.5px;
  /* Corner radius on artwork: 10px on a desktop, easing down on small screens. */
  --img-radius: clamp(3px, .28vw, 5px);
  --nav-h:     64px;
  --pad:       clamp(20px, 4.5vw, 64px);
  --maxw:      1640px;
}

/* Light sections. Same token names, different values. */
.light {
  --bg:        #f0f0ed;
  --bg-2:      #e7e7e3;
  --bg-3:      #ffffff;
  --line:      rgba(0, 0, 0, .13);
  --line-2:    rgba(0, 0, 0, .24);
  --head:      #131316;
  --text:      #1c1c20;
  --muted:     #56565e;
  --dim:       #7b7b83;
  --tint:      rgba(0, 0, 0, .05);
  --tint-2:    rgba(0, 0, 0, .3);

  background: var(--bg);
  color: var(--text);
}

/* A slightly deeper light tone. Used when two light sections sit next to each
   other, so the boundary between them still reads. */
.light-alt {
  --bg:   #e6e6e1;
  --bg-2: #dcdcd6;
  --bg-3: #f7f7f5;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 24px);
}

/* clip, not hidden: overflow-x:hidden turns this into a scroll container and
   silently kills position:sticky anywhere inside. clip trims the same overflow
   without creating one. */
html, body { margin: 0; padding: 0; max-width: 100%; overflow-x: clip; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: Poppins, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { margin: 0; font-weight: 200; letter-spacing: -.01em; line-height: 1.1; }
p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

/* The UA stylesheet gives figure a 40px margin on each side, which silently
   widens any flex or grid track it sits in. */
figure, blockquote { margin: 0; }

::selection { background: var(--red); color: #fff; }
:focus-visible { outline: 2px solid var(--red-lift); outline-offset: 3px; }

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding-left: var(--pad);
  padding-right: var(--pad);
}

.eyebrow {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 18px;
}

.section {
  padding: clamp(72px, 11vw, 148px) 0;
  background: var(--bg);
  color: var(--text);
}

.section-head { max-width: 900px; margin-bottom: clamp(40px, 6vw, 76px); }
.section-head h2 { font-size: clamp(32px, 5.4vw, 60px); color: var(--head); }
.section-head .lede {
  margin-top: 22px;
  color: var(--muted);
  font-size: clamp(15px, 1.5vw, 18px);
  max-width: 60ch;
}

/* ---------- Buttons ---------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 50px;
  padding: 0 26px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color .2s, border-color .2s, color .2s;
}

.btn:hover { background: var(--tint); border-color: var(--tint-2); }

.btn.primary { background: var(--red); border-color: var(--red); color: #fff; }
.btn.primary:hover { background: var(--red-lift); border-color: var(--red-lift); color: #fff; }

.btn-row { display: flex; flex-wrap: wrap; gap: 14px; }

.tlink {
  display: inline-block;
  position: relative;
  color: var(--text);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding-bottom: 6px;
}

.tlink::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--line-2);
}

.tlink::before {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 0; height: 1px;
  background: var(--red);
  transition: width .3s ease;
  z-index: 1;
}

.tlink:hover::before { width: 100%; }

/* Inline link inside body copy. */
.ilink {
  color: var(--text);
  border-bottom: 1px solid var(--line-2);
  transition: color .2s, border-color .2s;
}

.ilink:hover { color: var(--head); border-color: var(--red); }

/* ---------- Navigation ------------------------------------------------- */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  height: var(--nav-h);
  /* No panel at the top of a page: the links sit straight on the hero. The
     backdrop blur only switches on with the background, since blurring nothing
     still tints what is behind it. */
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color .3s, border-color .3s, backdrop-filter .3s;
}

.nav.stuck {
  background: rgba(8, 8, 8, .55);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: rgba(255, 255, 255, .12);
}

/* With the menu open the bar matches the dropdown panel exactly, whatever the
   scroll position. Otherwise, opened at the top of a page, the dropdown had a
   panel while the bar above it stayed transparent and looked detached. */
.nav.open {
  background: rgba(8, 8, 8, .98);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: transparent;
}

/* Over a photo with no panel behind it, the links need their own weight. */
.nav:not(.stuck):not(.open) .brand,
.nav:not(.stuck):not(.open) .nav-links a:not(.nav-cta),
.nav:not(.stuck):not(.open) .nav-toggle span {
  text-shadow: 0 1px 12px rgba(0, 0, 0, .55);
}

.nav:not(.stuck):not(.open) .nav-toggle span { box-shadow: 0 1px 10px rgba(0, 0, 0, .5); }

.nav-inner {
  height: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding-left: var(--pad);
  padding-right: var(--pad);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}

.brand { font-size: 19px; font-weight: 400; letter-spacing: .04em; color: #e8e8e8; transition: color .2s; }
.brand:hover { color: var(--red-lift); }

.nav-links { display: flex; align-items: center; gap: 30px; }

.nav-links a {
  font-size: 13px;
  font-weight: 400;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #fff;
  transition: color .2s;
}

.nav-links a:hover { color: var(--red-lift); }

/* The page you are on reads a step bolder rather than a different colour. */
.nav-links a.here { font-weight: 500; }

.nav-links a.nav-cta {
  color: #0b0b0b;
  background: #fff;
  border-radius: var(--radius);
  padding: 10px 18px;
  transition: background-color .2s, color .2s;
}

.nav-links a.nav-cta:hover { background: var(--red); color: #fff; }

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  margin-right: -10px;
  border: 0; background: transparent; cursor: pointer; padding: 0;
}

.nav-toggle span {
  display: block;
  width: 22px; height: 1px;
  margin: 5px auto;
  background: #e8e8e8;
  transition: transform .3s, opacity .2s;
}

.nav.open .nav-toggle span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav.open .nav-toggle span:nth-child(2) { opacity: 0; }
.nav.open .nav-toggle span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

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

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
  /* overflow:hidden alone lets the transformed photo layer bleed a row past the
     bottom edge at fractional pixel positions. clip-path clips the composited
     layer instead of just the paint. See .hero::after for the hard backstop. */
  clip-path: inset(0);
  background: #0b0b0b;
}

/* THE SEAM BACKSTOP.
   Rounding between a transformed photo layer and a separate overlay layer can
   leave a hairline of raw photo along the bottom edge. Rather than rely on that
   rounding going our way, a solid bar of the page colour is painted over the
   last few rows of the hero, above every other layer inside it. The scrim is
   already fully opaque there, so this is invisible, and it makes the seam
   impossible rather than unlikely. The section below also overlaps upward
   (see .strip and .footer) so the join is covered from both sides. */
.hero::after {
  content: "";
  position: absolute;
  left: -2px;
  right: -2px;
  bottom: -1px;
  height: 5px;
  background: #0b0b0b;
  z-index: 3;
  pointer-events: none;
}

.hero-bg {
  position: absolute;
  inset: -2%;
  background-image: url("../img/hero-home.webp");
  background-position: 50% 46%;
  background-size: cover;
  will-change: transform;
}

/* The still underneath stays visible until the loop can actually play, and it
   is also the fallback when video is blocked or motion is reduced. */
.hero-video {
  position: absolute;
  inset: -2%;
  width: 104%;
  height: 104%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .9s ease;
  will-change: transform, opacity;
}

.hero-video.ready { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .hero-video { display: none; }
}

/* Reaches solid page-black before the bottom edge, so the hero never leaves a
   half-lit band where it meets the section below it.
   The -2px inset matters: the photo layer is transformed and lands on
   fractional pixels, so an overlay stopping exactly at 0 leaves a one-pixel
   line of raw photo along the edge. Overhanging covers it, and the hero's
   own overflow:hidden trims the excess. */
.hero-scrim {
  position: absolute;
  inset: -2px;
  background:
    /* Just enough shadow on the left for the headline to hold, leaving the
       right two thirds of the photo close to untouched. */
    linear-gradient(
      to right,
      rgba(0, 0, 0, .24) 0%,
      rgba(0, 0, 0, .13) 42%,
      rgba(0, 0, 0, .03) 74%,
      rgba(0, 0, 0, 0) 100%
    ),
    linear-gradient(
      to bottom,
      rgba(0, 0, 0, .11) 0%,
      rgba(0, 0, 0, .09) 40%,
      rgba(9, 9, 9, .50) 80%,
      rgba(11, 11, 11, 1) 95%,
      rgba(11, 11, 11, 1) 100%
    );
}

.hero-dark { position: absolute; inset: -2px; background: #0b0b0b; opacity: 0; }

.hero-inner {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: calc(var(--nav-h) + 40px) var(--pad) 40px;
}

/* Sits over a photo, so it needs more contrast than the section eyebrows. */
.hero .eyebrow { color: #bdbdbd; }

.hero-title {
  font-size: clamp(46px, 9.2vw, 122px);
  font-weight: 200;
  color: #fff;
  letter-spacing: -.02em;
  line-height: .96;
  margin: 0 0 28px;
}

.hero-title .w { display: inline-block; white-space: nowrap; }
.hero-title .ch { display: inline-block; will-change: transform, opacity; }

.hero-sub {
  font-size: clamp(20px, 2.6vw, 30px);
  font-weight: 200;
  color: #ededed;
  margin: 0 0 14px;
  line-height: 1.3;
}

.hero-meta { font-size: 16px; color: #a9a9a9; margin: 0 0 38px; }

/* Work-page hero: shorter, its own photo. */
.hero.page {
  min-height: 58svh;
  align-items: flex-end;
}

.hero.page .hero-bg {
  background-image: url("../img/hero-work.webp");
  background-position: 50% 50%;
}

.hero.page .hero-scrim {
  background:
    linear-gradient(
      to right,
      rgba(0, 0, 0, .19) 0%,
      rgba(0, 0, 0, .10) 46%,
      rgba(0, 0, 0, 0) 88%
    ),
    linear-gradient(
      to bottom,
      rgba(0, 0, 0, .12) 0%,
      rgba(0, 0, 0, .10) 45%,
      rgba(9, 9, 9, .48) 82%,
      rgba(11, 11, 11, 1) 97%,
      rgba(11, 11, 11, 1) 100%
    );
}

.hero.page .hero-inner { padding-top: calc(var(--nav-h) + 70px); padding-bottom: 62px; }
.hero.page h1 { font-size: clamp(44px, 8vw, 96px); color: #fff; margin: 0 0 20px; }

.hero.page .lede {
  color: #c8c8c8;
  font-size: clamp(16px, 1.7vw, 20px);
  max-width: 46ch;
  margin: 0;
}

/* ---------- Trust strip ------------------------------------------------ */
/* Same colour as the hero's bottom, and pulled up a few pixels so it physically
   paints over the hero's bottom edge. Second half of the seam backstop. */

.strip { background: var(--bg); }

/* The section after a hero overlaps it by a few pixels so any sub-pixel bleed
   at the hero's edge gets painted over from the other side too.
   This is a class, not `.hero + section`: GSAP's pin wraps the hero in a spacer
   div at runtime, which breaks the adjacent-sibling match exactly when the
   pinned hero is the one that needs guarding. */
.seam-guard {
  position: relative;
  z-index: 1;
  margin-top: -4px;
}

.strip-grid { display: grid; grid-template-columns: repeat(4, 1fr); }

.strip-item {
  padding: clamp(32px, 4vw, 50px) clamp(16px, 2.4vw, 34px);
  border-right: 1px solid var(--line);
}

.strip-item:first-child { padding-left: 0; }
.strip-item:last-child { border-right: 0; }

.strip-item .k {
  display: block;
  font-size: clamp(26px, 3.4vw, 40px);
  font-weight: 200;
  color: var(--head);
  line-height: 1.05;
  margin-bottom: 8px;
}

.strip-item .v { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--dim); }

/* ---------- Testimonial carousel --------------------------------------- */
/* One testimonial at a time, full width, with the controls in the usual place:
   centred underneath, previous on the left of the dots and next on the right. */

.quotes { padding: clamp(40px, 6vh, 104px) 0; }

/* Heading on the left, the testimonial beside it. There is room for this now
   that the gutters are wider. */
@media (min-width: 1001px) {
  .quotes .wrap {
    display: grid;
    grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
    gap: clamp(32px, 4vw, 72px);
    align-items: start;
  }

  .quotes .section-head { margin-bottom: 0; align-self: center; }
  .quotes-nav { grid-column: 2; }
}

.quotes .section-head { margin-bottom: clamp(26px, 3.2vh, 44px); }
.quotes .section-head h2 { font-size: clamp(28px, 4vw, 46px); }

.quotes-rail {
  display: flex;
  gap: 24px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.quotes-rail::-webkit-scrollbar { display: none; }

.quote {
  flex: 0 0 100%;
  min-width: 0;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 2.6vw, 40px) clamp(24px, 2.8vw, 46px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-3);
}

.quote .stars {
  color: var(--red);
  font-size: 13px;
  letter-spacing: .26em;
  text-align: center;
  /* The letter-spacing adds a trailing gap that would throw the centring off. */
  text-indent: .26em;
  margin-bottom: 22px;
}

.quote blockquote {
  margin: 0 0 clamp(26px, 3vw, 40px);
  font-size: clamp(17px, 1.55vw, 22px);
  font-weight: 200;
  line-height: 1.5;
  color: var(--head);
  letter-spacing: -.005em;
  /* Cards match the tallest one so the section does not jump between slides.
     Centring a short quote in the spare room reads as deliberate. */
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Set by JS from the length of the quote: a short one gets to be bigger. */
.quote.q-lg blockquote { font-size: clamp(20px, 2.1vw, 30px); line-height: 1.42; }
.quote.q-xl blockquote { font-size: clamp(23px, 2.7vw, 38px); line-height: 1.34; }

.quote blockquote { max-width: 62ch; }
.quote blockquote p { margin-bottom: .6em; }
.quote blockquote p:last-child { margin-bottom: 0; }

/* Quotation marks come from CSS so any testimonial added later gets them. */
.quote blockquote p:first-of-type::before { content: "“"; }
.quote blockquote p:last-of-type::after { content: "”"; }

/* No rule between the words and the person who said them: same thought.
   The only divider separates the quote from the project note. */
.quote figcaption {
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.25fr);
  gap: clamp(24px, 3.4vw, 56px);
  align-items: start;
  margin-top: auto;
}

.who { display: flex; align-items: center; gap: 15px; }

.avatar {
  width: 56px;
  height: 56px;
  flex: 0 0 56px;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 30%;
  background: var(--bg-2);
}

.avatar.initials {
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: .06em;
  color: var(--muted);
}

.who b {
  display: block;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text);
  margin-bottom: 3px;
}

.who span {
  display: block;
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dim);
}

.built {
  border-left: 1px solid var(--line);
  padding-left: clamp(24px, 3.4vw, 56px);
}

.built .k {
  display: block;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--red);
  margin-bottom: 7px;
}

.built p { font-size: 13px; line-height: 1.55; color: var(--muted); margin: 0; }

/* Controls: centred under the card. */
.quotes-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-top: clamp(20px, 2.4vh, 30px);
}

/* Play/pause for the carousels. Hovering no longer stops anything, so this is
   the only way to hold a slide, which means it has to be obvious. */
.rail-toggle {
  width: 13px;
  height: 13px;
  flex: 0 0 13px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line-2);
  border-radius: 50%;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  transition: background-color .2s, border-color .2s, color .2s;
}

.rail-toggle:hover { background: var(--red); border-color: var(--red); color: #fff; }

.rail-toggle svg { width: 5px; height: 5px; fill: currentColor; display: block; }
.rail-toggle .ico-play { display: none; }
.rail-toggle[aria-pressed="true"] .ico-play { display: block; }
.rail-toggle[aria-pressed="true"] .ico-pause { display: none; }

/* In the project sliders the controls sit in a row under the image. */
.shot-nav { gap: 14px; }

/* Progress dots. The active one stretches into a pill and a fill sweeps
   across it for the length of the slide, so the dots are also the timer. */
.pdots, .rail-dots, .dots { display: flex; align-items: center; gap: 8px; }

.pdot {
  position: relative;
  width: 8px;
  height: 8px;
  flex: 0 0 auto;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--line-2);
  cursor: pointer;
  overflow: hidden;
  /* clip-path clips the fill exactly. overflow:hidden alone leaves the
     anti-aliased corners of the child poking past the rounded edge, which is
     what produced the red spikes around the pill. */
  clip-path: inset(0 round 999px);
  transition: width .45s cubic-bezier(.16, 1, .3, 1), background-color .3s;
}

.pdot.on { width: 52px; background: var(--line); }

/* Grows by width, not by scaleX. Scaling a rounded box distorts its corners
   into points; a plain square block clipped by the parent stays crisp. */
.pdot-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0;
  border-radius: 0;
  background: var(--red);
}

/* With reduced motion there is no timer, so show a plain filled dot. */
@media (prefers-reduced-motion: reduce) {
  .pdot.on { width: 8px; background: var(--red); }
  .pdot-fill { display: none; }
}

/* ---------- Capabilities ----------------------------------------------- */
/* One screen that holds still while you scroll. The writing stays on the left,
   the picture on the right, and each scroll step crossfades both to the next
   capability rather than moving the page. */

/* The wrapper is as tall as the number of capabilities; the stage sticks to
   the top of it. Height comes from a variable JS sets from the item count. */
/* The stage carries its own palette so the dark "What we build" heading and
   the grey capability panels read as two separate bands, not one block. */
/* The heading band is deliberately tall, with the copy sitting in the middle
   of it rather than at the top. */
#services > .wrap {
  min-height: 99svh;
  /* Flex rather than grid: child margins inside the heading block skew grid's
     align-content, and this centres the whole block cleanly either way. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

#services > .wrap .section-head { margin-bottom: 0; max-width: 760px; }
#services > .wrap .section-head .lede { margin-left: auto; margin-right: auto; }

.caps-scroll {
  position: relative;
  height: calc(var(--caps-steps, 4) * 100svh);
  background: var(--bg);
  color: var(--text);
}

/* The stage ends flush against whatever follows it. */
#services { padding-top: 0; padding-bottom: 0; }

.caps-stage {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: grid;
  align-items: center;
  overflow: hidden;
}

.caps-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(28px, 4vw, 76px);
  /* stretch, not center: the picture panel runs the whole height of the
     screen. The writing centres itself inside its own column. */
  align-items: stretch;
  min-height: 100svh;
  width: 100%;
  /* No centred container here. The left pad matches what the rest of the site
     uses, and the right side runs clean off the edge so the panel is not cut
     short at the gutter. 100% is the stage width, which excludes the
     scrollbar, so this cannot cause horizontal overflow. */
  padding-left: max(var(--pad), calc((100% - var(--maxw)) / 2 + var(--pad)));
  padding-right: 0;
}

/* Both stacks put every panel in the same grid cell so they crossfade in
   place, and the cell sizes itself to the tallest one. */
.caps-text, .caps-media { display: grid; }

.caps-text { align-content: center; padding: clamp(30px, 5vh, 70px) 0; }
.caps-text > *, .caps-media > * { grid-area: 1 / 1; }
.caps-media > * { justify-self: center; align-self: center; }

.cap-item {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .55s ease, transform .55s cubic-bezier(.16, 1, .3, 1);
  pointer-events: none;
}

.cap-item.on { opacity: 1; transform: none; pointer-events: auto; }

.cap-meta {
  display: flex;
  align-items: baseline;
  gap: 16px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: clamp(18px, 2.6vh, 30px);
}

.cap-meta .n { color: var(--red); margin: 0; }

.cap-item h3 {
  font-size: clamp(28px, 3.8vw, 56px);
  color: var(--head);
  margin-bottom: 20px;
}

.cap-item p { color: var(--muted); font-size: clamp(15px, 1.4vw, 18px); max-width: 46ch; }

.cap-item .tools {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dim);
}

/* The picture rests on a light panel rather than a black one, and the panel
   runs to the right edge of the screen instead of stopping at the gutter. */
.caps-media {
  position: relative;
  background: var(--bg-2);
  padding: clamp(24px, 4vh, 64px) clamp(16px, 2vw, 40px);
  place-items: center;
}

.caps-media img,
.caps-media video {
  /* Sized to the picture, not to the panel, so the corners round the artwork. */
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  justify-self: center;
  align-self: center;
  opacity: 0;
  transition: opacity .55s ease;
  border-radius: var(--img-radius);
}

.caps-media img.on,
.caps-media video.on { opacity: 1; }

/* The per-item picture is for the stacked phone layout only. */
.cap-item-img { display: none; }

/* ---------- Work cards ------------------------------------------------- */

.work-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 40px);
}

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--img-radius);
  overflow: hidden;
  background: var(--bg-3);
  overflow: hidden;
  transition: border-color .3s, transform .3s;
}

.card:hover { border-color: var(--tint-2); }

.card-media { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: #070707;
  border-radius: var(--img-radius) var(--img-radius) 0 0; }

.card-media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  transition: transform .6s cubic-bezier(.16, 1, .3, 1);
}

.card:hover .card-media img { transform: scale(1.045); }

/* On the home page these sit on a black section but read light themselves,
   so the rounded bottom corners have to be carried through. */
.card-body {
  flex: 1 1 auto;
  padding: clamp(22px, 2.6vw, 34px);
  border-radius: 0 0 var(--img-radius) var(--img-radius);
}

.card-body .k {
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 12px;
}

.card-body h3 { font-size: clamp(22px, 2.5vw, 30px); color: var(--head); margin-bottom: 12px; }
.card-body p { color: var(--muted); font-size: 15px; }

.card-body .go {
  display: inline-block;
  margin-top: 18px;
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text);
  border-bottom: 1px solid var(--line-2);
  padding-bottom: 5px;
  transition: color .2s, border-color .2s;
}

.card:hover .go { border-color: var(--red); }

/* ---------- Process ---------------------------------------------------- */

.steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(20px, 3vw, 44px); }

/* Each step's top rule draws itself left to right, then the copy fades up
   after it. The .drawn class lands once the section scrolls into view. */
.step { position: relative; padding-top: 26px; }

.step::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: var(--line-2);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1s cubic-bezier(.16, 1, .3, 1);
}

.step > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .55s ease, transform .55s cubic-bezier(.16, 1, .3, 1);
}

.steps.drawn .step::before { transform: scaleX(1); }
.steps.drawn .step > * { opacity: 1; transform: none; }

/* Lines start one after another; each step's copy follows its own line. */
.steps.drawn .step:nth-child(2)::before { transition-delay: .2s; }
.steps.drawn .step:nth-child(3)::before { transition-delay: .4s; }
.steps.drawn .step:nth-child(1) > *:nth-child(1) { transition-delay: .3s; }
.steps.drawn .step:nth-child(1) > *:nth-child(2) { transition-delay: .4s; }
.steps.drawn .step:nth-child(1) > *:nth-child(3) { transition-delay: .5s; }
.steps.drawn .step:nth-child(2) > *:nth-child(1) { transition-delay: .5s; }
.steps.drawn .step:nth-child(2) > *:nth-child(2) { transition-delay: .6s; }
.steps.drawn .step:nth-child(2) > *:nth-child(3) { transition-delay: .7s; }
.steps.drawn .step:nth-child(3) > *:nth-child(1) { transition-delay: .7s; }
.steps.drawn .step:nth-child(3) > *:nth-child(2) { transition-delay: .8s; }
.steps.drawn .step:nth-child(3) > *:nth-child(3) { transition-delay: .9s; }

.step .n { font-size: 12px; font-weight: 500; letter-spacing: .18em; color: var(--red); margin-bottom: 16px; }
.step h3 { font-size: clamp(19px, 2vw, 24px); color: var(--head); margin-bottom: 12px; }
.step p { color: var(--muted); font-size: 15px; }

/* ---------- CTA card ---------------------------------------------------- */
/* A rounded panel inset from the page rather than a full-bleed band, with the
   photo living inside the card. */

.cta-wrap { padding: clamp(48px, 7vw, 104px) 0 clamp(30px, 4vw, 56px); background: var(--bg); }

.cta-card {
  position: relative;
  overflow: hidden;
  border-radius: clamp(16px, 1.8vw, 26px);
  background: #0b0b0b;
  color: #e8e8e8;
  padding: clamp(34px, 5vw, 82px) clamp(26px, 4.4vw, 74px);
}

.cta-bg {
  position: absolute;
  inset: -2px;
  background-image: url("../img/cta-bg.webp");
  background-position: 50% 58%;
  background-size: cover;
}

.cta-scrim {
  position: absolute;
  inset: -2px;
  background:
    linear-gradient(to right, rgba(9, 9, 9, .68) 0%, rgba(9, 9, 9, .50) 38%, rgba(9, 9, 9, .13) 72%, rgba(9, 9, 9, .08) 100%),
    linear-gradient(to bottom, rgba(9, 9, 9, .18) 0%, rgba(9, 9, 9, .13) 50%, rgba(9, 9, 9, .24) 100%);
}

.cta-inner { position: relative; z-index: 2; max-width: 640px; }

.cta-inner .eyebrow { color: #9a9a9a; }
.cta-inner h2 { font-size: clamp(30px, 4.6vw, 56px); color: #fff; margin-bottom: 20px; }
.cta-inner p { color: #c4c4c4; font-size: clamp(15px, 1.5vw, 18px); margin-bottom: 30px; }

/* Two-by-two list of what you get, from the reference layout. */
.cta-points {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px 26px;
  list-style: none;
  margin: 0 0 34px;
  padding: 0;
}

.cta-points li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 14px;
  color: #dcdcdc;
  line-height: 1.45;
}

.cta-points li::before {
  content: "✓";
  color: var(--red-lift);
  font-size: 13px;
  line-height: 1.5;
  flex: 0 0 auto;
}

.cta-card .btn:not(.primary) { border-color: rgba(255, 255, 255, .45); color: #fff; }
.cta-card .btn:not(.primary):hover { background: rgba(255, 255, 255, .12); border-color: #fff; }

/* ---------- Footer ----------------------------------------------------- */

.footer { background: var(--bg); padding: clamp(30px, 4vw, 54px) 0 34px; }

.footer-cols {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
  gap: clamp(26px, 4vw, 60px);
  padding-bottom: clamp(30px, 4vw, 52px);
}

.fb-name {
  font-size: 19px;
  font-weight: 500;
  /* No uppercase transform: the mark is written Jwm.nyc, not JWM.NYC. */
  letter-spacing: .01em;
  color: var(--head);
  margin-bottom: 12px;
}

.fb-tag { color: var(--dim); font-size: 13px; line-height: 1.6; max-width: 34ch; }

.footer-col h4 {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--head);
  margin-bottom: 16px;
}

.footer-col a {
  display: block;
  font-size: 13px;
  color: var(--dim);
  padding: 5px 0;
  transition: color .2s;
}

.footer-col a:hover { color: var(--red-lift); }

.footer-base {
  border-top: 1px solid var(--line);
  padding-top: 26px;
  text-align: center;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dim);
}

/* ---------- Gallery page ----------------------------------------------- */

.jump { display: flex; flex-wrap: wrap; gap: 10px 12px; margin-top: 32px; }

.jump a {
  padding: 9px 16px;
  border: 1px solid rgba(255, 255, 255, .24);
  border-radius: var(--radius);
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #dcdcdc;
  transition: background-color .2s, border-color .2s, color .2s;
}

.jump a:hover { background: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, .4); color: #fff; }

.group { padding: clamp(66px, 9vw, 118px) 0; background: var(--bg); color: var(--text); }

.group-head {
  padding-bottom: 22px;
  border-bottom: 1px solid var(--line-2);
  margin-bottom: clamp(34px, 4.5vw, 60px);
}

.group-head h2 { font-size: clamp(28px, 4.4vw, 46px); color: var(--head); }

.group-intro { color: var(--muted); max-width: 64ch; margin: -14px 0 clamp(34px, 4vw, 56px); font-size: 15px; }

.proj {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 60px);
  align-items: start;
  padding: clamp(34px, 4.5vw, 62px) 0;
  border-top: 1px solid var(--line);
}

.proj:first-of-type { border-top: 0; padding-top: 0; }

.proj-media { position: relative; }

/* No dark frame: the image sits straight on the section background, so rounded
   screen corners and light UI shots read as themselves. */
.shot {
  position: relative;
  aspect-ratio: 16 / 10;
  background: transparent;
  cursor: zoom-in;
}

/* A tinted bed for mockups that carry no background of their own. */
.shot.tint-green {
  --tint-pad: clamp(14px, 1.8vw, 34px);
  background: #e3efe2;
  border-radius: var(--img-radius);
}

/* The art fills the tint edge to edge top and bottom. cover would crop the
   sides, so contain keeps it whole and the panel takes the image's ratio. */
.shot.tint-green { aspect-ratio: 1986 / 1200; }

.shot.tint-green img,
.shot.tint-green video {
  inset: 0;
  margin: auto;
  max-width: 100%;
  max-height: 100%;
}

.shot img,
.shot video {
  position: absolute;
  inset: 0;
  margin: auto;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  opacity: 0;
  transition: opacity .45s ease;
  border-radius: var(--img-radius);
}

.shot img.on,
.shot video.on { opacity: 1; }

/* Controls sit under the image rather than floating on top of it. */
.shot-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 16px;
}

.arrows { display: flex; gap: 8px; }

.arrows button {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  padding: 0;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text);
  font-size: 14px; line-height: 1;
  cursor: pointer;
  transition: background-color .2s, border-color .2s, color .2s;
}

.arrows button:hover { background: var(--red); border-color: var(--red); color: #fff; }

.proj-copy .k { font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--red); margin-bottom: 14px; }
.proj-copy h3 { font-size: clamp(24px, 3vw, 34px); color: var(--head); margin-bottom: 10px; }

.proj-role { font-size: 13px; letter-spacing: .04em; color: var(--dim); margin-bottom: 20px; }
.proj-role span { display: block; }

.proj-copy p { color: var(--muted); font-size: 15px; }

.proj-links { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }

.proj-links a {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 10px 17px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text);
  transition: background-color .2s, border-color .2s, color .2s;
}

.proj-links a:hover { background: var(--red); border-color: var(--red); color: #fff; }
.proj-links a.ghost:hover { background: var(--tint); border-color: var(--tint-2); color: var(--head); }

/* ---------- Lightbox ---------------------------------------------------- */
/* Clicking a project image opens it full screen with left and right paging. */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  place-items: center;
  background: rgba(6, 6, 6, .96);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.lightbox.open { display: grid; }

.lb-stage {
  position: relative;
  width: min(94vw, 1500px);
  height: min(84vh, 900px);
  display: grid;
  place-items: center;
}

.lb-stage img,
.lb-stage video {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 2px;
}

.lightbox button {
  position: absolute;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: var(--radius);
  background: rgba(0, 0, 0, .55);
  color: #f0f0f0;
  cursor: pointer;
  transition: background-color .2s, border-color .2s;
}

.lightbox button:hover { background: var(--red); border-color: var(--red); color: #fff; }

.lb-prev, .lb-next {
  top: 50%;
  width: 52px; height: 52px;
  margin-top: -26px;
  font-size: 22px;
  line-height: 1;
}

.lb-prev { left: clamp(10px, 2.5vw, 40px); }
.lb-next { right: clamp(10px, 2.5vw, 40px); }

.lb-close {
  top: clamp(14px, 2.4vw, 30px);
  right: clamp(14px, 2.4vw, 30px);
  width: 46px; height: 46px;
  font-size: 20px;
  line-height: 1;
}

.lb-count {
  position: absolute;
  left: 0; right: 0;
  bottom: clamp(14px, 2.4vw, 30px);
  margin: 0;
  text-align: center;
  font-size: 11px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: #9c9c9c;
}

.lightbox[data-single="true"] .lb-prev,
.lightbox[data-single="true"] .lb-next,
.lightbox[data-single="true"] .lb-count { display: none; }

/* Reveal-on-scroll base state (GSAP takes over once it loads) */
[data-reveal] { opacity: 0; transform: translateY(26px); }
.reveal-ready [data-reveal] { opacity: 1; transform: none; }

/* ---------- Responsive ------------------------------------------------- */

@media (max-width: 1000px) {
  /* No pinned stage on a phone: the capabilities simply stack, each with its
     own picture above its writing. */
  .caps-scroll { height: auto; }
  .caps-stage { position: static; min-height: 0; display: block; overflow: visible; }
  .caps-inner { grid-template-columns: minmax(0, 1fr); gap: 0; padding: 0 var(--pad); }
  .caps-media { display: none; }
  .caps-text { display: block; }

  .cap-item {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    padding: clamp(30px, 6vw, 48px) 0;
    border-top: 1px solid var(--line);
  }

  .cap-item:first-child { border-top: 0; }

  .cap-item-img {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 10;
    object-fit: contain;
    background: var(--bg-2);
    border-radius: var(--img-radius);
    padding: 10px;
    margin-bottom: clamp(20px, 4vw, 30px);
  }

  .footer-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .proj { grid-template-columns: minmax(0, 1fr); }
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  :root { --nav-h: 58px; }

  .nav-toggle { display: block; }

  .nav-links {
    position: fixed;
    top: var(--nav-h);
    left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px var(--pad) 24px;
    background: rgba(8, 8, 8, .98);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid rgba(255, 255, 255, .12);
    transform: translateY(-12px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity .25s, transform .25s, visibility .25s;
  }

  .nav.open .nav-links { opacity: 1; visibility: visible; pointer-events: auto; transform: none; }

  .nav-links a { padding: 15px 0; border-bottom: 1px solid rgba(255, 255, 255, .12); font-size: 14px; }
  .nav-links a.nav-cta { margin-top: 16px; padding: 15px 18px; text-align: center; border-bottom: 0; }

  .strip-grid { grid-template-columns: repeat(2, 1fr); }
  .strip-item { padding-left: 0; }
  .strip-item:nth-child(2n) { border-right: 0; padding-left: clamp(16px, 4vw, 34px); }
  .strip-item:nth-child(-n+2) { border-bottom: 1px solid var(--line); }

  .work-grid { grid-template-columns: minmax(0, 1fr); }
  .steps { grid-template-columns: minmax(0, 1fr); }
  .cta-points { grid-template-columns: minmax(0, 1fr); }
  .cta-card { padding: clamp(26px, 6vw, 40px) clamp(20px, 5vw, 32px); }
  .cta-inner .btn { width: 100%; }

  .quote { padding: 22px; }
  .quote blockquote { font-size: 17px; line-height: 1.5; margin-bottom: 22px; }
  .quote.q-lg blockquote { font-size: 19px; }
  .quote.q-xl blockquote { font-size: 21px; }
  .quote .stars { margin-bottom: 14px; }

  /* Stack the person above the project note, and move the divider with it. */
  .quote figcaption { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .built {
    border-left: 0;
    padding-left: 0;
    border-top: 1px solid var(--line);
    padding-top: 16px;
  }

  @media (max-width: 520px) {
  .footer-grid { flex-direction: column; align-items: flex-start; }
  .btn { padding: 0 18px; font-size: 12px; }
  .arrows button { width: 40px; height: 40px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .step::before { transform: none !important; }
  .step > * { opacity: 1 !important; transform: none !important; }
  html { scroll-behavior: auto; }
}
