/* ============================================================ 趴趴鲸鱼娘 dsh-whale-lap —— 样式与动效 纯本地资源:无外部字体、无外部图片、无网络请求。 ============================================================ */ #dsh-whale-lap-root { position: fixed; left: 0; top: 0; z-index: 2147483000; pointer-events: none; font-family: "Segoe UI", "Microsoft YaHei", system-ui, sans-serif; transition: left .34s cubic-bezier(.34, 1.56, .64, 1), top .34s cubic-bezier(.34, 1.56, .64, 1); } /* 拖拽中禁用 transition:否则拖动会「黏手」,松手弹回也依赖它 */ #dsh-whale-lap-root[data-wl-dragging="1"] { transition: none; } #dsh-whale-lap-root[hidden] { display: none; } /* ---------- 舞台(SVG 本体) ---------- */ #dsh-whale-lap-root .wl-stage { position: relative; pointer-events: auto; width: 100%; height: auto; display: block; cursor: grab; user-select: none; -webkit-user-select: none; touch-action: none; filter: drop-shadow(0 8px 12px rgba(60, 110, 190, .28)); animation: wl-breathe 3.4s ease-in-out infinite; } #dsh-whale-lap-root .wl-stage svg { display: block; width: 100%; height: auto; overflow: visible; } #dsh-whale-lap-root[data-wl-dragging="1"] .wl-stage { cursor: grabbing; } #dsh-whale-lap-root[data-wl-dragging="1"] .wl-stage svg { transition: transform .12s ease-out; } @keyframes wl-breathe { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-1.6px); } } /* ---------- 尾巴 ---------- */ #wlgTail { transform-box: fill-box; transform-origin: 0% 100%; animation: wl-tail 2.8s ease-in-out infinite; } @keyframes wl-tail { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(-7deg); } } #wlgFlukes { transform-box: fill-box; transform-origin: 50% 100%; animation: wl-fluke 2.8s ease-in-out infinite; } @keyframes wl-fluke { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(7deg); } } /* ---------- 胸鳍 ---------- */ #wlgFinL, #wlgFinR { transform-box: fill-box; transform-origin: 100% 100%; animation: wl-fin 3.6s ease-in-out infinite; } #wlgFinR { animation-delay: .4s; } @keyframes wl-fin { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(-9deg); } } /* ---------- 头发 ---------- */ #wlgTwinL { transform-box: fill-box; transform-origin: 90% 0%; animation: wl-hair-l 4.2s ease-in-out infinite; } #wlgTwinR { transform-box: fill-box; transform-origin: 10% 0%; animation: wl-hair-r 4.2s ease-in-out infinite; } @keyframes wl-hair-l { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(-4deg); } } @keyframes wl-hair-r { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(4deg); } } #wlgLockL { transform-box: fill-box; transform-origin: 50% 0%; animation: wl-lock 3.8s ease-in-out infinite; } #wlgLockR { transform-box: fill-box; transform-origin: 50% 0%; animation: wl-lock 3.8s ease-in-out infinite reverse; animation-delay: .7s; } @keyframes wl-lock { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(3deg); } } /* ---------- 头(轻微歪头) ---------- */ #wlgHead { transform-box: fill-box; transform-origin: 50% 65%; animation: wl-head 5.2s ease-in-out infinite; } @keyframes wl-head { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(1.2deg); } } /* ---------- 眨眼(CSS 周期眨眼 + JS 双连眨) ---------- */ #wlgEyes { transform-box: fill-box; transform-origin: center; animation: wl-blink 4.6s infinite; } @keyframes wl-blink { 0%, 91%, 100% { transform: scaleY(1); } 92.5%, 95% { transform: scaleY(.08); } 96.5% { transform: scaleY(1); } } #dsh-whale-lap-root.wl-dbl #wlgEyes { animation: wl-blink-dbl 1.2s ease-in-out; } @keyframes wl-blink-dbl { 0%, 100% { transform: scaleY(1); } 10%, 45% { transform: scaleY(.08); } 28%, 60% { transform: scaleY(1); } } /* 闭眼(睡觉 / 被拎起来) */ #wlgEyesClosed { opacity: 0; } #dsh-whale-lap-root[data-wl-state="sleep"] #wlgEyes, #dsh-whale-lap-root[data-wl-dragging="1"] #wlgEyes { animation: none; opacity: 0; } #dsh-whale-lap-root[data-wl-state="sleep"] #wlgEyesClosed, #dsh-whale-lap-root[data-wl-dragging="1"] #wlgEyesClosed { opacity: 1; } /* ---------- 腮红 ---------- */ #wlgBlush { animation: wl-blush 2.4s ease-in-out infinite; } @keyframes wl-blush { 0%, 100% { opacity: .5; } 50% { opacity: .78; } } /* ---------- 嘴巴多形态 ---------- */ #wlgMouthHappy, #wlgMouthHappyTongue, #wlgMouthSad, #wlgMouthO { display: none; } #dsh-whale-lap-root[data-wl-state="happy"] #wlgMouthDefault, #dsh-whale-lap-root[data-wl-state="happy"] #wlgMouthTongue { display: none; } #dsh-whale-lap-root[data-wl-state="happy"] #wlgMouthHappy, #dsh-whale-lap-root[data-wl-state="happy"] #wlgMouthHappyTongue { display: block; } #dsh-whale-lap-root[data-wl-state="sad"] #wlgMouthDefault, #dsh-whale-lap-root[data-wl-state="sad"] #wlgMouthTongue, #dsh-whale-lap-root[data-wl-state="error"] #wlgMouthDefault, #dsh-whale-lap-root[data-wl-state="error"] #wlgMouthTongue { display: none; } #dsh-whale-lap-root[data-wl-state="sad"] #wlgMouthSad, #dsh-whale-lap-root[data-wl-state="error"] #wlgMouthSad { display: block; } #dsh-whale-lap-root[data-wl-state="think"] #wlgMouthDefault, #dsh-whale-lap-root[data-wl-state="think"] #wlgMouthTongue, #dsh-whale-lap-root[data-wl-state="listen"] #wlgMouthDefault, #dsh-whale-lap-root[data-wl-state="listen"] #wlgMouthTongue { display: none; } #dsh-whale-lap-root[data-wl-state="think"] #wlgMouthO, #dsh-whale-lap-root[data-wl-state="listen"] #wlgMouthO { display: block; } /* ---------- 头顶喷泉(鲸鱼娘本体特征) ---------- */ #wlgSpout { opacity: 0; transform-box: fill-box; transform-origin: 50% 100%; animation: wl-spout 9s ease-in-out infinite; } @keyframes wl-spout { 0%, 90% { opacity: 0; transform: scaleY(.2); } 92% { opacity: 1; transform: scaleY(1); } 97% { opacity: 1; } 100% { opacity: 0; transform: scaleY(.2); } } /* ---------- 泡泡 ---------- */ #wlgBubbles circle { animation: wl-rise 3.4s ease-in infinite; transform-box: fill-box; } #wlgBubbles circle:nth-child(1) { animation-delay: 0s; } #wlgBubbles circle:nth-child(2) { animation-delay: 1.1s; } #wlgBubbles circle:nth-child(3) { animation-delay: 1.7s; } #wlgBubbles circle:nth-child(4) { animation-delay: 2.4s; } #wlgBubbles circle:nth-child(5) { animation-delay: .5s; } #wlgBubbles circle:nth-child(6) { animation-delay: 3.1s; } @keyframes wl-rise { 0% { transform: translateY(0); opacity: 0; } 12% { opacity: .8; } 100% { transform: translateY(-40px); opacity: 0; } } /* ---------- 星星闪片 ---------- */ #wlgSparkles g { animation: wl-twinkle 2.6s ease-in-out infinite; transform-box: fill-box; transform-origin: center; } #wlgSparkles g:nth-child(2) { animation-delay: .7s; } #wlgSparkles g:nth-child(3) { animation-delay: 1.4s; } #wlgSparkles g:nth-child(4) { animation-delay: 2s; } @keyframes wl-twinkle { 0%, 100% { opacity: .15; transform: scale(.6); } 50% { opacity: 1; transform: scale(1); } } /* ---------- 睡觉 Zzz ---------- */ #wlgZzz { display: none; } #dsh-whale-lap-root[data-wl-state="sleep"] #wlgZzz { display: block; } #wlgZzz text { animation: wl-zzz 2.8s ease-in infinite; transform-box: fill-box; } #wlgZzz text:nth-child(2) { animation-delay: .8s; } #wlgZzz text:nth-child(3) { animation-delay: 1.6s; } @keyframes wl-zzz { 0% { opacity: 0; transform: translateY(6px); } 30% { opacity: .9; } 100% { opacity: 0; transform: translateY(-12px); } } /* ---------- 工作模式 ---------- */ #wlgLaptop { display: none; } #dsh-whale-lap-root[data-wl-state="work"] #wlgLaptop { display: block; } #wlgTypeHands ellipse { animation: wl-type .45s ease-in-out infinite alternate; transform-box: fill-box; } #wlgTypeHands ellipse:nth-child(2) { animation-delay: .22s; } @keyframes wl-type { from { transform: translateY(0); } to { transform: translateY(-2.4px); } } #wlgSweat { display: none; } #dsh-whale-lap-root[data-wl-state="work"] #wlgSweat { display: block; animation: wl-drop 1.3s ease-in-out infinite; transform-box: fill-box; transform-origin: center; } #dsh-whale-lap-root[data-wl-state="work"] .wl-stage { filter: drop-shadow(0 8px 14px rgba(60, 110, 190, .3)) drop-shadow(0 0 14px rgba(130, 205, 255, .5)); } @keyframes wl-drop { 0%, 100% { opacity: .9; transform: translateY(0); } 50% { opacity: .35; transform: translateY(2.5px); } } /* ---------- 难过 / 报错 ---------- */ #wlgTear { display: none; } #dsh-whale-lap-root[data-wl-state="sad"] #wlgTear, #dsh-whale-lap-root[data-wl-state="error"] #wlgTear { display: block; animation: wl-tear 1s ease-in-out infinite; transform-box: fill-box; transform-origin: center; } @keyframes wl-tear { 0%, 100% { transform: translateY(0) scale(1); } 50% { transform: translateY(3px) scale(1.08); } } /* ---------- 开心 ---------- */ #wlgNote { display: none; } #dsh-whale-lap-root[data-wl-state="happy"] #wlgNote { display: block; } #wlgNote text { animation: wl-note 1.4s ease-in-out infinite; transform-box: fill-box; } #wlgNote text:nth-child(2) { animation-delay: .3s; } @keyframes wl-note { 0%, 100% { transform: translateY(0) rotate(-6deg); } 50% { transform: translateY(-5px) rotate(6deg); } } #dsh-whale-lap-root[data-wl-state="happy"] .wl-stage svg { animation: wl-bounce .55s ease-in-out 3; } @keyframes wl-bounce { 0%, 100% { transform: translateY(0); } 40% { transform: translateY(-10px); } } /* ---------- 思考 / 倾听 ---------- */ #dsh-whale-lap-root[data-wl-state="think"] #wlgHead, #dsh-whale-lap-root[data-wl-state="listen"] #wlgHead { animation: wl-tilt 1.6s ease-in-out infinite; } @keyframes wl-tilt { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(3.5deg); } } /* ---------- 工作姿势微调 ---------- */ #dsh-whale-lap-root[data-wl-state="work"] #wlgHead { animation: none; transform: rotate(2.5deg); } /* ---------- 睡觉状态:呼吸变慢、头低一点 ---------- */ #dsh-whale-lap-root[data-wl-state="sleep"] .wl-stage { animation-duration: 5.2s; } #dsh-whale-lap-root[data-wl-state="sleep"] #wlgHead { animation: none; transform: rotate(4deg); } #dsh-whale-lap-root[data-wl-state="sleep"] #wlgTail, #dsh-whale-lap-root[data-wl-state="sleep"] #wlgFlukes { animation-duration: 5s; } /* ---------- 拖拽:尾巴甩快一点 ---------- */ #dsh-whale-lap-root[data-wl-dragging="1"] #wlgTail, #dsh-whale-lap-root[data-wl-dragging="1"] #wlgFlukes { animation-duration: 1.1s; } /* ============================================================ 气泡 / 齿轮 / 菜单 / 粒子 ============================================================ */ #dsh-whale-lap-root .wl-bubble { position: absolute; left: 50%; bottom: calc(100% + 8px); transform: translateX(-50%); background: #ffffff; color: #2b4a6f; border: 1.5px solid #bfe3ff; border-radius: 12px; padding: 6px 10px; font-size: 12px; line-height: 1.45; max-width: 190px; white-space: pre-wrap; box-shadow: 0 4px 14px rgba(60, 110, 190, .22); pointer-events: none; z-index: 1; } #dsh-whale-lap-root .wl-bubble[hidden] { display: none; } #dsh-whale-lap-root .wl-bubble::after { content: ""; position: absolute; top: 100%; left: 50%; margin-left: -5px; border: 5px solid transparent; border-top-color: #ffffff; } #dsh-whale-lap-root .wl-bubble.wl-in { animation: wl-pop .28s cubic-bezier(.34, 1.56, .64, 1); } @keyframes wl-pop { from { transform: translateX(-50%) scale(.6); opacity: 0; } to { transform: translateX(-50%) scale(1); opacity: 1; } } #dsh-whale-lap-root .wl-gear { position: absolute; top: -6px; right: -4px; width: 22px; height: 22px; border-radius: 50%; border: 1.5px solid #bfe3ff; background: #ffffff; color: #4a90d9; font-size: 12px; line-height: 1; cursor: pointer; opacity: 0; transition: opacity .18s; pointer-events: auto; box-shadow: 0 2px 6px rgba(60, 110, 190, .25); z-index: 2; } #dsh-whale-lap-root:hover .wl-gear { opacity: 1; } #dsh-whale-lap-root .wl-gear:focus-visible { opacity: 1; } #dsh-whale-lap-root .wl-menu { position: absolute; top: calc(100% + 6px); right: 0; background: #ffffff; border: 1.5px solid #bfe3ff; border-radius: 10px; padding: 4px; box-shadow: 0 6px 18px rgba(60, 110, 190, .25); display: none; pointer-events: auto; min-width: 128px; z-index: 3; } #dsh-whale-lap-root .wl-menu[hidden] { display: none; } #dsh-whale-lap-root .wl-menu[open] { display: block; animation: wl-pop .18s cubic-bezier(.34, 1.56, .64, 1); } #dsh-whale-lap-root .wl-menu button { display: block; width: 100%; text-align: left; border: none; background: none; padding: 6px 10px; font-size: 12px; color: #33507a; border-radius: 7px; cursor: pointer; } #dsh-whale-lap-root .wl-menu button:hover { background: #eaf5ff; } #dsh-whale-lap-root .wl-menu .wl-menu-title { font-size: 10px; color: #8aa8c9; padding: 4px 10px 2px; } #dsh-whale-lap-root .wl-fx { position: absolute; inset: 0; overflow: visible; pointer-events: none; z-index: 1; } #dsh-whale-lap-root .wl-fx span { position: absolute; bottom: 30%; font-size: 15px; animation: wl-float-up 1.05s ease-out forwards; } @keyframes wl-float-up { from { transform: translateY(0) scale(.7); opacity: 0; } 20% { opacity: 1; } to { transform: translateY(-52px) scale(1.2); opacity: 0; } } /* 隐藏后的找回小按钮 */ #dsh-whale-lap-findme { position: fixed; right: 14px; bottom: 14px; width: 34px; height: 34px; border-radius: 50%; border: 1.5px solid #bfe3ff; background: rgba(255, 255, 255, .92); color: #4a90d9; font-size: 17px; cursor: pointer; z-index: 2147483001; box-shadow: 0 3px 10px rgba(60, 110, 190, .3); pointer-events: auto; } /* ---------- 无障碍:减弱动效 ---------- */ @media (prefers-reduced-motion: reduce) { #dsh-whale-lap-root * { animation: none !important; transition: none !important; } }