/* splash.css - the opening screen.
 *
 * Two rules make this safe to put on the homepage at all:
 *   1. the overlay dismisses itself with a CSS animation that ends on
 *      `visibility: hidden`, so a script failure can never leave a stuck
 *      curtain over the page;
 *   2. it never takes pointer events, so even mid-animation the page is usable.
 * Skipping on repeat visits is decided in splash-guard.js, before first paint.
 */

.splash {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: grid;
  place-items: center;
  overflow: hidden;
  pointer-events: none;
  background:
    radial-gradient(120% 90% at 50% 42%, rgba(46, 232, 255, 0.12) 0%, transparent 62%),
    linear-gradient(180deg, #05070f 0%, #0a1230 52%, #05070f 100%);
  animation: splash-out 3.5s ease forwards;
}

/* Storage said this session has already seen it. The class lands before the
   first paint, so nothing flashes. */
.splash-skip .splash {
  display: none;
}

@keyframes splash-out {
  0%, 62% { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}

/* ---- the cloud. This is the layer that makes it 云雾散开 rather than a glow
   fading: the mass starts COVERING the middle and travels apart to the sides,
   so the wordmark is uncovered rather than just appearing under it.

   Each bank is a stack of blobs with organic radii rather than one ellipse -
   a perfect ellipse reads as a spotlight, not as weather. The bank carries the
   outward travel; each blob churns slowly on its own axis at the same time, so
   the interior keeps moving while the whole thing drifts. Two elements, two
   transforms, which CSS can compose; one element cannot. ------------------- */

.splash__bank {
  position: absolute;
  inset: -12% -8%;
  z-index: 1;
  background: radial-gradient(58% 44% at 50% 58%, rgba(176, 212, 255, 0.24) 0%, transparent 72%);
  filter: blur(32px);
  opacity: 0;
  animation: splash-bank 3.5s ease-out forwards;
}

.splash__bank--far {
  background: radial-gradient(52% 38% at 45% 62%, rgba(150, 190, 255, 0.2) 0%, transparent 74%);
  animation-delay: 0.12s;
}

@keyframes splash-bank {
  0% { opacity: 0; transform: scale(1.02); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: scale(1.34) translateY(-7%); }
}

.splash__mass {
  position: absolute;
  inset: 0;
  z-index: 3;
  animation: splash-part-left 3.5s cubic-bezier(0.34, 0.06, 0.24, 1) forwards;
}

.splash__mass--right {
  animation-name: splash-part-right;
}

.splash__mass i {
  position: absolute;
  /* A volumetric cloud, not a soft disc. Six stacked gradients give lit crowns
     along the top, a mid body with several lobes so the density varies, and a
     bluish shadowed underside. One radial gradient can only ever read as a
     spotlight - the thing this whole layer exists to avoid. The light comes
     from above in every lobe, which is what makes the stack read as one cloud
     rather than as unrelated blobs. */
  background:
    radial-gradient(34% 30% at 34% 26%, rgba(247, 251, 255, 0.74) 0%, rgba(214, 236, 255, 0.28) 52%, transparent 70%),
    radial-gradient(28% 24% at 60% 22%, rgba(240, 249, 255, 0.62) 0%, rgba(206, 232, 255, 0.22) 54%, transparent 72%),
    radial-gradient(24% 20% at 76% 40%, rgba(230, 244, 255, 0.5) 0%, transparent 72%),
    radial-gradient(48% 40% at 44% 50%, rgba(200, 228, 255, 0.5) 0%, rgba(176, 212, 255, 0.22) 56%, transparent 76%),
    radial-gradient(40% 34% at 66% 60%, rgba(186, 218, 255, 0.42) 0%, transparent 78%),
    radial-gradient(58% 28% at 50% 84%, rgba(108, 142, 200, 0.34) 0%, transparent 80%);
  filter: blur(20px);
  animation: splash-churn 3.5s ease-in-out forwards;
}

/* Four lumps a side, each with its own silhouette: two large masses and two
   smaller detail lobes sitting toward the edge that opens. A silhouette per
   element is what stops the stack reading as one stamp repeated. */
.splash__mass i:nth-child(1) { border-radius: 58% 42% 47% 53% / 46% 54% 43% 57%; }
.splash__mass i:nth-child(2) { border-radius: 44% 56% 62% 38% / 52% 44% 56% 48%; }
.splash__mass i:nth-child(3) { border-radius: 62% 38% 41% 59% / 55% 61% 39% 45%; }
.splash__mass i:nth-child(4) { border-radius: 48% 52% 55% 45% / 62% 38% 62% 38%; }

/* The detail lobes carry a tighter arrangement, so a big mass and a small one
   are never the same shape seen twice. */
.splash__mass i:nth-child(3),
.splash__mass i:nth-child(4) {
  background:
    radial-gradient(40% 34% at 42% 30%, rgba(246, 251, 255, 0.66) 0%, transparent 70%),
    radial-gradient(30% 26% at 66% 36%, rgba(224, 242, 255, 0.46) 0%, transparent 74%),
    radial-gradient(52% 42% at 48% 58%, rgba(190, 220, 255, 0.44) 0%, transparent 78%),
    radial-gradient(44% 26% at 54% 82%, rgba(112, 146, 204, 0.3) 0%, transparent 80%);
}

.splash__mass--left i:nth-child(1) { left: 0%;  top: 20%; width: 50vmin; height: 44vmin; }
.splash__mass--left i:nth-child(2) { left: 16%; top: 40%; width: 58vmin; height: 50vmin; }
.splash__mass--left i:nth-child(3) { left: 26%; top: 8%;  width: 30vmin; height: 26vmin; }
.splash__mass--left i:nth-child(4) { left: 34%; top: 52%; width: 26vmin; height: 22vmin; }

.splash__mass--right i:nth-child(1) { right: 0%;  top: 22%; width: 50vmin; height: 44vmin; }
.splash__mass--right i:nth-child(2) { right: 16%; top: 42%; width: 58vmin; height: 50vmin; }
.splash__mass--right i:nth-child(3) { right: 26%; top: 10%; width: 30vmin; height: 26vmin; }
.splash__mass--right i:nth-child(4) { right: 34%; top: 54%; width: 26vmin; height: 22vmin; }

@keyframes splash-churn {
  0% { transform: rotate(0deg) scale(1); }
  100% { transform: rotate(16deg) scale(1.14); }
}

/* Cover, hold, then open. The hold at 28% is what makes the parting read as a
   movement rather than as one long fade. */
@keyframes splash-part-left {
  0% { opacity: 0; transform: translate3d(7%, 0, 0) scale(1.04); }
  13% { opacity: 1; transform: translate3d(0, 0, 0) scale(1.05); }
  28% { opacity: 1; transform: translate3d(-6%, 0, 0) scale(1.07); }
  100% { opacity: 0; transform: translate3d(-72%, -4%, 0) scale(1.22); }
}

@keyframes splash-part-right {
  0% { opacity: 0; transform: translate3d(-7%, 0, 0) scale(1.04); }
  13% { opacity: 1; transform: translate3d(0, 0, 0) scale(1.05); }
  28% { opacity: 1; transform: translate3d(6%, 0, 0) scale(1.07); }
  100% { opacity: 0; transform: translate3d(72%, -4%, 0) scale(1.22); }
}

/* Foreground wisps, moving faster than the banks behind them - that speed
   difference is what gives the scene depth. */
.splash__wisp {
  position: absolute;
  z-index: 5;
  border-radius: 50%;
  filter: blur(24px);
  background: radial-gradient(ellipse at center, rgba(234, 246, 255, 0.42) 0%, transparent 70%);
  opacity: 0;
  animation: splash-wisp 3.5s ease-out forwards;
}

.splash__wisp--a { left: 12%; top: 36%; width: 44vmin; height: 26vmin; }
.splash__wisp--b { right: 10%; top: 50%; width: 40vmin; height: 24vmin; animation-delay: 0.18s; }

@keyframes splash-wisp {
  0% { opacity: 0; transform: translate3d(0, 4%, 0) scale(0.72); }
  26% { opacity: 0.85; }
  100% { opacity: 0; transform: translate3d(-46%, -10%, 0) scale(1.5); }
}

.splash__wisp--b {
  animation-name: splash-wisp-right;
}

@keyframes splash-wisp-right {
  0% { opacity: 0; transform: translate3d(0, 4%, 0) scale(0.72); }
  26% { opacity: 0.85; }
  100% { opacity: 0; transform: translate3d(46%, -12%, 0) scale(1.5); }
}

/* ---- the wordmark: wide and blurred, sharpening into place --------------- */
.splash__mark {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
}

.splash__mark strong {
  font-family: var(--home-display, "SF Pro Display", "PingFang SC", sans-serif);
  font-size: clamp(20px, 4vw, 36px);
  font-weight: 700;
  line-height: 1.1;
  color: var(--home-ink, #f0fbff);
  animation: splash-mark 3.5s cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}

.splash__mark span {
  font-family: var(--home-body, -apple-system, "PingFang SC", sans-serif);
  font-size: clamp(11px, 1.5vw, 13px);
  color: var(--home-muted, rgba(216, 222, 241, 0.7));
  animation: splash-sub 3.5s ease forwards;
  animation-delay: 0.5s;
  opacity: 0;
}

.splash__rule {
  width: min(46vw, 260px);
  height: 1px;
  margin-top: 4px;
  background: linear-gradient(90deg, transparent, var(--home-cyan, #2ee8ff), transparent);
  transform: scaleX(0);
  animation: splash-rule 2.4s cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
  animation-delay: 0.35s;
}

@keyframes splash-mark {
  0% { opacity: 0; letter-spacing: 0.6em; filter: blur(12px); }
  32% {
    opacity: 1;
    letter-spacing: 0.26em;
    filter: blur(0) drop-shadow(0 0 20px rgba(46, 232, 255, 0.42));
  }
  100% {
    opacity: 1;
    letter-spacing: 0.3em;
    filter: blur(0) drop-shadow(0 0 20px rgba(46, 232, 255, 0.42));
  }
}

@keyframes splash-sub {
  0% { opacity: 0; }
  40%, 82% { opacity: 1; }
  100% { opacity: 1; }
}

@keyframes splash-rule {
  to { transform: scaleX(1); }
}

/* Someone who asked their system not to animate things gets no opening at all,
   rather than a shorter one. */
@media (prefers-reduced-motion: reduce) {
  .splash {
    display: none;
  }
}

/* ---- rings. Two thin halos leaving the wordmark, staggered, so the opening
   has a beat in the middle instead of one long dissolve. ----------------- */
.splash__ring {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 34vmin;
  height: 34vmin;
  /* centred with margin rather than a transform, so the animation owns
     `transform` outright and cannot fight the positioning. */
  margin: -17vmin 0 0 -17vmin;
  border: 1px solid rgba(46, 232, 255, 0.55);
  border-radius: 50%;
  box-shadow:
    0 0 26px rgba(46, 232, 255, 0.3),
    inset 0 0 26px rgba(46, 232, 255, 0.18);
  opacity: 0;
  animation: splash-ring 3.5s cubic-bezier(0.2, 0.6, 0.3, 1) forwards;
}

.splash__ring--late {
  border-color: rgba(255, 79, 190, 0.45);
  box-shadow:
    0 0 26px rgba(255, 79, 190, 0.26),
    inset 0 0 26px rgba(255, 79, 190, 0.16);
  animation-delay: 0.55s;
}

@keyframes splash-ring {
  0% { opacity: 0; transform: scale(0.5); }
  20% { opacity: 0.85; }
  100% { opacity: 0; transform: scale(2.6); }
}

/* ---- motes. Fine dust lifting through the light, which is what makes the
   dissolve read as mist rather than as a fading rectangle. ---------------- */
.splash__field {
  position: absolute;
  inset: 0;
  z-index: 4;
  overflow: hidden;
}

.splash__mote {
  position: absolute;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: rgba(214, 242, 255, 0.92);
  box-shadow: 0 0 9px rgba(46, 232, 255, 0.85);
  opacity: 0;
  animation: splash-mote 3.5s ease-out forwards;
}

@keyframes splash-mote {
  0% { opacity: 0; transform: translate3d(0, 18px, 0) scale(0.5); }
  16% { opacity: 0.95; }
  70% { opacity: 0.5; }
  100% { opacity: 0; transform: translate3d(0, -66px, 0) scale(1.15); }
}

.splash__mote:nth-child(1) { left: 11%; top: 59%; animation-delay: 0.14s; }
.splash__mote:nth-child(2) { left: 23%; top: 67%; animation-delay: 0.46s; }
.splash__mote:nth-child(3) { left: 35%; top: 55%; animation-delay: 0.27s; }
.splash__mote:nth-child(4) { left: 45%; top: 71%; animation-delay: 0.63s; }
.splash__mote:nth-child(5) { left: 56%; top: 61%; animation-delay: 0.19s; }
.splash__mote:nth-child(6) { left: 66%; top: 69%; animation-delay: 0.53s; }
.splash__mote:nth-child(7) { left: 78%; top: 57%; animation-delay: 0.35s; }
.splash__mote:nth-child(8) { left: 89%; top: 65%; animation-delay: 0.74s; }

/* ---- a light sweeping across the wordmark. Wrapped in @supports because the
   transparent fill it needs is only safe where the clip actually works: a
   browser without it would paint the text invisible. --------------------- */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .splash__mark strong {
    background-image: linear-gradient(
      100deg,
      #f0fbff 0%,
      #f0fbff 34%,
      #9df3ff 47%,
      #ffffff 52%,
      #f0fbff 66%,
      #f0fbff 100%
    );
    background-size: 260% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation:
      splash-mark 3.5s cubic-bezier(0.2, 0.7, 0.2, 1) forwards,
      splash-shimmer 3.5s linear forwards;
  }

  @keyframes splash-shimmer {
    0% { background-position: 140% 50%; }
    100% { background-position: -70% 50%; }
  }
}
