/*
 * work: the screening room.
 *
 * Layers, in order:
 *   1. Base (phones and tablets, and every static state): stacked project blocks.
 *   2. Desktop (1024 and up) static: each project as a 12 column spread, stacked.
 *   3. Desktop with motion (html.motion-ready): one horizontal track in a sticky room.
 *
 * Without JS or with reduced motion the section is night via .field-night, with a
 * hard edge. With motion it reads the live root tokens so Lights Down can dim the
 * room on the way in and bring the lights back up on the way out.
 */

.work {
  --work-bg: var(--night);
  --work-edge: var(--gx);
  --work-top: 0px;
  position: relative;
  overflow-x: clip;
  padding-block: var(--section-y);
}
html.motion-ready .work {
  --work-bg: var(--bg);
  --fg-soft: inherit;
  --rule: inherit;
  --link: inherit;
  background: var(--work-bg);
  color: var(--fg);
}
/* On the way out the room keeps the night set while the page around it lights back up, so it
   leaves with a hard edge and nothing inside it ever sits on paper (work.js sets the class). */
html.motion-ready .work.is-leaving {
  --bg: var(--night);
  --fg: var(--paper);
  --work-bg: var(--night);
  --fg-soft: var(--mist);
  --rule: rgba(238, 237, 232, .2);
  --link: var(--cobalt-lift);
  --focus: var(--lime);
}

.work__track {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gx);
}

/* ---------- intro ---------- */

.work__intro { margin-bottom: clamp(56px, 9vw, 120px); }
.work__eyebrow { margin: 0 0 22px; }
.work__title {
  margin: 0;
  max-width: 11ch;
  text-wrap: balance;
}
.work__lede {
  margin: 24px 0 0;
  color: var(--fg-soft);
  text-wrap: pretty;
}

/* ---------- project blocks (phones and tablets) ---------- */

.work__list {
  display: grid;
  gap: 72px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.work-item { position: relative; }
.work-item__inner {
  display: flex;
  flex-direction: column;
}
.work-item__text { display: contents; }

.work-item__head {
  display: flex;
  align-items: baseline;
  gap: 14px;
}
.work-item__index {
  flex: none;
  font-family: var(--f-display);
  font-weight: 800;
  font-stretch: 75%;
  font-size: 2.5rem;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--fg-soft);
}
.work-item__name { margin: 0; text-wrap: balance; }
.work-item__meta {
  margin: 16px 0 0;
  color: var(--fg-soft);
  line-height: 1.35;
}
.work-item__scope {
  margin: 12px 0 0;
  max-width: 34ch;
  text-wrap: pretty;
}
.work-item__chips {
  margin: 18px 0 0;
  padding: 0;
  list-style: none;
  color: var(--fg-soft);
}
.work-item__action {
  order: 2;
  margin-top: 28px;
}

/* The stage: phone in front, browser peeking behind it top right. */
.work-item__stage {
  --pw: 64vw;
  --bw: 78vw;
  position: relative;
  order: 1;
  height: calc((100vw - 2 * var(--gx)) * 1.2);
  margin: 32px calc(var(--gx) * -1) 0;
  overflow: hidden;
  isolation: isolate;
}
/* Light spill: the client's colour glowing behind the frames. It fades out inside the stage on
   phones (the stage clips), and around the browser frame on desktop. */
.work-item__spill {
  position: absolute;
  z-index: 0;
  left: 50%;
  top: 50%;
  width: 100%;
  height: 100%;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 45%, transparent) 30%, color-mix(in srgb, var(--accent) 16%, transparent) 68%, transparent);
  pointer-events: none;
}
.work-item__screen {
  position: absolute;
  z-index: 1;
  top: 3%;
  left: calc(var(--gx) + var(--pw) * .46);
  width: var(--bw);
  transform: rotate(4deg);
  transform-origin: 0 0;
}
.work-item__phone {
  position: absolute;
  z-index: 2;
  top: 11%;
  left: var(--gx);
  width: var(--pw);
  pointer-events: none;
}
/* The frame viewports are spans; give them a box so aspect-ratio applies (see report: base.css). */
.work .frame-browser__view,
.work .frame-phone__view { display: block; }

/*
 * Phone status bar: 44 of the capture's 390 points, in the site's own top colour (--bar, set
 * per item in work.php). The capture starts below it, so the speaker pill sits in the bar and
 * never over the site's logo, and a long capture scrolls up under it like a real phone.
 */
.work .frame-phone__view {
  --bar-h: 5.213%;
  container-type: inline-size;
  background: var(--bar, #0B0B0A);
}
.work .frame-phone__view img { top: var(--bar-h); }
.work .frame-phone__view::before,
.work .frame-phone__view::after {
  content: '';
  position: absolute;
  z-index: 1;
  pointer-events: none;
}
.work .frame-phone__view::before {
  content: '9:41';
  top: 0; left: 0; right: 0;
  height: var(--bar-h);
  padding: calc(10.5px - 1.7cqw) 0 0 8.5cqw;
  background: var(--bar, #0B0B0A);
  color: var(--bar-ink, #EEEDE8);
  font: 600 3.4cqw/1 var(--f-body);
  letter-spacing: .01em;
  font-variant-numeric: tabular-nums;
}
.work .frame-phone__view::after {
  top: calc(10.5px - 1.5cqw);
  right: 7cqw;
  width: 17cqw;
  height: 3cqw;
  background: var(--bar-ink, #EEEDE8);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 68 12'%3E%3Crect x='0' y='8' width='3' height='4' rx='1'/%3E%3Crect x='5' y='6' width='3' height='6' rx='1'/%3E%3Crect x='10' y='3.5' width='3' height='8.5' rx='1'/%3E%3Crect x='15' y='1' width='3' height='11' rx='1'/%3E%3Cpath d='M31 3.2a11 11 0 0 1 14 0l-1.6 1.7a8.7 8.7 0 0 0-10.8 0zM33.6 6a7 7 0 0 1 8.8 0l-1.6 1.7a4.7 4.7 0 0 0-5.6 0zM36.2 8.8a3 3 0 0 1 3.6 0L38 10.8z'/%3E%3Crect x='47.5' y='1.5' width='17' height='9' rx='2.6' fill='none' stroke='%23000' stroke-opacity='.45'/%3E%3Crect x='49.5' y='3.5' width='13' height='5' rx='1.2'/%3E%3Crect x='65.6' y='4.3' width='1.6' height='3.4' rx='.8' fill-opacity='.45'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 68 12'%3E%3Crect x='0' y='8' width='3' height='4' rx='1'/%3E%3Crect x='5' y='6' width='3' height='6' rx='1'/%3E%3Crect x='10' y='3.5' width='3' height='8.5' rx='1'/%3E%3Crect x='15' y='1' width='3' height='11' rx='1'/%3E%3Cpath d='M31 3.2a11 11 0 0 1 14 0l-1.6 1.7a8.7 8.7 0 0 0-10.8 0zM33.6 6a7 7 0 0 1 8.8 0l-1.6 1.7a4.7 4.7 0 0 0-5.6 0zM36.2 8.8a3 3 0 0 1 3.6 0L38 10.8z'/%3E%3Crect x='47.5' y='1.5' width='17' height='9' rx='2.6' fill='none' stroke='%23000' stroke-opacity='.45'/%3E%3Crect x='49.5' y='3.5' width='13' height='5' rx='1.2'/%3E%3Crect x='65.6' y='4.3' width='1.6' height='3.4' rx='.8' fill-opacity='.45'/%3E%3C/svg%3E") center / contain no-repeat;
}
.work-item__handset { box-shadow: var(--shadow-night), inset 0 0 0 1px rgba(255, 255, 255, .08); }
/* The stage floor: the phone runs into the dark rather than ending on a hard crop. */
.work-item__stage::after {
  content: '';
  position: absolute;
  z-index: 3;
  left: 0; right: 0; bottom: 0;
  height: 30%;
  background: linear-gradient(to bottom, transparent, var(--work-bg) 88%);
  pointer-events: none;
}

/* Visit the site: a full width outline button on phones, a text link on desktop. */
.work-visit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .45em;
  width: 100%;
  min-height: 52px;
  padding: 0 20px;
  border: 1.5px solid currentColor;
  border-radius: 4px;
  color: inherit;
  font-family: var(--f-display);
  font-weight: 700;
  font-stretch: 88%;
  font-size: 1.0625rem;
  line-height: 1;
  text-decoration: none;
  transition: background-color .2s var(--ease-soft);
}
.work-visit__arrow {
  display: inline-block;
  font-family: var(--f-body);
  transition: transform .25s var(--ease-soft);
}
.work-visit:hover { background: color-mix(in srgb, currentColor 8%, transparent); }
.work-visit:hover .work-visit__arrow { transform: translate(2px, -2px); }

/* ---------- end card ---------- */

.work__end { margin-top: clamp(96px, 14vw, 160px); }
.work__end-title {
  margin: 0;
  max-width: 9ch;
  text-wrap: balance;
}
.work__end-calls {
  display: grid;
  gap: 12px;
  margin-top: 36px;
}

/* Counter and progress only exist inside the desktop pin. */
.work__counter,
.work__progress { display: none; }

@media (min-width: 560px) and (max-width: 1023px) {
  .work__end-calls { display: flex; flex-wrap: wrap; }
  .work-visit { width: auto; display: inline-flex; min-width: 280px; }
}

/* Tablet: the same block, with the devices scaled to the stage instead of the viewport. */
@media (min-width: 768px) and (max-width: 1023px) {
  .work-item__stage {
    --pw: calc((100vw - 2 * var(--gx)) * .42);
    --bw: calc((100vw - 2 * var(--gx)) * .8);
    height: calc((100vw - 2 * var(--gx)) * 1.02);
  }
  .work-item__screen { top: 4%; left: calc(var(--gx) + var(--pw) * .5); }
  .work-item__phone { top: 14%; }
  .work-item__stage::after { height: 22%; }
  .work-item__scope { max-width: 44ch; }
}

/* ---------- desktop: spreads (static, stacked) ---------- */

@media (min-width: 1024px) {
  .work-item__stage {
    --pw: clamp(170px, 14vw, 250px);
    --bw: min(58vw, 920px, calc((100svh - 340px) * 1.6));
    --bh: calc(var(--bw) * .625 + 36px);
    --ph: calc((var(--pw) - 18px) * 2.1641 + 18px);
  }
  .work__intro { margin-bottom: clamp(80px, 9vw, 140px); }
  .work__list { gap: clamp(112px, 11vw, 176px); }

  .work-item__inner {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--gutter);
    align-items: center;
  }
  .work-item__text {
    display: block;
    grid-column: 1 / span 4;
    position: relative;
    z-index: 2;
  }
  .work-item__head { flex-direction: column; align-items: flex-start; gap: 14px; }
  .work-item__index { font-size: 1.25rem; }
  .work-item__meta { margin-top: 18px; }
  .work-item__scope { margin-top: 14px; }
  .work-item__chips { margin-top: 22px; }
  .work-item__action { margin-top: 26px; }

  .work-item__stage {
    --screen-top: 0px;
    grid-column: 5 / -1;
    height: calc(var(--bh) + var(--ph) * .12 + 16px);
    margin: 0;
    overflow: visible;
  }
  .work-item__stage::after { display: none; }
  .work-item__screen {
    top: var(--screen-top);
    left: auto;
    right: 0;
    width: var(--bw);
    transform: none;
  }
  .work-item__phone {
    top: calc(var(--screen-top) + var(--bh) - var(--ph) * .88);
    /* Hang off the browser's bottom left corner, but keep at least 24px clear of the text column. */
    left: max(calc(100% - var(--bw) - var(--pw) * .38), calc(24px - var(--gutter)));
    width: var(--pw);
  }
  .work-item__spill {
    left: calc(100% - var(--bw) / 2);
    top: calc(var(--screen-top) + var(--bh) / 2);
    width: calc(var(--bw) * 1.7);
    height: calc(var(--bh) * 1.75);
  }

  .work-visit {
    display: inline-flex;
    width: auto;
    min-height: 48px;
    padding: 0;
    border: 0;
    gap: .4em;
    color: var(--link);
    font-size: 1.0625rem;
  }
  .work-visit:hover { background: none; }
  .work-visit:hover .work-visit__text { text-decoration: underline; text-underline-offset: .2em; }

  .work__end { margin-top: clamp(120px, 12vw, 200px); }
  .work__end-calls { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 44px; }
}

@media (hover: hover) and (min-width: 1024px) {
  .work-item__browser,
  .work-item__handset { transition: transform .45s var(--ease-out), box-shadow .45s var(--ease-out); }
  .work-item__stage:hover .work-item__browser,
  .work-item__stage:hover .work-item__handset { transform: translateY(-4px); }
  .work-item__stage:hover .work-item__browser { box-shadow: 0 40px 70px -24px rgba(0, 0, 0, .7); }
}

/* ---------- desktop with motion: the pinned horizontal screening room ---------- */

@media (min-width: 1024px) {
  /*
   * The room is held with CSS sticky, not a ScrollTrigger pin: the section is one screen tall
   * plus the track's travel (--work-travel, set by work.js), and the room sticks to the top
   * while the track slides. Sticky offsets count as scrolling, so this never registers as a
   * layout shift, on mouse or touch, and it follows native momentum scrolling exactly.
   */
  html.motion-ready .work {
    --work-top: 56px;
    --work-edge: max(var(--gx), calc((100vw - var(--maxw)) / 2 + var(--gx)));
    height: calc(100svh + var(--work-travel, 0px));
    padding: 0;
    overflow: clip;
  }
  html.motion-ready .work__room {
    position: sticky;
    top: 0;
    height: 100svh;
    overflow: clip;
  }
  html.motion-ready .work__track {
    display: flex;
    width: max-content;
    max-width: none;
    height: 100%;
    margin: 0;
    padding: 0;
  }
  html.motion-ready .work__intro {
    flex: 0 0 38vw;
    display: flex;
    align-items: center;
    margin: 0;
    padding: var(--work-top) 3vw 0 var(--work-edge);
  }
  html.motion-ready .work__list {
    display: flex;
    gap: 0;
  }
  html.motion-ready .work-item {
    flex: 0 0 100vw;
    height: 100svh;
    padding: var(--work-top) var(--work-edge) 0;
  }
  html.motion-ready .work-item__inner {
    height: 100%;
    grid-template-rows: minmax(0, 1fr);
  }
  html.motion-ready .work-item__text { align-self: center; margin-top: -2vh; }
  html.motion-ready .work-item__index { display: none; }
  html.motion-ready .work-item__stage {
    --screen-top: calc(50% - 4vh - var(--bh) / 2);
    align-self: stretch;
    height: auto;
  }
  /* The end card fills the last screen on its own, so the room closes on a clean frame: the
     last project has fully left before the pin lets go. */
  html.motion-ready .work__end {
    position: relative;
    flex: 0 0 100vw;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: var(--work-top) var(--work-edge) 0;
    text-align: center;
  }
  html.motion-ready .work__end::before {
    content: '';
    position: absolute;
    z-index: 0;
    left: 50%;
    top: calc(50% + var(--work-top) / 2);
    width: min(1100px, 80vw);
    height: min(760px, 90svh);
    transform: translate(-50%, -50%);
    background: radial-gradient(closest-side, color-mix(in srgb, var(--lime) 9%, transparent) 20%, color-mix(in srgb, var(--lime) 3%, transparent) 62%, transparent);
    pointer-events: none;
  }
  html.motion-ready .work__end-inner { position: relative; z-index: 1; }
  html.motion-ready .work__end-title { margin-inline: auto; }
  html.motion-ready .work__end-calls { justify-content: center; }

  html.motion-ready .work__counter {
    position: absolute;
    z-index: 5;
    top: calc(var(--work-top) + 22px);
    right: var(--work-edge);
    display: flex;
    align-items: flex-start;
    gap: 14px;
    pointer-events: none;
  }
  /* Hidden until the room is dark and the first spread slides in (work.js fades it up). */
  html.motion-ready .work__counter > * { visibility: hidden; opacity: 0; }
  html.motion-ready .work__counter-label { margin-top: .35em; }
  /* The split-flap card: a real tile, a step up from the night ground with a hairline edge, so it
     reads as a deliberate object over the dark room and over a light spill alike. */
  html.motion-ready .work .work__flip {
    --flip-bg: var(--night-2);
    border-radius: 5px;
    color: var(--paper);
    box-shadow: 0 0 0 1px rgba(238, 237, 232, .1), 0 10px 24px -12px rgba(0, 0, 0, .6);
  }
  html.motion-ready .work .work__flip .flip__sizer { padding: 0 .14em; }
  html.motion-ready .work .work__flip .flip__top,
  html.motion-ready .work .work__flip .flip__leaf--top { border-radius: 5px 5px 0 0; }
  html.motion-ready .work .work__flip .flip__bottom,
  html.motion-ready .work .work__flip .flip__leaf--bottom { border-radius: 0 0 5px 5px; }
  html.motion-ready .work .work__flip::after { border-top-color: #000; opacity: .55; }
  html.motion-ready .work__count {
    display: flex;
    align-items: baseline;
    gap: .3em;
  }
  html.motion-ready .work__of {
    font-family: var(--f-display);
    font-weight: 800;
    font-stretch: 75%;
    font-size: calc(var(--fs-counter) * .42);
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
    color: var(--fg-soft);
  }

  html.motion-ready .work__progress {
    position: absolute;
    z-index: 5;
    left: var(--work-edge);
    right: var(--work-edge);
    bottom: 28px;
    display: block;
    height: 1px;
    background: color-mix(in srgb, var(--mist) 38%, transparent);
  }
  html.motion-ready .work__progress-fill {
    position: absolute;
    inset: -1px 0 0;
    height: 2px;
    background: var(--lime);
    transform: scaleX(0);
    transform-origin: 0 50%;
  }
}

/* Phones and tablets with motion: frames wait off stage until Dock brings them in. */
@media (max-width: 1023px) {
  html.motion-ready .work [data-work-dock] { opacity: 0; }
}
