/*
 * Universal block effects: entrance animation, hover, sticky, overlays,
 * and shape dividers.
 *
 * Loaded on every page, because the extension layer applies to core
 * blocks too and there is no cheap "does this page use it" signal. It is
 * deliberately small and contains no per-block values: those are
 * generated into the head as custom properties, so a page with forty
 * animated blocks adds forty short rules rather than forty keyframe
 * sets.
 *
 * The starting state of an entrance animation lives here rather than in
 * the generated CSS. That matters: it means a block never paints in its
 * final position and then jump-starts, even if the generated stylesheet
 * arrives late.
 */

/* ------------------------------------------------------------------ */
/* Entrance animation                                                  */
/* ------------------------------------------------------------------ */

.twu-x-anim {
  transition:
    opacity var(--twu-x-duration, 600ms) cubic-bezier(0.22, 0.61, 0.36, 1) var(--twu-x-delay, 0ms),
    transform var(--twu-x-duration, 600ms) cubic-bezier(0.22, 0.61, 0.36, 1) var(--twu-x-delay, 0ms);
  will-change: opacity, transform;
}

/*
 * Only hide the block once the script has confirmed it is running.
 * Without the html gate, a visitor with JavaScript disabled or a failed
 * script load would meet a page of permanently invisible content.
 */
html.twu-x-motion .twu-x-anim:not(.is-visible) {
  opacity: 0;
}

html.twu-x-motion .twu-x-anim--fade-up:not(.is-visible) { transform: translate3d(0, var(--twu-x-distance, 24px), 0); }
html.twu-x-motion .twu-x-anim--fade-down:not(.is-visible) { transform: translate3d(0, calc(var(--twu-x-distance, 24px) * -1), 0); }
html.twu-x-motion .twu-x-anim--fade-left:not(.is-visible) { transform: translate3d(var(--twu-x-distance, 24px), 0, 0); }
html.twu-x-motion .twu-x-anim--fade-right:not(.is-visible) { transform: translate3d(calc(var(--twu-x-distance, 24px) * -1), 0, 0); }
html.twu-x-motion .twu-x-anim--zoom-in:not(.is-visible) { transform: scale(0.94); }
html.twu-x-motion .twu-x-anim--zoom-out:not(.is-visible) { transform: scale(1.06); }
html.twu-x-motion .twu-x-anim--rise:not(.is-visible) { transform: translate3d(0, var(--twu-x-distance, 24px), 0) scale(0.97); }

.twu-x-anim.is-visible {
  opacity: 1;
  transform: none;
}

/* ------------------------------------------------------------------ */
/* Hover effects                                                       */
/* ------------------------------------------------------------------ */

/*
 * Gated behind hover: hover so a touch device never gets stuck in a
 * hover state after a tap, which is what happens when these are applied
 * unconditionally.
 */
@media (hover: hover) {
  [class*="twu-x-hover--"] {
    transition: transform 260ms ease, box-shadow 260ms ease, filter 260ms ease;
  }

  .twu-x-hover--lift:hover { transform: translateY(-6px); box-shadow: 0 18px 40px rgba(8, 22, 37, 0.18); }
  .twu-x-hover--grow:hover { transform: scale(1.03); }
  .twu-x-hover--shrink:hover { transform: scale(0.97); }
  .twu-x-hover--glow:hover { box-shadow: 0 0 0 3px var(--wp--preset--color--brass, #069ec6); }
  .twu-x-hover--tilt:hover { transform: perspective(800px) rotateX(2deg) rotateY(-2deg) translateY(-4px); }
}

/* ------------------------------------------------------------------ */
/* Sticky                                                              */
/* ------------------------------------------------------------------ */

/*
 * position: sticky silently does nothing when any ancestor has
 * overflow other than visible. That is the single most common reason a
 * sticky block "does not work", so the ancestors the theme controls are
 * corrected here rather than left to be rediscovered.
 */
.twu-x-sticky { will-change: transform; }

.has-twu-sticky-descendant,
.twu-page-body:has(.twu-x-sticky),
.wp-block-columns:has(.twu-x-sticky),
.wp-block-group:has(.twu-x-sticky) {
  overflow: visible;
}

/* ------------------------------------------------------------------ */
/* Overlay and blend                                                   */
/* ------------------------------------------------------------------ */

.twu-x-has-overlay { position: relative; isolation: isolate; }

.twu-x-overlay {
  position: absolute;
  z-index: 0;
  inset: 0;
  display: block;
  pointer-events: none;
}

/*
 * The overlay sits above the background and below the content, so every
 * real child needs its own stacking context. :not() on the injected
 * elements keeps the overlay and dividers out of the promotion.
 */
.twu-x-has-overlay > *:not(.twu-x-overlay):not(.twu-x-shape) {
  position: relative;
  z-index: 1;
}

/* ------------------------------------------------------------------ */
/* Shape dividers                                                      */
/* ------------------------------------------------------------------ */

.twu-x-has-shape { position: relative; }

.twu-x-shape {
  position: absolute;
  z-index: 1;
  left: 0;
  width: 100%;
  overflow: hidden;
  line-height: 0;
  pointer-events: none;
}

.twu-x-shape svg {
  display: block;
  width: 100%;
  height: 100%;
}

.twu-x-shape--top { top: 0; }
.twu-x-shape--bottom { bottom: 0; }

/* A top divider points into the section; a bottom one points out of it. */
.twu-x-shape--top svg { transform: scaleY(-1); }
.twu-x-shape.is-flipped svg { transform: scaleX(-1); }
.twu-x-shape--top.is-flipped svg { transform: scale(-1, -1); }
.twu-x-shape.is-inverted svg { transform: scaleY(-1); }
.twu-x-shape--top.is-inverted svg { transform: none; }

/* ------------------------------------------------------------------ */
/* Reduced motion                                                      */
/* ------------------------------------------------------------------ */

/*
 * Not a softened version: everything animated arrives in its final
 * state immediately and stays there. Sticky and overlays are unaffected
 * because neither of them moves.
 */
@media (prefers-reduced-motion: reduce) {
  html.twu-x-motion .twu-x-anim,
  html.twu-x-motion .twu-x-anim:not(.is-visible) {
    opacity: 1;
    transform: none;
    transition: none;
  }

  [class*="twu-x-hover--"] { transition: none; }

  .twu-x-hover--lift:hover,
  .twu-x-hover--grow:hover,
  .twu-x-hover--shrink:hover,
  .twu-x-hover--tilt:hover {
    transform: none;
  }
}

/* ------------------------------------------------------------------ */
/* Editor affordances                                                  */
/* ------------------------------------------------------------------ */

/*
 * In the canvas nothing is ever animated away or removed. A block set
 * to hide on mobile, or behind a display condition, is dimmed and
 * labelled instead, so it can still be selected and edited.
 */
.editor-styles-wrapper .twu-x-anim {
  opacity: 1;
  transform: none;
  transition: none;
}

.editor-styles-wrapper .twu-x-editor-hidden {
  position: relative;
  opacity: 0.45;
  outline: 1px dashed rgba(161, 58, 49, 0.6);
  outline-offset: 2px;
}

.editor-styles-wrapper .twu-x-editor-conditional {
  position: relative;
  outline: 1px dashed rgba(6, 158, 198, 0.7);
  outline-offset: 2px;
}

.editor-styles-wrapper .twu-x-editor-hidden::after,
.editor-styles-wrapper .twu-x-editor-conditional::after {
  position: absolute;
  z-index: 30;
  top: 0;
  right: 0;
  padding: 2px 6px;
  background: #1a3f67;
  color: #fff;
  font-family: sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  line-height: 1.4;
  text-transform: uppercase;
  pointer-events: none;
}

.editor-styles-wrapper .twu-x-editor-hidden::after { content: "Hidden at this width"; }
.editor-styles-wrapper .twu-x-editor-conditional::after { content: "Conditional"; }

.editor-styles-wrapper .twu-x-editor-sticky {
  box-shadow: inset 3px 0 0 rgba(6, 158, 198, 0.8);
}
