/* ============================================================
   NOVA BOOT — the arrival animation (nova-boot.css)

   WHAT THIS REPLACES
   ------------------
   Nova Assistant's first load used to run the shared shell's first-load
   reveal: layout.css gates `.rise` / `.stagger > *` to "first load only" (they
   are neutralised once `body.nav-ready` lands), so on arrival every element in
   the view animated in on its own staggered delay. On a dense three-pane chat —
   sidebar rows, pinned chats, project rows, greeting, chips, composer — that is
   dozens of independently-timed pop-ins firing over each other while data is
   still streaming in and re-rendering rows mid-animation. Vincent: "instead of
   this weird glitching animation — because I think it's coming from something
   else". He was right that it wasn't the chat view: it was the shell.

   So on this product that cascade is switched OFF (app.js marks the body
   nav-ready before first paint) and this ONE deliberate animation runs instead.

   THE ANIMATION — the wordmark, and nothing else
   ---------------------------------------------
   Three rounds of subtraction (see nova-boot.js for the quotes): the nine
   opening slices went, then the spark icon went. What is left is the Nova
   wordmark coming up out of nothing in the middle of the screen, with a single
   soft light passing over it.

   Every value here is tuned around ONE idea: nothing should look like it is
   *starting*. No bounce, no overshoot, no spring. It enters already most of the
   way there on a long decelerating curve, so the eye reads it as arriving
   rather than as being animated.

   Transform/opacity/filter only — GPU-cheap, no layout thrash.
   ============================================================ */

.nvb {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: grid;
  place-items: center;
  background: var(--bg, #0b0b0c);
  /* The overlay owns the screen while it plays; nothing behind it is clickable
     and nothing behind it is announced. */
  pointer-events: all;
  opacity: 1;
  /* The exit is the longest curve in the file. A quick cut at the end undoes the
     calm the entrance just bought. */
  transition: opacity 260ms cubic-bezier(0.4, 0, 0.2, 1);
}
.nvb.is-out { opacity: 0; pointer-events: none; }

.nvb-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  /* The stage lifts a few pixels as it leaves, so the overlay reads as pulling
     away from the app rather than simply switching off. */
  transition: transform 260ms cubic-bezier(0.4, 0, 0.2, 1);
}
.nvb.is-out .nvb-stage { transform: translateY(-6px); }

/* ---- the wordmark ---- */
.nvb-wordwrap { position: relative; display: block; color: var(--text-100, #fff); }

.nvb-word {
  display: block;
  height: 34px;
  width: auto;
  opacity: 0;
  /* 0.16/1/0.3/1 — close to a pure ease-out with a very early peak velocity. It
     arrives fast and spends most of its time settling, which is what reads as
     "smooth" rather than "animated". */
  animation: nvb-word-in 420ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes nvb-word-in {
  from {
    opacity: 0;
    /* Up out of nothing: a small rise plus a scale that starts near-final.
       0.94, not 0.6 — a big scale jump is a pop, and this is a settle. */
    transform: translateY(10px) scale(0.94);
    filter: blur(7px);
  }
  55% { opacity: 1; }
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}
/* One wordmark per theme — the same pair the rail lockup uses, so the intro and
   the app agree about which mark this product wears. The classes are named after
   the INK the file carries (white/black), not after the theme it belongs to: an
   earlier build called them -light/-dark, read as theme names, and painted black
   ink on the dark background — an invisible wordmark. */
[data-theme='light'] .nvb-word-white { display: none; }
[data-theme='dark'] .nvb-word-black,
:root:not([data-theme='light']) .nvb-word-black { display: none; }

/* The light sweep: one soft highlight crossing the wordmark once.
   mix-blend-mode:plus-lighter keeps it additive on both themes — a plain white
   overlay would wash the mark out on light. */
.nvb-sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  mix-blend-mode: plus-lighter;
  opacity: 0;
  animation: nvb-sheen-on 520ms linear 120ms both;
}
.nvb-sheen::after {
  content: "";
  position: absolute;
  top: -40%;
  bottom: -40%;
  width: 34%;
  left: -50%;
  background: linear-gradient(100deg, transparent, color-mix(in srgb, currentColor 46%, transparent), transparent);
  filter: blur(6px);
  animation: nvb-sheen 520ms cubic-bezier(0.35, 0, 0.2, 1) 120ms both;
}
@keyframes nvb-sheen-on { 0%, 100% { opacity: 0; } 20%, 74% { opacity: 1; } }
@keyframes nvb-sheen { from { left: -50%; } to { left: 120%; } }

/* ---- reduced motion ----
   Not "a faster animation" — no animation. The overlay still appears so the
   arrival is not a bare flash of an unpainted shell, but everything is in its
   final state immediately and nova-boot.js shortens the hold to match. */
@media (prefers-reduced-motion: reduce) {
  .nvb-word { animation: none; opacity: 1; transform: none; filter: none; }
  .nvb-sheen { display: none; }
  .nvb, .nvb-stage { transition: none; }
}
