/* ===== css/motion.css — motion features (group 'motion') =====
   Every rule is scoped under html.f-<feature id>; anything that moves continuously is also gated by
   html.cx-motion (core swaps it for cx-reduced when the visitor asks for less motion). The easing tokens
   come from style.css (m-motion-foundation); the fallbacks inside var() keep every curve valid without them.
   z-index scale: inside the card <= 3000, overlays <= 7000, the splash 8000. */

/* ===== Entrance holds (m-enter-splash, m-intro-choreography) ===== */
/* From the very first paint the card waits for its entrance, so it never flashes before the splash or the
   intro. motion.js releases it (html.mx-ready / html.mx-splash-seen); if that file never runs, the
   failsafe animation shows the card after 4 s anyway. */
html.f-m-enter-splash:not(.mx-splash-seen):not(.mx-ready):not(.mx-splash-open) .main-container,
html.f-m-intro-choreography:not(.mx-ready):not(.mx-splash-open) .main-container {
    opacity: 0;
    animation: mx-failsafe-show 0.4s ease 4s forwards;
}

html.mx-splash-open .main-container {
    opacity: 0;
}

/* until the script builds the splash button, CSS paints its scrim (the same background: the swap is invisible) */
html.f-m-enter-splash:not(.mx-splash-seen):not(.mx-ready):not(.mx-splash-open) #site::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: 8000;
    pointer-events: none;
    background:
        radial-gradient(ellipse 70% 55% at 50% 46%, rgb(1 32 149 / 0.47), transparent 72%),
        radial-gradient(ellipse at 50% 45%, rgb(2 11 38 / 0.5), rgb(2 11 38 / 0.94) 72%);
    animation: mx-failsafe-hide 0.4s ease 4s forwards;
}

@keyframes mx-failsafe-show { to { opacity: 1; } }
@keyframes mx-failsafe-hide { to { opacity: 0; visibility: hidden; } }

/* ===== Enter Splash (m-enter-splash) ===== */
html .mx-splash {
    position: fixed;
    inset: 0;
    z-index: 8000;
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: max(24px, env(safe-area-inset-top, 0px)) max(24px, env(safe-area-inset-right, 0px)) max(24px, env(safe-area-inset-bottom, 0px)) max(24px, env(safe-area-inset-left, 0px));
    border: 0;
    border-radius: 0;
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
    color: #f2f5fc;
    text-align: center;
    font: inherit;
    /* a scrim only, no backdrop-filter: blurring the moving sparkles would cost a full-screen blur per frame */
    background:
        radial-gradient(ellipse 70% 55% at 50% 46%, rgb(1 32 149 / 0.47), transparent 72%),
        radial-gradient(ellipse at 50% 45%, rgb(2 11 38 / 0.5), rgb(2 11 38 / 0.94) 72%);
    -webkit-tap-highlight-color: transparent;
    touch-action: none;   /* the hidden page underneath must not scroll while the splash is up */
    -webkit-user-select: none;
    user-select: none;
}

html .mx-splash:focus {
    outline: none;
}

.mx-splash .mx-splash-inner {
    position: relative;
    display: grid;
    justify-items: center;
    gap: 18px;
    max-width: min(100%, 760px);
}

.mx-splash .mx-splash-motto {
    max-width: 100%;
    font: 250 clamp(23px, 6.6vw, 40px) / 1.25 'Unbounded', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    letter-spacing: 0.04em;
    text-wrap: balance;
    color: #f2f5fc;
    text-shadow: 0 0 22px rgb(170 196 255 / 0.55), 0 0 2px rgb(255 255 255 / 0.45), 0 2px 14px rgb(0 0 0 / 0.55);
}

.mx-splash .mx-splash-line {
    width: min(150px, 38vw);
    height: 1px;
    background: linear-gradient(90deg, transparent, rgb(206 222 255 / 0.6), transparent);
}

.mx-splash .mx-splash-hint {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px 10px 17px;
    border: 1px solid rgb(255 255 255 / 0.16);
    border-radius: 999px;
    background: rgb(255 255 255 / 0.05);
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.1);
    font: 500 11px / 1 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: rgb(242 245 252 / 0.9);
    transition: border-color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}

.mx-splash .mx-splash-hint .icon {
    width: 14px;
    height: 14px;
    flex: none;
    opacity: 0.9;
}

.mx-splash .mx-splash-hint-text {
    margin-right: -0.3em;   /* letter-spacing adds a trailing gap: keep the pill's text optically centred */
}

@media (hover: hover) {
    .mx-splash:hover .mx-splash-hint {
        border-color: rgb(255 255 255 / 0.32);
        background: rgb(255 255 255 / 0.09);
    }
}

.mx-splash:focus-visible .mx-splash-hint {
    border-color: rgb(255 255 255 / 0.7);
    box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.1), 0 0 0 3px rgb(0 51 255 / 0.55);
}

/* four crisp pixel '+' around the motto: the same grammar as the krist.mp4 sparkles */
.mx-splash .mx-splash-sparks {
    position: absolute;
    inset: -26px -22px;
    pointer-events: none;
}

.mx-splash .mx-splash-sparks::before,
.mx-splash .mx-splash-sparks::after {
    content: '';
    position: absolute;
    width: 10px;
    height: 10px;
    background: #dbe6ff;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 5' shape-rendering='crispEdges'%3E%3Cpath d='M2 0h1v2h2v1H3v2H2V3H0V2h2z'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 5' shape-rendering='crispEdges'%3E%3Cpath d='M2 0h1v2h2v1H3v2H2V3H0V2h2z'/%3E%3C/svg%3E") center / contain no-repeat;
    opacity: 0.75;
}

.mx-splash .mx-splash-sparks.is-a::before { left: 0; top: 0; width: 15px; height: 15px; }
.mx-splash .mx-splash-sparks.is-a::after { right: 0; bottom: 0; }
.mx-splash .mx-splash-sparks.is-b::before { right: 4%; top: 6%; }
.mx-splash .mx-splash-sparks.is-b::after { left: 6%; bottom: 14%; width: 5px; height: 5px; }

/* entrance: the motto rises, the line draws, the hint follows and breathes; reduced motion shows it at once */
html.cx-motion .mx-splash .mx-splash-motto { animation: mx-splash-rise 0.9s var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 0.05s backwards; }
html.cx-motion .mx-splash .mx-splash-line { animation: mx-splash-draw 0.8s var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 0.3s backwards; }
html.cx-motion .mx-splash .mx-splash-hint { animation: mx-splash-fade 0.7s ease 0.55s backwards; }
html.cx-motion .mx-splash .mx-splash-hint-text { animation: mx-hint-breathe 2.6s ease-in-out 1.4s infinite; }
html.cx-motion .mx-splash .mx-splash-sparks { animation: mx-splash-fade 1.2s ease 0.6s backwards; }
html.cx-motion .mx-splash .mx-splash-sparks.is-a::before { animation: mx-twinkle 3.1s ease-in-out infinite; }
html.cx-motion .mx-splash .mx-splash-sparks.is-a::after { animation: mx-twinkle 2.4s ease-in-out 0.9s infinite; }
html.cx-motion .mx-splash .mx-splash-sparks.is-b::before { animation: mx-twinkle 3.7s ease-in-out 0.4s infinite; }
html.cx-motion .mx-splash .mx-splash-sparks.is-b::after { animation: mx-twinkle 2.9s ease-in-out 1.6s infinite; }

@keyframes mx-splash-rise { from { opacity: 0; translate: 0 10px; } }
@keyframes mx-splash-draw { from { opacity: 0; scale: 0 1; } }
@keyframes mx-splash-fade { from { opacity: 0; } }
@keyframes mx-hint-breathe { 50% { opacity: 0.45; } }
@keyframes mx-twinkle { 0%, 100% { opacity: 0.18; } 50% { opacity: 1; } }

/* exit: opacity (and a hint of scale) only, so it does not stack heavy layers on top of the intro */
html .mx-splash.is-leaving { pointer-events: none; }
html.cx-motion .mx-splash.is-leaving { animation: mx-splash-out 0.5s var(--ease-in-out, cubic-bezier(0.65, 0, 0.35, 1)) forwards; }
html.cx-reduced .mx-splash.is-leaving { animation: mx-splash-out-fade 0.2s ease forwards; }
@keyframes mx-splash-out { to { opacity: 0; scale: 1.04; } }
@keyframes mx-splash-out-fade { to { opacity: 0; } }

/* the dock waits behind the splash (it is under the scrim and cannot be reached anyway) */
html.mx-splash-open .fixed-controls { visibility: hidden; }

/* without the intro, the card simply rises in after the tap */
@keyframes mx-reveal { from { opacity: 0; translate: 0 10px; } }
html.cx-motion.f-m-enter-splash.mx-splash-reveal .main-container { animation: mx-reveal 650ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) backwards; }
html.cx-reduced.f-m-enter-splash.mx-splash-reveal .main-container { animation: mx-intro-fade 200ms ease backwards; }

/* ===== Intro Choreography (m-intro-choreography) ===== */
@keyframes mx-intro-rise { from { opacity: 0; translate: 0 var(--mx-rise, 12px); scale: var(--mx-from, 1); } }
@keyframes mx-intro-draw { from { opacity: 0; scale: 0 1; } }
@keyframes mx-intro-fade { from { opacity: 0; } }

/* stagger index: sibling-index() where supported, an nth-child ladder otherwise */
html.f-m-intro-choreography :is(.stat-item, .social-link):nth-child(2) { --mx-i: 1; }
html.f-m-intro-choreography :is(.stat-item, .social-link):nth-child(3) { --mx-i: 2; }
html.f-m-intro-choreography :is(.stat-item, .social-link):nth-child(4) { --mx-i: 3; }
html.f-m-intro-choreography :is(.stat-item, .social-link):nth-child(5) { --mx-i: 4; }
html.f-m-intro-choreography :is(.stat-item, .social-link):nth-child(6) { --mx-i: 5; }
html.f-m-intro-choreography :is(.stat-item, .social-link):nth-child(7) { --mx-i: 6; }
html.f-m-intro-choreography :is(.stat-item, .social-link):nth-child(n + 8) { --mx-i: 7; }

@supports (animation-delay: calc(sibling-index() * 1ms)) {
    html.f-m-intro-choreography :is(.stat-item, .social-link) { --mx-i: calc(sibling-index() - 1); }
}

/* banner 0 ms, card 150, avatar pop 180, stats 380 + 60 each, lines 320 / 520 / 680, name 400, bio 560,
   icons 700 + 45 each, player 950 — 1.55 s in all. fill-mode 'backwards': every animation releases its
   properties when it ends, so hover, tilt and the magnets keep working and nothing can stay hidden */
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .banner-section { animation: mx-intro-rise 600ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .avatar-wrapper { animation: mx-intro-fade 250ms ease 180ms backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .avatar-container { --mx-from: 0.6; --mx-rise: 0px; animation: mx-intro-rise 800ms var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)) 180ms backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .stat-item { --mx-rise: -6px; animation: mx-intro-rise 400ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) calc(380ms + var(--mx-i, 0) * 60ms) backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .profile-content { animation: mx-intro-fade 450ms ease 150ms backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .divider-line { animation: mx-intro-draw 600ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 320ms backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .divider-line.mid { animation-delay: 520ms; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .divider-line.bottom { animation-delay: 680ms; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .name-section { animation: mx-intro-rise 500ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 400ms backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .bio-section { animation: mx-intro-rise 500ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 560ms backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .social-link { --mx-from: 0.8; animation: mx-intro-rise 450ms var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)) calc(700ms + var(--mx-i, 0) * 45ms) backwards; }
html.cx-motion.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) .music-player { --mx-rise: 16px; animation: mx-intro-rise 600ms var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) 950ms backwards; }

/* the glass slab (v-liquid-glass-card) fades in with its content instead of standing there empty */
html.cx-motion.f-m-intro-choreography.f-v-liquid-glass-card.mx-intro:not(.mx-intro-fast) .profile-card { animation: mx-intro-fade 450ms ease backwards; }

/* reduced motion: the same parts simply fade in, nothing moves */
html.cx-reduced.f-m-intro-choreography.mx-intro:not(.mx-intro-fast) :is(.banner-section, .stat-item, .avatar-wrapper, .profile-content,
    .name-section, .bio-section, .social-link, .music-player) { animation: mx-intro-fade 300ms ease backwards; }

/* a reload within the same tab session: one short fade instead of the whole choreography */
html.f-m-intro-choreography.mx-intro.mx-intro-fast .main-container { animation: mx-intro-fade 250ms ease backwards; }

/* ===== Name Decrypt (m-name-decrypt) ===== */
html.f-m-name-decrypt .display-name .mx-decrypt {
    display: inline-block;
    white-space: nowrap;
    text-align: left;
}

/* ===== Bio Typewriter (m-bio-typewriter) ===== */
html.f-m-bio-typewriter .bio-section { position: relative; }
html.f-m-bio-typewriter.mx-typing .bio-text { opacity: 0; }   /* still read by screen readers */

html.f-m-bio-typewriter .mx-bio-typed {
    position: absolute;   /* top / left / width / height follow the bio's own box (set by the script) */
    top: 0;
    left: 0;
    width: 100%;
    white-space: pre-wrap;
    cursor: default;
}

/* a steady caret while it types; at the end it blinks twice and fades */
html.f-m-bio-typewriter .mx-bio-typed::after {
    content: '';
    display: inline-block;
    width: 2px;
    height: 1em;
    margin: 0 -5px 0 3px;   /* zero net advance: the centred text never shifts because of the caret */
    vertical-align: -0.12em;
    background: currentColor;
    box-shadow: 0 0 8px rgb(255 255 255 / 0.55);
}

html.f-m-bio-typewriter .mx-bio-typed.is-done::after { animation: mx-caret-out 2s linear forwards; }
@keyframes mx-caret-out { 0%, 19% { opacity: 1; } 20%, 39% { opacity: 0; } 40%, 59% { opacity: 1; } 60%, 100% { opacity: 0; } }

/* ===== Name Shimmer (m-name-shimmer) ===== */
html.f-m-name-shimmer .display-name { position: relative; }

@supports (background-clip: text) or (-webkit-background-clip: text) {
    html.f-m-name-shimmer .display-name::after {
        content: attr(data-mx-text);
        content: attr(data-mx-text) / '';
        /* shrink-wrapped and centred exactly like the name, so the band is sized to the word, not the card */
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        width: max-content;
        margin-inline: auto;
        pointer-events: none;
        white-space: nowrap;
        color: transparent;
        -webkit-text-fill-color: transparent;
        text-shadow: none;
        background: linear-gradient(100deg, transparent 41%, #b0ccff 50%, transparent 59%) 100% 0 / 250% 100% no-repeat;
        -webkit-background-clip: text;
        background-clip: text;
    }
}

/* ===== Avatar Orbit Ring (m-avatar-orbit-ring) ===== */
html.f-m-avatar-orbit-ring .avatar-wrapper::before,
html.f-m-avatar-orbit-ring .avatar-wrapper::after {
    content: '';
    position: absolute;
    z-index: -1;
    border-radius: 50%;
    pointer-events: none;
}

html.f-m-avatar-orbit-ring .avatar-wrapper::before {
    inset: -5px;
    background: conic-gradient(transparent 0 50%, #0033ff 72%, #89b2ff 90%, #fff 94%, transparent 97%);
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2px));
    mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2px));
    rotate: 62deg;   /* static (reduced motion): the comet head rests at the top right */
}

html.f-m-avatar-orbit-ring .avatar-wrapper::after {
    inset: -24px;
    background: radial-gradient(closest-side, rgb(0 51 255 / 0.6), transparent);
    opacity: 0.6;
    transition: opacity 0.5s ease;
}

html.cx-motion.f-m-avatar-orbit-ring .avatar-wrapper::before { animation: mx-ring-spin 6s linear infinite; }
html.cx-motion.f-m-avatar-orbit-ring .avatar-wrapper::after { animation: mx-glow-breathe 4.8s ease-in-out infinite alternate; }
@keyframes mx-ring-spin { from { rotate: 0turn; } to { rotate: 1turn; } }
@keyframes mx-glow-breathe { from { opacity: 0.45; scale: 0.94; } to { opacity: 0.9; scale: 1.06; } }

/* ===== Audio Reactive Glow (m-audio-reactive-glow) ===== */
html.f-m-audio-reactive-glow .mx-beat-glow {
    position: absolute;
    inset: -30px;
    z-index: -2;   /* under the orbit ring (-1), which keeps circling on top of the pulse */
    border-radius: 50%;
    pointer-events: none;
    /* solid under the avatar, brightest right at its edge, fading out over the 30 px rim */
    background: radial-gradient(closest-side, #689aff 60%, rgb(0 51 255 / 0.55) 76%, transparent);
    opacity: calc(var(--mx-on, 0) * (0.25 + 0.75 * var(--mx-level, 0)));
    scale: calc(0.9 + 0.3 * var(--mx-level, 0));
    will-change: opacity, scale;   /* own layer: per-frame updates skip paint */
}

html.f-m-audio-reactive-glow .mx-beat-bloom {
    position: fixed;
    inset: 0;
    z-index: -9;
    pointer-events: none;
    background: radial-gradient(62% 46% at 50% 46%, rgb(62 120 255 / 0.55), transparent 72%);
    opacity: calc(var(--mx-on, 0) * 0.6 * var(--mx-level, 0));   /* the real track pulses ~2x a second: keep it soft */
    will-change: opacity;
}

/* weak phones keep the avatar pulse but not the full-screen bloom */
html.lite.f-m-audio-reactive-glow .mx-beat-bloom { display: none; }

/* while the beat drives the glow, the orbit ring's breathing glow steps aside */
html.cx-motion.cx-playing.f-m-audio-reactive-glow.f-m-avatar-orbit-ring .avatar-wrapper::after { animation: none; opacity: 0; }

/* ===== Player Spectrum (m-player-spectrum) ===== */
html.f-m-player-spectrum .player-inner { position: relative; }
html.f-m-player-spectrum .player-content { position: relative; }
html.f-m-player-spectrum .mx-spectrum {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 70%;
    /* the canvas rounds its own bottom corners with the player's radius (instead of overflow: hidden on
       the player, which would also cut off the scrubber's touch target below the player) */
    border-bottom-left-radius: inherit;
    border-bottom-right-radius: inherit;
    opacity: 0.3;
    pointer-events: none;
    color: #91b7ff;   /* read by the canvas as its bar colour */
    /* the bars fade out toward the top, so the title and the controls stay clean */
    -webkit-mask-image: linear-gradient(to top, #000 30%, rgb(0 0 0 / 0.35) 75%, transparent);
    mask-image: linear-gradient(to top, #000 30%, rgb(0 0 0 / 0.35) 75%, transparent);
}

/* ===== Play State + Vinyl (m-play-state-vinyl) ===== */
html.f-m-play-state-vinyl .control-btn.play :is(.play-icon, .pause-icon) {
    display: block !important;   /* both icons stay rendered and cross-fade */
    grid-area: 1 / 1;
    transition: opacity 0.2s ease;
}
html.f-m-play-state-vinyl .control-btn.play .pause-icon,
html.f-m-play-state-vinyl.cx-playing .control-btn.play .play-icon { opacity: 0; }
html.f-m-play-state-vinyl.cx-playing .control-btn.play .pause-icon { opacity: 1; }

html.cx-motion.f-m-play-state-vinyl .control-btn.play :is(.play-icon, .pause-icon) {
    transition: opacity 0.2s ease, rotate 0.45s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)), scale 0.45s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1));
}
html.cx-motion.f-m-play-state-vinyl .control-btn.play .pause-icon,
html.cx-motion.f-m-play-state-vinyl.cx-playing .control-btn.play .play-icon { rotate: -90deg; scale: 0.4; }
html.cx-motion.f-m-play-state-vinyl.cx-playing .control-btn.play .pause-icon { rotate: 0deg; scale: 1; }

html.cx-motion.f-m-play-state-vinyl .control-btn { transition: scale 0.45s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)); }
html.cx-motion.f-m-play-state-vinyl .control-btn:active { scale: 0.86; transition-duration: 0.08s; }

/* the cover becomes a record: round, with the centre hole cut out */
html.f-m-play-state-vinyl .album-cover {
    border-radius: 50%;
    -webkit-mask: radial-gradient(circle, transparent 3px, #000 3.5px);
    mask: radial-gradient(circle, transparent 3px, #000 3.5px);
}

/* ===== Progress Scrub (m-progress-scrub) ===== */
/* the baseline keeps writing width / left on every tick; these overrides make those writes inert and the
   script moves the fill and the handle with transform only */
html.f-m-progress-scrub #progress {
    width: 100% !important;
    transform-origin: 0 50%;
    scale: 0 1;
}
html.f-m-progress-scrub #progressHandle {
    left: 0 !important;
}
html.cx-motion.f-m-progress-scrub #progressHandle {
    transition: scale 0.3s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1));
}
/* between the ~4 Hz time events the fill and the handle glide (the script drops it for seeks and drags) */
html.f-m-progress-scrub #progressBar.mx-glide #progress { transition: scale 0.26s linear; }
html.f-m-progress-scrub #progressBar.mx-glide :is(#progressHandle, .mx-scrub-tip) { transition: translate 0.26s linear, scale 0.3s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)); }
html.f-m-progress-scrub.mx-scrubbing #progressHandle { scale: 1.3; }

html.f-m-progress-scrub .mx-scrub {
    position: absolute;
    inset: -10px 0;   /* 26 px tall target around the 6 px bar */
    z-index: 2;
    cursor: pointer;
    touch-action: none;
    border-radius: 9999px;
    -webkit-tap-highlight-color: transparent;
}
html.f-m-progress-scrub .mx-scrub:focus { outline: none; }

/* touch screens: a 44 px tall target, 10 px above the bar (the play / prev / next row is just above)
   and 30 px below it, past the player's bottom edge */
@media (pointer: coarse) {
    html.f-m-progress-scrub .mx-scrub {
        inset: -10px 0 -30px;
        border-radius: 0;   /* a rounded 44 px box would cut the bar's two ends out of the target */
    }

    /* the player's own buttons always stay on top of the scrubber's larger area */
    html.f-m-progress-scrub :is(.player-controls, .ft-lyric) {
        position: relative;
        z-index: 3;
    }
}

/* own focus ring on the bar itself — unless the shared focus ring of a-focus-visible-and-names is on */
html.f-m-progress-scrub:not(.f-a-focus-visible-and-names) #progressBar:has(> .mx-scrub:focus-visible) {
    box-shadow: 0 0 0 2px rgb(255 255 255 / 0.85), 0 0 0 5px rgb(0 51 255 / 0.55);
}

html.f-m-progress-scrub .mx-scrub-tip {
    position: absolute;
    left: 0;
    bottom: calc(100% + 12px);
    z-index: 3;
    padding: 3px 7px;
    border-radius: 7px;
    background: rgb(8 10 18 / 0.92);
    border: 1px solid rgb(255 255 255 / 0.14);
    color: #fff;
    font: 600 11px / 1.2 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    pointer-events: none;
    transform: translateX(-50%);
    opacity: 0;
}
html.f-m-progress-scrub.mx-scrubbing .mx-scrub-tip { opacity: 1; }

/* ===== Social Icon Feel (m-social-icon-feel) ===== */
/* 52 px tap and magnet targets that still take 36 px in the layout: same icon centres, same wrapping (also
   at 360 px), same card height. With the glass brand chips (v-brand-hover-socials) the chips keep their size. */
html.f-m-social-icon-feel:not(.f-v-brand-hover-socials) .social-link { width: 52px; height: 52px; margin: -8px; }
html.f-m-social-icon-feel:not(.f-v-brand-hover-socials) .social-link .tooltip { top: -28px; }   /* the tooltip stays where it was */
html.f-m-social-icon-feel .social-link[data-brand="discord"] { --mx-brand: #5865f2; }
html.f-m-social-icon-feel .social-link[data-brand="telegram"] { --mx-brand: #26a5e4; }
html.f-m-social-icon-feel .social-link[data-brand="tiktok"] { --mx-brand: #fe2c55; }
html.f-m-social-icon-feel .social-link[data-brand="youtube"] { --mx-brand: #ff0033; }
html.f-m-social-icon-feel .social-link[data-brand="instagram"] { --mx-brand: #e1306c; }
html.f-m-social-icon-feel .social-link[data-brand="threads"] { --mx-brand: #ffffff; }

html.f-m-social-icon-feel .social-link .mx-halo {
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    pointer-events: none;
    background: radial-gradient(closest-side, var(--mx-brand, #fff), transparent);
    opacity: 0;
    transition: opacity 0.25s ease;
}
html.cx-motion.f-m-social-icon-feel .social-link .mx-halo { scale: 0.5; transition: opacity 0.25s ease, scale 0.5s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)); }

html.f-m-social-icon-feel .social-link .icon { transform: none !important; }   /* the individual scale property takes over */
html.cx-motion.f-m-social-icon-feel .social-link .icon { transition: translate 0.5s var(--ease-spring, cubic-bezier(0.22, 1, 0.36, 1)), scale 0.45s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)); }
html.f-m-social-icon-feel .social-link:focus-visible .icon { scale: 1.1; }
html.f-m-social-icon-feel .social-link:focus-visible .mx-halo { opacity: 0.6; scale: 1; }

@media (hover: hover) {
    html.f-m-social-icon-feel .social-link:hover .icon { scale: 1.1; }
    html.f-m-social-icon-feel .social-link:hover .mx-halo { opacity: 0.6; scale: 1; }
}

@media (hover: none) {
    /* a tap must not leave the tooltip stuck on phones */
    html.f-m-social-icon-feel .social-link:hover .tooltip { opacity: 0; }
}

html.cx-motion.f-m-social-icon-feel .social-link:active .icon { scale: 0.86; transition-duration: 0.5s, 0.08s; }

html.f-m-social-icon-feel .social-link .mx-ripple {
    position: absolute;
    inset: 8px;
    border: 2px solid var(--mx-brand, #fff);
    border-radius: 50%;
    pointer-events: none;
    opacity: 0;
}
html.f-m-social-icon-feel.f-v-brand-hover-socials .social-link .mx-ripple { inset: 0; border-radius: inherit; }

/* ===== Pixel Plus Sparkles (m-pixel-plus-sparkles) ===== */
html.f-m-pixel-plus-sparkles .video-overlay { display: none; }
html.f-m-pixel-plus-sparkles .mx-sparkles {
    position: fixed;
    inset: -32px;   /* overscan, so the sky parallax never shows an edge */
    z-index: 50;
    overflow: hidden;
    pointer-events: none;
}
html.f-m-pixel-plus-sparkles .mx-sparkles canvas {
    position: absolute;
    left: 0;
    top: 0;
    image-rendering: pixelated;
}

/* ===== Shooting Stars (m-shooting-stars) ===== */
html.f-m-shooting-stars .mx-meteor {
    position: fixed;
    top: 0;
    left: 0;
    z-index: -8;   /* under the sparkles (50) and the card (100) */
    width: 150px;
    height: 2px;
    border-radius: 999px;
    background: linear-gradient(90deg, transparent, rgb(100 143 255 / 0.72) 70%, #fff);
    filter: drop-shadow(0 0 6px rgb(160 185 255 / 0.9));   /* static: rasterised once */
    transform-origin: 100% 50%;
    opacity: 0;
    pointer-events: none;
}

@media (max-width: 600px) {
    html.f-m-shooting-stars .mx-meteor { width: 120px; }
}

/* ===== Sky Parallax (m-sky-parallax) ===== */
html.cx-motion.f-m-sky-parallax:not(.lite) .background { inset: -24px; }      /* overscan > max travel, edges never show */
html.cx-motion.f-m-sky-parallax:not(.lite) .video-overlay { inset: -32px; }

/* ===== Card Tilt + Glare (m-card-tilt-glare) ===== */
html.cx-motion.f-m-card-tilt-glare .profile-card { transition: transform 0.7s var(--ease-spring, cubic-bezier(0.22, 1, 0.36, 1)); }
html.cx-motion.f-m-card-tilt-glare .profile-card:hover,
html.cx-motion.f-m-card-tilt-glare.mx-tilt-live .profile-card { transition: transform 0.15s ease-out; }

html.f-m-card-tilt-glare .mx-glare {
    position: absolute;
    inset: 0;
    z-index: 3000;
    overflow: hidden;
    border-radius: inherit;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.4s ease;
}
html.f-m-card-tilt-glare .mx-glare::before {
    content: '';
    position: absolute;
    inset: -50%;
    background: radial-gradient(circle, rgb(255 255 255 / 0.13), rgb(38 83 255 / 0.16) 20%, transparent 42%);
    translate: var(--mx-gx, 0) var(--mx-gy, 0);
    transition: translate 0.15s ease-out;
}
@media (hover: hover) and (pointer: fine) {
    html.cx-motion.f-m-card-tilt-glare:not(.lite) .profile-card:hover .mx-glare { opacity: 1; }
}
html.cx-motion.f-m-card-tilt-glare.mx-tilt-live .mx-glare { opacity: 1; }

/* ===== Cursor Plus Trail (m-cursor-plus-trail) ===== */
html.f-m-cursor-plus-trail .mx-trail {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 150;   /* above the card (100), below the fixed controls (200) */
    pointer-events: none;
    image-rendering: pixelated;
    color: #89b2ff;   /* read by the canvas as the blue tint */
}

/* ===== EQ Panel Spring (m-eq-panel-spring) ===== */
/* opens from the mixer button's corner with a soft spring, closes quickly; works for the native popover
   (a-eq-panel-popover) and for the .active fallback. The id keeps these rules above the panel's own styles. */
html.f-m-eq-panel-spring #eqPanel {
    transform: none;
    transform-origin: 100% 100%;
}
html.cx-motion.f-m-eq-panel-spring #eqPanel {
    translate: 0 8px;
    scale: 0.92;
    transition: opacity 0.15s ease-in, translate 0.15s ease-in, scale 0.15s ease-in, visibility 0s 0.15s;
    transition: opacity 0.15s ease-in, translate 0.15s ease-in, scale 0.15s ease-in, visibility 0s 0.15s, overlay 0.15s allow-discrete, display 0.15s allow-discrete;
}
html.cx-motion.f-m-eq-panel-spring #eqPanel:is(.active, :popover-open) {
    translate: 0 0;
    scale: 1;
    transition: opacity 0.2s ease-out, translate 0.45s var(--ease-spring, cubic-bezier(0.22, 1, 0.36, 1)), scale 0.45s var(--ease-spring, cubic-bezier(0.22, 1, 0.36, 1)), visibility 0s;
    transition: opacity 0.2s ease-out, translate 0.45s var(--ease-spring, cubic-bezier(0.22, 1, 0.36, 1)), scale 0.45s var(--ease-spring, cubic-bezier(0.22, 1, 0.36, 1)), visibility 0s, overlay 0.45s allow-discrete, display 0.45s allow-discrete;
}
@media (hover: hover) and (pointer: fine) {
    /* the legacy hover-open (no popover) gets the same spring */
    html.cx-motion.f-m-eq-panel-spring .mixer-wrapper:hover #eqPanel:not([popover]) {
        translate: 0 0;
        scale: 1;
        transition: opacity 0.2s ease-out, translate 0.45s var(--ease-spring, cubic-bezier(0.22, 1, 0.36, 1)), scale 0.45s var(--ease-spring, cubic-bezier(0.22, 1, 0.36, 1)), visibility 0s;
    }
}
@starting-style {
    html.cx-motion.f-m-eq-panel-spring #eqPanel:popover-open { opacity: 0; translate: 0 8px; scale: 0.92; }
}

@media (hover: none) {
    /* hover-to-open sticks after a tap on phones: there only the button opens the panel */
    html.f-m-eq-panel-spring .mixer-wrapper:hover #eqPanel:not([popover]):not(.active) {
        opacity: 0;
        visibility: hidden;
    }
}

/* the three mixer lines become an X while the panel is open (when the dock shows them) */
html.cx-motion.f-m-eq-panel-spring .mixer-icon::before,
html.cx-motion.f-m-eq-panel-spring .mixer-icon::after,
html.cx-motion.f-m-eq-panel-spring .mixer-icon i { transition: translate 0.35s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)), rotate 0.35s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)), opacity 0.2s ease; }
html.f-m-eq-panel-spring .mixer-wrapper:has(#eqPanel:is(.active, :popover-open)) .mixer-icon::before { translate: 0 5px; rotate: 45deg; }
html.f-m-eq-panel-spring .mixer-wrapper:has(#eqPanel:is(.active, :popover-open)) .mixer-icon::after { translate: 0 -5px; rotate: -45deg; }
html.f-m-eq-panel-spring .mixer-wrapper:has(#eqPanel:is(.active, :popover-open)) .mixer-icon i { opacity: 0; }

/* sliders: the handle grows while dragged and the fill follows the finger without lag */
html.f-m-eq-panel-spring .eq-slider-handle { transform-origin: 0 50%; }
html.cx-motion.f-m-eq-panel-spring .eq-slider-handle { transition: scale 0.3s var(--ease-pop, cubic-bezier(0.34, 1.56, 0.64, 1)); }
html.f-m-eq-panel-spring .eq-slider-track.mx-dragging .eq-slider-handle { scale: 1.3; }
html.f-m-eq-panel-spring .eq-slider-track.mx-dragging .eq-slider-fill { transition: none; }

/* ===== View Counter Roll (m-view-counter-roll) ===== */
html.f-m-view-counter-roll .stat-item[data-stat="views"] { position: relative; }
html.f-m-view-counter-roll #viewCount { display: none; }   /* still core's source of truth; the copy below is what shows */
html.f-m-view-counter-roll .stat-item .mx-views { display: inline-flex; position: relative; }
html.f-m-view-counter-roll .mx-views .mx-sr {   /* the value for screen readers, the rolling digits are aria-hidden */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
html.f-m-view-counter-roll .stat-item .mx-digits {
    display: inline-flex;
    justify-content: flex-end;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
html.f-m-view-counter-roll .mx-views .mx-cell { display: block; height: 1lh; }
html.f-m-view-counter-roll .mx-views .mx-cell.is-rolling {
    -webkit-mask: linear-gradient(transparent, #000 26%, #000 74%, transparent) no-repeat;
    mask: linear-gradient(transparent, #000 26%, #000 74%, transparent) no-repeat;
}
html.f-m-view-counter-roll .mx-views .mx-strip { display: flex; flex-direction: column; }
html.f-m-view-counter-roll .mx-views .mx-strip > span { display: block; height: 1lh; }

/* engines without the lh unit (iOS < 16.4, Firefox < 120): the same one-line height in em, so a roll never
   stretches the pill — the body's 1.4 line height, or 1 in the 12px/1 Geist Mono chips (v-display-typeface) */
@supports not (height: 1lh) {
    html.f-m-view-counter-roll .mx-views :is(.mx-cell, .mx-strip > span) { height: 1.4em; }
    html.f-m-view-counter-roll.f-v-display-typeface .mx-views :is(.mx-cell, .mx-strip > span) { height: 1em; }
}

html.f-m-view-counter-roll .stat-item .mx-views-chip {
    position: absolute;
    top: calc(100% + 2px);
    left: 50%;
    translate: -50% 0;
    font-size: 11px;
    font-weight: 600;
    color: #a5c5ff;
    text-shadow: 0 0 8px rgb(0 51 255 / 0.7);
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
}

/* ===== Accent mixes =====
   The colours above that follow the theme's --accent, for engines with color-mix(); the rules themselves
   hold plain values for the default blue. (A plain fallback written just before a color-mix(var(…))
   declaration never applies: the var() one wins the cascade, and an engine without color-mix() then
   drops it to nothing — the splash would lose its scrim.) */
@supports (color: color-mix(in oklab, red, blue)) {
    html.f-m-enter-splash:not(.mx-splash-seen):not(.mx-ready):not(.mx-splash-open) #site::before,
    html .mx-splash {
        background:
            radial-gradient(ellipse 70% 55% at 50% 46%, color-mix(in srgb, var(--accent, #0033ff) 24%, rgb(2 11 38 / 0.3)), transparent 72%),
            radial-gradient(ellipse at 50% 45%, rgb(2 11 38 / 0.5), rgb(2 11 38 / 0.94) 72%);
    }

    .mx-splash:focus-visible .mx-splash-hint {
        box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.1), 0 0 0 3px color-mix(in srgb, var(--accent, #0033ff) 55%, transparent);
    }

    /* the image only: the shorthand would reset the band's background-clip: text */
    html.f-m-name-shimmer .display-name::after {
        background-image: linear-gradient(100deg, transparent 41%, color-mix(in oklab, var(--accent, #0033ff) 30%, #fff) 50%, transparent 59%);
    }

    html.f-m-avatar-orbit-ring .avatar-wrapper::before {
        background: conic-gradient(transparent 0 50%, var(--accent, #0033ff) 72%, color-mix(in oklab, var(--accent, #0033ff) 45%, #fff) 90%, #fff 94%, transparent 97%);
    }

    html.f-m-avatar-orbit-ring .avatar-wrapper::after {
        background: radial-gradient(closest-side, color-mix(in srgb, var(--accent, #0033ff) 60%, transparent), transparent);
    }

    html.f-m-audio-reactive-glow .mx-beat-glow {
        background: radial-gradient(closest-side, color-mix(in oklab, var(--accent, #0033ff) 58%, #fff) 60%, color-mix(in srgb, var(--accent, #0033ff) 55%, transparent) 76%, transparent);
    }

    html.f-m-audio-reactive-glow .mx-beat-bloom {
        background: radial-gradient(62% 46% at 50% 46%, color-mix(in srgb, color-mix(in oklab, var(--accent, #0033ff) 75%, #fff) 55%, transparent), transparent 72%);
    }

    html.f-m-player-spectrum .mx-spectrum {
        color: color-mix(in oklab, var(--accent, #0033ff) 42%, #fff);
    }

    html.f-m-progress-scrub:not(.f-a-focus-visible-and-names) #progressBar:has(> .mx-scrub:focus-visible) {
        box-shadow: 0 0 0 2px rgb(255 255 255 / 0.85), 0 0 0 5px color-mix(in srgb, var(--accent, #0033ff) 55%, transparent);
    }

    html.f-m-shooting-stars .mx-meteor {
        background: linear-gradient(90deg, transparent, color-mix(in oklab, var(--accent, #0033ff) 30%, rgb(170 190 255 / 0.6)) 70%, #fff);
    }

    html.f-m-card-tilt-glare .mx-glare::before {
        background: radial-gradient(circle, rgb(255 255 255 / 0.13), color-mix(in srgb, var(--accent, #0033ff) 12%, rgb(140 170 255 / 0.05)) 20%, transparent 42%);
    }

    html.f-m-cursor-plus-trail .mx-trail {
        color: color-mix(in oklab, var(--accent, #0033ff) 45%, #fff);
    }

    html.f-m-view-counter-roll .stat-item .mx-views-chip {
        color: color-mix(in oklab, var(--accent, #0033ff) 34%, #fff);
    }
}
