/*
  nerix motion: generated by nerix-app/brand/kit/build_motion.py. Do not edit by hand; change the
  tables in build_motion.py, rebuild and copy this file next to each app stylesheet.

  The principles, in code:
  1. Ice moves, Ink holds. Loops belong to the slash, the colour of everything AI does; stems,
     text and layout settle and stay.
  2. Everything travels on the mark's own lines: the slash's pen direction for light, the 11.9°
     lean for things that slide. Nothing spins, bounces or wobbles.
  3. Fast in, soft landing (--nx-ease-out). Exits accelerate (--nx-ease-in) and take ~70% of the time.
  4. The gap stays. Moving parts approach the slash and stop at the gap; Ink and Ice never touch.
  5. Reduced motion keeps the meaning, not the movement: the loader breathes instead of travelling.
*/

:root {
  --nx-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --nx-ease-in: cubic-bezier(0.7, 0, 0.84, 0);
  --nx-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --nx-ease-snap: cubic-bezier(0.2, 0, 0, 1);
  --nx-dur-instant: 90ms;
  --nx-dur-quick: 160ms;
  --nx-dur-base: 240ms;
  --nx-dur-panel: 360ms;
  --nx-dur-page: 420ms;
  --nx-dur-brand: 900ms;
  --nx-dist-1: 4px;
  --nx-dist-2: 8px;
  --nx-dist-3: 16px;
  --nx-streak-cycle: 1500ms;
  --nx-write-cycle: 2400ms;
}


/* ── The loader ─────────────────────────────────────────────────────────────────────
   Layers stacked in one box: the two stems, the resting slash (the track), then bands of light.
   A band's box is its stroke's own vertical extent, so a clip-path inset in percent is a position
   along the stroke. The outer box of a band clips its head, the inner <svg> its tail. HTML boxes,
   not SVG children, carry the clips: inset() on an HTML element animates alike in every engine. */
.nx-loader {
  position: relative;
  display: inline-block;
  inline-size: 2rem;
  block-size: 2rem;
  flex: none;
  /* Where the left stem starts its slide: down and back along the lean (0.21 across per 1 down),
     so it approaches the slash as it rises and stops at the gap. The right stem mirrors it. */
  --nx-lean-x: -3.15%;
  --nx-lean-y: 15%;
}
.nx-loader svg { position: absolute; overflow: visible; }
.nx-loader .nx-l-full { inset: 0; inline-size: 100%; block-size: 100%; }
.nx-loader .nx-l-band { position: absolute; display: block; }
.nx-loader .nx-l-band > svg { inset: 0; inline-size: 100%; block-size: 100%; }
.nx-loader .nx-l-stem { fill: var(--mark-stem, currentColor); }
.nx-loader .nx-l-slash { fill: var(--mark-slash, currentColor); }
.nx-loader .nx-l-tile { fill: var(--mark-tile, #0d1b23); }
.nx-loader[data-tile] .nx-l-stem { fill: var(--mark-tile-stem, #e4f1f5); }
.nx-loader[data-tile] .nx-l-slash { fill: var(--mark-tile-slash, #4ddae9); }
.nx-loader[data-mono] .nx-l-stem, .nx-loader[data-mono] .nx-l-slash { fill: currentColor; }
.nx-loader .nx-l-track { opacity: 0.16; }
.nx-loader .nx-l-glow { opacity: 0.38; }
.nx-loader .nx-l-band { clip-path: inset(0 0 100% 0); }

/* Streak: light runs down the slash in its pen direction, lands, drains; an afterglow trails it. */
.nx-loader[data-kind="streak"] .nx-l-head { animation: nx-head var(--nx-streak-cycle) linear infinite; }
.nx-loader[data-kind="streak"] .nx-l-head > svg { animation: nx-tail var(--nx-streak-cycle) linear infinite; }
.nx-loader[data-kind="streak"] .nx-l-glow { animation: nx-head var(--nx-streak-cycle) linear infinite; }
.nx-loader[data-kind="streak"] .nx-l-glow > svg { animation: nx-glow-tail var(--nx-streak-cycle) linear infinite; }

/* Intro (boot screens): the N assembles once (the slash is drawn, the stems slide in along the
   lean and stop at the gap), holds, drains, then the streak takes over from the same empty state. */
.nx-loader[data-kind="intro"] .nx-l-stem0 { animation: nx-intro-stem0 1300ms linear both; }
.nx-loader[data-kind="intro"] .nx-l-stem1 { animation: nx-intro-stem1 1300ms linear both; --nx-lean-x: 3.15%; --nx-lean-y: -15%; }
.nx-loader[data-kind="intro"] .nx-l-track { animation: nx-fade-in 650ms 433ms linear both; }
.nx-loader[data-kind="intro"] .nx-l-head { animation: nx-intro-head 1300ms linear both, nx-head var(--nx-streak-cycle) 1300ms linear infinite; }
.nx-loader[data-kind="intro"] .nx-l-head > svg { animation: nx-intro-tail 1300ms linear both, nx-tail var(--nx-streak-cycle) 1300ms linear infinite; }
.nx-loader[data-kind="intro"] .nx-l-glow { animation: nx-head var(--nx-streak-cycle) 1300ms linear infinite; }
.nx-loader[data-kind="intro"] .nx-l-glow > svg { animation: nx-glow-tail var(--nx-streak-cycle) 1300ms linear infinite; }

/* Writing (an answer being composed): the N drawn in pen order (stem up, slash down, stem up) over
   its faint outline, then released in the same order. */
.nx-loader[data-kind="write"] .nx-l-stem0, .nx-loader[data-kind="write"] .nx-l-stem1 { opacity: 0.14; }
.nx-loader[data-kind="write"] .nx-l-track { opacity: 0.14; }

.nx-loader[data-kind="write"] .nx-l-w0 { animation: nx-w0-head var(--nx-write-cycle) linear infinite; }
.nx-loader[data-kind="write"] .nx-l-w0 > svg { animation: nx-w0-tail var(--nx-write-cycle) linear infinite; }

.nx-loader[data-kind="write"] .nx-l-w1 { animation: nx-w1-head var(--nx-write-cycle) linear infinite; }
.nx-loader[data-kind="write"] .nx-l-w1 > svg { animation: nx-w1-tail var(--nx-write-cycle) linear infinite; }

.nx-loader[data-kind="write"] .nx-l-w2 { animation: nx-w2-head var(--nx-write-cycle) linear infinite; }
.nx-loader[data-kind="write"] .nx-l-w2 > svg { animation: nx-w2-tail var(--nx-write-cycle) linear infinite; }


/* Progress: the light fills the slash to --nx-value (0 to 1). */
.nx-loader[data-kind="progress"] .nx-l-head {
  clip-path: inset(0 0 calc(100% - var(--nx-value, 0) * 100%) 0);
  transition: clip-path var(--nx-dur-page) var(--nx-ease-out);
}

/* Reduced motion: nothing travels. The slash breathes between its resting and full strength,
   which still says "working". Specific enough to outrank each stylesheet's global reduced-motion
   rule; [data-motion="reduced"] is the account preference the apps stamp on a wrapper. */
@media (prefers-reduced-motion: reduce) {
  .nx-loader[data-kind] .nx-l-band:not(.nx-l-progress), .nx-loader[data-kind] .nx-l-band > svg { animation: none !important; }
  .nx-loader[data-kind]:not([data-kind="progress"]) .nx-l-band { opacity: 0; }
  .nx-loader[data-kind] .nx-l-stem0, .nx-loader[data-kind] .nx-l-stem1 { animation: none !important; opacity: 1; }
  .nx-loader[data-kind]:not([data-kind="progress"]) .nx-l-track { animation: nx-breathe 2.4s ease-in-out infinite !important; }
}
[data-motion="reduced"] .nx-loader[data-kind] .nx-l-band, [data-motion="reduced"] .nx-loader[data-kind] .nx-l-band > svg { animation: none !important; }
[data-motion="reduced"] .nx-loader[data-kind]:not([data-kind="progress"]) .nx-l-band { opacity: 0; }
[data-motion="reduced"] .nx-loader[data-kind] .nx-l-stem0, [data-motion="reduced"] .nx-loader[data-kind] .nx-l-stem1 { animation: none !important; opacity: 1; }
[data-motion="reduced"] .nx-loader[data-kind]:not([data-kind="progress"]) .nx-l-track { animation: nx-breathe 2.4s ease-in-out infinite !important; }

@keyframes nx-breathe {
  0%, 100% { opacity: 0.16; }
  50% { opacity: 0.9; }
}
@keyframes nx-fade-in {
  from { opacity: 0; }
}

@keyframes nx-head {
  0% { clip-path: inset(0 0 100% 0); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  50%, 100% { clip-path: inset(0 0 0% 0); }
}

@keyframes nx-tail {
  0%, 12% { clip-path: inset(0% 0 0 0); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  76%, 100% { clip-path: inset(100% 0 0 0); }
}

@keyframes nx-glow-tail {
  0%, 22% { clip-path: inset(0% 0 0 0); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  92%, 100% { clip-path: inset(100% 0 0 0); }
}

@keyframes nx-intro-head {
  0% { clip-path: inset(0 0 100% 0); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  42%, 100% { clip-path: inset(0 0 0% 0); }
}

@keyframes nx-intro-tail {
  0%, 70% { clip-path: inset(0% 0 0 0); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  100% { clip-path: inset(100% 0 0 0); }
}

@keyframes nx-intro-stem0 {
  0%, 12% { opacity: 0; transform: translate(var(--nx-lean-x), var(--nx-lean-y)); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  52%, 100% { opacity: 1; transform: none; }
}

@keyframes nx-intro-stem1 {
  0%, 20% { opacity: 0; transform: translate(var(--nx-lean-x), var(--nx-lean-y)); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  60%, 100% { opacity: 1; transform: none; }
}

@keyframes nx-w0-head {
  0% { clip-path: inset(100% 0 0 0); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  20%, 100% { clip-path: inset(0% 0 0 0); }
}

@keyframes nx-w0-tail {
  0%, 62% { clip-path: inset(0 0 0% 0); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  80%, 100% { clip-path: inset(0 0 100% 0); }
}

@keyframes nx-w1-head {
  0%, 14% { clip-path: inset(0 0 100% 0); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  38%, 100% { clip-path: inset(0 0 0% 0); }
}

@keyframes nx-w1-tail {
  0%, 68% { clip-path: inset(0% 0 0 0); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  88%, 100% { clip-path: inset(100% 0 0 0); }
}

@keyframes nx-w2-head {
  0%, 32% { clip-path: inset(100% 0 0 0); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  52%, 100% { clip-path: inset(0% 0 0 0); }
}

@keyframes nx-w2-tail {
  0%, 76% { clip-path: inset(0 0 0% 0); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  96%, 100% { clip-path: inset(0 0 100% 0); }
}


/* ── The streak bar ─────────────────────────────────────────────────────────────────
   The same light as a hairline, for route loads and anything without a percentage:
   <span class="nx-streak-bar"><span class="nx-b nx-b-glow"><i></i></span><span class="nx-b"><i></i></span></span>
   It runs toward the reading end, so it mirrors under RTL (the logo never does; a progress line
   is directional). */
.nx-streak-bar {
  position: relative;
  display: block;
  block-size: 2px;
  overflow: hidden;
  pointer-events: none;
}
.nx-streak-bar .nx-b, .nx-streak-bar .nx-b > i {
  position: absolute;
  inset: 0;
  display: block;
}
.nx-streak-bar .nx-b > i { background: var(--brand, var(--primary)); }
.nx-streak-bar .nx-b-glow { opacity: 0.38; }
.nx-streak-bar .nx-b { animation: nx-bar-head var(--nx-streak-cycle) linear infinite; }
.nx-streak-bar .nx-b > i { animation: nx-bar-tail var(--nx-streak-cycle) linear infinite; }
.nx-streak-bar .nx-b-glow > i { animation-name: nx-bar-glow-tail; }
[dir="rtl"] .nx-streak-bar .nx-b { animation-name: nx-bar-head-rtl; }
[dir="rtl"] .nx-streak-bar .nx-b > i { animation-name: nx-bar-tail-rtl; }
[dir="rtl"] .nx-streak-bar .nx-b-glow > i { animation-name: nx-bar-glow-tail-rtl; }
@media (prefers-reduced-motion: reduce) {
  .nx-streak-bar .nx-b, .nx-streak-bar .nx-b > i { animation: none !important; }
  .nx-streak-bar .nx-b-glow { opacity: 0; }
  .nx-streak-bar .nx-b:not(.nx-b-glow) { animation: nx-breathe 2.4s ease-in-out infinite !important; }
}
[data-motion="reduced"] .nx-streak-bar .nx-b, [data-motion="reduced"] .nx-streak-bar .nx-b > i { animation: none !important; }
[data-motion="reduced"] .nx-streak-bar .nx-b-glow { opacity: 0; }
[data-motion="reduced"] .nx-streak-bar .nx-b:not(.nx-b-glow) { animation: nx-breathe 2.4s ease-in-out infinite !important; }

@keyframes nx-bar-head {
  0% { clip-path: inset(0 100% 0 0); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  50%, 100% { clip-path: inset(0 0% 0 0); }
}

@keyframes nx-bar-tail {
  0%, 12% { clip-path: inset(0 0 0 0%); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  76%, 100% { clip-path: inset(0 0 0 100%); }
}

@keyframes nx-bar-glow-tail {
  0%, 22% { clip-path: inset(0 0 0 0%); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  92%, 100% { clip-path: inset(0 0 0 100%); }
}

@keyframes nx-bar-head-rtl {
  0% { clip-path: inset(0 0 0 100%); animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1); }
  50%, 100% { clip-path: inset(0 0 0 0%); }
}

@keyframes nx-bar-tail-rtl {
  0%, 12% { clip-path: inset(0 0% 0 0); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  76%, 100% { clip-path: inset(0 100% 0 0); }
}

@keyframes nx-bar-glow-tail-rtl {
  0%, 22% { clip-path: inset(0 0% 0 0); animation-timing-function: cubic-bezier(0.65, 0, 0.35, 1); }
  92%, 100% { clip-path: inset(0 100% 0 0); }
}


/* ── Text that is being written ─────────────────────────────────────────────────────
   "Writing", "Searching": a soft light passes over the words toward the reading end. */
.nx-shimmer {
  background: linear-gradient(90deg, currentColor 0 35%, var(--brand, var(--primary)) 50%, currentColor 65% 100%) 0 0 / 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: nx-shimmer 2.2s var(--nx-ease-in-out) infinite;
}
[dir="rtl"] .nx-shimmer { animation-direction: reverse; }
@keyframes nx-shimmer {
  from { background-position: 100% 0; }
  to { background-position: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .nx-shimmer { animation: none !important; background: none; -webkit-text-fill-color: currentColor; }
}
[data-motion="reduced"] .nx-shimmer { animation: none !important; background: none; -webkit-text-fill-color: currentColor; }

/* ── Transitions ─────────────────────────────────────────────────────────────────────
   Route content: a short rise and fade, keyed on the route so it plays on every navigation.
   Small surfaces (menus, popovers, cards): rise a few pixels and settle.
   Lists: children enter in reading order, 40 ms apart, capped so a long list never waits.
   The stylesheets' global reduced-motion rules collapse all of these to their end state. */
.nx-route-in {
  animation: nx-route-in var(--nx-dur-page) var(--nx-ease-out) both;
}
@keyframes nx-route-in {
  from { opacity: 0; transform: translateY(var(--nx-dist-2)); }
}

.nx-rise-in {
  animation: nx-rise-in var(--nx-dur-base) var(--nx-ease-out) both;
}
@keyframes nx-rise-in {
  from { opacity: 0; transform: translateY(var(--nx-dist-1)) scale(0.985); }
}

.nx-stagger > * {
  animation: nx-route-in var(--nx-dur-page) var(--nx-ease-out) both;
  animation-delay: calc(var(--nx-i, 0) * 40ms);
}
.nx-stagger > :nth-child(2) { --nx-i: 1; }
.nx-stagger > :nth-child(3) { --nx-i: 2; }
.nx-stagger > :nth-child(4) { --nx-i: 3; }
.nx-stagger > :nth-child(5) { --nx-i: 4; }
.nx-stagger > :nth-child(6) { --nx-i: 5; }
.nx-stagger > :nth-child(7) { --nx-i: 6; }
.nx-stagger > :nth-child(n + 8) { --nx-i: 7; }

/* Leaving a boot screen: the loader settles and steps back while the page arrives. */
.nx-boot-out {
  animation: nx-boot-out var(--nx-dur-base) var(--nx-ease-in) both;
}
@keyframes nx-boot-out {
  to { opacity: 0; transform: scale(0.96); }
}
