/* Filters are centred at the client's request ("make the nav bar inside the
   work section in the middle") and no longer carry an "All" entry. */
/* A rule above and below, with equal padding on both sides, so the row of
   categories sits centred in its own band rather than hanging off a single
   line. The client asked for it "in the middle of 2 lines". */
.filters {
  display: flex; flex-wrap: wrap; gap: var(--space-6);
  justify-content: center; align-items: center;
  margin-block: var(--space-8);
  padding-block: var(--space-4);
  border-block: 1px solid var(--hairline);
  font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase;
}
.filters a { color: var(--neutral); }
.filters a:hover { color: var(--ink); }
.filters a[aria-current="page"] {
  color: var(--ink);
  box-shadow: 0 2px 0 var(--rose);
}
[dir="rtl"] .filters { letter-spacing: 0; text-transform: none; font-size: 0.9375rem; }

/* The four service families, folded in from the Services page. */
.offer {
  display: grid; gap: var(--space-12);
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  margin-block: var(--space-12);
}
.offer article { border-block-start: 1px solid var(--hairline); padding-block-start: var(--space-6); }
/* Two lines' worth of room for every heading, so the paragraphs below them
   start on the same line across the row. A floor, not a fixed height: at
   narrower widths "Built to bring the idea to life." takes two lines while
   "Made personal." takes one, and without this its paragraph sat a line
   lower than its neighbours'. */
.offer h3 {
  margin-block: var(--space-2) var(--space-3);
  min-block-size: calc(2em * 1.06);
}
/* Four families in a three-column row leave the fourth alone at the start
   of the second row; the client asked for it centred. The wrap caps at
   78rem, which with a 20rem minimum and a 3rem gap tops out at three
   columns, so 72rem is exactly where the third column - and the orphan -
   appears. Below it the four sit two-by-two and nothing is orphaned. */
@media (min-width: 72rem) {
  .offer article:nth-child(4) { grid-column: 2; }
}

/* The portfolio grid: three equal 4/3 tiles per row on desktop, two on
   tablet, one on a phone - every image the same size, cropped by the frame,
   never stretched. Row gaps run larger than column gaps so the page scrolls
   in breaths rather than as a wall. */
.work-index {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--space-12) var(--space-6);
}

/* Set by the server for the no-JS view and toggled by work-filter.js for the
   no-reload one, so both routes hide a project the same way. */
.work-index__item.is-filtered-out { display: none; }

/* Cards drift up as they enter, one small beat after their row neighbour -
   the delay is set per tile in the template. Composes with the global
   .reveal fade; reduced motion gets base.css's no-transform treatment. */
.js .work-index__item.reveal.is-visible {
  transition-delay: var(--reveal-delay, 0ms);
}

.filters__empty { text-align: center; color: var(--neutral); }
/* Title and meta are captions under the tile, so they centre with it.
   The title, not the image, is the way into the project page. */
.work-index__title {
  margin-block: var(--space-4) var(--space-1); font-size: 1.375rem;
  text-align: center;
}
.work-index__title a { color: inherit; }
.work-index__title a:hover { color: var(--rose-deep); }
.work-index .meta { text-align: center; }

/* The frame clips the image so it can scale inside it without pushing the
   grid around, and anchors the veil. */
.work-index__frame {
  display: block; position: relative; overflow: hidden;
  background: var(--off-white);
  transition: transform 200ms var(--ease);
}
.work-index__item img {
  aspect-ratio: 4 / 3; object-fit: cover; width: 100%; display: block;
  transition: transform 600ms var(--ease);
}
/* The veil floats over the lightbox trigger, so it must not eat the click. */
.work-index__veil {
  position: absolute; inset: 0; pointer-events: none;
  display: flex; flex-direction: column; gap: var(--space-2);
  align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--navy) 55%, transparent);
  opacity: 0; transition: opacity 400ms var(--ease);
}
.work-index__veil-name {
  color: var(--warm-white); font-family: var(--font-heading);
  font-size: 1.25rem;
  transform: translateY(0.5rem); transition: transform 400ms var(--ease);
}
.work-index__cue {
  color: var(--rose-light);
  font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase;
  transform: translateY(0.5rem); transition: transform 400ms var(--ease);
}
[dir="rtl"] .work-index__cue { letter-spacing: 0; text-transform: none; font-size: 0.875rem; }

/* Hover and keyboard focus get the same treatment, so the tile is not a
   mouse-only affordance - the trigger button lives inside the frame, so
   :focus-within covers it. :active is the small step back under the finger. */
.work-index__frame:hover .work-index__veil,
.work-index__frame:focus-within .work-index__veil { opacity: 1; }
.work-index__frame:hover :is(.work-index__cue, .work-index__veil-name),
.work-index__frame:focus-within :is(.work-index__cue, .work-index__veil-name) { transform: translateY(0); }
.work-index__frame:hover img,
.work-index__frame:focus-within img { transform: scale(1.05); }
.work-index__frame:active { transform: scale(0.985); }

@media (prefers-reduced-motion: reduce) {
  .work-index__item img,
  .work-index__veil,
  .work-index__veil-name,
  .work-index__cue,
  .work-index__frame { transition: none; }
  .work-index__frame:hover img,
  .work-index__frame:focus-within img { transform: none; }
  .work-index__frame:active { transform: none; }
}

@media (max-width: 64rem) {
  .work-index { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 40rem) {
  .work-index { grid-template-columns: 1fr; gap: var(--space-8); }
}

/* Centred prose, per the client. */
.offer article :is(p, h3) { text-align: center; }
