/* ==========================================================================
   Likoma Airlines — Animation Library
   --------------------------------------------------------------------------
   Motion is a supporting actor. Every keyframe here is short, eased-out and
   travels a small distance — the effect should register as responsiveness,
   not as decoration. Nothing loops except genuine loading indicators.

   Usage:
     <div class="lk-reveal" data-reveal>…</div>   ← scroll-triggered, via JS
     <div class="animate-fade-up">…</div>          ← immediate, on paint
   ========================================================================== */

/* --- Keyframes ----------------------------------------------------------- */

@keyframes lk-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes lk-fade-up {
  from { opacity: 0; transform: translate3d(0, 16px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes lk-fade-down {
  from { opacity: 0; transform: translate3d(0, -16px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes lk-fade-start {
  from { opacity: 0; transform: translate3d(-20px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes lk-fade-end {
  from { opacity: 0; transform: translate3d(20px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* The scale is deliberately shallow — 0.97, not 0.8 */
@keyframes lk-scale-in {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes lk-scale-out {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.97); }
}

/* Dropdowns and popovers: originate from their trigger edge */
@keyframes lk-pop-in {
  from { opacity: 0; transform: translate3d(0, -6px, 0) scale(0.98); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}

@keyframes lk-slide-in-end {
  from { transform: translate3d(100%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

@keyframes lk-slide-in-start {
  from { transform: translate3d(-100%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

@keyframes lk-slide-up-sheet {
  from { transform: translate3d(0, 100%, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

/* Toasts arrive from the bottom-end corner */
@keyframes lk-toast-in {
  from { opacity: 0; transform: translate3d(0, 12px, 0) scale(0.98); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}

@keyframes lk-toast-out {
  from { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
  to   { opacity: 0; transform: translate3d(0, 8px, 0) scale(0.98); }
}

@keyframes lk-spin {
  to { transform: rotate(360deg); }
}

/* Skeleton sheen — travels once per cycle, slowly */
@keyframes lk-shimmer {
  from { background-position: -160% 0; }
  to   { background-position: 160% 0; }
}

@keyframes lk-pulse-soft {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

/* Focus/attention halo on a live status dot */
@keyframes lk-ping {
  0%   { transform: scale(1); opacity: 0.55; }
  75%, 100% { transform: scale(2.2); opacity: 0; }
}

/* Progress bar for an indeterminate search */
@keyframes lk-indeterminate {
  0%   { inset-inline-start: -35%; inline-size: 35%; }
  60%  { inset-inline-start: 100%; inline-size: 45%; }
  100% { inset-inline-start: 100%; inline-size: 45%; }
}

/* Material-style ripple on button press */
@keyframes lk-ripple {
  from { transform: scale(0); opacity: 0.32; }
  to   { transform: scale(2.6); opacity: 0; }
}

/* The aircraft mark drifting across a loading state */
@keyframes lk-fly-across {
  from { transform: translate3d(-14%, 0, 0); opacity: 0; }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  to   { transform: translate3d(114%, 0, 0); opacity: 0; }
}

/* Very slow parallax drift for hero background imagery */
@keyframes lk-drift {
  from { transform: scale(1.06) translate3d(0, 0, 0); }
  to   { transform: scale(1.12) translate3d(0, -1.5%, 0); }
}

@keyframes lk-bob {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -6px, 0); }
}

/* --- Ready-made animation classes ---------------------------------------- */

.animate-fade       { animation: lk-fade-in var(--duration-slow) var(--ease-out) both; }
.animate-fade-up    { animation: lk-fade-up var(--duration-slow) var(--ease-out) both; }
.animate-fade-down  { animation: lk-fade-down var(--duration-slow) var(--ease-out) both; }
.animate-fade-start { animation: lk-fade-start var(--duration-slow) var(--ease-out) both; }
.animate-fade-end   { animation: lk-fade-end var(--duration-slow) var(--ease-out) both; }
.animate-scale-in   { animation: lk-scale-in var(--duration-base) var(--ease-out) both; }
.animate-pop-in     { animation: lk-pop-in var(--duration-fast) var(--ease-out) both; }
.animate-spin       { animation: lk-spin 720ms linear infinite; }
.animate-pulse      { animation: lk-pulse-soft 2s var(--ease-in-out) infinite; }
.animate-bob        { animation: lk-bob 4s var(--ease-in-out) infinite; }

/* --- Stagger -------------------------------------------------------------
   Applied to a parent; children animate in sequence. Capped at 8 so a long
   list never leaves the last item waiting.
   ------------------------------------------------------------------------ */

.stagger > *  { animation-fill-mode: both; }
.stagger > *:nth-child(1) { animation-delay: 0ms; }
.stagger > *:nth-child(2) { animation-delay: 60ms; }
.stagger > *:nth-child(3) { animation-delay: 120ms; }
.stagger > *:nth-child(4) { animation-delay: 180ms; }
.stagger > *:nth-child(5) { animation-delay: 240ms; }
.stagger > *:nth-child(6) { animation-delay: 300ms; }
.stagger > *:nth-child(7) { animation-delay: 360ms; }
.stagger > *:nth-child(n + 8) { animation-delay: 420ms; }

.delay-100 { animation-delay: 100ms; }
.delay-200 { animation-delay: 200ms; }
.delay-300 { animation-delay: 300ms; }
.delay-500 { animation-delay: 500ms; }

/* --- Scroll reveal -------------------------------------------------------
   Progressive enhancement. `data-reveal` elements start hidden only once JS
   confirms IntersectionObserver support (it sets `js-reveal` on <html>), so
   content is never trapped invisible.
   ------------------------------------------------------------------------ */

.js-reveal [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition:
    opacity var(--duration-slower) var(--ease-out),
    transform var(--duration-slower) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}

.js-reveal [data-reveal="start"] { transform: translate3d(-24px, 0, 0); }
.js-reveal [data-reveal="end"]   { transform: translate3d(24px, 0, 0); }
.js-reveal [data-reveal="scale"] { transform: scale(0.97); }
.js-reveal [data-reveal="fade"]  { transform: none; }

.js-reveal [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* --- Ripple --------------------------------------------------------------
   The span is injected by buttons.js at the pointer position.
   ------------------------------------------------------------------------ */

.lk-ripple {
  position: absolute;
  border-radius: var(--radius-full);
  background-color: currentColor;
  pointer-events: none;
  transform: scale(0);
  animation: lk-ripple var(--duration-slower) var(--ease-out) forwards;
}

/* --- Shimmer / skeleton -------------------------------------------------- */

.lk-shimmer {
  background-image: linear-gradient(
    90deg,
    var(--color-surface-sunken) 0%,
    color-mix(in srgb, var(--color-surface-sunken) 55%, #fff) 50%,
    var(--color-surface-sunken) 100%
  );
  background-size: 220% 100%;
  animation: lk-shimmer 1.6s var(--ease-in-out) infinite;
}

/* --- Underline sweep -----------------------------------------------------
   Nav links and inline CTAs: the rule grows from the start edge on hover and
   retracts to the end edge on leave, so it always feels directional.
   ------------------------------------------------------------------------ */

.lk-underline-sweep {
  position: relative;
}

.lk-underline-sweep::after {
  content: "";
  position: absolute;
  inset-block-end: -2px;
  inset-inline: 0;
  block-size: 2px;
  border-radius: var(--radius-full);
  background-color: currentColor;
  transform: scaleX(0);
  transform-origin: 100% 50%;
  transition: transform var(--duration-base) var(--ease-out);
}

.lk-underline-sweep:hover::after,
.lk-underline-sweep:focus-visible::after,
.lk-underline-sweep[aria-current]::after {
  transform: scaleX(1);
  transform-origin: 0 50%;
}

/* --- Arrow nudge ---------------------------------------------------------- */

.lk-nudge svg,
.lk-nudge .lk-icon {
  transition: transform var(--duration-base) var(--ease-out);
}

.lk-nudge:hover svg,
.lk-nudge:hover .lk-icon,
.lk-nudge:focus-visible svg {
  transform: translateX(3px);
}

/* --- Live indicator ------------------------------------------------------- */

.lk-ping {
  position: relative;
  display: inline-flex;
}

.lk-ping::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-color: currentColor;
  animation: lk-ping 1.8s var(--ease-out) infinite;
}

/* --- View transitions ----------------------------------------------------
   Opt-in, and only where supported. Falls back to a normal navigation.
   ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: no-preference) {
  @supports (view-transition-name: none) {
    ::view-transition-old(root) {
      animation: lk-fade-in var(--duration-fast) var(--ease-in) reverse;
    }
    ::view-transition-new(root) {
      animation: lk-fade-up var(--duration-base) var(--ease-out);
    }
  }
}

/* --- Reduced motion ------------------------------------------------------
   reset.css neutralises durations globally. Here we additionally make sure
   reveal elements are visible and infinite loops stop entirely.
   ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .js-reveal [data-reveal] {
    opacity: 1;
    transform: none;
  }

  .animate-spin,
  .animate-pulse,
  .animate-bob,
  .lk-shimmer,
  .lk-ping::before {
    animation: none;
  }

  .lk-shimmer {
    background-image: none;
    background-color: var(--color-surface-sunken);
  }
}
