/* ==========================================================
   OrbitPanel — v4 enhancement (earthaccess.xyz parity)
   Goal: idle page = ZERO continuous CPU/GPU work.
   ========================================================== */

:root {
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ============================================================
   1) GLOBAL CALM: clamp every infinite animation to a single
   iteration so it reaches the rest frame and stops forever.
   Earthaccess hero has zero continuous loops — same here.
   Hover/transition effects remain unaffected.
   ============================================================ */
*,
*::before,
*::after {
  animation-iteration-count: 1 !important;
  animation-fill-mode: both !important;
}

/* Entrance / one-shot animations: stay enabled (count=1 already fine). */

/* Video bg: drop GPU zoom, add containment, fixed position so
   scroll never re-layouts it. */
#earth-video {
  position: fixed !important;
  inset: 0 !important;
  width: 100vw !important;
  height: 100vh !important;
  transform: translateZ(0) scale(1.02) !important;
  will-change: opacity, transform !important;
  transition: opacity 850ms var(--ease-out-quart, ease), transform 1100ms var(--ease-out-quart, ease) !important;
  backface-visibility: hidden !important;
  contain: strict;
  object-fit: cover;
  z-index: 0;
  /* Hidden by default — JS marks <body> as .video-ready when the first
     real frame is decoded, then we cinematically reveal. */
  opacity: 0 !important;
  animation: none !important;
}
body.video-ready #earth-video {
  opacity: 0.72 !important;
  transform: translateZ(0) scale(1) !important;
}
body.is-lowpower.video-ready #earth-video {
  opacity: 0.42 !important;
}

/* ============================================================
   SMOOTH PAGE-OPEN ANIMATION
   On every page open, gently lift the content into view and let
   the video bloom in behind it. One-shot, no repeats.
   ============================================================ */
.wrap, .shell, .panel {
  animation: opPageIn 720ms var(--ease-out-quart, cubic-bezier(0.25, 1, 0.5, 1)) 80ms both;
}
@keyframes opPageIn {
  from { opacity: 0; transform: translateY(14px); filter: blur(6px); }
  to   { opacity: 1; transform: translateY(0);     filter: blur(0); }
}
@media (prefers-reduced-motion: reduce) {
  .wrap, .shell, .panel { animation: none !important; }
}
/* The various pages each wrap the video in a .stage / .panel container
   with a solid #03040a background. That solid layer would HIDE our
   beautiful CSS earth-glow during the brief moment before the decoder
   emits its first frame. Make those backgrounds transparent so users
   never stare at a flat-black panel. */
.stage, .panel { background: transparent !important; }

/* ============================================================
   STATIC EARTH-GLOW BASE LAYER — pure CSS, zero per-frame cost.
   Sits behind the video. On mobile / low-end devices it BECOMES
   the background (video is removed completely from the DOM).
   ============================================================ */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(ellipse 70% 55% at 50% 58%, rgba(34, 211, 238, 0.18) 0%, rgba(34, 211, 238, 0.06) 28%, transparent 60%),
    radial-gradient(ellipse 55% 40% at 50% 60%, rgba(99, 102, 241, 0.18) 0%, transparent 65%),
    radial-gradient(ellipse 95% 70% at 50% 100%, rgba(3, 7, 18, 0.95) 0%, rgba(3, 7, 18, 0.6) 60%, transparent 100%),
    linear-gradient(180deg, #03060f 0%, #050a18 45%, #03060f 100%);
}
body::after {
  /* Sparse star dots — single static paint, no animation. */
  content: "";
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    radial-gradient(1px 1px at 12% 18%, rgba(255,255,255,0.55), transparent 50%),
    radial-gradient(1px 1px at 78% 22%, rgba(255,255,255,0.45), transparent 50%),
    radial-gradient(1px 1px at 32% 80%, rgba(255,255,255,0.5), transparent 50%),
    radial-gradient(1px 1px at 62% 64%, rgba(255,255,255,0.4), transparent 50%),
    radial-gradient(1px 1px at 88% 88%, rgba(255,255,255,0.5), transparent 50%),
    radial-gradient(1px 1px at 18% 52%, rgba(255,255,255,0.35), transparent 50%),
    radial-gradient(1px 1px at 50% 12%, rgba(255,255,255,0.45), transparent 50%),
    radial-gradient(1px 1px at 92% 48%, rgba(255,255,255,0.35), transparent 50%);
  opacity: 0.65;
}

/* Grain is a constant compositing cost on idle frames → kill it
   completely (earthaccess paints noise into a static <canvas>
   exactly once, not as a blend layer). */
.grain { display: none !important; }

/* ============================================================
   GLASS UPLIFT — slightly stronger glass on cards/panels.
   Desktop only (>= 769px). Mobile keeps lighter inline values
   so battery / weak GPUs are not hit. Static, no animation.
   ============================================================ */
@media (min-width: 769px) {
  header,
  .panel,
  .device-card,
  .sim-card,
  .stat,
  .tabs,
  .upipin-hero,
  .tg-card,
  .login-card,
  .card,
  .glass {
    backdrop-filter: blur(18px) saturate(145%) !important;
    -webkit-backdrop-filter: blur(18px) saturate(145%) !important;
  }
  .panel, .device-card, .sim-card, .upipin-hero, .tg-card, .login-card {
    box-shadow:
      0 24px 64px -22px rgba(0,0,0,0.55),
      inset 0 1px 0 rgba(255,255,255,0.09),
      inset 0 0 0 1px rgba(255,255,255,0.02) !important;
  }
}

/* ============================================================
   GLASSY PREMIUM TOAST / NOTIFICATIONS
   Covers .toast (device/login/settings) AND #op-toast (dashboard).
   Frosted glass + animated gradient border + soft inner glow.
   ============================================================ */
.toast,
#op-toast {
  position: fixed !important;
  right: 24px !important;
  bottom: 26px !important;
  left: auto !important;
  transform: translateX(0) translateY(14px) !important;
  min-width: 240px;
  max-width: min(92vw, 420px);
  padding: 14px 20px !important;
  border-radius: 16px !important;
  background:
    linear-gradient(135deg, rgba(34,211,238,0.10), rgba(217,255,0,0.04) 50%, rgba(125,211,252,0.08)),
    rgba(8,12,22,0.45) !important;
  backdrop-filter: blur(28px) saturate(160%) !important;
  -webkit-backdrop-filter: blur(28px) saturate(160%) !important;
  border: 1px solid rgba(255,255,255,0.14) !important;
  color: #f1f5f9 !important;
  font-family: "Manrope", system-ui, -apple-system, sans-serif !important;
  font-size: 13px !important;
  font-weight: 500 !important;
  letter-spacing: 0.01em !important;
  line-height: 1.45 !important;
  text-align: left !important;
  opacity: 0 !important;
  pointer-events: none;
  z-index: 9999 !important;
  box-shadow:
    0 24px 60px -18px rgba(0,0,0,0.55),
    0 0 0 1px rgba(34,211,238,0.18),
    inset 0 1px 0 rgba(255,255,255,0.14),
    inset 0 -1px 0 rgba(0,0,0,0.25) !important;
  transition:
    transform 380ms cubic-bezier(0.16, 1, 0.3, 1),
    opacity 280ms cubic-bezier(0.25, 1, 0.5, 1) !important;
  overflow: hidden;
  isolation: isolate;
}

/* Animated gradient ring on top edge */
.toast::before,
#op-toast::before {
  content: ""; position: absolute; inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(120deg,
    rgba(34,211,238,0.55),
    rgba(217,255,0,0.45) 35%,
    rgba(165,180,252,0.55) 70%,
    rgba(34,211,238,0.45));
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
  opacity: 0.55;
}

/* Soft inner glow */
.toast::after,
#op-toast::after {
  content: ""; position: absolute; inset: 0;
  border-radius: inherit;
  background:
    radial-gradient(120% 60% at 10% 0%, rgba(34,211,238,0.18), transparent 55%),
    radial-gradient(120% 60% at 100% 100%, rgba(217,255,0,0.12), transparent 55%);
  pointer-events: none;
  z-index: -1;
}

/* Shown state — JS adds .show class (or sets opacity inline) */
.toast.show,
#op-toast[style*="opacity: 1"],
#op-toast.show {
  transform: translateX(0) translateY(0) !important;
  opacity: 1 !important;
  pointer-events: auto;
}

/* Variants — success / error tint the ring + glow */
.toast.success,
#op-toast.success {
  box-shadow:
    0 24px 60px -18px rgba(0,0,0,0.55),
    0 0 0 1px rgba(217,255,0,0.45),
    0 0 28px -6px rgba(217,255,0,0.35),
    inset 0 1px 0 rgba(255,255,255,0.16) !important;
}
.toast.success::before,
#op-toast.success::before {
  background: linear-gradient(120deg,
    rgba(217,255,0,0.85),
    rgba(34,197,94,0.55) 50%,
    rgba(217,255,0,0.75));
  opacity: 0.85;
}

.toast.error,
#op-toast.error {
  box-shadow:
    0 24px 60px -18px rgba(0,0,0,0.55),
    0 0 0 1px rgba(248,113,113,0.5),
    0 0 28px -6px rgba(248,113,113,0.35),
    inset 0 1px 0 rgba(255,255,255,0.14) !important;
}
.toast.error::before,
#op-toast.error::before {
  background: linear-gradient(120deg,
    rgba(248,113,113,0.85),
    rgba(251,113,133,0.5) 50%,
    rgba(252,165,165,0.75));
  opacity: 0.9;
}

/* Login page has a richer toast with .ic icon — keep it readable */
.toast .ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 9px;
  margin-right: 10px;
  flex-shrink: 0;
  box-shadow: 0 4px 14px -4px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.25);
}

/* Reduced motion / low-power — keep glass but skip transition */
body.is-lowpower .toast,
body.is-lowpower #op-toast {
  backdrop-filter: blur(20px) saturate(140%) !important;
  -webkit-backdrop-filter: blur(20px) saturate(140%) !important;
}
@media (prefers-reduced-motion: reduce) {
  .toast, #op-toast { transition: opacity 80ms linear !important; }
}

/* ============================================================
   2) LOW-POWER MODE: when body.is-lowpower (tab hidden / blur /
   reduced-motion / low-battery / save-data), freeze + dim.
   ============================================================ */
body.is-lowpower *,
body.is-lowpower *::before,
body.is-lowpower *::after {
  animation: none !important;
}
body.is-lowpower .vignette { display: none !important; }
body.is-lowpower #earth-video { filter: none !important; }

/* ============================================================
   3) Interaction polish (transitions, not loops)
   ============================================================ */
button, .btn, .btn-primary, .btn-ghost, .btn-cyan, .btn-secondary,
.tab, .nav-link, .logout-btn, .back-link,
a.btn, a.brand, .device-card, input[type="submit"] {
  transition:
    transform 380ms var(--ease-out-expo),
    background-color 320ms var(--ease-out-quart),
    color 240ms var(--ease-out-quart),
    border-color 320ms var(--ease-out-quart),
    box-shadow 380ms var(--ease-out-expo),
    opacity 240ms var(--ease-out-quart) !important;
}
button:active:not(:disabled),
.btn:active, .tab:active, .nav-link:active,
.logout-btn:active, .back-link:active,
input[type="submit"]:active {
  transform: scale(0.96) !important;
  transition-duration: 90ms !important;
}

/* Tabs */
.tab { position: relative; overflow: hidden; isolation: isolate; }
.tab::before {
  content: ""; position: absolute; inset: 0;
  border-radius: inherit; background: #d9ff00;
  opacity: 0; transform: scale(0.8);
  transition: opacity 360ms var(--ease-out-expo), transform 480ms var(--ease-out-expo);
  z-index: -1;
}
.tab.active::before { opacity: 1; transform: scale(1); }
.tab:not(.active):hover { transform: translateY(-1px); background: rgba(255,255,255,0.04) !important; }
.tab.active { transform: translateY(-1px); }

/* Ripple */
.tab::after, .btn-primary::after, .btn-ghost::after, .btn-cyan::after,
.btn::after, .nav-link::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 8px; height: 8px; border-radius: 50%;
  background: rgba(255,255,255,0.55);
  transform: translate(-50%, -50%) scale(0);
  opacity: 0; pointer-events: none;
  transition: transform 620ms var(--ease-out-expo), opacity 620ms var(--ease-out-expo);
}
.tab.ripple::after, .btn-primary.ripple::after, .btn-ghost.ripple::after,
.btn-cyan.ripple::after, .btn.ripple::after, .nav-link.ripple::after {
  transform: translate(-50%, -50%) scale(32); opacity: 0;
  transition: transform 620ms var(--ease-out-expo), opacity 620ms var(--ease-out-expo);
}
.tab, .btn, .btn-primary, .btn-ghost, .btn-cyan, .nav-link {
  position: relative; overflow: hidden;
}

/* Hover lift */
.btn-primary:hover:not(:disabled) {
  transform: translateY(-3px) scale(1.02) !important;
  box-shadow: 0 22px 48px -12px rgba(217,255,0,0.55) !important;
}
.btn-ghost:hover { transform: translateY(-2px) !important; }
.btn-cyan:hover { transform: translateY(-3px) scale(1.02) !important; }
.logout-btn:hover { transform: translateY(-1px) !important; }

/* Panel enter (one-shot) */
.panel.active { animation: panelSlideIn 420ms var(--ease-out-expo) both; }
@keyframes panelSlideIn {
  from { opacity: 0; transform: translateY(10px) scale(0.995); filter: blur(4px); }
  to   { opacity: 1; transform: translateY(0)    scale(1);     filter: blur(0); }
}

/* New message highlight (one-shot, count clamped to 1 anyway) */
.msg {
  transition:
    border-color 320ms var(--ease-out-quart),
    background-color 480ms var(--ease-out-quart),
    transform 420ms var(--ease-out-expo),
    box-shadow 480ms var(--ease-out-expo) !important;
}
.msg.is-new {
  animation: newMsgPulse 1800ms var(--ease-out-expo);
  border-color: rgba(217,255,0,0.55) !important;
  background: linear-gradient(90deg, rgba(217,255,0,0.10), rgba(34,211,238,0.04)) !important;
  box-shadow: 0 0 0 1px rgba(217,255,0,0.35), 0 10px 36px -12px rgba(217,255,0,0.35);
}
.msg.is-new .msg-avatar { animation: avatarPing 1200ms var(--ease-out-expo); }
@keyframes newMsgPulse {
  0%   { transform: translateX(-12px); opacity: 0; }
  50%  { transform: translateX(0); opacity: 1; }
  100% { transform: translateX(0); }
}
@keyframes avatarPing {
  0%   { box-shadow: 0 0 0 0 rgba(217,255,0,0.7); }
  100% { box-shadow: 0 0 0 18px rgba(217,255,0,0); }
}

/* "New" pill — keep visible, just don't pulse forever */
.tab .tab-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: #ff3860; margin-left: 6px;
  box-shadow: 0 0 10px #ff3860;
  vertical-align: middle; opacity: 0; transform: scale(0);
  transition: opacity 240ms ease, transform 320ms var(--ease-bounce);
}
.tab .tab-dot.show { opacity: 1; transform: scale(1); }

/* Device cards */
.device-card:hover {
  transform: translateY(-4px) scale(1.01) !important;
  box-shadow: 0 26px 60px -16px rgba(34,211,238,0.35) !important;
}

/* Nav underline */
.nav-link { position: relative; }
.nav-link::before {
  content: ""; position: absolute;
  left: 14px; right: 14px; bottom: 6px;
  height: 2px;
  background: linear-gradient(90deg, #d9ff00, #22d3ee);
  border-radius: 2px;
  transform: scaleX(0); transform-origin: left center;
  opacity: 0;
  transition: transform 420ms var(--ease-out-expo), opacity 320ms ease;
}
.nav-link:hover::before, .nav-link.active::before {
  transform: scaleX(1); opacity: 1;
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.05ms !important;
  }
  #earth-video { animation: none !important; opacity: 0.45 !important; }
  .grain, .vignette { display: none !important; }
}
