@keyframes dropFall {
  0% {
    transform: translate(-50%, -50%) translateY(-82vh) scale(.58, .88);
    opacity: 0;
  }
  38% { opacity: 1; }
  72% {
    transform: translate(-50%, -50%) translateY(12px) scale(1.07, .95);
  }
  86% {
    transform: translate(-50%, -50%) translateY(-4px) scale(.99, 1.025);
  }
  100% {
    transform: translate(-50%, -50%) translateY(0) scale(1);
    opacity: 1;
  }
}

/* V01 atmosphere, kept asset-free so the hero is reliable on every device. */
.hero-image {
  background:
    linear-gradient(180deg, transparent 0 48.8%, rgba(255,255,255,.34) 49.05%, rgba(47,99,116,.11) 49.35%, transparent 50.15%),
    radial-gradient(ellipse at 50% 38%, rgba(255,255,255,.98) 0%, rgba(241,249,251,.88) 23%, rgba(216,234,239,.36) 47%, rgba(216,234,239,0) 69%),
    linear-gradient(180deg, #deedf2 0%, #d9e9ee 45%, #afc8d0 51%, #92aeb9 68%, #7899a6 100%);
  transform: none;
  filter: none;
}

.veil {
  background:
    radial-gradient(circle at 50% 35%, rgba(255,255,255,.42) 0%, rgba(255,255,255,0) 40%),
    linear-gradient(180deg, rgba(247,251,252,.08) 0%, rgba(247,251,252,.015) 47%, rgba(20,65,82,.07) 100%);
}

.perception-stage {
  --morph: 0;
  --drop-x: 50%;
  --drop-y: 50%;
  --drop-r: 0px;
  isolation: isolate;
}

/* CSS/fallback semantic layers. */
.base-word,
.notice-word {
  position: absolute;
  left: 50%;
  top: 50%;
  margin: 0;
  font-size: clamp(1rem, 1.45vw, 1.25rem);
  font-weight: 760;
  line-height: 1;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(7, 27, 46, .76);
  transform: translate(-50%, -50%);
  transform-origin: center;
  white-space: nowrap;
  pointer-events: none;
}

.base-word {
  z-index: 4;
  opacity: calc(1 - var(--morph));
  transition: opacity .16s linear;
}

.notice-word {
  z-index: 2;
  opacity: var(--morph);
  transition: opacity .16s linear;
}

/*
  WebGL metaphor: OBSERVE is the upper coating, NOTICE sits underneath the water.
  Both semantic layers become full-stage overlays so the drop coordinates and
  radial masks share exactly the same coordinate space.
*/
.perception-stage.webgl-active .base-word,
.perception-stage.webgl-active .notice-word {
  inset: 0;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  margin: 0;
  transform: none;
  font-size: 0;
  opacity: 1;
  transition: none;
  white-space: normal;
}

.perception-stage.webgl-active .base-word::before,
.perception-stage.webgl-active .notice-word::before {
  display: inline-block;
  font-size: clamp(1rem, 1.45vw, 1.25rem);
  font-weight: 760;
  line-height: 1;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(7, 27, 46, .76);
  white-space: nowrap;
}

.perception-stage.webgl-active .base-word::before {
  content: 'OBSERVE';
}

.perception-stage.webgl-active .notice-word::before {
  content: 'NOTICE';
}

/* Upper OBSERVE coating: a tighter optical core follows the physical drop. */
.perception-stage.webgl-active .base-word {
  -webkit-mask-image: radial-gradient(
    circle at var(--drop-x) var(--drop-y),
    transparent 0,
    transparent calc(var(--drop-r) * 0.56),
    #000 calc(var(--drop-r) * 0.96),
    #000 100%
  );
  mask-image: radial-gradient(
    circle at var(--drop-x) var(--drop-y),
    transparent 0,
    transparent calc(var(--drop-r) * 0.56),
    #000 calc(var(--drop-r) * 0.96),
    #000 100%
  );
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* NOTICE is exposed only in the inner optical core, and its strength follows overlap. */
.perception-stage.webgl-active .notice-word {
  opacity: var(--morph);
  -webkit-mask-image: radial-gradient(
    circle at var(--drop-x) var(--drop-y),
    #000 0,
    #000 calc(var(--drop-r) * 0.56),
    transparent calc(var(--drop-r) * 0.96),
    transparent 100%
  );
  mask-image: radial-gradient(
    circle at var(--drop-x) var(--drop-y),
    #000 0,
    #000 calc(var(--drop-r) * 0.56),
    transparent calc(var(--drop-r) * 0.96),
    transparent 100%
  );
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* CSS fallback: used when WebGL2 is unavailable or loses context. */
.lens {
  z-index: 5;
  animation: dropFall 1.62s cubic-bezier(.2, .82, .25, 1) both;
  touch-action: none;
  overflow: hidden;
  border-radius: 53% 47% 51% 49% / 58% 54% 46% 42%;
  border: 1px solid rgba(255,255,255,.78);
  background:
    radial-gradient(ellipse at 30% 22%, rgba(255,255,255,.96) 0 4%, rgba(255,255,255,.60) 5%, rgba(255,255,255,.10) 15%, transparent 24%),
    radial-gradient(ellipse at 72% 77%, rgba(34,102,126,.16) 0%, rgba(34,102,126,.06) 28%, transparent 56%),
    radial-gradient(circle at 48% 43%, rgba(255,255,255,.12) 0%, rgba(118,181,198,.08) 62%, rgba(255,255,255,.27) 100%);
  box-shadow:
    inset 8px 9px 18px rgba(255,255,255,.48),
    inset -13px -15px 25px rgba(25,82,103,.15),
    inset 0 0 0 1px rgba(255,255,255,.22),
    0 2px 3px rgba(255,255,255,.34),
    0 18px 34px rgba(20,67,86,.16),
    0 32px 55px rgba(20,67,86,.08);
  backdrop-filter: blur(.55px) saturate(1.24) contrast(1.10) brightness(1.035);
  -webkit-backdrop-filter: blur(.55px) saturate(1.24) contrast(1.10) brightness(1.035);
  filter: drop-shadow(0 7px 7px rgba(25,75,94,.10));
}

.lens::before {
  content: '';
  position: absolute;
  width: 30%;
  height: 13%;
  left: 17%;
  top: 14%;
  border-radius: 50%;
  background: linear-gradient(100deg, rgba(255,255,255,.94), rgba(255,255,255,.18));
  filter: blur(1.2px);
  transform: rotate(-26deg);
  opacity: .92;
  pointer-events: none;
}

.lens::after {
  content: '';
  position: absolute;
  left: 22%;
  right: 17%;
  bottom: 8%;
  height: 14%;
  border-radius: 50%;
  background: radial-gradient(ellipse, rgba(29,97,121,.24) 0%, rgba(255,255,255,.18) 36%, transparent 72%);
  filter: blur(3px);
  opacity: .72;
  pointer-events: none;
}

/* WebGL renders only the moving water optics. */
.drop-webgl-canvas {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Keep the DOM lens as motion/hit-test anchor, but let WebGL draw the water. */
.perception-stage.webgl-active .lens {
  opacity: 0 !important;
  background: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  filter: none !important;
}

.perception-stage.webgl-active .lens::before,
.perception-stage.webgl-active .lens::after {
  display: none !important;
}

.perception-stage.webgl-active .hint {
  z-index: 7;
}

.hint {
  transition: opacity .25s ease, color .25s ease;
}

/* Desktop: give the word more runway and pull the whole interaction left. */
@media (min-width: 781px) {
  .perception-stage {
    right: clamp(0px, 1.4vw, 24px);
    bottom: 9vh;
    width: min(980px, 62vw);
    height: clamp(255px, 30vh, 340px);
  }

  .base-word,
  .notice-word,
  .perception-stage.webgl-active .base-word::before,
  .perception-stage.webgl-active .notice-word::before {
    font-size: clamp(2.4rem, 3.7vw, 4.35rem);
    font-weight: 700;
    letter-spacing: .11em;
  }

  .base-word,
  .perception-stage.webgl-active .base-word::before {
    color: rgba(7, 27, 46, .78);
  }

  .notice-word,
  .perception-stage.webgl-active .notice-word::before {
    color: rgba(7, 27, 46, .72);
  }

  .lens {
    width: clamp(166px, 12.8vw, 212px);
  }

  .hint {
    bottom: -2px;
    letter-spacing: .19em;
  }
}

@media (max-width: 780px) {
  .lens {
    width: 132px;
    animation-duration: 1.88s;
  }

  .base-word,
  .notice-word {
    font-size: .98rem;
    letter-spacing: .15em;
  }

  .perception-stage.webgl-active .base-word::before,
  .perception-stage.webgl-active .notice-word::before {
    font-size: .98rem;
    letter-spacing: .15em;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lens { animation: none; }
}


/* LT WebGL semantic words */
html[lang="lt"] .perception-stage.webgl-active .base-word::before {
  content: 'PAŽVELK';
}

html[lang="lt"] .perception-stage.webgl-active .notice-word::before {
  content: 'PASTEBĖK';
}
