/* =========================================================
   Unopen — Homepage
   Built from Figma "Unopen Website":
   Desktop 1920 (549:998) · Tablet 1000 (51:3) · Mobile 480 (58:91)

   Everything is sized in design pixels multiplied by --s,
   so each layout scales smoothly from its Figma frame.
   ========================================================= */

:root {
  /* Brand colors (from Figma) */
  --navy: #00001e;        /* page background */
  --ink: #ffffff;         /* text on navy */
  --blue: #0d29e4;        /* primary blue: portfolio, borders */
  --sky: #4fa3f6;         /* links, "Learn More", "Connect with our team" */
  --pill: #0d1f3b;        /* nav Contact button */
  --pill-hover: #11294c;  /* Contact button hover fill */
  --mist: #eff5fe;        /* light portfolio background */
  --frame: #4c9dee;       /* portfolio tile frames */
  --tile-shade: #e7edfc;  /* the two darker tiles (Multivu, Northeastern) */
  --flag: #e4ecf9;
  --client: #3366f1;      /* "@Client" names on the work cards */        /* white corner flag on hovered tiles */

  --font: "Poppins", "Helvetica Neue", Arial, sans-serif;

  /* Scale: 1 design px. Desktop frame is 1920 wide. */
  --s: min(1px, calc(100vw / 1920));
  --gutter: calc(200 * var(--s));
  /* height of the scroll video's original 16:9 frame as drawn on screen */
  --stage-h: calc(min(100vw, 100svh * 16 / 9) * 9 / 16);
  /* space between "Unlocking New Dimensions" and the portfolio section */
  --flow-gap: calc(295 * var(--s));
  /* where the video frame sits on screen while pinned: low enough that the
     text ends exactly --flow-gap above the bottom of the screen, so the
     portfolio arrives right as the animation lets go (text ends 714px down
     the 1080px frame) */
  --stage-top: calc(100svh - var(--flow-gap) - var(--stage-h) * 714 / 1080);
  color-scheme: dark;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--navy);
  color: var(--ink);
  font-family: var(--font);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, p { margin: 0; font-weight: 400; }
h1, h2, h3 { text-wrap: balance; }

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--sky);
  outline-offset: 4px;
  border-radius: 2px;
}

/* Placeholder boxes for images/videos still to come */
.placeholder {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  padding: 1em;
  border: 1px dashed rgba(79, 163, 246, .6);
  background: repeating-linear-gradient(135deg, rgba(79,163,246,.06) 0 12px, transparent 12px 24px);
  color: var(--sky);
  font-size: max(12px, calc(16 * var(--s)));
  text-align: center;
}

/* =========================================================
   NAV
   ========================================================= */
.nav {
  position: relative;
  z-index: 10;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: calc(40 * var(--s)) calc(60 * var(--s)) calc(16 * var(--s));
  min-height: calc(120 * var(--s));
  background: var(--navy);
}
.nav__mark {
  position: relative;
  justify-self: start;
  display: block;
  width: calc(36 * var(--s));
  min-width: 22px;
  aspect-ratio: 36 / 67;
}
.nav__mark svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: var(--ink);
}
.nav__mark path { transition: transform .35s cubic-bezier(.3, .7, .2, 1); }
/* Hover: the two strokes of the N pull apart vertically, then rejoin */
.nav__mark:hover .nav__mark-top,
.nav__mark:focus-visible .nav__mark-top { transform: translateY(-9.5px); }
.nav__mark:hover .nav__mark-bottom,
.nav__mark:focus-visible .nav__mark-bottom { transform: translateY(9.5px); }
@media (prefers-reduced-motion: reduce) { .nav__mark path { transition: none; } }
.nav__wordmark img { width: calc(258 * var(--s)); }
.nav__links {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: calc(48 * var(--s));
  font-size: max(14px, calc(18 * var(--s)));
}
.nav__links a { position: relative; }
.nav__contact { display: none; }

/* White links: underline via .uline (see "UNDERLINES THAT MOVE") */
/* Contact: a lighter fill sweeps in from the left, and out to the right
   (on desktop it is a button, so no underline) */
@media (min-width: 1100px) { .nav__cta .uline { background-image: none; } }
.nav__cta {
  isolation: isolate;
  overflow: hidden;
  color: var(--sky);
  background: var(--pill);
  border-radius: 3px;
  padding: calc(12 * var(--s)) calc(16 * var(--s));
}
.nav__cta::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--pill-hover);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform .45s cubic-bezier(.6, .05, .3, 1);
}
.nav__cta:hover::before,
.nav__cta:focus-visible::before {
  transform: scaleX(1);
  transform-origin: left center;
}
@media (prefers-reduced-motion: reduce) {
  .nav__cta::before { transition-duration: .01s; }
}

.nav__toggle {
  display: none;
  justify-self: end;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.nav__toggle svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* Hover (from the Wix recording): the fill lightens to the SVG's colour while
   the pointer is over the button and darkens again when it leaves, near-instantly */
.nav__toggle-bg { fill: #10203B; }
/* hover: the lighter fill sweeps in from the left, and leaves to the right */
.nav__toggle-sweep {
  fill: #152A4E;
  transform-box: fill-box;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform .5s cubic-bezier(.8,0,.18,.72);
}
.nav__toggle:hover .nav__toggle-sweep,
.nav__toggle:focus-visible .nav__toggle-sweep { transform: scaleX(1); transform-origin: left center; }
/* Open/close animation (copied from the Wix recording, 0.32s each way).
   Each line has two moves: sliding to the middle (.mv) and turning (.bar).
   Into the X, the lines turn first and then meet, so halfway it reads "<";
   back out, they separate first and then level, so it reads "<" again. */
.nav__toggle .bar {
  stroke: #4A99E8;
  stroke-width: 2.2;
  transform-box: fill-box;
  transform-origin: center;
  transition: transform .32s cubic-bezier(.6, 0, .4, 1);      /* turning back: late */
}
.nav__toggle .mv {
  transition: transform .32s cubic-bezier(.2, .6, .3, 1);      /* separating: early */
}
.nav.is-open .bar { transition-timing-function: cubic-bezier(.2, .6, .3, 1); }   /* turning in: early */
.nav.is-open .mv { transition-timing-function: cubic-bezier(.6, 0, .4, 1); }     /* meeting: late */

.nav.is-open .mv--top    { transform: translateY(3.75px); }
.nav.is-open .mv--bottom { transform: translateY(-3.75px); }
.nav.is-open .mv--top .bar    { transform: rotate(-45deg); }
.nav.is-open .mv--bottom .bar { transform: rotate(45deg); }
@media (prefers-reduced-motion: reduce) { .nav__toggle .bar, .nav__toggle .mv { transition: none; } }


/* =========================================================
   HERO
   ========================================================= */
.hero {
  position: relative;
  isolation: isolate;
  padding: calc(212 * var(--s)) var(--gutter) 0;
}

/* Background video, placed as on Wix: about 1.2x the window width,
   shifted left so its animated lines sit to the right of the title.
   It is fixed to the window, so the page scrolls over it.
   --nav-h is set by main.js to the nav's real height. */
.hero__bg {
  position: fixed;
  z-index: -1;
  top: var(--nav-h, 120px);
  left: calc(var(--bg-w) * -0.188);
  width: var(--bg-w);
  aspect-ratio: 1920 / 1200;
  pointer-events: none;
  --bg-w: 120.6vw;
  /* soften the video's own bottom edge, so it never shows as a line
     (on tall phone screens the video ends above the bottom of the screen) */
  -webkit-mask-image: linear-gradient(to bottom, #000 65%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 65%, transparent 100%);
}

/* Everything after the hero: opaque, so it slides over the fixed video.
   (The gradient behind "Designing Experiences…" will go on .work.) */
.stage,
.footer {
  position: relative;
  z-index: 1;
  background: var(--navy);
}
/* The fixed hero video fades into the page instead of stopping at a hard
   edge. The fade is the supplied gradient (navy, clear to solid), 2153px
   tall at 1920 wide, scaled with the screen width; it starts a little
   above "Designing Experiences…". */
.stage {
  --fade-start: -13.5vw;                 /* about 260px above the section at 1920 */
  --fade-len: 112.1vw;                   /* 2153px at 1920 */
  background: linear-gradient(to bottom,
      transparent 0,
      transparent calc(var(--fade-start) + var(--fade-len)),
      var(--navy) calc(var(--fade-start) + var(--fade-len)));
}
.stage::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 0;
  right: 0;
  top: var(--fade-start);
  height: var(--fade-len);
  pointer-events: none;
  background: linear-gradient(to bottom,
    rgba(0, 0, 30, 0) 0%,
    rgba(0, 0, 30, .153) 10%,
    rgba(0, 0, 30, .306) 20%,
    rgba(0, 0, 30, .435) 30%,
    rgba(0, 0, 30, .565) 40%,
    rgba(0, 0, 30, .675) 50%,
    rgba(0, 0, 30, .773) 60%,
    rgba(0, 0, 30, .859) 70%,
    rgba(0, 0, 30, .925) 80%,
    rgba(0, 0, 30, .976) 90%,
    rgba(0, 0, 30, 1) 100%);
}
.hero__bg video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__title {
  text-wrap: wrap;
  max-width: calc(920 * var(--s));
  font-size: calc(113 * var(--s));
  line-height: 1.106;
  letter-spacing: -0.04em;
}

.hero__title .line { display: block; white-space: nowrap; }

/* Title reveal: each word slides up from behind a mask, one after another */
.hero__title .w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: .12em;
  margin-bottom: -.12em;
}
/* Based on "3_Title_Texts" (0.58s, words 0.1s apart), lengthened by 0.3s:
   the extra time goes into a gentler start, so each word eases into
   motion before gliding up and settling. */
.hero__title .w > span {
  display: inline-block;
  animation: word-rise 1.08s cubic-bezier(.45, 0, 0, 1) backwards;   /* +0.2s, glides to a full stop */
  animation-delay: calc(var(--i) * .1s);
}
@keyframes word-rise {
  from { transform: translateY(104%); }
  to   { transform: translateY(0); }
}
.hero__lede,
.hero__more {
  animation: fade-up 1.5s cubic-bezier(.25, .1, 0, 1) backwards;   /* long, soft fade that glides to a stop */
  animation-delay: .75s;
}
.hero__more { animation-delay: .9s; }
@keyframes fade-up {
  from { opacity: 0; transform: translateY(14px); }
}
/* Line reveal (e.g. "Designing Experiences…"): each line slides up from
   behind its own mask when the heading scrolls into view. Like the hero
   title but 0.3s slower and easing in more; lines start 0.1s apart.
   JS splits the lines. */
.line-reveal .rl { display: block; overflow: hidden; padding-bottom: .12em; margin-bottom: -.12em; }
.line-reveal .rl > span {
  display: inline-block;
  transform: translateY(104%);
  transition: transform 1.38s cubic-bezier(.6, 0, 0, 1);   /* softer start, settles to a full stop */
  transition-delay: calc(var(--i) * .1s);
}
.line-reveal.is-in .rl > span { transform: none; }
.line-reveal.no-anim .rl > span { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .line-reveal .rl > span { transform: none; transition: none; }
}
/* Phones and tablets can still be busy loading when these animations would
   start, so they'd finish before anything is drawn. With JS on, they wait
   (words hidden) until main.js marks the page ready. */
.js:not(.is-ready) .hero__title .w > span,
.js:not(.is-ready) .hero__lede,
.js:not(.is-ready) .hero__more { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .hero__title .w > span, .hero__lede, .hero__more { animation: none; }
}
.hero__lede {
  max-width: calc(478 * var(--s));
  margin-top: calc(134 * var(--s));
  font-size: calc(35 * var(--s));
  line-height: 1.2;
  letter-spacing: -0.04em;
}
.hero__more {
  display: inline-flex;
  align-items: center;
  gap: .77em;                        /* triangle and gap scale with the text */
  margin-top: calc(56 * var(--s));
  color: var(--sky);
  font-size: max(14px, calc(22 * var(--s)));
  letter-spacing: -0.04em;
}
.hero__tri { display: block; flex: none; width: 1.29em; height: .645em; fill: currentColor; transition: transform .25s; }   /* solid triangle pointing down */
.hero__more:hover .hero__tri { transform: translateY(4px); }

/* =========================================================
   WORK CARDS
   ========================================================= */
.work { padding: calc(170 * var(--s)) var(--gutter) 0; }
.work__title {
  max-width: calc(797 * var(--s));
  margin-left: auto;
  text-align: right;
  font-size: calc(70 * var(--s));
  line-height: 1.1;
  letter-spacing: -0.04em;
}
/* Card layout measured from the Wix screenshot (card width = 1 unit):
   cards are 0.762 wide : 1 tall, 0.127 apart, each stepping down
   0.292 / 0.611 / 0.998 card-widths, and the row starts 0.234 above
   the bottom of the title. Inside, everything is in % of card width (cqw). */
.cards {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: calc(44 * var(--s));
  align-items: start;
  margin-top: calc(-81 * var(--s));
}
/* % margins on grid items are a share of the card's own width */
.card--2 { margin-top: 29.2%; }
.card--3 { margin-top: 61.1%; }
.card--4 { margin-top: 99.8%; }

.card {
  position: relative;
  container-type: inline-size;
  aspect-ratio: 607 / 796;
  border: 1px solid var(--frame);
  min-width: 0;
}
/* Entrance: each card fades in while rising from 48px lower, 0.6s ease-in,
   one after another 0.15s apart, left first. main.js adds .is-in once the
   visitor has started scrolling and the card is in view. Uses "translate" so it adds to the layout transforms. */
.js .card {
  opacity: 0;
  translate: 0 48px;
  transition: opacity .8s cubic-bezier(.4, 0, 0, 1), translate .8s cubic-bezier(.4, 0, 0, 1);   /* +0.2s, eases to a stop */
}
.js .card.is-in { opacity: 1; translate: none; }
@media (prefers-reduced-motion: reduce) {
  .js .card { opacity: 1; translate: none; transition: none; }
}

.card__media {
  position: absolute;
  top: 1.3cqw;
  left: 1.5cqw;
  right: 1.5cqw;
  height: 91cqw;
  overflow: hidden;
  background: var(--navy);
}
.card__media img,
.card__media video { display: block; width: 100%; height: 100%; object-fit: cover; }
.card__caption {
  position: absolute;
  left: 3cqw;
  right: 3cqw;
  bottom: 3.7cqw;
  font-size: 8.5cqw;        /* measured from letter heights in the screenshot */
  line-height: 1.155;
  letter-spacing: -0.05em;
  text-wrap: wrap;   /* plain wrapping, like Wix (headings elsewhere use balance) */
  /* the extra space before "@Client" is a non-breaking space attached to the
     previous word, so a client name that wraps still starts flush left */
}
.card__client { color: var(--client); white-space: nowrap; }

/* =========================================================
   AI INTEGRATED DESIGN FLOW
   ========================================================= */
.flow {
  padding-top: calc(135 * var(--s));
  /* clear down to the bottom of the title (the background video shows behind
     it), then fades to solid navy, so nothing of the fixed hero video shows
     through behind the scroll animation */
  background: linear-gradient(to bottom, transparent calc(135 * var(--s) + 2.2 * var(--fs-title)), var(--navy) calc(135 * var(--s) + 4 * var(--fs-title)));
}
.flow__title {
  /* stays over the animation while it is pinned, then scrolls away with it
     (main.js sets --hold and --tm) */
  position: sticky;
  top: var(--hold, 0px);
  margin-bottom: var(--tm, 0px);
  z-index: 2;   /* stays on top of the video's empty upper-left area */
  max-width: calc(528 * var(--s));
  margin-left: var(--gutter);
  font-size: calc(70 * var(--s));
  line-height: 1.1;
  letter-spacing: -0.04em;
}

/* Scroll-driven video.
   The outer box is tall; the inner box sticks to the screen while you scroll
   through it, and main.js maps scroll position to a frame of the video.
   --scrub-length is how much scrolling the pinned part takes. */
.scrub {
  --scrub-length: 500px;
  /* height of the video's original 16:9 frame as drawn on screen */
  position: relative;
  /* --scrub-hold (set by main.js): extra scrolling at the start and the end
     where the first / last frame stays still */
  height: calc(100vh + var(--scrub-length) + var(--scrub-hold, 0px));
  height: calc(100svh + var(--scrub-length) + var(--scrub-hold, 0px));
  /* Place the video so "Your Journey Starts Here" (25% down the original frame)
     starts about 233px (at 1920 wide) under the section title */
  margin-top: calc(233 * var(--s) - var(--stage-top) - var(--stage-h) * 0.2509 - var(--tm, 0px));
}
.scrub__pin {
  position: sticky;
  /* --pin-top (main.js): pins a little down the screen so the animation
     sticks at the same moment, and distance, as the title above it */
  top: var(--pin-top, 0px);
  height: calc(100vh - var(--pin-top, 0px));
  height: var(--pin-hd, calc(100svh - var(--pin-top, 0px)));   /* --pin-hd (main.js): ends a set space under the shapes */
  overflow: hidden;
}
/* The stage is the original 1920×1080 frame. 1 frame pixel = var(--u). */
.scrub__stage {
  --u: calc(100cqw / 1920);
  container-type: inline-size;
  position: relative;
  width: min(100vw, 100svh * 16 / 9);
  aspect-ratio: 16 / 9;
  /* --stage-mt (main.js): the same distance under the title, in proportion
     to the width, at every screen size */
  margin: var(--stage-mt, var(--stage-top)) auto 0;
  /* no clipping here: the text runs off the edge of the screen like normal content */
  overflow: visible;
}
/* The video file is cropped to the band where the animation happens
   (frame rows 200–800), so it sits 200px down the frame. */
.scrub__video {
  position: absolute;
  left: 0;
  top: calc(200 / 1080 * 100%);
  width: 100%;
  height: calc(600 / 1080 * 100%);
  display: block;
  background: var(--navy);
}
/* Desktop: a navy fade between the animation and the text, so the text reads
   clearly. Same curve as the supplied gradient (alpha = 1 - (1 - t)^1.6),
   starting just left of the text and topping out at 50%, so the shapes still show
   faintly behind the words. Covers only the animation band (rows 200-800). */
.scrub__shade {
  position: absolute;
  top: calc(200 / 1080 * 100%);
  height: calc(600 / 1080 * 100%);
  left: calc(1110 * var(--u));
  right: 0;
  pointer-events: none;
  background: linear-gradient(to right,
    rgba(0, 0, 30, 0) 0,
    rgba(0, 0, 30, 0.096) calc(300 * var(--u) * 0.125),
    rgba(0, 0, 30, 0.184) calc(300 * var(--u) * 0.25),
    rgba(0, 0, 30, 0.264) calc(300 * var(--u) * 0.375),
    rgba(0, 0, 30, 0.335) calc(300 * var(--u) * 0.5),
    rgba(0, 0, 30, 0.396) calc(300 * var(--u) * 0.625),
    rgba(0, 0, 30, 0.446) calc(300 * var(--u) * 0.75),
    rgba(0, 0, 30, 0.482) calc(300 * var(--u) * 0.875),
    rgba(0, 0, 30, 0.5) calc(300 * var(--u)));
}
@media (max-width: 1099px) { .scrub__shade { display: none; } }
/* Text column: placed and sized exactly as in the reference animation */
.scrub__text {
  position: absolute;
  top: 0;
  left: calc(1228 * var(--u));
  width: calc(600 * var(--u));
  will-change: transform;
}
.flow__step { position: absolute; left: 0; width: 100%; }
.flow__step--journey { top: calc(-8.4 * var(--u)); }
.flow__step--unlock  { top: calc(770.6 * var(--u)); }
/* Sizes fitted to the reference: 36px heading on 42px lines, 20px text on 25px lines */
/* Line breaks (.lb) follow the reference animation exactly on large screens */
.flow__step h3 {
  font-size: calc(36 * var(--u));
  line-height: calc(42 / 36);
  letter-spacing: -0.04em;   /* same as the other headings (Figma: -4%) */
}
.flow__step p {
  white-space: nowrap;
  margin-top: calc(23.1 * var(--u));
  font-size: calc(20 * var(--u));
  line-height: 1.25;
  letter-spacing: -0.04em;   /* same as the other body text (Figma "Text": -4%) */
}

/* Phones and tablets: the frame would make the text too small, so the
   video sits on top and the two text blocks slide past each other below it,
   on the same timing as the desktop animation. */
@media (max-width: 1099px) {
  /* The animation and its text stay pinned together in the middle of the
     screen while you scroll through the section (main.js sets --pin-h); the
     scrolling plays the animation, and halfway through the first text fades
     out and the second fades in, so both are read with the shapes in view. */
  .scrub {
    margin-top: calc(0px - var(--tm, 0px));
    height: calc(var(--pin-h, 100svh) + 110svh + var(--scrub-hold, 0px));
  }
  .scrub__pin {
    position: sticky;
    top: var(--pin-top, max(0px, calc((100svh - var(--pin-h, 0px)) / 2)));   /* main.js: pinned together with the title */
    height: auto;
    padding: 24px 0 calc(48 * var(--s) + 15px);   /* dark gap = the title's inset in the light box */
  }
  .scrub__stage {
    width: 100%;
    margin: 0;
    aspect-ratio: auto;
    height: auto;
    display: flex;
    flex-direction: column;
  }
  .scrub__video {
    position: relative;
    top: auto;
    height: auto;
    aspect-ratio: 1920 / 600;
    flex: none;
  }
  .scrub__text {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    height: var(--text-h, 40svh);
    margin: 20px var(--gutter) 0;
    overflow: visible;
  }
  .scrub__text-track { position: relative; height: 100%; }
  .flow__step--journey,
  .flow__step--unlock { top: 0; }     /* same spot: one fades out, the other fades in */
  .flow__step { --rise: 40px; }
  .flow__step--unlock { --rise: 28px; }
  .flow__step > h3,
  .flow__step > p { transition: opacity 1s ease, translate 1s cubic-bezier(.4, 0, 0, 1); }
  .flow__step > p { transition-delay: .15s; }
  .scrub--up .flow__step--unlock > p { transition-delay: 0s; }
  .scrub--up .flow__step--unlock > h3 { transition-delay: .15s; }
  .flow__step.is-out > h3,
  .flow__step.is-out > p { opacity: 0; translate: none; transition-duration: .5s; transition-delay: 0s !important; }
  .flow__step.is-below > h3,
  .flow__step.is-below > p { opacity: 0; translate: 0 var(--rise); transition: none; }
  .lb { display: none; }
  .flow__step h3 { font-size: 22px; line-height: 1.15; }
  .flow__step p { white-space: normal; margin-top: 14px; font-size: 15px; line-height: 1.4; max-width: 34em; }
}

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* =========================================================
   PORTFOLIO
   ========================================================= */
.portfolio {
  position: relative;
  z-index: 1;
  /* no margin: the pinned video already ends --flow-gap below its text */
  margin-top: 0;
  padding: calc(138 * var(--s)) var(--gutter) calc(206 * var(--s));
  background: var(--mist);
  color: var(--blue);
}
.portfolio__title {
  max-width: calc(281 * var(--s));
  margin-left: calc(12 * var(--s));
  font-size: calc(70 * var(--s));
  line-height: 1.1;
  letter-spacing: -0.04em;
}
/* Measurements below are from the Figma screenshot: a small tile is 352px,
   so each percentage is (size in screenshot ÷ tile size). */
.pgrid {
  --gap: calc(23 * var(--s));
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--gap);
  margin-top: calc(67 * var(--s));
}
.tile {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  background: transparent;
  border: 1px solid var(--frame);
  transition: background .25s;
}
.tile--shade { background: var(--tile-shade); }

/* Corner triangles: 27px legs on a 352px tile, sitting over the frame line */
.tri-a::before, .tri-a::after,
.tri-b::before, .tri-b::after {
  content: "";
  position: absolute;
  width: 7.7%;
  aspect-ratio: 1;
  background: var(--blue);
  pointer-events: none;
}
.tri-a::before { top: -1px; left: -1px;   clip-path: polygon(0 0, 100% 0, 0 100%); }        /* ◤ */
.tri-a::after  { bottom: -1px; right: -1px; clip-path: polygon(100% 0, 100% 100%, 0 100%); } /* ◢ */
.tri-b::before { top: -1px; right: -1px;  clip-path: polygon(0 0, 100% 0, 100% 100%); }     /* ◥ */
.tri-b::after  { bottom: -1px; left: -1px; clip-path: polygon(0 0, 0 100%, 100% 100%); }    /* ◣ */

/* ---- Tile hover (timings measured from the Wix recording) ----
   The image fades in over the whole tile (frame and corners included),
   the logo turns white, and a soft white flag slides into the top-right corner.
   Everything reverses with the same timing when the pointer leaves. */
.tile {
  --hover-t: .29s;
  --hover-ease: cubic-bezier(.5, .3, .5, 1);
}
.tile__bg {
  position: absolute;
  inset: -1px;              /* covers the frame line too */
  z-index: 1;
  opacity: 0;
  overflow: hidden;
  transition: opacity var(--hover-t) var(--hover-ease);
}
.tile__bg img { width: 100%; height: 100%; object-fit: cover; }
.tile__logo {
  position: relative;
  z-index: 2;
  height: auto;
  transition: filter var(--hover-t) var(--hover-ease);
}
.tile__flag {
  position: absolute;
  z-index: 2;
  top: 4%;
  right: 4%;
  width: 10.9%;
  aspect-ratio: 1;
  background: var(--flag);
  clip-path: polygon(0 0, 100% 0, 100% 100%);   /* ◥ */
  opacity: 0;
  transform: translate(-19%, 19%);
  transition: opacity .3s var(--hover-ease) .04s, transform .3s var(--hover-ease) .04s;
  pointer-events: none;
}
a.tile:hover .tile__bg,
a.tile:focus-visible .tile__bg { opacity: 1; }
a.tile:hover .tile__logo,
a.tile:focus-visible .tile__logo { filter: brightness(0) invert(1); }
a.tile:hover .tile__flag,
a.tile:focus-visible .tile__flag { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .tile__bg, .tile__logo, .tile__flag { transition-duration: .01s; transition-delay: 0s; }
}

/* Logo widths as a share of the tile */
.tile--multivu .tile__logo    { width: 23.9%; }
.tile--aws .tile__logo        { width: 35.8%; }
.tile--scout .tile__logo      { width: 57%; }
.tile--bombora .tile__logo    { width: 42.6%; }
.tile--deepintent .tile__logo { width: 60.5%; }
.tile--ruckus .tile__logo     { width: 56.3%; }
.tile--neu .tile__logo        { width: 60.2%; }
.tile--doceree .tile__logo    { width: 42%; }

/* Large square 1: rotating flower, scaled so the petals run past the edges.
   The flower's centre is 60.1% across and 49.9% down the image. */
.tile--flower {
  grid-column: 3 / span 2;
  grid-row: 1 / span 2;
  aspect-ratio: auto;
  overflow: hidden;
}
/* The flower SVG is the whole flower in a square centred on its middle, at
   the scale of your design frame (frame 855 wide = 54.4% of the flower square).
   Its centre sits on the tile centre, under the N, so it turns around the N. */
.tile > .flower {
  position: absolute;
  width: 183.86%;
  max-width: none;
  height: auto;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  transform-origin: 50% 50%;
  will-change: transform;   /* main.js turns it while the tile is hovered */
}
.tile > .flower__mark { position: relative; width: 6.3%; }

/* Large square 2: CTA with nine balls (727px tile in the screenshot) */
.tile--cta {
  grid-column: 1 / span 2;
  grid-row: 3 / span 2;
  aspect-ratio: auto;
  container-type: inline-size;
  display: block;
}
.balls {
  position: absolute;
  left: 30.8%;
  top: 20.4%;
  width: 41.3%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
/* Each ball's SVG is trimmed to the circle itself, so with no grid gap
   neighbouring balls touch exactly along their edges, never overlapping. */
/* Hover (measured from the Wix recording): each ball makes a half turn
   in 0.76s on a smooth S-curve, and turns back the same way on leave.
   All turn counter-clockwise except the top-middle one, which turns clockwise. */
.balls img { display: block; width: 100%; transition: transform .76s cubic-bezier(.4, 0, .6, 1); }
/* the balls turn only while the pointer is over the balls themselves */
.balls:hover img,
.tile--cta:focus-visible .balls img { transform: rotate(-180deg); }
.balls:hover img:nth-child(2),
.tile--cta:focus-visible .balls img:nth-child(2) { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .balls img { transition: none; } }
.tile__cta-text {
  position: absolute;
  left: 4.7%;
  bottom: 3.5%;
  max-width: 60%;
  font-size: 8.14cqw;
  line-height: 1.1;
  letter-spacing: -0.04em;
}
.tile > .tile__cta-arrow {
  position: absolute;
  right: 3.6%;
  bottom: 3.6%;
  width: 6.7%;
  height: auto;
  transition: transform .25s;
}
/* hovering the words or the arrow: underline draws in, arrow nudges right */
.tile--cta:has(.tile__cta-text:hover, .tile__cta-arrow:hover) .tile__cta-arrow,
.tile--cta:focus-visible .tile__cta-arrow { transform: translateX(6px); }
.tile--cta:has(.tile__cta-text:hover, .tile__cta-arrow:hover) .uline,
.tile--cta:focus-visible .uline { background-size: 100% var(--uline-w); background-position-x: 0; }

.tile--multivu    { grid-column: 1; grid-row: 1; }
.tile--aws        { grid-column: 2; grid-row: 1; }
.tile--scout      { grid-column: 1; grid-row: 2; }
.tile--bombora    { grid-column: 2; grid-row: 2; }
.tile--deepintent { grid-column: 3; grid-row: 3; }
.tile--ruckus     { grid-column: 4; grid-row: 3; }
.tile--neu        { grid-column: 3; grid-row: 4; }
.tile--doceree    { grid-column: 4; grid-row: 4; }

/* BOTTOM CALL TO ACTION + FOOTER: see the end of this file */

/* =========================================================
   TABLET  (Figma frame: 1000 wide)
   ========================================================= */
@media (max-width: 1099px) {
  :root {
    --s: min(1px, calc(100vw / 1000));
    --gutter: calc(40 * var(--s));
  }

  .nav { padding: calc(43 * var(--s)) calc(43 * var(--s)) 0; }
  .nav__wordmark img { width: calc(218 * var(--s)); min-width: 150px; }
  .nav__mark { width: calc(34 * var(--s) * .75); min-width: 17px; }   /* tablet: N 25% smaller */
  .nav__toggle { display: block; }
  /* Menu panel (Figma "Hamburger Menu Layout"): a dimmed, blurred layer
     covering the page below the nav bar, links stacked at the left and
     "Follow us" at the bottom. */
  .nav__links {
    position: fixed;
    top: var(--menu-top, 111px);
    left: 0;
    right: 0;
    bottom: 0;
    justify-self: stretch;   /* undo the desktop right-alignment */
    width: 100%;
    z-index: 20;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: 6px 44px 48px;
    background: rgba(0, 0, 30, .75);
    -webkit-backdrop-filter: blur(10px);
            backdrop-filter: blur(10px);
    box-shadow: 0 4px 4px rgba(0, 0, 0, .25);
    font-size: 18px;
    opacity: 0;
    visibility: hidden;
    transition: opacity .32s cubic-bezier(.45, 0, .55, 1), visibility 0s .32s;
  }
  /* links sit 42px apart (Figma); no padding, so the hover underline sits
     the same distance under the words as in the desktop nav */
  .nav__links > a { padding: 0; line-height: normal; margin: 7.5px 0; }
  .nav__cta,
  .nav__cta:hover { color: var(--ink); background: none; padding: 0; border-radius: 0; overflow: visible; }
  .nav__cta::before { display: none; }
  /* bottom of the menu: contact details, on the same left edge as the links */
  .nav__contact {
    display: block;
    margin-top: auto;
    line-height: 1.35;
  }
  /* same size as Portfolio / About / Contact above */
  .nav__contact-label { font-size: inherit; }
  .nav__contact-email {
    display: inline-block;
    font-size: inherit;
  }
  .nav.is-open .nav__links {
    opacity: 1;
    visibility: visible;
    transition: opacity .32s cubic-bezier(.45, 0, .55, 1);
  }

  .hero { padding-top: calc(158 * var(--s)); }
  .hero__bg { --bg-w: max(140vw, 1300px); left: calc(var(--bg-w) * -0.3); }
  .hero__title { max-width: calc(677 * var(--s)); font-size: calc(80 * var(--s)); line-height: 1.05; }
  .hero__lede { max-width: calc(373 * var(--s)); margin-top: calc(26 * var(--s)); font-size: calc(23 * var(--s)); line-height: 1.217; }
  .hero__more { margin-top: calc(9 * var(--s)); }

  .work { padding-top: calc(95 * var(--s)); padding-right: calc(45 * var(--s)); }
  .work__title { max-width: calc(509 * var(--s)); font-size: calc(45 * var(--s)); line-height: 1.11; }
  /* Two staggered columns: Campaigns + Transforming on the left,
     Digital + Branding on the right, the right column set lower */
  .cards {
    grid-template-columns: repeat(2, 1fr);
    column-gap: calc(32 * var(--s));
    row-gap: calc(34 * var(--s));
    margin-top: calc(48 * var(--s));
    padding-bottom: 11.5%;   /* room for the lowered right column */
  }
  .card--1 { order: 1; }
  .card--4 { order: 2; }
  .card--2 { order: 3; }
  .card--3 { order: 4; }
  .card--2, .card--3, .card--4 { margin-top: 0; }
  .card--4, .card--3 { transform: translateY(18.5%); }   /* about 0.24 card-widths */

  .flow { padding-top: calc(170 * var(--s)); }
  .flow__title { max-width: calc(370 * var(--s)); font-size: calc(45 * var(--s)); line-height: 1.11; }


  :root { --flow-gap: calc(150 * var(--s)); }
  .portfolio { padding: calc(66 * var(--s)) calc(27 * var(--s)) calc(70 * var(--s)); }
  .portfolio__title { max-width: calc(240 * var(--s)); margin-left: calc(10 * var(--s)); font-size: calc(47.86 * var(--s)); line-height: 1.18; }
  .pgrid { --gap: calc(16 * var(--s)); margin-top: calc(22 * var(--s)); }

}

/* =========================================================
   MOBILE  (Figma frame: 480 wide)
   ========================================================= */
@media (max-width: 599px) {
  :root {
    --s: calc(100vw / 480);
    --gutter: max(16px, calc(21 * var(--s)));
  }

  .nav {
    grid-template-columns: 1fr auto;
    padding: 32px var(--gutter) 0;
    min-height: 0;
  }
  .nav__mark { display: none; }
  .nav__wordmark img { width: 180px; min-width: 0; }

  .hero { padding-top: calc(70 * var(--s)); }
  .hero__bg { --bg-w: max(200vw, 900px); left: calc(var(--bg-w) * -0.42); }
  .hero__title { max-width: calc(338 * var(--s)); font-size: calc(40 * var(--s)); }
  .hero__lede { max-width: calc(260 * var(--s)); margin-top: calc(24 * var(--s)); font-size: max(15px, calc(16 * var(--s))); line-height: 1.25; }
  .hero__more { margin-top: calc(28 * var(--s)); font-size: 16px; }

  .work { padding: calc(50 * var(--s)) var(--gutter) 0 calc(14 * var(--s)); }
  .work__title { max-width: calc(255 * var(--s)); font-size: calc(22.5 * var(--s)); }
  .cards { column-gap: calc(13 * var(--s)); row-gap: calc(17 * var(--s)); margin-top: calc(25 * var(--s)); }
  .placeholder { font-size: 11px; padding: 6px; }

  .flow { padding-top: calc(70 * var(--s)); }
  .flow__title { max-width: calc(185 * var(--s)); font-size: calc(22.5 * var(--s)); }

  .portfolio { padding: calc(62 * var(--s)) calc(16 * var(--s)) calc(70 * var(--s)); }
  .portfolio__title { max-width: calc(199 * var(--s)); margin-left: 0; font-size: calc(47 * var(--s)); }
  .pgrid { --gap: calc(13 * var(--s)); grid-template-columns: repeat(2, 1fr); margin-top: calc(43 * var(--s)); }
  .tile--flower { grid-column: 1 / -1; grid-row: 1; aspect-ratio: 1; }
  .tile--multivu { grid-column: 1; grid-row: 2; }
  .tile--aws     { grid-column: 2; grid-row: 2; }
  .tile--scout   { grid-column: 1; grid-row: 3; }
  .tile--bombora { grid-column: 2; grid-row: 3; }
  .tile--deepintent { grid-column: 1; grid-row: 4; }
  .tile--ruckus  { grid-column: 2; grid-row: 4; }
  .tile--neu     { grid-column: 1; grid-row: 5; }
  .tile--doceree { grid-column: 2; grid-row: 5; }
  .tile--cta { grid-column: 1 / -1; grid-row: 6; aspect-ratio: 1; }

}

/* Phones and small tablets use the stacked scroll layout, which ends flush */
@media (max-width: 1099px) {
  .portfolio { margin-top: 0; }
}

/* =========================================================
   TYPE SCALE
   One fluid scale for every screen size. Each style is its Figma size at
   1920px wide and shrinks evenly to a readable minimum at 390px (phone),
   so text never jumps between layouts and the hierarchy always holds:
   display > section title > card caption / sub-heading > body > small.
   ========================================================= */
:root {
  /* clamp(min @390px, linear in between, max @1920px) */
  --fs-display: clamp(34px, calc(34px + 79 * (100vw - 390px) / 1530), 113px);
  --fs-title:   calc(var(--fs-display) * 0.62);   /* section titles: always 62% of the headline (Figma 70 : 113) */
  --fs-more:    clamp(26px, calc(26px + 30 * (100vw - 390px) / 1530), 56px);
  --fs-link:    clamp(20px, calc(20px + 20 * (100vw - 390px) / 1530), 40px);
  --fs-lede:    clamp(16px, calc(16px + 19 * (100vw - 390px) / 1530), 35px);
  --fs-card:    clamp(16px, calc(16px + 14 * (100vw - 390px) / 1530), 30px);
  --fs-more-sm: clamp(16px, calc(16px +  6 * (100vw - 390px) / 1530), 22px);
  --fs-ui:      clamp(15px, calc(15px +  3 * (100vw - 390px) / 1530), 18px);
  --fs-small:   clamp(14px, calc(14px +  3 * (100vw - 390px) / 1530), 17px);
}

.hero__title                { font-size: var(--fs-display); }
.hero__lede                 { font-size: var(--fs-lede); max-width: 13.7em; }
.hero__more                 { font-size: var(--fs-more-sm); }
.nav__links                 { font-size: var(--fs-ui); }

.work__title                { font-size: var(--fs-title); max-width: 11.4em; }
.flow__title                { font-size: var(--fs-title); max-width: 7.6em; }
.portfolio__title           { font-size: var(--fs-title); max-width: 4.1em; }

/* captions follow the card's width on narrow cards, but never outgrow the scale */
.card__caption              { font-size: 8.5cqw; }   /* always the same share of its box */


/* Text beside the scroll animation (large screens): it stays locked to the
   animation's frame, but never smaller than a readable size. When the
   readable minimum kicks in, main.js adds .scrub--wrap and the lines wrap
   naturally inside the space to the right of the animation. */
@media (min-width: 1100px) {
  /* the two text blocks fade (0.5s) instead of scrolling (main.js) */
  /* both rise into place from below as they fade in, the title first and the
     paragraph just after it; the first carries on rising as it fades out, the
     second sinks back down. The second travels 30% less. */
  .flow__step { --rise: 96px; }
  .flow__step--unlock { --rise: 67px; }
  .flow__step > h3,
  .flow__step > p { transition: opacity 1s ease, translate 1s cubic-bezier(.4, 0, 0, 1); }
  /* scrolling down: the title moves first, then its text (in and out);
     scrolling back up: the reverse, text first, then the title */
  .flow__step > p { transition-delay: .15s; }
  .scrub--up .flow__step--unlock > p { transition-delay: 0s; }    /* second text leaving: text, then title */
  .scrub--up .flow__step--unlock > h3 { transition-delay: .15s; }
  .flow__step.is-out > h3,
  .flow__step.is-out > p { opacity: 0; translate: 0 calc(var(--rise) * -1); }
  /* leaving, both texts just fade out in place (no movement) */
  .flow__step.is-out > h3,
  .flow__step.is-out > p { translate: none; transition-duration: .5s; transition-delay: 0s !important; }   /* fade-outs: half as long, title and text together */
  .flow__step.is-below > h3,
  .flow__step.is-below > p { opacity: 0; translate: 0 var(--rise); transition: none; }
  .flow__step h3 { font-size: max(calc(36 * var(--u)), 22px); }
  .flow__step p  { font-size: max(calc(20 * var(--u)), 15px); }
  .scrub--wrap .scrub__text { width: calc(692 * var(--u) - 32px); }
  .scrub--wrap .flow__step p .lb { display: none; }   /* headings keep their two-line break */
  .scrub--wrap .flow__step p { white-space: normal; }
}

/* =========================================================
   PHONE + TABLET: work cards in the Wix proportions (measured from the Wix
   mobile and tablet screenshots, as shares of the screen width). Everything
   scales with the screen, so cards, titles and captions shrink together.
   ========================================================= */
@media (max-width: 1099px) {
  .work { padding-left: 4.9vw; padding-right: 3.7vw; }
  .work__title,
  .flow__title {
    font-size: var(--fs-title);       /* same proportion to the headline at every size */
    line-height: 1.12;
    max-width: 11.4em;                /* "Designing Experiences / that Transcend / Boundaries" */
    text-wrap: wrap;                  /* break like Wix, not balanced */
  }
  .flow__title { max-width: 7.6em; }
  .flow__step h3 { font-size: clamp(17px, 3.4vw, 30px); }   /* clearly below the section title */
  .flow__step p  { font-size: clamp(15px, 2.1vw, 19px); max-width: 38em; }

  /* two columns in reading order (Campaigns + Amazon on top),
     the right column stepped down like the Wix version */
  .cards {
    column-gap: 5vw;          /* same as the gap between rows */
    row-gap: 5vw;
    margin-top: 5.5vw;
    padding-bottom: 7.6vw;
  }
  .card--1 { order: 1; }
  .card--2 { order: 2; }
  .card--3 { order: 3; }
  .card--4 { order: 4; }
  .card--1, .card--2, .card--3, .card--4 { margin-top: 0; transform: none; }
  .card--2, .card--4 { transform: translateY(7.6vw); }

  /* caption is 7.3% of the card's width (title : caption = 1.6 : 1) */

}

/* =========================================================
   UNDERLINES THAT MOVE (multi-line safe: one line under every row of text)
   .uline        no line at rest; on hover it draws in from the left, and
                 slides away to the right when the pointer leaves.
   .uline--pass  line at rest; on hover in AND out it slides away to the
                 right and draws back in from the left (main.js restarts it).
   Timing from the reference recording: out 0.28s, back in 0.5s, both easing out.
   ========================================================= */
.uline {
  --uline-w: max(1px, .074em);       /* line thickness = the font's own horizontal strokes (Poppins Regular: 7.4% of the size, like the bar of the T or H) */
  /* snapped down to whole screen pixels (half-pixels on retina) so the line
     stays crisp and never looks heavier than the letters' strokes */
  --uline-w: max(1px, round(down, .074em, .5px));
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-size: 0 var(--uline-w);
  background-position: 100% calc(100% - .14em);
  -webkit-box-decoration-break: clone;
          box-decoration-break: clone;
  transition: background-size .5s cubic-bezier(.2, .6, .3, 1);
}
/* any link: hovering it draws its line in */
a:not(.tile--cta):hover .uline:not(.uline--pass),
a:not(.tile--cta):focus-visible .uline:not(.uline--pass) { background-size: 100% var(--uline-w); background-position-x: 0; }
.uline--pass { background-size: 100% var(--uline-w); background-position-x: 0; transition: none; }
.uline--pass.is-passing { animation: uline-pass .78s linear; }
@keyframes uline-pass {
  0%     { background-size: 100% var(--uline-w); background-position-x: 100%; animation-timing-function: cubic-bezier(.2, .6, .3, 1); }
  36%    { background-size: 0 var(--uline-w);    background-position-x: 100%; }
  36.01% { background-size: 0 var(--uline-w);    background-position-x: 0;    animation-timing-function: cubic-bezier(.2, .6, .3, 1); }
  100%   { background-size: 100% var(--uline-w); background-position-x: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .uline { transition: none; }
  .uline--pass.is-passing { animation: none; }
}

/* =========================================================
   BOTTOM CALL TO ACTION + FOOTER
   Laid out from the desktop / tablet / phone screenshots. One shared left
   edge (--edge) for the title, the logo, the links and the legal text on
   tablet and phone; on desktop the right column (contact) starts exactly
   where the "Connect" arrow ends.
   ========================================================= */
.more {
  --edge: calc(64 * var(--s));
  position: relative;
  color: var(--ink);                /* white on every page */
  isolation: isolate;               /* keeps the video behind the text */
  overflow: hidden;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 2rem;
  padding: calc(133 * var(--s)) calc(331 * var(--s)) calc(78 * var(--s)) var(--edge);
}
/* the hero animation, behind the band only */
.more__bg { position: absolute; inset: 0; z-index: -1; background: var(--navy); }
.more__bg video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 30%;
  display: block;
}
.more__title {
  font-size: calc(56 * var(--s));
  line-height: 1.18;
  letter-spacing: -0.04em;
  max-width: 9.4em;
}
/* arrow and gap are in em, so they stay in proportion to the text at every size */
.more__link {
  display: flex;
  align-items: center;
  gap: .72em;
  font-size: calc(40 * var(--s));
  color: var(--sky);
  flex: none;
  margin-top: calc(35 * var(--s));   /* sits a little below the title's centre */
}
.more__link-text {
  white-space: nowrap;               /* two lines, broken after "with" */
  line-height: 1.08;
  letter-spacing: -0.04em;
}
.more__arrow { width: .8em; height: auto; fill: currentColor; transition: transform .25s; }
.more__link:hover .more__arrow { transform: translateX(6px); }

.footer {
  --edge: calc(64 * var(--s));   /* same left edge as "Find out more" above */
  display: grid;
  /* logo + links | legal, centred on the page | contact, flush right */
  grid-template-columns: 1fr auto 1fr;
  grid-template-rows: auto auto;
  column-gap: calc(40 * var(--s));
  align-items: start;
  padding: calc(122 * var(--s)) var(--edge) calc(113 * var(--s));   /* even sides, so the legal line sits on the page's centre */
  font-size: max(13px, calc(18 * var(--s)));
  line-height: 1.43;
}
/* the wordmark file is trimmed to the letters, so it lines up with the text */
.footer__logo { grid-column: 1; grid-row: 1; width: calc(221 * var(--s)); min-width: 140px; height: auto; margin-bottom: calc(28 * var(--s)); }
.footer__links {
  grid-column: 1; grid-row: 2;
  align-self: end;
  display: flex;
  gap: calc(47 * var(--s));
  font-size: max(13.5px, calc(18.5 * var(--s)));
}
/* legal text and contact block share the same bottom line as the links (desktop) */
.footer__legal { grid-column: 2; grid-row: 1 / span 2; align-self: end; justify-self: center; text-align: center; max-width: 44em; }
.footer__contact { grid-column: 3; grid-row: 1 / span 2; align-self: end; justify-self: end; text-align: right;  }
.footer__label { font-size: max(13.5px, calc(19.5 * var(--s))); }
.footer__email { display: inline-block; font-size: max(14.5px, calc(19.9 * var(--s))); }
/* footer links and email: underlines via .uline (see "UNDERLINES THAT MOVE") */

/* Tablet and phone: stacked footer, title + link side by side (tablet) or
   one under the other (phone) */
@media (max-width: 1099px) {
  .more,
  .footer { --edge: max(17px, calc(39 * 100vw / 1000)); }
  .more {
    padding: calc(75 * 100vw / 1000) calc(168 * 100vw / 1000) calc(66 * 100vw / 1000) var(--edge);
  }
  .more__title { font-size: max(21px, calc(30 * 100vw / 1000)); max-width: 9.6em; }
  .more__link { margin-top: 0; font-size: max(16px, calc(21.5 * 100vw / 1000)); }

  .footer {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: calc(73 * 100vw / 1000) var(--edge) calc(74 * 100vw / 1000);
    font-size: 13.2px;
    line-height: 1.6;
  }
  .footer__logo { order: 1; width: 160px; min-width: 0; margin-top: 7px; margin-bottom: 0; }
  .footer__contact { order: 2; margin-top: 30px; margin-right: 0; align-self: flex-start; text-align: left; }
  .footer__legal { order: 3; margin-top: 21px; padding-top: 0; max-width: 46em; align-self: flex-start; text-align: left; }
  .footer__links {
    order: 4;
    align-self: stretch;
    margin-top: 18px;
    padding-block: 15px;
    border-block: 1px solid rgba(255, 255, 255, .45);
    margin-right: 6px;
    gap: 29px;
    font-size: 14px;
  }
  .footer__label { font-size: 13.5px; line-height: 1.3; }
  .footer__email { font-size: 15px; }
}
@media (max-width: 599px) {
  .more {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: 50px var(--edge) 27px;
  }
  .more__title { font-size: 21.9px; }
  .more__link { margin-top: 15px; }
  .footer { padding-top: 37px; padding-bottom: 38px; }
  .footer__logo { width: 143px; }
  .footer__legal { margin-top: 36px; }
}

/* optical alignment: the big "F" of "Find out more" has a little built-in
   space before it, so the logo and links move over by the same amount and
   all three start on exactly the same visible line */
.footer__logo  { margin-left: calc(2 * var(--s)); }
.footer__links { margin-left: calc(1 * var(--s)); }
@media (max-width: 1099px) {
  .footer__logo  { margin-left: 1px; }
  .footer__links { margin-left: 0; }
}
/* the email address is the same size as "General Inquiries" above it */
.footer__email { font-size: max(13.5px, calc(19.5 * var(--s))); }
@media (max-width: 1099px) { .footer__email { font-size: 13.5px; } }

/* underlines that run over two lines draw identically on both: the line
   thickness and the line spacing are whole pixels, so every browser places
   each underline on the same pixel grid (Safari could render one a hair thinner) */
.uline { --uline-w: max(1px, round(.074em, 1px)); }
.more__link-text { line-height: round(1.08em, 1px); }
/* footer logo: exactly the drawing's own proportions, pinned to the left, so its
   first letter lines up with "Portfolio" below in every browser */
.footer__logo { aspect-ratio: 218.53 / 21.55; height: auto; object-fit: contain; object-position: left center; }


/* the top bar is symmetric at every size: the wordmark always sits in the exact middle of the window,
   and the left and right margins match. Phone: the hamburger keeps its right-hand spot. */
/* phone: the wordmark sits at the left, its "U" on the same line as the page text
   (the logo file has 20 of 258 units of space before the U; the big headline's
   first letter has about 0.077em before its ink) */
@media (max-width: 599px) {
  .nav__wordmark img { translate: calc(-20 / 258 * 100% + var(--wm-nudge, 0px)) 0; }
}
/* no scrollbar taking width off one side (the page still scrolls), so "centred" means the middle of the window */
html { scrollbar-width: none; }
html::-webkit-scrollbar { display: none; }

@media (max-width: 599px) { .footer__logo { margin-left: 0; } }   /* phone: U on the same line as the text */
/* cover any hairline gap above the footer, so the background video never shows through as a line */
.footer { box-shadow: 0 -3px 0 var(--navy); }
/* footer wordmark position, set by eye in the preview editor */
.footer__logo { translate: -5.5px 0; }
@media (max-width: 1099px) { .footer__logo { translate: -4px 0; } }
/* no bounce past the top or bottom of the page (Safari would show the fixed background video below the footer) */
html, body { overscroll-behavior-y: none; }
html { background: var(--navy); }
/* on short pages (or tall screens) the space under the footer stays navy instead of showing the background video */
.footer { box-shadow: 0 -3px 0 var(--navy), 0 0 0 100vmax var(--navy); clip-path: inset(-3px -100vmax -100vmax -100vmax); }
/* phone: "Find out more", its link and the footer all start on one vertical line (set by eye in the preview) */
@media (max-width: 599px) {
  .more__title   { position: relative; left: 1.5px; }
  .more__link    { position: relative; left: 3.25px; }
  .footer__contact, .footer__legal { position: relative; left: 1.5px; }
  .footer__logo  { translate: -1.5px 0; }
  .footer__links { position: relative; left: 2.25px; }
}
/* "Designing Experiences / that Transcend / Boundaries": always these three lines */
.work__title { max-width: none; white-space: nowrap; }
.nav__wordmark img { --wm-nudge: calc(var(--fs-display) * .077); }
/* phone: positions set by eye in the preview (top-bar wordmark and footer logo) */
@media (max-width: 599px) {
  .nav__wordmark { translate: -4px 0; }
  .footer__logo  { translate: 3px 0; }
}
/* phone: top-bar wordmark nudged left (set by eye in the preview) */
@media (max-width: 599px) { .nav__wordmark { translate: -4px 0; } }
/* homepage animation: fades in when scrolled to, just before its first text */
.js .scrub .scrub__stage { opacity: 0; transition: opacity 1s cubic-bezier(.4, 0, 0, 1); }
.js .scrub.is-in .scrub__stage { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .js .scrub .scrub__stage { opacity: 1; transition: none; } }
/* the image rises in as it fades in */
.js .scrub .scrub__video { translate: 0 calc(60 * var(--s)); transition: translate 1.38s cubic-bezier(.2, .7, 0, 1); }
.js .scrub.is-in .scrub__video { translate: 0 0; }
@media (prefers-reduced-motion: reduce) { .js .scrub .scrub__video { translate: none; transition: none; } }
/* homepage hero: "Learn More" one line closer to the text on desktop */
@media (min-width: 1100px) { .hero__more { margin-top: calc(14 * var(--s)); } }
@media (max-width: 599px) { .hero__more { margin-top: calc(4 * var(--s)); } }
