/*
 * TritonIQ DNN Gallery — styles for the server-rendered section (Services/Gallery/GalleryRenderer.cs).
 * Registered in <head> by Controls/GalleryView.cs, BEFORE the skin's CSS, so a skin can override any
 * rule here with an equally specific one.
 *
 * Layout follows gallery-grid.astro. Colours and fonts come from the SITE'S tokens; the fallbacks,
 * for a site that does not set them (or ships them blank), are the Triton skin's own defaults:
 *
 *   site token            used for                                            fallback
 *   --font-headline       title, subtitle, pills, badges, buttons             the skin's own font
 *   --font-body           description, counts                                 the skin's own font
 *   --color-primary       active pill, badge, subtitle, focus ring, button    #9E2065
 *   --color-secondary     pill hover, active sub-pill, button                 #00ABD8
 *   --color-tertiary      tertiary button                                     #6B6B6B
 *   --color-dark-shade    hover overlay, photo placeholder, button hover      #222222
 *   --color-light-shade   (reserved)                                          #E6E6E6
 *
 * They arrive as --tg-site-*, copied by the inline script after each section, and only when they
 * hold a value: a token declared blank (`--color-primary:;`) would otherwise defeat var()'s fallback.
 *
 * Per-gallery overrides, set on `.tg { … }` (or `#tg-<moduleId>`), win over the tokens:
 *   --triton-gallery-accent  --triton-gallery-accent-contrast  --triton-gallery-count
 *   --triton-gallery-scrim   --triton-gallery-placeholder      --triton-gallery-gap
 *   --triton-gallery-pill-radius  --triton-gallery-max-width
 * The tile shape is a module setting (it is written into the grid's style attribute).
 *
 * State classes, set by script: .js / .js-reveal on the section (inline script), .is-loaded on a
 * tile (its <img> onload), .is-visible on a tile (gallery.js). Without script none apply and the
 * gallery simply shows, fully visible.
 */

.tg {
  --tg-primary: var(--tg-site-color-primary, #9e2065);
  --tg-secondary: var(--tg-site-color-secondary, #00abd8);
  --tg-tertiary: var(--tg-site-color-tertiary, #6b6b6b);
  --tg-dark: var(--tg-site-color-dark-shade, #222);
  --tg-light: var(--tg-site-color-light-shade, #e6e6e6);

  --tg-accent: var(--triton-gallery-accent, var(--tg-primary));
  --tg-accent-contrast: var(--triton-gallery-accent-contrast, #fff);
  --tg-scrim-color: var(--triton-gallery-scrim, color-mix(in srgb, var(--tg-dark) 55%, transparent));
  --tg-placeholder: var(--triton-gallery-placeholder, color-mix(in srgb, var(--tg-dark) 10%, transparent));
  --tg-gap: var(--triton-gallery-gap, 20px);
  --tg-radius: var(--triton-gallery-pill-radius, 999px);

  container-type: inline-size;
  display: flex;
  flex-direction: column;
  max-width: var(--triton-gallery-max-width, 1248px);
  margin-inline: auto;
  /* The space below the whole section (grid, pager and buttons), not below the grid alone. */
  padding-bottom: clamp(4rem, 5vw, 6.25rem);
  /* No fallback on purpose: with no --font-body token this is unset, i.e. the skin's own font. */
  font-family: var(--tg-site-font-body);
}

.tg-title,
.tg-subtitle,
.tg-pill,
.tg-badge,
.tg-button {
  font-family: var(--tg-site-font-headline);
}

.tg-toolbar {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 8px;
}

.tg-settings-button {
  font: inherit;
  font-size: 0.875rem;
  padding: 6px 14px;
  border: 1px solid currentColor;
  border-radius: 4px;
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.tg-title {
  text-align: center;
  margin: 0 0 10px;
  text-wrap: balance;
}

/* The Triton skin's __subtitle: a short uppercase line between the title and the copy. */
.tg-subtitle {
  text-align: center;
  margin: -2px auto 12px;
  max-width: 1034px;
  color: var(--tg-primary);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-wrap: balance;
}

.tg-desc {
  text-align: center;
  max-width: 1034px;
  margin: 0 auto 0.5rem;
}

/* Editors only. Muted so it does not read as page copy. */
.tg-notice {
  text-align: center;
  font-size: 0.875rem;
  opacity: 0.7;
  margin: 1rem auto;
  padding: 1.5rem;
  border: 1px dashed currentColor;
  max-width: 720px;
}

/* --- Filter pills ------------------------------------------------------- */
.tg-filters {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 8px;
}

/* display:flex above would otherwise beat the [hidden] attribute on the sub-rows. */
.tg-filters[hidden] {
  display: none;
}

.tg-filters--sub {
  margin-top: 12px;
}

.tg-pill {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 40px;
  margin: 0;
  padding: 0 20px;
  border: 0;
  border-radius: var(--tg-radius);
  background: transparent;
  box-shadow: inset 0 0 0 1px currentColor;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1;
  text-transform: uppercase;
  color: inherit;
  cursor: pointer;
  transition: background 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;
}

.tg-pill:hover {
  box-shadow: inset 0 0 0 2px var(--tg-secondary);
  color: var(--tg-secondary);
}

.tg-pill:focus-visible {
  outline: 2px solid var(--tg-accent);
  outline-offset: 3px;
}

.tg-pill.is-active {
  background: var(--tg-accent);
  box-shadow: inset 0 0 0 1px var(--tg-accent);
  color: var(--tg-accent-contrast);
}

.tg-pill.is-active:hover {
  color: var(--tg-accent-contrast);
}

.tg-filters--sub .tg-pill {
  height: 34px;
  font-size: 0.8rem;
}

/* The second row reads as a level down: secondary, not primary. */
.tg-filters--sub .tg-pill.is-active {
  background: var(--tg-secondary);
  box-shadow: inset 0 0 0 1px var(--tg-secondary);
}

.tg-count {
  font-family: var(--tg-site-font-body);
  font-weight: 400;
  font-size: 0.8em;
  color: var(--triton-gallery-count, currentColor);
  opacity: 0.8;
}

.tg-pill.is-active .tg-count {
  color: inherit;
  opacity: 1;
}

/* --- Grid --------------------------------------------------------------- */
.tg-grid {
  display: grid;
  grid-template-columns: repeat(var(--tg-columns, 4), 1fr);
  gap: var(--tg-gap);
  margin-top: 16px;
}

/*
 * Every tile's box is fixed by its aspect ratio (the module's tile width × height), so the grid
 * has its final height in the first paint. Loading then happens inside those boxes:
 *   1. placeholder — the tile's background plus a light sweep, until the photo arrives;
 *   2. photo       — fades in from a slight blur and zoom once loaded (.is-loaded);
 *   3. tile        — rises into place when scrolled into view (.is-visible), cascading.
 * Only opacity and transform animate, and neither counts as layout shift.
 */
.tg-tile {
  position: relative;
  aspect-ratio: var(--tg-ratio, 297 / 306);
  overflow: hidden;
  background: var(--tg-placeholder);
}

.tg-tile[hidden] {
  display: none;
}

.tg.js .tg-tile::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(100deg, transparent 20%, rgba(255, 255, 255, 0.28) 50%, transparent 80%);
  transform: translateX(-100%);
  animation: tg-sweep 1.3s ease-in-out infinite;
  pointer-events: none;
}

.tg.js .tg-tile.is-loaded::before {
  content: none;
}

@keyframes tg-sweep {
  to {
    transform: translateX(100%);
  }
}

.tg-trigger {
  position: absolute;
  inset: 0;
  display: block;
}

.tg-trigger img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  transition:
    opacity 0.6s ease,
    filter 0.7s ease,
    transform 1.1s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.tg.js .tg-tile:not(.is-loaded) .tg-trigger img {
  opacity: 0;
  filter: blur(10px);
  transform: scale(1.08);
}

/* A slow push-in on hover, under the scrim. */
.tg-tile.is-loaded:hover .tg-trigger img {
  transform: scale(1.05);
}

.tg.js-reveal .tg-tile {
  opacity: 0;
  transform: translateY(24px) scale(0.97);
  transition:
    opacity 0.55s ease var(--tg-delay, 0ms),
    transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) var(--tg-delay, 0ms);
}

.tg.js-reveal .tg-tile.is-visible {
  opacity: 1;
  transform: none;
}

/* Used for one frame when a filter replays the reveal, so tiles hide instantly rather than fading out. */
.tg-grid.tg-no-transition .tg-tile {
  transition: none;
}

.tg-badge {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  padding: 6px 14px;
  background: var(--tg-accent);
  color: var(--tg-accent-contrast);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.45px;
  text-transform: uppercase;
  line-height: 1;
  pointer-events: none;
}

.tg-scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--tg-scrim-color);
  color: #fff;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.tg-tile:hover .tg-scrim,
.tg-tile:focus-within .tg-scrim {
  opacity: 1;
}

.tg-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Album layout -------------------------------------------------------
 * Layout "albums": a tile per album (.tg-albums), and the album view (.tg-album-view: banner, sub
 * pills, the photo grid above). One is [hidden]. The tile and the banner share the view-transition
 * name "tg-hero" while gallery.js swaps them, so one morphs into the other.
 * Override on .tg: --triton-gallery-album-columns (3), --triton-gallery-album-height (270px),
 * --triton-gallery-album-hover (the title colour on hover).
 */
.tg-albums {
  display: grid;
  grid-template-columns: repeat(var(--triton-gallery-album-columns, 3), 1fr);
  column-gap: var(--tg-gap);
  row-gap: 30px;
  margin-top: 16px;
}

.tg-albums[hidden],
.tg-album-view[hidden] {
  display: none;
}

.tg-album {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: var(--triton-gallery-album-height, 270px);
  overflow: hidden;
  background: var(--tg-placeholder);
  color: #fff;
  text-align: center;
  text-decoration: none;
}

.tg-album::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.7) 80%);
}

.tg-album:hover,
.tg-album:focus-visible {
  color: var(--triton-gallery-album-hover, var(--tg-site-color-primary, #00abd8));
}

.tg-album:focus-visible {
  outline: 2px solid var(--tg-accent);
  outline-offset: 3px;
}

.tg-album-img {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100% !important;
  max-width: none;
  object-fit: cover;
  transition: opacity 0.5s ease, transform 1s ease;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.tg-album:hover .tg-album-img,
.tg-album:focus-visible .tg-album-img {
  transform: scale(1.2);
}

.tg-album-details {
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: 1;
  box-sizing: border-box;
  width: 100%;
  padding: 1rem 20px;
  text-align: left;
  transition: max-height 1.5s ease, opacity 1s ease, background 0.5s ease;
}

.tg-album:hover .tg-album-details,
.tg-album:focus-visible .tg-album-details {
  background: rgba(0, 0, 0, 0.65);
}

.tg-album-title {
  margin: 0;
  color: inherit;
  font-family: var(--tg-site-font-headline);
  font-size: clamp(1.1rem, 5vw, 1.35rem);
  font-weight: 400;
  line-height: 1.1;
  text-transform: uppercase;
  transition: color 1s ease;
}

.tg-album-more {
  display: flex;
  justify-content: flex-end;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.5s ease, opacity 0.3s ease;
}

.tg-album:hover .tg-album-more,
.tg-album:focus-visible .tg-album-more {
  max-height: 2.5rem;
  opacity: 1;
}

.tg-album-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  color: #fff;
  font-size: 1.15rem;
  text-align: left;
  transform: translateY(5%);
  transition: all 0.3s ease;
}

.tg-album:hover .tg-album-cta {
  transform: translateY(0);
}

.tg-album:hover .tg-album-cta:hover {
  color: var(--tg-tertiary);
}

.tg-album-arrow {
  transition: transform 0.3s ease;
}

.tg-album:hover .tg-album-arrow {
  transform: translateX(3px);
}

/* The album's banner: its cover, name and photo count, and the way back. */
.tg-album-view {
  margin-top: 16px;
}

.tg-banner {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 4px;
  box-sizing: border-box;
  min-height: clamp(180px, 22vw, 280px);
  padding: 72px 20px 20px;
  overflow: hidden;
  background: var(--tg-dark);
  color: #fff;
}

.tg-banner::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0) 35%, rgba(0, 0, 0, 0.7) 90%);
}

.tg-banner-img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100% !important;
  max-width: none;
  object-fit: cover;
}

/* No cover yet (the page has not opened an album): no broken-image icon. */
.tg-banner-img:not([src]) {
  display: none;
}

.tg-banner-title {
  margin: 0;
  color: inherit;
  font-family: var(--tg-site-font-headline);
  font-size: clamp(1.5rem, 4vw, 2.25rem);
  font-weight: 400;
  line-height: 1.1;
  text-transform: uppercase;
  outline: none;
}

.tg-banner-count {
  font-size: 0.95rem;
  opacity: 0.85;
}

.tg-back {
  position: absolute;
  top: 18px;
  left: 20px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border-radius: var(--tg-radius);
  background: rgba(0, 0, 0, 0.4);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #fff;
  font-family: var(--tg-site-font-headline);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  text-transform: uppercase;
  transition: background 0.2s ease, color 0.2s ease;
}

.tg-back:hover,
.tg-back:focus-visible {
  background: var(--tg-accent);
  color: var(--tg-accent-contrast);
}

.tg-back:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.tg-back-arrow {
  transition: transform 0.25s ease;
}

.tg-back:hover .tg-back-arrow {
  transform: translateX(-3px);
}

.tg-album-view .tg-filters--sub {
  margin-top: 20px;
}

/* Entrances. The album tiles rise back in one after another (the morphing hero excepted); without
   view transitions the album view fades up. */
@keyframes tg-rise {
  from {
    opacity: 0;
    transform: translateY(24px) scale(0.97);
  }
}

.tg-albums.is-entering .tg-album:not(.is-hero) {
  animation: tg-rise 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  animation-delay: calc(var(--tg-i, 0) * 60ms);
}

.tg-album-view.is-entering .tg-banner {
  animation: tg-rise 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

::view-transition-group(tg-hero) {
  animation-duration: 0.6s;
  animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* The site's sticky header, lifted into its own layer (gallery.js) for the moment of the morph so the
   hero passes under it, not over it. It does not change, so it shows its new state only: no fade. */
::view-transition-group(tg-site-bar) {
  z-index: 2;
  animation: none;
}

::view-transition-old(tg-site-bar) {
  display: none;
}

::view-transition-new(tg-site-bar) {
  animation: none;
}

/* The tile and the banner have different shapes: crop, don't stretch. */
::view-transition-image-pair(tg-hero) {
  overflow: hidden;
}

::view-transition-old(tg-hero),
::view-transition-new(tg-hero) {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- Pager -------------------------------------------------------------
 * Matches the filter pills: outlined, the current page filled with the accent.
 */
.tg-pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 28px;
}

.tg-pager[hidden] {
  display: none;
}

.tg-page {
  min-width: 40px;
  height: 40px;
  margin: 0;
  padding: 0 12px;
  border: 0;
  border-radius: var(--tg-radius);
  background: transparent;
  box-shadow: inset 0 0 0 1px currentColor;
  color: inherit;
  font-family: var(--tg-site-font-headline);
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: background 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;
}

.tg-page:hover:not(:disabled):not(.is-current) {
  box-shadow: inset 0 0 0 2px var(--tg-secondary);
  color: var(--tg-secondary);
}

.tg-page:focus-visible {
  outline: 2px solid var(--tg-accent);
  outline-offset: 3px;
}

.tg-page.is-current {
  background: var(--tg-accent);
  box-shadow: inset 0 0 0 1px var(--tg-accent);
  color: var(--tg-accent-contrast);
  cursor: default;
}

.tg-page--step {
  font-size: 1.25rem;
}

.tg-page:disabled {
  opacity: 0.35;
  cursor: default;
}

.tg-page-gap {
  min-width: 20px;
  text-align: center;
  opacity: 0.6;
}

/* --- Buttons ------------------------------------------------------------
 * They also carry the Triton skin's `button button--primary|secondary|tertiary`, and the skin's
 * CSS loads after this file, so on a Triton site its rules apply; these mirror _button.scss so the
 * buttons look the same on a skin without those classes.
 */
.tg-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 19px;
  justify-content: center;
  margin-top: 26px;
}

.tg-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 12px 15px;
  border: none;
  color: #fff;
  font-size: 1.042rem;
  font-weight: 700;
  text-transform: uppercase;
  text-decoration: none;
  transition: all 0.3s ease;
}

.tg-button:focus-visible {
  outline: 2px solid var(--tg-primary);
  outline-offset: 3px;
}

.tg-button--primary {
  background: var(--tg-primary);
}

.tg-button--primary:hover {
  background: var(--tg-secondary);
  color: #fff;
}

.tg-button--secondary {
  background: var(--tg-secondary);
}

.tg-button--secondary:hover {
  background: var(--tg-primary);
  color: #fff;
}

.tg-button--tertiary {
  background: var(--tg-tertiary);
}

.tg-button--tertiary:hover {
  background: var(--tg-dark);
  color: var(--tg-primary);
}

/*
 * Container queries, not media queries: a DNN pane can be a sidebar on a wide screen. Two columns
 * below 1023px of available width, and it stays at two below that, as the Astro grid does.
 */
@container (max-width: 1023px) {
  .tg-grid {
    grid-template-columns: repeat(min(2, var(--tg-columns, 4)), 1fr);
  }

  .tg-albums {
    grid-template-columns: repeat(min(2, var(--triton-gallery-album-columns, 3)), 1fr);
  }
}

/* Narrow, or no hover to reveal it: the album tiles show their details from the start. */
@container (max-width: 576px) {
  .tg-albums {
    grid-template-columns: 1fr;
  }

  .tg-album {
    height: var(--triton-gallery-album-height-small, 250px);
  }

  .tg-album .tg-album-details {
    background: rgba(0, 0, 0, 0.65);
  }

  .tg-album .tg-album-more {
    max-height: 2.5rem;
    opacity: 1;
  }
}

@media (hover: none) {
  .tg-album .tg-album-details {
    background: rgba(0, 0, 0, 0.65);
  }

  .tg-album .tg-album-more {
    max-height: 2.5rem;
    opacity: 1;
  }
}

@container (max-width: 560px) {
  /* The bar scrolls sideways rather than stacking into a column of pills. */
  .tg-filters {
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
    gap: 8px;
    scrollbar-width: none;
  }

  .tg-filters::-webkit-scrollbar {
    display: none;
  }

  .tg-pill {
    flex: 0 0 auto;
  }

  .tg-buttons {
    flex-direction: column;
    align-items: stretch;
  }
}

/* The inline script also skips the scroll reveal here; this covers the CSS-only effects. */
@media (prefers-reduced-motion: reduce) {
  .tg.js .tg-tile::before {
    animation: none;
  }

  .tg-trigger img,
  .tg.js .tg-tile:not(.is-loaded) .tg-trigger img,
  .tg-tile.is-loaded:hover .tg-trigger img {
    filter: none;
    transform: none;
    transition: opacity 0.3s ease;
  }

  .tg-album:hover .tg-album-img,
  .tg-album:focus-visible .tg-album-img {
    transform: none;
  }
}
