/* The map and everything standing on it: layers, biome looks, characters, pickups, effects. */

/* ---------- layers ---------- */
#world { position: fixed; inset: 0; overflow: hidden; }
#world canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
#bg { transition: filter 2s; image-rendering: pixelated; }
#sky, #night, #cyber, #dream, #nm, #eqfx { pointer-events: none; }
#sky, #night, #cyber { position: absolute; inset: 0; transition: opacity 2s, background 2s; }
#sky { opacity: .0; mix-blend-mode: multiply; }
#night { background: radial-gradient(ellipse at 50% 40%, rgba(30,40,120,.35), rgba(5,8,40,.78)); opacity: 0; mix-blend-mode: multiply; }
/* the effects canvas must never catch clicks meant for merchants and pickups */
#fx { pointer-events: none; }

/* the map is bigger than the screen; the camera follows the avatar */
#map { position: absolute; left: 0; top: 0; width: calc(100% * var(--z, 1.8)); height: calc(100% * var(--z, 1.8)); transform-origin: 0 0; will-change: transform; }
body.in-sanctuary #map, body.in-lobby #map, body.in-arena #map { width: 100%; height: 100%; transform: none !important; }

/* ---------- biome looks ---------- */
#trees { pointer-events: none; transform-origin: 50% 100%; }
body.biome-Windy #trees { animation: sway 3.4s ease-in-out infinite; }
@keyframes sway { 0%, 100% { transform: skewX(-1.1deg); } 50% { transform: skewX(1.3deg); } }
#world.swap #bg, #world.swap #trees { animation: biomeswap .9s ease-out; }
@keyframes biomeswap { from { opacity: .15; } to { opacity: 1; } }
body.biome-Null #bg { filter: grayscale(1) contrast(1.4) brightness(.55); }
body.biome-Singularity #bg { filter: brightness(.35) hue-rotate(250deg) saturate(1.4); }
body.biome-Heaven #bg { filter: brightness(1.2) saturate(.9) sepia(.25); }
body.area-limbo #bg { filter: grayscale(1) brightness(.12) contrast(1.3); }
body.area-limbo #sky { opacity: .95 !important; }
@keyframes glitch { 0%{transform:translate(0,0)} 20%{transform:translate(-5px,2px) skewX(1.5deg)} 40%{transform:translate(4px,-3px)} 60%{transform:translate(-2px,0) skewX(-2deg)} 80%{transform:translate(3px,2px)} 100%{transform:translate(0,0)} }
body.biome-Glitched #trees { animation: glitch 1.7s steps(2) infinite reverse; }
body.biome-Glitched #bg { animation: glitch 1.1s steps(2) infinite; }
/* Cyberspace: blue grid */
#cyber { opacity: 0; mix-blend-mode: screen; background: linear-gradient(rgba(41,182,246,.22) 1px, transparent 1px) 0 0 / 46px 46px, linear-gradient(90deg, rgba(41,182,246,.22) 1px, transparent 1px) 0 0 / 46px 46px, radial-gradient(ellipse at 50% 100%, rgba(41,182,246,.38), transparent 70%); }
body.biome-Cyberspace #cyber { opacity: 1; animation: cybergrid 6s linear infinite; }
@keyframes cybergrid { to { background-position: 0 46px, 46px 0, 0 0; } }
/* Dreamspace: floating pink furniture */
#dream { position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity 2s; overflow: hidden; }
body.biome-Dreamspace #dream { opacity: .9; }
#dream .dz { position: absolute; filter: drop-shadow(0 0 14px #ff4fb8) drop-shadow(0 0 30px rgba(255,80,190,.6)); animation: dfloat 11s ease-in-out infinite; }
#dream .dz svg { width: 100%; height: auto; display: block; }
@keyframes dfloat { 0%, 100% { transform: translateY(0) rotate(-4deg); } 50% { transform: translateY(-26px) rotate(5deg); } }

body.area-limbo .tr-board, body.area-limbo .sidebar { filter: grayscale(.8); }

/* ---------- people and places on the map ---------- */
.nametag { position: absolute; transform: translate(-50%, -100%); font: 600 12px var(--head); white-space: nowrap; text-shadow: 0 1px 2px #000, 0 0 3px #000; pointer-events: none; }
.spot { position: absolute; z-index: 3; width: 56px; height: 56px; padding: 0; background: none; border: 0; transform: translate(-50%, -50%); transition: transform .15s; }
.spot:hover { transform: translate(-50%, -54%) scale(1.06); }
.spot .blk { position: absolute; inset: 8px; display: grid; place-items: center; font: 700 22px var(--head); color: #fff; background: var(--c); border: 2px solid var(--edge); border-radius: 4px; box-shadow: 0 4px 0 var(--edge), 0 9px 6px rgba(0, 0, 0, .25); text-shadow: 0 2px 0 rgba(0, 0, 0, .35); }
.spot .nametag { left: 50%; top: 4px; }
.spot .badge { position: absolute; top: 3px; right: 3px; z-index: 2; display: none; place-items: center; width: 17px; height: 17px; font: 700 12px var(--head); color: var(--accent-ink); background: var(--accent); border: 2px solid var(--edge); border-radius: 50%; animation: bob 1s ease-in-out infinite; }
.spot.has-badge .badge { display: grid; }
@keyframes bob { 50% { transform: translateY(-4px); } }

.pickup { position: absolute; z-index: 4; transform: translate(-50%, -50%); width: 40px; height: 40px; padding: 0; background: none; border: 0; animation: float 2s ease-in-out infinite; }
.pickup i { position: absolute; inset: 6px; display: grid; place-items: center; font: 700 14px var(--head); font-style: normal; color: #14181c; background: var(--c); border: 3px solid #fff; border-radius: 50%; box-shadow: 0 3px 0 rgba(0, 0, 0, .4), 0 0 12px var(--c); }
@keyframes float { 50% { transform: translate(-50%, -62%); } }

/* travelling merchants */
#merchants { position: absolute; inset: 0; pointer-events: none; }
#merchants .spot { pointer-events: auto; }
.spot.merchant .beam { position: absolute; left: 50%; bottom: 50%; z-index: -1; width: 22px; height: 70vh; background: linear-gradient(to top, var(--c), transparent); border-radius: 11px 11px 0 0; opacity: .5; transform: translateX(-50%); pointer-events: none; }
.spot.merchant .blk { border-radius: 50%; }

/* ---------- the player and other players ---------- */
#avatar { position: absolute; left: 50%; top: 52%; z-index: 2; width: 22px; height: 30px; transform: translate(-50%, -50%); pointer-events: none; will-change: left, top; }
#peers { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.peer { position: absolute; width: 22px; height: 30px; transform: translate(-50%, -50%); transition: left 2s linear, top 2s linear; }
#avatar::before, .peer::before { content: ""; position: absolute; left: -5px; right: -5px; bottom: -3px; height: 8px; background: rgba(0, 0, 0, .3); border-radius: 50%; }

/* A small character: head, torso, two arms, two legs, drawn from the front, the back, the side and the two diagonals.
   Colors come from the player's look settings. Only the right-facing poses are written out; the left ones are mirrored. */
#avatar, .peer, .look-prev { --skin: #e6c9a0; --hair: #4a3426; --shirt: #2e6bd0; --pants: #2a3a55; }
.peer { --shirt: #c0742b; --pants: #3a2a2a; --hair: #2b2b2b; }
.fig { --shoe: #151a22; --ol: #14100c; position: absolute; inset: 0; display: block; transform: scale(1.5); transform-origin: 50% 100%; filter: drop-shadow(0 0 calc(var(--gs, 0px) / 2) var(--gc, transparent)); transition: filter .6s; }
.f-l .fig, .f-dl .fig, .f-ul .fig { transform: scale(-1.5, 1.5); }
.fig > * { position: absolute; display: block; box-shadow: 0 0 0 1px var(--ol); }
.fig .head { z-index: 3; left: 6px; top: 0; width: 10px; height: 10px; border-radius: 4px 4px 3px 3px; background: linear-gradient(var(--hair) 0 40%, var(--skin) 40%); }
.fig .head::before { content: ""; position: absolute; left: 2px; top: 5px; width: 2px; height: 2px; background: var(--ol); box-shadow: 4px 0 var(--ol); }
.fig .torso { z-index: 2; left: 5px; top: 10px; width: 12px; height: 11px; border-radius: 2px; background: linear-gradient(90deg, rgba(255, 255, 255, .14) 0 22%, transparent 22% 78%, rgba(0, 0, 0, .16) 78%), var(--shirt); }
.fig .arm { z-index: 1; top: 10px; width: 4px; height: 11px; border-radius: 2px; background: linear-gradient(var(--shirt) 0 62%, var(--skin) 62%); transform-origin: 50% 1px; }
.fig .arm.l { left: 0; }
.fig .arm.r { z-index: 4; left: 18px; }
.fig .leg { z-index: 1; top: 20px; width: 5px; height: 10px; border-radius: 1px 1px 2px 2px; background: linear-gradient(var(--pants) 0 72%, var(--shoe) 72%); transform-origin: 50% 0; }
.fig .leg.l { left: 6px; }
.fig .leg.r { left: 11px; }

/* from behind: all hair, no face */
:is(.f-u, .f-ul, .f-ur) .fig .head { background: var(--hair); }
:is(.f-u, .f-ul, .f-ur) .fig .head::before { display: none; }

/* sideways: a profile head with one eye, a slim torso, arms and legs that swing front to back */
:is(.f-l, .f-r) .fig .head { background: linear-gradient(var(--hair) 0 36%, transparent 36%), linear-gradient(90deg, var(--hair) 0 38%, var(--skin) 38%); }
:is(.f-l, .f-r) .fig .head::before { left: 6px; box-shadow: none; }
:is(.f-l, .f-r) .fig .torso { left: 7px; width: 8px; }
:is(.f-l, .f-r) .fig .arm { left: 9px; }
:is(.f-l, .f-r) .fig .arm.l { filter: brightness(.78); }
:is(.f-l, .f-r) .fig .leg.l { left: 8px; filter: brightness(.82); }
:is(.f-l, .f-r) .fig .leg.r { left: 9px; }

/* diagonals: turned a quarter, so the body narrows and the face or hair shifts toward the way it is heading */
:is(.f-dl, .f-dr, .f-ul, .f-ur) .fig .head { left: 7px; }
:is(.f-dl, .f-dr) .fig .head::before { left: 4px; }
:is(.f-ul, .f-ur) .fig .head { background: linear-gradient(90deg, var(--hair) 0 78%, var(--skin) 78%); }
:is(.f-dl, .f-dr, .f-ul, .f-ur) .fig .torso { left: 6px; width: 10px; }
:is(.f-dl, .f-dr, .f-ul, .f-ur) .fig .arm.l { left: 2px; filter: brightness(.82); }
:is(.f-dl, .f-dr, .f-ul, .f-ur) .fig .arm.r { left: 16px; }
:is(.f-dl, .f-dr, .f-ul, .f-ur) .fig .leg.l { left: 7px; }
:is(.f-dl, .f-dr, .f-ul, .f-ur) .fig .leg.r { left: 11px; }

.peer .fig { filter: drop-shadow(0 0 5px var(--pc, #8bc34a)); opacity: .92; }

/* walking: legs lift in turn and arms swing the other way, the upper body bobs once per step.
   Facing sideways the limbs rotate from the hip and shoulder instead of lifting. */
.walking .fig .leg.l, .walking .fig .arm.r { animation: lift .5s ease-in-out infinite; }
.walking .fig .leg.r, .walking .fig .arm.l { animation: lift .5s ease-in-out infinite -.25s; }
.walking .fig .arm { animation-name: swing; }
.walking .fig .head, .walking .fig .torso { animation: bob-step .25s ease-in-out infinite; }
.walking:is(.f-l, .f-r) .fig :is(.leg.l, .arm.r) { animation: stride .55s ease-in-out infinite; }
.walking:is(.f-l, .f-r) .fig :is(.leg.r, .arm.l) { animation: stride .55s ease-in-out infinite -.275s; }
.walking:is(.f-dl, .f-dr, .f-ul, .f-ur) .fig :is(.leg.l, .arm.r) { animation: stride-small .5s ease-in-out infinite; }
.walking:is(.f-dl, .f-dr, .f-ul, .f-ur) .fig :is(.leg.r, .arm.l) { animation: stride-small .5s ease-in-out infinite -.25s; }
@keyframes lift { 50% { transform: translateY(-3px); } }
@keyframes swing { 0%, 100% { transform: rotate(20deg); } 50% { transform: rotate(-20deg); } }
@keyframes stride { 0%, 100% { transform: rotate(30deg); } 50% { transform: rotate(-30deg); } }
@keyframes stride-small { 0%, 100% { transform: rotate(15deg) translateY(0); } 25%, 75% { transform: rotate(0) translateY(-2px); } 50% { transform: rotate(-15deg) translateY(0); } }
@keyframes bob-step { 50% { transform: translateY(-1px); } }

/* name + equipped-aura labels above the avatar (same layout as peers) */
#avatar .pn { position: absolute; left: 50%; bottom: calc(100% + 19px); z-index: 9; font-size: 11px; white-space: nowrap; transform: translateX(-50%); text-shadow: 0 1px 2px #000, 0 0 6px rgba(0, 0, 0, .8); pointer-events: none; color: #e8eef4; }
#avatar .al { position: absolute; left: 50%; bottom: calc(100% + 35px); z-index: 9; display: none; width: max-content; text-align: center; line-height: 1.15; white-space: nowrap; transform: translateX(-50%); text-shadow: 0 1px 2px #000, 0 0 6px rgba(0, 0, 0, .8); pointer-events: none; }
#avatar .al b { display: block; font: 700 13px var(--head); color: var(--ac, #fff); }
#avatar .al small { display: block; font-size: 10px; color: #fff; opacity: 1; }
#avatar.has-aura .al { display: block; }

.peer .pn { position: absolute; left: 50%; bottom: calc(100% + 19px); z-index: 6; font-size: 11px; white-space: nowrap; transform: translateX(-50%); text-shadow: 0 1px 2px #000, 0 0 6px rgba(0, 0, 0, .8); }
.peer .pa { position: absolute; left: 50%; bottom: calc(100% + 35px); z-index: 6; font: 700 10px var(--head); white-space: nowrap; transform: translateX(-50%); text-shadow: 0 1px 2px #000; color: #fff; }
.peer .pa small { display: block; font-weight: 600; color: #fff; opacity: 1; margin-left: 0; }
.peer .pb, #avatar .pb { position: absolute; left: 50%; bottom: calc(100% + 47px); z-index: 5; width: max-content; max-width: 180px; padding: 3px 8px; font-size: 12px; line-height: 1.3; text-align: center; word-break: break-word; color: #14181c; background: #f0f2f4; border-radius: 4px; transform: translateX(-50%); opacity: 0; transition: opacity .25s; pointer-events: none; }
.peer .pb::after, #avatar .pb::after { content: ""; position: absolute; left: 50%; top: 100%; margin-left: -4px; border: 4px solid transparent; border-top-color: #f0f2f4; }
.peer .pb.on, #avatar .pb.on { opacity: 1; }

/* ---------- portal, sanctuary cave ---------- */
.spot.portal .blk { border-color: rgba(120, 220, 255, .9); border-radius: 50%; background: conic-gradient(from 0deg, #1565c0, #4fc3f7, #e1f5fe, #4fc3f7, #1565c0); box-shadow: 0 0 26px #4fc3f7, 0 0 60px rgba(79, 195, 247, .6), inset 0 0 14px #0d47a1; animation: spin 2.4s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
#cave { position: absolute; inset: 0; display: none; pointer-events: none; background: radial-gradient(ellipse at 50% 38%, #123a5a 0%, #0a1f35 38%, #050d18 78%), #050d18; }
#cave::before, #cave::after { content: ''; position: absolute; inset: 0; background-image: radial-gradient(2px 2px at 20% 30%, #9fd8ff, transparent), radial-gradient(2px 2px at 70% 20%, #cfe9ff, transparent), radial-gradient(3px 3px at 40% 70%, #7fc4ff, transparent), radial-gradient(2px 2px at 85% 60%, #bfe3ff, transparent), radial-gradient(2px 2px at 10% 80%, #8fd0ff, transparent); animation: spiritfloat 9s ease-in-out infinite alternate; opacity: .8; }
#cave::after { animation-duration: 13s; transform: scale(-1, 1); opacity: .5; }
@keyframes spiritfloat { from { transform: translateY(14px); } to { transform: translateY(-18px); } }
body.in-sanctuary #cave { display: block; }

/* ---------- Nightmare: blood red hellscape, built on the Dreamspace layer ---------- */
body.biome-Nightmare #bg { filter: brightness(.88); transition: filter .5s; }
body.nm-beat.biome-Nightmare #bg { filter: brightness(1.38) saturate(1.35); transition: filter .07s; }
#nm { position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity 2s; overflow: hidden; }
body.biome-Nightmare #nm { opacity: 1; }
#nm .nmz { position: absolute; animation: dfloat 11s ease-in-out infinite; filter: drop-shadow(0 0 12px #ff0a2e) drop-shadow(0 0 28px rgba(255,20,50,.55)); }
#nm .nmz svg { width: 100%; height: auto; display: block; transition: transform .12s ease-out; }
body.nm-beat #nm .nmz.heart svg { transform: scale(1.26); }
body.nm-beat #nm .nmz.cross svg, body.nm-beat #nm .nmz.monitor svg { transform: scale(1.06); }
#nm .nmc { position: absolute; left: -20%; width: 140%; height: 34%; background: radial-gradient(ellipse at 50% 40%, rgba(10,0,3,.95), rgba(40,0,8,.7) 45%, transparent 72%); filter: blur(10px); animation: nmdrift 38s linear infinite; }
#nm .cl1 { top: -14%; } #nm .cl2 { top: -4%; animation-duration: 52s; animation-direction: reverse; opacity: .8; } #nm .cl3 { top: 6%; animation-duration: 70s; opacity: .6; }
@keyframes nmdrift { from { transform: translateX(-9%); } to { transform: translateX(9%); } }
#nm .nmfog { position: absolute; left: 0; right: 0; bottom: 0; height: 45%; background: linear-gradient(transparent, rgba(120,0,16,.45)); animation: nmfog 9s ease-in-out infinite; }
@keyframes nmfog { 0%, 100% { opacity: .55; transform: translateY(0); } 50% { opacity: 1; transform: translateY(-10px); } }
body.biome-Nightmare #sky { mix-blend-mode: normal; }
body.biome-Nightmare #world.swap { animation: nmswap 1.4s ease-out; }
@keyframes nmswap { 0% { filter: invert(1) contrast(2) saturate(3); transform: translateX(-12px) skewX(4deg); } 12% { filter: none; transform: translateX(10px); } 24% { filter: invert(1) hue-rotate(160deg); transform: translateX(-6px); } 40%, 100% { filter: none; transform: none; } }

/* aura titles with moving gradients (Insomnia, Bloodshed, Lucifer) */
.grad-Insomnia, .grad-Bloodshed, .grad-Lucifer { color: transparent !important; -webkit-background-clip: text; background-clip: text; background-size: 300% 100%; animation: gradmove 5s linear infinite; text-shadow: none !important; }
.grad-Insomnia { background-image: linear-gradient(90deg, #ff3b3b, #ffb300, #ffee58, #66bb6a, #29b6f6, #7e57c2, #ec407a, #ff3b3b); }
.grad-Bloodshed { background-image: linear-gradient(90deg, #ff5a5a, #6b0010, #ff5a5a, #6b0010, #ff5a5a); }
.grad-Lucifer { background-image: linear-gradient(90deg, #dc143c, #ffd54f, #dc143c, #ffd54f, #dc143c); }
@keyframes gradmove { to { background-position: -300% 0; } }

/* equipped Nightmare aura effects */
#avatar .avfx { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
#avatar .avfx > * { position: absolute; }
#avatar .avfx { transform: scale(1.7); transform-origin: 50% 70%; }
#avatar .avfx[data-a=Lucifer] { transform: none; }
.ins-smoke { left: -30px; top: -26px; width: 82px; height: 70px; background: radial-gradient(ellipse, rgba(25,0,12,.55), rgba(60,0,20,.3) 45%, transparent 68%); filter: blur(3px); animation: dfloat 6s ease-in-out infinite; }
.ins-eyes { left: -34px; top: -26px; width: 90px; height: 50px; }
.ins-eyes b { position: absolute; width: 9px; height: 4px; border-radius: 50%; background: #ff1230; box-shadow: 0 0 7px 2px #ff1230; animation: insblink 3.4s infinite; }
.ins-eyes b:nth-child(1) { left: 6px; top: 8px; } .ins-eyes b:nth-child(2) { left: 22px; top: 8px; } .ins-eyes b:nth-child(3) { left: 50px; top: 2px; animation-delay: -1s; } .ins-eyes b:nth-child(4) { left: 66px; top: 2px; animation-delay: -1s; } .ins-eyes b:nth-child(5) { left: 30px; top: 30px; animation-delay: -2s; } .ins-eyes b:nth-child(6) { left: 46px; top: 30px; animation-delay: -2s; }
@keyframes insblink { 0%, 44%, 50%, 100% { transform: scaleY(1); opacity: 1; } 47% { transform: scaleY(.1); opacity: .5; } }
.ins-hands { left: -26px; bottom: -14px; width: 74px; height: 28px; animation: inshands 2.6s ease-in-out infinite; }
@keyframes inshands { 0%, 100% { transform: translateY(6px); } 50% { transform: translateY(-3px); } }
.bs-cloud { left: -26px; top: -42px; width: 74px; height: 26px; border-radius: 50%; background: radial-gradient(ellipse, #4a0e18, #2a0610 60%, transparent 78%); box-shadow: 0 0 14px 3px rgba(255,40,70,.55); }
.bs-rain { left: -8px; top: -26px; width: 38px; height: 64px; overflow: hidden; }
.bs-rain i { position: absolute; top: 0; width: 5px; height: 8px; border-radius: 50% 50% 50% 50% / 65% 65% 35% 35%; background: radial-gradient(circle at 35% 30%, #ff9aa6, #e01030 55%, #7a0010); box-shadow: 0 0 4px rgba(255,30,60,.8); animation: bsdrop 1s ease-in infinite; }
.bs-rain i:nth-child(1) { left: 2px; animation-delay: -.1s; } .bs-rain i:nth-child(2) { left: 9px; animation-delay: -.6s; animation-duration: 1.2s; } .bs-rain i:nth-child(3) { left: 16px; animation-delay: -.35s; } .bs-rain i:nth-child(4) { left: 23px; animation-delay: -.85s; animation-duration: .9s; } .bs-rain i:nth-child(5) { left: 30px; animation-delay: -.5s; animation-duration: 1.1s; } .bs-rain i:nth-child(6) { left: 12px; animation-delay: -.95s; animation-duration: 1.3s; }
@keyframes bsdrop { 0% { transform: translateY(-4px) scaleY(.6); opacity: 0; } 15% { opacity: 1; } 100% { transform: translateY(62px) scaleY(1.3); opacity: .9; } }
.bs-band { left: 5px; top: 2px; width: 12px; height: 5px; background: repeating-linear-gradient(135deg, #f1e6d6 0 3px, #cdbba3 3px 5px); border-radius: 2px; box-shadow: 0 0 3px rgba(120,0,10,.9); }
.luc-ent { left: -31px; bottom: -2px; width: 84px; height: 105px; transform: translateY(-2px); opacity: .95; filter: drop-shadow(0 0 10px #ff1030); animation: dfloat 7s ease-in-out infinite; z-index: -1; }
body.luc-dim::before { content: ''; position: fixed; inset: 0; z-index: 6; pointer-events: none; background: radial-gradient(circle at 50% 52%, transparent 0, transparent 110px, rgba(0,0,0,.86) 480px); animation: lucdim 1.2s ease-out; }
@keyframes lucdim { from { opacity: 0; } to { opacity: 1; } }

/* Singularity: a black hole in the top right that eats the particles */
#hole { position: absolute; left: 72%; top: 14%; width: min(210px, 26vw); aspect-ratio: 1; pointer-events: none; opacity: 0; transition: opacity 2s; }
body.biome-Singularity #hole { opacity: 1; }
#hole .core { position: absolute; inset: 31%; border-radius: 50%; background: #000; box-shadow: 0 0 30px 12px #000, 0 0 70px 22px rgba(179,136,255,.55); }
#hole .ring { position: absolute; inset: 0; border-radius: 50%; background: conic-gradient(from 0deg, transparent 0 8%, rgba(255,171,64,.9) 18%, rgba(255,255,255,.95) 26%, rgba(179,136,255,.9) 42%, transparent 55%, rgba(255,112,67,.7) 78%, transparent 92%);
  -webkit-mask: radial-gradient(circle, transparent 0 34%, #000 36% 62%, transparent 70%); mask: radial-gradient(circle, transparent 0 34%, #000 36% 62%, transparent 70%); filter: blur(1.5px); animation: holespin 5s linear infinite; transform: scaleY(.55) rotate(0deg); }
@keyframes holespin { to { transform: scaleY(.55) rotate(360deg); } }
#hole.in .core { box-shadow: 0 0 40px 18px #000, 0 0 90px 34px rgba(255,255,255,.5); }

/* ---------- Glitched: the interface corrupts ---------- */
body.gui-corrupt #hud, body.gui-corrupt .win, body.gui-corrupt #toasts, body.gui-corrupt #modal, body.gui-corrupt #banner { animation: guicorrupt .7s steps(1) both; }
body.gui-corrupt.gui-soft #hud, body.gui-corrupt.gui-soft .win, body.gui-corrupt.gui-soft #toasts, body.gui-corrupt.gui-soft #modal, body.gui-corrupt.gui-soft #banner { animation: none; }
@keyframes guicorrupt {
  0% { translate: 0 0; filter: none; } 10% { translate: -7px 2px; filter: hue-rotate(170deg) contrast(1.7) drop-shadow(4px 0 #f00) drop-shadow(-4px 0 #0ff); }
  22% { translate: 6px -3px; filter: invert(1) hue-rotate(40deg); } 34% { translate: -3px 5px; filter: contrast(2.4) saturate(3) drop-shadow(-5px 0 #f0f); }
  48% { translate: 9px 0; filter: hue-rotate(300deg) drop-shadow(5px 0 #f00); } 60% { translate: -8px -2px; filter: grayscale(1) contrast(2.2); }
  74% { translate: 4px 4px; filter: hue-rotate(90deg) saturate(4) drop-shadow(-4px 0 #0ff); } 88% { translate: -2px -1px; filter: contrast(1.5) drop-shadow(3px 0 #f00); } 100% { translate: 0 0; filter: none; }
}
#corrupt { position: fixed; inset: 0; z-index: 90; pointer-events: none; overflow: hidden; }
#corrupt i { position: absolute; background: #ff1f1f; mix-blend-mode: screen; }
/* "<< SERVER INFO >>" notices */
.toast.server { display: flex; gap: 10px; align-items: center; text-align: left; background: rgba(28,0,0,.92); border: 2px solid #ff2b2b; color: #ff3b3b; box-shadow: 0 0 14px rgba(255,0,0,.35), inset 0 0 20px rgba(255,0,0,.12); position: relative; overflow: hidden; }
.toast.server .warn-ico { flex: none; width: 46px; height: 46px; border: 2px solid #ff2b2b; display: grid; place-items: center; background: rgba(255,0,0,.12); }
.toast.server .warn-ico i { font-style: normal; font-weight: bold; font-size: 24px; width: 0; height: 0; display: block; position: relative; }
.toast.server .warn-ico::before { content: ''; width: 0; height: 0; border-left: 14px solid transparent; border-right: 14px solid transparent; border-bottom: 24px solid #ff2b2b; position: absolute; }
.toast.server .warn-ico i { position: absolute; color: #200; font-size: 15px; width: auto; height: auto; margin-top: 6px; }
.toast.server h4 { color: #ff3b3b; text-align: center; letter-spacing: .12em; text-shadow: 0 0 6px #f00; }
.toast.server p { color: #ff5252; font-size: 11px; word-break: break-all; margin: 2px 0 0; }
.toast.server .si { flex: 1; min-width: 0; }
.toast.server.torn::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: repeating-linear-gradient(115deg, transparent 0 22px, rgba(255,20,20,.9) 22px 46px, transparent 46px 120px); -webkit-mask: linear-gradient(180deg, transparent 0 18%, #000 18% 62%, transparent 62%); mask: linear-gradient(180deg, transparent 0 18%, #000 18% 62%, transparent 62%); mix-blend-mode: screen; animation: tornflick .35s steps(2) infinite; }
@keyframes tornflick { 0% { background-position: 0 0; } 100% { background-position: 40px 0; } }


/* ---------- Equilibrium: black and white, flash-inverting on the beat (js toggles body.eq-inv) ---------- */
#equi { position: absolute; inset: 0; pointer-events: none; display: none; --p: 0; overflow: hidden; }
body.biome-Equilibrium #equi { display: block; }
body.biome-Equilibrium #bg, body.biome-Equilibrium #trees { transition: none; }
body.eq-inv #bg, body.eq-inv #trees { filter: invert(1); }
#equi .glyph { position: absolute; left: 50%; top: 54%; font-family: 'Noto Serif CJK SC', 'Noto Serif SC', 'Source Han Serif SC', 'Songti SC', 'SimSun', 'MS Mincho', serif; font-weight: 900; font-size: min(78vw, 120vh); line-height: 1; color: #000; opacity: calc(.16 + var(--p) * .08); transform: translate(-50%, -50%) perspective(900px) rotateX(58deg) scale(calc(1 + var(--p) * .035)); text-shadow: 0 0 40px rgba(0,0,0,.35); white-space: nowrap; }
#equi .beam { position: absolute; left: 50%; top: 54%; width: min(46vw, 70vh); height: 130%; transform: translate(-50%, -100%); background: linear-gradient(to top, rgba(0,0,0,calc(.14 + var(--p) * .08)), rgba(0,0,0,0)); clip-path: polygon(18% 100%, 82% 100%, 100% 0, 0 0); }
#equi .ring { position: absolute; left: 50%; top: 54%; border-radius: 50%; border: 2px solid rgba(0,0,0,.45); transform: translate(-50%, -50%) perspective(900px) rotateX(62deg) scale(calc(1 + var(--p) * .04)); box-shadow: 0 0 18px 2px rgba(0,0,0,.25), inset 0 0 18px 2px rgba(0,0,0,.18); }
#equi .r1 { width: min(62vw, 92vh); aspect-ratio: 1; }
#equi .r2 { width: min(44vw, 66vh); aspect-ratio: 1; border-style: dashed; }
body.eq-inv #equi .glyph { color: #fff; text-shadow: 0 0 40px rgba(255,255,255,.4); }
body.eq-inv #equi .beam { background: linear-gradient(to top, rgba(255,255,255,calc(.18 + var(--p) * .1)), rgba(255,255,255,0)); }
body.eq-inv #equi .ring { border-color: rgba(255,255,255,.6); box-shadow: 0 0 18px 2px rgba(255,255,255,.35), inset 0 0 18px 2px rgba(255,255,255,.2); }
body.biome-Equilibrium.eq-soft #bg, body.biome-Equilibrium.eq-soft #trees { transition: filter .22s ease-in-out; }


/* Equilibrium extras (screen-wide layer: split sides, orbs, bars, words, pulses) */
#eqfx { position: absolute; inset: 0; pointer-events: none; display: none; overflow: hidden; }
body.biome-Equilibrium #eqfx { display: block; }
#eqfx .eqa, #eqfx .eqb { position: absolute; inset: 0; opacity: .26; }
#eqfx .eqa { background: #000; clip-path: polygon(0 0, 64% 0, 36% 100%, 0 100%); }
#eqfx .eqb { background: #fff; clip-path: polygon(64% 0, 100% 0, 100% 100%, 36% 100%); }
body.eq-inv #eqfx .eqa { background: #fff; } body.eq-inv #eqfx .eqb { background: #000; }
#eqfx .eqline { position: absolute; left: 50%; top: -20%; width: 3px; height: 140%; background: #fff; mix-blend-mode: difference; transform: rotate(15deg); opacity: .8; }
#eqfx .eqs { position: absolute; mix-blend-mode: difference; opacity: 0; animation: eqtw 4s ease-in-out infinite; }
@keyframes eqtw { 0%, 100% { opacity: 0; transform: scale(.4) rotate(0); } 50% { opacity: .95; transform: scale(1) rotate(45deg); } }
#eqfx .eqorb { position: absolute; left: 50%; top: 44%; width: 0; height: 0; animation: eqx 12s ease-in-out infinite alternate; }
#eqfx .eqorb > i { position: absolute; left: -46px; top: -46px; width: 92px; height: 92px; border-radius: 50%; animation: eqy 12s ease-in-out infinite alternate; display: block; }
#eqfx .eqorb.w > i { background: radial-gradient(circle at 35% 30%, #fff, #e8e8e8 60%, #bbb); box-shadow: 0 0 26px 6px rgba(255,255,255,.55), 0 0 0 4px #000; }
#eqfx .eqorb.k > i { background: radial-gradient(circle at 35% 30%, #444, #000 62%); box-shadow: 0 0 26px 6px rgba(0,0,0,.55), 0 0 0 4px #fff; }
#eqfx .eqorb svg { position: absolute; left: 22px; top: 22px; width: 48px; height: 48px; filter: drop-shadow(0 0 8px #fff); }
#eqfx .eqorb.w svg path { fill: #000; } #eqfx .eqorb.w svg { filter: drop-shadow(0 0 6px #000); }
#eqfx .eqorb u { position: absolute; inset: -14px; border-radius: 50%; border: 2px solid #fff; mix-blend-mode: difference; }
@keyframes eqx { from { transform: translateX(-27vw); } to { transform: translateX(27vw); } }
@keyframes eqy { from { transform: translateY(-17vh) scale(.82); } to { transform: translateY(17vh) scale(1.12); } }
#eqfx .eqbars { position: absolute; left: 0; right: 0; bottom: 0; height: 30vh; display: flex; align-items: flex-end; opacity: .5; }
#eqfx .eqbars b { flex: 1; height: 8%; margin: 0 1px; background: #000; transition: height .1s ease-out; }
#eqfx .eqbars b:nth-child(odd) { background: #fff; }
body.eq-inv #eqfx .eqbars b { background: #fff; } body.eq-inv #eqfx .eqbars b:nth-child(odd) { background: #000; }
#eqfx .eqk { position: absolute; color: #fff; mix-blend-mode: difference; font-family: 'Noto Serif CJK SC', 'Noto Serif SC', 'Source Han Serif SC', 'Songti SC', 'SimSun', 'MS Mincho', serif; font-weight: 900; line-height: 1; opacity: 0; animation: eqfade 4s ease-in-out forwards; }
@keyframes eqfade { 0% { opacity: 0; transform: scale(.85); } 35%, 60% { opacity: .92; transform: scale(1); } 100% { opacity: 0; transform: scale(1.12); } }
#eqfx .eqpulse { position: absolute; left: 50%; top: 46%; width: 30vh; height: 30vh; margin: -15vh 0 0 -15vh; border-radius: 50%; border: 4px solid #fff; mix-blend-mode: difference; animation: eqpulse 1s ease-out forwards; }
@keyframes eqpulse { from { transform: scale(.2); opacity: .9; } to { transform: scale(4); opacity: 0; } }
#eqfx .eqvl { position: absolute; top: 0; bottom: 0; width: 5px; background: #fff; mix-blend-mode: difference; animation: eqvl .35s ease-out forwards; }
@keyframes eqvl { from { opacity: .9; } to { opacity: 0; } }


/* character render shots replace the letter on spots, portraits and quest headers */
.face { display: block; width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
.spot .blk:has(.face), .portrait:has(.face), .npc-av:has(.face) { padding: 0; overflow: hidden; }

/* ---------- Backrooms (see js/ui/backrooms.js) ---------- */
#brfx, #brfade { position: absolute; inset: 0; pointer-events: none; }
#brfx { opacity: 0; transition: opacity 2.2s; }
#brfx.on { opacity: 1; }
#brfx .tint { position: absolute; inset: 0; background: rgba(190, 160, 40, .26); mix-blend-mode: multiply; }
/* a grid of ceiling panels, glowing softly over the whole map */
#brfx .lights { position: absolute; inset: 0; mix-blend-mode: screen; transition: opacity .05s;
  background: radial-gradient(ellipse 84px 26px at 50% 50%, rgba(255, 250, 200, .5), rgba(255, 250, 200, 0) 72%) 0 0 / 300px 190px; opacity: .55; }
#brfx.dim .lights { opacity: .06; }
#brfx.dim .tint { background: rgba(120, 100, 20, .34); }
#brfx .vig { position: absolute; inset: 0; background: radial-gradient(ellipse at 50% 45%, rgba(0, 0, 0, 0) 38%, rgba(35, 28, 0, .62) 100%); }
#brfx .msg { position: absolute; left: 50%; top: 34%; max-width: 80vw; transform: translateX(-50%); font: 600 20px/1.4 var(--head); letter-spacing: .08em; text-align: center; color: #efe3a0; text-shadow: 0 0 12px rgba(0, 0, 0, .9), 0 0 3px rgba(0, 0, 0, .9); opacity: 0; }
#brfx .msg.on { opacity: .9; }
/* red and black drain into a damp yellow, then it clears to show the carpet */
#brfade { z-index: 3; opacity: 0; transition: opacity 2.6s linear;
  background: repeating-linear-gradient(90deg, #8f8130 0 34px, #7b6e27 34px 38px), radial-gradient(ellipse at 50% 50%, #b9a746, #5f541c); background-blend-mode: multiply; }
#brfade.on { opacity: .96; }
body.br-freeze #world *, body.br-freeze #hud * { animation-play-state: paused !important; transition: none !important; }
body.br-freeze #world { filter: contrast(1.35) saturate(.6); }
.toast.server.brnote { transition: background 1.2s, border-color 1.2s, color 1.2s, box-shadow 1.2s; }
.toast.server.brnote.fractured { background: rgba(14, 11, 0, .96); border-color: #ffd800; color: #ffd800; box-shadow: 0 0 16px rgba(255, 216, 0, .55), inset 0 0 22px rgba(255, 216, 0, .08); }
.toast.server.brnote.fractured h4 { color: #ffd800; text-shadow: 0 0 6px rgba(255, 216, 0, .6); }
.toast.server.brnote.fractured p { color: #ffd800; }
.toast.server.brnote.fractured .warn-ico { width: 62px; height: 62px; border: 0; background: none; color: #ffd800; }
.toast.server.brnote.fractured .warn-ico::before { display: none; }
.toast.server.brnote.fractured .warn-ico svg { display: block; }
.toast.server.brnote.fractured h4 { letter-spacing: .05em; white-space: nowrap; }

/* placeable luck zones (candle / incense / portable) */
#devices { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
#devices .zone { position: absolute; border-radius: 50%; transform: translate(-50%, -50%);
  border: 2px dashed currentColor; opacity: 0.55; box-shadow: 0 0 18px currentColor inset, 0 0 8px currentColor;
  animation: zonePulse 2.4s ease-in-out infinite; }
#devices .zone .dot { position: absolute; left: 50%; top: 50%; width: 10px; height: 10px; margin: -5px 0 0 -5px;
  border-radius: 50%; background: currentColor; box-shadow: 0 0 8px currentColor; }
#devices .zone .tag { position: absolute; left: 50%; top: calc(50% + 8px); transform: translateX(-50%);
  font-size: 10px; white-space: nowrap; color: #fff; text-shadow: 0 1px 2px #000; opacity: 0.9; pointer-events: none; }
@keyframes zonePulse { 0%,100% { opacity: 0.4; } 50% { opacity: 0.7; } }
