{"version":3,"file":"loader.module.mjs","names":[],"sources":["../../../../package/common/loader/loader.module.pcss"],"sourcesContent":["/* No prefers-reduced-motion block: a loader that stands still says the app has hung. */\n.loader {\n  display: inline-block;\n  position: relative;\n  flex-shrink: 0;\n  width: var(--loader-size);\n  height: var(--loader-size);\n  vertical-align: middle;\n\n  /* A spinning box reaches past its corners. This keeps that out of a scroll container's overflow,\n     where it toggled a scrollbar every turn, and still paints it: `overflow: hidden` would cut off\n     the comet's glow. */\n  contain: layout;\n\n  &-spinner {\n    display: block;\n    width: 100%;\n    height: 100%;\n    overflow: visible;\n    animation: loaderSpin 1.4s linear infinite;\n\n    &-track,\n    &-arc {\n      fill: none;\n      stroke-width: 4.5;\n    }\n\n    &-track {\n      stroke: var(--tone-light);\n    }\n\n    &-arc {\n      stroke: var(--tone);\n      stroke-linecap: round;\n      stroke-dasharray: 1 150;\n      animation: loaderArc 1.4s ease-in-out infinite;\n    }\n  }\n\n  &-comet {\n    position: absolute;\n\n    /* The spinner's ring reaches 89% of the box; this keeps the two the same size. */\n    inset: 5%;\n    animation: loaderSpin 0.9s linear infinite;\n\n    &-tail {\n      position: absolute;\n      inset: 0;\n      border-radius: 50%;\n\n      /* Brightest just behind the head at 0deg, which covers the seam where it starts again. */\n      background: conic-gradient(transparent 25%, var(--tone));\n\n      /* The hole sits off centre towards the bottom right, so the ring is 12% thick at the head\n         and thins to under 5% along the tail. */\n      -webkit-mask-image: radial-gradient(41% 41% at 53% 53%, transparent calc(100% - 0.5px), #000 100%);\n      mask-image: radial-gradient(41% 41% at 53% 53%, transparent calc(100% - 0.5px), #000 100%);\n    }\n\n    &-head {\n      position: absolute;\n      top: 0;\n      left: 44%;\n      width: 12%;\n      height: 12%;\n      border-radius: 50%;\n      background: var(--tone);\n\n      /* A gradient rather than a box-shadow, whose blur cannot be a percentage of the size. */\n      &::before {\n        content: '';\n        position: absolute;\n        inset: -100%;\n        border-radius: 50%;\n        background: radial-gradient(closest-side, color-mix(in srgb, var(--tone) 60%, transparent), transparent);\n      }\n    }\n  }\n\n  /* In text, Dots rest on the baseline like an ellipsis: 0.32 is the resting dot's bottom edge in\n     loaderBounce's 0% frame. Must follow .loader's own vertical-align, as both are one class. */\n  &-on-baseline {\n    vertical-align: calc(var(--loader-size) * -0.32);\n  }\n\n  &-dots {\n    position: absolute;\n    inset: 0;\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n  }\n\n  &-dot {\n    width: 24%;\n    aspect-ratio: 1;\n    border-radius: 50%;\n    background: var(--tone);\n    animation: loaderBounce 1.2s ease-in-out infinite;\n\n    /* Negative delays, so every dot is already in flight on the first frame. */\n    &:nth-child(1) {\n      animation-delay: -0.3s;\n    }\n\n    &:nth-child(2) {\n      animation-delay: -0.15s;\n    }\n  }\n\n  &-bars {\n    position: absolute;\n    inset: 8% 4%;\n    display: flex;\n    justify-content: space-between;\n  }\n\n  /* A clip-path rather than height, which would lay the bars out again every frame, or scaleY,\n     which would squash the rounded ends flat. */\n  &-bar {\n    width: 12%;\n    background: var(--tone);\n    animation: loaderEqualise 1s ease-in-out infinite;\n\n    &:nth-child(1) {\n      animation-delay: -0.6s;\n    }\n\n    &:nth-child(2) {\n      animation-delay: -0.45s;\n    }\n\n    &:nth-child(3) {\n      animation-delay: -0.3s;\n    }\n\n    &:nth-child(4) {\n      animation-delay: -0.15s;\n    }\n  }\n\n  &-pulse {\n    position: absolute;\n    inset: 0;\n\n    &-ring {\n      position: absolute;\n      inset: 0;\n      border-radius: 50%;\n      background: var(--tone);\n      opacity: 0;\n      animation: loaderRipple 1.8s cubic-bezier(0.25, 0.6, 0.4, 1) infinite;\n\n      &:nth-child(2) {\n        animation-delay: -0.9s;\n      }\n    }\n\n    &-core {\n      position: absolute;\n      inset: 34%;\n      border-radius: 50%;\n      background: var(--tone);\n      animation: loaderBreathe 1.8s ease-in-out infinite;\n    }\n  }\n}\n\n/* No keyframe may share a name with a class's camelCase key (loaderDot for .loader-dot): CSS\n   Modules exports both under that key, and the class gets the keyframe's name. */\n@keyframes loaderSpin {\n  to {\n    transform: rotate(360deg);\n  }\n}\n\n/* r=20, so the circumference is 125.7: the arc grows to 90 and slides off the end. */\n@keyframes loaderArc {\n  0% {\n    stroke-dasharray: 1 150;\n    stroke-dashoffset: 0;\n  }\n\n  50% {\n    stroke-dasharray: 90 150;\n    stroke-dashoffset: -35;\n  }\n\n  100% {\n    stroke-dasharray: 90 150;\n    stroke-dashoffset: -124;\n  }\n}\n\n/* Resting dots stay plainly visible: faded, only the raised ones showed, and the dots read as\n   floating mid-line rather than on the baseline. */\n@keyframes loaderBounce {\n  0%,\n  30%,\n  100% {\n    transform: translateY(25%);\n    opacity: 0.55;\n  }\n\n  15% {\n    transform: translateY(-35%);\n    opacity: 1;\n  }\n}\n\n@keyframes loaderEqualise {\n  0%,\n  100% {\n    clip-path: inset(35% 0 round 999px);\n    opacity: 0.45;\n  }\n\n  50% {\n    clip-path: inset(0 0 round 999px);\n    opacity: 1;\n  }\n}\n\n@keyframes loaderRipple {\n  from {\n    transform: scale(0.3);\n    opacity: 0.7;\n  }\n\n  to {\n    transform: scale(1);\n    opacity: 0;\n  }\n}\n\n@keyframes loaderBreathe {\n  0%,\n  100% {\n    transform: scale(1);\n  }\n\n  50% {\n    transform: scale(0.8);\n  }\n}\n"],"mappings":""}