:root {
  /* Glass surfaces: opacity deliberately high (0.85+) so the effective composite
     color stays stable even where two gradient orbs overlap at peak opacity behind it. */
  --glass-bg: rgba(4, 14, 46, 0.88);
  --glass-border: rgba(74, 222, 222, 0.28);
  --glass-border-hover: rgba(74, 222, 222, 0.55);
}

html { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}

/* Ambient gradient orbs — fixed, decorative only. Never sit directly behind
   text without a glass panel between them (that's what breaks contrast). */
.orb-1, .orb-2 { position: fixed; z-index: 0; pointer-events: none; border-radius: 50%; }
.orb-1 {
  width: 600px; height: 600px;
  background: radial-gradient(circle, rgba(54,6,154,0.3) 0%, rgba(2,12,40,0) 70%);
  top: -200px; left: -150px;
}
.orb-2 {
  width: 550px; height: 550px;
  background: radial-gradient(circle, rgba(222,99,153,0.2) 0%, rgba(2,12,40,0) 70%);
  bottom: -150px; right: -100px;
}

.glass-panel {
  background: var(--glass-bg);
  backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--glass-border);
}
.glass-panel:hover { border-color: var(--glass-border-hover); }

/* Focus rings use a dark separator ring + teal outer ring — visible regardless
   of what gradient/blur happens to sit behind the element. Overrides Tailwind's reset. */
:focus-visible {
  outline: none !important;
  box-shadow: 0 0 0 2px #020C28, 0 0 0 4px #4ADEDE !important;
  border-radius: 6px;
}

.no-scrollbar::-webkit-scrollbar { display: none; }
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }

@keyframes heartBeat {
  0% { transform: scale(1); }
  14% { transform: scale(1.3); }
  28% { transform: scale(1); }
  42% { transform: scale(1.3); }
  70% { transform: scale(1); }
}
.animate-heart { animation: heartBeat 1.2s cubic-bezier(0.215, 0.61, 0.355, 1); }

/* Brief highlight pulse for a term reached via deep link */
@keyframes highlightPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(74,222,222,0); }
  30% { box-shadow: 0 0 0 4px rgba(74,222,222,0.5); }
}
.deep-link-highlight { animation: highlightPulse 1.6s ease-out; }

/* Same class of bug has bitten this project before: an unconditional `display`
   utility can out-specificity the native [hidden] attribute if it's ever used
   instead of Tailwind's .hidden class. This project standardizes on .hidden,
   but keep this as a defensive backstop. */
[hidden] { display: none !important; }

/* Shift these up when a bottom banner (install or consent) is showing, so it doesn't sit
   on top of them. The two banners never show at once — consent resolves before the install
   prompt is allowed to appear — so one offset value covers both, tuned for whichever is
   currently the taller one at a given width. The install banner is always single-line
   (~69px, via `truncate`); the consent banner wraps to two rows below the `sm` breakpoint
   (~125px, two full-width buttons under the message) since unlike the install banner it
   has two equally-weighted actions that can't be safely squeezed into one line without
   either button becoming illegible or one being visually de-emphasized versus the other. */
#back-to-top.banner-visible { bottom: 88px; }
#toast-container.banner-visible { bottom: 88px; }

@media (max-width: 639px) {
  #back-to-top.banner-visible { bottom: 148px; }
  #toast-container.banner-visible { bottom: 148px; }
}
