/* ═══════════════════════════════════════════════════════════════════════════
 * animations.css — v2.0.0
 *
 * ONE change is active in this file: STEP 1 (the LCP fix, marked ★ below).
 * STEP 2, 3 and 4 are documented but commented out. Enable them one at a time
 * and re-measure between each, per the project's one-change-at-a-time rule.
 *
 * ── STEP 1 ★ ACTIVE — LCP element started at opacity: 0 ────────────────────
 *   .landing-section h1.landing-title is the page's LCP element. It was
 *   animated with a keyframe whose `from` state is opacity: 0. Chrome does not
 *   count a fully transparent element as painted, so LCP could not be reported
 *   until the fade had progressed — regardless of how fast the HTML, CSS and
 *   fonts arrived.
 *
 *   Measured before this change (PageSpeed Insights, Aug 2026):
 *     Time to first byte ......    30 ms
 *     Element render delay ... 1,450 ms   (98% of LCP, zero resource load time)
 *
 *   Fix: drop `opacity` from the keyframe and keep `transform`. The heading is
 *   opaque from the first frame, so it counts as painted immediately, while the
 *   slide-in entrance is preserved. This is not a metric trick — the headline
 *   genuinely becomes readable sooner.
 *
 *   Pairs with random-slogan-animation.js v2, which stops rewriting the same
 *   h1 via innerHTML on first visits. Both touch the same LCP element; fixing
 *   only one of them will not move the number.
 *
 * ── STEP 2 — .landing-title .home-video can never recover ──────────────────
 * ── STEP 3 — gradientShift animates a non-compositable property ────────────
 * ── STEP 4 — 100vw causes horizontal overflow and layout shift ─────────────
 * ── STEP 5 — hover transition targets the wrong property ───────────────────
 *   See the notes at each site below.
 * ═══════════════════════════════════════════════════════════════════════════ */

@import url("./horizontal-gallery.css");
@import url("./map.css");

/* -------- Home Animation -------- */

/* ⚠️ STEP 2 — UNRECOVERABLE HIDDEN STATE. Left as-is for now; do not enable the
   fallback below until the Vimeo player error is diagnosed.

   This element is set to opacity: 0 with nothing in any stylesheet restoring
   it. It is visible only if GSAP runs and animates it back. If that script
   fails, is blocked by the cookie banner, or errors out, the video area stays
   permanently invisible to the user with no CSS-level recovery.

   The PageSpeed screenshots show a Vimeo "Player error" panel in exactly this
   region of the page across every capture. The two may well be the same
   incident. Diagnose the player first (Vimeo embed domain allowlist for
   cmt.ch), then decide whether this rule should keep a CSS safety net such as:

     .landing-title .home-video {
       animation: homeVideoReveal 0.01s linear 3s forwards;
     }
     @keyframes homeVideoReveal { to { opacity: 1; transform: none; } }

   That would reveal the element after 3s even if JS never runs. It will fight
   with GSAP if GSAP does run, so it needs testing on a staging copy first. */
.landing-title .home-video {
  opacity: 0;
  transform: translateY(40px);
}

/* -------- Logo Slider Animation -------- */
.has-global-padding:has(.logo-slider-section) {
  padding-left: 0 !important;
  padding-right: 0 !important;
}

/* ⚠️ STEP 4 — 100vw INCLUDES THE SCROLLBAR.
   On desktop, 100vw is wider than the visible viewport by the scrollbar width,
   which produces horizontal overflow. When the scrollbar appears or disappears
   during load, the layout jumps. This is the same class of problem as the
   100vh issue recorded in v1 §E, and a plausible contributor to CLS 0.092.

   Confirm first by expanding the "Layout shift culprits" insight in PageSpeed
   Insights — if this section is named there, replace the 100vw approach with:

     .logo-slider-section {
       position: relative;
       width: auto !important;
       left: auto !important;
       transform: none !important;
       margin-left: calc(-50vw + 50%);
       margin-right: calc(-50vw + 50%);
     }

   Verify on desktop, tablet and mobile before keeping it. */
.logo-slider-section {
  position: relative;
  width: 100vw !important;
  left: 50% !important;
  transform: translateX(-50%) !important;
}

.slider-row {
  position: relative;
  /* Note: `width: 100%` below is immediately overridden by `width: 100vw`.
     The first declaration has no effect and can be deleted once STEP 4 is
     resolved one way or the other. */
  width: 100%;
  width: 100vw;
  padding: 40px 0;
  overflow: hidden;

  /* v2 FIX: fade left/right using a mask instead of a solid-color overlay.
     This makes the logos fade into whatever the section background actually is
     (solid color, gradient, or image) with no color-matching required. */
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 160px,
    #000 calc(100% - 160px),
    transparent 100%
  );
  mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 160px,
    #000 calc(100% - 160px),
    transparent 100%
  );
}

/* v2 FIX: removed the ::before/::after overlays that used a hardcoded
   background color (#5c5078c2). They are no longer needed since the
   mask-image above now creates the fade effect. */

/* Note: `will-change: transform` keeps a compositing layer alive for the entire
   session, not just while the slider is moving. For one always-animating
   element this is an acceptable trade, but it is worth removing if the logo
   slider is ever changed to animate only on scroll into view. */
.slider-track {
  display: flex;
  align-items: center;
  width: max-content;
  will-change: transform;
}

/* ⚠️ STEP 5 — the transition lists `opacity`, but every hover rule below
   changes `transform`. The scale-up therefore snaps instead of easing. This is
   a plain visual bug with no performance impact. When ready, change to:

     transition: transform 0.3s ease, opacity 0.3s ease; */
.slider-track .logo-item {
  flex-shrink: 0;
  width: 128px;
  height: 44px;
  margin: 0 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.3s ease;
}

.slider-track .logo-item:hover {
  transform: scale(1.05);
}

.slider-track .logo-item img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
}

.slider-track .logo-item.small-logo {
  transform: scale(1.3);
}

.slider-track .logo-item.small-logo:hover {
  transform: scale(1.35);
}

/* ----- Changing Text Animation -----*/
.changing-slider-frame {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  position: relative;
  min-height: 1.5em;
  vertical-align: middle;
}

ul.changing-slides {
  list-style-type: none;
  margin: 0;
  padding: 0;
  position: relative;
}

.changing-slide {
  font-size: inherit;
  line-height: 1.3;
  color: var(--color-yk-secondary);
  margin: 0;
  padding: 0;
  white-space: nowrap;
  font-weight: inherit;
  display: block;
  height: auto;
}

@media (max-width: 768px) {
  .changing-slider-frame {
    min-height: 1.5em;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * Random Slogan Animation
 *
 * ★ STEP 1 — THE ONE ACTIVE CHANGE IN THIS FILE.
 *
 * Before:
 *   @keyframes sloganFadeIn {
 *     from { opacity: 0; transform: translateY(10px); }
 *     to   { opacity: 1; transform: translateY(0); }
 *   }
 *
 * `opacity: 0` on the LCP element is what pushed Element render delay to
 * 1,450 ms. Removing it — and only it — leaves the heading opaque from the
 * first painted frame while keeping the slide-in.
 *
 * Optional refinement if the entrance now feels too abrupt: raise the starting
 * offset (e.g. translateY(16px)) or lengthen the duration. Do NOT reintroduce
 * opacity, and do not "soften" it by starting at a small non-zero opacity such
 * as 0.05 — that would restore the score while leaving the text unreadable,
 * which is the wrong side of the trade.
 *
 * Consider also honouring reduced-motion preferences:
 *   @media (prefers-reduced-motion: reduce) {
 *     .landing-section h1.landing-title { animation: none; }
 *   }
 * ═══════════════════════════════════════════════════════════════════════════ */
.landing-section h1.landing-title {
  animation: sloganFadeIn 0.5s ease-in-out;
}

@keyframes sloganFadeIn {
  from {
    transform: translateY(10px);
  }
  to {
    transform: translateY(0);
  }
}

/* -------- Gradient Buttons Animation -------- */
/* -- Make buttons clickable -- */
.wp-block-cover.gradient-button {
  position: relative;
  cursor: pointer;
}

.wp-block-cover.gradient-button .wp-block-cover__inner-container {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
}

.wp-block-cover.gradient-button
  .wp-block-cover__inner-container
  :where(h1, h2, h3, h4, h5, h6, p) {
  margin: 0;
}

.wp-block-cover.gradient-button .wp-block-cover__inner-container a {
  position: static;
}

.wp-block-cover.gradient-button .wp-block-cover__inner-container a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}
/* ----- End of Clickable CSS ----- */

.gradient-button {
  position: relative;
  overflow: hidden;
  cursor: pointer;
  transition: transform 0.3s ease;
}

.gradient-button:hover {
  transform: translateY(-5px);
}

/* Ensure button content is clickable */
.gradient-button > * {
  position: relative;
  z-index: 2;
}

/* ⚠️ STEP 3 — THESE ARE THE "5 non-composited animations" IN THE REPORT.
   `background-position` cannot be handled by the compositor, so each of the two
   ::before layers is repainted every frame, forever, on a box sized 200% x 200%
   of its parent. This runs for the whole session whether or not the button is
   in view, and feeds directly into "Minimize main-thread work — 2.4 s".

   Composited replacement — same drifting-gradient effect, transform only:

     .gradient-button.left-button::before {
       content: "";
       position: absolute;
       top: -50%;
       left: -50%;
       width: 400%;
       height: 200%;
       background: linear-gradient(45deg, #818181 0%, #5d5179 25%,
                                   #b3b470 50%, #98bcd4 75%, #818181 100%);
       animation: gradientSlide 8s ease infinite;
       z-index: 0;
     }
     @keyframes gradientSlide {
       0%, 100% { transform: translateX(0); }
       50%      { transform: translateX(-25%); }
     }

   The motion path is not pixel-identical to background-position, so this needs
   a side-by-side visual check with the client before it ships. Consider also
   pausing it out of view, which removes the cost entirely:

     @media (prefers-reduced-motion: reduce) {
       .gradient-button::before { animation: none; }
     } */

/* Gradient background layer - Left button */
.gradient-button.left-button::before {
  content: "";
  position: absolute;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  background: linear-gradient(
    45deg,
    #818181 0%,
    #5d5179 25%,
    #b3b470 50%,
    #98bcd4 75%,
    #818181 100%
  );
  background-size: 200% 200%;
  animation: gradientShift 8s ease infinite;
  z-index: 0;
}

/* Gradient background layer - Right button */
.gradient-button.right-button::before {
  content: "";
  position: absolute;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  background: linear-gradient(
    45deg,
    #98bcd4 0%,
    #b3b470 25%,
    #5d5179 50%,
    #818181 75%,
    #98bcd4 100%
  );
  background-size: 200% 200%;
  animation: gradientShift 8s ease infinite;
  z-index: 0;
}

/* Keep WordPress background visible but overlay gradient */
.gradient-button .wp-block-cover__background {
  position: absolute;
  z-index: 1;
  opacity: 0.3 !important;
}

/* Default gradient animation */
@keyframes gradientShift {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

/* Hover state - will be controlled by GSAP */
.gradient-button.hover-active::before {
  animation: none;
}

/* -------- Product Animation -------- */

@media (min-width: 768px) {
  .product-box {
    transition: transform 0.3s ease;
  }
}

@media (min-width: 768px) {
  .product-box:hover {
    transform: scale(1.05);
    z-index: 10;
  }
}

/* ----- Desktop and Tablet View (>1366px) ----- */
@media screen and (min-width: 1366px) {
  .lower-columns {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 100%;
  }
}

/* ----- Tablet View (<1365px) ----- */
@media screen and (max-width: 1365px) and (min-width: 767px) {
  .referenzen-section {
    padding-bottom: var(--wp--preset--spacing--50) !important;
  }
  .referenzen-section h2 {
    padding-top: 0 !important;
  }
}

/* ----- Mobile View (<768px) ----- */
@media screen and (max-width: 767px) {
  .slider-row {
    padding: 24px 0;

    /* v2 FIX: mask width shrinks on mobile to match the old ::before/::after width */
    -webkit-mask-image: linear-gradient(
      to right,
      transparent 0,
      #000 80px,
      #000 calc(100% - 80px),
      transparent 100%
    );
    mask-image: linear-gradient(
      to right,
      transparent 0,
      #000 80px,
      #000 calc(100% - 80px),
      transparent 100%
    );
  }

  .slider-track .logo-item {
    width: 100px;
    height: 32px;
    margin: 0 28px;
  }
}
