/*
Spinner

An indeterminate loading ring, the same ring Button draws while loading:
a currentColor circle with one transparent quarter, turning. Sized from
the icon tokens, colored by the text around it, so it reads right inside
a button, a badge or a line of text.

  .spinner                 the ring (md: --icon-size)
  .spinner.is-sm | is-lg   --icon-size-sm | --icon-size-lg
  .spinner:has(> svg)      a custom icon spins instead of the ring
*/

@layer components {

.spinner {
  --spinner-size:   var(--icon-size);
  --spinner-stroke: calc(var(--icon-stroke) * 1px);

  position:         relative;
  display:          inline-block;
  flex:             none;
  box-sizing:       border-box;
  width:            var(--spinner-size);
  height:           var(--spinner-size);
  border:           var(--spinner-stroke) solid currentColor;
  border-top-color: transparent;
  border-radius:    var(--radius-full);
  color:            inherit;
  vertical-align:   middle;
  animation:        spinner-spin calc(var(--duration-loop) * 1.5) linear infinite;
}

.spinner.is-sm { --spinner-size: var(--icon-size-sm); }
.spinner.is-lg { --spinner-size: var(--icon-size-lg); }

/* A custom glyph (shadcn swaps the icon): no ring, the svg fills the box. */
.spinner:has(> svg) {
  border: 0;
}

.spinner > svg {
  display: block;
  width:   100%;
  height:  100%;
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation-duration: calc(var(--duration-loop) * 4);
  }
}

/* Forced colors (Windows High Contrast) paints every border side in the
   text color, closing the transparent quarter, and a closed ring turning
   looks still. The ring opts out of the override; its color is
   currentColor, which already holds the forced text color it inherits. */
@media (forced-colors: active) {
  .spinner {
    forced-color-adjust: none;
  }
}

@keyframes spinner-spin {
  to { transform: rotate(360deg); }
}

}
