/* ---- category menu ------------------------------------------------------
   Vanilla port of the ReactBits FlowingMenu, re-skinned.

   The mechanism is unchanged from the original: on hover a marquee strip
   slides in from whichever edge the cursor crossed, carrying that
   category's own photography. What changed is register. The original is a
   bold uppercase display band; here the rows are set in the page serif at a tight
   negative track, sentence case, with the marquee filling in bone rather
   than in the accent, so the reveal reads as a plate being pulled rather
   than as a highlighter sweeping across.

   This is the page's only marquee.
   ------------------------------------------------------------------------ */

.cats { border-bottom: 1px solid var(--line-soft); }

.cats__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  padding-block: clamp(56px, 7vw, 96px) clamp(28px, 3vw, 44px);
}
.cats__title {
  font-size: var(--fs-h2);
  max-width: 16ch;
}
.cats__note {
  font-size: var(--fs-sm);
  color: var(--bone-dim);
  max-width: 24ch;
  text-align: right;
}

.fm { width: 100%; }
.fm__list { display: flex; flex-direction: column; }

.fm__item {
  position: relative;
  overflow: hidden;
  border-top: 1px solid var(--line-soft);
}

.fm__link {
  position: relative;
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(12px, 2vw, 28px);
  padding: clamp(18px, 2.4vw, 30px) var(--gut);
  transition: color var(--dur-1) var(--ease);
}

.fm__idx {
  font-family: var(--mono);
  font-size: var(--fs-micro);
  color: var(--bone-dim);
  letter-spacing: var(--track-micro);
}

.fm__name {
  font-size: clamp(1.75rem, 1rem + 3.4vw, 4.25rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--track-tight);
  padding-bottom: 0.05em;
}

.fm__meta {
  font-size: var(--fs-xs);
  color: var(--bone-dim);
  text-align: right;
  max-width: 22ch;
  line-height: 1.4;
}

/* The strip. Parked below the row until a pointer crosses an edge. */
.fm__marquee {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  background: var(--bone);
  transform: translate3d(0, 101%, 0);
  will-change: transform;
}
/* Width comes from the content, never from a percentage of the row.
   The earlier version pinned each copy to 50% of a 200%-wide strip, so a copy
   was always exactly one row wide whatever it held: a category with three
   cells overflowed that box and the next copy painted on top of it, while a
   category with two cells left a long empty stretch before the next copy
   began. max-content lets each copy be as wide as it actually is, and
   menu.js then clones it enough times to cover the row and scrolls by exactly
   one copy, so the loop is seamless at any cell count. */
.fm__inner {
  display: flex;
  width: max-content;
  height: 100%;
  will-change: transform;
}
.fm__unit {
  flex: none;
  height: 100%;
  display: flex;
  align-items: center;
}
.fm__cell {
  display: flex;
  align-items: center;
  gap: clamp(14px, 1.8vw, 30px);
  padding: 0 clamp(14px, 1.8vw, 30px);
  flex: none;
}
.fm__word {
  white-space: nowrap;
  font-size: clamp(1.75rem, 1rem + 3.4vw, 4.25rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--track-tight);
  color: var(--void);
}
.fm__shot {
  width: clamp(96px, 11vw, 168px);
  aspect-ratio: 4 / 3;
  flex: none;
  background-color: var(--raise-2);
  background-size: cover;
  background-position: center;
}

/* A category with no photography supplied yet runs as a text band. Without
   the images between them the words sit too close, so the cells carry the
   spacing the pictures would otherwise have provided. */
.fm__marquee--text .fm__cell { padding-inline: clamp(28px, 4vw, 64px); }

/* Until menu.js has measured and cloned, only the first copy exists and it
   may be narrower than the row. The strip is parked off-screen at that point
   so nothing shows, but keeping the ground opaque means no seam can flash on
   the first hover if measurement and reveal land on the same frame. */
.fm__marquee { background: var(--bone); }

@media (prefers-reduced-motion: reduce) {
  .fm__inner { transform: none !important; }
}

/* Coarse pointers never fire the marquee, so the rows carry themselves:
   the trailing description is dropped and the name does the work. */
@media (max-width: 860px) {
  .cats__head { flex-direction: column; align-items: flex-start; gap: 14px; }
  .cats__note { text-align: left; }
  .fm__link { grid-template-columns: 2.5rem minmax(0, 1fr); }
  .fm__meta { display: none; }
}
