/* =====================================================================================================
   NeuroShrub — motion system. Only transform, opacity and stroke-dashoffset are animated.
   Everything here is switched off under prefers-reduced-motion (bottom of file); the UI never relies on motion
   to convey information.
   ===================================================================================================== */

@keyframes ai-page-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes ai-fade-up { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes ai-fade-right { from { opacity: 0; transform: translateX(-22px); } to { opacity: 1; transform: none; } }
@keyframes ai-scale-in { from { opacity: 0; transform: scale(.94); } to { opacity: 1; transform: none; } }
@keyframes ai-line-expand { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes ai-spin { to { transform: rotate(360deg); } }
@keyframes ai-spin-reverse { to { transform: rotate(-360deg); } }
@keyframes ai-pulse { 0%, 100% { opacity: .55; transform: scale(1); } 50% { opacity: 1; transform: scale(1.08); } }
@keyframes ai-blink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@keyframes ai-flow { to { stroke-dashoffset: -40; } }
@keyframes ai-scan { from { transform: translateX(-100%); } to { transform: translateX(400%); } }
@keyframes ai-shimmer { from { transform: translateX(-120%); } to { transform: translateX(320%); } }
@keyframes ai-grid-move { from { transform: translateY(0); } to { transform: translateY(60px); } }
@keyframes ai-drift { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(-3%, -6%, 0); } }
@keyframes ai-slow-zoom { from { transform: scale(1.02); } to { transform: scale(1.1); } }
@keyframes ai-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@keyframes ai-glow-breathe { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
@keyframes ai-rise { 0% { opacity: 0; transform: translateY(0) scale(.6); } 20% { opacity: 1; } 100% { opacity: 0; transform: translateY(-46px) scale(1); } }
@keyframes ai-flash { 0% { opacity: 0; } 25% { opacity: 1; } 100% { opacity: 0; } }
@keyframes ai-pop { 0% { transform: scale(1); } 40% { transform: scale(1.35); } 100% { transform: scale(1); } }
@keyframes ai-ring-out { from { opacity: .9; transform: scale(.4); } to { opacity: 0; transform: scale(2.2); } }
@keyframes ai-reveal-text { from { opacity: 0; transform: translateY(.4em); filter: blur(4px); } to { opacity: 1; transform: none; filter: none; } }

/* ---- Page load: short and non-blocking ----
   Fill mode "backwards" only (never forwards/both): once the animation ends nothing of it stays applied, so <main> is not
   left as a stacking context / containing block that would trap fixed-position dialogs under Bootstrap's backdrop.
   Dialogs are rendered outside <main> anyway (_Layout.cshtml "Modals" section). */
main[role="main"], .admin-main { animation: ai-page-in .42s var(--ai-ease) backwards; }

/* ---- Scroll reveals (only armed when JS is running: html.ai-js) ---- */
.ai-js [data-reveal] { opacity: 0; }
.ai-js [data-reveal].is-visible { animation: ai-fade-up .7s var(--ai-ease) both; animation-delay: var(--reveal-delay, 0s); }
.ai-js [data-reveal="right"].is-visible { animation-name: ai-fade-right; }
.ai-js [data-reveal="scale"].is-visible { animation-name: ai-scale-in; }
.ai-js [data-reveal="line"] { opacity: 1; transform: scaleX(0); transform-origin: left; }
.ai-js [data-reveal="line"].is-visible { animation: ai-line-expand .9s var(--ai-ease) both; }

/* ---- Active progress bars: a transform-only shimmer ---- */
.progress-bar-animated::after, .ai-meter.is-active > span::after {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 40%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .45), transparent);
    animation: ai-shimmer 1.8s linear infinite;
}

/* ---- Live indicators ---- */
.ai-dot.is-live { animation: ai-blink 1.6s ease-in-out infinite; }
.ai-pulse { animation: ai-pulse 2.4s ease-in-out infinite; transform-origin: center; }
.ai-float { animation: ai-float 6s ease-in-out infinite; }

/* ---- Perspective digital grid (transform only) ---- */
.ai-grid-floor {
    position: absolute;
    inset: auto -20% -2px;
    height: 55%;
    overflow: hidden;
    perspective: 520px;
    perspective-origin: 50% 0%;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(to top, #000 10%, transparent 95%);
    mask-image: linear-gradient(to top, #000 10%, transparent 95%);
}
.ai-grid-floor > i {
    position: absolute;
    inset-inline-start: 0;
    inset-inline-end: 0;
    top: 0;
    height: 220%;
    display: block;
    overflow: hidden;
    transform-origin: 50% 0;
    transform: rotateX(62deg);
}
/* The plane moves one cell, then loops — a seamless forward drift using transform only. */
.ai-grid-floor > i::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    inset-inline-end: 0;
    top: -60px;
    bottom: 0;
    background-image:
        linear-gradient(rgba(196, 181, 253, .5) 1px, transparent 1px),
        linear-gradient(90deg, rgba(var(--ai-violet-bright-rgb), .38) 1px, transparent 1px);
    background-size: 60px 60px;
    background-position: center top;
    animation: ai-grid-move 4s linear infinite;
}

/* Flat drifting grid for page backgrounds. */
.ai-grid-drift { position: absolute; inset: -10%; pointer-events: none; opacity: .5; background-image: linear-gradient(rgba(var(--ai-violet-bright-rgb), .07) 1px, transparent 1px), linear-gradient(90deg, rgba(var(--ai-violet-bright-rgb), .07) 1px, transparent 1px); background-size: 48px 48px; animation: ai-drift 40s linear infinite alternate; }

/* ---- Reusable inline-SVG animation classes (energy flow, server art, network) ---- */
.ai-flow-line { stroke-dasharray: 6 14; animation: ai-flow 1.4s linear infinite; }
.ai-flow-line.is-fast { animation-duration: .8s; }
.ai-flow-line.is-slow { animation-duration: 2.6s; }
.ai-spin-slow { animation: ai-spin 40s linear infinite; transform-origin: center; transform-box: fill-box; }
.ai-spin-rev { animation: ai-spin-reverse 28s linear infinite; transform-origin: center; transform-box: fill-box; }
.ai-led { animation: ai-blink 1.8s steps(2, jump-none) infinite; }
.ai-led:nth-of-type(3n) { animation-duration: 2.6s; animation-delay: -.7s; }
.ai-led:nth-of-type(3n + 1) { animation-duration: 1.2s; animation-delay: -.3s; }

/* ---- Upgrade success: flash, level pop, rising particles, "+1" ---- */
.ai-upgraded { animation: ai-scale-in .5s var(--ai-ease) both; }
.ai-upgraded::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 3;
    pointer-events: none;
    background: radial-gradient(80% 80% at 50% 50%, rgba(var(--ai-violet-bright-rgb), .55), rgba(var(--ai-violet-rgb), .15) 60%, transparent);
    animation: ai-flash 1.2s ease-out both;
}
.ai-upgraded [data-level] { display: inline-block; animation: ai-pop .7s .25s var(--ai-ease) both; }
.ai-burst { position: absolute; inset: 0; z-index: 4; pointer-events: none; overflow: hidden; }
.ai-burst > i { position: absolute; bottom: 30%; width: 4px; height: 4px; background: var(--ai-violet-soft); box-shadow: 0 0 8px var(--ai-violet-bright); transform: rotate(45deg); animation: ai-rise 1.3s ease-out both; }
.ai-burst > b { position: absolute; top: 38%; left: 50%; font-family: var(--ai-font-display); font-size: 1.4rem; color: var(--ai-violet-pale); text-shadow: 0 0 14px var(--ai-violet-bright); transform: translateX(-50%); animation: ai-rise 1.6s ease-out both; }

/* ---- Technology generation unlock overlay ---- */
.ai-unlock {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: grid;
    place-items: center;
    background: radial-gradient(circle at 50% 45%, rgba(var(--ai-violet-rgb), .35), rgba(5, 3, 11, .94) 60%);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    animation: ai-page-in .4s ease-out both;
}
.ai-unlock[hidden] { display: none; }
.ai-unlock__stage { position: relative; display: grid; justify-items: center; gap: .6rem; text-align: center; padding: 2rem; }
.ai-unlock__core { position: relative; width: min(16rem, 60vw); aspect-ratio: 1; }
.ai-unlock__core img { width: 100%; height: 100%; animation: ai-scale-in .9s var(--ai-ease) both; }
.ai-unlock__ring { position: absolute; inset: 15%; border: 2px solid var(--ai-violet-soft); border-radius: 50%; animation: ai-ring-out 1.8s ease-out infinite; }
.ai-unlock__ring:nth-child(3) { animation-delay: .6s; }
.ai-unlock__ring:nth-child(4) { animation-delay: 1.2s; }
.ai-unlock__kicker { animation: ai-reveal-text .6s .5s both; }
.ai-unlock__title { font-family: var(--ai-font-display); font-size: clamp(1.6rem, 1rem + 3vw, 3rem); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: #fff; text-shadow: 0 0 30px rgba(var(--ai-violet-bright-rgb), .9); margin: 0; animation: ai-reveal-text .7s .7s both; }
.ai-unlock__text { color: var(--ai-text-secondary); max-width: 32rem; animation: ai-reveal-text .7s .9s both; }
.ai-unlock .btn { animation: ai-reveal-text .6s 1.1s both; }

/* ---- Count-up numbers hold their width while animating ---- */
[data-count-up] { font-variant-numeric: tabular-nums; }

/* ---- NeuroShrub mark (Views/Shared/_BrandMark): the core activates, branches grow outward, nodes light up ----
   static: navigation; only a short spark along one branch on hover. intro: landing hero, ~3 s then a calm idle.
   loader: loading states. Only stroke-dashoffset, opacity and transform are animated. */
@keyframes ns-grow { to { stroke-dashoffset: 0; } }
@keyframes ns-node { 0% { opacity: 0; transform: scale(.2); } 60% { opacity: 1; transform: scale(1.35); } 100% { opacity: 1; transform: scale(1); } }
@keyframes ns-core { 0% { opacity: 0; transform: scale(.3); } 55% { opacity: 1; transform: scale(1.18); } 100% { opacity: 1; transform: scale(1); } }
@keyframes ns-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@keyframes ns-spark { 0% { opacity: 0; stroke-dashoffset: .16; } 15%, 80% { opacity: 1; } 100% { opacity: 0; stroke-dashoffset: -1; } }
@keyframes ns-glow-in { to { opacity: 1; } }
@keyframes ns-loop { 0% { stroke-dashoffset: 1; opacity: .3; } 40%, 72% { stroke-dashoffset: 0; opacity: 1; } 100% { stroke-dashoffset: 0; opacity: .3; } }
@keyframes ns-node-loop { 0%, 25% { opacity: .3; } 50%, 72% { opacity: 1; } 100% { opacity: .3; } }

.ns-mark { display: block; overflow: visible; }
.ns-mark .ns-node, .ns-mark .ns-core, .ns-mark .ns-core-dot { transform-box: fill-box; transform-origin: center; }
.ns-mark .ns-node { transition: fill .35s ease; }
.ns-mark .ns-spark { stroke: #fff; stroke-width: 2.6; stroke-dasharray: .16 2; stroke-dashoffset: .16; opacity: 0; }

/* static (navbar): brighter nodes and one spark up the trunk while hovered — never a continuous animation */
.brand:hover .ns-mark--static .ns-node { fill: #f8f7fc; }
.brand:hover .ns-mark--static .ns-spark { animation: ns-spark .9s var(--ai-ease) 1; }

/* intro (landing hero) */
.ns-mark--intro .ns-core { animation: ns-core .8s var(--ai-ease) both; }
.ns-mark--intro .ns-core-dot { animation: ns-core .8s .15s var(--ai-ease) both, ns-breathe 4s ease-in-out 3.4s infinite; }
.ns-mark--intro .ns-pins { opacity: 0; animation: ns-glow-in .5s .45s ease-out forwards; }
.ns-mark--intro .ns-branch { stroke-dasharray: 1; stroke-dashoffset: 1; animation: ns-grow .65s var(--ai-ease) var(--d, .4s) forwards; }
.ns-mark--intro .ns-node { opacity: 0; animation: ns-node .45s var(--ai-ease) var(--d, 1s) forwards; }
.ns-emblem { position: relative; display: grid; place-items: center; }
.ns-emblem::before {
    content: "";
    position: absolute;
    inset: 4% 10% 0;
    background: radial-gradient(circle at 50% 80%, rgba(139, 92, 246, .5), rgba(124, 58, 237, .12) 45%, rgba(124, 58, 237, 0) 70%);
    opacity: 0;
    pointer-events: none;
    animation: ns-glow-in 1.2s ease-out 2s forwards, ai-glow-breathe 6s ease-in-out 3.6s infinite;
}
.ns-emblem .ns-mark { position: relative; width: 100%; height: 100%; }

/* loader */
.ns-loader { display: inline-flex; flex-direction: column; align-items: center; gap: .45rem; }
.ns-loader .ns-mark { width: 3.25rem; height: 3.25rem; filter: drop-shadow(0 0 10px rgba(139, 92, 246, .55)); }
.ns-loader__word { font-family: var(--ai-font-display); font-size: .72rem; font-weight: 600; letter-spacing: .32em; text-transform: uppercase; color: var(--ai-violet-soft); }
.ns-loader__text { font-size: .85rem; color: var(--ai-text-secondary); }
.ns-mark--loader .ns-branch { stroke-dasharray: 1; animation: ns-loop 2.4s var(--ai-ease) calc(var(--d, 0s) * .5) infinite; }
.ns-mark--loader .ns-node { animation: ns-node-loop 2.4s ease-in-out calc(var(--d, 0s) * .5) infinite; }
.ns-mark--loader .ns-core-dot { animation: ai-pulse 1.2s ease-in-out infinite; }

/* =====================================================================================================
   Reduced motion: stop continuous movement, keep state changes instant.
   ===================================================================================================== */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        animation-delay: 0s !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
    .ai-js [data-reveal] { opacity: 1 !important; transform: none !important; }
    main[role="main"], .admin-main { animation: none !important; }
    .ai-grid-floor > i::before, .ai-grid-drift, .progress-bar-animated::after, .ai-meter.is-active > span::after, .ai-unlock__ring { animation: none !important; }
    .progress-bar-animated::after, .ai-meter.is-active > span::after { display: none; }
    .btn::before { display: none; }
    /* NeuroShrub mark: always fully drawn and still. */
    .ns-mark *, .ns-emblem::before { animation: none !important; }
    .ns-mark .ns-branch { stroke-dashoffset: 0 !important; opacity: 1 !important; }
    .ns-mark .ns-node, .ns-mark .ns-pins, .ns-mark .ns-core, .ns-mark .ns-core-dot { opacity: 1 !important; transform: none !important; }
    .ns-mark .ns-spark { display: none; }
    .ns-emblem::before { opacity: 1 !important; }
}
