/**
 * One large image, its controls and its strip of thumbnails.
 *
 * Deliberately plain: enough to be usable out of the box and no opinion beyond
 * that. Everything worth changing is a custom property set on the component, so
 * a theme changes values rather than fighting selectors:
 *
 *   .gallery-engine-wrapper {
 *     --ge-thumb-width: 140px;
 *     --ge-thumb-height: 90px;
 *     --ge-nav-background: transparent;
 *   }
 *
 * | Property | Is |
 * |---|---|
 * | `--ge-gap` | between the image, the controls, the caption and the strip |
 * | `--ge-thumb-width` / `--ge-thumb-height` | the box a thumbnail is cropped to |
 * | `--ge-thumb-gap` | between thumbnails |
 * | `--ge-thumb-radius` | rounding of a thumbnail |
 * | `--ge-thumb-dim` | opacity of the ones not being shown |
 * | `--ge-nav-background` / `--ge-nav-color` / `--ge-nav-padding` | previous and next |
 * | `--ge-nav-off-opacity` | a control with nowhere to go |
 * | `--ge-caption-size` | the caption |
 * | `--ge-dot-size` / `--ge-dot-gap` / `--ge-dot-radius` | shape of a dot |
 * | `--ge-dot-color` / `--ge-dot-color-active` | a dot, and the current one |
 * | `--ge-side-width` | width of the strip when it sits beside the image |
 * | `--ge-main-width` | set to 100% for a stage that fills its column |
 * | `--ge-main-max-height` | a ceiling for the image on show |
 *
 * Every part has a class of its own, so nothing here needs a descendant
 * selector and an override never has to repeat one:
 * `gallery-engine-mainimage`, `-caption`, `-actions`, `-prev`, `-next`,
 * `-counter`, `-dots`, `-dot`, `-thumbs`, `-thumb`, `-status`.
 */

.gallery-engine-wrapper {
  --ge-gap: 10px;
  --ge-thumb-width: 100px;
  --ge-thumb-height: 70px;
  --ge-thumb-gap: 6px;
  --ge-thumb-radius: 0;
  --ge-thumb-dim: 0.55;
  --ge-nav-background: #bbbbbb;
  --ge-nav-color: inherit;
  --ge-nav-padding: 0.35em 0.6em;
  --ge-nav-off-opacity: 0.45;
  --ge-caption-size: 0.9em;
  --ge-dot-size: 10px;
  --ge-dot-gap: 8px;
  --ge-dot-radius: 50%;
  --ge-dot-color: #cccccc;
  --ge-dot-color-active: #666666;
  --ge-side-width: auto;
  /* The image on show draws at the size of the file behind it, which is the
     image style's doing and not this file's. These two are for the times when
     the box matters more than the file: a stage that always fills its column,
     or one that never grows past a given height. Left alone, neither does
     anything. Filling with a file smaller than the box will blur it — the style
     is still the right place to fix that. */
  --ge-main-width: auto;
  --ge-main-max-height: none;
  /* How many thumbnails the strip shows at once. The layout writes it; 0 is
     every one of them. */
  --ge-thumbs-visible: 0;

  display: flex;
  flex-direction: column;
  gap: var(--ge-gap);
  text-align: center;
}

/**
 * The image on show.
 *
 * The anchor is a block because it wraps a block level image, which would
 * otherwise split the inline box and land off centre; the automatic inline
 * margins centre the image whatever the theme does to its display.
 */
.gallery-engine-mainimage {
  order: 1;
}
.gallery-engine-mainimage > a {
  display: block;
}
.gallery-engine-mainimage img {
  width: var(--ge-main-width);
  max-width: 100%;
  max-height: var(--ge-main-max-height);
  height: auto;
  margin-inline: auto;
  object-fit: contain;
}

/* Cells a view rendered: a row is as tall as its fields make it, so the slot
   stops behaving like a picture frame. */
.gallery-engine-mainimage--content {
  line-height: normal;
}
.gallery-engine-slide {
  display: none;
}
.gallery-engine-slide.active {
  display: block;
}

/**
 * What the gallery says out loud when the image changes.
 *
 * Off the screen but not out of the accessibility tree: display:none or
 * visibility:hidden would take it out of both and nothing would ever be
 * announced. A theme that would rather show the position here than in the
 * counter only has to undo these six lines.
 */
.gallery-engine-status {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Under the image, because it describes what is above it and not what the
   controls do. */
.gallery-engine-caption {
  order: 2;
  font-size: var(--ge-caption-size);
  line-height: 1.35;
}

/**
 * Previous, next and the counter.
 *
 * A row rather than two inline blocks, so the counter has a middle to sit in
 * without either control moving.
 */
.gallery-engine-actions {
  order: 3;
  display: flex;
  align-items: center;
  gap: 4px;
}
.gallery-engine-prev,
.gallery-engine-next {
  flex: 1 1 0;
  min-width: 0;
  padding: var(--ge-nav-padding);
  background-color: var(--ge-nav-background);
  color: var(--ge-nav-color);
}
/* A control with nowhere to go. Faded rather than gone, because one that
   disappeared would move the other, and inert rather than merely faded, since
   the anchor stays in the markup for the script to bind to. */
.gallery-engine-nav--off {
  opacity: var(--ge-nav-off-opacity);
}
.gallery-engine-nav--off a {
  pointer-events: none;
  cursor: default;
}
.gallery-engine-counter {
  flex: 0 0 auto;
  padding-inline: 0.6em;
  /* So the width does not jump between 9/10 and 10/10. */
  font-variant-numeric: tabular-nums;
}

/**
 * A dot per image.
 *
 * They are links with no text, so what they look like is entirely this: a
 * square with a radius here, a dash by setting the radius to 0 and the width
 * wider, a number by giving them content. Nothing about the shape is baked
 * into the markup.
 */
.gallery-engine-dots {
  order: 5;
  display: flex;
  justify-content: center;
  gap: var(--ge-dot-gap);
}
.gallery-engine-dot {
  width: var(--ge-dot-size);
  height: var(--ge-dot-size);
  border-radius: var(--ge-dot-radius);
  background-color: var(--ge-dot-color);
  /* An empty anchor is a zero-width inline box in most themes. */
  display: block;
  flex: none;
}
.gallery-engine-dot.active,
.gallery-engine-dot[aria-current] {
  background-color: var(--ge-dot-color-active);
}

/**
 * The strip.
 *
 * With a maximum set it becomes a window that many thumbnails wide, and the
 * rest are reached by scrolling it — which is also how previous and next drag
 * it along, so the thumbnail being shown is always the one in view. Nothing is
 * hidden: hiding the overflow used to leave the visitor on image 8 of 10 with
 * the strip still showing 1 to 4 and no sign the others existed.
 */
.gallery-engine-thumbs {
  order: 4;
  display: flex;
  gap: var(--ge-thumb-gap);
  justify-content: center;
  overflow: auto;
  overscroll-behavior-inline: contain;
  scrollbar-width: thin;
}
/* The layout without a strip still keeps it in the DOM — the script navigates
   by it and the no-JS links go through it — so the attribute has to be honoured
   here, or the display above would win over the browser's own rule for it. */
.gallery-engine-thumbs[hidden] {
  display: none;
}
.gallery-engine-thumbs--windowed {
  justify-content: start;
  max-width: calc(
    var(--ge-thumbs-visible) * var(--ge-thumb-width) +
    (var(--ge-thumbs-visible) - 1) * var(--ge-thumb-gap)
  );
  margin-inline: auto;
}
.gallery-engine-thumb {
  flex: 0 0 auto;
  display: inline-flex;
  overflow: hidden;
  border-radius: var(--ge-thumb-radius);
  opacity: var(--ge-thumb-dim);
}
.gallery-engine-thumb.active,
.gallery-engine-thumb:hover,
.gallery-engine-thumb:focus-visible {
  opacity: 1;
}
/* A fixed box keeps the strip tidy whatever shape each image is. No width or
   height attributes are written on these on purpose: they would contradict this
   and cause the very layout shift the attributes exist to prevent. */
.gallery-engine-thumb img {
  display: block;
  width: var(--ge-thumb-width);
  height: var(--ge-thumb-height);
  object-fit: cover;
}
/* What a strip with no picture to show puts in the cell instead. */
.gallery-engine-thumb--label {
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  min-height: 2.5rem;
  border: 1px solid currentColor;
  border-radius: 50%;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
}

/**
 * Where the strip sits.
 *
 * Above and below only change the order. Beside the image the wrapper becomes a
 * row and the strip a column, on the inline axis so it mirrors by itself in
 * right-to-left languages.
 */
.gallery-engine--thumbs-above .gallery-engine-thumbs {
  order: 0;
}
/**
 * Beside the image: two columns, and the parts placed one by one.
 *
 * The controls go with the strip — above it and below it — rather than in a bar
 * under the picture. Running down the page, that is where a hand expects them:
 * the strip moves up and down, so the things that move it sit at its ends. A
 * horizontal bar under a vertical strip belongs to neither.
 *
 * The bar stops being a box for that (`display: contents`), so previous, the
 * counter and next become pieces of this grid and each can be put where it
 * belongs. Which is also what leaves a theme free to arrange them differently —
 * over the image at its edges, say — without the markup standing in the way.
 *
 * They are still text, and still whatever text the site wrote. Turning that
 * text into a chevron is a few lines of CSS on a class that exists for it; see
 * the README.
 */
.gallery-engine--thumbs-before,
.gallery-engine--thumbs-after {
  display: grid;
  align-items: start;
  column-gap: var(--ge-gap);
  /* The rows carry their own spacing, so an absent caption costs nothing rather
     than leaving a gap where it would have been. */
  row-gap: 0;
  /* Above the strip, the strip, below it, and then the image's own three
     lines: its caption, its counter and its dots. */
  grid-template-rows: auto 1fr auto auto auto auto;
}
.gallery-engine--thumbs-before {
  grid-template-columns: auto minmax(0, 1fr);
}
.gallery-engine--thumbs-after {
  grid-template-columns: minmax(0, 1fr) auto;
}
.gallery-engine--thumbs-before .gallery-engine-actions,
.gallery-engine--thumbs-after .gallery-engine-actions {
  display: contents;
}

/* The strip's column: a control, the strip, the other control. */
.gallery-engine--thumbs-before .gallery-engine-prev {
  grid-area: 1 / 1;
}
.gallery-engine--thumbs-before .gallery-engine-thumbs {
  grid-area: 2 / 1;
}
.gallery-engine--thumbs-before .gallery-engine-next {
  grid-area: 3 / 1;
}
.gallery-engine--thumbs-after .gallery-engine-prev {
  grid-area: 1 / 2;
}
.gallery-engine--thumbs-after .gallery-engine-thumbs {
  grid-area: 2 / 2;
}
.gallery-engine--thumbs-after .gallery-engine-next {
  grid-area: 3 / 2;
}

/* And the image's column: the picture, then what it has to say about itself. */
.gallery-engine--thumbs-before .gallery-engine-mainimage {
  grid-area: 1 / 2 / 4 / 3;
}
.gallery-engine--thumbs-before .gallery-engine-caption {
  grid-area: 4 / 2;
}
.gallery-engine--thumbs-before .gallery-engine-counter {
  grid-area: 5 / 2;
}
.gallery-engine--thumbs-after .gallery-engine-mainimage {
  grid-area: 1 / 1 / 4 / 2;
}
.gallery-engine--thumbs-after .gallery-engine-caption {
  grid-area: 4 / 1;
}
.gallery-engine--thumbs-after .gallery-engine-counter {
  grid-area: 5 / 1;
}
.gallery-engine--thumbs-before .gallery-engine-dots {
  grid-area: 6 / 2;
}
.gallery-engine--thumbs-after .gallery-engine-dots {
  grid-area: 6 / 1;
}
.gallery-engine--thumbs-before .gallery-engine-caption,
.gallery-engine--thumbs-after .gallery-engine-caption,
.gallery-engine--thumbs-before .gallery-engine-counter,
.gallery-engine--thumbs-after .gallery-engine-counter {
  margin-block-start: var(--ge-gap);
}
/* Flex sizing meant something in the bar and means nothing here. */
.gallery-engine--thumbs-before .gallery-engine-prev,
.gallery-engine--thumbs-after .gallery-engine-prev,
.gallery-engine--thumbs-before .gallery-engine-next,
.gallery-engine--thumbs-after .gallery-engine-next {
  flex: none;
  width: var(--ge-side-width);
}
/* The strip runs the height between the two controls and scrolls inside it, so
   a long strip no longer towers over a short image. */
.gallery-engine--thumbs-before .gallery-engine-thumbs,
.gallery-engine--thumbs-after .gallery-engine-thumbs {
  align-self: stretch;
  min-height: 0;
  width: var(--ge-side-width);
  flex-direction: column;
  margin-block: var(--ge-thumb-gap);
}
.gallery-engine--thumbs-before .gallery-engine-thumbs--windowed,
.gallery-engine--thumbs-after .gallery-engine-thumbs--windowed {
  max-width: none;
  max-height: calc(
    var(--ge-thumbs-visible) * var(--ge-thumb-height) +
    (var(--ge-thumbs-visible) - 1) * var(--ge-thumb-gap)
  );
}

/* On a narrow screen a strip beside the image eats a quarter of the width and
   leaves the image too small to be worth showing, so both side positions fall
   back to the stacked arrangement — which means undoing the placement above
   rather than merely overriding it: a grid-area left standing would pin these
   where there is no longer a grid, and a bar left as contents would have no box
   to be a row in. */
@media all and (max-width: 559px) {
  .gallery-engine--thumbs-before,
  .gallery-engine--thumbs-after {
    display: flex;
    flex-direction: column;
    gap: var(--ge-gap);
  }
  .gallery-engine--thumbs-before .gallery-engine-actions,
  .gallery-engine--thumbs-after .gallery-engine-actions {
    display: flex;
  }
  .gallery-engine--thumbs-before .gallery-engine-mainimage,
  .gallery-engine--thumbs-after .gallery-engine-mainimage,
  .gallery-engine--thumbs-before .gallery-engine-caption,
  .gallery-engine--thumbs-after .gallery-engine-caption,
  .gallery-engine--thumbs-before .gallery-engine-counter,
  .gallery-engine--thumbs-after .gallery-engine-counter,
  .gallery-engine--thumbs-before .gallery-engine-prev,
  .gallery-engine--thumbs-after .gallery-engine-prev,
  .gallery-engine--thumbs-before .gallery-engine-next,
  .gallery-engine--thumbs-after .gallery-engine-next,
  .gallery-engine--thumbs-before .gallery-engine-thumbs,
  .gallery-engine--thumbs-after .gallery-engine-thumbs {
    grid-area: auto;
    margin-block: 0;
  }
  .gallery-engine--thumbs-before .gallery-engine-prev,
  .gallery-engine--thumbs-after .gallery-engine-prev,
  .gallery-engine--thumbs-before .gallery-engine-next,
  .gallery-engine--thumbs-after .gallery-engine-next {
    flex: 1 1 0;
    width: auto;
  }
  .gallery-engine--thumbs-before .gallery-engine-thumbs,
  .gallery-engine--thumbs-after .gallery-engine-thumbs {
    align-self: auto;
    width: auto;
    flex-direction: row;
  }
  .gallery-engine--thumbs-before .gallery-engine-thumbs--windowed,
  .gallery-engine--thumbs-after .gallery-engine-thumbs--windowed {
    max-height: none;
    max-width: calc(
      var(--ge-thumbs-visible) * var(--ge-thumb-width) +
      (var(--ge-thumbs-visible) - 1) * var(--ge-thumb-gap)
    );
  }
}
