/* ============================================================
   Animations — every keyframe here maps to a specific beat:
   Tru-We's entrance flight, the city's ambient life, the CTA's
   premium sweep, and the fade into the "Loading Assessment" state.
   ============================================================ */

/* ---------- Shared ---------- */
@keyframes orb-drift {
  0%, 100% { transform: translate(0, 0) scale(1);     opacity: 0.4; }
  50%      { transform: translate(26px, 16px) scale(1.06); opacity: 0.55; }
}

@keyframes fog-drift {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(-40px, 24px) scale(1.12); }
}

@keyframes ray-pulse {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 0.7; }
}

@keyframes node-pulse {
  0%, 100% { opacity: 0.2; transform: scale(1); }
  50%      { opacity: 0.7; transform: scale(1.6); }
}

@keyframes node-line-pulse {
  0%, 100% { opacity: 0.15; }
  50%      { opacity: 0.4; }
}

@keyframes bg-particle-drift {
  0%   { transform: translateY(0) scale(0.8); opacity: 0; }
  10%  { opacity: 0.6; }
  90%  { opacity: 0.3; }
  100% { transform: translateY(-100vh) scale(1.1); opacity: 0; }
}

@keyframes btn-sweep {
  to { transform: rotate(360deg); }
}

@keyframes btn-shine-sweep {
  0%   { left: -30%; }
  60%, 100% { left: 130%; }
}

/* ---------- Tru-We: settles quietly into place, no flying around ---------- */
@keyframes mascot-settle-in {
  0%   { opacity: 0; transform: translateY(16px) scale(0.92); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* Idle float once settled — slow and premium, not a bounce */
@keyframes float {
  0%, 100% { transform: translateY(0) rotate(-1deg); }
  50%      { transform: translateY(-8px) rotate(1deg); }
}

@keyframes glow-pulse {
  0%, 100% { opacity: 0.4; transform: translateX(-50%) scale(0.9); }
  50%      { opacity: 0.8; transform: translateX(-50%) scale(1.08); }
}

/* Fades in, holds for ~4s, then fades away for good (no loop, no repeat) */
@keyframes bubble-lifecycle {
  0%   { opacity: 0; transform: translateY(6px); }
  12%  { opacity: 1; transform: translateY(0); }
  85%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-6px); }
}

/* ---------- Digital city — alive, but calm ---------- */
@keyframes city-light-pulse {
  0%, 100% { opacity: 0.2; }
  50%      { opacity: 0.85; }
}

/* Irregular, stepped flicker — deliberately uneven so it reads as random */
@keyframes city-light-flicker {
  0%   { opacity: 0.85; }
  8%   { opacity: 0.25; }
  19%  { opacity: 0.7; }
  27%  { opacity: 0.3; }
  41%  { opacity: 0.8; }
  53%  { opacity: 0.35; }
  68%  { opacity: 0.6; }
  79%  { opacity: 0.2; }
  91%  { opacity: 0.75; }
  100% { opacity: 0.85; }
}

@keyframes city-window-pulse {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 0.68; }
}

@keyframes city-building-glow {
  0%, 100% {
    filter: drop-shadow(0 0 7px rgba(41, 151, 255, 0.22)) drop-shadow(0 0 16px rgba(41, 151, 255, 0.12));
  }
  50% {
    filter: drop-shadow(0 0 11px rgba(41, 151, 255, 0.34)) drop-shadow(0 0 22px rgba(41, 151, 255, 0.2));
  }
}

@keyframes antenna-blink {
  0%, 40%  { opacity: 1; }
  50%, 90% { opacity: 0.15; }
  100%     { opacity: 1; }
}

@keyframes particle-rise {
  0%   { transform: translateY(0) scale(0.8); opacity: 0; }
  15%  { opacity: 0.85; }
  85%  { opacity: 0.35; }
  100% { transform: translateY(-170px) scale(1.1); opacity: 0; }
}

@keyframes badge-link-pulse {
  0%, 100% { opacity: 0.25; stroke-dashoffset: 0; }
  50%      { opacity: 0.55; stroke-dashoffset: -9.2; }
}

/* ---------- Category Selection (V2): particles drifting inside each card ---------- */
@keyframes card-particle-drift {
  0%, 100% { opacity: 0; transform: translateY(0); }
  15%      { opacity: 0.8; }
  50%      { transform: translateY(-18px); }
  85%      { opacity: 0.4; }
}

/* ---------- Category badges around the city ---------- */
@keyframes badge-float {
  0%, 100% { transform: translateY(0);   filter: brightness(1); }
  50%      { transform: translateY(-8px); filter: brightness(1.15); }
}

/* Traveling highlight along a connector line on hover/focus */
@keyframes badge-energy-flow {
  from { stroke-dashoffset: 23.2; }
  to   { stroke-dashoffset: 0; }
}

/* Faint distant light points behind the city */
@keyframes ambient-twinkle {
  0%, 100% { opacity: 0.12; }
  50%      { opacity: 0.4; }
}

/* ---------- Digital globe (index.html hero) — ambient life ---------- */
@keyframes globe-halo-breathe {
  0%, 100% { opacity: 0.55; transform: scale(1); }
  50%      { opacity: 0.8;  transform: scale(1.04); }
}

/* ---------- Sequential category pulse: Infrastructure -> Cyber Security ->
   Operations -> Licensing -> AI & Automation -> repeat. One 10s cycle, each
   category's --seq delay (0/2/4/6/8s) gives it a ~1.8s illuminated window
   (0.4s fade in, 1s hold, 0.4s fade out) with the rest of the cycle spent
   dim/subtle so only one category is ever strongly lit at a time. ---------- */
@keyframes label-sequence-pulse {
  0%, 18%, 100% {
    color: var(--tw-ink-2);
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.9);
    transform: scale(1);
  }
  4%, 14% {
    color: var(--tw-white);
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.9), 0 0 14px rgba(41, 151, 255, 0.85),
      0 0 26px rgba(125, 211, 252, 0.5);
    transform: scale(1.08);
  }
}

@keyframes icon-sequence-pulse {
  0%, 18%, 100% {
    border-color: rgba(125, 211, 252, 0.42);
    color: var(--tw-electric-bright);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.09),
      0 3px 8px rgba(0, 0, 0, 0.4),
      0 0 0 1px rgba(125, 211, 252, 0.1),
      0 0 20px rgba(41, 151, 255, 0.22);
    transform: translateY(0) scale(1);
  }
  4%, 14% {
    border-color: rgba(255, 255, 255, 0.65);
    color: var(--tw-white);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.2),
      0 10px 20px rgba(0, 0, 0, 0.45),
      0 0 0 1px rgba(255, 255, 255, 0.45),
      0 0 50px rgba(41, 151, 255, 0.75);
    transform: translateY(-6px) scale(1.14);
  }
}

@keyframes badge-halo-sequence-pulse {
  0%, 18%, 100% { opacity: 0;    transform: scale(0.85); }
  4%, 14%       { opacity: 0.55; transform: scale(1.15); }
}

@keyframes link-sequence-pulse {
  0%, 18%, 100% {
    opacity: 0.32;
    stroke-width: 0.35;
    filter: none;
  }
  4%, 14% {
    opacity: 1;
    stroke-width: 0.7;
    filter: drop-shadow(0 0 4px rgba(125, 211, 252, 0.9)) drop-shadow(0 0 8px rgba(41, 151, 255, 0.6));
  }
}

@keyframes node-sequence-pulse {
  0%, 18%, 100% {
    opacity: 0.45;
    transform: scale(1);
    filter: drop-shadow(0 0 2px rgba(125, 211, 252, 0.6));
  }
  4%, 14% {
    opacity: 1;
    transform: scale(1.9);
    filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.9)) drop-shadow(0 0 12px rgba(41, 151, 255, 0.9));
  }
}

/* Matching soft glow around the globe itself — bumps once per category
   activation, five times across the same 10s cycle. */
@keyframes globe-active-glow-sequence {
  0%, 18%, 20%, 38%, 40%, 58%, 60%, 78%, 80%, 98%, 100% {
    opacity: 0;
    transform: scale(0.92);
  }
  4%, 14%, 24%, 34%, 44%, 54%, 64%, 74%, 84%, 94% {
    opacity: 0.85;
    transform: scale(1.08);
  }
}

/* ---------- Assessment Questions (V3): card entrance, tile stagger, progress glow ---------- */
@keyframes card-float-in {
  0%   { opacity: 0; transform: translateY(24px) scale(0.98); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* Animates the standalone `translate` property, not `transform` — with
   `forwards` fill-mode the animation's final value keeps animation-level
   cascade priority forever, which would permanently block a hover/lift
   `transform` declared on the same element. Keeping the entrance offset on
   `translate` leaves `transform` free for that hover state. */
@keyframes tile-in {
  0%   { opacity: 0; translate: 0 14px; }
  100% { opacity: 1; translate: 0 0; }
}

@keyframes progress-fill-glow {
  0%, 100% { box-shadow: 0 0 10px rgba(41, 151, 255, 0.5); }
  50%      { box-shadow: 0 0 18px rgba(41, 151, 255, 0.85); }
}

/* ---------- Lead Capture (V4): unlock checklist stagger, field validation ---------- */
@keyframes unlock-item-in {
  0%   { opacity: 0; transform: translateX(-14px); }
  100% { opacity: 1; transform: translateX(0); }
}

@keyframes check-pop-in {
  0%   { opacity: 0; transform: scale(0.4); }
  60%  { opacity: 1; transform: scale(1.15); }
  100% { opacity: 1; transform: scale(1); }
}

@keyframes field-error-in {
  0%   { opacity: 0; transform: translateY(-4px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ---------- Results Dashboard (V5): card rise-in, gauge pulse, AI icon, mascot blink ---------- */
/* Animates the standalone `translate` property, not `transform` — with
   `forwards` fill-mode the animation's final value keeps animation-level
   cascade priority forever, which would permanently block a hover "pop"
   `transform` declared on the same element. Keeping the entrance offset on
   `translate` leaves `transform` free for that hover state. */
@keyframes card-rise-in {
  0%   { opacity: 0; translate: 0 18px; }
  100% { opacity: 1; translate: 0 0; }
}

@keyframes gauge-pulse {
  0%, 100% { box-shadow: 0 0 24px 2px currentColor; opacity: 0.55; }
  50%      { box-shadow: 0 0 46px 10px currentColor; opacity: 0.9; }
}

@keyframes ai-icon-pulse {
  0%, 100% { transform: scale(1) rotate(0deg); }
  50%      { transform: scale(1.08) rotate(8deg); }
}

/* ---------- CTA loading state ---------- */
@keyframes loader-spin {
  to { transform: rotate(360deg); }
}

/* ---------- Entrance animation (staggered fade-up) ---------- */
.reveal {
  opacity: 0;
  transform: translateY(20px);
  animation: reveal-up var(--dur-slow) var(--ease-out) forwards;
}

.reveal-delay-1 { animation-delay: 0.1s; }
.reveal-delay-2 { animation-delay: 0.22s; }
.reveal-delay-3 { animation-delay: 0.34s; }
.reveal-delay-4 { animation-delay: 0.46s; }
.reveal-delay-5 { animation-delay: 0.58s; }

@keyframes reveal-up {
  to { opacity: 1; transform: translateY(0); }
}

/* ---------- Page transition into "Loading Assessment…" ---------- */
.is-transitioning .hero {
  transition: opacity 0.5s ease, filter 0.5s ease;
  opacity: 0;
  filter: blur(8px);
  pointer-events: none;
}
