/* ==========================================================================
   Case study (work/<slug>.html, built by tools/work/build.py)
   The head (back to all work, the name across the page, the line and the
   facts), the work on its stage (a site on a desktop with the phone beside
   it, or one of our products' shots, over its own backdrop and haze), then
   the overview across the page, and numbered sections with their titles held
   on the left: the challenge, what we did, the pictures (each on the
   project's backdrop, as on its card), a band of lines running across, the
   approach and what it's built with, what we built, the figures or what's
   under the hood; then "want something like this?", the next project and the
   previous one.
   Motion (case.js): the head plays in as the type loads and the stage wipes
   up after it; the stage's layers part a little as it scrolls by; the
   overview's words fill in as it's read; every block rises as it arrives;
   figures roll up; the log runs line by line; the band runs on its own.
   ========================================================================== */

.cs {
  position: relative;
  background: var(--bone);
}

/* Paper grain, as on the rest of the site. */
.cs::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url("../assets/textures/grain.webp") repeat;
  background-size: 160px 160px;
  opacity: 0.55;
  pointer-events: none;
}

.cs > * {
  position: relative;
}

/* ------------------------------------------------------------------ head */

.cs-head {
  padding: calc(var(--header-h) + clamp(24px, 5vh, 64px)) var(--gutter) 0;
}

.cs-head__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
}

.cs-back {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
  background: linear-gradient(currentColor, currentColor) 24px 100% / 0 1px no-repeat;
  transition: background-size 500ms var(--ease-out);
}

.cs-back svg {
  flex: none;
  width: 14px;
  height: 14px;
  transition: translate 420ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .cs-back:hover {
    background-size: calc(100% - 24px) 1px;
  }

  .cs-back:hover svg {
    translate: -3px 0;
  }
}

.cs-head__index {
  color: var(--text-mute);
  text-align: right;
}

/* The name across the page. --chars is its longest word (build.py), so
   the size keeps the longest word on one line at any width. */
.cs-title {
  margin-top: clamp(20px, 4vh, 44px);
  font-size: min(12.5rem, calc((100vw - 2 * var(--gutter)) / (var(--chars, 8) * 0.86)), 22vh);
  font-stretch: var(--wdth-display);
  font-weight: 500;
  line-height: 0.86;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  font-synthesis: none;
  text-wrap: balance;
}

.cs-title__w,
.cs-tagline__w {
  display: inline-block;
  overflow: clip;
  vertical-align: top;
}

.cs-title__w {
  padding: 0.06em 0.02em 0.02em;
  margin: -0.06em -0.02em -0.02em;
}

.cs-tagline__w {
  padding-bottom: 0.1em;
  margin-bottom: -0.1em;
}

.cs-title__w > span,
.cs-tagline__w > span {
  display: inline-block;
}

.cs-head__foot {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  align-items: start;
  gap: 32px clamp(32px, 5vw, 96px);
  margin-top: clamp(32px, 5.5vh, 64px);
  padding-top: clamp(18px, 2.6vh, 26px);
  border-top: 1px solid var(--line);
}

.cs-tagline {
  max-width: 19ch;
  font-size: clamp(1.75rem, 2.9vw, 3.5rem);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: -0.036em;
  text-wrap: balance;
}

.cs-head__side {
  display: grid;
  gap: 24px;
  justify-items: start;
}

.cs-meta {
  width: 100%;
  margin: 0;
}

.cs-meta__row {
  display: grid;
  grid-template-columns: minmax(7.5rem, 0.42fr) minmax(0, 1fr);
  gap: 16px;
  padding: 12px 0 11px;
  border-bottom: 1px solid var(--line);
}

.cs-meta__row:first-child {
  padding-top: 0;
}

.cs-meta dt {
  padding-top: 0.25em;
  color: var(--text-mute);
}

.cs-meta dd {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.4;
}

/* A website concept says so under its facts, where it's read first. */
.cs-note {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  max-width: 34rem;
  margin: 0;
  padding: 14px 16px 15px;
  border-radius: 12px;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--text-mute);
  background: var(--bone-deep);
  box-shadow: inset 0 0 0 1px var(--line);
}

.cs-note strong {
  font-weight: 600;
  color: var(--ink);
}

.cs-note__dot {
  width: 7px;
  height: 7px;
  margin-top: 0.5em;
  border-radius: 50%;
  background: var(--ink);
}

.cs-live {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 46px;
  padding: 0 20px 0 22px;
  border-radius: 999px;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--white);
  background: var(--ink);
  transition:
    background-color 300ms ease,
    scale 240ms var(--ease-out);
}

.cs-live svg {
  flex: none;
  width: 15px;
  height: 15px;
  transition: translate 420ms var(--ease-out);
}

.cs-live:active {
  scale: 0.97;
}

.cs-live:focus-visible {
  border-radius: 999px;
}

@media (hover: hover) and (pointer: fine) {
  .cs-live:hover {
    background: #262626;
  }

  .cs-live:hover svg {
    translate: 2px -2px;
  }

  .cs-live:hover > .roll > span:first-child {
    transform: translateY(-105%);
  }

  .cs-live:hover > .roll > span + span {
    transform: none;
  }
}

/* Entrance (html.is-entered, from the inline script after the head). */
html.js:not(.is-entered) .cs-title__w > span,
html.js:not(.is-entered) .cs-tagline__w > span {
  transform: translateY(108%);
}

html.js:not(.is-entered) .cs-head [data-enter] {
  opacity: 0;
  translate: 0 14px;
}

.cs-title__w > span {
  transition: transform 1300ms var(--ease-out) calc(60ms + var(--w, 0) * 90ms);
}

.cs-tagline__w > span {
  transition: transform 1100ms var(--ease-out) calc(300ms + var(--w, 0) * 35ms);
}

.cs-head [data-enter] {
  transition:
    opacity 900ms ease calc(340ms + var(--e, 0) * 60ms),
    translate 1100ms var(--ease-out) calc(340ms + var(--e, 0) * 60ms);
}

/* ------------------------------------------------------------------ the stage */

/* The work on its stage. A site: its first screen on a desktop, framed at
   16:10, with the phone standing beside it; one of our products: its shot
   across the stage. Over the project's backdrop, on its own haze. */
.cs-stage {
  --stage-h: min(calc((100vw - 2 * var(--gutter)) * 0.52), 86svh);
  --pad: clamp(18px, 3.6vw, 72px);
  --in: calc(var(--stage-h) - 2 * var(--pad));
  --r: clamp(16px, 1.4vw, 26px);
  height: var(--stage-h);
  margin: clamp(40px, 7vh, 88px) var(--gutter) 0;
}

.cs-stage__glow {
  position: absolute;
  left: -7%;
  top: -5%;
  z-index: -1;
  width: 114%;
  max-width: none;
  height: 118%;
  opacity: 0.72;
  pointer-events: none;
  user-select: none;
  transition: opacity 1600ms ease 700ms;
  /* Takes the last of the baked haze to zero at its edges (no faint box). */
  -webkit-mask-image: radial-gradient(closest-side, #000 78%, transparent);
  mask-image: radial-gradient(closest-side, #000 78%, transparent);
}

.cs-stage__card {
  position: relative;
  isolation: isolate;
  height: 100%;
  overflow: hidden;
  border-radius: var(--r);
  background: var(--ink-soft);
  clip-path: inset(0 0 0 0 round var(--r));
  transition: clip-path 1400ms var(--ease-out) 450ms;
}

.cs-stage__bg {
  position: absolute;
  inset: -3%;
  z-index: -1;
}

.cs-stage__bg img,
.cs-stage__desk img,
.cs-stage__phone img,
.cs-stage__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cs-stage__desk img,
.cs-stage__phone img {
  object-position: 50% 0;
}

.cs-stage__desk,
.cs-stage__phone {
  position: absolute;
  overflow: hidden;
  background: rgb(255 255 255 / 0.06);
}

.cs-stage__desk {
  top: var(--pad);
  left: calc(50% - var(--in) * 0.8);
  height: var(--in);
  aspect-ratio: 16 / 10;
  border-radius: calc(var(--r) * 0.6);
  box-shadow: 0 40px 80px -30px rgb(0 0 0 / 0.65);
}

/* With a phone: the desktop steps left to make room, the phone overlaps its edge. */
.cs-stage.has-phone .cs-stage__desk {
  left: calc(50% - var(--in));
}

.cs-stage__phone {
  bottom: calc(var(--pad) * 0.55);
  left: calc(50% + var(--in) * 0.6 - var(--in) * 0.9 * 390 / 844 * 0.22);
  height: calc(var(--in) * 0.9);
  aspect-ratio: 390 / 844;
  border-radius: calc(var(--in) * 0.055);
  box-shadow:
    0 0 0 clamp(3px, 0.35vw, 7px) rgb(10 10 10 / 0.94),
    0 0 0 calc(clamp(3px, 0.35vw, 7px) + 1px) rgb(255 255 255 / 0.12),
    0 50px 90px -30px rgb(0 0 0 / 0.75);
}

.cs-stage__desk::after,
.cs-stage__phone::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1);
  pointer-events: none;
}

/* Overscanned, so its drift (case.js) never shows an edge. */
.cs-stage__photo {
  position: absolute;
  inset: -36px 0;
}

/* The stage's pictures settle as it opens. */
.cs-stage__desk img,
.cs-stage__phone img,
.cs-stage__photo img {
  transition: transform 1900ms var(--ease-out) 450ms;
}

html.js:not(.is-entered) .cs-stage__card {
  clip-path: inset(100% 0 0 0 round var(--r));
}

html.js:not(.is-entered) .cs-stage__glow {
  opacity: 0;
}

html.js:not(.is-entered) .cs-stage__desk img,
html.js:not(.is-entered) .cs-stage__phone img,
html.js:not(.is-entered) .cs-stage__photo img {
  transform: scale(1.14);
}

/* ------------------------------------------------------------------ sections */

/* Each section: its number and title held on the left, the matter on the right. */
.cs-sec {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  align-items: start;
  gap: 24px clamp(32px, 4vw, 80px);
  padding: clamp(96px, 15vh, 176px) var(--gutter) 0;
}

.cs-sec__head {
  position: sticky;
  top: calc(var(--header-compact) + clamp(24px, 4vh, 40px));
  display: grid;
  gap: 12px;
}

.cs-label {
  color: var(--text-mute);
}

.cs-h2 {
  font-size: clamp(1.75rem, 2.5vw, 3.25rem);
  font-stretch: 112.5%;
  font-weight: 500;
  line-height: 0.98;
  letter-spacing: -0.012em;
  text-transform: uppercase;
  text-wrap: balance;
}

/* ---- the overview: the project in a sentence or two, across the page. Its
   words fill in as it's read (--p, case.js); without the script, it's all ink. */

.cs-over {
  padding: clamp(110px, 17vh, 200px) var(--gutter) 0;
}

.cs-over__label {
  display: flex;
  gap: 10px;
  margin-bottom: clamp(22px, 3.6vh, 40px);
}

.cs-fill {
  --p: 1;
  --lo: 0.14;
  max-width: 24ch;
  font-size: clamp(2rem, 1.1rem + 3.5vw, 5.25rem);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.038em;
  text-wrap: pretty;
}

html.js:not(.case-static) .cs-fill {
  --p: 0;
}

.cs-fill__w {
  opacity: clamp(var(--lo), calc(var(--lo) + (var(--p) * (var(--n) + 4) - var(--i)) / 4 * (1 - var(--lo))), 1);
}

/* ---- prose: the challenge, the approach */

.cs-prose {
  display: grid;
  gap: clamp(20px, 3vh, 32px);
}

.cs-prose__lead {
  max-width: 28ch;
  font-size: clamp(1.5rem, 2.25vw, 2.75rem);
  line-height: 1.16;
  letter-spacing: -0.03em;
  text-wrap: pretty;
}

.cs-prose__text {
  max-width: 58ch;
  font-size: clamp(1rem, 0.94rem + 0.25vw, 1.1875rem);
  line-height: 1.55;
  color: rgb(17 17 17 / 0.72);
  text-wrap: pretty;
}

/* ---- what we did: one row per service, the title large */

.cs-svc__list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-bottom: 1px solid var(--line);
}

.cs-svc__row {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 0.95fr) minmax(0, 1.05fr);
  align-items: baseline;
  gap: 8px clamp(20px, 2.6vw, 48px);
  padding: clamp(20px, 3.2vh, 32px) 0;
  border-top: 1px solid var(--line);
}

.cs-svc__n {
  color: var(--text-faint);
}

.cs-svc__title {
  font-size: clamp(1.375rem, 0.95rem + 1.15vw, 2.25rem);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.cs-svc__text {
  max-width: 44ch;
  font-size: clamp(0.9375rem, 0.9rem + 0.15vw, 1.0625rem);
  line-height: 1.55;
  color: var(--text-mute);
  text-wrap: pretty;
}

/* ---- what we built */

.cs-built__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(28px, 4vh, 44px) clamp(24px, 3vw, 56px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cs-built__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 16px;
  align-content: start;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.cs-built__n {
  grid-row: span 2;
  padding-top: 0.45em;
  color: var(--text-faint);
}

.cs-built__title {
  font-size: clamp(1.25rem, 1rem + 0.6vw, 1.625rem);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.022em;
}

.cs-built__text {
  margin-top: 10px;
  font-size: 0.9875rem;
  line-height: 1.5;
  color: var(--text-mute);
  text-wrap: pretty;
}

/* ---- the pictures: the head on top, the pictures across the full width */

.cs-gal {
  grid-template-columns: minmax(0, 1fr);
}

.cs-gal .cs-sec__head {
  position: static;
  margin-bottom: clamp(12px, 2vh, 24px);
}

/* A site's gallery is its reel alone: held to the right of the title, like the sections around it. */
.cs-gal.cs-gal--reel {
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
}

.cs-gal--reel .cs-sec__head {
  position: sticky;
  margin-bottom: 0;
}

.cs-gal__grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(36px, 6vh, 64px) clamp(12px, 1.4vw, 24px);
}

.cs-shot,
.cs-phonecard {
  display: flex;
  flex-direction: column;
  margin: 0;
}

.cs-shot--full {
  grid-column: 1 / -1;
}

.cs-shot--half {
  grid-column: span 6;
}

.cs-phonecard {
  grid-column: span 5;
}

.cs-shot--wide {
  grid-column: span 7;
}

/* Every picture of the work sits on the project's backdrop (art.py's
   <slug>-bg.webp), the screen inset on it, as on the project's card. */
.cs-shot__frame,
.cs-phonecard__frame,
.cs-laptop__frame,
.cs-logstage {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: clamp(12px, 1.1vw, 20px);
  background: var(--ink-soft);
  box-shadow: var(--shadow-deep);
}

.cs-bd {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.cs-bd img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cs-shot__frame {
  padding: 5.5%;
}

.cs-shot--half .cs-shot__frame {
  padding: 7%;
}

.cs-shot__pic {
  position: relative;
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: clamp(6px, 0.6vw, 12px);
  background: rgb(255 255 255 / 0.06);
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 0.1),
    0 34px 60px -26px rgb(0 0 0 / 0.7);
}

.cs-shot__frame::after,
.cs-phonecard__frame::after,
.cs-laptop__frame::after,
.cs-logstage::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgb(17 17 17 / 0.08);
  pointer-events: none;
}

.cs-shot__pic img,
.cs-shot__pic video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0;
}

/* The reel's pause / play, in the screen's corner. */
.cs-reel__btn {
  position: absolute;
  right: clamp(10px, 1.2vw, 20px);
  bottom: clamp(10px, 1.2vw, 20px);
  display: grid;
  place-items: center;
  width: clamp(36px, 2.6vw, 44px);
  aspect-ratio: 1;
  border: 0;
  border-radius: 50%;
  color: var(--white);
  background: rgb(17 17 17 / 0.55);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.16);
  cursor: pointer;
  opacity: 0.8;
  transition:
    opacity 300ms ease,
    scale 240ms var(--ease-out);
}

.cs-reel__btn svg {
  width: 38%;
  height: 38%;
}

.cs-reel__play,
.cs-shot__pic.is-playing .cs-reel__pause {
  display: block;
}

.cs-reel__pause,
.cs-shot__pic.is-playing .cs-reel__play {
  display: none;
}

.cs-reel__btn:active {
  scale: 0.94;
}

@media (hover: hover) and (pointer: fine) {
  .cs-reel__btn:hover {
    opacity: 1;
  }
}

.cs-shot figcaption,
.cs-phonecard figcaption {
  display: flex;
  gap: 8px;
  margin-top: 14px;
  color: var(--text-mute);
}

.cs-shot figcaption span,
.cs-phonecard figcaption span {
  color: var(--text-faint);
}

/* The site on a phone, upright on its backdrop, as tall as the picture beside it. */
.cs-phonecard__frame {
  --pad: clamp(18px, 2.4vw, 44px);
  flex: 1;
  min-height: 0;
}

.cs-phonecard__phone {
  position: absolute;
  top: var(--pad);
  left: 0;
  right: 0;
  width: auto;
  height: calc(100% - 2 * var(--pad));
  margin-inline: auto;
  aspect-ratio: 390 / 844;
  overflow: hidden;
  border-radius: clamp(14px, 1.5vw, 28px);
  box-shadow:
    0 0 0 clamp(3px, 0.3vw, 6px) rgb(10 10 10 / 0.94),
    0 0 0 calc(clamp(3px, 0.3vw, 6px) + 1px) rgb(255 255 255 / 0.12),
    0 40px 70px -26px rgb(0 0 0 / 0.75);
}

.cs-phonecard__phone img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0;
}

/* Fitevolve: the screens in a row on the app's backdrop (they swipe on a phone). */
.cs-phones {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: clamp(16px, 1.4vw, 26px);
  background: var(--ink-soft);
}

.cs-phones__list {
  display: flex;
  gap: clamp(10px, 1.6vw, 28px);
  margin: 0;
  padding: clamp(36px, 6vw, 110px) clamp(20px, 3.6vw, 72px) clamp(56px, 8vw, 140px);
  list-style: none;
}

.cs-phones__item {
  flex: 1 1 0;
  min-width: 0;
  filter: drop-shadow(0 34px 40px rgb(0 0 0 / 0.45));
}

/* every other one sits a little lower, so the row has a rhythm */
.cs-phones__item:nth-child(even) {
  margin-top: 7%;
}

.cs-phones__item img {
  width: 100%;
  height: auto;
}

/* Tradervolve: the screens on laptops, two by two, each on the backdrop. */
.cs-laptops {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(12px, 1.4vw, 24px);
}

.cs-laptop {
  margin: 0;
}

.cs-laptop__frame {
  padding: clamp(16px, 3vw, 56px);
}

.cs-laptop__frame > img {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 30px 34px rgb(0 0 0 / 0.45));
}

/* Pitch Daily: one cycle of the research log, running line by line, on the backdrop. */
.cs-logstage {
  padding: clamp(16px, 4.5vw, 84px);
}

.cs-log {
  position: relative;
  overflow: hidden;
  border-radius: clamp(14px, 1.2vw, 22px);
  color: rgb(247 245 242 / 0.86);
  background: radial-gradient(120% 90% at 0% 0%, #232323 0%, var(--ink) 60%);
  box-shadow: var(--shadow-deep);
}

.cs-log__bar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px clamp(18px, 2.4vw, 36px);
  border-bottom: 1px solid rgb(255 255 255 / 0.08);
  color: var(--on-ink-mute);
}

.cs-log__dots {
  display: flex;
  gap: 6px;
}

.cs-log__dots i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.16);
}

.cs-log__live {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  color: var(--bone);
}

.cs-log__live i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #58d68d;
  box-shadow: 0 0 0 0 rgb(88 214 141 / 0.5);
  animation: cs-live 2.2s ease-out infinite;
}

@keyframes cs-live {
  0% {
    box-shadow: 0 0 0 0 rgb(88 214 141 / 0.45);
  }

  70%,
  100% {
    box-shadow: 0 0 0 9px rgb(88 214 141 / 0);
  }
}

.cs-log__lines {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: clamp(20px, 2.6vw, 40px) clamp(18px, 2.4vw, 36px) clamp(24px, 3vw, 44px);
  list-style: none;
  font-size: clamp(0.6875rem, 0.6rem + 0.3vw, 0.875rem);
  text-transform: none;
  letter-spacing: 0.01em;
  line-height: 1.9;
}

.cs-log__line {
  display: grid;
  grid-template-columns: 6.5em minmax(0, 24em) minmax(0, 1fr);
  gap: 1.5em;
  white-space: nowrap;
}

.cs-log__t {
  color: rgb(247 245 242 / 0.38);
}

.cs-log__src,
.cs-log__res {
  overflow: hidden;
  text-overflow: ellipsis;
}

.cs-log__res {
  color: rgb(247 245 242 / 0.6);
}

.cs-log__line.is-hot .cs-log__res {
  color: var(--white);
}

.cs-log__line.is-hot .cs-log__res::before {
  content: "\2192\00a0";
  color: #58d68d;
}

/* The social content: the hook, before and after, then the analytics. */
.cs-hook {
  display: grid;
  gap: clamp(28px, 4vh, 44px);
}

.cs-hook__title {
  max-width: 22ch;
  font-size: clamp(1.75rem, 3vw, 3.75rem);
  line-height: 1.04;
  letter-spacing: -0.036em;
  text-wrap: balance;
}

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

.cs-hook__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) minmax(0, 1fr);
  align-items: start;
  gap: 16px clamp(20px, 3vw, 56px);
  padding: clamp(18px, 3vh, 28px) 0;
  border-top: 1px solid var(--line);
}

.cs-hook__row:last-child {
  border-bottom: 1px solid var(--line);
}

.cs-hook__before,
.cs-hook__after {
  display: grid;
  gap: 8px;
  font-size: clamp(1.0625rem, 0.95rem + 0.45vw, 1.375rem);
  line-height: 1.3;
  letter-spacing: -0.015em;
}

.cs-hook__before .mono,
.cs-hook__after .mono {
  color: var(--text-mute);
}

.cs-hook__before s {
  color: var(--text-mute);
  text-decoration-thickness: 1.5px;
}

.cs-hook__after {
  font-weight: 500;
}

.cs-hook__note {
  padding-top: 1.55rem;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--text-mute);
}

.cs-hook__closing {
  max-width: 52ch;
  font-size: clamp(1rem, 0.94rem + 0.25vw, 1.1875rem);
  line-height: 1.55;
  color: rgb(17 17 17 / 0.72);
}

.cs-shot--proof {
  margin-top: clamp(48px, 8vh, 96px);
}

.cs-shot--proof .cs-shot__frame {
  padding: 4.5%;
}

.cs-shot--proof .cs-shot__pic {
  aspect-ratio: 1600 / 1100;
}

.cs-shot--proof .cs-shot__pic img {
  object-position: 50% 45%;
}

/* ---- the band: a few lines running across the page, on ink */

.cs-band {
  margin-top: clamp(110px, 17vh, 200px);
  overflow: hidden;
  padding: clamp(18px, 3.4vh, 36px) 0;
  color: var(--bone);
  background: var(--ink);
}

.cs-band__track {
  display: flex;
  width: max-content;
  will-change: transform;
  animation: cs-band calc(var(--len, 80) * 0.42s) linear infinite;
}

.cs-band__run {
  display: flex;
  align-items: center;
  flex: none;
}

.cs-band__item {
  font-size: clamp(2.25rem, 1.2rem + 4.4vw, 7rem);
  font-stretch: var(--wdth-display);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.015em;
  text-transform: uppercase;
  white-space: nowrap;
  font-synthesis: none;
}

.cs-band__dot {
  flex: none;
  width: clamp(10px, 1.1vw, 20px);
  aspect-ratio: 1;
  margin: 0 clamp(22px, 2.8vw, 56px);
  border-radius: 50%;
  background: currentColor;
  opacity: 0.5;
}

@keyframes cs-band {
  to {
    transform: translateX(-50%);
  }
}

/* ---- the approach: what it's built with, under the words */

.cs-stack {
  margin-top: clamp(28px, 5vh, 56px);
}

.cs-stack__label {
  margin-bottom: 16px;
  color: var(--text-mute);
}

.cs-stack__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 clamp(24px, 3vw, 56px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cs-stack__item {
  display: grid;
  align-content: start;
  gap: 6px;
  padding: 16px 0 18px;
  border-top: 1px solid var(--line);
}

.cs-stack__name {
  font-size: clamp(1.0625rem, 1rem + 0.2vw, 1.25rem);
  font-weight: 500;
  letter-spacing: -0.015em;
}

.cs-stack__text {
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--text-mute);
}

/* ---- figures */

.cs-stats__list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 28px clamp(20px, 2.4vw, 48px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cs-stat {
  display: grid;
  align-content: start;
  gap: 14px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.cs-stat__value {
  font-size: clamp(2.75rem, 1.6rem + 3.4vw, 6rem);
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cs-stat__label {
  max-width: 24ch;
  font-size: 0.9375rem;
  line-height: 1.4;
  color: var(--text-mute);
}

/* ---- under the hood */

.cs-under__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 clamp(24px, 3vw, 56px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cs-under__item {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 64px;
  padding: 14px 0;
  border-top: 1px solid var(--line);
  font-size: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
  line-height: 1.35;
  letter-spacing: -0.01em;
}

.cs-under__tick {
  flex: none;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  color: var(--white);
  background: var(--ink);
}

.cs-under__tick svg {
  width: 14px;
  height: 14px;
}

/* ------------------------------------------------------------------ the end */

.cs-end {
  padding: clamp(110px, 17vh, 200px) var(--gutter) clamp(72px, 12vh, 140px);
}

.cs-ask {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px 40px;
  padding: clamp(22px, 3.4vh, 34px) 0;
  border-block: 1px solid var(--line);
}

.cs-ask__text {
  max-width: 46ch;
  font-size: clamp(1.0625rem, 0.98rem + 0.35vw, 1.375rem);
  line-height: 1.38;
  letter-spacing: -0.015em;
  text-wrap: pretty;
}

.cs-ask .btn-cta {
  display: inline-flex;
}

/* The next project: its name across the page, its picture beside it. */
.cs-next {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(220px, 26vw, 460px);
  grid-template-areas:
    "label pic"
    "name pic"
    "what pic";
  align-items: end;
  column-gap: clamp(24px, 4vw, 72px);
  margin-top: clamp(48px, 8vh, 96px);
  -webkit-tap-highlight-color: transparent;
}

.cs-next__label {
  grid-area: label;
  align-self: start;
  color: var(--text-mute);
}

.cs-next__name {
  grid-area: name;
  margin-top: 14px;
  /* --chars is the next name's longest word (build.py): it always fits beside the picture. */
  font-size: min(10rem, 8.4vw, calc((100vw - 2 * var(--gutter) - clamp(220px, 26vw, 460px) - clamp(24px, 4vw, 72px)) / (var(--chars, 8) * 0.9)));
  font-stretch: var(--wdth-display);
  font-weight: 500;
  line-height: 0.88;
  letter-spacing: -0.015em;
  text-transform: uppercase;
  font-synthesis: none;
  text-wrap: balance;
  transition: translate 700ms var(--ease-out);
}

.cs-next__what {
  grid-area: what;
  margin-top: 18px;
  font-size: 1rem;
  color: var(--text-mute);
}

.cs-next__pic {
  grid-area: pic;
  position: relative;
  isolation: isolate;
  display: block;
  padding: 7%;
  overflow: hidden;
  border-radius: clamp(10px, 1vw, 18px);
  background: var(--ink-soft);
  box-shadow: var(--shadow-deep);
}

.cs-next__pic .cs-bd img {
  transition: scale 1400ms var(--ease-out);
}

.cs-next__shot {
  position: relative;
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: clamp(5px, 0.5vw, 9px);
  box-shadow:
    0 0 0 1px rgb(255 255 255 / 0.1),
    0 24px 44px -20px rgb(0 0 0 / 0.7);
}

.cs-next__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  transition: scale 1100ms var(--ease-out);
}

/* The arrow sits on the picture's top corner. */
.cs-next__go {
  grid-area: pic;
  position: relative;
  align-self: start;
  justify-self: end;
  display: grid;
  place-items: center;
  width: clamp(44px, 3.4vw, 60px);
  aspect-ratio: 1;
  margin: calc(clamp(44px, 3.4vw, 60px) * -0.5) 14px 0 0;
  border-radius: 50%;
  color: var(--white);
  background: var(--ink);
  transition:
    rotate 600ms var(--ease-out),
    scale 400ms var(--ease-out);
}

.cs-next__go svg {
  width: 40%;
  height: 40%;
}

@media (hover: hover) and (pointer: fine) {
  .cs-next:hover .cs-next__name {
    translate: 18px 0;
  }

  .cs-next:hover .cs-next__shot img {
    scale: 1.06;
  }

  .cs-next:hover .cs-next__pic .cs-bd img {
    scale: 1.08;
  }

  .cs-next:hover .cs-next__go {
    rotate: -45deg;
    scale: 1.08;
  }
}

.cs-next:focus-visible {
  outline-offset: 8px;
  border-radius: 8px;
}

/* The previous project and all work, under the next one. */
.cs-pager {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px 32px;
  margin-top: clamp(44px, 7vh, 80px);
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.cs-pager__link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
  color: var(--text-mute);
  background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition:
    color 300ms ease,
    background-size 500ms var(--ease-out);
}

.cs-pager__link svg {
  flex: none;
  width: 14px;
  height: 14px;
  transition: translate 420ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .cs-pager__link:hover {
    color: var(--ink);
    background-size: 100% 1px;
  }

  .cs-pager__link:hover svg {
    translate: -3px 0;
  }
}

/* ------------------------------------------------------------------ reveal */

/* Armed by case.js (without it, nothing hides): each block rises as it
   arrives; ones arriving together follow one another (--d). */
[data-rv] {
  transition:
    opacity 900ms ease calc(var(--d, 0) * 90ms),
    translate 1100ms var(--ease-out) calc(var(--d, 0) * 90ms);
}

html.js:not(.case-static) .cs [data-rv]:not(.is-in) {
  opacity: 0;
  translate: 0 26px;
}

/* Pictures also settle from slightly large. */
.cs-shot__pic img,
.cs-phonecard__phone,
.cs-laptop__frame > img,
.cs-phones__item {
  transition: transform 1600ms var(--ease-out) calc(120ms + var(--d, 0) * 90ms);
}

html.js:not(.case-static) .cs [data-rv]:not(.is-in) .cs-shot__pic img,
html.js:not(.case-static) .cs [data-rv]:not(.is-in) .cs-laptop__frame > img {
  transform: scale(1.1);
}

html.js:not(.case-static) .cs [data-rv]:not(.is-in) .cs-phonecard__phone {
  transform: translateY(8%);
}

html.js:not(.case-static) .cs [data-rv]:not(.is-in) .cs-phones__item {
  transform: translateY(14%);
}

.cs-phones__item {
  transition-delay: calc(150ms + var(--k, 0) * 70ms);
}

/* The log runs line by line once it's in. */
.cs-log__line {
  transition:
    opacity 300ms ease calc(500ms + var(--k, 0) * 140ms),
    translate 500ms var(--ease-out) calc(500ms + var(--k, 0) * 140ms);
}

html.js:not(.case-static) .cs-logstage:not(.is-in) .cs-log__line {
  opacity: 0;
  translate: -8px 0;
}

/* ------------------------------------------------------------------ responsive */

@media (max-width: 1099px) {
  .cs-head__foot {
    grid-template-columns: 1fr;
  }

  .cs-sec {
    grid-template-columns: 1fr;
  }

  .cs-sec__head {
    position: static;
  }

  .cs-gal.cs-gal--reel {
    grid-template-columns: 1fr;
  }

  .cs-gal--reel .cs-sec__head {
    position: static;
  }

  .cs-hook__row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .cs-hook__note {
    grid-column: 1 / -1;
    padding-top: 0;
  }
}

@media (max-width: 719px) {
  /* One row, as on desktop; the index drops under the link only if it must. */
  .cs-head__top {
    flex-wrap: wrap;
    gap: 6px 24px;
  }

  .cs-head__index {
    text-align: left;
  }

  .cs-meta__row {
    grid-template-columns: 6.5rem minmax(0, 1fr);
  }

  /* The stage: the desktop across the top, the phone over its corner. */
  .cs-stage {
    --stage-h: calc((100vw - 2 * var(--gutter)) * 1.02);
    --pad: 16px;
  }

  .cs-stage.has-phone .cs-stage__desk,
  .cs-stage__desk {
    left: var(--pad);
    width: calc(100% - 2 * var(--pad));
    height: auto;
  }

  .cs-stage__phone {
    left: auto;
    right: calc(var(--pad) * 1.6);
    bottom: var(--pad);
    height: 64%;
    border-radius: 16px;
  }

  .cs-built__list,
  .cs-under__list,
  .cs-stack__list,
  .cs-laptops {
    grid-template-columns: 1fr;
  }

  .cs-svc__row {
    grid-template-columns: 2.25rem minmax(0, 1fr);
  }

  .cs-svc__text {
    grid-column: 2;
  }

  .cs-shot__frame,
  .cs-shot--half .cs-shot__frame {
    padding: 6%;
  }

  .cs-logstage {
    padding: 12px;
  }

  .cs-gal__grid {
    gap: 32px 0;
  }

  .cs-shot--half,
  .cs-shot--wide,
  .cs-phonecard {
    grid-column: 1 / -1;
  }

  .cs-phonecard__frame {
    flex: none;
    height: min(118vw, 520px);
  }

  .cs-phones__list {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 20px;
    scrollbar-width: none;
  }

  .cs-phones__list::-webkit-scrollbar {
    display: none;
  }

  .cs-phones__item {
    flex: 0 0 46%;
    scroll-snap-align: start;
  }

  .cs-log__line {
    grid-template-columns: 5.6em minmax(0, 1fr);
    gap: 0 1em;
  }

  .cs-log__res {
    grid-column: 2;
  }

  .cs-hook__row {
    grid-template-columns: 1fr;
  }

  .cs-stats__list {
    grid-template-columns: 1fr;
  }

  .cs-next {
    grid-template-columns: 1fr;
    grid-template-areas:
      "pic"
      "label"
      "name"
      "what";
  }

  .cs-next__pic,
  .cs-next__go {
    margin-bottom: 24px;
  }

  .cs-next__name {
    font-size: min(3.5rem, calc((100vw - 2 * var(--gutter)) / (var(--chars, 8) * 0.9)));
  }

}

@media (prefers-reduced-motion: reduce) {
  .cs *,
  .cs *::before,
  .cs *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    animation: none !important;
  }
}
