/* ==========================================================================
   The AI mark (components/lys/AiOrb.tsx): the logo's blue star — the soft
   four-armed star over the «i» (scripts/merke.mjs) — floating over a soft
   blue shadow. Prefix .l-orb. Loaded app-wide from app/layout.tsx: the
   phone's tab bar and AI bubble, /assistent's stage, the corner helper and
   the chats' «thinking» line use it.

   Inputs, all custom properties set by whoever places it (none declared on
   .l-orb itself, so a value set on an ancestor reaches it):
     --orb-str    its size (default 2.5rem)
     --orb-niva   0–1, how loud the voice is right now (default 0): the star
                  swells with it
     --orb-tempo  the pulse's speed as a factor of the idle one (default 1);
                  listening and speaking set it lower, which is faster
   Not --l- names: those are tokens, declared once in tokens.css (and the
   token test holds them to it); these are inputs, set per use.

   THE OWNER, 14 OCT: the sound wave is replaced by the logo's star
   everywhere, and while Pling thinks it pulses and turns, calmly.
   ========================================================================== */

/* The mark is its own size container: every length inside is a share of it,
   so the same star is crisp at 24 px and at 160. */
.l-orb {
  position: relative; display: inline-block; flex: none;
  width: var(--orb-str, var(--l-s-8)); aspect-ratio: 1;
  container-type: size;
}

/* The shadow on the ground: a soft blue ellipse, by a radial mask rather
   than a blur filter. */
.l-orb__skygge {
  position: absolute; left: 22%; right: 22%; top: 84%; height: 9%;
  background: var(--l-stjerne-skygge);
  -webkit-mask: var(--l-orb-skygge-maske); mask: var(--l-orb-skygge-maske);
}

/* The star's box, a hair above the middle so the shadow has the bottom. The
   voice swells it — a uniform scale, so the arms keep their shape. */
.l-orb__klynge {
  position: absolute; inset: 2% 4% 12% 4%;
  scale: calc(1 + var(--orb-niva, 0) * 0.14);
}
/* The star: the logo's blue, one colour all over like the logo (the owner,
   14 Oct: no lighter top, no gloss), cut by the logo's own shape
   (--l-stjerne-form). */
.l-orb__stjerne {
  position: absolute; inset: 0;
  background: var(--l-stjerne);
  -webkit-mask: var(--l-stjerne-form) center / contain no-repeat;
  mask: var(--l-stjerne-form) center / contain no-repeat;
}

/* ---- motion ---------------------------------------------------------------
   Pulsing and floating, alive at a glance, wherever Pling is the one speaking;
   listening or speaking only turn it up (--orb-tempo, --orb-niva), so the mark
   needs no state of its own. Thinking (.l-orb--tenker) turns slowly as it pulses.
   The still variant (.l-orb--still, a header icon) and reduced motion stand still.

   THE COPY ON EVERY PAGE (.l-orb--rolig: the tab bar, the corner helper) STANDS
   STILL, and breathes only under a mouse pointer on the button it sits in. The
   owner's decision, 1 Nov 2026, after this was measured with e2e/app-ledig.mjs at
   CPU 4×: a shell left alone spent 83-107 ms of every second with the star moving
   and 22-25 with it still. The animations were not the fault as such, both are on
   the compositor (compositeFailed = 0, --omstart). But Chromium draws a main frame
   for this shell on every vsync even with every animation removed, and a running
   animation has its style worked out on every main frame there is. What asks for
   those frames was not found: not an animation, a transition, script, an
   IntersectionObserver or the page's height (--fjern), and a plain copy of a tab
   does it too. That is the 22-25 ms left. (hover: hover) keeps a phone out: a
   finger leaves a :hover behind it. */
@media (prefers-reduced-motion: no-preference) {
  .l-orb:not(.l-orb--still, .l-orb--rolig) .l-orb__klynge { animation: l-orb-sveve calc(3.6s * var(--orb-tempo, 1)) ease-in-out infinite; }
  .l-orb:not(.l-orb--still, .l-orb--rolig) .l-orb__skygge { animation: l-orb-skygge calc(3.6s * var(--orb-tempo, 1)) ease-in-out infinite; }
  .l-orb:not(.l-orb--still, .l-orb--rolig) .l-orb__stjerne { animation: l-orb-puls calc(2.4s * var(--orb-tempo, 1)) ease-in-out infinite; }
  @media (hover: hover) {
    button:hover .l-orb--rolig .l-orb__klynge { animation: l-orb-sveve 6s ease-in-out infinite; }
    button:hover .l-orb--rolig .l-orb__skygge { animation: l-orb-skygge 6s ease-in-out infinite; }
    button:hover .l-orb--rolig .l-orb__stjerne { animation: l-orb-pust 4.8s ease-in-out infinite; }
  }
  .l-orb.l-orb--tenker .l-orb__stjerne {
    animation: l-orb-puls 1.6s ease-in-out infinite, l-orb-snurr 3.2s linear infinite;
  }
  @keyframes l-orb-sveve {
    0%, 100% { translate: 0 0; }
    50% { translate: 0 -5%; }
  }
  @keyframes l-orb-skygge {
    0%, 100% { scale: 1; opacity: 1; }
    50% { scale: 0.82; opacity: 0.65; }
  }
  @keyframes l-orb-puls {
    0%, 100% { scale: 0.9; }
    50% { scale: 1.06; }
  }
  @keyframes l-orb-pust {
    0%, 100% { scale: 0.95; }
    50% { scale: 1.03; }
  }
  @keyframes l-orb-snurr {
    to { rotate: 1turn; }
  }
}
/* Reduced motion: no pulse, but the voice still swells the star, at half
   the gain — that movement says someone is speaking. */
@media (prefers-reduced-motion: reduce) {
  .l-orb__klynge { scale: calc(1 + var(--orb-niva, 0) * 0.07); }
}
