/* assets/css/cosmetics.css
 * All cosmetic visual classes. Applied dynamically when an item is equipped.
 * Uses base.css :root tokens for colors. No external image dependencies.
 */

/* === Frames (border around avatar) === */
/* Frames: use outline (not box-shadow) — outlines aren't clipped by parent overflow:hidden,
   so the ring stays visible inside containers like .up-hero on the public profile. */
.cosmetic-frame-bronze   { outline: 2px solid #cd7f32; outline-offset: 2px; border-radius: 50%; }
.cosmetic-frame-silver   { outline: 2px solid #c0c0c0; outline-offset: 2px; border-radius: 50%; }
.cosmetic-frame-gold     {
    outline: 2px solid #ffd700; outline-offset: 2px; border-radius: 50%;
    filter: drop-shadow(0 0 6px rgba(255,215,0,.5));
}
.cosmetic-frame-diamond  {
    outline: 2px solid #b9f2ff; outline-offset: 3px; border-radius: 50%;
    filter: drop-shadow(0 0 8px rgba(185,242,255,.7));
}

/* === Titles (username styling) ===
   Player title gets a subtle "tag" badge so it's visibly distinct from default text. */
.cosmetic-title-player   {
    color: var(--text);
    font-weight: var(--fw-medium);
    position: relative;
}
.cosmetic-title-player::after {
    content: 'PLAYER';
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 3px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-veteran::after {
    content: 'VETERAN';
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 3px;
    background: var(--accent);
    color: var(--bg);
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-veteran  { color: var(--accent); font-weight: var(--fw-semi); }
.cosmetic-title-veteran  { color: var(--accent); font-weight: var(--fw-semi); }
.cosmetic-title-pro      {
    background: linear-gradient(90deg, var(--accent), #ffaa66);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
    color: #ffaa66;
    font-weight: var(--fw-bold);
}
.cosmetic-title-pro::after {
    content: 'PRO';
    display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 3px;
    background: linear-gradient(135deg, var(--accent), #ffaa66);
    color: var(--bg);
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
    box-shadow: 0 0 8px rgba(255,170,102,.55);
}
.cosmetic-title-legend   {
    background: linear-gradient(90deg, #ff6b6b, #ffd93d, #6dc28b, #4dabf7, #c77dff);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
    color: #ffd93d;
    font-weight: var(--fw-bold);
    animation: legend-shimmer 4s linear infinite;
}
@keyframes legend-shimmer { to { background-position: 200% center; } }

/* === Effects === */
.cosmetic-effect-pulse   { animation: effect-pulse 2s ease-in-out infinite; }
@keyframes effect-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.6; }
}
.cosmetic-effect-glow    { text-shadow: 0 0 8px var(--accent), 0 0 16px rgba(255,170,102,.4); }
/* Rainbow uses its own color gradient so it works on plain text (hue-rotate only
   rotates colors that already exist). Overrides any title gradient. */
.cosmetic-effect-rainbow {
    background: linear-gradient(90deg,
        #ff6b6b, #ffa94d, #ffd93d, #6dc28b, #4dabf7, #c77dff, #ff6b6b);
    background-size: 200% auto;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: #ffa94d;
    font-weight: var(--fw-semi);
    animation: effect-rainbow 5s linear infinite;
}
@keyframes effect-rainbow { to { background-position: 200% center; } }

/* === Backgrounds ===
   Applied to document.body together with .has-cosmetic-bg so they render as
   a fullscreen page backdrop instead of clipping to a single card. */
body.has-cosmetic-bg {
    background-attachment: fixed;
    background-repeat: repeat;
    background-size: auto;
}
.cosmetic-bg-stars {
    background-image: radial-gradient(2px 2px at 20% 30%, white, transparent),
                      radial-gradient(1px 1px at 40% 70%, white, transparent),
                      radial-gradient(1.5px 1.5px at 60% 20%, white, transparent),
                      radial-gradient(1px 1px at 80% 50%, white, transparent),
                      radial-gradient(2px 2px at 90% 80%, white, transparent),
                      var(--bg-card);
    background-size: 200px 200px, 150px 150px, 300px 300px, 100px 100px, 250px 250px, auto;
}
.cosmetic-bg-nebula {
    background:
        radial-gradient(ellipse at 30% 40%, rgba(199,125,255,.3), transparent 60%),
        radial-gradient(ellipse at 70% 60%, rgba(77,171,247,.3), transparent 60%),
        var(--bg-card);
}
.cosmetic-bg-void {
    background:
        radial-gradient(circle at 50% 50%, rgba(255,255,255,.05), transparent 70%),
        linear-gradient(135deg, #0a0a0f, #1a0a1f);
    position: relative;
    overflow: hidden;
}
.cosmetic-bg-void::after {
    content: '';
    position: absolute; inset: 0;
    background-image:
        radial-gradient(1px 1px at 15% 25%, rgba(199,125,255,.6), transparent),
        radial-gradient(1px 1px at 75% 65%, rgba(77,171,247,.6), transparent),
        radial-gradient(1.5px 1.5px at 50% 50%, white, transparent);
    background-size: 100% 100%;
    pointer-events: none;
    animation: void-drift 20s linear infinite;
}
@keyframes void-drift {
    from { transform: translate(0, 0); }
    to   { transform: translate(-20px, -10px); }
}

/* === Shop & Inventory grid === */
.cosmetic-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 14px;
}
.cosmetic-card {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-card);
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    position: relative;
}
.cosmetic-card.rarity-common    { border-left: 3px solid #888; }
.cosmetic-card.rarity-rare      { border-left: 3px solid #4dabf7; }
.cosmetic-card.rarity-epic      { border-left: 3px solid #c77dff; }
.cosmetic-card.rarity-legendary { border-left: 3px solid #ffd93d; }
.cosmetic-card-name {
    font-family: var(--font-mono);
    font-size: var(--fs-body);
    color: var(--text);
    margin: 0;
    /* Give space for the state pill (top-left) + rarity badge (top-right)
       that absolutely-position to the same row. */
    padding-top: 22px;
}
.cosmetic-card-meta {
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: var(--ls-default);
    display: flex;
    justify-content: space-between;
}
.cosmetic-card-preview {
    height: 60px;
    border-radius: var(--radius);
    background: var(--bg-input);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: var(--fs-md);
    color: var(--text);
}
.cosmetic-card-preview.is-frame {
    width: 48px; height: 48px;
    margin: 6px auto;
    background: var(--bg-input);
}
.cosmetic-card-action {
    background: var(--accent);
    border: none;
    color: var(--bg);
    padding: 8px 12px;
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    cursor: pointer;
    text-transform: uppercase;
}
.cosmetic-card-action:disabled { opacity: .4; cursor: not-allowed; background: var(--text-muted); }
.cosmetic-card-action.equipped { background: var(--text-muted); }
.cosmetic-card-badge {
    position: absolute;
    top: 8px; right: 8px;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: var(--ls-default);
}

.cosmetic-category-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 12px;
}
.cosmetic-category-pill {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 6px 12px;
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    color: var(--text-muted);
    cursor: pointer;
    text-transform: uppercase;
    letter-spacing: var(--ls-default);
    transition: color .12s, border-color .12s, background .12s;
}
.cosmetic-category-pill:hover  { color: var(--text); border-color: var(--accent); }
.cosmetic-category-pill.active { color: var(--bg); background: var(--accent); border-color: var(--accent); }

/* ═════════════════════════════════════════════════════════════════════
 * Phase 10 — extended cosmetic categories
 * Each category has its own set of css_class values that the renderer
 * applies to the correct target element.
 * ═════════════════════════════════════════════════════════════════════ */

/* === Animated frames (applied to avatar like regular frames) ===
 * Implemented with outline + box-shadow only — conic-gradient backgrounds are
 * overdrawn by the <img> pixels, and filter:hue-rotate tints the avatar
 * itself which we never want. */
.cosmetic-frame-neon-cycle {
    outline: 2px solid #4dabf7;
    outline-offset: 2px;
    border-radius: 50%;
    animation: frame-neon-cycle 3s linear infinite;
}
@keyframes frame-neon-cycle {
    0%, 100% { outline-color: #ff6b6b; box-shadow: 0 0 10px 2px rgba(255,107,107,.65); }
    33%      { outline-color: #6dc28b; box-shadow: 0 0 10px 2px rgba(109,194,139,.65); }
    66%      { outline-color: #4dabf7; box-shadow: 0 0 10px 2px rgba(77,171,247,.65); }
}

.cosmetic-frame-fire {
    outline: 2px solid #ff8c3b;
    outline-offset: 2px;
    border-radius: 50%;
    box-shadow: 0 0 8px 2px rgba(255,140,59,.75), 0 -2px 10px 1px rgba(255,80,30,.45);
    animation: frame-fire-flicker .45s ease-in-out infinite alternate;
}
@keyframes frame-fire-flicker {
    from { box-shadow: 0 0 8px 2px rgba(255,140,59,.75), 0 -2px 10px 1px rgba(255,80,30,.45); }
    to   { box-shadow: 0 0 14px 3px rgba(255,180,80,1),  0 -3px 14px 2px rgba(255,120,40,.7); }
}

.cosmetic-frame-plasma {
    outline: 2px solid #c77dff;
    outline-offset: 2px;
    border-radius: 50%;
    animation: frame-plasma-cycle 4s linear infinite;
}
@keyframes frame-plasma-cycle {
    0%   { outline-color: #c77dff; box-shadow: 0 0 10px #c77dff, 0 0 22px rgba(199,125,255,.35); }
    25%  { outline-color: #4dabf7; box-shadow: 0 0 10px #4dabf7, 0 0 22px rgba(77,171,247,.35); }
    50%  { outline-color: #6dc28b; box-shadow: 0 0 10px #6dc28b, 0 0 22px rgba(109,194,139,.35); }
    75%  { outline-color: #ffd93d; box-shadow: 0 0 10px #ffd93d, 0 0 22px rgba(255,217,61,.35); }
    100% { outline-color: #c77dff; box-shadow: 0 0 10px #c77dff, 0 0 22px rgba(199,125,255,.35); }
}

.cosmetic-frame-hologram {
    outline: 2px solid #b9f2ff;
    outline-offset: 3px;
    border-radius: 50%;
    animation: frame-hologram-shift 5s linear infinite;
}
@keyframes frame-hologram-shift {
    0%   { outline-color: #b9f2ff; box-shadow: 0 0 8px #b9f2ff,  0 0 18px rgba(185,242,255,.45); }
    33%  { outline-color: #ffaaf7; box-shadow: 0 0 10px #ffaaf7, 0 0 22px rgba(255,170,247,.5); }
    66%  { outline-color: #a3ffd3; box-shadow: 0 0 10px #a3ffd3, 0 0 22px rgba(163,255,211,.45); }
    100% { outline-color: #b9f2ff; box-shadow: 0 0 8px #b9f2ff,  0 0 18px rgba(185,242,255,.45); }
}

/* === Animated titles (applied to username element) === */
.cosmetic-username-wave {
    display: inline-block;
    font-weight: var(--fw-semi);
    color: var(--accent);
    animation: username-wave 2s ease-in-out infinite;
}
@keyframes username-wave {
    0%, 100% { transform: translateY(0);    }
    25%      { transform: translateY(-2px); }
    75%      { transform: translateY(2px);  }
}

.cosmetic-username-glitch {
    position: relative;
    color: #e6e6e6;
    font-weight: var(--fw-bold);
    text-shadow:
        1px 0 0 rgba(255,0,80,.8),
        -1px 0 0 rgba(0,200,255,.8);
    animation: username-glitch-shake .4s steps(2) infinite;
}
@keyframes username-glitch-shake {
    0%, 100% { text-shadow: 1px 0 0 rgba(255,0,80,.8), -1px 0 0 rgba(0,200,255,.8); }
    50%      { text-shadow: -1px 0 0 rgba(255,0,80,.8), 1px 0 0 rgba(0,200,255,.8); }
}

.cosmetic-username-fire {
    color: #ffeb6b;
    font-weight: var(--fw-bold);
    text-shadow:
        0 0 4px #ffb347,
        0 -1px 6px #ff7b24,
        0 -3px 10px #ff2a00;
    animation: username-fire-flicker .4s ease-in-out infinite alternate;
}
@keyframes username-fire-flicker {
    from { text-shadow: 0 0 4px #ffb347, 0 -1px 6px #ff7b24, 0 -3px 10px #ff2a00; }
    to   { text-shadow: 0 0 6px #ffe09c, 0 -2px 8px #ffa24b, 0 -4px 14px #ff5418; }
}

/* === Avatar particles — wrapper class applied to an outer .cosmetic-avatar-wrap === */
.cosmetic-avatar-wrap {
    position: relative;
    display: inline-block;
    line-height: 0;
}
.cosmetic-avatar-wrap::before,
.cosmetic-avatar-wrap::after {
    content: '';
    position: absolute;
    inset: -10px;
    border-radius: 50%;
    pointer-events: none;
}

.cosmetic-avatar-wrap.cosmetic-particle-sparks::before {
    background:
        radial-gradient(2px 2px at 20% 30%, #ffd93d, transparent 55%),
        radial-gradient(1.5px 1.5px at 80% 20%, #ffe896, transparent 55%),
        radial-gradient(1px 1px at 75% 75%, #ffd93d, transparent 55%),
        radial-gradient(1.5px 1.5px at 15% 75%, #ffe896, transparent 55%);
    animation: particle-spin 4s linear infinite;
}
.cosmetic-avatar-wrap.cosmetic-particle-embers::before {
    background:
        radial-gradient(2px 2px at 30% 85%, #ff8c3b, transparent 55%),
        radial-gradient(1.5px 1.5px at 65% 80%, #ffb347, transparent 55%),
        radial-gradient(1px 1px at 50% 95%, #ff5500, transparent 55%);
    animation: particle-rise 2s linear infinite;
}
.cosmetic-avatar-wrap.cosmetic-particle-orbit::before {
    content: '';
    position: absolute;
    inset: -8px;
    border-radius: 50%;
    border: 1px dashed rgba(199,125,255,.35);
    animation: particle-spin 6s linear infinite;
}
.cosmetic-avatar-wrap.cosmetic-particle-orbit::after {
    content: '';
    position: absolute;
    top: -10px;
    left: 50%;
    width: 6px;
    height: 6px;
    margin-left: -3px;
    border-radius: 50%;
    background: #c77dff;
    box-shadow: 0 0 8px #c77dff;
    transform-origin: 3px calc(50% + 14px);
    animation: particle-orbit-dot 3s linear infinite;
}
@keyframes particle-spin  { to { transform: rotate(360deg); } }
@keyframes particle-orbit-dot {
    from { transform: rotate(0deg)   translateX(0); }
    to   { transform: rotate(360deg) translateX(0); }
}
@keyframes particle-rise {
    0%   { transform: translateY(6px); opacity: 0.9; }
    100% { transform: translateY(-12px); opacity: 0; }
}

/* === Custom coin icon — applied on the .header-coin-pill svg container ===
 * The svg is hidden, and ::before draws the replacement glyph. */
/* Hide the default coin svg when a custom icon class is present. */
.header-coin-pill.cosmetic-coin-heart   .coin-icon,
.header-coin-pill.cosmetic-coin-diamond .coin-icon,
.header-coin-pill.cosmetic-coin-bitcoin .coin-icon,
.header-coin-pill.cosmetic-coin-crown   .coin-icon { display: none; }

/* Each coin icon draws its glyph via ::before on the pill itself. Using the
   header-coin-pill prefix lifts specificity above unrelated ::before rules. */
.header-coin-pill.cosmetic-coin-heart::before {
    content: '♥';
    color: #ff6b9d;
    font-size: var(--fs-base);
    line-height: 1;
    display: inline-block;
    margin-right: 4px;
    vertical-align: middle;
}
.header-coin-pill.cosmetic-coin-diamond::before {
    content: '◆';
    color: #b9f2ff;
    font-size: var(--fs-base);
    line-height: 1;
    display: inline-block;
    margin-right: 4px;
    vertical-align: middle;
    filter: drop-shadow(0 0 3px #b9f2ff);
}
.header-coin-pill.cosmetic-coin-bitcoin::before {
    content: '₿';
    color: #f7931a;
    font-size: var(--fs-base);
    font-weight: var(--fw-bold);
    line-height: 1;
    display: inline-block;
    margin-right: 4px;
    vertical-align: middle;
}
.header-coin-pill.cosmetic-coin-crown::before {
    content: '♛';
    color: #ffd93d;
    font-size: var(--fs-lg);
    line-height: 1;
    display: inline-block;
    margin-right: 4px;
    vertical-align: middle;
    filter: drop-shadow(0 0 4px #ffd93d);
    animation: coin-crown-sheen 2.5s ease-in-out infinite;
}
@keyframes coin-crown-sheen {
    0%, 100% { filter: drop-shadow(0 0 4px #ffd93d); }
    50%      { filter: drop-shadow(0 0 10px #ffe896); }
}

/* === Banner overlays — applied on a .banner-overlay div sitting on top of the banner === */
.banner-overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: hidden;
    border-radius: inherit;
}
.cosmetic-overlay-shine {
    background: linear-gradient(110deg, transparent 30%, rgba(255,255,255,.25) 45%, transparent 60%);
    background-size: 200% 100%;
    background-repeat: no-repeat;
    animation: overlay-shine 3.5s ease-in-out infinite;
}
@keyframes overlay-shine {
    0%   { background-position: 200% 0; }
    100% { background-position: -100% 0; }
}
.cosmetic-overlay-sparkles {
    background:
        radial-gradient(1.5px 1.5px at 10% 20%, #fff, transparent 55%),
        radial-gradient(2px 2px at 25% 75%, #ffd93d, transparent 55%),
        radial-gradient(1.5px 1.5px at 40% 30%, #fff, transparent 55%),
        radial-gradient(1px 1px at 60% 80%, #fff, transparent 55%),
        radial-gradient(2px 2px at 75% 40%, #ffd93d, transparent 55%),
        radial-gradient(1.5px 1.5px at 90% 70%, #fff, transparent 55%);
    animation: overlay-sparkle-twinkle 2s ease-in-out infinite;
}
@keyframes overlay-sparkle-twinkle {
    0%, 100% { opacity: 0.4; }
    50%      { opacity: 1; }
}
.cosmetic-overlay-confetti {
    background-image:
        linear-gradient(45deg, #ff6b6b 0, #ff6b6b 3px, transparent 3px 6px),
        linear-gradient(-45deg, #4dabf7 0, #4dabf7 3px, transparent 3px 6px),
        linear-gradient(45deg, #6dc28b 0, #6dc28b 3px, transparent 3px 6px);
    background-size: 40px 40px, 32px 32px, 48px 48px;
    background-position: 0 0, 0 0, 0 0;
    opacity: 0.60;
    animation: overlay-confetti-scroll 6s linear infinite;
}
@keyframes overlay-confetti-scroll {
    from { background-position: 0 0,     0 0,     0 0; }
    to   { background-position: 40px 40px, -32px 32px, 48px 48px; }
}
.cosmetic-overlay-matrix {
    background-image:
        linear-gradient(180deg,
            transparent 0%,
            rgba(0,255,80,.0)  30%,
            rgba(0,255,80,.45) 55%,
            rgba(0,255,80,.18) 65%,
            transparent 100%),
        repeating-linear-gradient(90deg,
            transparent 0, transparent 7px,
            rgba(0,255,80,.12) 7px, rgba(0,255,80,.12) 8px);
    background-size: 3px 60px, auto auto;
    background-repeat: repeat, repeat;
    animation: overlay-matrix-rain 1.1s linear infinite;
    mix-blend-mode: screen;
}
@keyframes overlay-matrix-rain {
    from { background-position: 0 0,     0 0; }
    to   { background-position: 0 60px,  0 0; }
}

/* === New title styles === */
/* New purchasable + achievement titles: colour the username itself so the
   effect is visible even when a parent clips ::after pseudo-elements. */
.cosmetic-title-shark     { color: #9bd0ff; font-weight: var(--fw-semi); }
.cosmetic-title-grinder   { color: #ffd27a; font-weight: var(--fw-semi); }
.cosmetic-title-whale     { color: #b9f2ff; font-weight: var(--fw-semi); text-shadow: 0 0 4px rgba(185,242,255,.5); }
.cosmetic-title-degen     { color: #ff6b9d; font-weight: var(--fw-semi); }
.cosmetic-title-lucky     { color: #6dc28b; font-weight: var(--fw-semi); }
.cosmetic-title-streak    { color: #ffaa66; font-weight: var(--fw-semi); }
.cosmetic-title-collector { color: #c77dff; font-weight: var(--fw-semi); }
.cosmetic-title-jackpot {
    background: linear-gradient(90deg, #ff8c3b, #ffd93d);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
    font-weight: var(--fw-bold);
}
.cosmetic-title-og {
    background: linear-gradient(90deg, #6dc28b, #4dabf7, #c77dff, #ff6b6b, #6dc28b);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
    font-weight: var(--fw-bold);
    animation: legend-shimmer 5s linear infinite;
}

.cosmetic-title-shark::after {
    content: 'SHARK';
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 3px;
    background: #1f3147;
    color: #9bd0ff;
    border: 1px solid #4dabf7;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-grinder::after {
    content: 'GRINDER';
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 3px;
    background: #2a1f0f;
    color: #ffd27a;
    border: 1px solid #cd7f32;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-whale::after {
    content: 'WHALE';
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 3px;
    background: #0b2338;
    color: #b9f2ff;
    border: 1px solid #2c6aa3;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    letter-spacing: var(--ls-default);
    vertical-align: 2px;
    text-shadow: 0 0 4px rgba(185,242,255,.6);
}

/* === Achievement-only titles (granted by server when criteria met) === */
.cosmetic-title-degen::after {
    content: 'DEGEN';
    display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 3px;
    background: #2a0f1f; color: #ff6b9d; border: 1px solid #ff4d87;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px; text-shadow: 0 0 4px rgba(255,77,135,.5);
}
.cosmetic-title-lucky::after {
    content: 'LUCKY';
    display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 3px;
    background: #0f2a1f; color: #6dc28b; border: 1px solid #4db890;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px; animation: title-lucky-glow 2.2s ease-in-out infinite;
}
@keyframes title-lucky-glow {
    0%,100% { box-shadow: 0 0 0 0 rgba(77,184,144,0); }
    50%     { box-shadow: 0 0 8px 2px rgba(77,184,144,.45); }
}
.cosmetic-title-streak::after {
    content: 'STREAK';
    display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 3px;
    background: #2a1a0f; color: #ffaa66; border: 1px solid #ff8c3b;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px; text-shadow: 0 0 6px rgba(255,140,59,.6);
}
.cosmetic-title-jackpot::after {
    content: 'JACKPOT';
    display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 3px;
    background: linear-gradient(135deg, #ff8c3b, #ffd93d);
    color: #1a1a1a; border: 1px solid #ffd93d;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default);
    vertical-align: 2px; box-shadow: 0 0 10px rgba(255,217,61,.6);
    animation: title-jackpot-shine 2.5s ease-in-out infinite;
}
@keyframes title-jackpot-shine {
    0%,100% { filter: brightness(1); }
    50%     { filter: brightness(1.35); }
}
.cosmetic-title-collector::after {
    content: 'COLLECTOR';
    display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 3px;
    background: #1a1438; color: #c77dff; border: 1px solid #9c5aff;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-og::after {
    content: 'OG';
    display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 3px;
    background: linear-gradient(90deg, #6dc28b, #4dabf7, #c77dff);
    background-size: 200% auto;
    color: var(--bg); border: 1px solid transparent;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default);
    vertical-align: 2px; animation: title-og-shimmer 5s linear infinite;
}
@keyframes title-og-shimmer { to { background-position: 200% center; } }

/* === sound preview button (shop) === */
.cosmetic-sound-preview-btn {
    background: var(--bg-card);
    border: 1px solid var(--border);
    color: var(--text);
    padding: 6px 12px;
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    cursor: pointer;
    transition: border-color .12s, color .12s;
}
.cosmetic-sound-preview-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}

/* === Tier II/III + new achievement titles ===
 * Each tier escalates: brighter color / stronger glow / legendary gradient. */

/* Degen II (epic) — deeper pink with glow */
.cosmetic-title-degen-2 { color: #ff4d87; font-weight: var(--fw-bold); text-shadow: 0 0 6px rgba(255,77,135,.55); }
.cosmetic-title-degen-2::after {
    content: 'DEGEN II'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: #3a0f24; color: #ff9bc4; border: 1px solid #ff4d87;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
/* Degen III (legendary) — hot pink -> red gradient */
.cosmetic-title-degen-3 {
    background: linear-gradient(90deg, #ff2a6d, #ff6b9d, #ff9d5a);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
    font-weight: var(--fw-bold); animation: legend-shimmer 5s linear infinite;
}
.cosmetic-title-degen-3::after {
    content: 'DEGEN III'; display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 3px; background: linear-gradient(90deg, #ff2a6d, #ff9d5a);
    color: #1a1a1a; border: 1px solid #ff6b9d; font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default); vertical-align: 2px;
    box-shadow: 0 0 10px rgba(255,107,157,.6);
}

/* Lucky II / III — deeper greens, legendary gradient */
.cosmetic-title-lucky-2 { color: #4db890; font-weight: var(--fw-bold); text-shadow: 0 0 6px rgba(77,184,144,.6); }
.cosmetic-title-lucky-2::after {
    content: 'LUCKY II'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: #083b2b; color: #9fe6c0; border: 1px solid #4db890;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-lucky-3 {
    background: linear-gradient(90deg, #2be27a, #6dc28b, #b9f2ff);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
    font-weight: var(--fw-bold); animation: legend-shimmer 5s linear infinite;
}
.cosmetic-title-lucky-3::after {
    content: 'LUCKY III'; display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 3px; background: linear-gradient(90deg, #2be27a, #b9f2ff);
    color: #1a1a1a; border: 1px solid #6dc28b; font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default); vertical-align: 2px;
    box-shadow: 0 0 10px rgba(109,194,139,.6);
}

/* Streak II / III */
.cosmetic-title-streak-2 { color: #ff8c3b; font-weight: var(--fw-bold); text-shadow: 0 0 8px rgba(255,140,59,.7); }
.cosmetic-title-streak-2::after {
    content: 'STREAK II'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: #3b1f08; color: #ffc88a; border: 1px solid #ff8c3b;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-streak-3 {
    background: linear-gradient(90deg, #ff5500, #ff8c3b, #ffd93d);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
    font-weight: var(--fw-bold); animation: legend-shimmer 5s linear infinite;
}
.cosmetic-title-streak-3::after {
    content: 'STREAK III'; display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 3px; background: linear-gradient(90deg, #ff5500, #ffd93d);
    color: #1a1a1a; border: 1px solid #ff8c3b; font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default); vertical-align: 2px;
    box-shadow: 0 0 12px rgba(255,140,59,.65);
}

/* Jackpot II / III (jackpot base already gold→orange gradient) */
.cosmetic-title-jackpot-2 {
    background: linear-gradient(90deg, #ff8c3b, #ffd93d, #fff4b3);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
    font-weight: var(--fw-xbold); animation: legend-shimmer 4s linear infinite;
}
.cosmetic-title-jackpot-2::after {
    content: 'JACKPOT II'; display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 3px; background: linear-gradient(135deg, #ff8c3b, #ffd93d);
    color: #1a1a1a; border: 1px solid #ffd93d; font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default); vertical-align: 2px;
    box-shadow: 0 0 12px rgba(255,217,61,.7);
}
.cosmetic-title-jackpot-3 {
    background: linear-gradient(90deg, #ffd93d, #fff4b3, #ffffff, #fff4b3, #ffd93d);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
    font-weight: var(--fw-xbold); animation: legend-shimmer 3s linear infinite;
}
.cosmetic-title-jackpot-3::after {
    content: 'JACKPOT III'; display: inline-block; margin-left: 6px; padding: 1px 8px;
    border-radius: 3px; background: linear-gradient(135deg, #ffd93d, #ffffff, #ffd93d);
    color: #1a1a1a; border: 1px solid #fff4b3; font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default); vertical-align: 2px;
    box-shadow: 0 0 16px rgba(255,217,61,.9);
}

/* Collector II / III */
.cosmetic-title-collector-2 { color: #9c5aff; font-weight: var(--fw-bold); text-shadow: 0 0 6px rgba(156,90,255,.6); }
.cosmetic-title-collector-2::after {
    content: 'COLLECTOR II'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: #1d0f38; color: #d2a3ff; border: 1px solid #9c5aff;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-collector-3 {
    background: linear-gradient(90deg, #c77dff, #9c5aff, #4dabf7);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
    font-weight: var(--fw-bold); animation: legend-shimmer 5s linear infinite;
}
.cosmetic-title-collector-3::after {
    content: 'COLLECTOR III'; display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 3px; background: linear-gradient(90deg, #c77dff, #4dabf7);
    color: #1a1a1a; border: 1px solid #9c5aff; font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default); vertical-align: 2px;
    box-shadow: 0 0 10px rgba(156,90,255,.6);
}

/* Account age tiers */
.cosmetic-title-rookie  { color: var(--text); font-weight: var(--fw-medium); }
.cosmetic-title-rookie::after {
    content: 'ROOKIE'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: var(--bg-input); color: var(--text-muted);
    border: 1px solid var(--border); font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default); vertical-align: 2px;
}
.cosmetic-title-regular { color: var(--accent); font-weight: var(--fw-semi); }
.cosmetic-title-regular::after {
    content: 'REGULAR'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: rgba(255,170,102,.12); color: var(--accent);
    border: 1px solid var(--accent); font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default); vertical-align: 2px;
}
.cosmetic-title-senior  { color: #b9f2ff; font-weight: var(--fw-bold); text-shadow: 0 0 5px rgba(185,242,255,.45); }
.cosmetic-title-senior::after {
    content: 'SENIOR'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: #0b2338; color: #b9f2ff; border: 1px solid #2c6aa3;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
/* title_og already has css above; just also give it a badge marker */
.cosmetic-title-og::after {
    content: 'OG'; display: inline-block; margin-left: 6px; padding: 1px 8px;
    border-radius: 3px;
    background: linear-gradient(90deg, #6dc28b, #4dabf7, #c77dff);
    background-size: 200% auto;
    color: var(--bg); border: 1px solid transparent;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
    animation: legend-shimmer 5s linear infinite;
    box-shadow: 0 0 10px rgba(109,194,139,.4);
}

/* Wagered-lifetime tiers */
.cosmetic-title-big-spender { color: #ffd27a; font-weight: var(--fw-semi); }
.cosmetic-title-big-spender::after {
    content: 'BIG SPENDER'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: #2a1f0f; color: #ffd27a; border: 1px solid #cd7f32;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-high-roller { color: #ffd93d; font-weight: var(--fw-bold); text-shadow: 0 0 6px rgba(255,217,61,.55); }
.cosmetic-title-high-roller::after {
    content: 'HIGH ROLLER'; display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px; background: #2e2310; color: #ffeb6b; border: 1px solid #ffd93d;
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}
.cosmetic-title-chip-leader {
    background: linear-gradient(90deg, #ffd93d, #fff4b3, #e9e9e9, #c0c0c0, #ffd93d);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
    font-weight: var(--fw-xbold); animation: legend-shimmer 4s linear infinite;
}
.cosmetic-title-chip-leader::after {
    content: 'CHIP LEADER'; display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 3px; background: linear-gradient(135deg, #ffd93d, #c0c0c0);
    color: #1a1a1a; border: 1px solid #ffd93d; font-family: var(--font-mono);
    font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default); vertical-align: 2px;
    box-shadow: 0 0 12px rgba(255,217,61,.65);
}

/* === Shop / inventory section dividers ===
 * The grid container toggles between .cosmetic-grid (flat) and
 * .cosmetic-sections (sectioned with dividers between equipped/owned/buyable). */
.cosmetic-sections {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.cosmetic-section-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0 4px;
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    text-transform: uppercase;
    letter-spacing: var(--ls-tracked);
    color: var(--text-dim);
}
.cosmetic-section-divider::before,
.cosmetic-section-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--border);
}
.cosmetic-section-divider-label { font-weight: var(--fw-bold); color: var(--text); }
.cosmetic-section-divider-count {
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    background: var(--bg-input);
    color: var(--text-dim);
    font-size: var(--fs-xs);
}

/* ═════════════════════════════════════════════════════════════════════
 * Hello Kitty cosmetic set (migration 059).
 * Local palette — only used by .cosmetic-*-kitty-* rules below.
 * ═════════════════════════════════════════════════════════════════════ */
:root {
    --hk-pink:    #ffb3d1;
    --hk-hot:     #ff7eb3;
    --hk-magenta: #ff4d8a;
    --hk-pastel:  #ffd6e7;
    --hk-deep:    #c8266a;
    --hk-cream:   #fff5fa;
}

/* === Frame: Pink Bow === */
.cosmetic-frame-kitty-bow {
    outline: 2px solid var(--hk-pink);
    outline-offset: 2px;
    border-radius: 50%;
    position: relative;
}
.cosmetic-frame-kitty-bow::after {
    content: '🎀';
    /* Fully inside the avatar bbox so NO parent with overflow:hidden can
       clip it (.com-card, .com-pulse-online, .lb-entry, etc.). Bow sits in
       the top-right quadrant overlapping the circle's edge — visually like
       a sticker on the avatar. */
    position: absolute;
    top: 0; right: 0;
    font-size: var(--fs-md); line-height: 1;
    filter: drop-shadow(0 0 4px rgba(255,126,179,.7));
    pointer-events: none;
}

/* === Animated Frame: Heart Cycle === */
.cosmetic-frame-kitty-hearts {
    outline: 2px solid var(--hk-hot);
    outline-offset: 2px;
    border-radius: 50%;
    animation: kitty-heart-cycle 3s linear infinite;
    position: relative;
}
@keyframes kitty-heart-cycle {
    0%,100% { outline-color: var(--hk-pink);    box-shadow: 0 0 10px 2px rgba(255,179,209,.65); }
    33%     { outline-color: var(--hk-hot);     box-shadow: 0 0 12px 2px rgba(255,126,179,.7); }
    66%     { outline-color: var(--hk-magenta); box-shadow: 0 0 14px 2px rgba(255,77,138,.7); }
}
.cosmetic-frame-kitty-hearts::after {
    content: '♥';
    /* Fully inside the avatar bbox — no overflow risk in any parent. */
    position: absolute; top: 0; left: 50%;
    transform: translateX(-50%);
    color: var(--hk-hot);
    font-size: var(--fs-md); line-height: 1;
    filter: drop-shadow(0 0 6px var(--hk-hot));
    animation: kitty-heart-bob 1.5s ease-in-out infinite;
    pointer-events: none;
}
@keyframes kitty-heart-bob {
    0%,100% { transform: translateX(-50%) scale(1);   opacity: 1; }
    50%     { transform: translateX(-50%) scale(1.2); opacity: .9; }
}

/* === Avatar Particle: Floating Hearts === */
.cosmetic-avatar-wrap.cosmetic-particle-kitty-hearts::before,
.cosmetic-avatar-wrap.cosmetic-particle-kitty-hearts::after {
    content: '♥';
    position: absolute;
    /* reset the global `inset: -10px` from .cosmetic-avatar-wrap::before/::after;
       otherwise the element stretches to fit all 4 sides instead of point-positioning */
    inset: auto;
    border-radius: 0;
    font-size: var(--fs-lg); line-height: 1;
    color: var(--hk-hot);
    filter: drop-shadow(0 0 4px var(--hk-pink));
    pointer-events: none;
    animation: kitty-heart-float 2.6s ease-in-out infinite;
    z-index: 2;
}
.cosmetic-avatar-wrap.cosmetic-particle-kitty-hearts::before {
    left: -6px; bottom: -2px;
    animation-delay: 0s;
}
.cosmetic-avatar-wrap.cosmetic-particle-kitty-hearts::after {
    right: -6px; bottom: -2px;
    color: var(--hk-pink);
    animation-delay: 1.3s;
}
@keyframes kitty-heart-float {
    0%   { transform: translateY(0)     scale(.8); opacity: 0; }
    20%  { opacity: 1; }
    80%  { opacity: 1; }
    100% { transform: translateY(-50px) scale(1.1); opacity: 0; }
}

/* === Avatar Particle: Bow Orbit === */
.cosmetic-avatar-wrap.cosmetic-particle-kitty-bows::after {
    content: '🎀';
    position: absolute;
    /* same global-inset reset as kitty-hearts */
    inset: auto;
    border-radius: 0;
    top: 50%; left: 50%;
    width: 24px; height: 24px;
    margin: -12px 0 0 -12px;
    font-size: var(--fs-h2); line-height: 24px; text-align: center;
    animation: kitty-bow-orbit 4s linear infinite;
    pointer-events: none;
    filter: drop-shadow(0 0 5px rgba(255,126,179,.7));
    z-index: 2;
}
@keyframes kitty-bow-orbit {
    from { transform: rotate(0deg)   translateX(40px) rotate(0deg); }
    to   { transform: rotate(360deg) translateX(40px) rotate(-360deg); }
}

/* === Title: Kitty === */
.cosmetic-title-kitty { color: var(--hk-hot); font-weight: var(--fw-semi); }
.cosmetic-title-kitty::after {
    content: 'KITTY';
    display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px;
    background: #2a0f1f; color: var(--hk-pink); border: 1px solid var(--hk-hot);
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}

/* === Title: Sweetie === */
.cosmetic-title-sweetie { color: var(--hk-pastel); font-weight: var(--fw-medium); }
.cosmetic-title-sweetie::after {
    content: 'SWEETIE';
    display: inline-block; margin-left: 6px; padding: 1px 6px;
    border-radius: 3px;
    background: var(--hk-cream); color: var(--hk-deep); border: 1px solid var(--hk-pink);
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
}

/* === Title: Princess === */
.cosmetic-title-princess {
    background: linear-gradient(90deg, var(--hk-magenta), var(--hk-pink), #fff);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
    font-weight: var(--fw-bold);
    animation: kitty-princess-shimmer 4s linear infinite;
}
@keyframes kitty-princess-shimmer { to { background-position: 200% center; } }
.cosmetic-title-princess::after {
    content: 'PRINCESS';
    display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 3px;
    background: linear-gradient(135deg, var(--hk-magenta), var(--hk-pink));
    /* reset gradient text clipping inherited from parent — without this the badge
       background is clipped to the text shape and renders empty */
    -webkit-background-clip: border-box;
            background-clip: border-box;
    -webkit-text-fill-color: #1a1a1a;
    color: #1a1a1a; border: 1px solid var(--hk-pink);
    font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: var(--fw-xbold); letter-spacing: var(--ls-default);
    vertical-align: 2px;
    box-shadow: 0 0 10px rgba(255,126,179,.55);
}

/* === Animated Title: Kitty Bounce === */
.cosmetic-username-kitty-bounce {
    display: inline-block;
    color: var(--hk-hot);
    font-weight: var(--fw-bold);
    animation: kitty-bounce 1.4s ease-in-out infinite;
}
@keyframes kitty-bounce {
    0%,100% { transform: translateY(0); }
    50%     { transform: translateY(-4px); }
}

/* === Animated Title: Pastel Rainbow === */
.cosmetic-username-kitty-pastel {
    background: linear-gradient(90deg, #ffb3d1, #ffd1ff, #d1c4ff, #b3d1ff, #c4f0e5, #ffe0b3, #ffb3d1);
    background-size: 200% auto;
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
    font-weight: var(--fw-bold);
    animation: kitty-pastel-shimmer 5s linear infinite;
}
@keyframes kitty-pastel-shimmer { to { background-position: 200% center; } }

/* === Effect: Heartbeat === */
.cosmetic-effect-kitty-heartbeat {
    color: var(--hk-hot);
    font-weight: var(--fw-semi);
    text-shadow: 0 0 6px var(--hk-pink);
    animation: kitty-heartbeat 1.1s ease-in-out infinite;
}
@keyframes kitty-heartbeat {
    0%,100% { transform: scale(1);    text-shadow: 0 0 6px var(--hk-pink); }
    14%     { transform: scale(1.06); text-shadow: 0 0 12px var(--hk-hot); }
    28%     { transform: scale(1);    text-shadow: 0 0 6px var(--hk-pink); }
    42%     { transform: scale(1.04); text-shadow: 0 0 10px var(--hk-hot); }
}

/* === Effect: Twinkle === */
.cosmetic-effect-kitty-twinkle {
    color: var(--hk-hot);
    font-weight: var(--fw-semi);
    position: relative;
    text-shadow: 0 0 6px var(--hk-pink);
    padding: 0 14px; /* so the stars don't overlap adjacent text */
    /* The host elements (.com-card-nick, .com-row-nick, .lb-name etc.)
       carry overflow:hidden + text-overflow:ellipsis + flex:1 to keep
       long names from breaking the row layout. Twinkle's ::before/::after
       stars need overflow:visible + content-sized width — !important
       because community.css/leaderboard.css load AFTER cosmetics.css and
       would otherwise win on equal specificity. */
    display: inline-block !important;
    flex: 0 0 auto !important;
    overflow: visible !important;
    max-width: max-content;
}
.cosmetic-effect-kitty-twinkle::before,
.cosmetic-effect-kitty-twinkle::after {
    position: absolute;
    color: var(--hk-pastel);
    filter: drop-shadow(0 0 4px var(--hk-hot));
    animation: kitty-twinkle 1.6s ease-in-out infinite;
    pointer-events: none;
}
.cosmetic-effect-kitty-twinkle::before {
    content: '✦';
    top: -4px; left: 0;
    font-size: var(--fs-sm);
    animation-delay: 0s;
}
.cosmetic-effect-kitty-twinkle::after {
    content: '✧';
    bottom: -2px; right: 0;
    font-size: var(--fs-xs);
    animation-delay: 0.8s;
}
@keyframes kitty-twinkle {
    0%, 100% { opacity: 0;  transform: scale(.5) rotate(0deg); }
    30%      { opacity: 1;  transform: scale(1.1) rotate(40deg); }
    60%      { opacity: .5; transform: scale(.9) rotate(-20deg); }
}

/* === Background: Bow Pattern === */
.cosmetic-bg-kitty-bows {
    background-color: #1a0f15;
    background-image:
        radial-gradient(circle at 20% 30%, var(--hk-pink) 0 3px, transparent 4px),
        radial-gradient(circle at 60% 70%, var(--hk-hot)  0 2.5px, transparent 4px),
        radial-gradient(circle at 80% 20%, var(--hk-pastel) 0 2px, transparent 4px);
    background-size: 80px 80px, 100px 100px, 60px 60px;
}

/* === Background: Pink Sky === */
.cosmetic-bg-kitty-sky {
    background:
        radial-gradient(ellipse at 30% 30%, rgba(255,214,231,.25), transparent 60%),
        radial-gradient(ellipse at 70% 70%, rgba(255,126,179,.25), transparent 60%),
        linear-gradient(180deg, #2a0f1f 0%, #1a0a17 100%);
    position: relative; overflow: hidden;
}
.cosmetic-bg-kitty-sky::after {
    content: '';
    position: absolute; inset: 0;
    background-image:
        radial-gradient(2px 2px at 18% 65%, var(--hk-hot), transparent 55%),
        radial-gradient(1.5px 1.5px at 55% 30%, var(--hk-pink), transparent 55%),
        radial-gradient(2px 2px at 80% 75%, var(--hk-pastel), transparent 55%);
    animation: kitty-sky-drift 18s linear infinite;
    pointer-events: none;
}
@keyframes kitty-sky-drift {
    from { transform: translate(0,0); }
    to   { transform: translate(-30px, -16px); }
}

/* === Banner Overlay: Falling Hearts ===
   Hearts are spawned by utils.apply_cosmetics when this class is created
   on a .banner-overlay child. Each .kitty-rain-heart child sets its own
   inline --x, --dur, --delay, --drift, --rot, --size, --c CSS variables
   and animates on a single shared keyframe — pure CSS, no JS runtime. */
.cosmetic-overlay-kitty-hearts .kitty-rain-heart {
    position: absolute;
    top: 0;
    left: var(--x);
    font-size: var(--size, 18px);
    color: var(--c, #ff7eb3);
    line-height: 1;
    pointer-events: none;
    will-change: transform, opacity;
    text-shadow: 0 0 6px currentColor;
    animation: kitty-rain-fall var(--dur, 3s) ease-in var(--delay, 0s) infinite;
}
@keyframes kitty-rain-fall {
    0%   { transform: translate(0, -25px) rotate(0deg); opacity: 0; }
    10%  { opacity: 1; }
    90%  { opacity: 1; }
    100% { transform: translate(var(--drift, 0px), calc(100% + 140px)) rotate(var(--rot, 0deg)); opacity: 0; }
}

/* === Banner Overlay: Aurora Pink (pure CSS) === */
.cosmetic-overlay-kitty-aurora {
    background:
        radial-gradient(ellipse 40% 60% at 20% 30%, rgba(255,126,179,.55), transparent 60%),
        radial-gradient(ellipse 50% 50% at 70% 70%, rgba(199,125,255,.45), transparent 60%),
        radial-gradient(ellipse 35% 45% at 50% 50%, rgba(255,214,231,.35), transparent 65%);
    background-size: 200% 200%, 180% 180%, 220% 220%;
    animation: kitty-aurora-drift 14s ease-in-out infinite alternate;
    mix-blend-mode: screen;
    opacity: .9;
}
@keyframes kitty-aurora-drift {
    0%   { background-position:   0%   0%, 100% 100%,  50%  50%; }
    50%  { background-position:  30%  70%,  60%  30%,  80%  20%; }
    100% { background-position: 100% 100%,   0%   0%,  20%  80%; }
}

/* === Coin Icon: Pink Bow ===
   Replaces the default coin svg with a 🎀 glyph via ::before.
   Match how cosmetic-coin-* in earlier migrations hide the original icon. */
.header-coin-pill.cosmetic-coin-kitty-bow .coin-icon { display: none; }
.header-coin-pill.cosmetic-coin-kitty-bow::before {
    content: '🎀';
    font-size: var(--fs-md); line-height: 1;
    margin-right: 2px;
    filter: drop-shadow(0 0 3px var(--hk-hot));
}

/* ═════════════════════════════════════════════════════════════════════
 * Badge text fix — pseudo ::after badges inherit -webkit-text-fill-color
 * from their parent title/effect classes. When the parent uses a gradient
 * text fill (transparent), the badge text goes invisible. Reset to the
 * badge's own color for every cosmetic title pseudo-badge.
 * ═════════════════════════════════════════════════════════════════════ */
[class*="cosmetic-title-"]::after,
[class*="cosmetic-username-"]::after,
[class*="cosmetic-effect-"]::after {
    -webkit-text-fill-color: currentColor;
}

/* Preview text inside shop + inventory cards must render as solid color.
 * Otherwise titles like the ones using `-webkit-text-fill-color: transparent`
 * end up invisible in the preview (only the ::after badge is visible). */
.cosmetic-card-preview span,
.cosmetic-card-preview > .cosmetic-title-preview {
    -webkit-text-fill-color: currentColor;
}

/* Background previews need the star/nebula/void pattern sized to the
 * compact preview box, otherwise the base pattern is invisible at 60px. */
.cosmetic-card-preview .cosmetic-bg-stars {
    background-size: 40px 40px, 30px 30px, 50px 50px, 25px 25px, 45px 45px, auto;
}
.cosmetic-card-preview .cosmetic-bg-nebula { background-size: cover; }
.cosmetic-card-preview .cosmetic-bg-void::after {
    background-size: cover;
}

/* Sell button in inventory — subtle secondary action under the equip button. */
.cosmetic-card-sell {
    background: transparent;
    color: var(--text-dim);
    border: 1px solid var(--border);
    padding: 6px 10px;
    border-radius: var(--radius);
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    font-weight: var(--fw-semi);
    text-transform: uppercase;
    letter-spacing: var(--ls-default);
    cursor: pointer;
    transition: border-color .12s, color .12s, background .12s;
}
.cosmetic-card-sell:hover {
    border-color: #d97a7a;
    color: #d97a7a;
    background: rgba(217,122,122,0.08);
}
.cosmetic-card-sell:disabled {
    opacity: 0.5;
    cursor: wait;
}

/* ═════════════════════════════════════════════════════════════════════
 * Unified shop+inventory (2026-05-14 redesign)
 * docs/superpowers/specs/2026-05-14-cosmetics-unified-redesign.md
 * ═════════════════════════════════════════════════════════════════════ */

/* Filter-pill row (mode): all / owned / available / locked.
   Mirrors .cosmetic-category-pills shape but lives ABOVE them so the user
   sees mode-first, then category-within-mode. */
.cosmetic-filter-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 8px;
}
.cosmetic-filter-pill {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    padding: 7px 14px;
    font-family: var(--font-mono);
    font-size: var(--fs-sm);
    font-weight: var(--fw-semi);
    color: var(--text-muted);
    cursor: pointer;
    text-transform: uppercase;
    letter-spacing: var(--ls-default);
    transition: color .12s, border-color .12s, background .12s, transform .1s;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.cosmetic-filter-pill:hover {
    color: var(--text);
    border-color: var(--accent);
}
.cosmetic-filter-pill.active {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-soft);
}

/* Card state badge — sits at the top-right of every card, replaces the old
   bottom-of-card "owned" / price text. .cosmetic-card-badge (rarity star)
   stays where it was; the state pill is offset above it. */
.cosmetic-card-state {
    position: absolute;
    top: 8px;
    left: 8px;
    font-family: var(--font-mono);
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: var(--ls-none).6px;
    padding: 3px 8px;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-muted);
}
.cosmetic-card-state.is-equipped {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-soft);
}
.cosmetic-card-state.is-owned {
    color: var(--success);
    border-color: var(--success);
    background: var(--success-muted);
}
.cosmetic-card-state.is-price {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-soft);
}
.cosmetic-card-state.is-locked {
    color: #c77dff;
    border-color: rgba(199, 125, 255, 0.55);
    background: rgba(199, 125, 255, 0.12);
}

/* Actions wrapper — primary + optional secondary (sell) stacked at bottom. */
.cosmetic-card-actions {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: auto;
}

/* Personalised preview helpers — avatar inside frame/particle previews. */
.cosmetic-card-avatar-img {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}
.cosmetic-card-avatar-letter {
    font-family: var(--font-body);
    font-size: var(--fs-h2);
    font-weight: var(--fw-bold);
    line-height: 1;
    color: var(--text);
}
