/* vryno-loader.css — the Vryno loading system.
   1. Boot mark      (#vr-boot, critical CSS also inlined in index.html)
   2. Route bar      (.vr-route-bar)
   3. Skeletons      (.vr-skel, .vr-skel-page)
   4. Busy buttons   ([data-vr-busy])
   5. AI thinking    (.vr-ai-think)
   All colours come from the theme tokens. Motion is removed for users who
   ask for reduced motion. */

:root {
  --vr-ld-primary: var(--primary, #482dc1);
  --vr-ld-tint: var(--primary-transparent, #f1ecff);
  --vr-skel-base: #eeedf5;
  --vr-skel-shine: #f8f7fc;
}
[data-bs-theme="dark"] {
  --vr-skel-base: rgba(255, 255, 255, .06);
  --vr-skel-shine: rgba(255, 255, 255, .11);
}

/* ---------------------------------------------------------------- 1. boot */
#vr-boot {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: var(--bs-body-bg, #f7f7fb);
  opacity: 0;
  animation: vr-boot-in .2s ease .3s forwards; /* nothing shows for quick loads */
  transition: opacity .25s ease;
}
#vr-boot.is-done { opacity: 0 !important; animation: none; pointer-events: none; }
[data-bs-theme="dark"] #vr-boot { background: #13141f; }
.vr-boot-mark { width: 56px; height: 56px; filter: drop-shadow(0 10px 24px rgba(72, 45, 193, .28)); }
.vr-boot-mark rect { fill: var(--vr-ld-primary); transform-origin: 50% 50%; animation: vr-boot-pop 1.4s ease-in-out infinite; }
.vr-boot-mark path {
  fill: none; stroke: #fff; stroke-width: 3.4; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 30; stroke-dashoffset: 30;
  animation: vr-boot-draw 1.4s ease-in-out infinite;
}
.vr-boot-line { width: 120px; height: 3px; border-radius: 3px; background: var(--vr-ld-tint); overflow: hidden; position: relative; }
.vr-boot-line::after {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 40%;
  border-radius: inherit; background: var(--vr-ld-primary);
  animation: vr-boot-slide 1.1s ease-in-out infinite;
}
.vr-boot-text { margin: 0; font-size: 12.5px; color: var(--gray-500, #8a8aa0); letter-spacing: .02em; }

@keyframes vr-boot-in { to { opacity: 1; } }
@keyframes vr-boot-draw { 0% { stroke-dashoffset: 30; } 45%, 70% { stroke-dashoffset: 0; } 100% { stroke-dashoffset: -30; } }
@keyframes vr-boot-pop { 0%, 100% { transform: scale(1); } 50% { transform: scale(.94); } }
@keyframes vr-boot-slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(260%); } }

/* ===== Vryno page loader — "Connected V" =====
   The three pieces of the Vryno mark (one per app family) start apart,
   linked by a data line, then assemble into the V, catch a light sweep
   and pulse. One 2.8s loop. */
.vr-cv { width: 88px; height: 80px; overflow: visible; }
.vr-cv .pc { transform-box: view-box; animation: 2.8s cubic-bezier(.65, 0, .35, 1) infinite; }
.vr-cv .pc-b { animation-name: vr-cv-b; }
.vr-cv .pc-p { animation-name: vr-cv-p; }
.vr-cv .pc-m { animation-name: vr-cv-m; }
@keyframes vr-cv-b { 0%, 22% { transform: translate(-26px, 22px); } 42%, 82% { transform: none; } 100% { transform: translate(-26px, 22px); } }
@keyframes vr-cv-p { 0%, 22% { transform: translate(0, -2px); } 42%, 82% { transform: none; } 100% { transform: translate(0, -2px); } }
@keyframes vr-cv-m { 0%, 22% { transform: translate(28px, -20px); } 42%, 82% { transform: none; } 100% { transform: translate(28px, -20px); } }

/* data line + particles: only while the pieces are apart */
.vr-cv .link { animation: vr-cv-link 2.8s ease infinite; }
@keyframes vr-cv-link { 0%, 24% { opacity: 1; } 34%, 90% { opacity: 0; } 100% { opacity: 1; } }
.vr-cv .link polyline { stroke: #9aa3ff; stroke-width: 3; stroke-dasharray: 6 8; stroke-linecap: round; animation: vr-cv-dash 2.8s linear infinite; }
@keyframes vr-cv-dash { to { stroke-dashoffset: -56; } }
.vr-cv .node { fill: none; stroke: #fff; stroke-width: 4; }
.vr-cv .spark { fill: #fff; offset-path: path("M333 16 L198 86 L84 189"); animation: vr-cv-spark 2.8s ease-in infinite; }
@keyframes vr-cv-spark { 0% { offset-distance: 0%; opacity: 0; } 4% { opacity: 1; } 24% { offset-distance: 100%; opacity: 1; } 28%, 100% { offset-distance: 100%; opacity: 0; } }

/* light sweep across the assembled mark */
.vr-cv .sweep { transform-box: view-box; animation: vr-cv-sweep 2.8s ease-in-out infinite; }
@keyframes vr-cv-sweep { 0%, 44% { transform: translateX(-260px) skewX(-20deg); } 62%, 100% { transform: translateX(460px) skewX(-20deg); } }

/* glow pulse once assembled */
.vr-cv { animation: vr-cv-glow 2.8s ease-in-out infinite; }
@keyframes vr-cv-glow {
  0%, 58%, 96%, 100% { filter: drop-shadow(0 0 0 rgba(30, 90, 255, 0)) drop-shadow(0 0 0 rgba(255, 31, 201, 0)); }
  72% { filter: drop-shadow(0 6px 14px rgba(30, 90, 255, .55)) drop-shadow(0 -2px 12px rgba(255, 31, 201, .45)); }
}

@media (prefers-reduced-motion: reduce) {
  .vr-cv, .vr-cv .pc, .vr-cv .link, .vr-cv .link line, .vr-cv .spark, .vr-cv .sweep { animation: none !important; }
  .vr-cv .link, .vr-cv .sweep, .vr-cv .spark { display: none; }
}

#vr-boot .vr-cv { width: 88px; height: 80px; }

/* ----------------------------------------------------------- 2. route bar */
.vr-route-bar {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2500;
  height: 2px;
  width: 0;
  background: var(--vr-bar, var(--vr-ld-primary));
  box-shadow: 0 0 8px var(--vr-bar, var(--vr-ld-primary));
  border-radius: 0 2px 2px 0;
  opacity: 0;
  pointer-events: none;
  transition: width .25s ease, opacity .3s ease;
}
.vr-route-bar.is-on { opacity: 1; }

/* ----------------------------------------------------------- 3. skeletons */
.vr-skel {
  display: block;
  border-radius: 8px;
  background: linear-gradient(90deg, var(--vr-skel-base) 0%, var(--vr-skel-shine) 40%, var(--vr-skel-base) 80%) 0 0 / 300% 100%;
  animation: vr-skel-shine 1.4s ease-in-out infinite;
}
.vr-skel.c { border-radius: 50%; }
@keyframes vr-skel-shine { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* Charts that have not drawn yet show a placeholder instead of an empty gap. */
.page-wrapper [id$="chart"]:not(canvas):empty,
.page-wrapper [id$="Chart"]:not(canvas):empty,
.page-wrapper [id$="-chart"]:not(canvas):empty {
  min-height: 160px;
  border-radius: 12px;
  background: linear-gradient(90deg, var(--vr-skel-base) 0%, var(--vr-skel-shine) 40%, var(--vr-skel-base) 80%) 0 0 / 300% 100%;
  animation: vr-skel-shine 1.4s ease-in-out infinite;
}

/* Full-page skeleton shown over the content area while a page settles. */
.vr-skel-page {
  position: absolute;
  inset: 0;
  z-index: 40;
  padding: 24px;
  background: var(--bs-body-bg, #f7f7fb);
  overflow: hidden;
  transition: opacity .2s ease;
}
[data-bs-theme="dark"] .vr-skel-page { background: #13141f; }
.vr-skel-page.is-out { opacity: 0; }
.vr-sk-row { display: flex; align-items: center; gap: 12px; }
.vr-sk-card { background: var(--white, #fff); border: 1px solid var(--border-color, #eef0f5); border-radius: 16px; padding: 16px; }
[data-bs-theme="dark"] .vr-sk-card { background: rgba(255, 255, 255, .02); border-color: rgba(255, 255, 255, .06); }
.vr-sk-grid { display: grid; gap: 16px; }
.vr-sk-kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.vr-sk-two { grid-template-columns: 2fr 1fr; }
.vr-sk-three { grid-template-columns: 1fr 1.6fr 1fr; }
.vr-sk-table .vr-sk-row { padding: 12px 4px; border-top: 1px solid var(--border-color, #eef0f5); }
.vr-sk-table .vr-sk-row:first-child { border-top: 0; }
@media (max-width: 991px) {
  .vr-sk-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .vr-sk-two, .vr-sk-three { grid-template-columns: 1fr; }
}

/* -------------------------------------------------------- 4. busy buttons */
[data-vr-busy] { position: relative; pointer-events: none; cursor: progress; }
[data-vr-busy] > :not(.vr-btn-spin) { opacity: .85; }
.vr-btn-spin {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 6px;
  vertical-align: -2px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-right-color: transparent;
  animation: vr-spin .7s linear infinite;
}
@keyframes vr-spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------- 5. AI thinking */
.vr-ai-think {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 12px;
  background: var(--vr-ld-tint);
  color: var(--vr-ld-primary);
  font-size: 13px;
  font-weight: 500;
}
.vr-ai-dots { display: inline-flex; gap: 4px; }
.vr-ai-dots i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--vr-ld-primary), #8b6cff);
  animation: vr-ai-pulse 1.2s ease-in-out infinite;
}
.vr-ai-dots i:nth-child(2) { animation-delay: .15s; }
.vr-ai-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes vr-ai-pulse { 0%, 80%, 100% { transform: scale(.6); opacity: .4; } 40% { transform: scale(1); opacity: 1; } }

/* ------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  #vr-boot, .vr-boot-mark rect, .vr-boot-mark path, .vr-boot-line::after,
  .vr-skel, .vr-ai-dots i, .vr-btn-spin,
  .page-wrapper [id$="chart"]:not(canvas):empty, .page-wrapper [id$="Chart"]:not(canvas):empty, .page-wrapper [id$="-chart"]:not(canvas):empty {
    animation: none !important;
  }
  #vr-boot { opacity: 1; }
  .vr-boot-mark path { stroke-dashoffset: 0; }
  .vr-boot-line::after { width: 100%; }
  .vr-ai-dots i { opacity: .8; transform: none; }
  .vr-route-bar { transition: opacity .3s ease; }
}
