/* Base skeleton styles. The visual design is added later from the
   inspiration references; change the tokens here first. */

/* PP Mori by Pangram Pangram. The files in assets/fonts are the free
   personal-use version and stay out of git; swap in licensed web
   fonts (woff2) before launch. */

@font-face {
  font-family: "PP Mori";
  src: url("/assets/fonts/PPMori-Extralight.otf") format("opentype");
  font-weight: 200;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "PP Mori";
  src: url("/assets/fonts/PPMori-ExtralightItalic.otf") format("opentype");
  font-weight: 200;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "PP Mori";
  src: url("/assets/fonts/PPMori-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "PP Mori";
  src: url("/assets/fonts/PPMori-RegularItalic.otf") format("opentype");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "PP Mori";
  src: url("/assets/fonts/PPMori-SemiBold.otf") format("opentype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "PP Mori";
  src: url("/assets/fonts/PPMori-SemiBoldItalic.otf") format("opentype");
  font-weight: 600;
  font-style: italic;
  font-display: swap;
}

:root {
  /* Colour roles: the "Geometric" palette, sampled from the geometric
     shapes reference, with a light blue (the blue's hue at the pink's
     lightness) in place of its forest green. Every colour on the site
     comes from these. Text pairs all pass 4.5:1. */
  --paper: #ffffff;               /* page background: pure white */
  --paper-alt: #f2f0ec;           /* warm off-white band (introduction) */
  --ink: #1c1c1c;                 /* text */
  --ink-soft: #5c5c5c;
  --block-1: #fbbad4;             /* pink */
  --block-1-ink: #000000;
  --block-2: #a45b61;             /* rosewood */
  --block-2-ink: #ffffff;
  --block-3: #486adc;             /* blue */
  --block-3-ink: #ffffff;
  --block-4: #bfcef7;             /* light blue */
  --block-4-ink: #000000;
  --block-neutral: #b8ab9b;       /* taupe, under the clouds behind the hero's hand */
  --pill: #fbbad4;                /* buttons */
  --pill-ink: #000000;
  --pill-on-blocks: #f2f0ec;      /* buttons over a colour block */
  --pill-on-blocks-ink: #000000;
  --accent: var(--ink);

  /* Roll: measured from the word-reel reference (Animation.mov). Each
     step eases in and out hard over ~0.62s, moving downwards. Used for
     the hero word and every button hover. */
  --roll-ease: cubic-bezier(0.76, 0, 0.24, 1);
  --roll-duration: 620ms;

  /* Hero outer card: blue to rosewood to pink */
  --hero-gradient: linear-gradient(180deg, #486adc 0%, #a45b61 50%, #fbbad4 100%);

  /* Corners on every photo and video box (cards, portrait, case images) */
  --radius-media: 10px;

  /* Hairlines between blocks: the work cards, the footer, above the toolbox */
  --rule: rgba(0, 0, 0, 0.13);

  /* Type scale: five sizes for the whole site (px at a 1440px window /
     on phones). Everything on the home page and the footer uses these. */
  --text-display: clamp(56px, 8vw, 168px); /* 115 / 56: hero headline, service and case titles */
  --text-large: clamp(24px, 3.41vw, 66px); /* 49 / 28: intro statement, case descriptions, footer */
  --text-medium: clamp(18px, 1.6vw, 29px); /* 23 / 18: buttons, nav, the sheets' text */
  --text-small: clamp(15px, 1.32vw, 22px); /* 19 / 15: labels, lists, links, small print, the service cards' text */
  --text-xsmall: clamp(14px, 1.05vw, 19px); /* 15 / 14: not used at the moment (was the service lists) */

  --font-body: "PP Mori", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: var(--font-body);

  --step-0: 1rem;
  --step-1: 1.25rem;
  --step-2: clamp(1.5rem, 1.2rem + 1.2vw, 2rem);
  --step-3: clamp(2.25rem, 1.6rem + 3vw, 4rem);

  --space-s: 0.75rem;
  --space-m: 1.5rem;
  --space-l: clamp(3rem, 2rem + 4vw, 6rem);

  --page-max: 72rem;
  --text-max: 40rem;
  --gutter: clamp(1rem, 0.5rem + 2vw, 2.5rem);
}

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 var(--step-0) / 1.55 var(--font-body);
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: var(--gutter);
  top: -4rem;
  padding: 0.5rem 1rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: 999px;
}

.skip-link:focus {
  top: 1rem;
}

.wrap {
  width: 100%;
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Header: pills and the handwritten logo centred between them, measured
   from serious.business. The logo is taller than the pills, so the top
   padding shrinks by half the difference to keep the pills 27px down.
   The pills change colour over colour blocks, where they would disappear. */

.site-header {
  --pill-bg: var(--pill);
  --pill-fg: var(--pill-ink);
  --header-pad-x: clamp(16px, 1.68vw, 32px);
  --logo-h: clamp(44px, 4vw, 64px);
  position: sticky;
  top: 0;
  z-index: 10;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  /* on tablets the nav is wider than its share and nudges the logo over;
     this keeps them apart */
  column-gap: 16px;
  align-items: center;
  padding: max(6px, calc(clamp(14px, 1.75vw, 27px) - (var(--logo-h) - var(--pill-h)) / 2)) var(--header-pad-x) 0;
  color: var(--ink);
  pointer-events: none;
}

.site-header > * {
  pointer-events: auto;
}

.site-header.is-on-blocks {
  --pill-bg: var(--pill-on-blocks);
  --pill-fg: var(--pill-on-blocks-ink);
}

/* Buttons: one system everywhere, text pills with no icons, all the same
   height, labels in PP Mori SemiBold. PP Mori's capitals sit 0.075em above
   the middle of their line box (ascent 0.75, descent 0.2, cap height 0.7),
   in theory 0.15em of extra top padding centres the capitals. Browsers
   round the ascent down to whole pixels, which lifts the text about 0.4px,
   so the padding is 0.19em; measured in Chrome, that puts the capitals
   within a quarter pixel of the middle at every size. Every element holding a label is a flex
   container, so no inherited line height can push the label off centre. */
/* Buttons are a step up from the small text: --text-medium in a 62px pill
   (54px on phones); the nav pill is as tall */
:root {
  --pill-h: 62px;
  --pill-text: var(--text-medium);
}

.pill,
.pill-link__text {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--pill-h);
  padding: 0.19em 1.05em 0;
  border-radius: 999px;
  background: var(--pill-bg, var(--pill));
  color: var(--pill-fg, var(--pill-ink));
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 200ms ease;
}

.pill-link {
  display: inline-flex;
  color: var(--ink);
  font-size: var(--pill-text);
  text-decoration: none;
}

/* Hover roll on every button: the label rolls down and an identical
   copy drops in from above, with the hero word's motion. main.js wraps
   the labels; the copy is hidden from screen readers. */
.roll {
  display: inline-block;
  height: 1.15em;
  overflow: hidden;
  line-height: 1.15;
  vertical-align: top;
}

.roll__track {
  display: flex;
  flex-direction: column;
  transform: translate3d(0, -50%, 0);
  transition: transform var(--roll-duration) var(--roll-ease);
}

.roll__item {
  display: block;
  white-space: nowrap;
}

:is(a, button):focus-visible .roll__track {
  transform: none;
}

@media (hover: hover) {
  :is(a, button):hover .roll__track {
    transform: none;
  }
}

@media (max-width: 760px) {
  :root {
    --pill-h: 54px;
  }
}

.site-header__cta {
  justify-self: start;
  font-size: var(--pill-text);
}

/* The label holders are flex boxes too, so they don't pick up the page's
   1.55 line height and push the text off centre. Narrow phones show just
   "CV", so the pill clears the centred logo: the full label needs a screen
   at least 433px wide for a 12px gap. */
.site-header__cta-label {
  display: flex;
}

.site-header__cta-label--short {
  display: none;
}

@media (max-width: 432px) {
  .site-header__cta-label--long {
    display: none;
  }

  .site-header__cta-label--short {
    display: flex;
  }
}

.site-header__logo {
  justify-self: center;
  display: block;
  line-height: 0;
}

.site-header__logo img,
.site-header__logo svg {
  display: block;
  width: auto;
  height: var(--logo-h);
}

/* Until the written logo has loaded, keep the static image hidden so it
   never flashes before being written in */
.js .site-header__logo:not(.is-ready) img {
  visibility: hidden;
}

/* Pen strokes in the logo's mask draw on as a left-to-right sweep, top
   line then bottom line. Each short piece carries its own --delay and
   --dur (generated with the logo); the hard ease is in that timing, so
   each piece itself draws linearly. */
.logo-write .pen {
  visibility: hidden;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
}

.logo-write.is-writing .pen {
  visibility: visible;
  stroke-dashoffset: 0;
  transition:
    stroke-dashoffset var(--dur) linear var(--delay),
    visibility 0s linear var(--delay);
}

/* Done: drop the mask so the logo is the original artwork, pixel for pixel */
.logo-write.is-written > g {
  mask: none;
}

.site-nav {
  position: relative;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 2px;
}

/* "Menu" button: only on phones, where the links fold away */
.site-nav__toggle {
  display: none;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

/* Nav text is the same size as the buttons */
.site-nav__label {
  font-size: var(--pill-text);
}

/* The nav is white, no outline, so it stands out on the beige hero */
.site-nav__links,
.site-nav__label {
  background: var(--paper);
  color: var(--ink);
}

.site-nav__links {
  gap: 24px;
  margin: 0;
  padding-inline: 34px;
  list-style: none;
  font-size: var(--pill-text);
}

.site-nav__links li,
.site-nav__links a {
  display: inline-flex;
  align-items: center;
}

.site-nav__links a {
  color: inherit;
  text-decoration: none;
}

/* Current page is underlined; the roll handles hover */
.site-nav__links a[aria-current="page"],
.site-nav__links a[aria-current="page"] .roll__item {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.site-nav.is-collapsed .site-nav__links {
  display: none;
}

@media (max-width: 760px) {
  .site-nav__toggle {
    display: flex;
  }


  .site-header {
    --logo-h: 40px;
  }

  /* Opened on a phone, the links drop down under the header */
  .site-nav__links {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    flex-direction: column;
    align-items: flex-end;
    gap: 10px;
    height: auto;
    padding: 16px 20px;
    border-radius: 21px;
  }
}

/* Type */

h1,
h2,
h3 {
  margin: 0 0 var(--space-s);
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

h1 {
  font-size: var(--step-3);
}

h2 {
  font-size: var(--step-2);
}

h3 {
  font-size: var(--step-1);
}

p {
  margin: 0 0 var(--space-s);
  max-width: var(--text-max);
}

.lede {
  font-size: var(--step-1);
  color: var(--ink-soft);
}

.section {
  padding-block: var(--space-l);
}

/* Hero */

.hero {
  padding-block: var(--space-l);
}

.status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: var(--space-m);
  color: var(--ink-soft);
}

.status::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: #1f9d55;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin-top: var(--space-m);
}

.button {
  display: inline-flex;
  align-items: center;
  padding: calc(0.7rem + 5px + 0.075em) 1.2rem calc(0.7rem + 5px - 0.075em);
  background: var(--ink);
  color: var(--paper);
  font-weight: 600;
  text-decoration: none;
}

/* Home page: the header floats over the full-screen hero, and waits for
   the intro animation to finish (main.js adds .intro-done) */

.site-header--overlay {
  position: fixed;
  inset: 0 0 auto;
  transition: opacity 900ms cubic-bezier(0.16, 1, 0.3, 1), transform 900ms cubic-bezier(0.16, 1, 0.3, 1);
}

.js:not(.intro-done) .site-header--overlay {
  visibility: hidden;
  transform: translate3d(0, -16px, 0);
  opacity: 0;
}

/* Hero: card stack that grows in, then fans out toward the pointer.
   Timings come from the reference reel; see the hero code in main.js. */

.hero-stack {
  position: relative;
  display: grid;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  overflow: hidden;
  background: var(--paper-alt);
}

.hero-stack__stage {
  position: absolute;
  inset: 0;
  perspective: 1400px;
  pointer-events: none;
}

.hero-stack__cards {
  position: absolute;
  inset: 0;
}

/* Cards are drawn at the back card's size (3.6x the front card) and only
   ever scaled down, so they stay sharp. The front card is drawn at its own
   size instead (--shrink, set by main.js): scaling a card down that far
   leaves its edges and photo pixelated. */
.stack-card {
  --w: clamp(432px, 46.8vw, 1008px);
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(var(--w) / var(--shrink, 1));
  aspect-ratio: 1.45;
  margin: calc(var(--w) / var(--shrink, 1) / -2.9) 0 0 calc(var(--w) / var(--shrink, 1) / -2);
  overflow: hidden;
  background: var(--c);
  clip-path: inset(0 round var(--corner, 16px));
  will-change: transform;
}

.js .stack-card {
  transform: scale(0);
}

/* Footage from Linn's work fills each card behind the phone, edge to edge;
   the card's colour only shows until the poster loads */
.stack-card img,
.stack-card video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Front card: a hand holding a phone that plays a reel, cut out of the
   hero photo, over a still of clouds (taupe until it loads); the arm is cut off by the
   card, and the top of the phone pokes out above it: main.js clips the
   layer to the card's shape plus everything above its top edge. */
.stack-card--phone {
  overflow: visible;
  background: none;
  clip-path: none;
}

.stack-card--phone::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--c);
  clip-path: inset(0 round var(--corner, 16px));
}

/* A picture or footage behind the hand, if the card is given one, in the
   card's shape; the card's colour shows under it. The clouds are a little
   bigger than the card, so main.js can shift them for a parallax: against
   the card as it follows the mouse, and behind as the page scrolls. */
.stack-card__backdrop {
  position: absolute;
  inset: 0;
  overflow: hidden;
  clip-path: inset(0 round var(--corner, 16px));
}

.stack-card__backdrop img {
  transform: scale(1.18);
  will-change: transform;
}

.stack-card__phone {
  position: absolute;
  inset: 0;
  clip-path: inset(-40% 0 0 0);
}

/* The phone's face is as tall as the card, with its top quarter above
   the card; the face is 625 of the cut-out's 891px height */
.stack-card__art {
  position: absolute;
  top: -25%;
  left: 24.8%;
  width: 106%;
}

/* Above the screen: the screen shows through a hole in the photo, so the
   bezel's smooth inner edge comes from the photo */
.stack-card .stack-card__art img {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  border-radius: 0;
}

/* Laid out at a phone screen's own shape and about its size on the page,
   then warped onto the photo's screen by main.js (matrix3d), so it follows
   the phone's tilt. Its edges sit under the bezel. */
.stack-card__screen {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  transform-origin: 0 0;
}

.stack-card__screen:not(.is-placed) {
  visibility: hidden;
}

/* The screen shows black until its reel loads */
.stack-card__screen {
  background: #000;
}

/* The headline turns white where it crosses the cards: main.js lays a
   white copy over the black one and clips it to the cards each frame. A
   faint shadow keeps it readable over light footage. */
.hero-title-stack {
  display: grid;
}

.hero-title-stack > .hero-title {
  grid-area: 1 / 1;
}

.hero-title.hero-title--light {
  color: var(--paper);
  text-shadow: 0 0 0.25em rgba(0, 0, 0, 0.22);
  pointer-events: none;
}

/* Markers on the cards' and phone screen's corners: where they land on the
   page tells main.js where to clip the white headline */
.corner-mark {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
}

.corner-mark[data-corner="1"] {
  left: 100%;
}

.corner-mark[data-corner="2"] {
  top: 100%;
  left: 100%;
}

.corner-mark[data-corner="3"] {
  top: 100%;
}

/* Headline: "Making brands / matter through / [word]." on three rows (on
   phones the first two may break onto two lines each). The word rotates; the rows above it never move. The widest
   row is "Artificial Intelligence." at about 9.3em, which phones swap for
   "AI"; see .hero-title for the size on narrow phones. */
.hero-stack__copy {
  position: relative;
  z-index: 2;
  padding-inline: clamp(16px, 1.68vw, 32px);
}

/* Once the intro animation is done, the headline rows slide up out of
   their masks 90ms apart, exactly like the introduction section, and the
   button fades up after the last row. */
.hero-title__line {
  display: block;
  transition: transform 1000ms cubic-bezier(0.16, 1, 0.3, 1);
}

.hero-title__row:nth-child(2) .hero-title__line {
  transition-delay: 90ms;
}

.js .hero-stack__copy:not(.is-in) .hero-title__line {
  transform: translate3d(0, 120%, 0);
}

.hero-stack__cta {
  transition: opacity 1000ms cubic-bezier(0.16, 1, 0.3, 1), transform 1000ms cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: 300ms;
}

.js .hero-stack__copy:not(.is-in) .hero-stack__cta {
  visibility: hidden;
  transform: translate3d(0, 24px, 0);
  opacity: 0;
}

/* Set exactly like the service card titles: the display size
   (--text-display), regular weight, pure black, tight 0.88 line height.
   On phones the two fixed rows break onto two lines each where they don't
   fit, so the headline keeps the display size; it only drops below 56px
   on phones narrower than about 370px, where the widest rotating word,
   "Social Media." (5.93em), sets the size. Phones show "AI" instead of
   "Artificial Intelligence." */
.hero-title {
  --swap: var(--roll-duration) var(--roll-ease);
  margin: 0;
  color: var(--block-1-ink);
  font-size: clamp(min(56px, (100vw - 2 * clamp(16px, 1.68vw, 32px)) / 6), 8vw, 168px);
  font-weight: 400;
  line-height: 0.88;
  letter-spacing: -0.02em;
}

/* Each row is a mask, with room below for descenders */
/* Room above for ascenders, which reach just over the tight line box */
.hero-title__row {
  display: block;
  padding: 0.05em 0 0.14em;
  margin: -0.05em 0 -0.14em;
  overflow: hidden;
}

/* The word rolls like a reel: the next word drops in from above as the
   current one leaves below, clipped to its own row (sides left open so a
   wider word isn't cut while the slot grows). The slot is also the third
   row's sliding line, so it carries both transitions. */
.hero-title__slot {
  position: relative;
  display: block;
  height: 0.88em;
  clip-path: inset(-0.05em -100vw);
  transition: width var(--swap), transform 1000ms cubic-bezier(0.16, 1, 0.3, 1) 180ms;
}

.hero-title__word {
  position: absolute;
  top: 0;
  left: 0;
  white-space: nowrap;
  transition: transform var(--swap), opacity var(--swap);
}

/* A word's own height plus a little, so with the tight line height no
   ascender or descender peeks into the slot before or after the roll */
.hero-title__word.is-entering {
  transform: translate3d(0, calc(-100% - 0.2em), 0);
}

.hero-title__word.is-leaving {
  transform: translate3d(0, calc(100% + 0.2em), 0);
}

.hero-stack__cta {
  margin-top: clamp(24px, 2.6vw, 44px);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}


@media (max-width: 760px) {
  /* On phones the large size scales with the screen (28px at 375) */
  :root {
    --text-large: clamp(24px, 7.5vw, 34px);
  }

  /* Portrait cards on phones; the footage stays upright and crops to fit */
  .stack-card {
    --w: 86.4vw;
    aspect-ratio: 1 / 1.45;
    margin-top: calc(var(--w) / var(--shrink, 1) * -0.725);
  }

  /* In the tall card the phone is scaled up until the arm reaches the
     card's bottom edge: its face is 1.25 card widths tall, centred, with
     the top quarter of it above the card */
  .stack-card__art {
    top: -21.55%;
    left: 4.3%;
    width: 192.2%;
  }
}

/* Smooth scroll (Lenis) */

html.lenis,
html.lenis body {
  height: auto;
}

.lenis:not(.lenis-autoToggle).lenis-stopped {
  overflow: clip;
}

.lenis.lenis-smooth iframe {
  pointer-events: none;
}

/* Section heads, after wearemotto.com: a semibold label on the left and an
   optional underlined link on the right. The label keeps the same space
   under its text as the link's padding and underline, so both sit on one
   baseline. Each section sets the spacing around its head. */
.section-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 16px;
  font-size: var(--text-small);
  line-height: 1.15;
}

.section-head__label {
  margin: 0;
  padding-bottom: calc(0.31em + 1px);
  font-size: inherit;
  font-weight: 600;
  line-height: inherit;
  letter-spacing: 0;
}

/* Underlined text links: the line sits 0.61em under the baseline */
.section-head__link,
.area__link {
  display: inline-block;
  padding-bottom: 0.31em;
  border-bottom: 1px solid currentColor;
  line-height: 1.15;
  text-decoration: none;
  white-space: nowrap;
}

/* Services: stacked cards. Sizes are measured from serious.business at a
   1548px-wide window and scale with the viewport width from there. */

.services {
  --services-bg: var(--paper-alt);
  --services-ink: var(--ink);
  --services-pad-x: clamp(16px, 1.3vw, 28px);
  --services-pad-y: clamp(18px, 1.68vw, 34px);
  --services-gap: clamp(12px, 1.03vw, 20px);

  /* The hero's beige runs on, and the label sits just below the fold, the
     same small gap above it as under it. No bottom padding: the last card
     runs straight into the introduction. */
  padding-top: clamp(24px, 2.34vw, 44px);
  background: var(--services-bg);
  color: var(--services-ink);
}

.services__head {
  margin-bottom: clamp(24px, 2.34vw, 44px);
  padding-inline: var(--services-pad-x);
}

.services__stack {
  margin: 0;
  padding: 0;
  list-style: none;
}

.service {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: auto 1fr;
  column-gap: var(--services-gap);
  padding: var(--services-pad-y) var(--services-pad-x);
  background: var(--card-bg);
  color: var(--card-ink, var(--services-ink));
  will-change: transform;
}

.service:nth-child(1) { z-index: 1; }
.service:nth-child(2) { z-index: 2; }
.service:nth-child(3) { z-index: 3; }
.service:nth-child(4) { z-index: 4; }

.service--block-1 { --card-bg: var(--block-1); --card-ink: var(--block-1-ink); }
.service--block-2 { --card-bg: var(--block-2); --card-ink: var(--block-2-ink); }
.service--block-3 { --card-bg: var(--block-3); --card-ink: var(--block-3-ink); }
.service--block-4 { --card-bg: var(--block-4); --card-ink: var(--block-4-ink); }

.service__title {
  grid-column: 1 / 3;
  grid-row: 1;
  margin: 0;
  font-size: var(--text-display);
  font-weight: 400;
  line-height: 0.88;
  letter-spacing: -0.02em;
}

.service__media {
  grid-column: 3;
  grid-row: 1 / 3;
  display: grid;
  place-items: center;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-media);
  overflow: hidden;
  background: color-mix(in srgb, currentColor 12%, transparent);
  font-size: 0.875rem;
}

.service__media > span {
  opacity: 0.6;
}

.service__media video,
.service__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Description and list sit at the bottom of the card, top-aligned with
   each other, so the taller of the two sets where the row starts. */
.service__text {
  grid-column: 1 / 3;
  grid-row: 2;
  align-self: end;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--services-gap);
  align-items: start;
  padding-top: var(--space-m);
}

/* Description and list in the same style as the facts on the work cards
   (--text-small, line height 1.4; Linn's choice of 2026-11-03) */
.service__desc {
  max-width: 30.5vw;
  margin: 0;
  font-size: var(--text-small);
  line-height: 1.4;
}

.service__list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-small);
  line-height: 1.4;
}


/* Introduction: one big statement, bold and tight like the reference.
   Each row slides up out of its own mask as it scrolls into view. */
.intro {
  padding: clamp(80px, 10vw, 180px) clamp(16px, 1.68vw, 32px);
  background: var(--paper-alt);
}

/* Every section head sits the same distance above its block. Here the
   block is the text, so the gap is measured to the top of its capitals
   (0.085em below the line box, at the statement's size). */
.intro__head {
  margin-bottom: calc(clamp(24px, 2.34vw, 44px) - 0.085 * var(--text-large));
}

.intro__text p {
  max-width: 24em;
  margin: 0;
  font-size: var(--text-large);
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: -0.03em;
}

/* "Read more" opens the about sheet; same gap as a section head's */
.intro__more {
  margin-top: clamp(24px, 2.34vw, 44px);
}

.intro__more .pill-link {
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  cursor: pointer;
}

.js [data-reveal-rows]:not(.is-split) {
  visibility: hidden;
}

/* Masks get room below for descenders; rows start fully below their mask */
[data-reveal-rows] .line {
  display: block;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
  overflow: hidden;
}

[data-reveal-rows] .line__inner {
  display: block;
  transform: translate3d(0, 120%, 0);
  transition: transform 1000ms cubic-bezier(0.16, 1, 0.3, 1);
}

[data-reveal-rows] .line.is-in .line__inner {
  transform: none;
}

/* Logo wave: white badges on the introduction's off-white, after the Osmo
   wavy marquee. Badges are 215px on a 1440px screen, as in the reference;
   the script places each one along the wave. Without the script they sit
   in a plain row. */
/* A hairline opens the toolbox, as on the work cards: the section's usual
   top space sits above it, and the label follows as a card's title follows
   its line */
.intro:has(+ .logo-wave) {
  padding-bottom: clamp(48px, 6vw, 110px);
}

.logo-wave {
  --d: clamp(150px, 14.93vw, 290px);
  padding-bottom: calc(var(--d) * 0.2);
  overflow: hidden;
  border-top: 1px solid var(--rule);
  background: var(--paper-alt);
}

.logo-wave__head {
  padding: clamp(24px, 2.78vw, 52px) clamp(16px, 1.68vw, 32px) clamp(24px, 2.34vw, 44px);
}

/* Just tall enough for the wave at rest (main.js: WAVE_HEIGHT 0.254 of a
   badge each way), so the highest badges sit the same distance under the
   label as every other block. At speed the wave swells into the space
   above and into the section's bottom padding. */
.logo-wave__list {
  display: flex;
  gap: calc(var(--d) * 0.128);
  align-items: center;
  height: calc(var(--d) * 1.508);
  margin: 0;
  padding: 0;
  list-style: none;
}

.js .logo-wave__list {
  position: relative;
  display: block;
}

.js .logo-wave:not(.is-ready) .logo-wave__list {
  visibility: hidden;
}

.logo-wave__item {
  display: grid;
  flex: none;
  place-items: center;
  width: var(--d);
  height: var(--d);
  border-radius: 50%;
  background: var(--paper);
}

.js .logo-wave__item {
  position: absolute;
  top: 50%;
  left: 0;
  margin-top: calc(var(--d) / -2);
  will-change: transform;
}

/* Logos are sized by eye so they weigh the same: --w is the width as a
   share of the badge, set per logo in the HTML */
.logo-wave__item img {
  width: calc(var(--d) * var(--w, 0.36));
  height: auto;
}

@media (max-width: 760px) {
  .logo-wave {
    --d: 36vw;
  }
}

/* Areas of expertise, after wearemotto.com. Measured at a 1537px-wide
   window and scaled with the viewport from there (1vw = 15.37px); the side
   margins follow the rest of this site. Cards are opaque and positioned so
   each one paints over the one before; main.js slows and darkens the card
   being covered (--dim). */
.areas {
  --areas-pad-x: clamp(16px, 1.68vw, 32px);
  /* The footer's grid gap: the media spans the footer's last four columns */
  --areas-grid-gap: 1.55vw;
  --areas-small: var(--text-small);
  --areas-rule: var(--rule);
  background: var(--paper-alt);
}

.areas__head {
  padding: clamp(48px, 6vw, 110px) var(--areas-pad-x) clamp(24px, 2.34vw, 44px);
}

.area {
  --dim: 0;
  position: relative;
  border-top: 1px solid var(--areas-rule);
  background: var(--paper-alt);
}

.area::after {
  content: "";
  position: absolute;
  inset: 0;
  background: #2e2e2e;
  opacity: var(--dim);
  pointer-events: none;
}

.area__head {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  height: 22.51vw;
  padding: 2.78vw var(--areas-pad-x) 0;
  font-size: var(--text-display);
  line-height: 1;
}

.area__title,
.area__number {
  margin: 0;
  font-size: inherit;
  font-weight: 400;
  line-height: inherit;
  letter-spacing: -0.02em;
}

/* The media column is as wide as the footer's last four columns (of 12),
   so it starts where "Ready to talk?" does */
.area__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc((100% - 2 * var(--areas-grid-gap)) / 3);
  grid-template-rows: auto auto;
  column-gap: var(--areas-pad-x);
  padding: 2.68vw var(--areas-pad-x) 7.48vw;
  border-top: 1px solid var(--areas-rule);
}

/* As tall as the longest summary on the page (main.js sets --desc-h), and
   at least four lines, so every card is the same height */
.area__desc {
  grid-column: 1;
  max-width: 17.85em;
  min-height: var(--desc-h, 4em);
  margin: 0.08vw 0 0;
  font-size: var(--text-large);
  line-height: 1;
  letter-spacing: -0.03em;
}

/* As tall as the reference's portrait media (21.37vw wide, 328.5 x 401.5),
   only wider, so the cards keep their height */
.area__media {
  grid-column: 2;
  grid-row: 1 / 3;
  align-self: start;
  height: 26.12vw;
  overflow: hidden;
  border-radius: var(--radius-media);
  background: color-mix(in srgb, currentColor 8%, transparent);
}

.area__media video,
.area__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Two lists and the "View case" button, bottom-aligned on their last
   baselines */
.area__foot {
  grid-column: 1;
  display: grid;
  grid-template-columns: 24.07vw 22.87vw auto;
  align-items: end;
  margin-top: 9.33vw;
  font-size: var(--areas-small);
}

.area__list {
  margin: 0;
  padding: 0 0 calc(0.185em + 1px);
  list-style: none;
  line-height: 1.4;
}

/* Buttons that look like the underlined links */
.area__link {
  justify-self: start;
}

.area__link,
button.section-head__link {
  padding-inline: 0;
  padding-top: 0;
  border-width: 0 0 1px;
  background: none;
  color: inherit;
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}

@media (max-width: 760px) {
  .area__head {
    height: auto;
    padding-block: 6vw 16vw;
  }

  .area__body {
    grid-template-columns: minmax(0, 1fr);
    padding-block: 6vw 14vw;
  }

  .area__desc {
    min-height: 0;
    line-height: 1.05;
  }

  .area__media {
    grid-column: 1;
    grid-row: 2;
    width: 58%;
    height: auto;
    aspect-ratio: 328.5 / 401.5;
    margin-top: 8vw;
  }

  .area__foot {
    grid-row: 3;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8vw 4vw;
    margin-top: 10vw;
  }

  .area__link {
    grid-column: 1 / -1;
  }
}

/* Line reveal: each line slides up out of its own mask. Hidden until the
   script has split the text, so nothing flashes before it animates. */
.js [data-reveal]:not(.is-split) {
  visibility: hidden;
}

[data-reveal] .line {
  display: block;
  overflow: hidden;
}

[data-reveal] .line__inner {
  display: block;
  transform: translate3d(0, 100%, 0);
  transition: transform 600ms cubic-bezier(0.215, 0.61, 0.355, 1);
  transition-delay: calc(var(--i, 0) * 60ms);
}

[data-reveal].is-in .line__inner {
  transform: none;
}

@media (max-width: 760px) {
  .service {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    row-gap: var(--space-m);
  }

  .service__title,
  .service__media,
  .service__text {
    grid-column: 1;
    grid-row: auto;
  }

  .service__text {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-m);
    padding-top: 0;
  }

  .service__desc {
    max-width: none;
  }
}

/* Sheets: "View case" and "Read more" open a white sheet that slides up
   over the dimmed page, after the project sheets on timestwo.com (from
   Linn's recording at a 1537px window: 48.8% of the window wide, 11.5px
   from the top, a 100px header, the page dimmed to 60%). It rises from
   below the screen and sinks back down with the site's hard ease in and
   out (--roll-ease). The header stays put while the sheet scrolls;
   dragging it down closes the sheet. main.js fills the sheet from the card
   or section that opened it. */
.sheet {
  --sheet-top: 12px;
  --sheet-radius: 38px;
  --close-size: clamp(44px, 3.33vw, 52px);
  --sheet-pad: clamp(16px, 2.6vw, 48px);
  --sheet-gap: clamp(40px, 4.2vw, 80px);
  --sheet-open: 800ms var(--roll-ease);
  --sheet-close: 700ms var(--roll-ease);
  position: fixed;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  /* clip, not hidden: opening moves focus into the panel, and a dialog that
     can scroll would jump to show it before the slide starts */
  overflow: hidden;
  overflow: clip;
  border: 0;
  background: rgba(0, 0, 0, 0);
  color: var(--ink);
  transition: background-color var(--sheet-close);
}

.sheet::backdrop {
  background: transparent;
}

.sheet.is-open {
  background: rgba(0, 0, 0, 0.4);
  transition: background-color var(--sheet-open);
}

html.has-sheet {
  overflow: hidden;
}

/* The header stays put and only the content under it scrolls, so the
   scrollbar starts below the header instead of running up into the
   rounded corner */
.sheet__panel {
  position: absolute;
  inset: var(--sheet-top) 0 0;
  display: flex;
  flex-direction: column;
  width: min(100%, max(48.8vw, 640px));
  margin-inline: auto;
  overflow: hidden;
  border-radius: var(--sheet-radius) var(--sheet-radius) 0 0;
  background: var(--paper);
  transform: translate3d(0, calc(100% + var(--sheet-top)), 0);
  transition: transform var(--sheet-close);
}

/* Apple's corners: 38px, as on an iOS sheet, drawn as Apple's continuous
   curve where the browser can (corner-shape, Chrome and Edge for now): a
   superellipse 1.6 times the radius, as deep at the diagonal as a 38px
   circle, like Figma's iOS corner smoothing. Elsewhere it's that circle. */
@supports (corner-shape: superellipse(2)) {
  .sheet__panel {
    border-radius: calc(var(--sheet-radius) * 1.6) calc(var(--sheet-radius) * 1.6) 0 0;
    corner-shape: superellipse(1.78);
  }
}

.sheet__panel:focus {
  outline: none;
}

.sheet.is-open .sheet__panel {
  transform: none;
  transition: transform var(--sheet-open);
}

/* Title in the middle, Close tucked into the top right corner. The header
   is as tall as the corner is wide twice over, so the title's middle lines
   up with Close's */
.sheet__head {
  position: relative;
  flex: none;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: calc(var(--sheet-radius) * 2);
  padding: 0 calc(var(--sheet-radius) + var(--close-size) / 2);
  background: var(--paper);
  cursor: grab;
  touch-action: none;
}

.sheet__title {
  grid-column: 2;
  margin: 0;
  font-size: var(--text-medium);
  font-weight: 600;
  line-height: 1.15;
  white-space: nowrap;
}

/* Close: an X in a round beige button, the way iOS does it, concentric
   with the sheet's corner: it sits the corner's radius minus its own from
   the top and right edges, so its curve and the corner's share a centre */
.sheet__close {
  position: absolute;
  top: calc(var(--sheet-radius) - var(--close-size) / 2);
  right: calc(var(--sheet-radius) - var(--close-size) / 2);
  display: grid;
  place-items: center;
  width: var(--close-size);
  height: var(--close-size);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--paper-alt);
  color: var(--ink);
  cursor: pointer;
  transition: background-color 200ms ease;
}

.sheet__close:hover {
  background: color-mix(in srgb, var(--paper-alt), var(--ink) 8%);
}

/* The X spans about 30% of the button, in fine round-ended strokes, like
   the SF Symbols xmark */
.sheet__close svg {
  width: 37.5%;
  height: 37.5%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

.sheet__scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* The card's own video or picture, edge to edge, in the card's shape */
.sheet__media {
  aspect-ratio: 896 / 752;
  overflow: hidden;
  background: color-mix(in srgb, currentColor 8%, transparent);
}

.sheet__media video,
.sheet__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sheet__body {
  display: grid;
  gap: var(--sheet-gap);
  padding: var(--sheet-pad) var(--sheet-pad) calc(var(--sheet-pad) * 2);
}

.sheet__intro {
  margin: 0;
  font-size: var(--text-large);
  line-height: 1;
  letter-spacing: -0.03em;
}

/* The story under it, in the service descriptions' style */
.sheet__text p {
  max-width: 30em;
  margin: 0;
  font-size: var(--text-medium);
  line-height: 1.3;
}

.sheet__facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sheet-pad);
  margin-top: calc(var(--sheet-pad) - var(--sheet-gap));
  font-size: var(--text-small);
}

.sheet__text p + p {
  margin-top: 1em;
}

/* The toolbox sheet: each tool's logo in a round beige frame, then its
   name, and its number on the right, as on the work cards; A to Z, one to a
   row between hairlines. Logos keep the wave's sizing by eye (--w, a share
   of the frame's width). */
.sheet__tools {
  margin: 0;
  padding: 0;
  list-style: none;
  border-bottom: 1px solid var(--rule);
}

.sheet__tools li {
  --frame: clamp(56px, 4.44vw, 80px);
  display: flex;
  align-items: center;
  gap: clamp(16px, 1.67vw, 32px);
  padding: clamp(12px, 1.11vw, 20px) 0;
  border-top: 1px solid var(--rule);
  font-size: var(--text-medium);
  line-height: 1.3;
}

.sheet__tool-logo {
  display: grid;
  flex: none;
  place-items: center;
  width: var(--frame);
  height: var(--frame);
  border-radius: 50%;
  background: var(--paper-alt);
}

.sheet__tool-logo img {
  width: calc(var(--frame) * var(--w, 0.36));
  height: auto;
}

.sheet__tool-number {
  margin-left: auto;
}

/* Numbers, after a reference Linn sent: one per row under a hairline, the
   label on the left and the number at display size on the right, their
   capitals level at the top */
.sheet__stats {
  margin: 0;
  padding: 0;
  list-style: none;
}

.sheet__stats li {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: var(--sheet-pad);
  align-items: start;
  padding: clamp(14px, 1.4vw, 24px) 0 clamp(20px, 2vw, 36px);
  border-top: 1px solid var(--rule);
}

.sheet__label {
  grid-column: 1;
  grid-row: 1;
  font-size: var(--text-small);
  font-weight: 600;
  line-height: 1.4;
}

.sheet__number {
  grid-column: 2;
  grid-row: 1;
  margin-top: calc(0.275 * var(--text-small) - 0.075em);
  font-size: var(--text-display);
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

/* One project picked out of a case, on the site's beige, with room around
   each part: a small label and its title, a picture of the post on a phone,
   the story, then its numbers (the same big rows as Boneo's, sized together
   by fitNumbers) */
.sheet__feature {
  display: grid;
  gap: clamp(36px, 3.6vw, 64px);
  padding: clamp(28px, 3.6vw, 64px) clamp(24px, 3.2vw, 56px);
  border-radius: 16px;
  background: var(--paper-alt);
}

.sheet__feature-head {
  display: grid;
  gap: clamp(12px, 1.1vw, 20px);
  margin: 0;
}

.sheet__feature-eyebrow {
  margin: 0;
  font-size: var(--text-small);
  font-weight: 600;
  line-height: 1.4;
}

.sheet__feature-title {
  margin: 0;
  font-size: var(--text-large);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.03em;
}

.sheet__feature-media {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-media);
}

@media (prefers-reduced-motion: reduce) {
  .sheet,
  .sheet__panel,
  .sheet.is-open,
  .sheet.is-open .sheet__panel {
    transition: none;
  }
}

/* Footer */

/* Footer, rebuilt 1:1 from the Flow site's in pink. Measured at a 1552px
   window (1vw = 15.52px) on its 12-column grid with 24px gaps; the side
   margins follow the rest of this site. Positioned and opaque, so on the
   home page it slides over the last work card. */
.site-footer {
  --footer-pad-x: clamp(16px, 1.68vw, 32px);
  --footer-gap: 1.55vw;
  --footer-big: var(--text-large);
  --footer-small: var(--text-small);
  --footer-rule: var(--rule);
  position: relative;
  background: var(--block-1);
  color: var(--ink);
}

.site-footer a {
  text-decoration: none;
}

.site-footer__top,
.site-footer__cols,
.site-footer__bar {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--footer-gap);
}

/* Logo and call to action, with the rule under them */
.site-footer__top {
  align-items: start;
  height: 22.13vw;
  padding: 1.93vw var(--footer-pad-x) 0;
  border-bottom: 1px solid var(--footer-rule);
}

/* Linn's portrait where the reference has its logo: square, with the same
   space under it as above */
.site-footer__portrait {
  grid-column: 1 / 9;
  display: block;
  width: 18.27vw;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--radius-media);
}

.site-footer__cta {
  grid-column: 9 / 13;
  margin: 0;
  font-size: var(--footer-big);
  line-height: 1.14;
  letter-spacing: -0.02em;
}

/* The line sits 0.22em under the baseline, 0.057em thick. On the rolled
   copies too: underlines don't reach into the roll's inline-block. */
.site-footer__cta a,
.site-footer__cta .roll__item {
  text-decoration: underline;
  text-decoration-thickness: 0.057em;
  text-underline-offset: 0.217em;
}

/* Columns at the top, the small print pinned to the bottom */
.site-footer__main {
  display: flex;
  flex-direction: column;
  min-height: 36.76vw;
  padding: 3.22vw var(--footer-pad-x) 1.29vw;
}

.site-footer__col {
  grid-column: 1 / 4;
}

.site-footer__col--connect {
  grid-column: 4 / 9;
}

.site-footer__col--open {
  grid-column: 9 / 13;
}

.site-footer__label {
  margin: 0 0 2.2vw;
  font-size: var(--text-small);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: 0;
}

.site-footer__list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--footer-big);
  line-height: 1;
  letter-spacing: -0.02em;
}

/* The hover roll keeps the list's tight line height */
.site-footer__list .roll {
  height: 1em;
  line-height: 1;
}

.site-footer__bar {
  align-items: end;
  margin-top: auto;
  padding-top: 4vw;
  font-size: var(--footer-small);
  line-height: 1.15;
}

.site-footer__bar p {
  grid-column: 1 / 5;
  margin: 0;
}

.site-footer__bar a {
  grid-column: 5 / 9;
  justify-self: start;
}

.site-footer__bar a:last-child {
  grid-column: 9 / 13;
}

@media (max-width: 760px) {
  .site-footer__top {
    height: auto;
    row-gap: 10vw;
    padding-block: 8vw 12vw;
  }

  .site-footer__portrait {
    grid-column: 1 / -1;
    width: 44vw;
  }

  .site-footer__cta {
    grid-column: 1 / -1;
  }

  .site-footer__main {
    min-height: 0;
    padding-block: 8vw 6vw;
  }

  .site-footer__cols {
    row-gap: 10vw;
  }

  /* One column under the other, so the email address always fits */
  .site-footer__col,
  .site-footer__col--connect,
  .site-footer__col--open {
    grid-column: 1 / -1;
  }

  .site-footer__label {
    margin-bottom: 4vw;
  }

  .site-footer__bar {
    row-gap: 3vw;
    padding-top: 14vw;
  }

  .site-footer__bar p,
  .site-footer__bar a,
  .site-footer__bar a:last-child {
    grid-column: 1 / -1;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }

  [data-reveal] .line__inner,
  [data-reveal-rows] .line__inner {
    transform: none;
  }

  /* Headline words swap with a plain fade, no movement */
  .hero-title__word {
    transition: opacity 400ms ease-in-out !important;
  }

  .hero-title__word.is-entering,
  .hero-title__word.is-leaving {
    transform: none;
    opacity: 0;
  }
}
