/*!
 * moe. motion kit · v0.2 · loaders and small moves
 * Pairs with moe-motion.js (which fills [data-moe-rings] with the ring SVG), or paste the SVG yourself.
 * Size with --moe-size. Colours with --moe-ink (rings) and --moe-bg (the surface behind them).
 */
:root {
  --moe-move: cubic-bezier(.45, 0, .2, 1);   /* everything that travels */
  --moe-land: cubic-bezier(.34, 1.18, .64, 1); /* rings locking, things arriving */
  --moe-fast: 160ms;   /* press, focus */
  --moe-small: 320ms;  /* hover, reveal */
  --moe-medium: 640ms; /* a single move */
  --moe-large: 820ms;  /* the fly into the header */
}
.moe-dark { --moe-ink: #fff; --moe-bg: #000; }
.moe-light { --moe-ink: #000; --moe-bg: #fff; }

/* Base ring drawing (also injected by moe-motion.js) */
.moe-rings { display: block; width: 100%; height: 100%; overflow: visible; }
.moe-rings circle, .moe-rings path { fill: none; stroke: var(--moe-ink, currentColor); stroke-width: 6; }
.moe-rings .moe-gap { stroke: var(--moe-bg, #fff); stroke-width: 9; }
.moe-pair { transform-box: view-box; transform-origin: 34px 34px; }
.moe-a { transform: translate(-10px, 0px); }
.moe-b { transform: translate(10px, 0px); }

.moe-orbit, .moe-link, .moe-breathe { display: inline-block; flex: none; vertical-align: middle; width: var(--moe-size, 24px); height: var(--moe-size, 24px); }

/* Working · Orbit — the pair turns a half and rests. A half turn lands on the same weave, so it loops cleanly. */
.moe-orbit .moe-pair { animation: moe-orbit 1.8s infinite; }
@keyframes moe-orbit {
  0% { transform: rotate(0deg); animation-timing-function: cubic-bezier(.45, 0, .2, 1); }
  55%, 100% { transform: rotate(180deg); }
}

/* Waiting · Link — a hook. The left ring holds; the right ring winds up, lifts out on an arc,
   swings back over the top and through, catches, and the left ring takes a small knock. */
.moe-link .moe-a { animation: moe-hook-a 2.6s infinite; }
.moe-link .moe-b { animation: moe-hook-b 2.6s infinite; }
@keyframes moe-hook-b {
  0% { transform: translate(10px, 0px); animation-timing-function: ease-in-out; }
  6% { transform: translate(8.6px, 0.8px); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  22%, 32% { transform: translate(32px, -10px); animation-timing-function: linear; }
  35.7% { transform: translate(31.81px, -10.28px); animation-timing-function: linear; }
  39.4% { transform: translate(30.45px, -11.94px); animation-timing-function: linear; }
  43.1% { transform: translate(26.31px, -14.14px); animation-timing-function: linear; }
  46.9% { transform: translate(17.94px, -10.25px); animation-timing-function: linear; }
  50.6% { transform: translate(12.07px, -3.4px); animation-timing-function: linear; }
  54.3% { transform: translate(9.74px, -0.02px); animation-timing-function: linear; }
  58% { transform: translate(9.4px, 0.5px); animation-timing-function: cubic-bezier(.45, 0, .2, 1); }
  63% { transform: translate(10.2px, -0.12px); animation-timing-function: cubic-bezier(.45, 0, .2, 1); }
  70%, 100% { transform: translate(10px, 0px); }
}
@keyframes moe-hook-a {
  0%, 58% { transform: translate(-10px, 0px); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  62% { transform: translate(-11.25px, 0.45px); animation-timing-function: cubic-bezier(.45, 0, .2, 1); }
  67% { transform: translate(-9.8px, -0.05px); animation-timing-function: cubic-bezier(.45, 0, .2, 1); }
  72%, 100% { transform: translate(-10px, 0px); }
}

/* Soon · Breathe — for things still taking shape. Slow, quiet, never urgent. */
.moe-breathe .moe-rings { animation: moe-breathe-o 3s ease-in-out infinite alternate; }
.moe-breathe .moe-a { animation: moe-breathe-a 3s ease-in-out infinite alternate; }
.moe-breathe .moe-b { animation: moe-breathe-b 3s ease-in-out infinite alternate; }
@keyframes moe-breathe-o { from { opacity: .5; } to { opacity: 1; } }
@keyframes moe-breathe-a { from { transform: translate(-10px, 0px); } to { transform: translate(-13.5px, 0px); } }
@keyframes moe-breathe-b { from { transform: translate(10px, 0px); } to { transform: translate(13.5px, 0px); } }

/* Typing · Chain — three small rings, a lift passes along them. CSS only, no SVG needed. */
.moe-typing { display: inline-flex; align-items: center; height: var(--moe-size, 20px); vertical-align: middle; }
.moe-typing i {
  width: calc(var(--moe-size, 20px) * .44); aspect-ratio: 1; border-radius: 50%;
  border: max(1.5px, calc(var(--moe-size, 20px) * .085)) solid var(--moe-ink, currentColor);
  margin-left: calc(var(--moe-size, 20px) * -.1); opacity: .4;
  animation: moe-chain 1.4s cubic-bezier(.45, 0, .2, 1) infinite;
}
.moe-typing i:first-child { margin-left: 0; }
.moe-typing i:nth-child(2) { animation-delay: .14s; }
.moe-typing i:nth-child(3) { animation-delay: .28s; }
@keyframes moe-chain { 0%, 55%, 100% { transform: none; opacity: .4; } 22% { transform: translateY(-30%); opacity: 1; } }

/* Small moves ------------------------------------------------------------------------- */

/* Tilt: the mark leans on hover. Put .moe-tilt on the link, the mark inside turns. */
.moe-tilt .moe-rings, .moe-tilt .moe-tilt-mark { transition: transform .5s var(--moe-land); }
.moe-tilt:hover .moe-rings, .moe-tilt:hover .moe-tilt-mark,
.moe-tilt:focus-visible .moe-rings, .moe-tilt:focus-visible .moe-tilt-mark { transform: rotate(-16deg); }

/* Ring numbers: the ring draws itself, then the number rises in. Add data-moe-draw to wait for scroll. */
.moe-num {
  position: relative; display: inline-grid; place-items: center; flex: none; vertical-align: middle;
  width: var(--moe-num, 28px); height: var(--moe-num, 28px);
  font-weight: 700; font-size: calc(var(--moe-num, 28px) * .46); line-height: 1; letter-spacing: 0;
}
.moe-num svg { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); overflow: visible; }
.moe-num circle { fill: none; stroke: currentColor; stroke-width: 2; stroke-dasharray: 1; stroke-dashoffset: 0; }
.moe-num b { font: inherit; }
.moe-num[data-moe-draw] circle { stroke-dashoffset: 1; }
.moe-num[data-moe-draw] b { opacity: 0; transform: translateY(35%); }
.moe-num[data-moe-draw].is-in circle { animation: moe-draw .8s var(--moe-move) forwards; }
.moe-num[data-moe-draw].is-in b { animation: moe-rise .5s .38s var(--moe-land) forwards; }
@keyframes moe-draw { to { stroke-dashoffset: 0; } }
@keyframes moe-rise { to { opacity: 1; transform: none; } }

/* Live: the green dot pings. Green means live, and only live. */
.moe-live { position: relative; display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #16A34A; flex: none; }
.moe-live::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: inherit; animation: moe-ping 2.4s var(--moe-move) infinite; }
@keyframes moe-ping { 70%, 100% { transform: scale(3.2); opacity: 0; } }

/* Stamp: circular text turns slowly. One full turn every 24 seconds. */
.moe-stamp-spin { animation: moe-spin 24s linear infinite; }
@keyframes moe-spin { to { transform: rotate(360deg); } }

/* Press: buttons give a little. */
.moe-press { transition: transform var(--moe-fast) var(--moe-move); }
.moe-press:active { transform: scale(.97); }

@media (prefers-reduced-motion: reduce) {
  .moe-orbit *, .moe-link *, .moe-breathe *, .moe-typing i, .moe-live::after, .moe-stamp-spin { animation: none !important; }
  .moe-breathe .moe-rings, .moe-typing i { opacity: .7; }
  .moe-tilt .moe-rings, .moe-tilt .moe-tilt-mark, .moe-press { transition: none; }
  .moe-num[data-moe-draw] circle { stroke-dashoffset: 0; }
  .moe-num[data-moe-draw] b { opacity: 1; transform: none; }
}
