/* =========================================================
   梦屿 Mengyu · H5  —  style.css  v2.3.3
   ========================================================= */
:root{
  --bg:#07090d;
  --bg-2:#0c0f15;
  --surface:rgba(255,255,255,.035);
  --surface-2:rgba(255,255,255,.06);
  --line:rgba(236,232,225,.12);
  --line-2:rgba(236,232,225,.22);
  --text:#ece8e1;
  --muted:rgba(236,232,225,.68);
  --faint:rgba(236,232,225,.54);
  --rose:#e8a598;
  --gold:#d8bb8c;
  --gold-10:rgba(216,187,140,.10);
  --gold-30:rgba(216,187,140,.30);
  --gold-60:rgba(216,187,140,.60);
  --sea:#7fa6c9;
  --paper:#f3e9dc;
  --sand:#e9dfd3;
  --cream:#fff3e8;
  --rose-deep:#7a4b45;
  --ok:#72bc8f;
  --ink-on-light:#0b0c10;
  --sel-fg:#14100f;
  /* 派生 token：带透明度的颜色统一收口，正文不再出现字面量 */
  --rose-08:rgba(232,165,152,.08);
  --rose-10:rgba(232,165,152,.10);
  --rose-14:rgba(232,165,152,.14);
  --rose-18:rgba(232,165,152,.18);
  --rose-55:rgba(232,165,152,.55);
  --rose-60:rgba(232,165,152,.60);
  --rose-85:rgba(232,165,152,.85);
  --sea-04:rgba(127,166,201,.04);
  --sea-18:rgba(127,166,201,.18);
  /* 贯穿全页的背景光带用：比 sea-04 明显一档，但仍属"余光"级别 */
  --sea-08:rgba(127,166,201,.08);
  --gold-06:rgba(216,187,140,.06);
  --ink-06:rgba(236,232,225,.06);
  --ink-14:rgba(236,232,225,.14);
  --ink-16:rgba(236,232,225,.16);
  --bg-15:rgba(7,9,13,.15);
  --bg-25:rgba(7,9,13,.25);
  --bg-30:rgba(7,9,13,.30);
  --bg-35:rgba(7,9,13,.35);
  --bg-50:rgba(7,9,13,.50);
  --bg-70:rgba(7,9,13,.70);
  --bg-72:rgba(7,9,13,.72);
  --bg-78:rgba(7,9,13,.78);
  --bg-96:rgba(7,9,13,.96);
  --ok-0:rgba(114,188,143,0);
  --ok-60:rgba(114,188,143,.60);
  --serif:"Noto Serif SC","Source Han Serif SC","Songti SC","STSong","SimSun",Georgia,serif;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans SC",Roboto,"Helvetica Neue",Arial,sans-serif;
  --mono:"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  --ease:cubic-bezier(.2,.7,.1,1);
  /* 动效语汇：出快收慢（press）／入慢回弹克制（lift）／长行程（scroll） */
  --e-press:cubic-bezier(.3,0,.2,1);
  --e-lift:cubic-bezier(.16,1,.3,1);
  --e-scroll:cubic-bezier(.22,.61,.36,1);
  --press-y:1px;
  --gutter:clamp(20px,4vw,56px);
  /* 容器宽度：不到超宽屏时吃满「视口 − 两侧 gutter」，不做二次收窄。
     之前用 92vw 当上限，等于 gutter 之外又留了 8%，两层边距叠起来就空得离谱。
     --maxw 只在 ≥1800 时起封顶作用，避免正文行宽过宽。 */
  --maxw:1800px;
  --nav-h:68px;
}
@media (min-width:1800px){:root{--maxw:1680px;--gutter:clamp(48px,4vw,96px)}}
@media (min-width:2400px){:root{--maxw:1840px}}
*,*::before,*::after{box-sizing:border-box}
/* scroll-behavior 必须留在 auto：JS 自写缓动时，浏览器原生 smooth 会和它抢每一帧，
   表现就是「点了没反应、过半秒才突然滑走」。 */
html{scroll-behavior:auto;-webkit-text-size-adjust:100%;scroll-padding-top:var(--nav-h)}
body{margin:0;
  /* 全页背景：底色之上叠三层极淡光晕，按页面高度铺开。
     此前只有首屏（占 18.7%）有背景层次，往下 81% 是纯色，滚动时会突然掉进黑里。
     这里让首屏的余光往下延续，四段正文各有一点明暗呼吸。
     首屏自带更亮的一层，会盖住顶部这一段，互不冲突。 */
  background:
    radial-gradient(ellipse 86% 24% at 76% 29%,var(--rose-08) 0%,transparent 68%),
    radial-gradient(ellipse 76% 22% at 20% 53%,var(--sea-08) 0%,transparent 70%),
    radial-gradient(ellipse 96% 26% at 62% 91%,var(--gold-06) 0%,transparent 72%),
    var(--bg);
  background-repeat:no-repeat;
  color:var(--text);font:16px/1.6 var(--sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overflow-x:hidden;text-rendering:optimizeLegibility}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
ul,ol{list-style:none;margin:0;padding:0}
h1,h2,h3,p{margin:0}
::selection{background:var(--rose);color:var(--sel-fg)}
/* 键盘聚焦（:focus-visible）保留，鼠标/手指点过的残留焦点一律清掉。
   ::focus-visible 的 outline 用透明色打底，真正可见的一层由各控件自己给，
   这样鼠标点完不会残留任何方框线。 */
:focus{outline:none}
:focus-visible{outline:2px solid transparent;outline-offset:3px}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums;letter-spacing:.02em}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter)}
.skip{position:fixed;left:12px;top:-60px;z-index:100;background:var(--text);color:var(--bg);padding:8px 14px;border-radius:8px}
.skip:focus{top:12px}

/* ---------------- 图标系统（内联 sprite + <use>） ---------------- */
.i{display:inline-block;flex:none;vertical-align:-0.125em;width:1em;height:1em;stroke-width:1.5}
.i-16{width:16px;height:16px}
.i-20{width:20px;height:20px}
.i-24{width:24px;height:24px}

/* 噪点质感 —— 纯 CSS，无额外请求 */
/* 颗粒质感：mix-blend-mode:overlay 在近黑底上会被压缩到只剩 1 个色阶（实测），
   等于白做。opacity 提到 .45 后，最亮与最暗的颗粒差约 3~4 个色阶 ——
   刚好是"看得见但说不出"的细纹理，不会显脏。 */
body::after{content:"";position:fixed;inset:0;pointer-events:none;z-index:90;opacity:.45;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

/* ---------------- 导航 ---------------- */
.nav{position:fixed;inset:0 0 auto 0;z-index:50;height:var(--nav-h);display:flex;align-items:center;gap:32px;padding:0 max(var(--gutter),calc((100% - var(--maxw)) / 2 + var(--gutter)));padding-top:env(safe-area-inset-top);
  transition:background .4s var(--ease),border-color .4s;border-bottom:1px solid transparent}
.nav.is-scrolled{background:var(--bg-72);-webkit-backdrop-filter:blur(14px) saturate(140%);backdrop-filter:blur(14px) saturate(140%);border-color:var(--line)}
.nav__logo{display:flex;align-items:center;gap:10px;font:600 19px/1 var(--serif);letter-spacing:.12em;min-height:44px}
.nav__mark{width:18px;height:18px;border-radius:50%;background:radial-gradient(circle at 35% 35%,var(--cream),var(--rose) 55%,var(--rose-deep));box-shadow:0 0 18px var(--rose-55)}
.nav__links{display:flex;gap:4px;margin-left:auto}
.nav__links a{position:relative;padding:10px 14px;font-size:14px;color:var(--muted);transition:color .3s}
.nav__links a::after{content:"";position:absolute;left:14px;right:14px;bottom:6px;height:1px;background:var(--rose);transform:scaleX(0);transform-origin:right;transition:transform .45s var(--ease)}
.nav__links a:hover,.nav__links a.is-active{color:var(--text)}
.nav__links a:hover::after,.nav__links a.is-active::after{transform:scaleX(1);transform-origin:left}
.nav__cta{font-size:14px;padding:9px 16px;border:1px solid var(--line-2);border-radius:999px;transition:background .3s,color .3s,border-color .3s;white-space:nowrap}
.nav__cta:hover{background:var(--text);color:var(--bg);border-color:var(--text)}
.nav__cta .i{vertical-align:-.2em;margin-left:2px}
.nav__toggle{display:none;width:44px;height:44px;margin-left:auto;background:none;border:0;color:var(--text);cursor:pointer;position:relative}
.nav__toggle span{position:absolute;left:12px;right:12px;height:1.5px;background:currentColor;transition:transform .4s var(--ease),top .4s var(--ease)}
.nav__toggle span:first-child{top:18px}.nav__toggle span:last-child{top:25px}
.nav-open .nav__toggle span:first-child{top:21.5px;transform:rotate(45deg)}
.nav-open .nav__toggle span:last-child{top:21.5px;transform:rotate(-45deg)}

/* ---------------- 按钮 ---------------- */
.btn{position:relative;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:48px;padding:0 24px;border-radius:999px;font-size:15px;font-weight:500;letter-spacing:.04em;
  transition:translate .22s var(--e-press),scale .22s var(--e-press),background .3s,color .3s,border-color .3s,box-shadow .4s}
.btn--solid{background:var(--text);color:var(--ink-on-light);box-shadow:inset 0 -2px 0 var(--line-2)}
.btn--solid:hover{background:#fff;box-shadow:0 10px 40px -10px var(--rose-60),inset 0 -2px 0 var(--line);translate:0 -2px}
/* 按压：不是往上飘，而是实打实往里陷 —— 位移 + 阴影收紧 + 内阴影压边 */
.btn--solid:active{translate:0 var(--press-y);scale:.985;box-shadow:0 2px 8px -4px var(--rose-60),inset 0 3px 6px var(--line)}
/* 次按钮样式：当前页脚已收成一个主按钮（客服入口统一放在「日常出没」），
   这里保留作为通用备用 —— 以后要在别处加次级操作直接用 .btn--ghost 即可。 */
.btn--ghost{border:1px solid var(--line-2);color:var(--text);background:var(--bg-25);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.btn--ghost:hover{border-color:var(--rose);color:var(--rose);translate:0 -2px}
.btn--ghost:active{translate:0 var(--press-y);scale:.985;background:var(--surface-2);border-color:var(--rose-60)}

/* ---------------- HERO ---------------- */
.hero{position:relative;height:100vh;height:100svh;min-height:600px;overflow:hidden;display:flex;align-items:center;isolation:isolate;
  background:radial-gradient(60% 50% at 70% 30%,var(--rose-18),transparent 70%),radial-gradient(80% 60% at 50% 110%,var(--sea-18),transparent 70%),var(--bg)}
.hero__canvas{position:absolute;inset:0;width:100%;height:100%;z-index:-2;opacity:0;transition:opacity 1.6s ease}
.hero__canvas.is-ready{opacity:1}
.hero__veil{position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(90deg,var(--bg-78) 0%,var(--bg-25) 45%,transparent 70%),linear-gradient(180deg,var(--bg-50) 0%,transparent 22%,transparent 70%,var(--bg) 100%)}
.hero__inner{width:100%;max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter);padding-bottom:6vh;box-sizing:border-box;
  /* 滚动退场由 JS 写 transform，这里加个过渡让首帧不跳；
     will-change 让手机上滚动时不掉帧 */
  will-change:transform,opacity}
.eyebrow{font:500 12px/1 var(--mono);letter-spacing:.32em;text-transform:uppercase;color:var(--gold)}
.hero__title{margin:28px 0 22px;font-weight:400;line-height:.9}
.hero__cn{display:block;font:500 clamp(64px,11vw,132px)/.94 var(--serif);letter-spacing:.06em;
  background:linear-gradient(180deg,#fff 10%,var(--sand) 55%,var(--rose-85) 100%);-webkit-background-clip:text;background-clip:text;color:transparent}
.hero__en{display:block;margin-top:14px;font:italic 400 clamp(16px,2vw,22px)/1 Georgia,var(--serif);color:var(--muted);letter-spacing:.04em}
.hero__en em{color:var(--rose);font-style:normal}
.hero__quote{font:400 clamp(14px,1.5vw,17px)/1.7 var(--serif);letter-spacing:.18em;color:var(--text);opacity:.9}
.hero__actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:40px;align-items:stretch}
/* 按钮文字不换行、可收缩；放不下两颗就整颗换行，纵向铺满容器宽，绝不横向溢出 */
.hero__actions .btn{flex:0 1 auto;white-space:nowrap;min-width:0;max-width:100%;padding:0 20px}
.hero__meta{position:absolute;left:0;right:0;bottom:calc(28px + env(safe-area-inset-bottom));max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter);display:flex;align-items:flex-end;gap:40px}
.meta-item span{display:block;font:500 11px/1 var(--mono);letter-spacing:.24em;color:var(--faint);text-transform:uppercase;margin-bottom:8px}
.meta-item b{font-weight:500;font-size:14px}
.hero__scroll{margin-left:auto;width:44px;height:64px;display:grid;place-items:center}
.hero__scroll span{width:1px;height:56px;background:linear-gradient(var(--line-2),var(--line-2)) top/1px 100% no-repeat;position:relative;overflow:hidden}
.hero__scroll span::after{content:"";position:absolute;left:0;top:-40%;width:1px;height:40%;background:var(--rose);animation:drip 2.2s var(--ease) infinite}
@keyframes drip{to{top:110%}}

/* ---------------- 首屏加料：标题逐字揭幕 / 分隔线生长 / 滚动提示呼吸 ----------------
   首屏不用 IO + transition（首屏元素本就在视口内，走 IO 只引入时序竞态，偶发空白）。
   改为 CSS animation 播放 + JS 兜底加 .is-done 定格，保证任何环境下内容最终必然可见。 */
.hero-in{opacity:0;translate:0 14px;animation:heroRise .95s var(--e-scroll) forwards;animation-delay:calc(.06s + var(--i,0) * .1s)}
@keyframes heroRise{to{opacity:1;translate:0 0}}
.hero__title.hero-in{translate:0 26px}
/* JS 兜底：动画结束后无条件归位（动画不推进的环境也不会留残影） */
.hero-in.is-done{opacity:1!important;translate:0 0!important;animation:none!important}
/* 中文名逐字从遮罩里升起（每字 --i 控制延迟），比整块淡入有版面感 */
/* 排版：字块用 inline-block，遮罩只负责竖向裁剪；白名辅助技术读屏 */
.hero__cn{display:flex;align-items:flex-end;min-height:1em}
.hero__cn span{display:block;overflow:hidden;line-height:.95;padding-bottom:.04em}
.hero__cn span i{display:block;font-style:normal;translate:0 100%;
  animation:charRise 1.05s var(--e-scroll) both;animation-delay:calc(.14s + var(--i,0) * .12s)}
@keyframes charRise{to{translate:0 0}}
/* eyebrow 前面那根线从 0 长出来，再向右滑出一段 */
.eyebrow{position:relative;padding-left:18px}
.eyebrow::before{content:"";position:absolute;left:0;top:50%;width:12px;height:1px;background:var(--gold);
  transform-origin:left;animation:lineGrow 1s var(--e-scroll) both .1s}
@keyframes lineGrow{from{transform:scaleX(0)}to{transform:scaleX(1)}}
/* 首屏元信息：底部细线随时间缓慢呼吸，暗示「本站还在跑」 */
.hero__scroll span::after{animation-duration:2.2s}
.hero__scroll{transition:opacity .4s}
.hero__scroll:hover{opacity:.55}
@media (prefers-reduced-motion:reduce){
  .hero__cn span i,.eyebrow::before{animation:none!important;translate:0 0;transform:none}
}

/* ---------------- 跑马灯 ---------------- */
.marquee{border-block:1px solid var(--line);overflow:hidden;padding:18px 0;background:var(--bg)}
.marquee__track{display:flex;width:max-content;animation:marquee var(--mq-dur,38s) linear infinite;will-change:transform;font:500 13px/1 var(--mono);letter-spacing:.28em;color:var(--faint);white-space:nowrap}
.marquee__group{display:flex;flex:none;gap:28px;padding-right:28px}
.marquee__track i{flex:none;width:5px;height:5px;border-radius:50%;background:var(--rose);align-self:center}
@keyframes marquee{to{transform:translate3d(-50%,0,0)}}

/* ---------------- 通用分区 ---------------- */
.section{padding:clamp(72px,10vw,128px) 0;position:relative}
.sec-head{display:grid;grid-template-columns:auto 1fr;align-items:baseline;column-gap:24px;row-gap:12px;margin-bottom:clamp(40px,6vw,72px);padding-bottom:24px;border-bottom:1px solid var(--line)}
.sec-no{font:500 13px/1 var(--mono);color:var(--rose);letter-spacing:.1em}
.sec-title{font:500 clamp(22px,3vw,32px)/1.2 var(--serif);letter-spacing:.06em}
.sec-title small{font:italic 400 .42em/1 Georgia,serif;color:var(--faint);letter-spacing:.04em;margin-left:10px}
.sec-desc{grid-column:2;color:var(--muted);font-size:15px}

/* 鼠标跟随光斑（双色渐变 + 色相持续流转，颜色每次悬停随机）
   与 newapi-home 同一套：JS 写 --spot/--spot2/--mx/--my，CSS 只管画 */
.spot::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;opacity:0;transition:opacity .25s ease;
  z-index:0;
  background:radial-gradient(240px circle at var(--mx,50%) var(--my,50%),
    var(--spot,var(--rose-18)) 0%,var(--spot2,var(--rose-08)) 45%,transparent 72%)}
/* 按钮类控件体积小，光斑半径要跟着缩，否则整颗按钮被一层平涂的色糊住 */
.btn.spot::before,.footer__act--solid.spot::before,.nav__cta.spot::before{
  background:radial-gradient(120px circle at var(--mx,50%) var(--my,50%),
    var(--spot,var(--rose-18)) 0%,var(--spot2,var(--rose-08)) 50%,transparent 78%)}
.spot:hover::before{opacity:1}
/* 光斑上方只抬高正文；装饰画布、箭头和涟漪保留自身的绝对定位。 */
.tile>*:not(.tile__fx):not(.tile__arrow):not(.ripple),.service>*:not(.ripple),
.btn>*:not(.ripple),.footer__act>*:not(.ripple){position:relative;z-index:1}

/* ---------------- 全局点击爆裂 ----------------
   15 种形态，形态名挂在 .burst[data-fx] 上，每个形态一套独立轨迹关键帧。
   全部用 translate/rotate/scale 独立属性，不和卡片的 transform 倾斜抢。 */
.burst{position:fixed;left:0;top:0;z-index:200;pointer-events:none;width:0;height:0;
  --c1:var(--rose);--c2:var(--gold)}
.burst__ring{position:absolute;left:0;top:0;width:14px;height:14px;margin:-7px 0 0 -7px;border-radius:50%;
  border:1px solid var(--bc,var(--c1));opacity:.9;
  animation:burstRing .66s cubic-bezier(.16,1,.3,1) var(--d,0ms) forwards}
@keyframes burstRing{
  0%{scale:.3;opacity:.85;border-width:1.5px}
  70%{opacity:.26}
  100%{scale:var(--rs,3.4);opacity:0;border-width:.5px}
}
.burst__core{position:absolute;left:0;top:0;width:6px;height:6px;margin:-3px 0 0 -3px;border-radius:50%;
  background:var(--bc,var(--c1));box-shadow:0 0 14px 3px var(--bc,var(--c1));
  animation:burstCore .42s ease-out forwards}
@keyframes burstCore{
  0%{scale:.5;opacity:1}
  100%{scale:var(--cs,3);opacity:0}
}
.burst__p{position:absolute;left:0;top:0;width:var(--sz,3px);height:var(--sz,3px);border-radius:50%;
  background:var(--bc,var(--c1));opacity:1;will-change:translate,scale,rotate;
  animation:burstFly var(--t,600ms) cubic-bezier(.12,.72,.2,1) var(--dl,0ms) forwards}

/* —— 默认：放射（ring / echo / prism 共用，靠 ring 圈数与配色区分） —— */
@keyframes burstFly{
  0%{translate:0 0;scale:1;opacity:1}
  62%{opacity:.9}
  100%{translate:var(--dx) var(--dy);scale:.2;opacity:0}
}
/* —— spark：锐利星火，细长拖尾 —— */
.burst[data-fx="spark"] .burst__p[data-k="line"]{height:2px;border-radius:1px;
  width:calc(var(--sz) * 3.4);transform-origin:0 50%}
@keyframes burstSpark{
  0%{translate:0 0;rotate:0deg;scale:1;opacity:1}
  100%{translate:var(--dx) var(--dy);rotate:0deg;scale:.15;opacity:0}
}
.burst[data-fx="spark"] .burst__p{animation-name:burstSpark}
/* —— petal：花瓣，先鼓起来再散开 —— */
.burst[data-fx="petal"] .burst__p{border-radius:60% 20% 60% 20%}
@keyframes burstPetal{
  0%{translate:0 0;scale:.2;rotate:0deg;opacity:0}
  22%{scale:1.3;opacity:1}
  100%{translate:var(--dx) var(--dy);scale:.5;rotate:var(--rot);opacity:0}
}
.burst[data-fx="petal"] .burst__p{animation-name:burstPetal}
/* —— shard：碎片，方块旋转飞出 —— */
.burst[data-fx="shard"] .burst__p{border-radius:1px}
@keyframes burstShard{
  0%{translate:0 0;scale:1.6;rotate:0deg;opacity:1}
  100%{translate:var(--dx) var(--dy);scale:.35;rotate:var(--rot);opacity:0}
}
.burst[data-fx="shard"] .burst__p{animation-name:burstShard}
/* —— orbit：沿切向绕出去 —— */
@keyframes burstOrbit{
  0%{translate:0 0;scale:.4;opacity:0}
  25%{opacity:1}
  60%{translate:var(--cx) var(--cy)}
  100%{translate:var(--dx) var(--dy);scale:.3;opacity:0}
}
.burst[data-fx="orbit"] .burst__p{animation-name:burstOrbit}
/* —— comet：单向扇面拖尾 —— */
.burst[data-fx="comet"] .burst__p{width:calc(var(--sz) * 2.6);height:2px;border-radius:1px;transform-origin:0 50%}
@keyframes burstComet{
  0%{translate:0 0;scale:.2;opacity:0}
  18%{scale:1;opacity:1}
  100%{translate:var(--dx) var(--dy);scale:1.6;opacity:0}
}
.burst[data-fx="comet"] .burst__p{animation-name:burstComet}
/* —— grid：十字四向 —— */
.burst[data-fx="grid"] .burst__p{border-radius:1px;height:calc(var(--sz) * .5)}
@keyframes burstGrid{
  0%{translate:0 0;scale:.6;opacity:1}
  50%{translate:calc(var(--dx) * .6) calc(var(--dy) * .6);opacity:1}
  100%{translate:var(--dx) var(--dy);scale:.2;opacity:0}
}
.burst[data-fx="grid"] .burst__p{animation-name:burstGrid}
/* —— rain：先上冲再落下 —— */
@keyframes burstRain{
  0%{translate:0 0;opacity:1}
  40%{translate:calc(var(--dx) * .5) calc(var(--dy) * .5 - 22px);opacity:1}
  100%{translate:var(--dx) calc(var(--dy) * .6 + 58px);scale:.4;opacity:0}
}
.burst[data-fx="rain"] .burst__p{animation-name:burstRain}
/* —— bubble：气泡上浮，边漂边涨—— */
.burst[data-fx="bubble"] .burst__p{background:transparent;border:1px solid var(--bc);
  box-shadow:inset 0 0 4px var(--bc)}
@keyframes burstBubble{
  0%{translate:0 0;scale:.2;opacity:0}
  25%{opacity:.95}
  100%{translate:var(--dx) calc(var(--dy) - 34px);scale:1.5;opacity:0}
}
.burst[data-fx="bubble"] .burst__p{animation-name:burstBubble}
/* —— star：六道长射线 —— */
.burst[data-fx="star"] .burst__p{height:2px;border-radius:1px;width:calc(var(--sz) * 4);transform-origin:0 50%}
@keyframes burstStar{
  0%{translate:0 0;scale:.1;opacity:0}
  15%{scale:1.2;opacity:1}
  100%{translate:var(--dx) var(--dy);scale:.4;opacity:0}
}
.burst[data-fx="star"] .burst__p{animation-name:burstStar}
/* —— confetti：彩纸，重力下坠 + 翻转 —— */
.burst[data-fx="confetti"] .burst__p{border-radius:1px;height:calc(var(--sz) * 1.5)}
@keyframes burstConfetti{
  0%{translate:0 0;rotate:0deg;scale:1;opacity:1}
  100%{translate:var(--dx) calc(var(--dy) + 46px);rotate:var(--rot);scale:.7;opacity:0}
}
.burst[data-fx="confetti"] .burst__p{animation-name:burstConfetti}
/* —— vortex：螺旋收尾 —— */
.burst[data-fx="vortex"] .burst__p{width:2px;height:2px;box-shadow:0 0 calc(var(--sz) * 3) var(--bc)}
@keyframes burstVortex{
  0%{translate:0 0;scale:1.6;opacity:0}
  20%{opacity:1}
  100%{translate:calc(var(--dx) + var(--cx)) calc(var(--dy) + var(--cy));scale:.15;opacity:0}
}
.burst[data-fx="vortex"] .burst__p{animation-name:burstVortex}
/* —— echo：一圈圈向外推（慢、扩散、长尾） —— */
@keyframes burstEcho{
  0%{translate:0 0;scale:1.4;opacity:1}
  100%{translate:calc(var(--dx) * 1.25) calc(var(--dy) * 1.25);scale:.05;opacity:0}
}
.burst[data-fx="echo"] .burst__p{animation-name:burstEcho}
/* —— prism：双色分裂，前半程一起、后半程岔开 —— */
@keyframes burstPrism{
  0%{translate:0 0;scale:1;opacity:1}
  45%{translate:calc(var(--dx) * .5) calc(var(--dy) * .5);scale:1.1}
  100%{translate:calc(var(--dx) * 1.3) calc(var(--dy) * 1.3);scale:.2;opacity:0}
}
.burst[data-fx="prism"] .burst__p{animation-name:burstPrism}
/* double：两圈环错时开，粒子走默认轨迹但时间抖得更开 */
.burst[data-fx="double"] .burst__p{border-radius:50%;
  box-shadow:0 0 6px -1px var(--bc)}
/* 实心按钮上爆裂用深色，避免白底看不见 */
.btn--solid .burst__p,.btn--solid .burst__ring,.btn--solid .burst__core{--bc:var(--ink-on-light)}

/* 局部涟漪：绝对定位，不参与宿主布局，也不撑高页面。
   · 卡片与胶囊由自身 overflow:hidden 裁剪；
   · 联系人这类纯文字入口不裁外框，改为圆形渐隐，散开时自然消失。 */
.ripple{position:absolute;border-radius:50%;pointer-events:none;transform:scale(0);opacity:1;
  background:var(--rose-18);animation:ripple .55s ease-out forwards;z-index:2}
@keyframes ripple{to{transform:scale(2);opacity:0}}
/* 文字入口的涟漪按径向渐隐，边缘不出现硬切 */
.rows a .ripple,.footer__links a .ripple{background:radial-gradient(circle,
  var(--rose-18) 0%,var(--rose-10) 52%,transparent 72%)}
/* 给涟漪留一个裁剪盒：文字入口不能用 overflow:hidden（下划线会被切），
   所以涟漪自己负责收敛，宿主只保证涟漪不覆盖相邻入口的点击。 */

/* 鼠标深度倾斜宿主：transform 由 JS 接管（perspective + rotateX/Y），这里只留过渡兜底 */
.tilt-host{transform-style:preserve-3d;will-change:transform}

/* 反「千篇一律的卡片」：服务区/实验室之外的普通卡片按位置错落 */
.card{position:relative;border:1px solid var(--line);border-radius:12px;background:var(--surface);overflow:hidden;
  transition:border-color .4s,background .4s,transform .5s var(--ease),box-shadow .5s}
.card:hover{border-color:var(--line-2);background:var(--surface-2)}

/* ---------------- 关于 ---------------- */
.about__grid{display:grid;grid-template-columns:minmax(220px,320px) 1fr;gap:clamp(32px,6vw,88px);align-items:center}
.about__avatar{position:relative;aspect-ratio:1;border-radius:12px;overflow:hidden;border:1px solid var(--line);background:var(--bg-2)}
.about__avatar img{width:100%;height:100%;object-fit:cover;filter:grayscale(.25) contrast(1.05);transition:filter .6s,transform 1.2s var(--ease)}
.about__avatar:hover img{filter:none;transform:scale(1.04)}
/* 头像加载失败兜底：无图时用一个「梦」字顶住版面 */
.about__avatar.is-fallback img{display:none}
.about__avatar.is-fallback::after{content:"梦";position:absolute;inset:0;z-index:0;display:grid;place-items:center;
  background:var(--surface-2);color:var(--rose);font:400 clamp(48px,7vw,76px)/1 var(--serif);letter-spacing:.06em}
.about__status{position:absolute;left:12px;bottom:12px;z-index:1;display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:999px;font-size:13px;background:var(--bg-70);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid var(--line)}
.about__status i{width:7px;height:7px;border-radius:50%;background:var(--ok);box-shadow:0 0 0 0 var(--ok-60);animation:pulse 2s infinite}
@keyframes pulse{70%{box-shadow:0 0 0 8px var(--ok-0)}100%{box-shadow:0 0 0 0 var(--ok-0)}}
.statement{font:400 clamp(21px,3vw,34px)/1.45 var(--serif);letter-spacing:.04em}
.lead{margin-top:28px;max-width:34em;color:var(--muted);font-size:15px}
/* 正文段落控制行宽（约 55–70 字符），容器本身吃满视口 */
.about__text{max-width:44em}
.sketch-mark{position:relative;display:inline-block;color:var(--rose);white-space:nowrap}
.sketch-mark svg{position:absolute;left:-18%;top:-22%;width:136%;height:144%;overflow:visible;pointer-events:none}
.sketch-mark svg path{stroke-dasharray:var(--len,600);stroke-dashoffset:var(--len,600);transition:stroke-dashoffset 1.4s var(--ease) .4s}
.sketch-mark.is-drawn svg path{stroke-dashoffset:0}

.services{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,1.8vw,26px);margin-top:clamp(56px,8vw,96px)}
/* 服务区反卡片：只用上边框 + 大序号，像一张技术档案的内页，不做圆角盒子 */
.service{padding:30px 0 0;border:0;border-top:1px solid var(--line-2);border-radius:0;background:none;overflow:visible;
  transition:border-color .45s,transform .5s var(--e-lift)}
.service::before{display:none}
.service:hover{border-top-color:var(--rose);background:none;translate:0 -3px}
.service__no{display:block;font:500 12px/1 var(--mono);color:var(--faint);letter-spacing:.12em;transition:transform .5s var(--e-lift),color .35s}
.service:hover .service__no{transform:translateX(4px);color:var(--rose)}
.service h3{margin:24px 0 12px;font:500 17px/1.4 var(--serif);letter-spacing:.04em;transition:letter-spacing .5s var(--e-lift)}
.service:hover h3{letter-spacing:.06em}
.service p{color:var(--muted);font-size:15px}
/* 序号作为背景纹理：与上边框拉开距离，只占右侧窄条，不侵入标题 */
.service{overflow:visible;padding-top:26px}
/* 数字退到最后层做纹理：只露出右端一点，标题始终完整可读 */
.service::after{content:attr(data-no);position:absolute;right:-6px;top:40px;
  font:300 clamp(26px,2.2vw,34px)/1 var(--serif);color:transparent;
  -webkit-text-stroke:1px var(--line);pointer-events:none;opacity:.6;z-index:0;
  transition:opacity .5s,translate .5s var(--e-lift)}
.service:hover::after{opacity:1;translate:0 -3px}
/* 文字压在数字之上；标题与正文右侧留出数字宽度。
   用 px 而非 em —— em 相对正文字号（17px）算，抵不住 34px 的描边数字。 */
.service__no,.service h3,.service p{position:relative;z-index:1}
.service h3{padding-right:48px}
.service p{padding-right:40px}

/* ---------------- 战斗力 ---------------- */
.power{background:linear-gradient(180deg,transparent,var(--sea-08) 50%,transparent)}
.power__grid{display:grid;grid-template-columns:1.15fr 1fr;gap:clamp(24px,4vw,56px);align-items:center}
/* 雷达站在一块「月光水面」上：径向光晕 + 底部反射，给它一个空间归属 */
.radar{margin:0;position:relative;padding:clamp(8px,2vw,24px) 0 clamp(24px,4vw,44px)}
.radar::before{content:"";position:absolute;left:50%;top:52%;transform:translate(-50%,-50%);width:min(96%,560px);aspect-ratio:1;pointer-events:none;
  background:radial-gradient(circle,var(--rose-10),transparent 62%);filter:blur(6px)}
.radar::after{content:"";position:absolute;left:12%;right:12%;bottom:clamp(14px,3vw,30px);height:1px;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--rose-18),transparent);box-shadow:0 0 24px 2px var(--rose-08)}
/* 宽高比由 JS 按 viewBox 写入（svg.style.aspectRatio）。
   这里不要写死 —— 写死会覆盖 JS 的值，导致图被拉高、上下留一大片空。 */
.radar svg{position:relative;width:100%;display:block;overflow:visible;filter:drop-shadow(0 18px 30px var(--bg));
  animation:radarFloat 7s ease-in-out infinite;transform-origin:50% 52%}
/* 整体缓慢起伏 + 极轻微摆动：雷达「活着」，而不是一张打印图 */
@keyframes radarFloat{
  0%,100%{translate:0 0;rotate:0deg}
  35%{translate:0 -7px;rotate:-.35deg}
  70%{translate:0 4px;rotate:.3deg}
}
/* 轴点脉冲：每个顶点自己呼吸，错开相位 */
.radar .pt{transform-box:fill-box;transform-origin:center;animation:ptPulse 3.4s ease-in-out infinite}
@keyframes ptPulse{
  0%,100%{scale:1;opacity:.9}
  50%{scale:1.55;opacity:1}
}
/* 悬停某条轴：标签提亮、对应顶点放大 */
.radar text{transition:fill .3s,opacity .3s}
.radar:hover text{opacity:.55}
.radar text.is-hot{fill:var(--rose)!important;opacity:1!important}
.radar:hover .pt{animation-play-state:paused}
.radar .pt.is-hot{animation:none;scale:1.9;opacity:1}
@media (prefers-reduced-motion:reduce){
  .radar svg,.radar .pt{animation:none!important}
}
.radar svg text{font:var(--rf,16px) var(--sans);fill:var(--muted)}
.radar figcaption{position:relative;margin-top:clamp(10px,1.4vw,16px);text-align:center;
  font:italic 13px Georgia,var(--serif);color:var(--faint);letter-spacing:.04em}
/* 统计条：整列吃满雷达的高度，9 行均分。
   原来 1/3/5 这类小值的条宽按 --v 线性算，几乎等于没有，整列看着稀。
   现在加一条可见下限（--bw 由 JS 按 0–100 → 8%–100% 归一），
   数据真值仍显示在右侧数字上，条形只负责「读得出长短」。 */
/* 统计条：九行均分，但不再用 space-between 硬撑满整列 ——
   那样在宽屏上每行之间会拉开一大截空气，读起来散。
   改成 margin-top:auto 把整列压在雷达中线附近，行距由 gap 控制。 */
.skills{counter-reset:s;display:flex;flex-direction:column;justify-content:center;
  gap:clamp(2px,.45vw,6px);height:100%;min-height:0}
.skills li{counter-increment:s;display:grid;grid-template-columns:26px 1fr auto;grid-template-rows:auto 5px;
  align-items:center;column-gap:10px;row-gap:6px;padding:8px 10px 11px;position:relative;border-radius:8px;
  transition:background .35s,transform .45s var(--e-lift)}
/* 逐条右滑让位 + 底色渐入：这一列是「列表」，不装成卡片 */
.skills li:hover{background:linear-gradient(90deg,var(--rose-08),transparent 82%);transform:translateX(6px)}
.skills li::before{content:counter(s,decimal-leading-zero);grid-row:1;font:11px var(--mono);color:var(--faint);letter-spacing:.06em;transition:color .3s}
.skills li:hover::before{color:var(--rose)}
.skills li span{grid-row:1;font-size:14px;letter-spacing:.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.skills li b{grid-row:1;font:500 13px var(--mono);color:var(--muted);font-variant-numeric:tabular-nums;letter-spacing:.04em}
.skills li.is-hot b{color:var(--rose)}
/* 轨道：垫一条极淡底槽，短的条也能看出「这是进度」而不是一根断线。
   em 用绝对定位贴在 li 底部，避开 grid 轨道分配（1fr 列不给跨列元素宽度）。 */
.skills li::after{content:"";position:absolute;left:10px;right:10px;bottom:5px;height:5px;border-radius:99px;
  background:var(--ink-06)}
.skills li em{position:absolute;left:10px;bottom:5px;height:5px;border-radius:99px;
  width:calc((100% - 20px) * var(--bw,8) / 100);min-width:10px;
  background:linear-gradient(90deg,var(--rose),var(--gold));
  transform:scaleX(0);transform-origin:left;
  transition:transform 1.25s var(--e-scroll) calc(var(--i,0) * 62ms)}
.skills.is-in li em{transform:scaleX(1)}
.skills li.is-hot em{background:linear-gradient(90deg,var(--rose),var(--rose));box-shadow:0 0 12px -2px var(--rose-60)}


/* ---------------- 实验室 ----------------
   设计目标（按用户要求）：
   1. 卡片要有大小变化，不能清一色；
   2. 手机不能因为卡片太高把页面拉长；
   3. 增删链接、替换链接内容，都不许出现错位或空洞；
   4. 不把某个格子写死成「只有它最大」。

   做法：**尺寸由位置决定，不由 class 决定**。
   - 列数交给 auto-fit + minmax，屏幕窄自动少列，不需要写断点；
   - 第 1、6、11… 张用 nth-child(6n+1) 自动跨两列，形成「大-小-小」的节奏，
     增删任意一张，节奏自动重排，绝不会因为手写 class 而错位；
   - 高度用 aspect-ratio 控制比例，比 min-height 更不容易把手机页面拉长；
   - 所有卡片语义只靠 .tile 一个类，换链接、换内容都不用动 class。 */
.lab__grid{
  display:grid;
  /* 下限 170px、上限 4 列：卡片够小才放得下 4 列，宽屏也不会变成 6 列
     （列数一多，首张跨 2 列的节奏就会留空）。 */
  /* minmax 下限决定能塞几列：240px 起步时 1440 宽只能放 4 列，不会挤成 5 列；
     窄屏自动降为 3 / 2 列，不需要写断点。 */
  grid-template-columns:repeat(auto-fit,minmax(clamp(180px,17vw,240px),1fr));
  /* 不要 grid-auto-rows:1fr —— 它会把行高平均分配给所有行，
     列数变少时每一行被撑得很高，手机/平板上尤其明显（正是「页面被拉长」的来源）。
     高度交给卡片自己的 min-height + align-items 决定。 */
  align-items:start;
  gap:clamp(14px,1.5vw,22px);
}
.tile{display:flex;flex-direction:column;padding:clamp(16px,1.6vw,24px);position:relative;
  border:1px solid var(--line);border-radius:14px;background:var(--surface);overflow:hidden;
  /* 高度交给网格行（auto-rows:1fr）+ 最小高度兜底：
     比 aspect-ratio 更可控 —— 手机上一行不会因为宽高比被撑得很高把页面拉长 */
  min-height:clamp(132px,14vw,168px);
  /* 双层：内侧一道亮边给出「上面有光」，外投影把它从背景里托起来 */
  box-shadow:0 1px 0 var(--ink-06) inset,0 20px 34px -26px var(--bg),0 3px 10px -6px var(--bg);
  transition:background .45s,border-color .45s,box-shadow .45s}
/* 首张「重点卡」：只加高、不跨行、不跨列。
   试过跨列和跨行两种方案，都会在「张数除不尽列数」时留白：
   · 5 张 + 4 列 + 首张跨 2 列 → 总格数 6，第二行空 3 格；
   · 5 张 + 4 列 + 首张跨 2 行 → 第二行没有卡，首张下沿悬空。
   只改高度就永远不会留白：同一行的其它卡被 align-self:stretch 拉齐，
   视觉上就是「一张大卡带着几张小的」。位置驱动，增删无需改 class。 */
.tile:nth-child(6n+1){min-height:clamp(196px,22vw,260px);padding:clamp(18px,1.9vw,28px)}
.tile:nth-child(6n+1) h3{font-size:clamp(18px,1.9vw,23px)}
/* 同一行其它卡拉到与首张齐平，避免「一大一小、底部参差」 */
.tile{align-self:stretch}
/* 只有一张时不该加高 */
.tile:only-child{min-height:clamp(132px,14vw,168px)}
.tile::before{content:"";position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .45s;
  background:radial-gradient(120% 100% at 0% 100%,var(--rose-10),transparent 62%)}
.tile:hover{background:var(--surface-2);border-color:var(--line-2);box-shadow:0 1px 0 var(--line) inset,0 26px 48px -30px var(--bg)}
.tile:hover::before{opacity:1}
.tile:active{scale:.985;background:var(--surface-2)}
.tile__tag{font:500 11px/1 var(--mono);letter-spacing:.2em;text-transform:uppercase;color:var(--gold);
  /* 标签给箭头留出位置；过长的英文标签自动截断，不会顶到箭头上 */
  max-width:calc(100% - 40px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:letter-spacing .45s var(--e-lift),color .3s}
.tile h3{margin-top:auto;font:500 clamp(16px,1.4vw,18px)/1.35 var(--serif);letter-spacing:.04em;
  /* 标题最多两行：换成更长的名字也不会把整张卡的节奏打乱 */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.tile p{margin-top:8px;font-size:13.5px;color:var(--muted);line-height:1.6;
  /* 描述最多两行，超出省略号：内容随便换都不会挤坏版式 */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* 放大格的字号跟着大一号，但用 clamp 封顶，避免窄屏上过大 */
.tile:nth-child(6n+1) h3{font-size:clamp(18px,1.9vw,23px)}
.tile:nth-child(6n+1) .tile__tag{letter-spacing:.26em}
.tile:nth-child(6n+1):hover .tile__tag{letter-spacing:.34em;color:var(--rose)}
/* 箭头绝对定位到右上角；z-index 保证不落到内容层下面 */
.tile__arrow{position:absolute;top:clamp(14px,1.4vw,20px);right:clamp(14px,1.4vw,22px);
  left:auto;bottom:auto;width:20px;height:20px;z-index:2;color:var(--faint);
  transition:transform .5s var(--e-lift),color .3s}
.tile:hover .tile__arrow{color:var(--rose);transform:translate(3px,-3px)}
.tile__fx{position:absolute;inset:0;width:100%;height:100%;z-index:0;pointer-events:none;border-radius:inherit}
/* 位移量由 JS 按「离视口中心的距离」写进 --py，卡片不等速上浮＝滚动时有纵深 */
.tile,.service{translate:0 var(--py,0px)}

/* ---------------- 控件持续浮动（不规则、不同步） ----------------
   「没有交互的控件」要有活气：每类控件一组不同的振幅/周期/相位，
   像漂浮在水面上，各自按各自节奏呼吸。用 rotate+translate 独立属性，
   与 tilt 的 transform、滚动视差的 --py 三者互不干扰。 */
@keyframes floatA{
  0%,100%{translate:0 var(--py,0px) ;rotate:0deg}
  33%{translate:0 calc(var(--py,0px) - 5px);rotate:-.28deg}
  66%{translate:0 calc(var(--py,0px) + 3px);rotate:.22deg}
}
@keyframes floatB{
  0%,100%{translate:0 var(--py,0px);rotate:0deg}
  40%{translate:0 calc(var(--py,0px) + 4px);rotate:.34deg}
  75%{translate:0 calc(var(--py,0px) - 6px);rotate:-.2deg}
}
@keyframes floatC{
  0%,100%{translate:0 var(--py,0px);rotate:0deg}
  50%{translate:0 calc(var(--py,0px) - 4px);rotate:-.18deg}
}
/* 磁贴与服务项各自浮动，文字链接不参与整项漂浮。 */
.lab__grid .tile{animation:floatA 9.5s ease-in-out infinite;animation-delay:-1.2s}
.lab__grid .tile:nth-child(3n+2){animation-name:floatB;animation-duration:11s;animation-delay:-3.4s}
.lab__grid .tile:nth-child(3n+3){animation-name:floatC;animation-duration:8.2s;animation-delay:-5.1s}
.service{animation:floatB 10.5s ease-in-out infinite;animation-delay:-2.6s}
.service:nth-child(2){animation-name:floatC;animation-duration:9s;animation-delay:-4.8s}
.service:nth-child(3){animation-name:floatA;animation-duration:12s;animation-delay:-1.8s}
.about__avatar{animation:floatC 13s ease-in-out infinite}
.footer__poem{animation:floatC 14s ease-in-out infinite}
/* 悬停/按压时暂停自漂，避免和用户操作打架 */
.tile:hover,.tile:active,.service:hover{animation-play-state:paused}
@media (prefers-reduced-motion:reduce){
  .tile,.service,.about__avatar,.footer__poem{animation:none!important}
}

/* ---------------- 日常出没：图标文字流 + 悬停跳动 ---------------- */
.contact{padding-bottom:clamp(40px,5vw,72px)}
.contact .sec-head{margin-bottom:clamp(24px,3vw,40px)}
/* 入口按文字宽度自然换行；每个入口自己承担跳动，容器不做整体位移。 */
.rows{display:flex;flex-wrap:wrap;align-items:center;
  gap:6px clamp(18px,2.6vw,34px);padding:0 0 2px}
.rows li{min-width:0;max-width:100%;--social-color:var(--rose)}
.rows li:nth-child(3n+2){--social-color:var(--sea)}
.rows li:nth-child(3n){--social-color:var(--gold)}
.rows a{position:relative;display:inline-flex;align-items:center;gap:10px;
  min-height:44px;max-width:100%;padding:6px 0;color:var(--text);
  transition:color .25s,translate .4s var(--e-lift)}
.rows__icon{display:flex;align-items:center;flex:none;color:var(--social-color);
  transition:color .25s,transform .4s var(--e-lift)}
.rows__icon .i{width:23px;height:23px;stroke-width:1.5}
.rows__body{display:flex;flex-wrap:wrap;align-items:baseline;gap:5px 12px;min-width:0}
.rows__k{position:relative;font:500 clamp(18px,1.45vw,21px)/1.5 var(--serif);
  letter-spacing:.02em;white-space:nowrap;transition:color .25s}
.rows__k::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:var(--social-color);transform:scaleX(0);transform-origin:left;transition:transform .35s var(--ease)}
.rows__v{font-size:12px;line-height:1.5;color:var(--faint);overflow-wrap:anywhere;transition:color .25s}
/* 悬停：整项抬起 3px，文字名起一下再落回，图标短暂弹开 —— 有「蹦」的轻快感，
   但用 translate/rotate 独立属性，不碰入场与 tilt 的 transform。 */
.rows a:hover,.rows a:focus-visible{translate:0 -3px}
.rows a:hover .rows__icon,.rows a:focus-visible .rows__icon{color:var(--text);transform:translateY(-2px) rotate(-6deg)}
.rows a:hover .rows__k,.rows a:focus-visible .rows__k,.rows a:active .rows__k{color:var(--social-color)}
.rows a:hover .rows__k,.rows a:focus-visible .rows__k{animation:rowJump .5s var(--e-lift)}
.rows a:hover .rows__v,.rows a:focus-visible .rows__v{color:var(--muted)}
.rows a:hover .rows__k::after,.rows a:focus-visible .rows__k::after,.rows a:active .rows__k::after{transform:scaleX(1)}
.rows a:active{translate:0 1px}
.rows a:active .rows__icon{transform:translateY(1px)}
@keyframes rowJump{
  0%{translate:0 0}
  35%{translate:0 -3px}
  100%{translate:0 0}
}

/* ---------------- 友情链接：胶囊标签云 + 悬停跳动 ---------------- */
.friends{padding-top:clamp(40px,5vw,72px);padding-bottom:clamp(56px,7vw,96px)}
.friends .sec-head{margin-bottom:clamp(24px,3vw,40px)}
/* 胶囊按内容宽度换行；悬停时单个胶囊跳起、描边收紧、箭头弹出。 */
.fl{display:flex;flex-wrap:wrap;align-items:center;gap:12px 10px}
.fl li{min-width:0;max-width:100%;--friend-color:var(--rose)}
.fl li:nth-child(3n+2){--friend-color:var(--gold)}
.fl li:nth-child(3n){--friend-color:var(--sea)}
.fl a{position:relative;display:inline-flex;align-items:center;gap:9px;max-width:100%;min-height:44px;
  padding:9px 18px;border:1px solid color-mix(in srgb,var(--friend-color) 26%,transparent);border-radius:999px;
  background:color-mix(in srgb,var(--friend-color) 7%,transparent);overflow:hidden;isolation:isolate;
  transition:background .25s,border-color .25s,color .25s,translate .4s var(--e-lift),
    box-shadow .4s var(--e-lift)}
.fl a>*:not(.ripple){position:relative;z-index:1}
.fl__name{min-width:0;font:500 clamp(15px,1.15vw,16.5px)/1.4 var(--serif);letter-spacing:.025em;white-space:nowrap}
.fl__host{font:10.5px/1.4 var(--mono);color:var(--faint);white-space:nowrap;transition:color .25s}
.fl a:hover,.fl a:focus-visible{translate:0 -3px;color:var(--friend-color);
  border-color:color-mix(in srgb,var(--friend-color) 52%,transparent);
  background:color-mix(in srgb,var(--friend-color) 11%,transparent);
  box-shadow:0 12px 24px -16px color-mix(in srgb,var(--friend-color) 70%,transparent)}
.fl a:hover .fl__name,.fl a:focus-visible .fl__name{animation:capHop .5s var(--e-lift)}
.fl a:hover .fl__host,.fl a:focus-visible .fl__host{color:color-mix(in srgb,var(--friend-color) 62%,var(--faint))}
.fl a:hover .fl__go,.fl a:focus-visible .fl__go{opacity:1;transform:translate(2px,-2px)}
.fl a:active{translate:0 1px;background:color-mix(in srgb,var(--friend-color) 16%,transparent);
  box-shadow:none}
@keyframes capHop{
  0%{translate:0 0}
  35%{translate:0 -4px}
  100%{translate:0 0}
}

@media (max-width:900px){
  /* 名称已足够辨认入口；小字仍保留供辅助阅读。 */
  .fl a .fl__host{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap}
}
@media (max-width:700px){
  .contact .sec-head{margin-bottom:18px}
  .rows{gap:2px 14px}
  .rows a{gap:7px;min-height:40px}
  .rows__icon .i{width:19px;height:19px}
  .rows__k{font-size:15.5px;letter-spacing:0}
  .rows__v{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap}
  .friends{padding-top:32px}
  .friends .sec-head{margin-bottom:18px}
  .fl{gap:8px}
  .fl a{gap:6px;padding:8px 13px;min-height:40px}
  .fl__name{font-size:14px;letter-spacing:0}
  .fl__go{width:12px;height:12px}
}
/* 最窄一档：入口再收一点，避免每行只放一两个、末端留半截空位 */
@media (max-width:360px){
  .rows{gap:0 12px}
  .rows a{gap:6px;min-height:38px}
  .rows__icon .i{width:18px;height:18px}
  .rows__k{font-size:14.5px}
  .contact .sec-head{margin-bottom:14px}
}
/* 触屏没有 hover：用按压时的轻微下压代替跳动，尺寸不放大。 */
@media (hover:none){
  .rows a:active{translate:0 1px}
  .fl a:active{translate:0 1px}
}

/* —— 手机（≤640）：技能使用细进度线与数字，保持紧凑的列表层级。 */
@media (max-width:640px){
  .power__grid{grid-template-columns:1fr;gap:clamp(16px,3.4vw,22px)}
  .skills{display:flex;flex-direction:column;justify-content:flex-start;
    gap:0;height:auto;border:0;background:none;border-radius:0;overflow:visible}
  .skills li{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto 3px;
    align-items:baseline;column-gap:10px;row-gap:8px;
    padding:11px 0 12px;border:0;border-bottom:1px solid var(--line);
    border-radius:0;background:none}
  .skills li:last-child{border-bottom:0}
  /* 序号很淡、很小，只做锚点，不参与阅读节奏 */
  .skills li::before{grid-row:1;grid-column:1;font-size:10px;color:var(--faint);
    opacity:.5;letter-spacing:.08em;align-self:center;margin-right:8px;display:inline}
  .skills li span{grid-row:1;grid-column:1;font-size:14px;line-height:1.35;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    /* 名称左移，给序号腾出位置（序号是绝对定位会更简单，但这里保持网格语义） */
    padding-left:26px;text-overflow:ellipsis}
  .skills li b{grid-row:1;grid-column:2;font:500 14px var(--mono);
    font-variant-numeric:tabular-nums;letter-spacing:.02em}
  /* 进度线：2px，通栏，无圆角 —— 像刻度尺，而不是胶囊 */
  .skills li::after{left:26px;right:0;bottom:3px;height:2px;border-radius:0;
    background:var(--ink-06)}
  .skills li em{left:26px;bottom:3px;height:2px;border-radius:0;
    width:calc((100% - 26px) * var(--bw,8) / 100);min-width:6px}
  .skills li:hover{transform:none;background:none}
  .skills li:hover::before{color:var(--rose);opacity:1}
}

/* ---------------- 页脚 ---------------- */
/* ---------------- 页脚 · 收尾区 ----------------
   结构：左侧落款（诗 + 出处）、右侧收尾 CTA、最右一列竖排印记。
   诗不是主角，而是「题跋」——有出处、有语气，就不会空。 */
.footer{position:relative;padding:clamp(64px,8vw,112px) 0 calc(28px + env(safe-area-inset-bottom));border-top:1px solid var(--line);overflow:hidden;
  background:radial-gradient(60% 80% at 50% 120%,var(--rose-10),transparent 70%)}
/* 底部月晕：一大一小两层，把纯黑托起来；居中偏下，让整体有「沉入水面」感 */
.footer__glow{position:absolute;left:50%;bottom:-52%;width:min(1400px,150%);aspect-ratio:1;translate:-50% 0;pointer-events:none;
  background:radial-gradient(circle,var(--rose-18) 0%,var(--rose-08) 40%,transparent 70%);filter:blur(14px);opacity:.6}
.footer__glow::after{content:"";position:absolute;inset:22%;border-radius:50%;
  background:radial-gradient(circle,var(--gold) 0%,transparent 58%);opacity:.16}

/* 宽屏三栏：题跋 / 收尾 / 印记，底栏占满整行。
   grid-template-areas 在这里就定义好，断点里只改「列数 + 区域排布」，
   避免某个断点忘了给某个块指定区域、被自动放置挤到错误位置。 */
/* 宽屏三栏：题跋 / 收尾 / 竖排印记，底栏独占整行。
   注意竖排印记天然很高（MENGYU + 兴趣所致 约 250px），若让它和生活 CTA 同处一行，
   会把整行撑到 260px 以上、CTA 下方留出一大片空 —— 所以：
   · 印记只占第 1 行、顶对齐，行高由左侧题跋和 CTA 决定；
   · 底栏用 grid-area:bar 独占第 2 行，不受印记高度影响。
   这样既保留截图里「最右一列竖排」的观感，页脚也不会被它撑开。 */
.footer__inner{position:relative;display:grid;
  grid-template-columns:minmax(0,.95fr) minmax(0,1.4fr) auto;
  grid-template-areas:"note cta seal" "bar bar bar";
  grid-template-rows:auto auto;
  gap:clamp(24px,3vw,40px) clamp(32px,4.4vw,72px);align-items:start}
.colophon{grid-area:note}
.footer__aside{grid-area:cta;align-self:center}
/* 竖排印记：独立一列，上下各一根渐隐线，把右边收住 */
.footer__seal{grid-area:seal;align-self:start;
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
  gap:12px;min-width:1.6em;padding:2px 0}
.footer__seal b,.footer__seal span{writing-mode:vertical-rl}
.footer__seal b{font:500 12px/1 var(--mono);letter-spacing:.34em}
.footer__seal span{font:400 12px/1 var(--serif);letter-spacing:.24em}
.footer__seal-line{width:1px;height:clamp(24px,3vw,44px);min-height:0;flex:0 0 auto;
  background:linear-gradient(var(--line-2),transparent)}
.footer__seal-line:last-child{background:linear-gradient(transparent,var(--line-2))}
.footer__bar{grid-area:bar}

/* —— 落款 —— */
.colophon{display:flex;flex-direction:column;justify-content:flex-start}
.colophon__label{font:500 11px/1 var(--mono);letter-spacing:.3em;color:var(--faint);text-transform:uppercase}
.colophon__label span{display:inline-flex;align-items:center;gap:10px}
.colophon__label span::after{content:"";width:34px;height:1px;background:var(--line-2)}
.footer__poem{margin-top:18px;font:400 clamp(19px,2.2vw,28px)/1.55 var(--serif);letter-spacing:.1em;color:var(--text)}
.footer__poem span{display:block;white-space:nowrap}
.footer__poem span:last-child{color:var(--muted)}
.colophon__meta{margin-top:20px;display:flex;align-items:center;flex-wrap:wrap;gap:10px;font-size:12px;color:var(--faint);letter-spacing:.08em}
.colophon__meta i{width:3px;height:3px;border-radius:50%;background:var(--line-2);display:block}

/* —— 中间列：两块落款式条目（谈项目 / 看看别的）——
   不并排三个胶囊，改成两段上下相接的短文：
   细线 + 小字标签 + 一行标题 + 一行说明 + 一枚入口。
   左列题跋、右列竖排印记的位置与列宽都不动。 */
.footer__aside{grid-area:cta;align-self:center;display:flex;flex-direction:column;
  gap:clamp(18px,2.2vw,28px);min-width:0}

/* PC：文案在左、入口在右 —— 客服回到右侧，与两块文案并排收口 */
.footer__row{display:grid;grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"kicker kicker" "title act" "desc act";
  column-gap:clamp(16px,2.4vw,32px);row-gap:6px;align-items:center;
  padding-top:clamp(12px,1.6vw,18px);border-top:1px solid var(--line)}
.footer__row:first-child{border-top:0;padding-top:0}

/* 与题跋「题跋」同一套笔法：等宽小字 + 一条短横线 */
.footer__kicker{grid-area:kicker;display:flex;align-items:center;gap:9px;
  font:500 10.5px/1 var(--mono);letter-spacing:.26em;color:var(--faint);text-transform:uppercase}
.footer__kicker span{color:var(--muted);letter-spacing:.2em}
.footer__kicker::after{content:"";width:26px;height:1px;background:var(--line-2)}

.footer__t{grid-area:title;font:500 clamp(15px,1.5vw,17px)/1.45 var(--serif);
  letter-spacing:.05em;color:var(--text);white-space:nowrap}
.footer__d{grid-area:desc;font-size:12.5px;line-height:1.65;color:var(--faint);max-width:26em}

/* 入口基类：胶囊形态的承载者，跳动与光感都挂在这里 */
.footer__act{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  flex:0 0 auto;white-space:nowrap;min-height:44px;padding:0 18px;border-radius:999px;
  font-family:var(--sans);font-size:13.5px;font-weight:500;letter-spacing:.02em;line-height:1;
  transition:color .3s,background .3s,border-color .3s,translate .3s var(--e-lift),box-shadow .3s}
.footer__act:active{translate:0 var(--press-y);scale:.985;box-shadow:none}

.footer__acts{grid-area:act;justify-self:end;display:flex;align-items:center;gap:8px;flex-wrap:wrap}

/* 博客 / 咖啡：恢复原来的描边胶囊 —— 一个中性、一个金色 */
.footer__act--pill{grid-area:act;justify-self:end}
.footer__act--pill:first-child{color:var(--text);background:var(--surface);border:1px solid var(--line-2)}
.footer__act--pill:first-child:hover{color:var(--bg);background:var(--text);border-color:var(--text);
  translate:0 -3px;box-shadow:0 10px 24px -12px var(--rose-60)}
.footer__act--pill .i{opacity:.75;transition:opacity .3s,transform .4s var(--e-lift)}
.footer__act--pill:first-child:hover .i{opacity:1;transform:translate(2px,-2px)}
.footer__act--gold{color:var(--gold);background:var(--gold-10);border:1px solid var(--gold-30)}
.footer__act--gold:hover{color:var(--bg);background:var(--gold);border-color:var(--gold);
  translate:0 -3px;box-shadow:0 10px 24px -12px var(--gold-60)}
.footer__act--gold .i{opacity:.9;color:currentColor;transition:rotate .4s var(--e-lift)}
.footer__act--gold:hover .i{rotate:-8deg;opacity:1}

/* 胶囊悬停：文字名起一下再落回，和联系人、友链同一套「蹦」的语汇 */
.footer__act--pill:hover{animation:capHop .5s var(--e-lift)}
.footer__act--solid:hover{animation:capHop .5s var(--e-lift)}

/* 客服：唯一实心入口，玫瑰色压住整块；PC 上单独待在右侧 */
.footer__act--solid{color:var(--ink-on-light);background:var(--rose);
  box-shadow:inset 0 -2px 0 var(--line-2)}
.footer__act--solid .i{opacity:.9;color:var(--ink-on-light)}
.footer__act--solid:hover{background:var(--cream);color:var(--ink-on-light);
  translate:0 -3px;box-shadow:0 12px 28px -14px var(--rose-60),inset 0 -2px 0 var(--line)}
.footer__act--solid:hover .i{opacity:1;transform:none}

/* —— 印记 ——
   位置、方向统一在上面的 .footer__inner 区域里定义（横排、与题跋同列），
   这里只补颜色与字重，避免两处 rule 互相覆盖导致「看着像改了其实没生效」。 */
.footer__seal{color:var(--faint)}
.footer__seal b{color:var(--rose);opacity:.85}

/* —— 底栏 ——
   原来用 `justify-content:space-between` + `flex-wrap`：一旦放不下，中间那块
   先被挤到第二行，版权和运行时长跟着错位，于是同一屏出现两行、三行、甚至一链接一行。
   现在三块各自成组、互不拆散；链接做成不可断的「芯片」，换行只发生在芯片之间。 */
.footer__bar{margin-top:clamp(40px,5vw,64px);padding-top:clamp(22px,2.6vw,30px);border-top:1px solid var(--line);grid-column:1/-1;
  display:flex;flex-wrap:wrap;align-items:center;gap:14px 28px;
  font-size:13px;color:var(--faint);letter-spacing:.02em}
.footer__copy{white-space:nowrap;font-variant-numeric:tabular-nums}
/* 版权里的「梦屿」可点：原地跳回站点根路径。
   做成网址式的「悬停下划线 + 颜色微亮」，而不是按钮，避免底栏多出一个控件。 */
.footer__brand{position:relative;color:var(--text);transition:color .3s}
.footer__brand::after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:1px;
  background:currentColor;opacity:.35;transform:scaleX(1);transform-origin:left;
  transition:opacity .3s,transform .35s var(--e-lift)}
.footer__brand:hover{color:var(--rose)}
.footer__brand:hover::after{opacity:.7}
.footer__brand:focus-visible{outline:1px solid var(--rose);outline-offset:3px;border-radius:2px}
/* 备案列表：把每条当作独立单元，内部绝不折行 */
.footer__links{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px;margin-left:auto}
.footer__links a{position:relative;white-space:nowrap;padding:4px 0;transition:color .3s}
/* 下划线只在文字下方生长，不占位、不撑高 */
.footer__links a::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:var(--rose);transform:scaleX(0);transform-origin:left;transition:transform .35s var(--e-lift)}
.footer__links a:hover{color:var(--text)}
.footer__links a:hover::after{transform:scaleX(1)}
/* 运行时长：单独成组，数字用等宽字保证不跳动 */
.footer__uptime{white-space:nowrap;color:var(--muted);font-variant-numeric:tabular-nums;
  padding:5px 14px;border:1px solid var(--line);border-radius:999px;background:var(--bg-25);
  display:inline-flex;align-items:center;gap:7px;width:max-content;max-width:100%}
/* 小圆点：表示「还在跑」，比纯文字更有存在感 */
.footer__uptime::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--ok);
  box-shadow:0 0 0 0 var(--ok-60);animation:livePulse 2.6s ease-out infinite}
@keyframes livePulse{
  0%{box-shadow:0 0 0 0 var(--ok-60)}
  70%{box-shadow:0 0 0 6px transparent}
  100%{box-shadow:0 0 0 0 transparent}
}

/* 底栏按「内容能不能放下」分三档，而不是按看起来大概的宽度。
   ≥1080：三块一行，备案居中、时长靠右。
   720–1080：版权 + 备案一行，运行时长单独居中一行（避免被挤到角落）。
   <720：全部居中竖排，运行时长单独一行居中。 */
@media (max-width:1080px){
  /* 不用 space-between 顶两头：那样版权与备案之间会出现一段莫名的大空隙 */
  .footer__bar{gap:14px 24px}
  .footer__links{margin-left:auto}
  /* 运行时长独占一行并居中，但宽度跟随内容（flex-basis:100% 会把它拉成通栏） */
  .footer__uptime{order:3;flex:0 0 auto;align-self:center;margin:2px 0 0}
}
@media (max-width:720px){
  .footer__bar{flex-direction:column;align-items:center;justify-content:center;
    text-align:center;gap:16px;padding-top:24px}
  .footer__copy{order:1}
  /* 手机上三条备案尽量压进一行：字号收到 12、间距收到 12，
     放不下时让「备案号」和「签章」自然分两行，而不是把某一条从中间劈开 */
  .footer__links{order:2;justify-content:center;gap:6px 12px;flex-basis:auto;width:100%}
  .footer__links a{font-size:12px;letter-spacing:0;padding:2px 0}
  .footer__uptime{order:3;flex-basis:auto;margin:4px auto 0}
}
/* 1240 以下：三栏挤不下，但印记要保持「右侧竖排」这个识别特征。
   做法：右侧留一条窄轨道专供印记（auto 列），内容仍按两栏排；
   竖排只在竖直方向占地方、横向只占 1.6em，不会挤压正文。 */
@media (max-width:1240px){
  .footer__inner{grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr) auto;
    grid-template-areas:"note cta seal" "bar bar bar";
    gap:clamp(18px,2.4vw,28px) clamp(24px,3.4vw,44px)}
  .footer__aside{align-self:center}
  .footer__seal{grid-area:seal;align-self:start;
    flex-direction:column;align-items:center;gap:10px;min-width:1.4em;padding:0}
  .footer__seal b,.footer__seal span{writing-mode:vertical-rl}
  .footer__seal-line{width:1px;height:clamp(18px,3vw,32px);
    background:linear-gradient(var(--line-2),transparent)}
  .footer__seal-line:last-child{background:linear-gradient(transparent,var(--line-2))}
  .footer__poem span{display:inline-block;white-space:normal}
  /* 中间两段仍是「左文右入口」，中屏时说明文字可折行，入口不动 */
  .footer__d{max-width:22em}
}
/* ≤900：手机收敛成「题跋在前、三枚按钮并排在后」。
   两块条目的文字（标签/标题/说明）全部隐藏，row 与 acts 用 display:contents
   抽掉包装盒，三枚胶囊直接落在同一个 flex 行里；放不下时才换行。
   印记仍钉在右边缘的窄轨道。 */
@media (max-width:900px){
  .footer__inner{grid-template-columns:minmax(0,1fr) auto;
    grid-template-areas:"note seal" "cta cta" "bar bar";
    grid-template-rows:auto auto auto;
    gap:clamp(22px,3.6vw,30px) clamp(12px,3vw,20px);align-items:start}
  .footer__aside{align-self:start;display:flex;flex-direction:row;flex-wrap:wrap;
    align-items:center;gap:8px}
  .footer__row{display:contents}
  .footer__kicker,.footer__t,.footer__d{display:none}
  .footer__acts{display:contents}
  .footer__act{min-height:42px;padding:0 12px;font-size:12.5px;letter-spacing:0;gap:6px}
  .footer__seal{grid-area:seal;align-self:start;padding-top:2px}
  .footer__seal b,.footer__seal span{writing-mode:vertical-rl}
  .footer__seal b{font-size:11px;letter-spacing:.3em}
  .footer__seal span{font-size:11px;letter-spacing:.2em}
  .footer__seal-line{width:1px;height:clamp(14px,3vw,24px);
    background:linear-gradient(var(--line-2),transparent)}
  .footer__seal-line:last-child{background:linear-gradient(transparent,var(--line-2))}
}

/* 更窄：三枚胶囊收紧内距；放不下就自然换成两行，仍保持并排形态 */
@media (max-width:420px){
  .footer__act{min-height:40px;padding:0 11px;font-size:12px;gap:5px}
  .footer__act .i{width:14px;height:14px}
}
/* 360 以下：内距再收一档，尽量让三枚胶囊压在同一行 */
@media (max-width:360px){
  .footer__aside{gap:6px}
  .footer__act{min-height:38px;padding:0 8px;font-size:11.5px;gap:4px}
  .footer__act .i{width:13px;height:13px}
}

/* ---------------- 滚动进度条（顶部 1px，玫瑰→金） ---------------- */
.scroll-progress{position:fixed;left:0;top:0;z-index:60;width:100%;height:2px;transform:scaleX(0);transform-origin:0 50%;
  background:linear-gradient(90deg,var(--rose),var(--gold));pointer-events:none;opacity:.85;
  transition:transform .1s linear}

/* ---------------- 视差深度（JS 写 --py，与 hover 位移叠加） ---------------- */
.about__avatar,.radar,.service,.tile,.footer__poem{translate:0 var(--py,0px)}
.about__avatar,.radar{transition:translate .5s var(--e-scroll)}
.service,.tile,.footer__poem{transition:translate .5s var(--e-scroll)}

/* ---------------- 滚动显现（不规则弹出，不再统一上浮） ----------------
   三层属性分工，互不打架：
   · translate —— 位移（入场用 --tx/--ty 随元素随机，形成不规则跳出）
   · rotate    —— 入场时的轻微歪斜，落位归零（倾斜用 transform，不冲突）
   · scale     —— 入场从略小弹到原大，落在 --sc
   所有随机量由 JS 写进变量，CSS 只负责过渡。 */
/* 过渡时长直接吃 JS 写好的毫秒值：不在 transition 里做 calc(时间) 运算，
   部分浏览器会因单位无法静态推导而整条声明失效（表现为完全不过渡/瞬间闪现）。 */
.js .reveal{
  opacity:0;
  translate:var(--tx,0) var(--ty,22px);
  rotate:var(--rot,0deg);
  scale:var(--sc,.96);
  transition:
    opacity var(--dur-fade,.66s) var(--e-scroll) var(--d,0s),
    translate var(--dur,.9s) var(--e-scroll) var(--d,0s),
    rotate var(--dur,.9s) var(--e-scroll) var(--d,0s),
    scale var(--dur,.9s) var(--e-scroll) var(--d,0s),
    clip-path 1.1s var(--e-scroll) var(--d,0s)
}
/* 归零：--tx/--ty/--rot/--sc 必须在 is-in 里逐项覆盖回中性值，
   否则它们还是入场前的随机值，元素会停在偏移/歪斜/缩小的状态。 */
.js .reveal.is-in{opacity:1;translate:var(--px,0px) var(--py,0px);rotate:0deg;scale:1}
.js .reveal.is-in{--tx:0px;--ty:0px;--rot:0deg;--sc:1}
/* 注意：下面这些「起始态」也必须带 .is-in 归零，
   否则同等权重下会盖掉通用 .is-in，元素永远停在偏移位置。 */
/* 标题类：横向偏一点落下 */
.js .sec-head.reveal{--tx:-14px;--ty:18px}
/* 日常出没整列：左进 */
.js .rows.reveal{--tx:-18px;--ty:6px}
/* 卡片类：纵向弹出 */
.js .card.reveal,.js .cs.reveal,.js .friends__body.reveal{--ty:24px}
.js .rows li.reveal{--ty:14px}
/* 文字擦除：关于区大字与页脚诗 */
.js .statement.reveal,.js .footer__poem.reveal{clip-path:inset(0 0 100% 0);--ty:10px}
.js .statement.reveal.is-in,.js .footer__poem.reveal.is-in{clip-path:inset(0 0 0 0)}
/* 首屏标题：整块只做很小的位移，逐字动画由 .hero__cn 内部接管 */
.js .hero__title.reveal{--ty:26px}
/* 注意：上面的起始位移规则必须带上 .is-in 才归零，
   否则同等权重下会盖掉通用 .is-in 的 translate:0 0，元素永远停在偏移位置。 */
/* 上面这些起始态一律由通用 .js .reveal.is-in 归零（变量同权重，无需重复写） */

/* ---------------- 按压缩进（不同控件不同手感） ----------------
   触屏点击的默认高亮（半透明色块）与焦点框会在控件外画一圈方框，
   和胶囊圆角对不上，看着就像「点了出现透明边框」。所以：
   · 全站清掉 tap-highlight，按压手感交给 :active 自己给；
   · 键盘聚焦（:focus-visible）保留，鼠标/手指点过的残留焦点一律清掉。 */
*{-webkit-tap-highlight-color:transparent}
a,button,summary,[tabindex]{
  -webkit-tap-highlight-color:transparent;
  -webkit-touch-callout:none;
}
.nav__cta:active{scale:.96;background:var(--surface-2)}
:where(a,button,summary,[tabindex],.tile,.service,.rows a,.fl a):focus{outline:none}
/* 键盘可达性：焦点环用描边而非 outline，圆角与控件一致，不会切成方框 */
:where(a,button,summary,[tabindex],.tile,.service,.rows a,.fl a):focus-visible{
  outline:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--rose) 62%,transparent)}
/* 触屏上不显示键盘焦点环：手指点完不该留一圈框 */
@media (hover:none){
  :focus-visible{outline:none;box-shadow:none}
}

/* ---------------- 响应式 ----------------
   容器宽度不再锁死 1120px：小屏吃满、中屏渐宽、超宽屏留出侧边栏感。
   断点只负责「列数变化」，宽度由 --maxw 随视口连续增长负责。 */
@media (min-width:1440px){
  /* 宽屏：劳动力两列不再挤在 1.1fr/1fr，雷达放大、列表拉宽 */
  .power__grid{grid-template-columns:1.15fr 1fr}
  .radar::before{width:min(96%,640px)}
}
/* 移动端：间距不缩小。
   小卡片上间距若跟着尺寸一起缩，缝隙占卡片边长的比例会掉到 3% 以下，看着像贴在一起。
   这里统一比桌面还松一档：手机上留白是唯一能撑住精致感的东西。 */
@media (max-width:1024px){
  .lab__grid{grid-template-columns:repeat(2,1fr);gap:20px}
  .services{grid-template-columns:1fr 1fr;gap:24px 22px}
  .services li:last-child{grid-column:span 2}
}
@media (max-width:560px){
  /* 手机上卡片更小，但间距更大 —— 留白比尺寸更影响精致感 */
  .lab__grid{gap:14px}
  .services{gap:20px}
}

/* ============ 触屏专属（无 hover 的设备：靠按压 + 跑马灯 + 入场补足动感） ============
   触屏上 hover 效果全部失效，如果只保留桌面那套，手机上就只剩「静态图」。
   所以这里单独给触屏设计：更大的按压位移、图标回弹、卡片边缘光。 */
@media (hover:none){
  :root{--press-y:2.5px}
  /* 按下时压得更实，配合 :active 的 scale 做出「指压」手感 */
  .tile:active,.service:active{background:var(--surface-2)}
  .tile:active .tile__arrow{translate:1px 1px;scale:.85}
  /* 首屏位置信息在触屏上更紧凑，给按钮腾空间 */
  .hero__meta{gap:20px}
  .meta-item b{font-size:13px}

  /* 触点光斑：按下点亮、松手淡出，滚动取消时立即清理。 */
  .tile::after,.btn::after{
    content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;
    opacity:0;transition:opacity .45s var(--ease);
    background:radial-gradient(220px circle at var(--mx,50%) var(--my,50%),var(--rose-14),transparent 62%)}
  .tile.is-lit::after,.btn.is-lit::after,.spot.is-lit::before{opacity:1}
  .tile.is-lit,.btn--ghost.is-lit{border-color:var(--line-2);background:var(--surface-2)}
  .is-lit .tile__arrow{color:var(--rose)}
}

/* ============ 小屏细节（≤560 已单独处理结构，这里只管手感） ============ */
@media (max-width:560px){
  /* 触屏滚动时固定背景会导致重绘抖动，canvas 降为 static 参与滚动 */
  .hero__canvas{position:absolute}
  /* 磁贴在小屏两列时高度压缩，min-height 跟随视口，避免出现半截卡片 */
  .tile{min-height:clamp(136px,32vw,168px)}
  /* 底部安全区：iPhone 刘海屏按钮不被手势条压住 */
  .hero__actions{padding-bottom:env(safe-area-inset-bottom)}
}
@media (max-width:820px){
  :root{--nav-h:60px}
  .nav__toggle{display:block}
  .nav__cta{display:none}
  .nav__links{position:fixed;inset:0;z-index:-1;flex-direction:column;justify-content:center;gap:4px;padding:0 var(--gutter);background:var(--bg-96);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);
    opacity:0;visibility:hidden;transition:opacity .45s var(--ease),visibility .45s}
  .nav__links a{font:500 32px/1.3 var(--serif);color:var(--text);padding:12px 0;letter-spacing:.08em;transform:translateY(16px);transition:transform .6s var(--ease),color .3s}
  .nav__links a::after{display:none}
  .nav-open .nav__links{opacity:1;visibility:visible}
  .nav-open .nav__links a{transform:none}
  .nav-open .nav{background:transparent;border-color:transparent;-webkit-backdrop-filter:none;backdrop-filter:none}
  .about__grid{grid-template-columns:1fr}
  .about__avatar{max-width:240px}
  .power__grid{grid-template-columns:1fr}
  /* 单列时列表不再与雷达等高，否则会被拉成长条 */
  .skills{height:auto;gap:0}
  .skills li{padding:10px 6px 14px}
  .radar{max-width:520px;margin:0 auto;width:100%}
  .hero__veil{background:linear-gradient(180deg,var(--bg-30) 0%,var(--bg-15) 35%,var(--bg-35) 70%,var(--bg) 100%)}
}
@media (max-width:560px){
  .services{grid-template-columns:1fr}
  .services li:last-child{grid-column:auto}
  .service h3{margin-top:28px}
  /* 手机上不再跨行：跨行会把卡片拉高，一屏只放得下一张半，页面被拉长。
     同时把最小高度收紧，同样内容占用更少纵向空间。 */
  .lab__grid{grid-template-columns:repeat(auto-fit,minmax(min(44%,160px),1fr));gap:14px}
  .tile{min-height:118px;padding:16px}
  .tile:nth-child(6n+1){grid-row:auto;min-height:118px;padding:16px}
  .tile h3{font-size:17px}
  .tile:nth-child(6n+1) h3{font-size:17px}
  .tile:nth-child(6n+1) .tile__tag{letter-spacing:.2em}
  .tile p{font-size:12.5px;line-height:1.5;margin-top:6px;
    /* 窄屏描述最多两行，超出省略：否则长描述换行后会把卡片顶出固定高度 */
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .tile__arrow{top:14px;right:14px}
  .sec-head{grid-template-columns:1fr}
  .sec-desc{grid-column:1}
  .hero__meta{gap:24px}
  /* 首屏两颗按钮并排等分，不再各占一行。
     之前 flex:1 1 100% 会让每个按钮独占整行，看起来是两条横幅。
     并排的关键是 flex-basis:0（等分剩余宽度）+ min-width:0（允许收缩不撑破），
     再用更小的左右内边距给文字腾位置。 */
  .hero__actions{display:flex;flex-wrap:nowrap;gap:10px}
  .hero__actions .btn{flex:1 1 0;min-width:0;width:auto;max-width:none;
    padding:0 14px;font-size:14px;letter-spacing:.01em}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
  /* 关键：入场用的是 translate 独立属性，只清 transform 会留下位移残影；
     延迟也必须归零，否则内容要等 --d 秒才出现 */
  .js .reveal,.js .reveal.is-in,
  .js .sec-head.reveal,.js .rows.reveal,.js .card.reveal,
  .js .cs.reveal,.js .rows li.reveal,.js .statement.reveal,.js .footer__poem.reveal,
  .js .hero__title.reveal{opacity:1!important;translate:none!important;transform:none!important;clip-path:none!important;transition:none!important}
  .reveal{transition-delay:0s!important}
  /* 减少动效：所有持续浮动/脉冲/爆裂一律停掉，只保留静态画面 */
  .tile,.service,.rows a,.rows__icon,.fl__go,.about__avatar,.footer__poem,
  .radar svg,.radar .pt{animation:none!important}
  .burst,.ripple{display:none!important}
}

/* 粗指针（触屏）不做 hover 暂停：手指按下的瞬间不该让卡片突然静止 */
@media (hover:none){
  .tile:hover,.tile:active,.service:hover{animation-play-state:running}
}
