/* ==========================================================================
   ALBI HOME — PROJEKTE (the gallery page)
   Page backdrop, centred filter bar, masonry wall.
   Depends on tokens.css + base.css + components.css + projects.css.

   projects.css already owns the filter chips, the CTA panel and the lightbox,
   so this file adds only what is genuinely new to this page. Loading both is
   the point — not duplication.
   ========================================================================== */

.gallery-section {
  /* Same rhythm as the homepage mosaic: 30px at 1440, never under 12px. */
  --gal-gap: clamp(0.75rem, 2.08vw, 1.875rem);

  position: relative;
  background-color: var(--bg-raised);
  background-image: url("../img/benefits-bg-1440.jpg");
  background-repeat: no-repeat;
  background-position: center top;
  background-size: cover;
  background-attachment: scroll;
}
@supports (background-image: image-set(url("x.webp") type("image/webp") 1x)) {
  .gallery-section {
    background-image: image-set(
      url("../img/benefits-bg-1440.webp") type("image/webp") 1x,
      url("../img/benefits-bg-1440.jpg")  type("image/jpeg") 1x
    );
  }
}

/* The photograph is 1822px tall and the wall below it is far taller, so past
   the image the section would fall back to bare --bg-raised with a hard seam
   across it. This scrim fades the backdrop into the page colour before it
   runs out, which is why background-size:cover alone is not enough here. */
.gallery-section::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-decor);
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(23, 26, 31, .55) 0%,
    rgba(23, 26, 31, .82) 34%,
    var(--bg-page) 72%
  );
}
.gallery-section > .container { position: relative; z-index: var(--z-content); }

/* --- Smaller backdrops for smaller screens ------------------------------- */
@media (max-width: 1024px) {
  .gallery-section { background-image: url("../img/benefits-bg-1024.jpg"); }
  @supports (background-image: image-set(url("x.webp") type("image/webp") 1x)) {
    .gallery-section {
      background-image: image-set(
        url("../img/benefits-bg-1024.webp") type("image/webp") 1x,
        url("../img/benefits-bg-1024.jpg")  type("image/jpeg") 1x
      );
    }
  }
}
@media (max-width: 720px) {
  .gallery-section { background-image: url("../img/benefits-bg-720.jpg"); }
  @supports (background-image: image-set(url("x.webp") type("image/webp") 1x)) {
    .gallery-section {
      background-image: image-set(
        url("../img/benefits-bg-720.webp") type("image/webp") 1x,
        url("../img/benefits-bg-720.jpg")  type("image/jpeg") 1x
      );
    }
  }
}

/* --------------------------------------------------------------------------
   1. CENTRED FILTER BAR
   Same panel and same chips as the homepage — only the alignment differs.
   On the homepage the bar sits under a two-column head and reads left-to-
   right with it; here it is the only thing between the head and the wall, so
   a centred row is what makes it read as the wall's own control.
   -------------------------------------------------------------------------- */
.projects-filter--center { justify-content: center; }
.projects-filter--center .projects-filter__chips { justify-content: center; }

/* --------------------------------------------------------------------------
   2. THE MASONRY WALL
   CSS multi-column, not grid.

   Grid cannot do masonry today — `grid-template-rows: masonry` is still
   behind a flag in every engine, and a JS implementation would have to
   measure every tile, re-measure on resize, and re-run on every filter press,
   which is a lot of machinery to reintroduce a layout the browser already
   does natively. Columns give true masonry with no script at all, so the wall
   is correct on first paint and stays correct if projects.js never loads.

   The trade-off is reading order: columns fill top-to-bottom, so tile 2 sits
   under tile 1 rather than beside it. For a gallery with no narrative order
   that costs nothing, and it is the reason each tile carries its own title
   instead of relying on position.
   -------------------------------------------------------------------------- */
.gallery {
  column-count: 3;
  column-gap: var(--gal-gap);
  margin-top: var(--section-stack);
}

.gal {
  /* A tile must never be split across a column break — half a photograph at
     the foot of one column and half at the head of the next. The three
     properties are the same request to three generations of engine. */
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  break-inside: avoid;

  /* margin, not gap: `gap` has no vertical meaning in a multi-column
     container, so the space between stacked tiles has to come from the tile
     itself. */
  margin-bottom: var(--gal-gap);
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background-color: var(--bg-card);   /* holds the shape while the photo loads */

  /* Columns break on the element box, and a transformed child can otherwise
     be clipped by the fragmentation container in Safari. */
  display: block;
}

.gal[hidden] { display: none; }

/* THE TILE TAKES ITS SHAPE FROM THE PHOTOGRAPH — the opposite of the
   homepage mosaic, where the slot is the shape authority and the photo is
   cropped to fit it. Here nothing is cropped: the image is in normal flow,
   its width/height attributes give it an intrinsic ratio, and the column
   simply grows to whatever that is. A panorama stays a panorama. */
.gal__img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform var(--dur-slow) var(--ease-out);
}

/* The whole tile is the button. */
.gal__open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  color: inherit;
  text-align: left;
}
.gal__open:focus-visible { outline-offset: -3px; border-radius: var(--radius-sm); }

/* Disabled until projects.js enables it, so a tile shows no affordance at all
   until the lightbox exists to answer the click. The photographs still
   render; they just do not pretend to be pressable. */
.gal__open:disabled { cursor: default; }
.gal__open:disabled .gal__zoom { display: none; }

/* --- Veil + caption bar ---------------------------------------------------
   The scrim is a separate layer from the text so it can fade independently:
   on a pointer device both are hidden at rest and the wall reads as pure
   photography, exactly like the homepage mosaic. */
.gal__veil {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, .10) 0%,
    rgba(0, 0, 0, .04) 38%,
    rgba(0, 0, 0, .62) 78%,
    rgba(0, 0, 0, .86) 100%
  );
  transition: opacity var(--dur-base) var(--ease-out);
}

.gal__meta {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-5) var(--space-4) var(--space-4);
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition:
    opacity var(--dur-base) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
}
.gal__cat {
  color: var(--text-accent);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
}
.gal__title {
  color: var(--white);
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
}

/* The gold badge, same vocabulary as the homepage tiles — but pinned to the
   top corner here, because the bottom of the tile belongs to the caption. */
.gal__zoom {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-pill);
  background: var(--grad-gold);
  color: var(--text-on-gold);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: scale(.7);
  transition:
    opacity var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-spring);
}
.gal__zoom .icon { width: 18px; height: 18px; }

/* Pointer devices only. On a touchscreen :hover sticks after a tap, leaving
   the veil burned onto whichever tile was pressed last. */
@media (hover: hover) {
  .gal__open:enabled:hover .gal__veil,
  .gal__open:enabled:focus-visible .gal__veil { opacity: 1; }

  .gal__open:enabled:hover .gal__meta,
  .gal__open:enabled:focus-visible .gal__meta { opacity: 1; transform: none; }

  .gal__open:enabled:hover .gal__zoom,
  .gal__open:enabled:focus-visible .gal__zoom { opacity: 1; transform: scale(1); }

  .gal__open:enabled:hover .gal__img,
  .gal__open:enabled:focus-visible .gal__img { transform: scale(1.05); }
  .gal__open:enabled:active .gal__img { transform: scale(1.02); }
}

/* Touch has no hover, so the caption is simply always there — without it the
   wall would be unlabelled photographs with no way to reveal the names. */
@media (hover: none) {
  .gal__veil { opacity: 1; }
  .gal__meta { opacity: 1; transform: none; }
  .gal__zoom {
    opacity: 1;
    transform: none;
    width: 34px;
    height: 34px;
    background: var(--a-black-64);
    color: var(--white);
    box-shadow: none;
  }
  .gal__zoom .icon { width: 15px; height: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  .gal__open:enabled:hover .gal__img,
  .gal__open:enabled:focus-visible .gal__img,
  .gal__open:enabled:active .gal__img { transform: none; }
  .gal__meta { transform: none; }
}

/* --- Filtering ------------------------------------------------------------
   Nothing to do to the layout: columns re-flow around the hidden tiles by
   themselves, which is the other reason this page is columns and not grid.
   The incoming tiles just fade so the reflow does not read as a jump. */
.gallery.is-switching > .gal:not([hidden]) {
  animation: project-in var(--dur-slow) var(--ease-out) both;
}
@media (prefers-reduced-motion: reduce) {
  .gallery.is-switching > .gal:not([hidden]) { animation: none; }
}

/* --------------------------------------------------------------------------
   3. BREAKPOINTS
   Three columns down to 768, two below it — as specified. Nothing else in the
   wall needs a breakpoint: the tiles are fluid and the heights follow the
   photographs.
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
  .gallery { column-count: 2; }

  /* At half a phone's width the caption would sit on two or three lines and
     cover most of the photograph, so it drops to the label alone. */
  .gal__meta { padding: var(--space-4) var(--space-3) var(--space-3); }
  .gal__title { font-size: var(--fs-body); }
}

/* Below 420 a column is under 190px — narrower than the title needs, and
   narrow enough that the rooms in the photographs stop reading. One tile per
   row from here down, which also gives the caption its full width back. */
@media (max-width: 419.98px) {
  .gallery { column-count: 1; }
}

/* --------------------------------------------------------------------------
   4. REVEAL
   motion.js staggers the children of [data-reveal-stagger]. In a multi-column
   container the children are fragmented, so the transform has to stay on the
   tile itself rather than on anything the column box owns — which it does.
   -------------------------------------------------------------------------- */
.reveal-ready .gallery > .gal { will-change: opacity, transform; }
.reveal-ready .gallery.is-revealed > .gal { will-change: auto; }
