/*
 * Wave Wallet — motion and native-shell styling.
 *
 * Rules this file sticks to, because they are what separates smooth from janky
 * inside a webview on a mid-range phone:
 *   • animate transform and opacity only — never width/height/top/left;
 *   • micro-interactions 120–180ms, screen transitions 250–350ms;
 *   • every decorative animation collapses under prefers-reduced-motion.
 */

:root {
  --wave-dur-instant: 120ms;
  --wave-dur-fast: 180ms;
  --wave-dur-base: 280ms;
  --wave-dur-slow: 420ms;

  /* Deceleration curve close to the platform default — things arrive calmly. */
  --wave-ease-out: cubic-bezier(0.32, 0.72, 0, 1);
  --wave-ease-in: cubic-bezier(0.4, 0, 1, 1);
  --wave-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  --wave-accent: #7b5cf5;
  --wave-accent-2: #a94fe0;
  --wave-ok: #2fd99a;
  --wave-bad: #e5604d;
  --wave-bg: #0c0a14;

  /* Zero on the web, real insets inside the app. */
  --wave-safe-top: env(safe-area-inset-top, 0px);
  --wave-safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* ---------- packaged app ---------- */

/*
 * In the browser the UI is presented inside a phone mock-up with a drawn status
 * bar. On a real device that frame is a bezel inside a bezel and the fake clock
 * sits under the real one, so both disappear.
 */
.wave-native .mobile-container,
.wave-installed .mobile-container {
  padding: 0 !important;
  align-items: stretch !important;
  background: var(--wave-bg) !important;
  min-height: 100vh;
  min-height: 100dvh;
}

.wave-native .mobile-phone-frame,
.wave-installed .mobile-phone-frame {
  width: 100% !important;
  height: 100vh !important;
  height: 100dvh !important;
  max-height: none !important;
  border-radius: 0 !important;
  border: none !important;
  box-shadow: none !important;
}

/*
 * Both the packaged app and a home-screen install run without browser chrome,
 * so the drawn phone frame and its fake clock are dropped in either case.
 */
.wave-native .status-bar,
.wave-installed .status-bar { display: none !important; }

/* Content must clear the notch, the home indicator and the gesture bar. */
.wave-native #scrollarea,
.wave-installed #scrollarea { padding-top: var(--wave-safe-top); }
.wave-native .tab-bar-container,
.wave-installed .tab-bar-container { padding-bottom: calc(28px + var(--wave-safe-bottom)) !important; }

/* Text selection and the long-press callout are desktop affordances. */
.wave-native, .wave-native * {
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}
.wave-native input, .wave-native textarea { user-select: text; }

/*
 * Backgrounded app: the switcher snapshot must not expose balances. Applied to
 * the frame rather than the body so the blur cannot be screenshotted mid-fade.
 */
.wave-obscured .mobile-phone-frame {
  filter: blur(18px);
  transition: filter 80ms linear;
}

/* ---------- entrances ---------- */

@keyframes waveEnter {
  from { opacity: 0; transform: translate3d(0, 12px, 0); }
  to { opacity: 1; transform: none; }
}

.wave-enter {
  animation: waveEnter var(--wave-dur-base) var(--wave-ease-out) both;
}

@keyframes waveFadeIn { from { opacity: 0; } to { opacity: 1; } }

/* ---------- skeletons ---------- */

/*
 * Shown while balances load. A spinner says "wait"; a skeleton says "your
 * dashboard is arriving", which is both truer and calmer.
 */
.wave-skeleton {
  position: relative;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 10px;
  color: transparent !important;
}
.wave-skeleton::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.09), transparent);
  animation: waveShimmer 1.4s infinite;
}
@keyframes waveShimmer { to { transform: translateX(100%); } }

/* ---------- feedback ---------- */

@keyframes waveShake {
  0%, 100% { transform: translate3d(0, 0, 0); }
  15% { transform: translate3d(-8px, 0, 0); }
  30% { transform: translate3d(7px, 0, 0); }
  45% { transform: translate3d(-5px, 0, 0); }
  60% { transform: translate3d(4px, 0, 0); }
  80% { transform: translate3d(-2px, 0, 0); }
}
.wave-shake { animation: waveShake 500ms cubic-bezier(0.36, 0.07, 0.19, 0.97); }

/* ---------- overlay layer ---------- */

#wave-native-layer {
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
}

/* Toasts */
.wave-toast {
  pointer-events: none;
  margin-bottom: calc(96px + var(--wave-safe-bottom));
  max-width: min(88vw, 360px);
  padding: 12px 18px;
  border-radius: 14px;
  background: rgba(32, 25, 52, 0.96);
  border: 1px solid rgba(255, 255, 255, 0.11);
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.45);
  color: #ece9f5;
  font: 500 14px/1.4 'Plus Jakarta Sans', system-ui, sans-serif;
  text-align: center;
  opacity: 0;
  transform: translate3d(0, 14px, 0) scale(0.96);
  transition: opacity var(--wave-dur-fast) var(--wave-ease-out),
              transform var(--wave-dur-fast) var(--wave-ease-out);
}
.wave-toast.in { opacity: 1; transform: none; }
.wave-toast-error {
  background: rgba(64, 24, 22, 0.96);
  border-color: rgba(229, 96, 77, 0.4);
  color: #ffb3a5;
}
.wave-toast-success {
  background: rgba(16, 52, 40, 0.96);
  border-color: rgba(47, 217, 154, 0.38);
  color: #7fe9bf;
}

/* Operation result */
.wave-result {
  pointer-events: auto;
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(7, 6, 13, 0.82);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  opacity: 0;
  transition: opacity var(--wave-dur-fast) var(--wave-ease-out);
}
.wave-result.in { opacity: 1; }

.wave-result-card {
  text-align: center;
  padding: 34px 30px;
  transform: scale(0.9);
  transition: transform var(--wave-dur-base) var(--wave-spring);
}
.wave-result.in .wave-result-card { transform: scale(1); }

.wave-result-icon { width: 92px; height: 92px; margin: 0 auto 20px; }
.wave-result-icon svg { width: 100%; height: 100%; }

.wave-result-icon .wr-circle {
  fill: none;
  stroke-width: 2.5;
  stroke-dasharray: 151;
  stroke-dashoffset: 151;
}
.wave-result-icon .wr-check {
  fill: none;
  stroke-width: 3.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 48;
  stroke-dashoffset: 48;
}
.wave-result-success .wr-circle { stroke: var(--wave-ok); }
.wave-result-success .wr-check { stroke: var(--wave-ok); }
.wave-result-error .wr-circle { stroke: var(--wave-bad); }
.wave-result-error .wr-check { stroke: var(--wave-bad); }

/* The ring draws itself, then the mark is written inside it. */
.wave-result.in .wr-circle { animation: waveDraw 520ms var(--wave-ease-out) forwards; }
.wave-result.in .wr-check { animation: waveDraw 320ms var(--wave-ease-out) 380ms forwards; }
@keyframes waveDraw { to { stroke-dashoffset: 0; } }

.wave-result-title {
  font: 700 20px/1.3 'Unbounded', system-ui, sans-serif;
  color: #ece9f5;
  margin-bottom: 8px;
}
.wave-result-sub {
  font: 400 14px/1.5 'Plus Jakarta Sans', system-ui, sans-serif;
  color: #9a93ad;
  max-width: 260px;
  margin: 0 auto;
}

/* ---------- pressed state ---------- */

/*
 * The press scale is applied inline by native.js so it composes with whatever
 * transform an element already carries; this only guarantees the element is a
 * compositing layer so the first tap is not the one that stutters.
 */
.ripple-btn, .tab-item, button, [data-press] { will-change: transform; }

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .wave-skeleton::after { animation: none; }
  .wave-result-icon .wr-circle,
  .wave-result-icon .wr-check { stroke-dashoffset: 0; }
}
