/* ==========================================================================
   Block: gallery-grid — the Photo Gallery page (src/blocks/gallery-grid.html)
   Figma "Photo Gallery" 5058:12 at 1920 (page y; the content starts at 114 under the fixed header):
     sidebar x100, 270 wide; title "Gallery" y195 (48px Blauer Nue Regular, 59 box) → 81 under the content top
     filters 20px Blauer Nue Medium, title case; 1px white 270px rules: Overview text 278 (green, x114) / rule 315,
             Hospitality 329 / 366, then text 10 under each rule on a 43px pitch (…624), the last pitch 45 (669)
     grid    x398→1820 (1422), top 201; justified rows ≈390 tall, 16px apart; row tops 201 610 1022 1431 1840 2249
             → rows 19 apart (the computed rows are 390.0 / 391.7 tall and land within ±1.5 of every Figma top)
   Section padding: top 81 (above); bottom: grid bottom 2642 → closing-CTA title 2903 = 261, and the service
   closing CTA keeps 175 above its title → 86.
   ========================================================================== */

.block-gallery-grid {
  --gg-side: 270px;
  --gg-gap-x: 16px;
  --gg-gap-y: 19px;
  --gg-row-k: 0.27426;                  /* target row height ÷ grid width: 390 / 1422 */
  --gg-row-max: 390;                    /* px cap (a plain number: js/blocks/gallery-grid.js reads both) */
  --gg-pad-top: min(4.22vw, 81px);
  padding: var(--gg-pad-top) 0 min(4.48vw, 86px);
}

.block-gallery-grid__layout {
  display: grid;
  grid-template-columns: var(--gg-side) minmax(0, 1fr);
  column-gap: 28px;                     /* 370 → 398 */
  align-items: start;
}

/* ---- Sidebar: title + filter list; stays put while the grid scrolls ---------------
   Native scrolling (reduced motion / no JS): sticky at its own starting offset, so it never moves until the
   grid runs out. Under ScrollSmoother the script pins it with ScrollTrigger instead (.is-pinned-js). */
.block-gallery-grid__side {
  position: sticky;
  top: calc(var(--nav-h) + var(--gg-pad-top));
  min-width: 0;
}
.block-gallery-grid__side.is-pinned-js { position: relative; top: auto; }
.block-gallery-grid__title {
  margin-left: 1px;                     /* x101 */
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 48px;
  line-height: 1.23;                    /* 59px box */
}
.block-gallery-grid__filter-item { border-bottom: 1px solid var(--fg); }
.block-gallery-grid__filter {
  display: block;
  padding: 9.5px 0 13.5px;              /* text 10 under the rule above, 43px rule pitch (19px line) */
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 20px;
  line-height: .95;
  text-transform: capitalize;
  transition: color .3s ease, padding-left .35s cubic-bezier(.22, .61, .36, 1);
}
/* Figma spacing by position (order-dependent nudges, safe to drop on the CMS): the Overview row sits 24 under
   the title and 18 over its rule; the first term row is 51 tall; the last is 45. */
.block-gallery-grid__filter-item:first-child .block-gallery-grid__filter { padding: 24px 0 17.5px; }
.block-gallery-grid__filter-item:nth-child(2) .block-gallery-grid__filter { padding: 13.5px 0 17.5px; }
.block-gallery-grid__filter-item:last-child .block-gallery-grid__filter { padding-top: 11.5px; }
.block-gallery-grid__filter:hover { color: var(--accent); }
.block-gallery-grid__filter-item:nth-child(n) .block-gallery-grid__filter.is-active { color: var(--accent); padding-left: 13px; }   /* x114 (beats the nudges' padding shorthand) */
.block-gallery-grid__filter-item[hidden] { display: none; }

/* ---- Grid: justified rows --------------------------------------------------------
   Every photo keeps its own proportions (client change #43 — the photos are the full frames, not the Figma's
   crops). No JS (and before the script runs): plain equal-height rows, each photo at its natural width for
   the row height, left-aligned with a ragged right edge — never grown or cropped. With JS (.is-justified)
   every item gets its exact width / height from its aspect ratio, so the rows fill the grid uncropped. */
.block-gallery-grid__main { min-width: 0; margin-top: min(.31vw, 6px); }   /* grid top 201 = title top + 6 */
.block-gallery-grid__grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gg-gap-y) var(--gg-gap-x);
  transition: opacity .28s ease;        /* = js/shared/photo-filter.js SWAP_MS */
}
.block-gallery-grid__grid::after { content: ""; flex: 999 1 0; }
.block-gallery-grid__grid.is-swapping { opacity: 0; }
.block-gallery-grid__item {
  flex: 0 1 auto;
  max-width: 100%;
  height: min(20.3vw, 390px);
  overflow: hidden;
  background: #161616;                  /* while the lazy photo loads */
}
.block-gallery-grid__item[hidden] { display: none; }
.block-gallery-grid__photo {
  width: auto;                          /* no JS: as wide as the row height allows (width/height attributes) */
  height: 100%;
  object-fit: cover;                    /* only ever trims a sub-pixel: every box has the photo's own ratio */
}
.block-gallery-grid__grid.is-justified .block-gallery-grid__photo { width: 100%; }
.block-gallery-grid__grid.is-justified::after { display: none; }
.block-gallery-grid__grid.is-justified .block-gallery-grid__item { flex: 0 0 auto; }
.block-gallery-grid__grid.is-justified .block-gallery-grid__item.is-row-end { flex-grow: 1; }   /* absorbs sub-pixel rounding */

/* Soft fade-in as each photo scrolls into view (and has loaded) — no movement. The script adds .is-live
   (never under reduced motion) and .is-in per photo; --gg-delay staggers photos that arrive together. */
.block-gallery-grid.is-live .block-gallery-grid__item {
  opacity: 0;
  background: transparent;
  transition: opacity .9s ease var(--gg-delay, 0ms);
}
.block-gallery-grid.is-live .block-gallery-grid__item.is-in { opacity: 1; }

/* ---- Load more / empty ------------------------------------------------------------ */
.block-gallery-grid__more { display: flex; justify-content: center; }
.block-gallery-grid__more-btn {
  display: inline-flex;
  align-items: center;
  height: 46px;
  margin-top: 48px;
  padding: 0 28px;
  border-radius: var(--radius-pill);
  box-shadow: inset 0 0 0 2px var(--accent);
  color: var(--accent);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 24px;
  text-transform: capitalize;
  transition: background-color .25s ease, color .25s ease;
}
.block-gallery-grid__more-btn:hover,
.block-gallery-grid__more-btn:focus-visible { background: var(--accent); color: var(--black); }
.block-gallery-grid__more-btn[hidden] { display: none; }
.block-gallery-grid__empty { padding: 40px 0; color: var(--grey); }

/* ---- Tablet: one column; the filter becomes a sideways-scrolling row of pill chips ---- */
@media (max-width: 1024px) {
  .block-gallery-grid {
    --gg-gap-x: 8px;
    --gg-gap-y: 8px;
    --gg-row-k: 0.3;
    --gg-row-max: 260;
  }
  .block-gallery-grid__layout { grid-template-columns: minmax(0, 1fr); }
  .block-gallery-grid__side { position: static; }
  .block-gallery-grid__filters {
    display: flex;
    gap: 8px;
    margin: 24px calc(var(--gutter) * -1) 0;
    padding: 0 var(--gutter) 2px;
    overflow-x: auto;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
  }
  .block-gallery-grid__filters::-webkit-scrollbar { display: none; }
  .block-gallery-grid__filter-item { flex: 0 0 auto; border: 0; }
  .block-gallery-grid__filter-item:nth-child(n) .block-gallery-grid__filter {
    display: inline-flex;
    align-items: center;
    height: 44px;
    padding: 0 18px;
    border-radius: var(--radius-pill);
    box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .35);
    font-size: 18px;
    white-space: nowrap;
    transition: color .25s ease, background-color .25s ease, box-shadow .25s ease;
  }
  .block-gallery-grid__filter-item:nth-child(n) .block-gallery-grid__filter:hover { box-shadow: inset 0 0 0 2px var(--accent); }
  .block-gallery-grid__filter-item:nth-child(n) .block-gallery-grid__filter.is-active {
    padding: 0 18px;
    background: var(--accent);
    box-shadow: none;
    color: var(--black);
  }
  .block-gallery-grid__main { margin-top: 28px; }
  .block-gallery-grid__item { height: min(30vw, 260px); }
}

/* ---- Mobile (derived — Mobile Category 4148:2776 language, 402 wide) --------------
   Title 36px 58 under the 98px header (as the service hero's title) → 44px chips → ≈150px justified rows. */
@media (max-width: 640px) {
  .block-gallery-grid {
    --gg-row-k: 0.42;
    --gg-row-max: 200;
    --gg-pad-top: 58px;
    padding-bottom: 48px;
  }
  .block-gallery-grid__title { margin-left: 0; font-size: 36px; line-height: 1.222; }
  .block-gallery-grid__filters { margin-top: 20px; }
  .block-gallery-grid__filter-item:nth-child(n) .block-gallery-grid__filter { font-size: 16px; padding: 0 16px; }
  .block-gallery-grid__filter-item:nth-child(n) .block-gallery-grid__filter.is-active { padding: 0 16px; }
  .block-gallery-grid__main { margin-top: 24px; }
  .block-gallery-grid__item { height: 42vw; }
  .block-gallery-grid__more-btn { width: 100%; justify-content: center; height: 46px; font-size: 20px; }
}
