/* =============================================================================
 * Kiviland — orb module styles. Owned by kl-orb.js. Base classes live in
 * kiviland.css; this file adds what the module needs and overrides nothing
 * outside its own selectors (.kl-orb* · .kl-speaker* · .kl-mark* · .kl-dots*).
 *
 * Laws kept: motion is transform/opacity only and value-scoped; the only
 * continuous movement is the breath the spec names (dots · corona), and the
 * corona is painted by the module, not by CSS.
 * ========================================================================== */

/* ---------------------------------------------------------------- the orb */
/* layer order: corona (canvas) → halos (fallback) → disc (faces + lid) → speaker */
.kl-orb {
  /* the eye, measured on the portraits (percent of the disc); orb-b "you" by default */
  --kl-lid-x: 51.7%;
  --kl-lid-y: 36%;
  --kl-lid-w: 6px;
  --kl-lid-h: 4px;
  --kl-lid-tilt: -8deg;
  isolation: isolate;
}
.kl-orb[data-gaze='words'] {
  --kl-lid-x: 43.7%;
  --kl-lid-y: 44.8%;
  --kl-lid-w: 5px;
  --kl-lid-h: 3.5px;
  --kl-lid-tilt: 6deg;
}
.kl-orb__corona {
  z-index: 0;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}
.kl-orb__halo { z-index: 0; transition: none; }
.kl-orb__halo--inner { width: 104px; height: 104px; }
.kl-orb__halo--outer {
  width: 124px;
  height: 124px;
  background: radial-gradient(circle, rgba(144, 196, 106, 0.18) 0%, rgba(144, 196, 106, 0.18) 52%, transparent 72%);
}
.kl-orb.is-planar .kl-orb__halo { display: none; }
.kl-orb__disc { z-index: 1; }
.kl-orb__face {
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
.kl-orb__lid {
  left: var(--kl-lid-x);
  top: var(--kl-lid-y);
  width: var(--kl-lid-w);
  height: var(--kl-lid-h);
  transform: translate(-50%, -50%) rotate(var(--kl-lid-tilt));
  pointer-events: none;
  will-change: opacity;
}
/* the disc's inner shading follows the gaze: the light sits where the portrait's glow is */
.kl-orb[data-gaze='words'] .kl-orb__disc {
  box-shadow: inset -6px -8px 14px rgba(0, 0, 0, 0.35), inset 3px 6px 10px rgba(144, 196, 106, 0.22);
}
.kl-orb.is-planar .kl-orb__disc { box-shadow: none; }

/* ------------------------------------------------------------- the speaker */
.kl-speaker {
  z-index: 2;
  opacity: 0.6;
  border-radius: var(--r-xs);
  transition: opacity 120ms var(--ease), color 120ms var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.kl-orb:hover .kl-speaker,
.kl-speaker:focus-visible,
.kl-stage[data-muted='true'] .kl-speaker { opacity: 1; }
.kl-speaker:focus-visible {
  outline: 1px solid var(--hairline-strong);
  outline-offset: 2px;
}
.kl-speaker svg { display: block; }
.kl-speaker__slash { transition: opacity 120ms var(--ease); }
.kl-speaker__caption { pointer-events: none; }
.kl-speaker__caption:empty { display: none; }

/* parked in the pane head while the orb is off the page: static, a size smaller,
   its caption reading to the left of the glyph */
.kl-pane__speaker .kl-speaker {
  position: static;
  transform: none;
  width: auto;
  height: 20px;
  display: inline-flex;
  flex-direction: row-reverse;
  align-items: center;
  gap: 6px;
}
.kl-pane__speaker .kl-speaker svg { width: 16px; height: 16px; }
.kl-pane__speaker .kl-speaker__caption {
  position: static;
  transform: none;
  margin: 0;
}

/* in a card's right gutter (56px) there is no room beside the disc: the speaker
   hangs under the orb, and its caption sits right-aligned on a sliver of glass so
   it stays legible over whatever card text runs beneath it */
.kl-turn__gutter--right .kl-speaker {
  left: 50%;
  top: calc(100% + 6px);
  transform: translateX(-50%);
}
.kl-turn__gutter--right .kl-speaker__caption {
  left: auto;
  right: 0;
  transform: none;
  padding: 2px 6px;
  border-radius: var(--r-xs);
  background: var(--kl-glass);
}
/* in the left gutter (your side, should the orb ever sit there) mirror it */
.kl-turn__gutter--left .kl-speaker {
  left: 50%;
  top: calc(100% + 6px);
  transform: translateX(-50%);
}
.kl-turn__gutter--left .kl-speaker__caption {
  left: 0;
  transform: none;
  padding: 2px 6px;
  border-radius: var(--r-xs);
  background: var(--kl-glass);
}

/* --------------------------------------------------------------- the mark */
.kl-mark { --kl-mark-lvl: 0; }
.kl-mark__stencil {
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
/* the ring grows with your voice: a transform on the 2px stroke, never a repaint */
.kl-mark::after {
  transform: scale(calc(1 + 0.12 * var(--kl-mark-lvl)));
  transition: border-color 120ms var(--ease), opacity 120ms var(--ease);
}
.kl-mark[data-ring='listening']::after { opacity: calc(0.6 + 0.4 * var(--kl-mark-lvl)); }
/* and a faint amber breath beneath it, opacity only (the same halo the held sphere uses) */
.kl-mark::before {
  content: '';
  position: absolute;
  inset: -12px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(151, 55, 4, 0.28) 0%, transparent 70%);
  opacity: 0;
  pointer-events: none;
}
.kl-mark[data-ring='listening']::before { opacity: var(--kl-mark-lvl); }
.kl-mark.is-sphere { border-color: var(--hairline-strong); }

/* --------------------------------------------------------------- the dots */
/* the tail runs from the speaker to the card: the small dot nearest the orb or
   mark, the large one nearest the card. kivi's orb is up-right of its card, your
   mark up-left of yours; the idle mark's dots rise straight up (kl-dots--up). */
.kl-dots { transform-origin: center; }
.kl-dots[data-dir='up-left'] { transform: rotate(32deg); }
.kl-dots[data-dir='up-right'] {
  flex-direction: row-reverse;
  transform: rotate(-32deg);
}
/* leaving: one dot at a time, 90ms each, the far one first */
.kl-dots.is-lifting i { animation: kl-lift 90ms var(--kl-ease-in) forwards; }
.kl-dots.is-lifting i:nth-child(3) { animation-delay: 0ms; }
.kl-dots.is-lifting i:nth-child(2) { animation-delay: 90ms; }
.kl-dots.is-lifting i:nth-child(1) { animation-delay: 180ms; }

/* ---------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  .kl-dots.is-lifting i { animation: none; opacity: 0; }
  .kl-dots[data-dir] { transition: none; }
  .kl-mark::after { transition: none; }
}
