.Clients__section {
  position: relative;
  display: grid;
  align-content: center;
  gap: clamp(2rem, 6vh, 4rem);
  min-height: 100vh;
  padding: clamp(4rem, 12vh, 10rem) clamp(2rem, 6vw, 7rem);
  overflow: hidden;
  isolation: isolate;

  opacity: 0.5;
  filter: saturate(0.25);
  transition:
    opacity var(--dur) var(--ease),
    filter var(--dur) var(--ease);
}

.Clients__section.Clients__resolved {
  opacity: 1;
  filter: saturate(1);
}

@media (min-width: 1024px) and (hover: hover) {
  .Clients__section {
    filter: saturate(0.25) blur(4px);
  }

  .Clients__section.Clients__resolved {
    filter: saturate(1) blur(0px);
  }
}

.Clients__heading {
  white-space: pre-line;
  color: var(--fg);
}

/**
 * Column flow, not row flow. Left to right would number the first line 01, 02
 * and the second 03, 04, so reading down a column gives every other client.
 * --rows comes from the component so the CSS is not coupled to the list length.
 */
.Clients__list {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(var(--rows), auto);
  column-gap: clamp(2rem, 6vw, 6rem);
}

/**
 * A call-sheet row: slate number, name, sector. The name carries credit size so
 * it can actually be read; the number and sector stay meta and recede, so the
 * hierarchy is carried by size and colour together.
 */
.Clients__row {
  position: relative;
  display: grid;
  grid-template-columns: 2.5rem 1fr auto;
  align-items: baseline;
  gap: 1rem;
  padding: 0.95rem 0;

  /** The entrance from CLAUDE.md: 24px rise, 60ms apart. */
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease);
  transition-delay: var(--delay, 0ms);
}

/**
 * The rule under each row is drawn, not faded — it wipes left to right as the
 * row lands, so the list assembles itself the way a call sheet gets ruled up
 * rather than simply appearing. scaleX on a pseudo-element, so it costs a
 * transform and nothing else.
 *
 * It inherits --delay from the row: transition-delay would not reach here.
 */
.Clients__row::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 1px;
  background: var(--grey-1);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-slow) var(--ease);
  transition-delay: var(--delay, 0ms);
}

/**
 * One flag on the list drives all 24 rows; per-row timing comes from the inline
 * transition-delay the component writes.
 *
 * It is React state rather than an imperative DOM write, because imperative
 * class and attribute changes on React-rendered nodes were being lost to
 * reconciliation here. It flips once, so it costs a single render.
 */
.Clients__list[data-entered] .Clients__row {
  opacity: 1;
  transform: none;
}

.Clients__list[data-entered] .Clients__row::after {
  transform: scaleX(1);
}

/* Hovering one row pushes the rest back, same behaviour as the stills grid so
   the two sections feel like one system. Pure CSS, nothing per-frame. It has to
   outrank the entrance rule above, so it carries the same specificity. */
.Clients__list[data-entered]:hover .Clients__row:not(:hover) {
  opacity: 0.35;
}

/**
 * Desktop only, per CLAUDE.md: each row resolves out of soft focus as it lands,
 * which is the same move the sections make. One-shot transition on 24 short
 * rows, not a scroll-driven filter — that is the version that costs frames.
 */
@media (min-width: 1024px) and (hover: hover) {
  .Clients__row {
    filter: blur(5px);
    transition:
      opacity var(--dur) var(--ease),
      transform var(--dur) var(--ease),
      filter var(--dur) var(--ease);
    transition-delay: var(--delay, 0ms);
  }

  .Clients__list[data-entered] .Clients__row {
    filter: blur(0px);
  }
}

.Clients__index {
  color: var(--grey-2);
}

/* Colour and size come from .credit; this only holds it off the baseline grid's
   default wrapping when a name runs long. */
.Clients__name {
  text-wrap: balance;
}

.Clients__sector {
  text-align: right;
}

.Clients__count {
  justify-self: start;
}

@media (max-width: 720px) {
  .Clients__list {
    grid-auto-flow: row;
    grid-template-rows: none;
    grid-template-columns: 1fr;
  }

  .Clients__row {
    grid-template-columns: 2rem 1fr;
  }

  /* The sector would crush the name at this width; drop it to its own line. */
  .Clients__sector {
    grid-column: 2;
    text-align: left;
  }
}

@media (prefers-reduced-motion: reduce) {
  .Clients__section,
  .Clients__section.Clients__resolved {
    filter: none;
  }

  .Clients__section {
    transition: opacity var(--dur) var(--ease);
  }

  /* No staged rise, no focus pull, no drawn rule; the list simply reads. */
  .Clients__row {
    opacity: 1;
    filter: none;
    transform: none;
  }

  .Clients__row::after {
    transform: scaleX(1);
    transition: none;
  }
}
