/* ==========================================================================
   Services (after Mondragon; copy and illustrations from spinta.co.uk)
   A staggered list of white rows, each a button: the title, its tags and a
   +. Every row sits on one of three lines (the left edge, the centre, the
   right edge), in two left-to-right sweeps, so the stagger reads as meant.
   The motion, in order:
   - In view: each row unrolls from the line it sits on (left rows from the
     left, right rows from the right, centre rows from the middle), its title
     drifting in with it.
   - Hover: an ink line draws along the row's foot from the side the pointer
     came in (and runs back out the side it leaves), the + turns a quarter,
     and the illustration slides out beside the row (services.js).
   - Open: the row slides and stretches to the full width, ink rises from the
     line to fill it (the type inverting as it passes), the panel unfolds,
     then its page follows in a cascade: the hairline draws, the words rise
     out of their masks, the picture unveils upward and the button lifts in.
   - Close: the same in reverse, quicker, with no cascade.
   One row is open at a time; all start closed. Every state is a CSS
   transition, so a change of mind half way reverses smoothly.
   ========================================================================== */

.services {
  position: relative;
  z-index: 1;
  padding: clamp(96px, 15vh, 176px) var(--gutter) clamp(96px, 16vh, 180px);
  background: var(--bone);
}

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

.services > * {
  position: relative;
}

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

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

.services__label {
  font-size: var(--fs-micro);
  font-weight: 400;
}

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

.services__intro {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 28px 48px;
  margin-top: clamp(28px, 4.5vh, 48px);
}

.services__lede {
  max-width: 26ch;
  font-size: clamp(1.375rem, 2.1vw, 2.25rem);
  font-weight: 400;
  line-height: 1.22;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

/* ------------------------------------------------------------------ list */

.services__list {
  display: grid;
  gap: 10px;
  margin: clamp(48px, 8vh, 96px) 0 0;
  padding: 0;
  list-style: none;
  overflow-anchor: none; /* services.js holds the pressed row still itself */
}

/* Each heading is a row: the white block sits at its own point along the
   free width (--s, 0 = left edge, 1 = right edge), set by two flexible
   spacers either side of it. Open, the spacers close and the block grows to
   the full width, all on transitions, so it slides and stretches smoothly
   (and reverses smoothly if it's closed half way). Closing runs quicker
   than opening, as exits should. */
.svc__heading {
  display: flex;
  margin: 0;
  font: inherit;
}

.svc__heading::before,
.svc__heading::after {
  content: "";
  transition: flex-grow 560ms var(--ease-drawer);
}

.svc__heading::before {
  flex: var(--s, 0) 1 0;
}

.svc__heading::after {
  flex: calc(1 - var(--s, 0)) 1 0;
}

.svc__head {
  position: relative;
  isolation: isolate;
  flex: 0 1 auto;
  display: flex;
  align-items: center;
  gap: clamp(16px, 1.7vw, 30px);
  min-width: 0;
  padding: clamp(14px, 1.45vw, 22px) clamp(18px, 1.8vw, 30px);
  text-align: left;
  background: var(--white);
  transition: flex-grow 560ms var(--ease-drawer);
  -webkit-tap-highlight-color: transparent;
}

/* The hover line along the foot, and the ink that fills the block when it
   opens (rising from that line). Both behind the type, inside the block. */
.svc__head::before,
.svc__head::after {
  content: "";
  position: absolute;
  z-index: -1;
  left: 0;
  right: 0;
  background: var(--ink);
}

/* Draws from the side the pointer came in (--line-from, services.js). */
.svc__head::before {
  bottom: 0;
  height: 3px;
  transform: scaleX(0);
  transform-origin: var(--line-from, 0%) 50%;
  transition: transform 600ms var(--ease-out);
}

.svc__head::after {
  top: 0;
  bottom: 0;
  transform: scaleY(0);
  transform-origin: 50% 100%;
  transition: transform 420ms var(--ease-drawer);
}

/* White type on a difference blend: ink on the white block, white where the
   ink has filled it, flipping exactly at the ink's edge as it rises. */
.svc__title,
.svc__tags,
.svc__plus {
  color: #fff;
  mix-blend-mode: difference;
}

.svc__title {
  font-size: clamp(1.625rem, 3.05vw, 3.75rem);
  font-stretch: 112.5%;
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.012em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* One tag a line, never wrapped: every row's tags are the same three-line
   block, so no word splits and no line starts with a stray comma. */
.svc__tags {
  line-height: 1.45;
  white-space: nowrap;
  opacity: 0.62;
}

/* Tags sit on the side with room: before the title on rows pushed right. */
.svc[data-side="start"] .svc__tags {
  order: -1;
  text-align: right;
}

.svc__plus {
  position: relative;
  flex: none;
  width: 22px;
  height: 22px;
  margin-left: auto;
  transition: rotate 450ms var(--ease-out);
}

.svc__plus::before,
.svc__plus::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1.5px;
  margin-top: -0.75px;
  background: currentColor;
}

.svc__plus::after {
  rotate: 90deg;
}

@media (hover: hover) and (pointer: fine) {
  .svc__head:hover::before {
    transform: scaleX(1);
  }

  /* A quarter turn lands back on a +: a tick that says "this opens". */
  .svc:not(.is-open) .svc__head:hover .svc__plus {
    rotate: 90deg;
  }
}

/* The ring sits inside the block, in the block's own contrast colour, and
   only for the keyboard: a press with the pointer (.is-pressed) shows none. */
.svc__head:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: -8px;
  border-radius: 0;
}

.svc.is-open .svc__head:focus-visible {
  outline-color: var(--bone);
}

.svc__head.is-pressed:focus-visible {
  outline: none;
}

/* ------------------------------------------------------------------ open */

.svc.is-open .svc__heading::before,
.svc.is-open .svc__heading::after {
  flex-grow: 0;
  transition-duration: 720ms;
}

.svc.is-open .svc__head {
  flex-grow: 1;
  transition-duration: 720ms;
}

.svc.is-open .svc__head::before {
  transform: scaleX(1);
}

.svc.is-open .svc__head::after {
  transform: scaleY(1);
  transition-duration: 640ms;
}

/* The + turns to an x with a little overshoot, and settles. */
.svc.is-open .svc__plus {
  rotate: 45deg;
  transition: rotate 700ms cubic-bezier(0.34, 1.45, 0.5, 1);
}

/* The panel unfolds to its own height (grid rows 0fr -> 1fr: no measuring). */
.svc__panel {
  display: grid;
  grid-template-rows: 0fr;
  color: var(--bone);
  background: var(--ink);
  transition: grid-template-rows 520ms var(--ease-drawer);
}

.svc.is-open .svc__panel {
  grid-template-rows: 1fr;
  transition-duration: 720ms;
}

.svc__inner {
  min-height: 0;
  overflow: hidden;
}

/* The words on the left, the scene across the rest of the width: a
   panorama (880x300), so it fills the row without making the open panel
   much taller (about a third of a screen). */
.svc__content {
  display: grid;
  grid-template-columns: minmax(240px, 1fr) minmax(0, 2.1fr);
  align-items: stretch;
  gap: clamp(14px, 1.6vw, 24px) clamp(24px, 4vw, 80px);
  padding: 0 clamp(18px, 1.8vw, 30px) clamp(18px, 1.8vw, 26px);
  opacity: 0;
  transition: opacity 180ms ease;
}

.svc.is-open .svc__content {
  opacity: 1;
  transition: opacity 300ms ease 140ms;
}

/* A hairline under the head, inset like the type, so the open row reads as a
   head and its page rather than one slab of ink. It draws left to right. */
.svc__content::before {
  content: "";
  grid-column: 1 / -1;
  height: 1px;
  background: rgb(247 245 242 / 0.16);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 200ms ease;
}

.svc.is-open .svc__content::before {
  transform: none;
  transition: transform 1000ms var(--ease-out) 160ms;
}

/* The words under the title, the button level with the foot of the picture. */
.svc__body {
  display: grid;
  align-content: space-between;
  justify-items: start;
  gap: clamp(18px, 2vw, 28px);
  padding: 0 0 2px;
}

.svc__text {
  max-width: 36ch;
  font-size: clamp(1.0625rem, 1.25vw, 1.4375rem);
  line-height: 1.34;
  letter-spacing: -0.015em;
  text-wrap: pretty;
}

/* Each word rises out of its own mask as the panel opens, one after another
   (services.js splits them, --w is the word's place; the sentence stays
   whole for assistive tech). The padding gives descenders room. */
.svc__w {
  display: inline-block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
  vertical-align: top;
}

.svc__w > span {
  display: inline-block;
  translate: 0 110%;
  transition: translate 200ms ease;
}

.svc.is-open .svc__w > span {
  translate: none;
  transition: translate 900ms var(--ease-out) calc(220ms + var(--w, 0) * 12ms);
}

.svc__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 48px;
  padding: 0 22px 0 24px;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink);
  background: var(--bone);
  border-radius: 999px;
  opacity: 0;
  translate: 0 14px;
  transition:
    background-color 300ms ease,
    scale 240ms var(--ease-out),
    opacity 160ms ease,
    translate 200ms ease;
}

/* It lifts in last, once the words have landed. */
.svc.is-open .svc__cta {
  opacity: 1;
  translate: none;
  transition:
    background-color 300ms ease,
    scale 240ms var(--ease-out),
    opacity 500ms ease 480ms,
    translate 900ms var(--ease-out) 480ms;
}

.svc__cta svg {
  width: 15px;
  height: 15px;
  transition: rotate 420ms var(--ease-out);
}

.svc__cta:active {
  scale: 0.97;
}

.svc__cta:focus-visible {
  outline-color: var(--bone);
  border-radius: 999px;
}

@media (hover: hover) and (pointer: fine) {
  .svc__cta:hover {
    background: var(--white);
  }

  /* Like "Work with us": it opens the form where you are. */
  .svc__cta:hover svg {
    rotate: 45deg;
  }
}

/* The service's scene, drawn on the ink itself (no paper card): a dot grid
   fading to the edges, a glow breathing behind the hero, the pieces wired
   together, a scrubber running along the foot with the 8s story
   (tools/service-art/scenes.py, -panel.svg). As the panel opens it wipes in
   left to right, the way the story reads, while the picture settles from a
   slight lean-in; services.js restarts the story at that moment, so it
   always plays from its first beat. Narrow screens get the same scene in
   its compact shape (-ink.svg). */
.svc__art {
  align-self: center;
  justify-self: end;
  width: 100%;
  max-width: 1000px;
  margin: 0;
  clip-path: inset(0 100% 0 0);
  transition: clip-path 220ms ease;
}

.svc.is-open .svc__art {
  clip-path: inset(0 0 0 0);
  transition: clip-path 1400ms var(--ease-out) 200ms;
}

.svc__art picture {
  display: block;
}

.svc__art img {
  display: block;
  width: 100%;
  height: auto;
  opacity: 0;
  scale: 1.05;
  transform-origin: 30% 50%;
  transition:
    opacity 200ms ease,
    scale 220ms ease;
}

.svc.is-open .svc__art img {
  opacity: 1;
  scale: 1;
  transition:
    opacity 700ms ease 200ms,
    scale 1700ms var(--ease-out) 200ms;
}

/* ------------------------------------------------------------------ preview */

/* Shows beside a closed row, on the side its tags face, level with the
   pointer; it keeps clear of the rows above and below, shrinking to fit
   when both reach across, so it never covers the words. It slides out from
   the row and glides from row to row (services.js; desktop only). GSAP owns
   the transforms, so nothing here uses translate or scale. The box places
   and fits it; the card inside fades, grows and leans. */
.svc-peek {
  position: fixed;
  top: 0;
  left: 0;
  z-index: calc(var(--z-header) - 1);
  width: clamp(190px, 13vw, 250px);
  aspect-ratio: 420 / 340;
  pointer-events: none;
  will-change: transform;
}

.svc-peek__card {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #f4f2ef;
  border-radius: 12px;
  box-shadow: var(--shadow-lift-up);
  opacity: 0;
  will-change: transform, opacity;
}

.svc-peek__card img {
  width: 100%;
  height: 100%;
}

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

/* The first time the list comes into view (services.js arms it, so without
   the script nothing is hidden): each row fades up and unrolls from the
   line it sits on (--s: 0 from the left, 1 from the right, 0.5 from the
   middle), its title drifting in the same way, one row after another. */
.services.is-armed .svc {
  opacity: 0;
  translate: 0 14px;
}

.services.is-armed .svc__head {
  clip-path: inset(0 calc((1 - var(--s, 0)) * 100%) 0 calc(var(--s, 0) * 100%));
}

.services.is-armed .svc__title {
  translate: calc((var(--s, 0) - 0.5) * 80px) 0;
}

.services.is-in .svc {
  opacity: 1;
  translate: none;
  transition:
    opacity 600ms ease,
    translate 1000ms var(--ease-out);
  transition-delay: calc(var(--i, 0) * 90ms);
}

.services.is-in .svc__head {
  clip-path: inset(0);
  transition:
    flex-grow 560ms var(--ease-drawer),
    clip-path 1100ms var(--ease-out) calc(var(--i, 0) * 90ms);
}

.services.is-in .svc.is-open .svc__head {
  transition:
    flex-grow 720ms var(--ease-drawer),
    clip-path 1100ms var(--ease-out);
}

.services.is-in .svc__title {
  translate: none;
  transition: translate 1300ms var(--ease-out) calc(var(--i, 0) * 90ms);
}

/* Without JS: every panel open, nothing to toggle, nothing hidden. */
.no-js .svc__panel {
  grid-template-rows: 1fr;
}

/* The panel's second way on: the service's own page, beside the button,
   lifting in just after it. */
.svc__acts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 24px;
}

.svc__more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  color: var(--on-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  opacity: 0;
  translate: 0 14px;
  transition:
    opacity 160ms ease,
    translate 200ms ease;
}

.svc.is-open .svc__more {
  opacity: 1;
  translate: none;
  transition:
    opacity 500ms ease 560ms,
    translate 900ms var(--ease-out) 560ms;
}

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

@media (hover: hover) and (pointer: fine) {
  .svc__more:hover svg {
    translate: 3px 0;
  }
}

.no-js .svc__content,
.no-js .svc__content::before,
.no-js .svc__art,
.no-js .svc__art img,
.no-js .svc__cta,
.no-js .svc__more {
  opacity: 1;
  transform: none;
  translate: none;
  scale: none;
  clip-path: none;
}

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

/* Narrow screens: the title wraps above its tags, the + on the right; the
   panel stacks its picture under the words. The desktop's stagger is kept:
   every row a little narrower than the list, sitting on its own line (left,
   centre, right); open, it still slides and stretches to the full width. */
@media (max-width: 899px) {
  .svc__head {
    flex: 0 0 auto;
    width: 86%;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "title plus"
      "tags plus";
    align-items: center;
    row-gap: 10px;
  }

  .svc__title {
    grid-area: title;
    white-space: normal;
  }

  /* One line under the title here: the tags run on as a list. */
  .svc__tags,
  .svc[data-side="start"] .svc__tags {
    grid-area: tags;
    order: 0;
    white-space: normal;
    text-align: left;
  }

  .svc__tags br {
    display: none;
  }

  .svc__plus {
    grid-area: plus;
    margin-left: 0;
  }

  .svc__content {
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
  }

  .svc__art {
    justify-self: start;
    max-width: 420px;
  }
}

/* Every state change lands at once (the open-state rules set their own
   durations, so this has to outrank them). */
@media (prefers-reduced-motion: reduce) {
  .services *,
  .services *::before,
  .services *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
}

/* Phones: the site's section rhythm (--sec-top / --sec-bot / --sec-end, tokens.css),
   so every gap between two sections reads the same. */
@media (max-width: 719px) {
  .services {
    padding-top: var(--sec-top);
    padding-bottom: var(--sec-bot);
  }
}
