/* Gallery section (M22, GAL-1). Starter tokens only; mobile first. Justified rows in CSS only: each photo grows by its
   width/height ratio (--r) from a basis of ratio × row height, so a row fills the width at one height; the list's ::after
   keeps the last row at its natural height. Width/height attributes reserve each photo's box (no layout shift). */
.gallery { margin: 2rem 0; --gallery-gap: 0.375rem; --gallery-h: calc(var(--gallery-row, 240px) * 0.6); }
@media (min-width: 40em) { .gallery { --gallery-gap: 0.5rem; --gallery-h: var(--gallery-row, 240px); } }
.gallery__heading { margin: 0 0 0.75rem; }
.gallery__folder-heading { margin: 1.5rem 0 0.5rem; }
.gallery__group:first-child .gallery__folder-heading { margin-top: 0.5rem; }
.gallery__group[hidden] { display: none; }
.gallery__note { margin: 0 0 0.75rem; padding: 0.5rem 0.75rem; border-left: 4px solid var(--starter-focus); background: var(--starter-background); }

.gallery__list { list-style: none; margin: 0; padding: 0; gap: var(--gallery-gap); }
.gallery__item { margin: 0; background: var(--c, var(--starter-muted)); overflow: hidden; }
.gallery__link { display: flex; align-items: center; justify-content: center; height: 100%; }
.gallery__link:focus-visible { outline: 3px solid var(--starter-focus); outline-offset: 2px; }
.gallery__img { display: block; width: 100%; max-width: var(--w, none); height: auto; }
/* GAL-3: once a photo has loaded (gallery.js), its slot drops the placeholder colour, so a transparent image sits on the
   page background (N2) and a photo smaller than its slot is centred on the page background (N1). */
.gallery__item.is-loaded { background: none; }

.gallery__list--justified { display: flex; flex-wrap: wrap; }
.gallery__list--justified::after { content: ""; flex-grow: 999999; }
/* GAL-3 S3: a row grows to fill the width by at most 1.5× its height, then ends short (with the 1:2 to 3:1 crop of very tall
   and very wide photos, rows stay near the chosen height). */
.gallery__list--justified .gallery__item { flex: var(--r) 1 calc(var(--r) * var(--gallery-h)); max-width: min(100%, calc(var(--r) * var(--gallery-h) * 1.5)); }
.gallery__list--justified .gallery__img { aspect-ratio: var(--r); }

.gallery__list--grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 40em) { .gallery__list--grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 70em) { .gallery__list--grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.gallery__list--grid .gallery__img { aspect-ratio: 1; object-fit: cover; }
.gallery__list--four-three .gallery__img { aspect-ratio: 4 / 3; }

.gallery__filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 1rem; }
/* GAL-3: the filter bar keeps its place until the script makes it usable (no layout shift); without script it stays an
   invisible gap, out of the tab order and hidden from screen readers. */
.gallery__filters--wait { visibility: hidden; }
.gallery__filter, .gallery__more {
  display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0.5rem 1rem;
  font: inherit; font-weight: 700; color: var(--starter-text); background: var(--starter-background);
  border: 2px solid currentColor; border-radius: 0.25rem; cursor: pointer; text-decoration: none;
}
.gallery__filter[aria-pressed="true"] { color: var(--starter-background); background: var(--starter-text); }
.gallery__filter:focus-visible, .gallery__more:focus-visible { outline: 3px solid var(--starter-focus); outline-offset: 2px; }
.gallery__more-wrap { margin: 1rem 0 0; text-align: center; }
.gallery__more-wrap[hidden] { display: none; }
.gallery__count { color: var(--starter-text); }

.gallery__viewer { width: 100vw; height: 100vh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: #000; color: #fff; }
.gallery__viewer::backdrop { background: rgb(0 0 0 / 0.9); }
.gallery__figure { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; margin: 0; padding: 3rem 0.5rem 1rem; box-sizing: border-box; touch-action: pan-y; }
/* GAL-3: the frame always fills the viewer (the window less the bars and the caption) and the photo is contained in it, on
   the black background; its size never comes from the photo or its loading (an image between sources can collapse), and
   the caption keeps a fixed height: nothing moves when a photo opens, loads or changes (CLS 0). */
.gallery__frame { position: relative; display: block; flex: none; width: 100%; height: calc(100vh - 9rem); }
.gallery__large { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.gallery__caption { box-sizing: border-box; flex: none; width: 100%; height: 4.5rem; margin-top: 0.5rem; overflow-y: auto; text-align: center; }
.gallery__nav, .gallery__close {
  position: absolute; min-width: 2.75rem; min-height: 2.75rem; padding: 0 0.75rem; font-size: 2rem; line-height: 1;
  color: #fff; background: rgb(0 0 0 / 0.5); border: 0; border-radius: 0.25rem; cursor: pointer;
}
.gallery__nav { top: 50%; transform: translateY(-50%); }
.gallery__nav--prev { left: 0.5rem; }
.gallery__nav--next { right: 0.5rem; }
.gallery__close { top: 0.5rem; right: 0.5rem; }
.gallery__nav:disabled { opacity: 0.3; cursor: default; }
.gallery__status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.gallery__nav:focus-visible, .gallery__close:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
@media (prefers-reduced-motion: no-preference) { .gallery__large { transition: opacity 0.15s; } }

/* MB-38 (#140, from Boyd's gallery): an intro line, one Action button, and hand-picked photos (.gallery--picked) with
   captions, a link per photo and the Feature layout (Boyd's bento grid: spans from GalleryFeature.cs as classes). */
.gallery__intro { max-width: 65ch; margin: -0.25rem 0 1rem; }
.gallery__action { margin: 1.25rem 0 0; }
.gallery__hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.gallery__tile { position: relative; isolation: isolate; }
.gallery__tile-figure { display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr); height: 100%; margin: 0; }
.gallery__tile-figure > * { grid-area: 1 / 1; }
/* The caption sits on a dark layer at the foot of the tile: white text stays at least 4.5:1 over any photo. Clicks pass
   through it to the photo (viewer), except on a page link. It is not positioned, so a page link's hit area is the tile. */
.gallery__tile-caption {
  align-self: end; padding: 1.5rem 0.75rem 0.625rem; color: #fff; font-weight: 600; line-height: 1.3;
  background: linear-gradient(to bottom, transparent 0, rgb(0 0 0 / 0.72) 1rem); pointer-events: none;
}
/* One link per photo: the caption link's hit area covers the whole tile (the tile is its positioned box). */
.gallery__page-link { color: inherit; text-decoration: none; pointer-events: auto; }
.gallery__page-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.gallery__item--linked:hover .gallery__page-link { text-decoration: underline; text-underline-offset: 3px; }
.gallery__page-link:focus-visible { outline: none; }
.gallery__page-link:focus-visible::after { outline: 3px solid var(--starter-focus); outline-offset: -3px; }
html.ve-canvas .gallery__page-link::after { pointer-events: none; }

.gallery__list--feature { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gallery__list--feature .gallery__item { aspect-ratio: 4 / 3; }
.gallery__list--feature .gallery__item--full { grid-column: span 2; }
.gallery__list--feature .gallery__link { height: 100%; }
.gallery__list--feature .gallery__img { width: 100%; height: 100%; max-width: none; object-fit: cover; }
@media (min-width: 64em) {
  .gallery__list--feature { grid-template-columns: repeat(12, minmax(0, 1fr)); grid-auto-rows: var(--gallery-row, 240px); }
  .gallery__list--feature .gallery__item { aspect-ratio: auto; grid-column: span var(--gallery-span, 3); }
  .gallery__list--feature .gallery__item--full { grid-column: span var(--gallery-span, 3); }
  .gallery__list--feature .gallery__item--tall { grid-row: span 2; }
  .gallery__item--span-3 { --gallery-span: 3; }
  .gallery__item--span-4 { --gallery-span: 4; }
  .gallery__item--span-6 { --gallery-span: 6; }
  .gallery__item--span-8 { --gallery-span: 8; }
  .gallery__item--span-12 { --gallery-span: 12; }
}

/* MB-130: Viewer look "Over the page" (FuelChief's viewer, measured: port capture motion.md row 10 and the site's own
   Magnific Popup CSS). The page stays visible behind a 6 px blur under the dark colour at 90 %; the photo shows at its own
   shape, at most the window less 8 px a side (6 px up to 900 px) and 90 % of its height, centred across, at the top of a
   box at least half the window tall that is centred (Magnific's content box), with a soft shadow; round
   54 px arrows 25 px in from the sides, their top 20 px above the middle, 10 px further out on hover (at once), drawn at
   75 % from their outer edge up to 900 px; the counter is for screen readers only and nothing else is written under the
   photo (the lead, 21 Oct 2026: no caption). Opens, changes and closes at once, as the original. */
.gallery__viewer--over { background: transparent; }
.gallery__viewer--over::backdrop {
  background: color-mix(in srgb, var(--gallery-viewer-over) 90%, transparent);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.gallery__viewer--over .gallery__figure { position: absolute; inset: 0; padding: 0 8px; }
.gallery__viewer--over .gallery__frame {
  position: static; display: flex; align-items: flex-start; justify-content: center; width: auto; height: auto;
  min-width: 80%; min-height: 50%;
}
.gallery__viewer--over .gallery__large {
  position: static; width: auto; height: auto; max-width: calc(100vw - 16px); max-height: 90vh; object-fit: fill;
  box-shadow: 0 0 8px rgb(0 0 0 / 0.6); cursor: pointer;
}
.gallery__viewer--over .gallery__caption {
  position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.gallery__viewer--over .gallery__nav {
  top: calc(50% - 20px); width: 54px; min-width: 54px; height: 54px; min-height: 54px; padding: 0; font-size: 0; color: transparent;
  background: var(--gallery-viewer-over); border-radius: 54px; transform: none;
}
.gallery__viewer--over .gallery__nav::after {
  content: ""; position: absolute; inset: 0; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16.828' height='15.414' viewBox='0 0 16.828 15.414'%3E%3Cg fill='none' stroke='white' stroke-linecap='round' stroke-width='2'%3E%3Cpath d='M8.414 1v12M15.414 7l-7 7M1.414 7l7 7'/%3E%3C/g%3E%3C/svg%3E") no-repeat center;
}
.gallery__viewer--over .gallery__nav--prev { left: 25px; }
.gallery__viewer--over .gallery__nav--prev::after { transform: rotate(90deg); }
.gallery__viewer--over .gallery__nav--prev:hover { left: 15px; }
.gallery__viewer--over .gallery__nav--next { right: 25px; }
.gallery__viewer--over .gallery__nav--next::after { transform: rotate(-90deg); }
.gallery__viewer--over .gallery__nav--next:hover { right: 15px; }
.gallery__viewer--over .gallery__close {
  top: 25px; right: 25px; min-width: 54px; height: 54px; padding: 0; border-radius: 0; opacity: 0.65;
  font: 50px/35px Arial, Baskerville, monospace; text-align: center; background: rgb(0 0 0 / 0.6);
}
.gallery__viewer--over .gallery__close:hover, .gallery__viewer--over .gallery__close:focus { opacity: 1; }
html:has(.gallery__viewer--over[open]) { overflow: hidden; }
@media (max-width: 56.25em) {
  .gallery__viewer--over .gallery__figure { padding: 0 6px; }
  .gallery__viewer--over .gallery__large { max-width: calc(100vw - 12px); }
  .gallery__viewer--over .gallery__nav { transform: scale(0.75); }
  .gallery__viewer--over .gallery__nav--prev { transform-origin: 0; }
  .gallery__viewer--over .gallery__nav--next { transform-origin: 100%; }
}
@media (prefers-reduced-motion: no-preference) { .gallery__viewer--over .gallery__large { transition: none; } }
