/* ==========================================================================
   Splash — shown on a full load of the home page only (an inline script in
   <head> adds .no-splash for any other route). Everything animates in CSS so
   it paints before a single script has run; assets/js/core/splash.js only
   decides when to leave. If scripts never arrive, the splash removes itself
   after 6 s (splashFailsafe) so the page is never trapped behind it.
   Shared verbatim by Systems Atlas and Algorithm Atlas: each page uses one of
   the two mark variants (.splash-sd / .splash-dsa).
   ========================================================================== */

.splash {
  position: fixed; inset: 0; z-index: 1000;
  display: grid; place-items: center;
  background: var(--ground);
  color: var(--ink);
  isolation: isolate; overflow: hidden;
  animation: splashFailsafe .01s linear 6s forwards;
  cursor: default;
  overscroll-behavior: contain; touch-action: none;
  /* the exit is a curtain lift, not a fade — see [data-state="out"] */
  transition: transform .62s cubic-bezier(.76, 0, .24, 1);
  box-shadow: 0 1px 0 var(--line-2), 0 24px 48px -12px rgba(0, 0, 0, .14);
}
.no-splash .splash { display: none; }

/* While the splash is up the page behind it must not scroll (a wheel over the
   splash used to leave you halfway down the home page). scrollbar-gutter keeps
   the scrollbar's space reserved so nothing jumps sideways when it returns.
   The home view is rendered FULLY OPAQUE underneath — no entrance fade — so
   the moment the curtain moves, finished page is what it uncovers. */
html.splash-on { overflow: hidden; scrollbar-gutter: stable; }
html.splash-on body { overflow: hidden; }
html.splash-on .stage > .view { animation: none; }
html.splash-on .desk { animation-play-state: paused; }   /* decorative cards drift in as it lifts */

/* Exit: the whole splash slides up and off. Every pixel is either splash or the
   finished page, so there is no frame where both blend (ghosting) and no frame
   where neither is visible (blank). Fades caused one or the other. */
.splash[data-state="out"] { transform: translateY(-100%); pointer-events: none; }
.splash[data-state="out"] .splash-in { transform: translateY(-28px); transition: transform .62s cubic-bezier(.76, 0, .24, 1); }

@keyframes splashFailsafe { to { transform: translateY(-100%); visibility: hidden; pointer-events: none; } }

/* soft glow and a faint engineering grid behind the lockup */
.splash::before {
  content: ""; position: absolute; inset: 22% 22% 14%; z-index: -1; border-radius: 50%;
  background: var(--surface); filter: blur(60px); opacity: .9;
}
.splash::after {
  content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background-image: linear-gradient(var(--line) 1px, transparent 1px), linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 32px 32px; opacity: .45;
  -webkit-mask-image: radial-gradient(ellipse 50% 45% at 50% 50%, #000, transparent 75%);
  mask-image: radial-gradient(ellipse 50% 45% at 50% 50%, #000, transparent 75%);
}

.splash-in { display: flex; flex-direction: column; align-items: center; gap: 22px; padding: 16px; text-align: center; }

.splash-mark { width: clamp(96px, 16vw, 132px); height: auto; overflow: visible; display: block; }

/* wordmark: letters rise in one after another */
.splash-word {
  font-family: var(--display, ui-monospace, monospace); font-weight: 400;
  font-size: clamp(26px, 4.4vw, 40px); line-height: 1; letter-spacing: 0;
  display: inline-flex; align-items: baseline; white-space: pre;
}
.splash-word span {
  display: inline-block; opacity: 0; transform: translateY(.24em);
  animation: splashLetter .22s cubic-bezier(.16, 1, .3, 1) forwards;
  animation-delay: calc(.42s + var(--i) * 45ms);
}
@keyframes splashLetter { to { opacity: 1; transform: none; } }

.splash-meta {
  font-family: var(--mono, ui-monospace, monospace); font-size: 12px; color: var(--ink-3);
  opacity: 0; animation: splashFade .4s ease 1.05s forwards;
  max-width: min(72ch, 92vw); line-height: 1.5; text-wrap: balance;
}
.splash-meta b { color: var(--ink); font-weight: 500; }
@keyframes splashFade { to { opacity: 1; } }

.splash-bar { width: 148px; height: 2px; background: var(--line-2); overflow: hidden; border-radius: 2px; }
.splash-bar span { display: block; height: 100%; width: 100%; background: var(--ink); transform-origin: left; transform: scaleX(0); animation: splashBar 1.6s cubic-bezier(.4, 0, .2, 1) .1s forwards; }
@keyframes splashBar { to { transform: scaleX(1); } }

.splash-skip {
  position: absolute; bottom: calc(22px + env(safe-area-inset-bottom, 0px)); left: 50%; transform: translateX(-50%);
  font-family: var(--mono, ui-monospace, monospace); font-size: 10.5px; color: var(--ink-4);
  opacity: 0; animation: splashFade .4s ease 1.4s forwards;
}

/* ---------------- Systems Atlas: the network assembles ---------------- */
.splash-sd .sp-edge {
  fill: none; stroke: var(--ink); stroke-width: 2.2; stroke-linecap: round;
  stroke-dasharray: 1; stroke-dashoffset: 1;
  animation: spDraw .36s cubic-bezier(.4, 0, .2, 1) forwards;
}
.splash-sd .sp-edge.e1 { animation-delay: .18s; }
.splash-sd .sp-edge.e2 { animation-delay: .30s; }
.splash-sd .sp-edge.e3 { animation-delay: .42s; }
.splash-sd .sp-edge.e4 { animation-delay: .56s; }
.splash-sd .sp-edge.e5 { animation-delay: .62s; }
@keyframes spDraw { to { stroke-dashoffset: 0; } }

/* packets: short dashes that keep travelling along the wires once drawn */
.splash-sd .sp-flow {
  fill: none; stroke: var(--ink-4); stroke-width: 2.2; stroke-linecap: round;
  stroke-dasharray: .06 .18; opacity: 0;
  animation: spFlowIn .2s ease forwards, spFlow 1s linear infinite;
}
.splash-sd .sp-flow.e1 { animation-delay: .55s, .55s; }
.splash-sd .sp-flow.e2 { animation-delay: .67s, .67s; }
.splash-sd .sp-flow.e3 { animation-delay: .79s, .79s; }
@keyframes spFlowIn { to { opacity: 1; } }
@keyframes spFlow { to { stroke-dashoffset: -.24; } }

.splash-sd .sp-node { transform-box: fill-box; transform-origin: center; transform: scale(0); animation: spPop .34s cubic-bezier(.34, 1.56, .64, 1) forwards; }
.splash-sd .sp-node circle { fill: var(--surface); stroke: var(--ink); stroke-width: 2.2; }
.splash-sd .sp-node.hub circle { fill: var(--ink); }
.splash-sd .sp-node.n1 { animation-delay: .05s; }
.splash-sd .sp-node.n2 { animation-delay: .40s; }
.splash-sd .sp-node.n3 { animation-delay: .52s; }
.splash-sd .sp-node.n4 { animation-delay: .74s; }
.splash-sd .sp-node.n5 { animation-delay: .80s; }
@keyframes spPop { to { transform: scale(1); } }
.splash-sd .sp-node.hub { animation: spPop .34s cubic-bezier(.34, 1.56, .64, 1) .05s forwards, spPulse 2.2s ease-in-out 1s infinite; }
@keyframes spPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } }

/* ---------------- Algorithm Atlas: the bars sort themselves ---------------- */
.splash-dsa .sb { transform-box: fill-box; transform-origin: bottom; }
.splash-dsa .sb-r { fill: var(--st-idle, #c8c8d2); }
.splash-dsa .sb-in { animation: sbGrow .32s cubic-bezier(.16, 1, .3, 1) both; animation-delay: calc(.04s + var(--i) * 55ms); transform-box: fill-box; transform-origin: bottom; }
@keyframes sbGrow { from { transform: scaleY(0); } }

/* two swaps: (slot1 ↔ slot4) then (slot0 ↔ slot2). --d is the slide distance */
.splash-dsa .sb.swap1 { animation: sbSlide .38s cubic-bezier(.65, 0, .35, 1) .46s forwards; }
.splash-dsa .sb.swap2 { animation: sbSlide .38s cubic-bezier(.65, 0, .35, 1) .92s forwards; }
@keyframes sbSlide { to { transform: translateX(var(--d)); } }

.splash-dsa .sb.swap1 .sb-r { animation: sbCompare .2s linear .26s forwards, sbSwap .1s linear .46s forwards, sbIdle .1s linear .84s forwards; }
.splash-dsa .sb.swap2 .sb-r { animation: sbCompare .2s linear .72s forwards, sbSwap .1s linear .92s forwards, sbIdle .1s linear 1.30s forwards; }
@keyframes sbCompare { to { fill: var(--st-compare, #d97706); } }
@keyframes sbSwap { to { fill: var(--st-swap, #c026d3); } }
@keyframes sbIdle { to { fill: var(--st-idle, #c8c8d2); } }

/* once sorted, a green wave settles left to right */
.splash-dsa .sb .sb-done { fill: var(--st-done, #15803d); opacity: 0; animation: splashFade .18s linear forwards; animation-delay: calc(1.34s + var(--slot) * 60ms); }

/* ---------------- reduced motion: the finished lockup, no movement ---------------- */
@media (prefers-reduced-motion: reduce) {
  .splash *, .splash *::before, .splash *::after { animation-duration: .001s !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; }
  .splash-dsa .sb.swap1, .splash-dsa .sb.swap2 { transform: translateX(var(--d)); }
  .splash-dsa .sb .sb-done { opacity: 1; }
}
