/* =========================================================================
   Blora Design 2.0 - Text Effects add-on
   Visual baseline: legacy/v1/blora.css lines 2951-3015, 4380-4450
   ========================================================================= */

@layer blora.addons {
  .blora-text-fx {
    --blora-fx-dur: 2.4s;

    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    max-width: 100%;
    transform: translateZ(0);
    white-space: pre-wrap;
    line-height: 1.4;
  }

  .blora-text-fx.is-clickable {
    cursor: pointer;
  }

  .blora-text-fx__ch {
    display: inline-block;
    transform: translateZ(0);
    transform-origin: center center;
    white-space: pre;
    will-change: transform, opacity, text-shadow;
  }

  /* Split chars overlap while animating; the shared selection token is already
     an opaque, light mix (primary + canvas) so overlaps stay flat. */
  .blora-text-fx__ch::selection {
    background: var(--blora-color-action-selection-bg);
    color: var(--blora-color-text-primary);
  }

  .blora-text-fx--big.is-play {
    animation: blora-fx-big var(--blora-fx-dur, 2.5s) cubic-bezier(0.12, 0.75, 0.25, 1) infinite;
  }

  .blora-text-fx--small.is-play {
    animation: blora-fx-small var(--blora-fx-dur, 2.5s) cubic-bezier(0.12, 0.75, 0.25, 1) infinite;
  }

  .blora-text-fx--shake.is-play {
    animation: blora-fx-shake-box var(--blora-fx-dur, 2.4s) ease-in-out infinite;
  }

  .blora-text-fx--shake.is-play .blora-text-fx__ch {
    animation: blora-fx-shake-fluid var(--blora-fx-dur, 2.4s) ease-in-out infinite;
  }

  .blora-text-fx--nod.is-play {
    animation: blora-fx-nod-apple var(--blora-fx-dur, 2.4s) cubic-bezier(0.25, 0.1, 0.25, 1)
      infinite;
    transform-origin: center bottom;
  }

  .blora-text-fx--disperse.is-play .blora-text-fx__ch {
    animation: blora-fx-disperse var(--blora-fx-dur, 2.4s) cubic-bezier(0.16, 1, 0.3, 1) infinite;
  }

  .blora-text-fx--ripple.is-play .blora-text-fx__ch {
    animation: blora-fx-ripple-apple 1.3s cubic-bezier(0.25, 0.9, 0.4, 1) infinite;
    animation-delay: calc(var(--i, 0) * 35ms);
    transform-origin: center bottom;
  }

  .blora-text-fx--bloom.is-play .blora-text-fx__ch {
    animation: blora-fx-bloom-apple 2.2s cubic-bezier(0.25, 1, 0.35, 1) infinite;
    animation-delay: calc(var(--i, 0) * 28ms);
    transform-origin: center bottom;
  }

  .blora-text-fx--jitter.is-play .blora-text-fx__ch {
    animation: blora-fx-jitter-apple 80ms steps(2, start) infinite;
  }

  .blora-text-fx--jitter.is-play .blora-text-fx__ch:nth-child(2n) {
    animation-duration: 70ms;
    animation-direction: reverse;
  }

  .blora-text-fx--jitter.is-play .blora-text-fx__ch:nth-child(3n) {
    animation-duration: 90ms;
  }

  .blora-text-fx--jitter.is-play .blora-text-fx__ch:nth-child(5n) {
    animation-duration: 65ms;
  }
}

@keyframes blora-fx-big {
  0%,
  8% {
    transform: scale(1);
  }

  30%,
  48% {
    transform: scale(1.28);
  }

  64% {
    transform: scale(0.97);
  }

  74% {
    transform: scale(1.01);
  }

  82%,
  100% {
    transform: scale(1);
  }
}
@keyframes blora-fx-small {
  0%,
  8% {
    transform: scale(1);
  }

  30%,
  48% {
    transform: scale(0.74);
  }

  64% {
    transform: scale(1.03);
  }

  74% {
    transform: scale(0.99);
  }

  82%,
  100% {
    transform: scale(1);
  }
}
@keyframes blora-fx-shake-box {
  0%,
  8%,
  42%,
  100% {
    transform: translateX(0);
  }

  13% {
    transform: translateX(-0.74em);
  }

  21% {
    transform: translateX(0.63em);
  }

  29% {
    transform: translateX(-0.42em);
  }

  36% {
    transform: translateX(0.26em);
  }
}
@keyframes blora-fx-shake-fluid {
  0%,
  8%,
  42%,
  100% {
    transform: scale(1);
    opacity: 1;
  }

  13% {
    transform: scale(
      calc(0.86 + (1 - var(--fx-ratio, 0.5)) * 0.38),
      calc(0.92 + (1 - var(--fx-ratio, 0.5)) * 0.22)
    );
    opacity: calc(0.65 + (1 - var(--fx-ratio, 0.5)) * 0.35);
  }

  21% {
    transform: scale(
      calc(0.86 + var(--fx-ratio, 0.5) * 0.38),
      calc(0.92 + var(--fx-ratio, 0.5) * 0.22)
    );
    opacity: calc(0.65 + var(--fx-ratio, 0.5) * 0.35);
  }

  29% {
    transform: scale(
      calc(0.92 + (1 - var(--fx-ratio, 0.5)) * 0.18),
      calc(0.96 + (1 - var(--fx-ratio, 0.5)) * 0.1)
    );
  }

  36% {
    transform: scale(
      calc(0.92 + var(--fx-ratio, 0.5) * 0.18),
      calc(0.96 + var(--fx-ratio, 0.5) * 0.1)
    );
  }
}
@keyframes blora-fx-nod-apple {
  0%,
  8% {
    transform: translateY(0) scale(1);
  }

  16% {
    transform: translateY(0.42em) scale(1.02, 0.92);
  }

  24% {
    transform: translateY(-0.1em) scale(0.99, 1.02);
  }

  32% {
    transform: translateY(0.21em) scale(1.01, 0.96);
  }

  40%,
  100% {
    transform: translateY(0) scale(1);
  }
}
@keyframes blora-fx-disperse {
  0%,
  15% {
    transform: translate3d(0, 0, 0) rotate(0deg) scale(1);
    opacity: 1;
  }

  22% {
    transform: translate3d(calc(var(--fx-x, 0) * -0.05), calc(var(--fx-y, -1em) * -0.05), 0)
      scale(0.94);
  }

  38% {
    transform: translate3d(var(--fx-x, 0.8em), var(--fx-y, -1em), 0) rotate(var(--fx-r, 15deg))
      scale(1.3);
    opacity: 0;
  }

  42% {
    transform: translate3d(0, 0, 0) scale(0.5);
    opacity: 0;
  }

  60%,
  100% {
    transform: translate3d(0, 0, 0) rotate(0deg) scale(1);
    opacity: 1;
  }
}
@keyframes blora-fx-ripple-apple {
  0%,
  35%,
  100% {
    transform: translate3d(0, 0, 0);
  }

  16% {
    transform: translate3d(0, -0.34em, 0);
  }
}
@keyframes blora-fx-bloom-apple {
  0%,
  25%,
  100% {
    transform: scale(1, 1) translateY(0);
    opacity: 0.85;
    text-shadow: none;
  }

  10% {
    transform: scale(1.13, 1.09) translateY(-0.03em);
    opacity: 1;
    text-shadow:
      0.2px 0 0 currentcolor,
      -0.2px 0 0 currentcolor;
  }
}
@keyframes blora-fx-jitter-apple {
  0% {
    transform: translate3d(0, 0, 0) rotate(0deg);
  }

  25% {
    transform: translate3d(-0.08em, 0.06em, 0) rotate(-1.5deg);
  }

  50% {
    transform: translate3d(0.07em, -0.07em, 0) rotate(1.2deg);
  }

  75% {
    transform: translate3d(-0.06em, -0.06em, 0) rotate(-0.8deg);
  }

  100% {
    transform: translate3d(0.08em, 0.06em, 0) rotate(1.4deg);
  }
}

/* ===== Migrated effects extras (no @layer 鈥?beat unlayered reset) ===== */

.blora-countdown {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--blora-space-2);
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
}

.blora-countdown__unit {
  display: grid;
  justify-items: center;
  gap: var(--blora-space-1);
  min-width: 2.75rem;
}

.blora-countdown__value {
  min-width: 2.2ch;
  color: var(--blora-color-text-emphasis);
  font-family: var(--blora-font-mono);
  font-size: var(--blora-text-2xl);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-align: center;
}

.blora-countdown__label {
  color: var(--blora-color-text-subtle);
  font-size: var(--blora-text-xs);
}

.blora-text-rotate {
  display: inline-grid;
  vertical-align: bottom;
  overflow: hidden;
}

.blora-text-rotate__item {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(0.35em);
  transition:
    opacity var(--blora-duration-base) var(--blora-easing-standard),
    transform var(--blora-duration-base) var(--blora-easing-standard);
  pointer-events: none;
}

.blora-text-rotate__item[data-active] {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.blora-watermark {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.blora-watermark__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: var(--blora-z-base);
  opacity: 0.14;
  background-repeat: repeat;
  background-position: center center;

  /* Never stretch a single stamp to fill the box */
  background-size: auto;
}

.blora-diff {
  --blora-diff-position: 50%;

  position: relative;
  overflow: hidden;
  border-radius: var(--blora-radius-lg);
  border: 1px solid var(--blora-color-border-subtle);
  aspect-ratio: var(--blora-diff-ratio, 16 / 9);
  background: var(--blora-color-surface-raised);
}

.blora-diff__item {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

/* Any pane content fills the frame: images, text, or components. */
.blora-diff__item > * {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
}

.blora-diff__item > :is(img, video, canvas) {
  display: block;
  object-fit: cover;
}

.blora-diff__item > :not(:is(img, video, canvas)) {
  overflow: auto;
}

.blora-diff__item--before {
  z-index: var(--blora-z-base);
  clip-path: inset(0 calc(100% - var(--blora-diff-position)) 0 0);
}

.blora-diff__divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--blora-diff-position);
  z-index: calc(var(--blora-z-base) + 1);
  width: 2px;
  transform: translateX(-50%);
  background: var(--blora-color-text-on-accent);
  box-shadow: var(--blora-shadow-2);
  pointer-events: none;
}

.blora-diff__divider::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 2rem;
  height: 2rem;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--blora-color-surface-default);
  border: 2px solid var(--blora-color-border-subtle);
  box-shadow: var(--blora-shadow-2);
}

.blora-diff__range {
  position: absolute;
  inset: 0;
  z-index: calc(var(--blora-z-base) + 2);
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
}

.blora-hover-gallery {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: var(--blora-gallery-ratio, 4 / 3);
  overflow: hidden;
  border: 1px solid var(--blora-color-border-subtle);
  border-radius: var(--blora-radius-lg);
  background: var(--blora-color-surface-raised);
  touch-action: pan-y;
  cursor: grab;
  user-select: none;
}

.blora-hover-gallery:active {
  cursor: grabbing;
}

.blora-hover-gallery:focus-visible {
  outline: 2px solid var(--blora-color-action-primary-default);
  outline-offset: 2px;
}

.blora-hover-gallery__track {
  display: flex;
  height: 100%;
  will-change: transform;
  transition: transform var(--blora-duration-slow, 0.35s) var(--blora-easing-standard);
}

.blora-hover-gallery__track.is-dragging {
  transition: none;
}

.blora-hover-gallery__item {
  flex: 0 0 100%;
  min-width: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}

.blora-hover-gallery--wide {
  --blora-gallery-ratio: 16 / 9;
}

.blora-hover-gallery__progress {
  position: absolute;
  left: var(--blora-space-3);
  right: var(--blora-space-3);
  bottom: var(--blora-space-3);
  z-index: calc(var(--blora-z-base) + 1);
  display: grid;
  grid-auto-flow: column;
  gap: var(--blora-space-1);
  pointer-events: none;
}

.blora-hover-gallery__progress span {
  height: 3px;
  border-radius: var(--blora-radius-full);
  background: color-mix(in srgb, var(--blora-color-text-on-accent) 35%, transparent);
}

.blora-hover-gallery__progress span[data-active] {
  background: var(--blora-color-text-on-accent);
}

/* Keyboard shortcut chip (v1 .blora-kbd) */
.blora-kbd,
kbd.blora-kbd,
kbd[data-blora-shortcut] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.75em;
  min-height: 1.75em;
  padding: 0.1em 0.45em;
  border: 1px solid var(--blora-color-border-subtle);
  border-bottom-width: 2px;
  border-radius: var(--blora-radius-xs);
  background: var(--blora-color-surface-raised);
  color: var(--blora-color-text-emphasis);
  font-family: var(--blora-font-mono);
  font-size: 0.82em;
  line-height: 1;
  box-shadow: 0 1px 0 var(--blora-color-surface-sunken);
  white-space: nowrap;
}
