/* =========================================================
   Soula · The Orb
   ---------------------------------------------------------
   The signature element: a soft, breathing radial blob.
   Three layers stacked inside .orb-wrap:
     1) outer halo  (::after)  — large pale wash behind the orb
     2) main body   (.orb)     — 4-stop radial gradient, blurred
     3) drift layer (::before) — screen-blend secondary gradient

   Sizes: .orb-xl/-lg/-md/-sm/-xs/-2xs/-tiny
   Brand: one orb, always pink. No agent variants — the orb IS
   the Soula mark (see Brand section of the design system).
   ========================================================= */

/* ---------------------------------------------------------
   Wrapper — sets size, contains glow
   --------------------------------------------------------- */
.orb-wrap {
  position: relative;
  display: inline-block;
  pointer-events: none;
}

/* main body */
.orb-wrap > .orb {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background:
    radial-gradient(ellipse 55% 60% at 38% 38%, rgba(255, 30, 110, 1)   0%, rgba(255, 30, 110, 0)   58%),
    radial-gradient(ellipse 45% 48% at 62% 56%, rgba(255, 96, 70, 0.55) 0%, transparent              58%),
    radial-gradient(ellipse 50% 55% at 50% 65%, rgba(255, 160, 180, 0.60) 0%, transparent            65%),
    radial-gradient(circle  at 50% 50%,         rgba(255, 220, 230, 0.70) 0%, rgba(255, 220, 230, 0.30) 45%, transparent 75%);
  filter: blur(10px) saturate(1.1);
  transform: translateZ(0);
  animation: orb-breathe var(--orb-breathe, 6s) ease-in-out infinite;
  will-change: transform, filter;
}

/* drift layer — overlays a screen-blend secondary gradient */
.orb-wrap > .orb::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(ellipse 50% 45% at 30% 70%, rgba(255, 90, 140, 0.55) 0%, transparent 60%),
    radial-gradient(ellipse 40% 50% at 70% 30%, rgba(255, 180, 90, 0.40) 0%, transparent 65%);
  mix-blend-mode: screen;
  animation: orb-drift var(--orb-drift, 11s) ease-in-out infinite;
  will-change: transform, opacity;
}

/* halo */
.orb-wrap::after {
  content: "";
  position: absolute; inset: -10%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 200, 215, 0.25) 0%, transparent 65%);
  z-index: -1;
  animation: orb-halo var(--orb-halo, 8s) ease-in-out infinite;
}

/* ---------------------------------------------------------
   Sizes
   --------------------------------------------------------- */
.orb-2xl   { width: 320px; height: 320px; }
.orb-xl    { width: 240px; height: 240px; }
.orb-lg    { width: 220px; height: 220px; }
.orb-md    { width: 200px; height: 200px; }
.orb-sm    { width: 140px; height: 140px; }
.orb-xs    { width: 80px;  height: 80px;  }
.orb-2xs   { width: 48px;  height: 48px;  }
.orb-inline {
  display: block;
  margin: 20px auto;
}

/* tiny (in-row) — single-layer, less blur. Used in agent pills, bubbles */
.orb-tiny {
  width: 26px; height: 26px;
  display: inline-block;
  position: relative;
  border-radius: 50%;
  overflow: hidden;
  pointer-events: none;
}
.orb-tiny > .orb {
  position: absolute; inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(ellipse 55% 60% at 38% 38%, rgba(255, 30, 110, 1)   0%, rgba(255, 30, 110, 0)   60%),
    radial-gradient(ellipse 45% 48% at 62% 56%, rgba(255, 96, 70, 0.70) 0%, transparent              60%),
    radial-gradient(circle, rgba(255, 200, 215, 0.5) 0%, transparent 70%);
  filter: blur(2px);
  animation: none;            /* tinies are static */
}
.orb-tiny > .orb::before { display: none; }

/* ---------------------------------------------------------
   Animations
   --------------------------------------------------------- */
@keyframes orb-breathe {
  0%, 100% { transform: scale(0.96); filter: blur(10px) saturate(1.10); }
  50%      { transform: scale(1.04); filter: blur(15px) saturate(1.30); }
}
@keyframes orb-drift {
  0%   { transform: translate(0, 0)    rotate(0deg);   opacity: 0.9; }
  33%  { transform: translate(4%, -3%) rotate(40deg);  opacity: 1;   }
  66%  { transform: translate(-3%, 4%) rotate(-30deg); opacity: 0.8; }
  100% { transform: translate(0, 0)    rotate(0deg);   opacity: 0.9; }
}
@keyframes orb-halo {
  0%, 100% { transform: scale(1);    opacity: 0.8; }
  50%      { transform: scale(1.08); opacity: 1;   }
}
@keyframes orb-speak {
  0%, 100% { transform: scale(0.97); filter: blur(11px) saturate(1.15); }
  30%      { transform: scale(1.08); filter: blur(17px) saturate(1.32); }
  60%      { transform: scale(1.02); filter: blur(13px) saturate(1.20); }
}

@media (prefers-reduced-motion: reduce) {
  .orb-wrap > .orb,
  .orb-wrap > .orb::before,
  .orb-wrap::after { animation: none !important; }
}

/* ---------------------------------------------------------
   One orb, one mark — agent palettes intentionally removed.
   Earlier versions tinted the orb per agent (bestie peach,
   cbt blue, navigator sage, right-here lavender). The pink
   orb is now the single brand mark across the whole product,
   so every surface — bubble avatar, agent pill, voice screen —
   renders the same gradient. Restore agent tints later by
   re-adding [data-agent="…"] selectors that override .orb /
   .voice-orb backgrounds.
   --------------------------------------------------------- */

/* ---------------------------------------------------------
   Voice mode states
   .voice-orb is just .orb-wrap on the voice screen — these
   classes drive the live audio-reactive scale.
   --------------------------------------------------------- */
.voice-orb.is-listening > .orb {
  animation: none;
  transform: scale(calc(0.96 + var(--audio-level, 0) * 0.18));
  filter: blur(calc(10px + var(--audio-level, 0) * 8px))
          saturate(calc(1.1 + var(--audio-level, 0) * 0.4));
  transition: transform 0.08s linear, filter 0.12s linear;
}
.voice-orb.is-speaking > .orb         { animation: orb-speak 2.6s ease-in-out infinite; }
.voice-orb.is-speaking > .orb::before { animation: orb-drift 7s   ease-in-out infinite; }
