/* ==========================================================================
   Content Block: activewerbung/textmedia
   --------------------------------------------------------------------------
   Heading, rich text and images / videos. The template sets the options as
   classes (no inline styles, CSP friendly):

   .textmedia--beside | --above | --below          position of the media
   .textmedia--media-left | --media-right          beside: side of the media
   .textmedia--valign-top | --valign-center        beside: vertical alignment of the text
   .textmedia--width-30 … -70                      beside: width of the media in %
   .textmedia--text-first                          beside: text above the media on small screens
   .textmedia--align-left | -center | -right       alignment of small images (max. width)
   .textmedia--bleed                               image tile to the screen edge (layout start page)
   .textmedia--cols-1 … -6, .textmedia--ratio-*    media grid / visible slides of the slider
   .textmedia--space-less-space | -default | -more-space   space text ↔ media
   Text (headings, eyebrow, alignment): RTE only, styled by .richtext

   Global parts: .section (spacing / background, Css/Global/layout.css),
   .richtext (Css/Global/typography.css), .container.

   01. Settings
   02. Layout: stack and beside
   03. Image tile (bleed)
   04. Media grid
   05. Figure: image, video, caption, lightbox, link
   06. Slider (Swiper, Assets/frontend.js)
   ========================================================================== */


/* ==========================================================================
   01. SETTINGS
   ========================================================================== */
.textmedia {
  --tm-gap: clamp(2rem, 4.5vw, 5.75rem);              /* text ↔ media, 61px at 1360 */
  --tm-media-gap: clamp(0.75rem, 1.25vw, 1.25rem);    /* between images */
  --media-width: 50;
  --cols: 1;
  --cols-md: 1;
  --cols-sm: 1;
}
.textmedia--space-less-space { --tm-gap: clamp(1.25rem, 2.25vw, 2.5rem); }
.textmedia--space-more-space { --tm-gap: clamp(3rem, 7vw, 8rem); }

.textmedia--width-30 { --media-width: 30; }
.textmedia--width-40 { --media-width: 40; }
.textmedia--width-60 { --media-width: 60; }
.textmedia--width-70 { --media-width: 70; }

/* Columns: desktop / tablet (40rem+) / smartphone. Same steps as the sizes attribute in Frontend.html */
.textmedia--cols-2 { --cols: 2; --cols-md: 2; --cols-sm: 2; }
.textmedia--cols-3 { --cols: 3; --cols-md: 3; --cols-sm: 2; }
.textmedia--cols-4 { --cols: 4; --cols-md: 3; --cols-sm: 2; }
.textmedia--cols-5 { --cols: 5; --cols-md: 3; --cols-sm: 2; }
.textmedia--cols-6 { --cols: 6; --cols-md: 3; --cols-sm: 3; }

.textmedia--ratio-16-9 { --ratio: 16 / 9; }
.textmedia--ratio-3-2 { --ratio: 3 / 2; }
.textmedia--ratio-4-3 { --ratio: 4 / 3; }
.textmedia--ratio-1-1 { --ratio: 1 / 1; }
.textmedia--ratio-4-5 { --ratio: 4 / 5; }


/* ==========================================================================
   02. LAYOUT
   Small screens: one column. Media above the text for "above" and for
   "beside" (consistent order when several elements follow each other),
   unless "text first" is chosen. From 64rem: beside = two columns.
   ========================================================================== */
.textmedia__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--tm-gap);
}
.textmedia--above .textmedia__media,
.textmedia--beside:not(.textmedia--text-first) .textmedia__media { order: -1; }

@media (min-width: 64rem) {
  .textmedia--beside .textmedia__inner {
    --media-col: calc((100% - var(--tm-gap)) * var(--media-width) / 100);
    grid-template-columns: minmax(0, 1fr) var(--media-col);
    align-items: start;
  }
  .textmedia--beside.textmedia--media-left .textmedia__inner {
    grid-template-columns: var(--media-col) minmax(0, 1fr);
  }
  .textmedia--beside .textmedia__media,
  .textmedia--beside .textmedia__text { grid-row: 1; }
  .textmedia--media-left .textmedia__media,
  .textmedia--media-right .textmedia__text { grid-column: 1; }
  .textmedia--media-left .textmedia__text,
  .textmedia--media-right .textmedia__media { grid-column: 2; }

  .textmedia--valign-center .textmedia__inner { align-items: center; }
}


/* ==========================================================================
   03. IMAGE TILE (BLEED)
   Like the start page of the layout: the media reaches the screen edge (thin
   frame --space-tile), tiles follow each other with the same thin joint.
   The text keeps the content edge of the page.
   ========================================================================== */
.textmedia--bleed.textmedia--beside:not([class*="section--space-top-"]) { --space-top: var(--space-tile); }
.textmedia--bleed.textmedia--beside:not([class*="section--space-bottom-"]) { --space-bottom: var(--space-tile); }

.textmedia--bleed .textmedia__inner { padding-inline: var(--space-tile); }

/* Text on the content edge: container width minus the tile frame of the parent */
.textmedia--bleed .textmedia__text {
  width: min(var(--container), 100% - 2 * (var(--gutter) - var(--space-tile)));
  margin-inline: auto;
}

/* Small screens: tiles are stacked, the text needs air to the next / previous tile */
.textmedia--bleed.textmedia--beside .textmedia__inner { padding-bottom: var(--tm-gap); }
.textmedia--bleed.textmedia--beside.textmedia--text-first .textmedia__inner {
  padding-top: var(--tm-gap);
  padding-bottom: 0;
}

@media (min-width: 64rem) {
  /* Beside: image half + text half, joint = tile gap, text centered in its half */
  .textmedia--bleed.textmedia--beside .textmedia__inner,
  .textmedia--bleed.textmedia--beside.textmedia--text-first .textmedia__inner {
    gap: var(--space-tile);
    padding-block: 0;
  }
  .textmedia--bleed.textmedia--beside .textmedia__text {
    width: auto;
    margin: 0;
    padding: clamp(2.5rem, 5vw, 5rem) var(--tm-gap);
  }
}

/* Captions below tile images start at the content edge like the text */
.textmedia--bleed .textmedia__caption { padding-inline: calc(var(--gutter) - var(--space-tile)); }

/* One image beside the text fills the height of the row (min. its aspect ratio, default 3:2) */
.textmedia__media--fill :is(.textmedia__image, .textmedia__video) {
  aspect-ratio: var(--ratio, 3 / 2);
  object-fit: cover;
}
@media (min-width: 64rem) {
  /* Height: at least the aspect ratio of the column (cqi = width of .textmedia__inner),
     taller when the text needs more space. No aspect-ratio here: with a stretched
     height it would widen the column. */
  .textmedia--bleed .textmedia__inner { container-type: inline-size; }
  .textmedia__media--fill {
    display: block;
    position: relative;
    align-self: stretch;
    min-height: calc((100cqi - var(--space-tile)) * var(--media-width) / 100 / (var(--ratio, 3 / 2)));
  }
  .textmedia__media--fill .textmedia__figure {
    position: absolute;
    inset: 0;
  }
  .textmedia__media--fill :is(.textmedia__zoom, .textmedia__link, .textmedia__embed, .textmedia__frame, .textmedia__box) { height: 100%; }
  .textmedia__media--fill .textmedia__embed { aspect-ratio: auto; }
  .textmedia__media--fill :is(.textmedia__image, .textmedia__video) {
    height: 100%;
    aspect-ratio: auto;
  }
  /* Caption on the image (images without own link) */
  .textmedia__media--fill .textmedia__figure:not(:has(.textmedia__embed, .textmedia__video)) .textmedia__caption {
    position: absolute;
    inset: auto 0 0;
    margin: 0;
    padding: 2.5rem 1.25rem 0.875rem;
    background: linear-gradient(transparent, rgb(0 0 0 / 0.6));
    color: var(--c-white);
    pointer-events: none;
  }
  /* Videos: caption below (it would cover the player controls), the video takes the remaining height */
  .textmedia__media--fill .textmedia__figure:has(.textmedia__embed, .textmedia__video) {
    display: flex;
    flex-direction: column;
  }
  .textmedia__media--fill .textmedia__figure:has(.textmedia__embed, .textmedia__video) > :not(.textmedia__caption) {
    flex: 1 1 auto;
    min-height: 0;
  }
}


/* ==========================================================================
   04. MEDIA GRID
   grid      all the same size
   featured  first image over all columns, the others below
   masonry   original formats, filled column by column
   ========================================================================== */
.textmedia__media {
  display: grid;
  grid-template-columns: repeat(var(--cols-sm), minmax(0, 1fr));
  gap: var(--tm-media-gap);
  align-content: start;
}
.textmedia__media--featured > :first-child { grid-column: 1 / -1; }

.textmedia__media--masonry {
  display: block;
  columns: var(--cols-sm);
  column-gap: var(--tm-media-gap);
}
.textmedia__media--masonry > .textmedia__figure {
  break-inside: avoid;
  margin-bottom: var(--tm-media-gap);
}
.textmedia__media--masonry > .textmedia__figure:last-child { margin-bottom: 0; }

@media (min-width: 40rem) {
  .textmedia__media { grid-template-columns: repeat(var(--cols-md), minmax(0, 1fr)); }
  .textmedia__media--masonry { columns: var(--cols-md); }
}
@media (min-width: 64rem) {
  .textmedia__media { grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); }
  .textmedia__media--masonry { columns: var(--cols); }
}


/* ==========================================================================
   05. FIGURE
   ========================================================================== */
.textmedia__figure { min-width: 0; }

.textmedia__image,
.textmedia__video {
  width: 100%;
  height: auto;
}
.textmedia__video { background: var(--c-text); }

/* YouTube / Vimeo: fixed box (16:9 or the chosen aspect ratio). Iframe and the
   placeholder of the cookie manager fill it, so nothing jumps after consent */
.textmedia__embed {
  position: relative;
  aspect-ratio: var(--ratio, 16 / 9);
  overflow: hidden;
  background: var(--c-text);
}
.textmedia__embed > * {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Fixed aspect ratio (option): cut to fit */
.textmedia:not(.textmedia--ratio-auto) :is(.textmedia__image:not(.textmedia__image--natural), .textmedia__video) {
  aspect-ratio: var(--ratio);
  object-fit: cover;
}
/* "First large": thumbnails with the same format, even with "Original" */
.textmedia--ratio-auto .textmedia__media--featured > :not(:first-child) :is(.textmedia__image, .textmedia__video) {
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

/* Max. width (logos, graphics): natural size, aligned by the option */
.textmedia__image--natural {
  width: auto;
  max-width: 100%;
}
.textmedia--align-center .textmedia__figure:has(.textmedia__image--natural) { text-align: center; }
.textmedia--align-center .textmedia__image--natural { margin-inline: auto; }
.textmedia--align-right .textmedia__figure:has(.textmedia__image--natural) { text-align: end; }
.textmedia--align-right .textmedia__image--natural { margin-inline-start: auto; }

/* ---- Title of the image (file reference "Titel") on the image, like the layout ("Fassadenanstrich") ----
   Size follows the image width (cqi of the frame). Text shadow + a soft dark glow in the middle
   behind the text (readable on bright photos, the edges of the photo stay untouched). */
.textmedia__frame {
  position: relative;
  display: block;
  container-type: inline-size;
}
.textmedia__title {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 1rem clamp(1rem, 8cqi, 4rem);
  color: var(--c-white);
  font-size: clamp(1.125rem, 0.6rem + 4cqi, 2.25rem);
  font-weight: 300;
  line-height: 1.2;
  text-align: center;
  text-wrap: balance;
  text-shadow: 0 1px 2px rgb(0 0 0 / 0.45), 0 2px 18px rgb(0 0 0 / 0.45);
  background: radial-gradient(ellipse 60% 45% at 50% 50%, rgb(0 0 0 / 0.28), transparent 100%);
  pointer-events: none;
}
/* Slider: keep the title free of the arrows */
.textmedia__slide .textmedia__title { padding-inline: calc(var(--tap) + 1.25rem); }

.textmedia__caption {
  margin-top: 0.625em;
  font-size: var(--fs-small);
  line-height: 1.45;
  opacity: 0.8;
}

/* ---- Lightbox / link: whole image clickable, slight zoom on hover ---- */
.textmedia__zoom,
.textmedia__link {
  position: relative;
  display: block;
  overflow: hidden;
}
.textmedia__zoom { cursor: zoom-in; }
.textmedia__image--natural:where(.textmedia__zoom *, .textmedia__link *) { display: inline-block; }

:is(.textmedia__zoom, .textmedia__link) .textmedia__image { transition: scale 0.6s ease; }
:is(.textmedia__zoom, .textmedia__link):hover .textmedia__image { scale: 1.03; }

/* Image with link and lightbox: link + lightbox button side by side in a box of the image size */
.textmedia__box {
  position: relative;
  display: block;
}
.textmedia__zoom-button {
  position: absolute;
  right: 0.75rem;
  bottom: 0.75rem;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  border-radius: 50%;
  background: rgb(255 255 255 / 0.85);
  box-shadow: 0 1px 6px rgb(0 0 0 / 0.2);
  color: var(--c-text);
  font-size: 1.375rem;
  cursor: zoom-in;
  transition: background-color var(--transition), color var(--transition);
}
.textmedia__zoom-button:hover {
  background: var(--c-text);
  color: var(--c-white);
}
/* Focus on photos: white ring with dark halo */
.textmedia__zoom-button:focus-visible {
  outline: 2px solid var(--c-white);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--c-text);
}

/* Magnifier: always visible on touch screens, on hover / focus with a mouse */
.textmedia__zoom-icon {
  position: absolute;
  right: 0.75rem;
  bottom: 0.75rem;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.85);
  color: var(--c-text);
  font-size: 1.375rem;
  transition: opacity var(--transition);
}
@media (hover: hover) {
  .textmedia__zoom-icon { opacity: 0; }
  .textmedia__zoom:is(:hover, :focus-visible) .textmedia__zoom-icon { opacity: 1; }
}


/* ==========================================================================
   06. SLIDER
   "Spalten" = visible slides, depending on the width of the slider itself
   (container query, also beside the text). Steps = breakpoints in frontend.js:
   480px: 2, 640px: 3, 800px: all "Spalten". Before Swiper starts, the slides
   already have these widths (no jump). Fixed aspect ratio (3:2 with "Original"),
   so all slides have the same height.
   Controls on the images: arrows left / right, dots at the bottom. The bar has
   the height of the images (not of the captions below), calculated from the
   slider width (cqi), the visible slides and the aspect ratio.
   ========================================================================== */
.textmedia__media--slider {
  --per-view: 1;
  position: relative;
  display: block;
  min-width: 0;
  container-type: inline-size;
}
/* --per-view on the slides and on the controls (descendants of the container).
   All rules have the same specificity, so the wider step (later rule) wins. */
@container (min-width: 480px) {
  :is(.textmedia--cols-2, .textmedia--cols-3, .textmedia--cols-4, .textmedia--cols-5, .textmedia--cols-6) :is(.textmedia__slide, .textmedia__slider-controls) { --per-view: 2; }
}
@container (min-width: 640px) {
  :is(.textmedia--cols-3, .textmedia--cols-4, .textmedia--cols-5, .textmedia--cols-6) :is(.textmedia__slide, .textmedia__slider-controls) { --per-view: 3; }
}
@container (min-width: 800px) {
  .textmedia--cols-4 :is(.textmedia__slide, .textmedia__slider-controls) { --per-view: 4; }
  .textmedia--cols-5 :is(.textmedia__slide, .textmedia__slider-controls) { --per-view: 5; }
  .textmedia--cols-6 :is(.textmedia__slide, .textmedia__slider-controls) { --per-view: 6; }
}

/* Swiping must not select images / captions or start a native image drag */
.textmedia__swiper {
  -webkit-user-select: none;
  user-select: none;
}
.textmedia__swiper img {
  -webkit-user-drag: none;
  user-drag: none;
}

.textmedia .textmedia__slide {
  width: calc((100% - (var(--per-view) - 1) * var(--tm-media-gap)) / var(--per-view));
  height: auto;
  margin-right: var(--tm-media-gap);          /* = spaceBetween in frontend.js */
}
.textmedia__slide :is(.textmedia__image:not(.textmedia__image--natural), .textmedia__video, .textmedia__embed) {
  aspect-ratio: var(--ratio, 3 / 2);
  object-fit: cover;
}

/* ---- Controls on the images ---- */
.textmedia__slider-controls {
  --slide-w: calc((100cqi - (var(--per-view) - 1) * var(--tm-media-gap)) / var(--per-view));
  position: absolute;
  inset: 0 0 auto;
  z-index: 2;
  height: calc(var(--slide-w) / (var(--ratio, 3 / 2)));
  pointer-events: none;                       /* only the buttons are clickable, the images stay draggable */
}
/* All slides visible: Swiper hides the arrows (…-lock), the whole controls too */
.textmedia__slider-controls:has(> .swiper-button-lock) { display: none; }

.textmedia__slider-arrow {
  position: absolute;
  top: 50%;
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  border-radius: 50%;
  background: rgb(255 255 255 / 0.8);
  color: var(--c-text);
  font-size: 1.25rem;
  translate: 0 -50%;
  pointer-events: auto;
  transition: background-color var(--transition), opacity var(--transition);
}
.textmedia__slider-arrow--prev { left: 0.75rem; }
.textmedia__slider-arrow--next { right: 0.75rem; }
.textmedia__slider-arrow:hover { background: var(--c-white); }
/* Endless slider: never disabled. Only if there are too few images for the loop
   (Swiper falls back to start / end): hidden at the first / last image */
.textmedia__slider-arrow:disabled {
  opacity: 0;
  pointer-events: none;
}

/* Bar at the bottom: (pause button +) dots, white on dark (readable on any image) */
.textmedia__slider-bar {
  position: absolute;
  bottom: 0.75rem;
  left: 50%;
  display: flex;
  align-items: center;
  gap: 0.25rem;
  max-width: calc(100% - 2 * var(--tap) - 3rem);   /* free of the arrows */
  padding: 0.125rem 0.5rem;
  border-radius: 999px;
  background: rgb(0 0 0 / 0.3);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--c-white);
  translate: -50% 0;
  pointer-events: auto;
}

/* Dots: 8px visible, 24px tap target (WCAG 2.5.8).
   Parent class: must win over Swiper's .swiper-pagination-bullets.swiper-pagination-horizontal (full width, left 0) */
.textmedia__slider-bar .textmedia__slider-pagination {
  --swiper-pagination-color: var(--c-white);
  --swiper-pagination-bullet-inactive-color: var(--c-white);
  --swiper-pagination-bullet-inactive-opacity: 0.5;
  position: static;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  width: auto;
}

/* Pause / play (option "Automatisch weiterblättern") */
.textmedia__slider-autoplay {
  display: grid;
  flex-shrink: 0;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  color: inherit;
  font-size: 1rem;
}
.textmedia__slider-autoplay[data-playing="true"] .textmedia__slider-icon-play,
.textmedia__slider-autoplay[data-playing="false"] .textmedia__slider-icon-pause { display: none; }
.textmedia__slider-pagination .swiper-pagination-bullet {
  width: 1.5rem;
  height: 1.5rem;
  margin: 0 !important;
  padding: 0.5rem;
  background-clip: content-box;
  opacity: var(--swiper-pagination-bullet-inactive-opacity);
  transition: opacity var(--transition);
}
.textmedia__slider-pagination .swiper-pagination-bullet-active { opacity: 1; }

/* Autoplay running (.is-autoplay, frontend.js): the active dot stays a circle and fills up
   clockwise until the next image (--autoplay-progress 0 → 1 from Swiper's autoplayTimeLeft).
   Slightly larger (10px) so the fill is visible. Stops with the autoplay (keyboard focus),
   plain dot again when the visitor stops it. */
.textmedia__slider-pagination .swiper-pagination-bullet { position: relative; }
.is-autoplay .textmedia__slider-pagination .swiper-pagination-bullet-active {
  padding: 0.4375rem;                              /* 10px visible, 24px tap target */
  background-color: rgb(255 255 255 / 0.45);
}
.is-autoplay .textmedia__slider-pagination .swiper-pagination-bullet-active::after {
  content: "";
  position: absolute;
  inset: 0.4375rem;
  border-radius: 50%;
  background: conic-gradient(var(--c-white) calc(var(--autoplay-progress, 0) * 1turn), transparent 0);
}

/* Focus on images: white ring with dark halo, visible on any image */
.textmedia__slider-controls :focus-visible {
  outline: 2px solid var(--c-white);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--c-text);
}

/* Without JavaScript: scroll sideways */
@media (scripting: none) {
  .textmedia__swiper {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
  }
  .textmedia__slide { scroll-snap-align: start; }
  .textmedia__slider-controls { display: none; }
}
