/*
 * Beam: a thin line in the brand colour that runs round the border of a card, button or
 * input. Inspired by libraries.dev/beam, written in plain CSS.
 *
 * Markup:
 *   <div class="beam" data-beam="idle">
 *     <span class="beam-bloom" aria-hidden="true"></span>   (optional: it draws nothing now)
 *     ...the box itself (opaque background, same border radius)...
 *     <span class="beam-stroke" aria-hidden="true"></span>
 *   </div>
 *
 * States (data-beam): off | idle | active
 *   idle    slow orbit (resting inputs)
 *   active  fast orbit (the AI is thinking / something new appeared)
 * Tuning: --beam-radius, --beam-width, --beam-speed, --beam-strength
 *
 * Only the line, never light: a blurred orange bloom around the box or a haze inside it reads
 * as a warm, creamy glow on the dark page (and a cream halo on the white one).
 */

@property --beam-o {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

.beam {
  --beam-radius: 28px;
  --beam-width: 1px;
  --beam-speed: 6s;
  --beam-strength: 1;
  /* one brand-colour line with a fading tail */
  --beam-colors: transparent 0deg, transparent 240deg, var(--brand) 330deg, transparent 346deg;
  position: relative;
  border-radius: var(--beam-radius);
  isolation: isolate;
  --beam-o: 0;
  transition: --beam-o 0.6s ease;
}

.beam[data-beam="idle"] {
  --beam-o: 0.55;
}

.beam[data-beam="active"] {
  --beam-o: 1;
  --beam-speed: 2.4s;
}

.beam[data-beam="idle"]:focus-within {
  --beam-o: 0.9;
}

/* The line itself: an arc of colour masked down to the border. The arc turns as a compositor
   layer (a square conic gradient, as wide as the box's diagonal, rotated about the box's centre),
   which looks exactly like conic-gradient(from <angle>) but costs no style or paint per frame. */
.beam-stroke {
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  padding: var(--beam-width);
  overflow: hidden;
  container-type: size;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  opacity: calc(var(--beam-o) * var(--beam-strength));
  pointer-events: none;
}
.beam-stroke::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: hypot(100cqw, 100cqh);
  height: hypot(100cqw, 100cqh);
  translate: -50% -50%;
  background: conic-gradient(from 0deg, var(--beam-colors));
}
.beam[data-beam="idle"] .beam-stroke::before,
.beam[data-beam="active"] .beam-stroke::before {
  animation: beam-turn var(--beam-speed) linear infinite;
}

/* No bloom around the box (see the note at the top). */
.beam-bloom { display: none; }

/* Everything inside sits above the bloom. */
.beam > :not(.beam-bloom):not(.beam-stroke) {
  position: relative;
  z-index: 1;
}

/* The box that carries the beam (.beam-haze): clipped to its corners, with no haze inside. */
.beam-haze {
  isolation: isolate;
  overflow: hidden;
}

@keyframes beam-turn {
  to { rotate: 360deg; }
}

/* Small round variant for icon buttons (the stop button while answering). */
.beam.beam-round {
  --beam-radius: 999px;
  --beam-width: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .beam .beam-stroke::before {
    animation: none !important;
    rotate: 135deg;
  }
}
