@layer components {
  /* ——— Spinner ———
     Three dots taking turns falling — chalet's spinner.css, drawn in
     currentColor so it takes the ink of whatever wears it. */
  .spinner {
    position: relative;
  }

  /* The working button's selector (buttons.css) is listed here on purpose,
     the way labels.css lists foreign selectors: same dots, one drawing. It
     cannot wear .spinner, because Turbo puts no class on the submitter it
     disables — so it retunes the three values below and nothing else. The
     mask reads alpha only, which is why the gradient's colour is arbitrary. */
  .spinner::before,
  form[aria-busy] .btn:disabled::after {
    --dot: no-repeat radial-gradient(#000 68%, #0000 71%);
    --dot-size: 1.25em;

    content: "";
    position: absolute;
    inset: var(--dot-inset, 50% 0.25em);
    inline-size: var(--dot-size);
    aspect-ratio: 8 / 5;
    margin-block: calc(var(--dot-size) / -3);
    margin-inline: calc(var(--dot-size) / -2);
    background: var(--dot-color, currentColor);
    mask: var(--dot), var(--dot), var(--dot);
    mask-size: 28% 45%;
    animation: submitting var(--dot-speed, 1.3s) infinite linear;
  }

  /* Unprefixed `mask`, where ../chalet still carries -webkit-; the property
     has been baseline since Safari 15.4. */
  @keyframes submitting {
    0%    { mask-position: 0% 0%,   50% 0%,   100% 0%   }
    12.5% { mask-position: 0% 50%,  50% 0%,   100% 0%   }
    25%   { mask-position: 0% 100%, 50% 50%,  100% 0%   }
    37.5% { mask-position: 0% 100%, 50% 100%, 100% 50%  }
    50%   { mask-position: 0% 100%, 50% 100%, 100% 100% }
    62.5% { mask-position: 0% 50%,  50% 100%, 100% 100% }
    75%   { mask-position: 0% 0%,   50% 50%,  100% 100% }
    87.5% { mask-position: 0% 0%,   50% 0%,   100% 50%  }
    100%  { mask-position: 0% 0%,   50% 0%,   100% 0%   }
  }

}
