/* Shared Yuri Fano route frame.
   The same DOM and terminal frame are used on World and the novel page so the
   document swap happens behind one continuous image. */

.yuri-loader {
  --yuri-loader-x: 50vw;
  --yuri-loader-y: 50vh;
  --yuri-poster-width: min(88vw, 70rem);
  position: fixed !important;
  inset: 0 !important;
  z-index: 260 !important;
  display: block !important;
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
  isolation: isolate;
  color: #e9f2f8;
  font-family: "Noto Sans SC", "Source Han Sans CN", "Microsoft YaHei UI", sans-serif;
}

html[data-yuri-return-pending]::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 259;
  pointer-events: none;
  background: #010308;
  animation: yuri-loader-return-guard 1800ms ease 1200ms both;
}

.yuri-loader.is-gsap-route,
html[data-novel-entry="blueprint-lock"] .yuri-loader,
body.is-entering-from-world .yuri-loader,
body.is-leaving .yuri-loader,
body.is-novel-transition .world-novel-route.yuri-loader,
body.is-returning-from-novel .world-novel-route.yuri-loader {
  visibility: visible;
}

body.is-entering-from-world.is-yuri-loader-gsap .scene-copy--title,
body.is-leaving.is-yuri-loader-gsap .scene-copy--title {
  opacity: 0;
}

.world-field.is-novel-transition .world-hit {
  pointer-events: none;
}

.world-field.is-novel-transition:not(.is-returning-from-novel) .world-copy,
.world-field.is-novel-transition:not(.is-returning-from-novel) .world-path,
.world-field.is-novel-transition:not(.is-returning-from-novel) .world-foot,
.world-field.is-novel-transition:not(.is-returning-from-novel) .world-back {
  animation: yuri-loader-world-ui-out 180ms ease both;
}

.world-field.is-returning-from-novel .world-copy,
.world-field.is-returning-from-novel .world-path,
.world-field.is-returning-from-novel .world-foot,
.world-field.is-returning-from-novel .world-back {
  animation: yuri-loader-world-ui-in 280ms ease 160ms both;
}

.yuri-loader > * {
  position: absolute !important;
  box-sizing: border-box;
}

.yuri-loader__field {
  z-index: 0;
  inset: -2px;
  opacity: 0;
  background:
    radial-gradient(circle at 50% 48%, rgba(10, 29, 48, 0.5), transparent 52%),
    #010308;
  clip-path: circle(0 at var(--yuri-loader-x) var(--yuri-loader-y));
  transform: translateZ(0);
  will-change: clip-path, opacity;
}

.yuri-loader__grain {
  z-index: 4;
  inset: 0;
  opacity: 0;
  background-image: url("signal-grain.webp");
  background-repeat: repeat;
  background-size: 256px 256px;
  mix-blend-mode: soft-light;
  pointer-events: none;
  will-change: opacity;
}

.yuri-loader__poster {
  z-index: 2;
  left: 50%;
  top: 50%;
  width: var(--yuri-poster-width);
  aspect-ratio: 1672 / 941;
  margin: 0;
  overflow: hidden;
  opacity: 0;
  background: #010308;
  box-shadow:
    0 0 0 1px rgba(219, 235, 244, 0.12),
    0 2.4rem 8rem rgba(0, 0, 0, 0.72);
  clip-path: inset(0 49.96% 0 49.96% round 1px);
  transform: translate(-50%, -50%) scale(0.985);
  transform-origin: center;
  will-change: transform, opacity, clip-path;
}

.yuri-loader__image,
.yuri-loader__grade {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.yuri-loader__image {
  display: block;
  object-fit: cover;
  object-position: center;
  transform: scale(1.055);
  transform-origin: 52% 50%;
  will-change: transform, opacity;
}

.yuri-loader__grade {
  z-index: 1;
  background:
    linear-gradient(90deg, rgba(1, 3, 8, 0.34), transparent 34%, transparent 67%, rgba(1, 3, 8, 0.25)),
    linear-gradient(180deg, rgba(1, 3, 8, 0.2), transparent 34%, transparent 64%, rgba(1, 3, 8, 0.52));
}

.yuri-loader__title {
  position: absolute;
  z-index: 3;
  left: 50%;
  top: 50%;
  width: 100%;
  margin: 0;
  opacity: 0;
  color: rgba(233, 242, 248, 0.96);
  font-family: "Noto Sans SC", "Source Han Sans CN", "Microsoft YaHei UI", sans-serif;
  font-size: clamp(4rem, 7.4vw, 8.15rem);
  font-weight: 900;
  line-height: 0.88;
  letter-spacing: -0.082em;
  text-align: center;
  text-indent: -0.082em;
  white-space: nowrap;
  text-shadow: 0 0.08em 0.8em rgba(0, 0, 0, 0.72);
  transform: translate(-50%, -47%);
  will-change: transform, opacity;
}

.yuri-loader__title::before {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  overflow: hidden;
  color: rgba(117, 173, 214, 0.38);
  clip-path: inset(39% 0 31% 0);
  text-shadow: none;
  transform: translate(2px, 1px);
}

.yuri-loader__meta,
.yuri-loader__status {
  position: absolute;
  z-index: 3;
  left: clamp(0.8rem, 2vw, 1.6rem);
  right: clamp(0.8rem, 2vw, 1.6rem);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 0;
  opacity: 0;
  color: rgba(233, 242, 248, 0.66);
  font-family: "Share Tech Mono", ui-monospace, monospace;
  font-size: clamp(0.52rem, 0.72vw, 0.68rem);
  font-weight: 400;
  line-height: 1;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  will-change: transform, opacity;
}

.yuri-loader__meta {
  top: clamp(0.8rem, 2vw, 1.5rem);
}

.yuri-loader__status {
  bottom: clamp(0.8rem, 2vw, 1.5rem);
}

.yuri-loader__meta b,
.yuri-loader__status b {
  color: rgba(233, 242, 248, 0.9);
  font-weight: 400;
}

/* Cross-document terminal frame. */
html[data-novel-entry="blueprint-lock"] .yuri-loader__field,
body.is-entering-from-world .yuri-loader__field,
body.is-returning-from-novel .world-novel-route.yuri-loader .yuri-loader__field {
  opacity: 1;
  clip-path: circle(150vmax at var(--yuri-loader-x) var(--yuri-loader-y));
}

html[data-novel-entry="blueprint-lock"] .yuri-loader__grain,
body.is-entering-from-world .yuri-loader__grain,
body.is-returning-from-novel .world-novel-route.yuri-loader .yuri-loader__grain {
  opacity: 0.16;
}

html[data-novel-entry="blueprint-lock"] .yuri-loader__poster,
body.is-entering-from-world .yuri-loader__poster,
body.is-returning-from-novel .world-novel-route.yuri-loader .yuri-loader__poster {
  opacity: 1;
  clip-path: inset(0 0 0 0 round 1px);
  transform: translate(-50%, -50%) scale(1.018);
}

html[data-novel-entry="blueprint-lock"] .yuri-loader__image,
body.is-entering-from-world .yuri-loader__image,
body.is-returning-from-novel .world-novel-route.yuri-loader .yuri-loader__image {
  transform: scale(1.018);
}

html[data-novel-entry="blueprint-lock"] .yuri-loader__title,
body.is-entering-from-world .yuri-loader__title,
body.is-returning-from-novel .world-novel-route.yuri-loader .yuri-loader__title {
  opacity: 0.14;
}

html[data-novel-entry="blueprint-lock"] .yuri-loader__meta,
html[data-novel-entry="blueprint-lock"] .yuri-loader__status,
body.is-entering-from-world .yuri-loader__meta,
body.is-entering-from-world .yuri-loader__status,
body.is-returning-from-novel .world-novel-route.yuri-loader .yuri-loader__meta,
body.is-returning-from-novel .world-novel-route.yuri-loader .yuri-loader__status {
  opacity: 0.62;
}

/* CSS-only fallback when the GSAP CDN has not resolved yet. */
.world-novel-route--depart.yuri-loader:not(.is-gsap-route) .yuri-loader__field {
  animation: yuri-loader-field-cover 1080ms cubic-bezier(0.2, 0.78, 0.2, 1) both;
}

.world-novel-route--depart.yuri-loader:not(.is-gsap-route) .yuri-loader__grain {
  animation: yuri-loader-grain-cover 1080ms ease both;
}

.world-novel-route--depart.yuri-loader:not(.is-gsap-route) .yuri-loader__poster {
  animation: yuri-loader-poster-open 1080ms cubic-bezier(0.2, 0.78, 0.2, 1) both;
}

.world-novel-route--depart.yuri-loader:not(.is-gsap-route) .yuri-loader__image {
  animation: yuri-loader-image-settle 1080ms cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

.world-novel-route--depart.yuri-loader:not(.is-gsap-route) .yuri-loader__title {
  animation: yuri-loader-title-load 1080ms ease both;
}

.world-novel-route--depart.yuri-loader:not(.is-gsap-route) .yuri-loader__meta,
.world-novel-route--depart.yuri-loader:not(.is-gsap-route) .yuri-loader__status {
  animation: yuri-loader-meta-load 1080ms ease both;
}

.world-novel-route--enter.yuri-loader:not(.is-gsap-route) .yuri-loader__field {
  animation: yuri-loader-field-release 800ms cubic-bezier(0.62, 0, 0.18, 1) both;
}

.world-novel-route--enter.yuri-loader:not(.is-gsap-route) .yuri-loader__grain {
  animation: yuri-loader-grain-release 800ms ease both;
}

.world-novel-route--enter.yuri-loader:not(.is-gsap-route) .yuri-loader__poster {
  animation: yuri-loader-poster-close 620ms cubic-bezier(0.62, 0, 0.18, 1) both;
}

.world-novel-route--enter.yuri-loader:not(.is-gsap-route) .yuri-loader__image {
  animation: yuri-loader-image-release 620ms cubic-bezier(0.62, 0, 0.18, 1) both;
}

.world-novel-route--enter.yuri-loader:not(.is-gsap-route) .yuri-loader__title,
.world-novel-route--enter.yuri-loader:not(.is-gsap-route) .yuri-loader__meta,
.world-novel-route--enter.yuri-loader:not(.is-gsap-route) .yuri-loader__status {
  animation: yuri-loader-copy-release 520ms ease both;
}

body.is-entering-from-world .yuri-loader--page:not(.is-gsap-route) .yuri-loader__field {
  animation: yuri-loader-page-field-in 680ms ease both;
}

body.is-entering-from-world .yuri-loader--page:not(.is-gsap-route) .yuri-loader__grain {
  animation: yuri-loader-page-grain-in 680ms ease both;
}

body.is-entering-from-world .yuri-loader--page:not(.is-gsap-route) .yuri-loader__poster {
  animation: yuri-loader-page-poster-in 680ms cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

body.is-entering-from-world .yuri-loader--page:not(.is-gsap-route) .yuri-loader__title,
body.is-entering-from-world .yuri-loader--page:not(.is-gsap-route) .yuri-loader__meta,
body.is-entering-from-world .yuri-loader--page:not(.is-gsap-route) .yuri-loader__status {
  animation: yuri-loader-page-copy-in 580ms ease both;
}

body.is-leaving .yuri-loader--page:not(.is-gsap-route) .yuri-loader__field {
  animation: yuri-loader-page-field-out 720ms ease both;
}

body.is-leaving .yuri-loader--page:not(.is-gsap-route) .yuri-loader__grain {
  animation: yuri-loader-page-grain-out 720ms ease both;
}

body.is-leaving .yuri-loader--page:not(.is-gsap-route) .yuri-loader__poster {
  animation: yuri-loader-page-poster-out 720ms cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

body.is-leaving .yuri-loader--page:not(.is-gsap-route) .yuri-loader__image {
  animation: yuri-loader-page-image-out 720ms cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

body.is-leaving .yuri-loader--page:not(.is-gsap-route) .yuri-loader__title,
body.is-leaving .yuri-loader--page:not(.is-gsap-route) .yuri-loader__meta,
body.is-leaving .yuri-loader--page:not(.is-gsap-route) .yuri-loader__status {
  animation: yuri-loader-page-copy-out 720ms ease both;
}

@keyframes yuri-loader-field-cover {
  0%, 4% { opacity: 0; clip-path: circle(0 at var(--yuri-loader-x) var(--yuri-loader-y)); }
  42%, 100% { opacity: 1; clip-path: circle(150vmax at var(--yuri-loader-x) var(--yuri-loader-y)); }
}

@keyframes yuri-loader-return-guard {
  0%, 72% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes yuri-loader-world-ui-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(5px); }
}

@keyframes yuri-loader-world-ui-in {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes yuri-loader-grain-cover {
  0%, 18% { opacity: 0; }
  56%, 100% { opacity: 0.16; }
}

@keyframes yuri-loader-poster-open {
  0%, 17% { opacity: 0; clip-path: inset(0 49.96% 0 49.96% round 1px); transform: translate(-50%, -50%) scale(0.985); }
  27% { opacity: 1; }
  64% { clip-path: inset(0 0 0 0 round 1px); transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 1; clip-path: inset(0 0 0 0 round 1px); transform: translate(-50%, -50%) scale(1.018); }
}

@keyframes yuri-loader-image-settle {
  0%, 18% { transform: scale(1.055); }
  100% { transform: scale(1.018); }
}

@keyframes yuri-loader-title-load {
  0%, 30% { opacity: 0; transform: translate(-50%, -42%); }
  48% { opacity: 0.72; transform: translate(-50%, -47%); }
  58% { opacity: 0.2; }
  68% { opacity: 0.52; }
  82%, 100% { opacity: 0.14; transform: translate(-50%, -47%); }
}

@keyframes yuri-loader-meta-load {
  0%, 40% { opacity: 0; transform: translateY(8px); }
  68%, 100% { opacity: 0.62; transform: translateY(0); }
}

@keyframes yuri-loader-field-release {
  0%, 32% { opacity: 1; clip-path: circle(150vmax at var(--yuri-loader-x) var(--yuri-loader-y)); }
  100% { opacity: 0; clip-path: circle(0 at var(--yuri-loader-x) var(--yuri-loader-y)); }
}

@keyframes yuri-loader-grain-release {
  0%, 24% { opacity: 0.16; }
  100% { opacity: 0; }
}

@keyframes yuri-loader-poster-close {
  0%, 14% { opacity: 1; clip-path: inset(0 0 0 0 round 1px); transform: translate(-50%, -50%) scale(1.018); }
  78% { opacity: 0.8; }
  100% {
    opacity: 0;
    clip-path: inset(0 49.96% 0 49.96% round 1px);
    transform: translate(
      calc(-50% + var(--yuri-loader-x) - 50vw),
      calc(-50% + var(--yuri-loader-y) - 50vh)
    ) scale(0.075);
  }
}

@keyframes yuri-loader-image-release {
  0%, 14% { transform: scale(1.018); }
  100% { transform: scale(1.06); }
}

@keyframes yuri-loader-copy-release {
  0% { opacity: 0.62; }
  34% { opacity: 0.22; }
  100% { opacity: 0; }
}

@keyframes yuri-loader-page-field-in {
  0%, 42% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes yuri-loader-page-grain-in {
  0%, 30% { opacity: 0.16; }
  100% { opacity: 0; }
}

@keyframes yuri-loader-page-poster-in {
  0%, 10% { opacity: 1; transform: translate(-50%, -50%) scale(1.018); clip-path: inset(0 0 0 0 round 1px); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.075); clip-path: inset(0 0 0 0 round 1px); }
}

@keyframes yuri-loader-page-copy-in {
  0% { opacity: 0.62; }
  38% { opacity: 0.16; }
  100% { opacity: 0; }
}

@keyframes yuri-loader-page-field-out {
  0% { opacity: 0; clip-path: circle(150vmax at 50% 50%); }
  58%, 100% { opacity: 1; clip-path: circle(150vmax at 50% 50%); }
}

@keyframes yuri-loader-page-grain-out {
  0%, 34% { opacity: 0; }
  100% { opacity: 0.16; }
}

@keyframes yuri-loader-page-poster-out {
  0%, 12% { opacity: 0; transform: translate(-50%, -50%) scale(1.075); clip-path: inset(0 0 0 0 round 1px); }
  72%, 100% { opacity: 1; transform: translate(-50%, -50%) scale(1.018); clip-path: inset(0 0 0 0 round 1px); }
}

@keyframes yuri-loader-page-image-out {
  0%, 12% { transform: scale(1.055); }
  72%, 100% { transform: scale(1.018); }
}

@keyframes yuri-loader-page-copy-out {
  0%, 50% { opacity: 0; }
  74% { opacity: 0.5; }
  100% { opacity: 0.62; }
}

@media (max-width: 760px) {
  .yuri-loader {
    --yuri-poster-width: 94vw;
  }

  .yuri-loader__poster {
    box-shadow:
      0 0 0 1px rgba(219, 235, 244, 0.12),
      0 1.4rem 4rem rgba(0, 0, 0, 0.78);
  }

  .yuri-loader__title {
    font-size: clamp(3.15rem, 16vw, 5.4rem);
    letter-spacing: -0.072em;
    text-indent: -0.072em;
  }

  .yuri-loader__meta,
  .yuri-loader__status {
    font-size: 0.48rem;
    letter-spacing: 0.14em;
  }

  .yuri-loader__status span {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .yuri-loader *,
  .yuri-loader *::before,
  .yuri-loader *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
  }
}

html.is-reduced-motion .yuri-loader *,
html.is-reduced-motion .yuri-loader *::before,
html.is-reduced-motion .yuri-loader *::after {
  animation-duration: 1ms !important;
  animation-delay: 0ms !important;
  animation-iteration-count: 1 !important;
}
