/* ============================================================
   史蒂芬的房车 · 视觉系统 v3
   皮肤(5) × 时辰(4) × 季节(4) × 天气(7) 自由组合
   纯 CSS + 内联 SVG + Canvas，零外部依赖，虚拟主机可直接跑
   ============================================================ */

/* ================= 皮肤：只管强调色系 ================= */
:root, html[data-skin="camp"]{
  --panel-rgb:38,29,54; --panel-rgb2:46,35,64;
  --amber:#ffb454; --amber-deep:#ff8c42; --ember:#ff6f61; --sage:#6fc39a;
  --me-bubble:linear-gradient(135deg,#ffc06a,#ff8f45); --me-text:#3a2210;
  --tint:255,180,84;
  --panel-rgb:38,29,54; --panel-rgb2:46,35,64;
}
html[data-skin="forest"]{
  --panel-rgb:24,38,32; --panel-rgb2:32,48,40;
  --amber:#7fd39a; --amber-deep:#4fb87a; --ember:#e8845f; --sage:#8fd8ae;
  --me-bubble:linear-gradient(135deg,#9fe0b4,#4fb87a); --me-text:#123322;
  --tint:127,211,154;
}
html[data-skin="ocean"]{
  --panel-rgb:22,36,50; --panel-rgb2:28,46,62;
  --amber:#6cc4e8; --amber-deep:#3f9cc4; --ember:#ef7a72; --sage:#7fd4d0;
  --me-bubble:linear-gradient(135deg,#8fd8f0,#3f9cc4); --me-text:#0c2c38;
  --tint:108,196,232;
}
html[data-skin="sakura"]{
  --panel-rgb:52,30,44; --panel-rgb2:62,38,54;
  --amber:#ff9ec0; --amber-deep:#f76f9e; --ember:#e86a80; --sage:#8fc9a8;
  --me-bubble:linear-gradient(135deg,#ffc0d8,#f76f9e); --me-text:#45182a;
  --tint:255,158,192;
}
html[data-skin="aurora"]{
  --panel-rgb:32,28,56; --panel-rgb2:42,36,70;
  --amber:#b79cf0; --amber-deep:#8f6fe0; --ember:#ef7fa8; --sage:#7fd0c4;
  --me-bubble:linear-gradient(135deg,#cdb8ff,#8f6fe0); --me-text:#251242;
  --tint:183,156,240;
}

/* ================= 时辰：天空 / 光照 / 文字 / 玻璃 ================= */
:root,
html[data-scene="night"]{--panel-a:.46;
  
  --sky-1:#161126; --sky-2:#241a38; --sky-3:#33253f; --horizon:#54343c;
  --hill-far:#1d1530; --hill-mid:#181026;
  --win:.95; --fire:1; --star-op:1; --fog:0; --sun:0;
  --glass:rgba(var(--panel-rgb),var(--panel-a)); --glass-2:rgba(var(--panel-rgb2),calc(var(--panel-a) + .05)); --glass-hi:rgba(255,255,255,.055);
  --solid:rgb(var(--panel-rgb));
  --stroke:rgba(255,226,196,.12); --stroke-2:rgba(255,226,196,.07);
  --text:#f7f0e6; --text-dim:#b0a4c2; --text-faint:#7d7392;
  --bubble:rgba(255,255,255,.075); --bubble-stroke:rgba(255,226,196,.1);
  --shadow:0 10px 34px rgba(0,0,0,.42); --shadow-sm:0 3px 12px rgba(0,0,0,.24);
  --glow:0 0 26px rgba(var(--tint),.28);
}
html[data-scene="dawn"]{--panel-a:.42;
  
  --sky-1:#2b2350; --sky-2:#63446b; --sky-3:#b8757a; --horizon:#f0a878;
  --hill-far:#4a3a5c; --hill-mid:#33283f;
  --win:.4; --fire:.35; --star-op:.28; --fog:.55; --sun:.5;
  --glass:rgba(var(--panel-rgb),var(--panel-a)); --glass-2:rgba(var(--panel-rgb2),calc(var(--panel-a) + .05)); --glass-hi:rgba(255,255,255,.09);
  --solid:rgb(var(--panel-rgb));
  --stroke:rgba(255,230,210,.16); --stroke-2:rgba(255,230,210,.09);
  --text:#fdf3ea; --text-dim:#cbb8c4; --text-faint:#9c8aa0;
  --bubble:rgba(255,255,255,.1); --bubble-stroke:rgba(255,235,215,.14);
  --shadow:0 10px 32px rgba(20,10,30,.35); --shadow-sm:0 3px 12px rgba(20,10,30,.22);
  --glow:0 0 28px rgba(var(--tint),.3);
}
html[data-scene="day"]{--panel-rgb:255,253,248; --panel-rgb2:255,251,244;
  --panel-a:.54;
  
  --sky-1:#7ab8e0; --sky-2:#a8d4ee; --sky-3:#d6e9f4; --horizon:#f3e3c8;
  --hill-far:#a9bcc6; --hill-mid:#7f9b86;
  --win:.08; --fire:0; --star-op:0; --fog:0; --sun:1;
  --glass:rgba(var(--panel-rgb),var(--panel-a)); --glass-2:rgba(var(--panel-rgb2),calc(var(--panel-a) + .05)); --glass-hi:rgba(255,255,255,.6);
  --solid:rgb(var(--panel-rgb));
  --stroke:rgba(90,60,40,.14); --stroke-2:rgba(90,60,40,.08);
  --text:#33251c; --text-dim:#6d5a4c; --text-faint:#96826f;
  --bubble:rgba(255,255,255,.75); --bubble-stroke:rgba(90,60,40,.12);
  --shadow:0 10px 30px rgba(90,70,50,.14); --shadow-sm:0 3px 10px rgba(90,70,50,.1);
  --glow:0 0 22px rgba(var(--tint),.18);
}
html[data-scene="dusk"]{--panel-a:.44;
  
  --sky-1:#33244f; --sky-2:#7d4358; --sky-3:#cf6f45; --horizon:#ffb066;
  --hill-far:#4b3450; --hill-mid:#331f34;
  --win:.85; --fire:.9; --star-op:.5; --fog:.2; --sun:.35;
  --glass:rgba(var(--panel-rgb),var(--panel-a)); --glass-2:rgba(var(--panel-rgb2),calc(var(--panel-a) + .05)); --glass-hi:rgba(255,255,255,.08);
  --solid:rgb(var(--panel-rgb));
  --stroke:rgba(255,220,190,.15); --stroke-2:rgba(255,220,190,.09);
  --text:#fdf0e2; --text-dim:#c9adab; --text-faint:#9c847f;
  --bubble:rgba(255,255,255,.1); --bubble-stroke:rgba(255,225,200,.13);
  --shadow:0 10px 32px rgba(30,10,20,.36); --shadow-sm:0 3px 12px rgba(30,10,20,.22);
  --glow:0 0 28px rgba(var(--tint),.3);
}

/* ================= 季节：植被 / 山雪 ================= */
:root, html[data-season="spring"]{
  --grass:#4f9c52; --grass-2:#3d8144;
  --tree-c:#5aa85c; --tree-c2:#6fbb6a; --trunk:#6b4a30;
  --petal:#ffc0d8; --snow-op:0;
}
html[data-season="summer"]{
  --grass:#3f8f45; --grass-2:#2f7538;
  --tree-c:#2f8f42; --tree-c2:#43a352; --trunk:#5a3f2a;
  --petal:#ffffff; --snow-op:0;
}
html[data-season="autumn"]{
  --grass:#8a8f42; --grass-2:#6f7534;
  --tree-c:#d4842c; --tree-c2:#eea349; --trunk:#6b4630;
  --petal:#e89440; --snow-op:0;
}
html[data-season="winter"]{
  --grass:#c8d6e0; --grass-2:#aebfcb;
  --tree-c:#6b8478; --tree-c2:#7d968a; --trunk:#5a4638;
  --petal:#ffffff; --snow-op:1;
}

/* 下雪天气：不管什么季节，地面/山/树都强制盖雪（优先级高于季节） */
/* :root 伪类把特异性抬到 0,2,1，压过后面的 html[data-theme=...]（0,1,1），
   否则「冬天 + 湖边」这类组合里，主题规则会盖掉积雪，草地依旧绿油油。 */
html:root[data-weather="snow"]{
  --snow-op:1;
  --grass:#dbe7f0; --grass-2:#c2d3e0;
}
html:root[data-weather="snow"] .grass-tuft{fill:#eef4fa}
html:root[data-weather="snow"] .hill-snow{opacity:1}

/* ================= 基础 ================= */
*{box-sizing:border-box}
[hidden]{display:none !important}
html,body{height:100%}
body{
  margin:0;color:var(--text);overflow:hidden;
  font:14px/1.65 -apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  -webkit-font-smoothing:antialiased;background:var(--sky-1);
  transition:color .7s ease;
}
body.scene-fading{animation:scene-fade .8s ease both}
@keyframes scene-fade{0%{opacity:.5}100%{opacity:1}}

/* ================= 天空 ================= */
#sky{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none;
  background:linear-gradient(180deg,var(--sky-1) 0%,var(--sky-2) 45%,var(--sky-3) 78%,var(--horizon) 100%)}
#sky::before{content:"";position:absolute;left:-20%;right:-20%;bottom:-30%;height:75%;
  background:radial-gradient(ellipse at 50% 100%,rgba(255,150,70,.24),transparent 62%);
  animation:ember-breathe 9s ease-in-out infinite;opacity:var(--fire)}
#sky::after{content:"";position:absolute;top:-15%;left:-25%;width:70%;height:60%;
  background:radial-gradient(ellipse at center,rgba(120,150,255,.16),transparent 66%);
  animation:drift-a 26s ease-in-out infinite;opacity:var(--star-op)}
@keyframes ember-breathe{0%,100%{opacity:.7;transform:scale(1)}50%{opacity:1;transform:scale(1.06)}}
@keyframes drift-a{0%,100%{transform:translate(0,0)}50%{transform:translate(9%,5%)}}

#stars,#weather{position:absolute;inset:0;width:100%;height:100%}
#stars{opacity:var(--star-op);transition:opacity .8s}
#weather{pointer-events:none}

/* 太阳 / 月亮 */
#orb{position:absolute;right:14%;top:11%;width:56px;height:56px;border-radius:50%;
  opacity:var(--sun);transition:opacity .8s}
html[data-scene="night"] #orb{background:radial-gradient(circle at 35% 35%,#fff8e0,#e8d9a8);
  box-shadow:0 0 40px 12px rgba(255,244,214,.28)}
html[data-scene="day"] #orb{background:radial-gradient(circle at 35% 35%,#fffbe8,#ffd97a);
  box-shadow:0 0 60px 18px rgba(255,220,120,.45);animation:sun-pulse 6s ease-in-out infinite}
html[data-scene="dawn"] #orb,html[data-scene="dusk"] #orb{
  background:radial-gradient(circle at 35% 35%,#ffe6c0,#ff9c5e);
  box-shadow:0 0 50px 14px rgba(255,150,80,.4)}
@keyframes sun-pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.05)}}
/* 雨雪阴雾天看不到太阳/月亮（雾天只留一点轮廓） */
html[data-weather="rain"]     #orb,
html[data-weather="storm"]    #orb,
html[data-weather="snow"]     #orb,
html[data-weather="overcast"] #orb{opacity:0}
html[data-weather="fog"]      #orb{opacity:.18}
html[data-weather="cloudy"]   #orb{opacity:calc(var(--sun) * .55)}

/* 晨雾 */
#fog{position:absolute;left:0;right:0;bottom:22%;height:22%;opacity:var(--fog);transition:opacity .8s;
  background:linear-gradient(180deg,transparent,rgba(255,235,220,.5),transparent);
  animation:fog-slide 30s ease-in-out infinite}
@keyframes fog-slide{0%,100%{transform:translateX(-4%)}50%{transform:translateX(4%)}}

/* 云 */
.cloud{position:absolute;top:8%;opacity:0;pointer-events:none;animation:cloud-drift linear infinite}
html[data-scene="day"] .cloud{opacity:.85}
html[data-scene="dawn"] .cloud,html[data-scene="dusk"] .cloud{opacity:.5}
html[data-scene="night"] .cloud{opacity:.18}
.cloud svg{display:block;fill:#fff;opacity:.9}
@keyframes cloud-drift{from{transform:translateX(-22vw)}to{transform:translateX(122vw)}}

/* 萤火虫 */
.firefly{position:absolute;width:4px;height:4px;border-radius:50%;background:#ffe9a8;
  box-shadow:0 0 8px 3px rgba(255,220,130,.75);opacity:0;pointer-events:none}
html[data-scene="night"] .firefly,html[data-scene="dusk"] .firefly{animation:firefly 9s ease-in-out infinite}
@keyframes firefly{
  0%{opacity:0;transform:translate(0,0)}
  12%{opacity:1}
  50%{opacity:.35;transform:translate(26px,-22px)}
  75%{opacity:.9;transform:translate(-14px,-34px)}
  100%{opacity:0;transform:translate(8px,-52px)}
}

/* 天气：雨 / 雪 / 落叶 —— canvas 画雨雪，DOM 画叶片 */
html[data-weather="rain"]  #sky::after,
html[data-weather="storm"] #sky::after{opacity:.05}
html[data-weather="overcast"] #sky,
html[data-weather="rain"] #sky,
html[data-weather="snow"] #sky,
html[data-weather="storm"] #sky{filter:saturate(.62) brightness(.92)}
html[data-weather="fog"] #fog{opacity:.9 !important}
.weather-badge{position:absolute;left:50%;top:5%;transform:translateX(-50%);
  font-size:11px;letter-spacing:1px;color:var(--text-dim);opacity:.75;
  background:rgba(0,0,0,.18);padding:3px 12px;border-radius:12px;white-space:nowrap}
html[data-weather="storm"] #flash{position:absolute;inset:0;background:#fff;opacity:0;pointer-events:none}
html[data-weather="storm"] #flash.on{animation:flash 1.4s ease-out}
@keyframes flash{0%{opacity:0}4%{opacity:.55}8%{opacity:.1}12%{opacity:.4}30%{opacity:0}100%{opacity:0}}

/* ================= 地面场景 ================= */
.scenery{position:absolute;left:0;right:0;bottom:0;height:58vh;min-height:320px;pointer-events:none;
  transition:height .3s}
.hills{position:absolute;bottom:22%;left:0;width:100%;height:58%}
.hill-far{fill:var(--hill-far);opacity:.9;transition:fill .7s}
.hill-mid{fill:var(--hill-mid);transition:fill .7s}
.hill-snow{fill:#eef4fa;opacity:var(--snow-op);transition:opacity .8s}

.grassland{position:absolute;bottom:0;left:0;width:100%;height:34%}
.grass-fill{fill:var(--grass);transition:fill .7s}
.grass-fill-2{fill:var(--grass-2);transition:fill .7s}
.grass-tuft{fill:var(--grass-2);transform-origin:50% 100%;animation:sway 4.2s ease-in-out infinite;transition:fill .7s}
@keyframes sway{0%,100%{transform:rotate(-2.5deg) skewX(-1deg)}50%{transform:rotate(2.5deg) skewX(1deg)}}
/* 草上积雪 */
.grass-snow{fill:#f2f7fc;opacity:var(--snow-op);transition:opacity .8s}

.trees{position:absolute;left:0;right:0;bottom:20%;height:60%}
.tree{position:absolute;bottom:0;transform-origin:50% 100%;animation:sway 6.5s ease-in-out infinite}
.tree .cr{fill:var(--tree-c);transition:fill .7s}
.tree .cr2{fill:var(--tree-c2);transition:fill .7s}
.tree .tk{fill:var(--trunk);transition:fill .7s}
.tree .sn{fill:#f2f7fc;opacity:var(--snow-op);transition:opacity .8s}
.t1{left:3%;width:64px;animation-duration:7s}
.t2{left:14%;width:48px;animation-duration:5.4s;animation-delay:-1.2s}
.t3{left:31%;width:56px;animation-duration:6.2s;animation-delay:-2.6s}
.t4{right:26%;width:70px;animation-duration:8s;animation-delay:-3.4s}
.t5{right:4%;width:52px;animation-duration:5.8s;animation-delay:-.8s}
.t6{right:16%;width:40px;animation-duration:6.8s;animation-delay:-4.2s}

/* 落叶 / 花瓣 */
.petal{position:absolute;top:-6%;width:9px;height:9px;pointer-events:none;opacity:0;
  background:var(--petal);border-radius:60% 10% 60% 10%;animation:petal-fall linear infinite}
@keyframes petal-fall{
  0%{opacity:0;transform:translateY(0) rotate(0) translateX(0)}
  8%{opacity:.9}
  50%{transform:translateY(45vh) rotate(180deg) translateX(30px)}
  92%{opacity:.85}
  100%{opacity:0;transform:translateY(92vh) rotate(420deg) translateX(-20px)}
}
html[data-season="summer"] .petal{display:none}

/* ================= 热点：场景元素本身即入口 ================= */
.spot{position:absolute;z-index:5;display:flex;flex-direction:column;align-items:center;gap:3px;
  background:none;border:0;padding:0;color:inherit;cursor:pointer;
  touch-action:manipulation;-webkit-tap-highlight-color:transparent;
  transition:transform .28s cubic-bezier(.4,0,.2,1);pointer-events:auto}
/* 按下时的即时反馈——手机上没有 hover，必须靠 active 告诉用户「点到了」 */
.spot:active{transform:translateY(-2px) scale(.94)}
.spot:active .art{filter:drop-shadow(0 0 20px rgba(var(--tint),1))}
.spot .art{display:block;transition:filter .28s;
  filter:drop-shadow(0 2px 6px rgba(0,0,0,.5)) drop-shadow(0 0 7px rgba(var(--tint),.3))}
/* 雪天：图标也要更立得住 */
html[data-weather="snow"] .spot .art{
  filter:drop-shadow(0 2px 5px rgba(0,0,0,.80))
         drop-shadow(0 4px 12px rgba(0,0,0,.55))
         drop-shadow(0 0 8px rgba(var(--tint),.35))}
.spot .cap{font-size:12px;letter-spacing:1.5px;white-space:nowrap;
  color:var(--text);opacity:.72;
  /* 常规阴影：多层叠加，比单层更"实" */
  text-shadow:0 1px 3px rgba(0,0,0,.75), 0 2px 8px rgba(0,0,0,.55);
  transition:opacity .25s,color .25s,transform .25s}

/* ⚠️ 下雪时地面/草地变白（--grass 被雪覆盖成浅色），
   浅色文字直接压在白雪上几乎看不见 —— 原来只有一层 0 1px 6px 的阴影，
   在这个背景下完全不够。
   雪天（含圣诞）单独加强：多层深色阴影 + 半透明底衬 + 提高不透明度。
   注意：这里用 data-weather="snow" 而不是 data-xmas，
   因为问题是"下雪导致背景变白"，跟是不是圣诞节无关。 */
html[data-weather="snow"]:not([data-scene="day"]) .spot .cap{
  opacity:1;color:#fff;font-weight:600;
  text-shadow:
    0 1px 2px rgba(0,0,0,.95),
    0 2px 5px rgba(0,0,0,.85),
    0 3px 10px rgba(0,0,0,.70),
    0 0 14px rgba(0,0,0,.55);
  /* 底衬：和白雪彻底分离 */
  background:rgba(18,22,32,.34);
  padding:2px 8px;border-radius:9px;
  backdrop-filter:blur(2px);
  -webkit-backdrop-filter:blur(2px);}

/* ================= 营地文字：按「背景亮暗」自适应 =================
   ⚠️ 之前的做法（雪天一律加深色 pill 底衬 + 强制白字）太粗暴：
      只有雪天会出现那圈边框，其它天气没有，风格不统一；
      而且夜晚本来就看得很清楚，白白多了一块突兀的底衬。

   真正看不清的只有一种组合：亮背景（白天）+ 雪。
   此时 --text 本来就是深色（#33251c），深色字压在白雪上其实能辨认，
   但雪天规则又给它叠了一层大范围黑色 text-shadow，深色字 + 黑阴影 = 糊成一团。

   所以改成按亮暗分开处理：
     · 暗背景（夜 / 黄昏 / 雪天的暗时辰）→ 浅色字 + 深色阴影（原方案，有效）
     · 亮背景（白天）                    → 深色字 + 柔和白色光晕（与亮天空/雪地分离）
   这样各时辰观感一致，也不会凭空多出一个边框。 */

/* 暗时辰：浅色字 + 深色阴影（含雪天） */
html[data-weather="snow"]:not([data-scene="day"]) .camp-title{
  text-shadow:0 1px 3px rgba(0,0,0,.9), 0 2px 8px rgba(0,0,0,.7), 0 0 14px rgba(0,0,0,.5)}
html[data-weather="snow"] .camp-tip{opacity:1}

/* 亮时辰（白天）：深色字 + 柔和白色光晕，不掉边框、不加底衬 */
html[data-scene="day"] .camp-title{
  color:#2b2118;
  text-shadow:
    0 1px 0 rgba(255,255,255,.95),
    0 0 7px rgba(255,255,255,.9),
    0 0 16px rgba(255,255,255,.75)}
/* 白天 + 雪：背景最亮，光晕再加强一点（雪地反光强） */
html[data-scene="day"][data-weather="snow"] .camp-title{
  text-shadow:
    0 1px 0 rgba(255,255,255,1),
    0 0 8px rgba(255,255,255,.95),
    0 0 20px rgba(255,255,255,.85),
    0 0 34px rgba(255,255,255,.6)}

/* 营地底部按钮：雪天加一层底衬保证可读 */
html[data-weather="snow"] .camp-ctrl button,
html[data-weather="snow"] .camp-exit{
  background:rgba(20,24,34,.55);
  text-shadow:0 1px 3px rgba(0,0,0,.9)}
html[data-weather="snow"] .weather-badge{
  background:rgba(20,24,34,.6);
  text-shadow:0 1px 3px rgba(0,0,0,.9)}
/* 亮时辰：入口文字同样用「深色字 + 白色光晕」，
   不再沿用深色阴影（会让深色字糊掉），也不加底衬。 */
html[data-scene="day"] .spot .cap{
  color:#2b2118;font-weight:600;opacity:1;background:none;padding:0;
  backdrop-filter:none;-webkit-backdrop-filter:none;
  text-shadow:
    0 1px 0 rgba(255,255,255,.95),
    0 0 6px rgba(255,255,255,.9),
    0 0 14px rgba(255,255,255,.7)}
/* ⚠️ 上面这条特异性 (0,3,1) 会盖过 .spot:hover .cap (0,3,0)，
   导致白天 hover 时不变色。这里补一条更高特异性的规则。 */
html[data-scene="day"] .spot:hover .cap,
html[data-scene="day"] .spot:focus-visible .cap{
  color:var(--amber-deep);opacity:1}
html[data-scene="day"][data-weather="snow"] .spot .cap{
  text-shadow:
    0 1px 0 rgba(255,255,255,1),
    0 0 7px rgba(255,255,255,.95),
    0 0 18px rgba(255,255,255,.8)}

.spot:hover,.spot:focus-visible{transform:translateY(-5px)}
.spot:hover .cap,.spot:focus-visible .cap{opacity:1;color:var(--amber);transform:translateY(1px)}
.spot:hover .art{filter:drop-shadow(0 0 16px rgba(var(--tint),.85))}
.spot:active{transform:translateY(-2px) scale(.97)}
/* 地面光晕：hover 时脚下亮起一圈 */
.spot::after{content:"";position:absolute;left:50%;bottom:-4px;width:76px;height:16px;pointer-events:none;
  transform:translateX(-50%);border-radius:50%;opacity:0;transition:opacity .28s;
  background:radial-gradient(ellipse,rgba(var(--tint),.55),transparent 70%)}
.spot:hover::after{opacity:1}
.spot .badge-dot{position:absolute;top:-4px;right:-6px;min-width:17px;padding:0 5px;
  background:linear-gradient(135deg,var(--amber-deep),var(--ember));color:#fff;border-radius:10px;
  font-size:10px;line-height:17px;font-weight:700;text-align:center;
  box-shadow:0 0 12px rgba(var(--tint),.6);animation:pulse 2.4s ease-in-out infinite}

/* 各热点的具体位置（与场景元素对齐） */
/* 用固定像素而非百分比：底部按钮区的高度是固定的，
   百分比会随视口高度漂移，在矮屏上就会撞在一起。 */
.spot-rv   {left:4.5%;  bottom:140px;width:92px}
.spot-tent {left:19%;   bottom:140px;width:58px}
.spot-sign {left:37%;   bottom:140px;width:56px}
.spot-fire {right:9%;   bottom:146px;width:60px}
.spot-rv   .cap,.spot-tent .cap,.spot-sign .cap,.spot-fire .cap{margin-top:1px}

/* 房车窗户 */
.spot-rv .win,#rv-far .win{animation:win-flicker 6s ease-in-out infinite;opacity:var(--win);transition:opacity .7s}
.spot-rv .body,#rv-far .body{fill:#4a3a62;stroke:var(--amber);stroke-width:1.4;transition:stroke .7s,fill .7s}
html[data-scene="day"] .spot-rv .body,#rv-far .body{fill:#fbf3e6;stroke:#b07a48}
html[data-scene="dawn"] .spot-rv .body,#rv-far .body{fill:#5a4468}
html[data-scene="dusk"] .spot-rv .body,#rv-far .body{fill:#5c3c52}
@keyframes win-flicker{0%,100%{opacity:.95}45%{opacity:.6}70%{opacity:1}}

/* 帐篷灯 */
.spot-tent .tp,#tent .tp{fill:#4a7fa4;stroke:var(--amber);stroke-width:1.3;transition:fill .7s,stroke .7s}
.spot-tent .tl,#tent .tl{fill:var(--amber);opacity:var(--win);transition:opacity .7s}
html[data-scene="day"] .spot-tent .tp,#tent .tp{fill:#e8d9c4;stroke:#a8734a}

/* 告示牌 */
.spot-sign .tk,#sign .tk{fill:var(--trunk);transition:fill .7s}
.spot-sign .bd,#sign .bd{fill:#8f6440;stroke:var(--amber);stroke-width:1.3;transition:stroke .7s}
.spot-sign .ln,#sign .ln{fill:var(--amber);transition:fill .7s}

/* 篝火 */
.campfire{position:relative;width:9px;height:9px;border-radius:50%;
  background:var(--amber);box-shadow:0 0 26px 10px rgba(var(--tint),.55);
  animation:fire 2.4s ease-in-out infinite;opacity:var(--fire);transition:opacity .7s}
.campfire::before,.campfire::after{content:"";position:absolute;bottom:100%;left:50%;width:2px;height:14px;
  transform-origin:50% 100%;background:linear-gradient(0deg,rgba(255,180,84,.9),transparent);
  border-radius:2px;animation:flame 1.6s ease-in-out infinite}
.campfire::before{margin-left:-5px;animation-delay:-.5s}
.campfire::after{margin-left:3px;height:18px;animation-delay:-.9s}
@keyframes fire{0%,100%{transform:scale(1);opacity:.85}50%{transform:scale(1.45);opacity:1}}
@keyframes flame{0%,100%{transform:scaleY(.8) rotate(-6deg);opacity:.8}50%{transform:scaleY(1.3) rotate(6deg);opacity:1}}
html[data-weather="rain"] .campfire,html[data-weather="storm"] .campfire,
html[data-weather="snow"] .campfire{opacity:.25}

/* 树可摇（彩蛋） */
.tree{pointer-events:auto;cursor:pointer}
.tree:active,.tree.shake{animation:tree-shake .55s ease-in-out!important;
  animation-delay:0s!important}
@keyframes tree-shake{0%,100%{transform:rotate(0)}25%{transform:rotate(-6deg)}75%{transform:rotate(6deg)}}

/* ================= 控件 ================= */
button{font:inherit;cursor:pointer;border:1px solid var(--stroke);background:var(--glass-hi);
  color:var(--text);border-radius:10px;padding:6px 13px;transition:.18s cubic-bezier(.4,0,.2,1)}
button:hover{background:rgba(var(--tint),.15);border-color:rgba(var(--tint),.42);transform:translateY(-1px)}
button:active{transform:translateY(0) scale(.98)}
button.primary{background:var(--me-bubble);border-color:transparent;color:var(--me-text);font-weight:600;box-shadow:var(--glow)}
button.primary:hover{filter:brightness(1.07);box-shadow:0 0 30px rgba(var(--tint),.45)}
button.danger{color:var(--ember);border-color:rgba(255,111,97,.35)}
button.danger:hover{background:rgba(255,111,97,.14);border-color:var(--ember)}
button.link{border:0;background:none;color:var(--amber);padding:4px 8px}
button.link:hover{background:rgba(var(--tint),.13);transform:none}
input,textarea,select{font:inherit;color:var(--text);background:var(--glass-hi);
  border:1px solid var(--stroke);border-radius:10px;padding:8px 11px;width:100%;transition:.18s}
input::placeholder,textarea::placeholder{color:var(--text-faint)}

/* 下拉框：原生 <option> 由操作系统绘制，不继承页面 CSS 变量。
   在 Windows / 部分安卓上会强制用白底，而弹窗里的文字又是浅色 → 白底白字看不见。
   这里显式给 option 写死一套深色（浅色场景下再覆盖成浅色）。 */
select{appearance:none;-webkit-appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
                   linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 17px) 51%,calc(100% - 12px) 51%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:32px}
select option{background:#2a2038;color:#f2ece4}
html[data-scene="day"] select option{background:#fffdf7;color:#33251c}
html[data-scene="dawn"] select option{background:#3a2a48;color:#fdf3ea}
html[data-scene="dusk"] select option{background:#3a2436;color:#fdf0e2}
/* Windows 上被选中项的默认蓝底白字在深色下拉里很突兀，统一一下 */
select option:checked,select option:hover{background:rgba(var(--tint),.32);color:#fff}
html[data-scene="day"] select option:checked,
html[data-scene="day"] select option:hover{background:rgba(var(--tint),.28);color:#33251c}
input:focus,textarea:focus,select:focus{outline:none;border-color:rgba(var(--tint),.55);
  background:rgba(var(--tint),.08);box-shadow:0 0 0 3px rgba(var(--tint),.14)}
ul{list-style:none;margin:0;padding:0}
.grow{flex:1}
small{font-size:12px;color:var(--text-dim)}
::selection{background:rgba(var(--tint),.35)}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(var(--tint),.24);border-radius:9px;border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:rgba(var(--tint),.48);background-clip:content-box}
.list,.admin-wrap,#modal-box{scrollbar-width:thin;scrollbar-color:rgba(var(--tint),.32) transparent}

/* 串灯 */
.fairy{position:relative;height:26px;flex:none;overflow:hidden}
.fairy::before{content:"";position:absolute;left:0;right:0;top:3px;height:1px;
  background:linear-gradient(90deg,transparent,rgba(var(--tint),.3) 12%,rgba(var(--tint),.3) 88%,transparent)}
.fairy i{position:absolute;top:4px;width:6px;height:6px;border-radius:50%;background:var(--amber);
  box-shadow:0 0 10px 2px rgba(var(--tint),.7);animation:twinkle 3.4s ease-in-out infinite}
.fairy i:nth-child(3n){animation-duration:2.6s}
.fairy i:nth-child(4n){animation-duration:4.1s}
.fairy i:nth-child(5n){animation-duration:3s}
@keyframes twinkle{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.3;transform:scale(.8)}}
@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.13)}}

/* ================= 骨架 ================= */
#app{position:relative;z-index:1;display:flex;height:100vh;height:100dvh;padding:14px;gap:14px;
  transition:opacity .35s ease,transform .35s cubic-bezier(.4,0,.2,1)}
#sidebar{width:298px;flex:none;display:flex;flex-direction:column;min-height:0;
  background:var(--glass);border:1px solid var(--stroke);border-radius:14px;
  backdrop-filter:blur(18px) saturate(1.35);-webkit-backdrop-filter:blur(18px) saturate(1.35);
  box-shadow:var(--shadow);overflow:hidden;transition:background .7s}
#main{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;
  background:var(--glass);border:1px solid var(--stroke);border-radius:14px;
  backdrop-filter:blur(18px) saturate(1.35);-webkit-backdrop-filter:blur(18px) saturate(1.35);
  box-shadow:var(--shadow);overflow:hidden;transition:background .7s}
.view{display:none;flex:1;flex-direction:column;min-height:0}
.view.active{display:flex;animation:view-in .3s cubic-bezier(.22,1,.36,1) both}
@keyframes view-in{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}

/* 营地模式
   用 flex 三段式分区（顶 / 中 / 底），元素之间物理隔离，
   不会像全 absolute 那样在窄屏互相压叠。 */
body.camp #app{opacity:0;transform:scale(.97) translateY(10px);pointer-events:none}
body.camp .scenery{height:68vh}

#camp-layer{
  position:fixed;inset:0;z-index:20;
  display:flex;flex-direction:column;
  padding:calc(env(safe-area-inset-top, 0px) + 14px) 14px calc(env(safe-area-inset-bottom, 0px) + 14px);
  /* visibility:hidden 是关键：只写 opacity:0 的话元素仍会拦截点击，
     会挡住下面的「去营区转转」等按钮。 */
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .4s ease,visibility .4s}
/* 关键：营地浮层本身全程不接收点击（连同它的 padding 区域）。
   只有底部按钮区 / 顶部文字区显式开启。
   这样中间整片（包括浮层的内边距）都直接穿透到下面的场景元素上，
   不会出现「看得见但点不到」的隐形拦截层。 */
body.camp #camp-layer{opacity:1;visibility:visible;pointer-events:none}

.camp-top{flex:none;display:flex;flex-direction:column;align-items:center;gap:5px;
  text-align:center;pointer-events:auto}
.camp-mid{flex:1;min-height:0;pointer-events:none}
.camp-bottom{flex:none;display:flex;flex-direction:column;align-items:center;gap:10px;pointer-events:auto}

.camp-title{font-size:19px;letter-spacing:3px;
  color:var(--text);text-shadow:0 2px 14px rgba(0,0,0,.5)}
.camp-tip{font-size:12px;letter-spacing:1.2px;opacity:.8;
  color:var(--text);text-shadow:0 2px 14px rgba(0,0,0,.5)}

/* 营地里的天气徽章改为常规流式元素（登录页那份仍是绝对定位） */
#camp-layer .weather-badge{position:static;transform:none;display:inline-block;
  font-size:11px;letter-spacing:1px;color:var(--text-dim);opacity:.85;
  background:rgba(0,0,0,.22);padding:3px 12px;border-radius:12px;white-space:nowrap}

/* 营地模式：场景元素可点；非营地时被 UI 挡住，不抢焦点 */
.scenery .spot{pointer-events:none;opacity:.55;transition:opacity .35s}
body.camp .scenery .spot{pointer-events:auto;opacity:1}
body:not(.camp) .scenery .spot .cap{opacity:0}

/* 深色半透明底上的文字色：固定暖白，不随场景变。
   营地按钮（时辰/天气/换肤/回车上）的背景恒为深色，
   若文字跟着 --text 走，白天会变成深棕黑字压在深底上，完全看不见。 */
:root{--on-dark:#fbf3e8}

.camp-ctrl{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.camp-ctrl button{padding:7px 14px;border-radius:20px;font-size:12px;letter-spacing:1px;
  background:rgba(24,16,36,.5);border:1px solid rgba(255,226,196,.2);color:var(--on-dark);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
.camp-ctrl button:hover{border-color:var(--amber);color:var(--amber)}
.camp-exit{padding:9px 20px;border-radius:24px;
  background:rgba(24,16,36,.5);border:1px solid rgba(255,226,196,.25);color:var(--on-dark);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);letter-spacing:1.5px}
.camp-exit:hover{border-color:var(--amber);color:var(--amber)}

/* ================= 侧栏 ================= */
#quick-bar{display:flex;gap:6px;padding:8px 11px;flex:none;border-bottom:1px solid var(--stroke-2)}
#quick-bar button{flex:1;display:flex;align-items:center;justify-content:center;gap:5px;
  padding:7px 4px;font-size:12px;border-radius:9px;background:var(--glass-hi)}
#quick-bar button .ic{font-size:14px;line-height:1}
#quick-bar button:hover{background:rgba(var(--tint),.16);border-color:rgba(var(--tint),.45);transform:none}

#me-bar{display:flex;align-items:center;gap:10px;padding:12px 13px;
  border-bottom:1px solid var(--stroke-2);flex:none}
.avatar{width:36px;height:36px;flex:none;border-radius:11px;display:flex;align-items:center;justify-content:center;
  font-size:15px;font-weight:600;color:#fff;
  background:linear-gradient(135deg,var(--amber),var(--amber-deep));
  box-shadow:0 3px 12px rgba(var(--tint),.35)}
.me-info{display:flex;flex-direction:column;line-height:1.35;min-width:0;flex:1}
.me-info b{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.me-info small{font-size:11px;letter-spacing:.3px}
.me-info small b{color:var(--amber);font-variant-numeric:tabular-nums;letter-spacing:1.2px}
#me-bar .ico-btn{border:0;background:none;padding:4px 6px;font-size:14px;color:var(--text-dim);line-height:1}
#me-bar .ico-btn:hover{color:var(--amber);background:rgba(var(--tint),.13);transform:none}

/* 开/关灯：放在「我的 ID」那一栏右侧，不再占用下面快捷栏的位置。
   灯亮时是暖黄发光的小圆钮，关掉时变暗 —— 一眼能看出当前状态。 */
#btn-lamp{flex:none;width:34px;height:34px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-size:15px;line-height:1;cursor:pointer;
  background:var(--glass-hi);border:1px solid var(--stroke-2);
  transition:background .2s,border-color .2s,box-shadow .25s,transform .15s}
#btn-lamp:hover{background:rgba(var(--tint),.16);border-color:rgba(var(--tint),.5);
  transform:scale(1.08)}
#btn-lamp:active{transform:scale(.94)}
#btn-lamp.on{background:rgba(255,196,88,.20);border-color:rgba(255,196,88,.62);
  box-shadow:0 0 14px rgba(255,196,88,.42),inset 0 0 8px rgba(255,196,88,.22)}
#btn-lamp.on #lamp-ic{filter:drop-shadow(0 0 5px rgba(255,206,110,.9))}
#btn-lamp.off #lamp-ic{opacity:.5;filter:grayscale(.55)}

#tabs{display:flex;gap:2px;padding:8px 8px 0;flex:none}
.tab{flex:1;border:0;background:none;padding:9px 2px;color:var(--text-dim);
  position:relative;font-size:13px;border-radius:9px 9px 0 0}
.tab:hover{color:var(--text);background:var(--glass-hi);transform:none}
.tab.active{color:var(--amber);font-weight:600}
.tab.active::after{content:"";position:absolute;left:22%;right:22%;bottom:0;height:2px;
  background:var(--amber);border-radius:2px;box-shadow:0 0 10px rgba(var(--tint),.7)}
.badge{display:inline-block;min-width:17px;padding:0 5px;margin-left:4px;
  background:linear-gradient(135deg,var(--amber-deep),var(--ember));color:#fff;border-radius:10px;
  font-size:10px;line-height:17px;text-align:center;vertical-align:1px;font-weight:700;
  box-shadow:0 0 12px rgba(var(--tint),.5);animation:pulse 2.4s ease-in-out infinite}

#panes{flex:1;display:flex;flex-direction:column;min-height:0}
/* 再加一层保险：万一某个 pane 内部元素溢出，也不至于盖到底部按钮上 */
.pane{display:none;flex:1;flex-direction:column;min-height:0;overflow:hidden}
.pane.active{display:flex;animation:fade-up .26s ease both}

/* ⚠️ .fold-body 才是 .pane 的直接 flex 子项（pane-bar 和 .list 都包在它里面）。
   之前它没有任何 flex 设置：作为 flex 子项 min-height 默认 auto = 内容高度，
   于是整块被列表内容撑开、溢出 .pane，底部被裁掉 ——
   看起来就是「列表最下面被 去营区转转 / 休息一下 挡住了」。

   必须让它也参与收缩：flex:1 + min-height:0，并自己成为 column flex 容器，
   内部的 .list 才能在它里面正常滚动。
   ⚠️ 只加 min-height:0 不够，必须是 flex:1（否则它按内容高，不占剩余空间）。 */
.fold-body{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}
@keyframes fade-up{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.pane-bar{display:flex;gap:7px;padding:9px 11px;flex:none;border-bottom:1px solid var(--stroke-2)}
.pane-bar input{flex:1;min-width:0;padding:7px 11px;border-radius:11px}
.pane-bar button{flex:none;padding:7px 13px;font-size:13px}

/* 折叠头 + 搜索栏同一行（会话/好友/备忘/广播）
   —— 省掉原来「折叠头占一行、工具栏再占一行」的两行高度。
   .fold-head 原来是 width:100% + margin-bottom，这里要收成一颗小胶囊。 */
.pane-head{display:flex;align-items:center;gap:7px;padding:8px 11px;flex:none;
  border-bottom:1px solid var(--stroke-2)}
.pane-head .fold-head{flex:none;width:auto;margin:0;padding:6px 10px;
  border-radius:10px;font-size:12.5px}
.pane-head .pane-bar{flex:1;min-width:0;padding:0;border:0;
  display:flex;gap:6px;align-items:center}
.pane-head .pane-bar input{flex:1;min-width:0;padding:6px 10px;font-size:12.5px}
.pane-head .pane-bar button{flex:none;padding:6px 10px;font-size:12.5px}
/* 折叠后：工具栏收起，只留「箭头 + 名称 + 数字」 */
.pane.folded .pane-head .pane-bar{display:none}
.pane.folded .pane-head{padding-bottom:9px}
/* ⚠️ min-height:0 是必须的：
   flex 子项的自动最小尺寸（min-height:auto）默认等于内容高度，
   即使写了 overflow-y:auto，列表也会被内容撑开、溢出 .pane，
   视觉上"长列表延伸到 去营区转转 / 休息一下 那一行"，还会挡住按钮的点击。
   加上 min-height:0 才能让它真正收缩并在内部滚动。 */
/* padding-bottom：滚到底时最后一条不紧贴容器边缘，看起来才「完整显示」 */
.list{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:5px 0 12px}

.item{display:flex;gap:11px;align-items:center;padding:10px 13px;cursor:pointer;position:relative;transition:background .18s}
.item::before{content:"";position:absolute;left:0;top:16%;bottom:16%;width:3px;border-radius:0 3px 3px 0;pointer-events:none;
  background:var(--amber);opacity:0;transition:.2s}
.item:hover{background:var(--glass-hi)}
.item:hover::before{opacity:.45}
.item.active{background:rgba(var(--tint),.14)}
.item.active::before{opacity:1;box-shadow:0 0 12px rgba(var(--tint),.85)}
.item .avatar{width:38px;height:38px;border-radius:12px;font-size:14px}
.item.group .avatar{background:linear-gradient(135deg,#9d8bd6,#7b68c4)}
.item .i-main{flex:1;min-width:0}
.item .i-title{display:flex;align-items:center;gap:6px;font-size:14px}
.item .i-title b{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.item .i-sub{color:var(--text-dim);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.item.active .i-sub{color:var(--text-faint)}
.item .i-id{color:var(--text-faint);font-size:11px;font-variant-numeric:tabular-nums}
.dot{width:7px;height:7px;border-radius:50%;background:var(--text-faint);flex:none;display:inline-block;transition:.3s}
.dot.on{background:var(--sage);box-shadow:0 0 0 3px rgba(111,195,154,.2);animation:breathe 2.6s ease-in-out infinite}
@keyframes breathe{0%,100%{box-shadow:0 0 0 3px rgba(111,195,154,.18)}50%{box-shadow:0 0 0 6px rgba(111,195,154,.06)}}
.pill{margin-left:auto;flex:none;background:linear-gradient(135deg,var(--amber-deep),var(--ember));color:#fff;
  border-radius:10px;font-size:11px;font-weight:700;min-width:19px;padding:0 6px;line-height:19px;
  text-align:center;box-shadow:0 0 14px rgba(var(--tint),.45);animation:pulse 2.4s ease-in-out infinite}
.empty-tip{color:var(--text-faint);text-align:center;padding:30px 14px;font-size:13px;line-height:1.9}

#camp-bar{flex:none;padding:9px 11px;border-top:1px solid var(--stroke-2)}
/* 去营区转转 / 我的家 并排 */
#camp-bar{display:flex;gap:8px}
#camp-bar button{flex:1;justify-content:center;min-width:0;white-space:nowrap}
#btn-camp{width:100%;display:flex;align-items:center;justify-content:center;gap:7px;padding:8px;
  letter-spacing:2px;font-size:13px}

/* ================= 空状态 ================= */
#view-empty{align-items:center;justify-content:center;text-align:center}
.center-hint{color:var(--text-faint)}
#view-empty .rv-logo{width:118px;opacity:.45;margin-bottom:12px;color:var(--text)}
#btn-camp-big{margin-top:16px;padding:10px 26px;border-radius:24px;letter-spacing:2px}

/* ================= 聊天 ================= */
#chat-header{display:flex;align-items:center;gap:11px;padding:11px 16px;flex:none;
  border-bottom:1px solid var(--stroke-2);background:linear-gradient(180deg,rgba(var(--tint),.06),transparent)}
.chat-title-wrap{display:flex;flex-direction:column;line-height:1.4;min-width:0}
.chat-title-wrap b{font-size:15.5px;letter-spacing:.2px}

.back-btn{display:none;flex:none;border:0;background:none;font-size:24px;padding:0 8px 0 0;
  color:var(--text-dim);line-height:1}
.back-btn:hover{color:var(--amber);transform:none;background:none}

/* ⚠️ .back-btn 默认 display:none，只在窄屏 media query 里才显示 ——
   那是给"聊天视图"设计的（宽屏靠点侧栏切换，不需要返回）。
   但下面这几个是"子页面"：宽屏也一样得靠这个按钮返回，
   所以必须始终可见，否则在电脑上根本找不到返回的入口。

   另外原来只有一个 ‹ 字符，在手机角落里又小又看不清、也很难点中。
   现在做成带「返回」二字的胶囊按钮，触控目标 ≥44px（iOS 建议值）。 */
#admin-header .back-btn,
#logs-header .back-btn,
#hide-header .back-btn,
#umemos-header .back-btn,
#udoodles-header .back-btn,
#ann-view-head .back-btn{
  display:inline-flex;align-items:center;gap:4px;
  cursor:pointer;font-size:14px;line-height:1;
  padding:11px 16px 11px 12px;
  min-height:44px;
  border-radius:22px;
  border:1px solid var(--stroke);
  background:rgba(255,255,255,.06);
  color:var(--text);
  white-space:nowrap;
  flex:none}
#admin-header .back-btn:hover,
#logs-header .back-btn:hover,
#hide-header .back-btn:hover,
#umemos-header .back-btn:hover,
#udoodles-header .back-btn:hover,
#ann-view-head .back-btn:hover{
  color:var(--amber);border-color:rgba(var(--tint),.55);
  background:rgba(var(--tint),.13)}
#admin-header .back-btn:active,
#logs-header .back-btn:active,
#hide-header .back-btn:active,
#umemos-header .back-btn:active,
#udoodles-header .back-btn:active,
#ann-view-head .back-btn:active{
  transform:scale(.96);background:rgba(var(--tint),.2)}

#msg-list{flex:1;overflow-y:auto;padding:20px 18px 10px;overscroll-behavior:contain}
.load-more{display:block;margin:4px auto 12px;color:var(--text-faint);font-size:12px}
.day-sep{text-align:center;margin:16px 0 12px;font-size:11px;color:var(--text-faint);
  letter-spacing:1.5px;position:relative}
.day-sep::before,.day-sep::after{content:"";position:absolute;top:50%;width:22%;height:1px;
  background:linear-gradient(90deg,transparent,var(--stroke))}
.day-sep::before{left:6%}
.day-sep::after{right:6%;transform:scaleX(-1)}

/* 消息：注意不要使用 overflow-wrap:anywhere，它会让 min-content 塌缩成一个字符，
   在窄屏 flex 收缩时把气泡压成竖排 */
.msg{display:flex;gap:9px;margin-bottom:13px;align-items:flex-end}
.msg.mine{flex-direction:row-reverse}
.msg .col{display:flex;flex-direction:column;gap:4px;min-width:0;max-width:min(70%,540px);flex:0 1 auto}
.msg.mine .col{align-items:flex-end}
/* 纯画作消息：不要气泡外壳（背景、边框、圆角、投影全去掉），
   让画直接浮在会话背景上 —— 跟笔记里一致。 */
.msg .doodle-only{
  display:block;max-width:100%;padding:0;
  background:none;border:0;border-radius:0;
  box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none;
  line-height:0}
/* 万一里面还混着文字，文字还是要有可读性 */
.msg .doodle-only span{line-height:1.62}

.msg .bubble{
  display:block;
  max-width:100%;
  min-width:3.2em;              /* 至少放得下 3 个字，杜绝竖排 */
  width:auto;
  padding:9px 14px;border-radius:16px;
  background:var(--bubble);border:1px solid var(--bubble-stroke);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  white-space:pre-wrap;
  overflow-wrap:break-word;
  word-break:normal;
  line-height:1.62;
  box-shadow:var(--shadow-sm);
  border-bottom-left-radius:5px}
.msg.mine .bubble{background:var(--me-bubble);border-color:transparent;color:var(--me-text);
  font-weight:500;box-shadow:0 4px 18px rgba(var(--tint),.3);
  border-bottom-left-radius:16px;border-bottom-right-radius:5px}
.msg .avatar{width:30px;height:30px;border-radius:9px;font-size:12px;flex:none;color:#fff}
.msg .avatar.c0{background:linear-gradient(135deg,#8e7cc8,#6f5cb0)}
.msg .avatar.c1{background:linear-gradient(135deg,#6fa8c9,#4b83ad)}
.msg .avatar.c2{background:linear-gradient(135deg,#c98f6f,#ad6f4b)}
.msg .avatar.c3{background:linear-gradient(135deg,#7fb98f,#4f9670)}
.msg .avatar.c4{background:linear-gradient(135deg,#c97f9f,#ad4f78)}
.msg .avatar.c5{background:linear-gradient(135deg,#c9b56f,#a8923f)}
.msg.mine .avatar{background:linear-gradient(135deg,var(--amber),var(--amber-deep))}
.msg-meta{font-size:10.5px;color:var(--text-faint);padding:0 4px;max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msg.mine .msg-meta{text-align:right}
.msg.compact{margin-top:-8px}
.msg.compact .msg-meta{display:none}
.msg.compact .avatar{visibility:hidden}
.msg--enter{animation:msg-in .34s cubic-bezier(.22,1.2,.36,1) both}
@keyframes msg-in{from{opacity:0;transform:translateY(10px) scale(.97)}to{opacity:1;transform:none}}
.msg.pending{opacity:.55}
.msg.failed .bubble{border-color:rgba(255,111,97,.6);background:rgba(255,111,97,.13);cursor:pointer}
.msg.failed .bubble::after{content:" ⚠";color:var(--ember)}
/* 纯画作消息没有气泡外壳，发送失败也要有提示 */
.msg.failed .doodle-only::after{content:" ⚠";color:var(--ember);
  font-size:13px;line-height:1;display:inline-block;vertical-align:top}

#form-send{display:flex;gap:9px;padding:12px 14px;flex:none;align-items:flex-end;
  border-top:1px solid var(--stroke-2);background:linear-gradient(0deg,rgba(var(--tint),.05),transparent)}
#msg-input{resize:none;max-height:130px;overflow-y:auto;line-height:1.6;border-radius:13px;padding:10px 14px}
#btn-emoji{flex:none;height:40px;width:40px;padding:0;border-radius:12px;font-size:19px;line-height:1;
  display:flex;align-items:center;justify-content:center}
#btn-emoji:hover{background:rgba(var(--tint),.18);border-color:rgba(var(--tint),.45);transform:translateY(-1px)}
#btn-send{flex:none;height:40px;width:52px;padding:0;border-radius:13px;display:flex;
  align-items:center;justify-content:center;background:var(--me-bubble);border-color:transparent;
  color:var(--me-text);box-shadow:var(--glow)}
#btn-send:hover{filter:brightness(1.08)}
#btn-send svg{width:19px;height:19px;transition:transform .2s}
#btn-send:hover svg{transform:translateX(2px) rotate(-4deg)}

/* ================= 备忘录 ================= */
#memo-header{display:flex;align-items:center;gap:8px;padding:11px 16px;flex:none;border-bottom:1px solid var(--stroke-2)}
/* 笔记标题：一行输入框，跟着纸一起变（所以也受纸材质影响） */
#memo-title-row{padding:10px 14px 0;flex:none}
/* 「更新于…」单独一行 —— 上面那排留给按钮 */
#memo-sub{display:flex;align-items:center;gap:10px;flex-wrap:wrap;flex:none;
  padding:7px 16px 2px;font-size:11.5px;color:var(--text-faint)}
#memo-sub small{font-size:11.5px;color:var(--text-faint);white-space:nowrap}
#memo-sub #memo-state{white-space:nowrap}
#memo-title{width:100%;box-sizing:border-box;padding:8px 11px;border-radius:10px;
  background:var(--glass);border:1px solid var(--stroke);color:var(--text);
  font-size:14px;font-weight:600;outline:none;
  font-family:inherit;transition:border-color .2s}
#memo-title:focus{border-color:var(--amber)}
/* 笔记编辑区：玻璃本体是暗的（--panel-a 只有 .46），
   所以开灯时这里要"深色底 + 浅字"，不能反过来配浅底深字 —— 那样会整个糊掉。 */
body[data-lamp="1"] #memo-title{background:rgba(46,34,24,.55);
  border-color:rgba(255,226,178,.24)}
body[data-lamp="1"] #memo-title::placeholder{color:#e3d5c0;
  -webkit-text-fill-color:#e3d5c0;opacity:1}
/* "更新于 xx:xx / 保存状态"：小字不加阴影，用提亮 + 加字重来保证可读。 */
body[data-lamp="1"] #memo-sub small,
body[data-lamp="1"] #memo-state{color:#e8dcc8;font-weight:600}
body[data-lamp="1"] #memo-state.saving{color:#e8dcc8}
/* 提示文字：原来用最淡的 --text-faint，压在深色玻璃上几乎看不见。
   换成亮一档的 --text-dim 并加一点描边，浅底深底都读得出来。 */
#memo-title::placeholder{color:var(--text-dim);font-weight:400;opacity:1;
  text-shadow:none;-webkit-text-fill-color:var(--text-dim)}
@media (max-width:760px){#memo-title-row{padding:8px 10px 0}#memo-title{font-size:13.5px}
#memo-sub{padding:6px 10px 2px}}

/* ================= 笔记纸材质 =================
   做法：每种纸只改三个变量（底色 / 墨色 / 纹理），结构统一、好加好改。
   全部纯 CSS 生成，不存任何图片，零存储开销。

   ⚠️ 横线周期统一 28px，正好等于行高（14.5px × 1.95 ≈ 28.3px），
      padding-top 也是 28px —— 这样每一条线都落在文字底部，不会越写越飘。
      原来的 30px 周期和行高对不上，写十几行就会明显错位。 */
/* ⚠️ 纸的两个变量必须在这里给默认值。
   原来只写在 [data-paper] 里，而笔记默认不设 data-paper ——
   于是 --paper-bg / --paper-ink 全都没定义：
     背景变透明（夜里透出深色玻璃）、占位提示却用了写死的深色兜底 #33251c，
     深色字压深色背景 —— 这就是"关灯时『写点什么』看不见"的根因。
   这里补上默认值，[data-paper] 的选择器更靠后，仍能覆盖它。 */
/* ⚠️ 千万别在这里（#memo-body，ID 选择器 1,0,0）声明纸变量：
   会压过下面所有 [data-paper="xxx"]（0,1,0），结果每种纸都变素白、纹理全丢。
   需要兜底就在用的时候写 var(--paper-bg,#fffdf9) 这样的 fallback。 */
#memo-body{flex:1;border:0;border-radius:0;padding:28px 30px;line-height:1.95;
  font-size:14.5px;overflow-y:auto;min-height:0;
  white-space:pre-wrap;word-break:break-word;
  -webkit-user-select:text;user-select:text;
  background-color:var(--paper-bg,#fffdf9);
  color:var(--paper-ink,#33251c);
  background-image:var(--paper-img,none);
  background-size:var(--paper-size,auto);
  background-attachment:local;
  transition:background-color .35s,color .35s}
/* 占位提示：原来只有 .38 的不透明度，在浅色纸（米黄、粉）上淡到看不清。
   垫一层中性灰底（浅纸上变深、深纸上变浅，两边都能衬住字），
   再把不透明度提到 .62 —— 够清楚，又不会抢正文。 */
#memo-body:empty::before,
#memo-body:has(> br:only-child)::before{content:attr(data-ph);
  /* 用纸自己的墨色（浅纸→深字、深纸如夜航本→浅字），
     ⚠️ 不能再写 #33251c 兜底 —— 变量没定义时会落到深色，
        在夜里的透明背景上等于隐形。 */
  color:var(--paper-ink,#33251c);opacity:.62;pointer-events:none;
  display:inline-block;padding:1px 7px;border-radius:8px;
  background:rgba(128,120,110,.13);
  text-shadow:0 1px 1px rgba(255,255,255,.28)}
/* 内嵌小画：跟文字排在一起，退格即可删除 */
/* 内嵌小画：跟文字排在一起，退格即可删除。
   ⚠️ 透明底 —— 之前这里写死 #fffdf8，画一插进正文就糊出一块白方块，
   盖住了笔记的纸纹。投影也要去掉（box-shadow 按元素矩形画，
   透明画布上会留一个方块影子，比白底更难看）。 */
.dk-memo-cv{display:inline-block;vertical-align:middle;margin:2px 4px;
  width:132px;height:132px;border-radius:12px;background:transparent;cursor:zoom-in}
@media (max-width:760px){ .dk-memo-cv{width:104px;height:104px} }
#memo-body:focus{outline:none;box-shadow:none}

/* 变量在 [data-paper] 上定义，正文和小预览图共用同一套 —— 加纸只改一处 */
[data-paper]{--paper-bg:#fffdf9;--paper-ink:#33251c;--paper-size:auto;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(90,70,55,.12) 28px,rgba(90,70,55,.12) 29px)}

/* ---------- 素雅 ---------- */
[data-paper="plain"]{
  --paper-bg:#fffdf9;--paper-ink:#33251c;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(90,70,55,.12) 28px,rgba(90,70,55,.12) 29px)}
[data-paper="draft"]{
  --paper-bg:#fcfaf3;--paper-ink:#3b3227;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(120,150,175,.28) 28px,rgba(120,150,175,.28) 29px)}
[data-paper="grid"]{
  --paper-bg:#fffef8;--paper-ink:#3a3a34;
  --paper-img:repeating-linear-gradient(0deg,rgba(120,140,120,.16) 0 1px,transparent 1px 28px),
              repeating-linear-gradient(90deg,rgba(120,140,120,.16) 0 1px,transparent 1px 28px)}
[data-paper="dot"]{
  --paper-bg:#fffef9;--paper-ink:#3a3a34;
  --paper-img:radial-gradient(rgba(130,120,110,.32) 1.3px,transparent 1.4px);
  --paper-size:28px 28px}
[data-paper="xuan"]{
  --paper-bg:#f8f2e4;--paper-ink:#4a3f30;
  --paper-img:repeating-linear-gradient(90deg,rgba(190,170,130,.10) 0 1px,transparent 1px 3px),
              repeating-linear-gradient(0deg,rgba(190,170,130,.08) 0 1px,transparent 1px 4px)}
[data-paper="kraft"]{
  --paper-bg:#cba97c;--paper-ink:#4a3520;
  --paper-img:repeating-linear-gradient(45deg,rgba(255,255,255,.06) 0 2px,transparent 2px 4px),
              repeating-linear-gradient(-45deg,rgba(110,80,48,.08) 0 2px,transparent 2px 5px)}
[data-paper="news"]{
  --paper-bg:#f2efe6;--paper-ink:#2f2c26;
  --paper-img:repeating-linear-gradient(0deg,rgba(120,110,95,.05) 0 1px,transparent 1px 3px),
              repeating-linear-gradient(90deg,rgba(120,110,95,.045) 0 1px,transparent 1px 3px)}

/* ---------- 彩色（你要的各种颜色） ---------- */
[data-paper="pink"]{
  --paper-bg:#fdeef4;--paper-ink:#7d4356;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(214,140,170,.26) 28px,rgba(214,140,170,.26) 29px)}
[data-paper="rose"]{
  --paper-bg:#fce4e1;--paper-ink:#8a4a44;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(206,130,120,.24) 28px,rgba(206,130,120,.24) 29px)}
[data-paper="green"]{
  --paper-bg:#eef7e4;--paper-ink:#3f6134;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(130,175,110,.26) 28px,rgba(130,175,110,.26) 29px)}
[data-paper="mint"]{
  --paper-bg:#e6f7f2;--paper-ink:#2f6257;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(110,190,175,.24) 28px,rgba(110,190,175,.24) 29px)}
[data-paper="blue"]{
  --paper-bg:#eaf3fb;--paper-ink:#2f5578;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(120,170,215,.26) 28px,rgba(120,170,215,.26) 29px)}
[data-paper="sky"]{
  --paper-bg:#e4f0fa;--paper-ink:#33617f;
  --paper-img:radial-gradient(rgba(120,175,215,.30) 1.3px,transparent 1.4px);
  --paper-size:28px 28px}
[data-paper="cream"]{
  --paper-bg:#fdf6e0;--paper-ink:#6b5526;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(200,170,95,.26) 28px,rgba(200,170,95,.26) 29px)}
[data-paper="lavender"]{
  --paper-bg:#f1ecfa;--paper-ink:#54467c;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(155,135,205,.24) 28px,rgba(155,135,205,.24) 29px)}
[data-paper="peach"]{
  --paper-bg:#fdeddf;--paper-ink:#8a5233;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(220,155,110,.26) 28px,rgba(220,155,110,.26) 29px)}

/* ---------- 情怀 ---------- */
/* 阿嫲的情书：泛黄信纸 + 淡淡的粉色横条 */
[data-paper="love"]{
  --paper-bg:#fbf3dd;--paper-ink:#6b4a3a;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(229,201,192,.55) 28px,rgba(229,201,192,.55) 29px)}
/* 平安批：南洋侨批那种竖红格的黄纸 */
[data-paper="pingan"]{
  --paper-bg:#f6ecc9;--paper-ink:#7a2e28;
  --paper-img:repeating-linear-gradient(90deg,transparent 0 27px,rgba(200,150,50,.42) 27px 28px)}
/* 夜航本：深色纸，墨色反转成浅色 */
[data-paper="night"]{
  --paper-bg:#252338;--paper-ink:#c8c2dd;
  --paper-img:repeating-linear-gradient(transparent,transparent 28px,rgba(255,255,255,.07) 28px,rgba(255,255,255,.07) 29px)}
.memo-state,#memo-state{font-size:11.5px;letter-spacing:.5px;white-space:nowrap;flex:none}

/* 纸材质选择面板 */
.paper-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(86px,1fr));
  gap:9px;margin-top:4px}
.paper-chip{border:1.5px solid var(--stroke);border-radius:11px;background:none;
  cursor:pointer;padding:0;overflow:hidden;transition:.16s;text-align:center;
  display:flex;flex-direction:column;align-items:stretch}
.paper-chip:hover{border-color:rgba(var(--tint),.5);transform:translateY(-2px)}
.paper-chip.sel{border-color:var(--amber);box-shadow:0 0 0 2px rgba(240,179,87,.28)}
.paper-mini{height:52px;display:block;
  background-color:var(--paper-bg,#fffdf9);background-image:var(--paper-img,none);
  background-size:var(--paper-size,auto);
  border-bottom:1px solid rgba(0,0,0,.06);position:relative}
/* 在预览小图上画几道"假字"，看得出墨色和纹理的实际效果 */
.paper-mini::after{content:'';position:absolute;left:8px;right:8px;top:11px;height:30px;
  background:repeating-linear-gradient(transparent,transparent 5px,
    var(--paper-ink,#33251c) 5px,var(--paper-ink,#33251c) 6.5px);
  opacity:.30;border-radius:1px}
.paper-nm{padding:5px 3px;font-size:11px;color:var(--text-dim);letter-spacing:.3px}
.paper-chip.sel .paper-nm{color:var(--amber)}
/* ⚠️ 分区标题必须 grid-column:1/-1 占满整行。
   它是 .paper-grid 的 grid 子项，不占满的话会被塞进格子里，
   跟着卡片横向排列，"素雅/彩色/情怀"就成了一排而不是三段。 */
.paper-sec{grid-column:1/-1;font-size:11px;color:var(--text-faint);letter-spacing:1.4px;
  margin:14px 0 7px;font-weight:600;
  display:flex;align-items:center;gap:8px;white-space:nowrap}
/* 标题两侧加细线，分隔更清楚 */
.paper-sec::after{content:'';flex:1;height:1px;background:var(--stroke);opacity:.6}
.paper-sec:first-child{margin-top:2px}
/* 笔记列表左侧的纸色条 */
.memo-pflag{width:4px;flex:none;align-self:stretch;min-height:32px;border-radius:3px;
  background-color:var(--paper-bg,#fffdf9);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.10)}
#memo-state.dirty{color:var(--amber)}
#memo-state.saving{color:var(--text-faint)}
#memo-state.saved{color:var(--sage)}
#memo-state.failed{color:var(--ember)}
#memo-header button{flex:none;padding:6px 12px;font-size:12.5px}

/* ================= 请求列表 ================= */
.notice-bar{padding:6px 11px;justify-content:flex-start;border-bottom:1px solid var(--stroke-2)}
.notice-bar .badge{margin-left:2px}
.req-list{border:1px solid var(--stroke);border-radius:11px;background:var(--glass-hi);
  max-height:230px;overflow-y:auto;margin-bottom:8px}
.req-row{display:flex;align-items:center;gap:9px;padding:10px 13px;border-bottom:1px solid var(--stroke-2)}
.req-row:last-child{border-bottom:0}
.req-info{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.45}
.req-info b{font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.req-info small{font-size:11.5px;color:var(--text-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.req-row button{flex:none;padding:5px 12px;font-size:12px;border-radius:8px}
.req-list .empty-tip{padding:18px 12px}
#modal-box label{font-size:12px;color:var(--text-dim);display:block;margin:14px 0 6px}

/* ================= 管理 ================= */
.admin-wrap{flex:1;overflow-y:auto;padding:22px;-webkit-overflow-scrolling:touch}

/* ⚠️ 滚动失效根因：.list 自带 overflow-y:auto + overscroll-behavior:contain。
   在侧栏里这是对的（列表自己滚、不带动外层）；
   但放进 .admin-wrap（块级、不限制高度）后，.list 高度=内容高、本身滚不动，
   而 overscroll-behavior:contain 又阻止滚动向外传播 ——
   于是鼠标停在列表上滚滚轮，整页纹丝不动。

   管理类页面（乘客名单 / 聊天管理 / 隐藏管理）由 .admin-wrap 统一滚动，
   里面的列表必须交出滚动容器身份。 */
.admin-wrap .list{overflow:visible;flex:none;min-height:auto;
  overscroll-behavior:auto;padding:4px 0}
#admin-header{display:flex;align-items:center;gap:4px;margin-bottom:16px}
.admin-wrap h2{font-size:18px;margin:0;letter-spacing:.5px}
.card{background:var(--glass-2);border:1px solid var(--stroke);border-radius:14px;
  padding:18px;margin-bottom:16px;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px)}
.card h3{margin:0 0 14px;font-size:14px;color:var(--amber);letter-spacing:.5px}
.card .row{display:flex;gap:13px;flex-wrap:wrap}
.card .row label{flex:1;min-width:150px;display:flex;flex-direction:column;gap:5px;font-size:12px;color:var(--text-dim)}
.card button{margin-top:15px}
.hint{display:block;margin-top:11px;color:var(--text-faint);line-height:1.7}
.table-scroll{overflow-x:auto;border-radius:11px;border:1px solid var(--stroke)}
table{width:100%;border-collapse:collapse;font-size:13px}
th{color:var(--text-dim);font-weight:500;font-size:11.5px;text-transform:uppercase;letter-spacing:.7px;background:var(--glass-hi)}
th,td{text-align:left;padding:10px 13px;border-bottom:1px solid var(--stroke-2);white-space:nowrap}
tbody tr{transition:background .15s}
tbody tr:hover{background:var(--glass-hi)}
tbody tr:last-child td{border-bottom:0}
td .act{display:flex;gap:5px}
td .act button{padding:4px 10px;font-size:12px;border-radius:8px}
.pid{font-variant-numeric:tabular-nums;letter-spacing:1.1px;color:var(--amber);font-weight:600}
/* 密码列 */
.pass-cell{white-space:nowrap}
.pass-cell .pw-text{font-family:Consolas,Menlo,monospace;font-size:12.5px;letter-spacing:1px;
  color:var(--text-dim);background:var(--glass-hi);padding:2px 7px;border-radius:6px;margin-right:4px}
.pass-cell .pw-eye{border:0;background:none;padding:2px 3px;font-size:12px;line-height:1;
  color:var(--text-faint)}
.pass-cell .pw-eye:hover{background:rgba(var(--tint),.18);color:var(--amber);transform:none}
.pass-cell .pw-none{color:var(--text-faint);font-size:12px}
.pass-cell .pw-set{border:1px dashed var(--stroke);background:none;padding:2px 8px;
  font-size:11px;border-radius:7px;color:var(--text-faint)}
.pass-cell .pw-set:hover{border-color:var(--amber);color:var(--amber);
  background:rgba(var(--tint),.12);transform:none}
.tag{padding:2px 9px;border-radius:20px;font-size:11px;background:var(--glass-hi);color:var(--text-dim)}
.tag.admin{background:rgba(var(--tint),.18);color:var(--amber)}
.tag.off{background:rgba(255,111,97,.16);color:var(--ember)}

/* ================= 弹窗 / Toast ================= */
#modal{position:fixed;inset:0;background:rgba(10,6,20,.55);display:flex;align-items:center;
  justify-content:center;z-index:60;padding:18px;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  animation:fade-in .22s ease both}
@keyframes fade-in{from{opacity:0}to{opacity:1}}
/* ⚠️ 原来只写了 overflow-y:auto。按 CSS 规范，overflow-x 是 visible 而
   overflow-y 不是 visible 时，overflow-x 会被计算成 auto —— 于是弹窗会冒出
   一条横向滚动条。表情面板里 hover 放大（scale 1.12）的格子正好溢出到右边：
     格子放大 → 横向溢出 → 出现横条 → 横条占掉高度 → 内容区变矮
       → 纵条出现/消失 → 高度又变 → 鼠标下的格子变了 → 放大另一个 → 循环
   这就是「滚动条疯狂显示又隐藏」的原因（只有电脑端有 hover，所以手机没事）。
   明确关掉横向溢出即可切断这个循环。 */
#modal-box{width:min(450px,100%);max-height:84vh;overflow-x:hidden;overflow-y:auto;padding:24px;border-radius:20px;
  background:linear-gradient(160deg,rgba(48,36,66,.97),rgba(32,24,46,.97));
  border:1px solid var(--stroke);box-shadow:0 24px 70px rgba(0,0,0,.5);
  animation:modal-in .3s cubic-bezier(.22,1.2,.36,1) both}
html[data-scene="day"] #modal-box{background:linear-gradient(160deg,#fffdf8,#fff6ea)}
html[data-scene="dawn"] #modal-box{background:linear-gradient(160deg,rgba(70,50,84,.97),rgba(48,34,62,.97))}
html[data-scene="dusk"] #modal-box{background:linear-gradient(160deg,rgba(64,40,60,.97),rgba(42,26,44,.97))}
@keyframes modal-in{from{opacity:0;transform:translateY(18px) scale(.96)}to{opacity:1;transform:none}}
#modal-box h3{margin:0 0 16px;font-size:16.5px;letter-spacing:.4px}
#modal-box p{color:var(--text-dim);line-height:1.8}
#modal-box .m-row{display:flex;flex-direction:column;gap:6px;margin-bottom:13px;font-size:12px;color:var(--text-dim)}
/* 弹窗里的补充说明文字 */
#modal-box .m-note{font-size:11.5px;line-height:1.75;color:var(--text-faint);
  margin:-4px 0 4px;padding:8px 11px;border-radius:9px;
  background:rgba(255,255,255,.04);border-left:2px solid rgba(var(--tint),.4)}

/* 管理页用户名单元格：用户名 + 一个小的「改」按钮 */
.u-cell{white-space:nowrap}
.u-cell .u-name{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px;
  background:rgba(255,255,255,.05);padding:2px 7px;border-radius:6px}
.u-cell .u-edit{margin-left:6px;padding:2px 8px;font-size:11px;border-radius:7px;
  background:transparent;border:1px solid var(--stroke);color:var(--text-dim);cursor:pointer}
/* 昵称：不用等宽字体（中文用等宽很难看），未设置时显示灰色短横 */
.u-cell .u-nick{font-size:12.5px;color:var(--text)}
.u-cell .u-nick:empty::before{content:'—';color:var(--text-dim)}
.u-cell .u-edit:hover{border-color:rgba(var(--tint),.55);color:var(--amber);
  background:rgba(var(--tint),.13)}
#modal-box /* ⚠️ 原来只有 display:flex 没有 flex-wrap，按钮永远挤在一行。
   手机窄屏上四个按钮（保存/加好友进群/解散群/取消）被压到几十像素宽，
   文字就被迫一个字一行，变成竖排 —— 很难看也很难点。
   现在：允许换行 + 文字禁止折行 + 窄屏改两列网格。 */
.m-actions{display:flex;justify-content:flex-end;gap:9px;margin-top:20px;
  flex-wrap:wrap}
#modal-box .m-actions button{
  white-space:nowrap;              /* 文字绝不竖排 */
  flex:0 1 auto;                   /* 不强制拉伸，也不被压扁 */
  min-width:84px;                  /* 至少够放四个字 + 内边距 */
  padding:9px 16px;
  border-radius:10px;
  font-size:13px;
  line-height:1.2}

/* 窄屏：改成两列网格，四个按钮正好两行两列，整齐又好点 */
@media (max-width:520px){
  #modal-box .m-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}
  #modal-box .m-actions button{min-width:0;width:100%;padding:10px 8px}
  /* 单个按钮（比如只有一个「关闭」）时占满整行 */
  #modal-box .m-actions button:only-child{grid-column:1 / -1}
  /* 危险操作（解散群/退出群聊）排到最后，避免手滑点到；
     不跨列 —— 让它和「取消」并排成 2×2，比各占一行更紧凑。 */
  #modal-box .m-actions button.danger{order:9}
  #modal-box .m-actions button.btn-cancel{order:10}
}
#modal-box hr{border:0;border-top:1px solid var(--stroke-2);margin:18px 0}
.mem-list{max-height:230px;overflow-y:auto;border:1px solid var(--stroke);border-radius:11px;background:var(--glass-hi)}
.mem-row{display:flex;align-items:center;gap:9px;padding:9px 13px;border-bottom:1px solid var(--stroke-2);font-size:13px}
.mem-row:last-child{border-bottom:0}
.mem-row input[type=checkbox]{width:auto;accent-color:var(--amber);cursor:pointer}
.mem-row:hover{background:var(--glass-hi)}

#toast{position:fixed;left:50%;bottom:38px;transform:translateX(-50%);z-index:99;
  padding:11px 22px;border-radius:24px;font-size:13px;color:var(--me-text);
  background:var(--me-bubble);box-shadow:0 8px 30px rgba(var(--tint),.4);
  animation:toast-in .32s cubic-bezier(.22,1.2,.36,1) both}
@keyframes toast-in{from{opacity:0;transform:translate(-50%,16px)}to{opacity:1;transform:translate(-50%,0)}}

/* ================= 设置面板 ================= */
.set-group{margin-bottom:18px}
.set-group > label{display:block;font-size:11.5px;color:var(--text-dim);margin-bottom:7px;letter-spacing:.6px}
/* 内嵌分组（环境音里的「音源」） */
.set-group.inset{margin:0 0 12px;padding:10px 12px;border-radius:10px;
  background:rgba(128,128,128,.07);border:1px solid var(--stroke)}
.set-group.inset > .set-label-row{display:flex;align-items:center;gap:7px;margin-bottom:7px}
.set-group.inset > .set-label-row > span{font-size:11.5px;color:var(--text-dim);letter-spacing:.6px}
/* 小问号：点一下展开解释 */
.help-q{flex:none;width:16px;height:16px;line-height:14px;padding:0;border-radius:50%;
  border:1px solid var(--stroke);background:transparent;color:var(--text-faint);
  font-size:10.5px;cursor:pointer;text-align:center}
.help-q:hover{border-color:var(--amber);color:var(--amber)}
.set-note{white-space:pre-line}
.swatches{display:flex;gap:9px;flex-wrap:wrap}
.swatch{width:38px;height:38px;border-radius:11px;border:2px solid transparent;position:relative;
  cursor:pointer;transition:.2s;padding:0}
.swatch:hover{transform:scale(1.08)}
.swatch.sel{border-color:var(--text);box-shadow:0 0 0 3px rgba(var(--tint),.3)}
.swatch i{position:absolute;inset:3px;border-radius:8px;display:block}
.chips{display:flex;gap:7px;flex-wrap:wrap}
.chip{padding:6px 13px;border-radius:18px;font-size:12.5px;cursor:pointer;
  border:1px solid var(--stroke);background:var(--glass-hi);color:var(--text-dim);transition:.18s}
.chip:hover{border-color:rgba(var(--tint),.45);color:var(--text)}
.chip.sel{background:var(--me-bubble);border-color:transparent;color:var(--me-text);font-weight:600}
.set-row{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.set-row span{font-size:12.5px;color:var(--text-dim);min-width:66px}
.set-row input[type=range]{flex:1;accent-color:var(--amber);cursor:pointer}

/* 复选行：开关与文字必须紧贴。
   上面 .set-row span 的 min-width:66px 会把 checkbox 和文字撑开，
   看着像两个不相干的东西，所以这里单独覆盖掉。 */
.set-row.check{gap:8px;margin-bottom:7px;align-items:center;cursor:pointer;
  user-select:none;-webkit-user-select:none}
.set-row.check span{min-width:0;flex:1;font-size:12.5px;color:var(--text);line-height:1.5}
.set-row.check input[type=checkbox]{
  flex:none;width:16px;height:16px;margin:0;padding:0;
  accent-color:var(--amber);cursor:pointer}
.set-row.check:hover span{color:var(--amber)}
.set-row input[type=color]{width:44px;height:30px;padding:0;border:1px solid var(--stroke);
  border-radius:8px;background:none;cursor:pointer}
.set-note{font-size:11.5px;color:var(--text-faint);line-height:1.7;margin-top:10px}

/* ================= Emoji 面板 ================= */
.emoji-panes{margin-top:10px}
/* 网格自己滚：
   · overflow-x:hidden —— 放大后的格子不会溢出到外面触发父级横条
   · padding:4px      —— 给放大的格子留出施展空间，不被裁掉
   · scrollbar-gutter:stable —— 滚动条槽位常驻。否则「内容刚好差一点
     超出 max-height」时会陷入 出现纵条→变窄→又不够→… 的抖动。
   · overscroll-behavior:contain —— 滚到底不带动外层弹窗一起滚 */
.emoji-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:4px;
  max-height:224px;padding:4px;overflow-x:hidden;overflow-y:auto;
  scrollbar-gutter:stable;overscroll-behavior:contain}
.emoji-cell{font-size:20px;padding:5px 0;border:1px solid transparent;background:none;border-radius:8px;
  line-height:1.2}
.emoji-cell:hover{background:rgba(var(--tint),.18);border-color:rgba(var(--tint),.35);transform:scale(1.12)}
.emoji-cell:active{transform:scale(.94)}
/* 窄屏 8 列太挤（每列不到 32px），改成 6 列，格子才点得准 */
@media (max-width:420px){
  .emoji-grid{grid-template-columns:repeat(6,1fr);gap:6px}
  .chip{padding:5px 10px;font-size:12px}
}

/* ================= 搜索结果 ================= */
.search-res{margin-top:12px;max-height:320px;overflow-y:auto}
.hit-row{padding:9px 11px;border:1px solid var(--stroke);border-radius:10px;margin-bottom:7px;
  cursor:pointer;background:var(--glass-hi);transition:.15s}
.hit-row:hover{background:rgba(var(--tint),.14);border-color:rgba(var(--tint),.4)}
.hit-top{display:flex;align-items:center;gap:7px;font-size:12.5px}
.hit-top b{font-size:13px}
.hit-where{font-size:11px;color:var(--amber);background:rgba(var(--tint),.13);
  padding:1px 7px;border-radius:8px}
.hit-body{font-size:13px;color:var(--text-dim);margin-top:4px;line-height:1.6;
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
@keyframes flash-hl{0%,100%{background:transparent}20%{background:rgba(var(--tint),.35)}}
.msg.flash .bubble{animation:flash-hl 1s ease 2}

/* ================= 营地广播 ================= */
.ann-item{border:1px solid var(--stroke);border-radius:11px;padding:11px 13px;margin-bottom:9px;
  background:var(--glass-hi)}
.ann-item.pinned{border-color:rgba(var(--tint),.5);background:rgba(var(--tint),.09)}
.ann-item.unread{border-left:3px solid var(--amber)}
.ann-head{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--text-dim);margin-bottom:5px}
.ann-pin-tag{background:var(--me-bubble);color:var(--me-text);font-size:10px;font-weight:700;
  padding:1px 7px;border-radius:8px}
.ann-dot{background:linear-gradient(135deg,var(--amber-deep),var(--ember));color:#fff;font-size:9px;
  font-weight:700;padding:1px 6px;border-radius:7px;letter-spacing:.5px}
.ann-body{font-size:13.5px;line-height:1.75;white-space:pre-wrap;overflow-wrap:break-word}

/* ================= 主题：草地 / 海边 / 湖边 =================
   草地保留原有的山+树+草；海边、湖边各自一整套专属场景，
   默认 display:none，切到该主题才渲染，不浪费性能。 */

.scene-sea,.scene-lake{position:absolute;left:0;right:0;bottom:0;height:100%;
  pointer-events:none;display:none}
html[data-theme="sea"]  .scene-sea  {display:block}
html[data-theme="lake"] .scene-lake {display:block}

/* 非草地主题时，隐藏草地专属的树（换成椰子树 / 垂柳） */
html[data-theme="sea"]  .trees,
html[data-theme="lake"] .trees{display:none}

/* ---------- 海 ---------- */
.sea-scene{position:absolute;left:0;bottom:19%;width:100%;height:34%}
.sea-body{fill:url(#seaGrad);opacity:.92;
  animation:sea-breathe 9s ease-in-out infinite}
@keyframes sea-breathe{0%,100%{opacity:.9}50%{opacity:.97}}
.wave-g{animation:wave-drift linear infinite}
.wave-g.w1{animation-duration:11s}
.wave-g.w2{animation-duration:8s;animation-direction:reverse}
.wave-g.w3{animation-duration:14s}
@keyframes wave-drift{from{transform:translateX(0)}to{transform:translateX(-1200px)}}
.wave-p{fill:rgba(255,255,255,.16)}
.wp1{fill:rgba(255,255,255,.18)}
.wp2{fill:rgba(255,255,255,.12)}
.wp3{fill:rgba(255,255,255,.09)}
.sea-foam{fill:rgba(255,255,255,.5);animation:foam-pulse 4.5s ease-in-out infinite}
@keyframes foam-pulse{0%,100%{opacity:.32;transform:translateY(0)}
  50%{opacity:.6;transform:translateY(-2px)}}
.sea-ice{fill:#eaf3fb;opacity:0;transition:opacity .8s}
html[data-weather="snow"] .sea-ice{opacity:.82}

/* 椰子树 */
.palm{position:absolute;bottom:19%;width:64px;height:104px;pointer-events:auto;
  transform-origin:50% 100%;animation:palm-sway 6.5s ease-in-out infinite;cursor:pointer}
/* 放在 48%~80% 这段：左边留给房车(4.5%)/帐篷(19%)/告示牌(37%)，右边避开篝火(91%)，
   避免装饰树盖住功能入口导致点不到。 */
.palm.p1{left:50%;animation-delay:-1.2s}
.palm.p2{left:72%;width:52px;height:86px;animation-delay:-3.4s}
@keyframes palm-sway{0%,100%{transform:rotate(-1.6deg)}50%{transform:rotate(1.6deg)}}
.palm-trunk{fill:none;stroke:#7a5a3a;stroke-width:6;stroke-linecap:round}
.palm-leaf{fill:#3f9a52;transform-origin:46px 34px}
html[data-scene="night"] .palm-leaf{fill:#2d6b3c}
html[data-scene="day"]   .palm-leaf{fill:#4cad5c}
html[data-scene="dawn"]  .palm-leaf{fill:#3d8a4c}
html[data-scene="dusk"]  .palm-leaf{fill:#36734a}
.coco{fill:#6b4a2e}

/* 海鸥 */
.gull{position:absolute;width:26px;height:13px;top:16%;left:-40px;
  animation:gull-fly linear infinite}
.gull g,.gull path{fill:none;stroke:rgba(255,255,255,.85);stroke-width:2;stroke-linecap:round}
.gull.g1{animation-duration:26s}
.gull.g2{animation-duration:34s;animation-delay:-14s;top:23%;width:20px}
@keyframes gull-fly{
  0%{transform:translate(0,0)}
  25%{transform:translate(40vw,-14px)}
  50%{transform:translate(80vw,8px)}
  75%{transform:translate(110vw,-10px)}
  100%{transform:translate(140vw,0)}}

/* 帆船 */
.sailboat{position:absolute;bottom:26%;left:58%;width:54px;height:42px;
  animation:boat-bob 7s ease-in-out infinite}
@keyframes boat-bob{0%,100%{transform:translateY(0) rotate(-2deg)}
  50%{transform:translateY(-5px) rotate(2deg)}}
.boat-hull{fill:#8a6a4a}
.boat-mast{stroke:#6b5238;stroke-width:2.5;fill:none}
.boat-sail{fill:#f5efe4;opacity:.95}
.boat-sail.s2{fill:#e6dccb;opacity:.85}

/* 沙滩（海边时草地染成沙色） */
html[data-theme="sea"]{--grass:#e8d9b8; --grass-2:#d6c39c}
html[data-theme="sea"][data-season="summer"]{--grass:#f0e0bc; --grass-2:#dcc9a2}
html[data-theme="sea"][data-season="autumn"]{--grass:#dcc79c; --grass-2:#c4ab84}
html[data-theme="sea"][data-season="winter"]{--grass:#dde6ec; --grass-2:#c5d2dc}
html[data-theme="sea"] .hill-far{fill:#4a6d8a}
html[data-theme="sea"] .hill-mid{fill:#5b7f9c}

/* ---------- 湖 ---------- */
.lake-scene{position:absolute;left:0;bottom:19%;width:100%;height:32%}
.lake-body{fill:url(#lakeGrad);opacity:.9}
.lake-mirror{fill:rgba(255,255,255,.13)}
.wave-g.lw1{animation-duration:16s}
.wave-g.lw2{animation-duration:22s;animation-direction:reverse}
.lwp1,.lwp2{fill:rgba(255,255,255,.08)}
.ripple{fill:none;stroke:rgba(255,255,255,.4);stroke-width:1.5;
  transform-box:fill-box;transform-origin:center;
  animation:ripple-out 5s ease-out infinite}
.ripple.r1{animation-delay:0s}
.ripple.r2{animation-delay:-1.7s}
.ripple.r3{animation-delay:-3.2s}
@keyframes ripple-out{0%{transform:scale(.3);opacity:.55}
  70%{opacity:0}100%{transform:scale(1.6);opacity:0}}
.lake-ice{fill:#eaf3fb;opacity:0;transition:opacity .8s}
html[data-weather="snow"] .lake-ice{opacity:.78}
/* 左右两岸：把湖面收窄到中间，做出「被陆地环抱」的湖，而不是一望无际的海。
   fill 用 var(--grass) → 自动跟随季节变色（春嫩绿/夏深绿/秋草黄/冬雪白）。 */
.lake-bank{fill:var(--grass);transition:fill .7s}
.lake-shore{fill:none;stroke:rgba(255,255,255,.2);stroke-width:3;stroke-linecap:round}

/* 灌木（柳树脚下的前景） */
.bush{position:absolute;width:46px;height:31px;pointer-events:auto;
  transform-origin:50% 100%;animation:bush-sway 8s ease-in-out infinite;cursor:pointer}
.bush .cr{fill:var(--tree-c);transition:fill .7s}
.bush .cr2{fill:var(--tree-c2);transition:fill .7s}
.bush .sn{fill:#f2f7fc;opacity:var(--snow-op);transition:opacity .8s}
@keyframes bush-sway{0%,100%{transform:rotate(-.8deg)}50%{transform:rotate(.8deg)}}

/* 芦苇 */
.reeds{position:absolute;bottom:20%;width:46px;height:70px}
/* 芦苇长在水边：岸线在 27.5% / 72.5%，所以挪到紧邻水线的位置。
   （原来 3% / 88% 现在已经是岸上了，长在岸上说不通） */
.reeds.r-a{left:28%;animation:reed-sway 5.2s ease-in-out infinite}
.reeds.r-b{left:71%;width:38px;height:60px;animation:reed-sway 6.1s ease-in-out infinite reverse}
@keyframes reed-sway{0%,100%{transform:rotate(-2.5deg)}50%{transform:rotate(2.5deg)}}
.reed{fill:none;stroke:#7a9a4a;stroke-width:2.4;stroke-linecap:round;
  transform-origin:50% 100%}
.reed-tip{fill:#a07a45}
html[data-scene="night"] .reed{stroke:#4a6a3a}
html[data-scene="night"] .reed-tip{fill:#6b5238}

/* 垂柳 */
.willow{position:absolute;bottom:20%;width:86px;height:104px;pointer-events:auto;
  transform-origin:50% 100%;animation:willow-sway 7s ease-in-out infinite;cursor:pointer}
/* 柳树全部移到两岸上（原来 wl1 46% / wl2 70% 站在水面中间，不合理）。
   岸线：左岸 0~27.5%、右岸 72.5%~100%（最近处），
   bottom 19%(岸底) ~ 33.5%(岸顶)，树要落在这个区间内。 */
.willow.wl1{left:4%;bottom:30%;animation-delay:-.8s}
.willow.wl2{left:12%;bottom:26%;width:70px;height:86px;animation-delay:-3.1s}
.willow.wl3{left:78%;bottom:26%;animation-delay:-1.9s}
.willow.wl4{left:88%;bottom:30%;width:70px;height:86px;animation-delay:-4.6s}
/* 这两棵小的最靠水线，贴着岸边長（柳树喜水），做成近大远小的层次 */
.willow.wl5{left:17.5%;bottom:22%;width:60px;height:74px;animation-delay:-2.4s}
.willow.wl6{left:74%;bottom:22%;width:56px;height:70px;animation-delay:-5.3s}

/* 灌木贴着树脚，DOM 在树之后所以自然在前 */
.bush.b1{left:8%;bottom:25%}
.bush.b2{left:15%;bottom:21%;width:38px;height:26px;animation-delay:-2.2s}
.bush.b3{left:76%;bottom:21%;width:38px;height:26px;animation-delay:-4.1s}
.bush.b4{left:86%;bottom:25%;animation-delay:-6.3s}
@keyframes willow-sway{0%,100%{transform:rotate(-1.4deg)}50%{transform:rotate(1.4deg)}}
.w-trunk{fill:none;stroke:#5a4030;stroke-width:5;stroke-linecap:round}
.w-branch{fill:none;stroke:#7fa04e;stroke-width:2;stroke-linecap:round;opacity:.85}
.w-crown{fill:#5f8f45;opacity:.9}
html[data-scene="night"] .w-crown{fill:#3c5c30}
html[data-scene="night"] .w-branch{stroke:#4a6a3a}
html[data-scene="autumn"],html[data-season="autumn"] .w-crown{fill:#a8933c}
html[data-season="autumn"] .w-crown{fill:#9c8a3a}
html[data-season="autumn"] .w-branch{stroke:#c0a44a}
html[data-weather="snow"] .w-crown{fill:#dfe9f0}

/* 荷叶 */
.lily{position:absolute;width:44px;height:19px;bottom:24%}
.lily.l1{left:32%;animation:lily-float 6s ease-in-out infinite}
.lily.l2{left:52%;width:32px;bottom:21%;animation:lily-float 7.5s ease-in-out infinite reverse}
.lily.l3{left:64%;width:38px;bottom:26%;animation:lily-float 8.5s ease-in-out infinite}
@keyframes lily-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}
.pad{fill:#4f8f52;opacity:.92}
html[data-scene="night"] .pad{fill:#2f5c36}
.flower{fill:#f4a6c0}

/* 木栈桥 */
.dock{position:absolute;bottom:22%;left:20%;width:120px;height:36px}
.dock-plank{fill:#8a6a4a}
html[data-scene="night"] .dock-plank{fill:#5a4632}
.dock-post{fill:none;stroke:#6b4a2e;stroke-width:3}

/* 湖畔草地更湿润 */
/* 湖畔草地：比内陆更湿润，但必须跟着季节走。
   只覆盖 --grass / --grass-2 变量（草丛 .grass-tuft 用的是 --grass-2，会自动跟上），
   不写死 fill，否则季节规则被压住，秋天冬天就永远是绿的。 */
html[data-theme="lake"]{--grass:#4a7f5a; --grass-2:#3a6a48}
html[data-theme="lake"][data-season="spring"]{--grass:#549055; --grass-2:#427a4b}
html[data-theme="lake"][data-season="summer"]{--grass:#3f7f50; --grass-2:#2f6640}
html[data-theme="lake"][data-season="autumn"]{--grass:#8a8442; --grass-2:#6d6832}
html[data-theme="lake"][data-season="winter"]{--grass:#c8d6e0; --grass-2:#aebfcb}
html[data-theme="lake"] .hill-far{fill:#4a6b64}
html[data-theme="lake"] .hill-mid{fill:#5c7f76}
html[data-theme="lake"][data-season="autumn"] .hill-far{fill:#6b6350}
html[data-theme="lake"][data-season="autumn"] .hill-mid{fill:#7a7260}
html[data-theme="lake"][data-season="winter"] .hill-far{fill:#7d8f9e}
html[data-theme="lake"][data-season="winter"] .hill-mid{fill:#8fa0ad}

/* 减少动效偏好：停掉所有装饰动画 */
@media (prefers-reduced-motion: reduce){
  .sea-body,.wave-g,.sea-foam,.palm,.gull,.sailboat,
  .ripple,.reeds,.willow,.bush,.lily{animation:none!important}
}

/* ================= 环境音按钮 ================= */
#camp-sound.on,#home-sound.on{border-color:var(--amber);color:var(--amber)}
#btn-sound.on .ic{filter:drop-shadow(0 0 6px rgba(255,180,84,.6))}
#btn-sound.on{color:var(--amber)}
/* 音量滑块：原生 accent-color 画出来的轨道，在 0% 和 100% 时都会留出
   大约半个滑块的空隙（浏览器要保证 thumb 完整可见，thumb 中心只能在
   [thumbW/2, 100%-thumbW/2] 之间移动），所以两端看着"没贴到头"。

   解决办法：轨道背景自己画（画在 input 的 background-image 上，
   高度 6px 垂直居中），track 伪元素保持透明不遮挡。
   填充宽度精确地算到 thumb 中心 = p * (100% - 18px) + 9px：
     0%   → 填充到 9px，正好被 thumb 左半边盖住，视觉上是 0
     100% → 填充到 100%-9px，thumb 右半边本身是琥珀色，看着是满的
   这条渐变由 JS 的 syncRange() 写成内联样式（不依赖 CSS 变量继承，
   避免伪元素读不到变量导致填充失效）。下面只是 JS 未执行时的兜底。 */
.set-row input[type=range]{
  -webkit-appearance:none;appearance:none;
  flex:1;min-width:110px;height:20px;margin:0;padding:0;border:0;
  cursor:pointer;accent-color:var(--amber);
  background-color:transparent;
  background-image:linear-gradient(to right,
    var(--amber) 0 calc(0.3 * (100% - 18px) + 9px),
    rgba(255,255,255,.16) calc(0.3 * (100% - 18px) + 9px) 100%);
  background-size:100% 6px;
  background-position:0 center;
  background-repeat:no-repeat;
  --p:0.3}
.set-row input[type=range]:focus{outline:none}
/* track 必须透明，否则会盖住 input 上画好的渐变 */
.set-row input[type=range]::-webkit-slider-runnable-track{
  height:6px;border:0;border-radius:3px;background:transparent}
.set-row input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:18px;height:18px;border-radius:50%;
  margin-top:-6px;                 /* (6 - 18) / 2，让 thumb 与 6px 轨道居中对齐 */
  background:var(--amber);border:0;
  box-shadow:0 1px 5px rgba(0,0,0,.42);
  transition:transform .14s}
.set-row input[type=range]:active::-webkit-slider-thumb{transform:scale(1.16)}
.set-row input[type=range]::-moz-range-track{
  height:6px;border:0;border-radius:3px;background:transparent}
.set-row input[type=range]::-moz-range-progress{
  height:6px;border-radius:3px;background:var(--amber)}
.set-row input[type=range]::-moz-range-thumb{
  width:18px;height:18px;border-radius:50%;
  background:var(--amber);border:0;
  box-shadow:0 1px 5px rgba(0,0,0,.42)}

/* ================= 房车实景背景（/pic） ================= */
#app{position:relative}
#rv-bg{position:absolute;inset:0;z-index:0;pointer-events:none;
  background-size:cover;background-position:center;background-repeat:no-repeat;
  opacity:0;transition:opacity .6s ease;border-radius:14px}
#rv-bg.on{opacity:.42}
/* 有实景图时，玻璃再薄一点，让风景透出来 */
body.has-pic #sidebar,body.has-pic #main{background:var(--glass)}
#sidebar,#main{position:relative;z-index:1}

/* ================= 小画（涂涂画画）在聊天 / 笔记 / 广播里的显示 =================
   画布不在 .dk-root 里（那是画板的作用域），所以样式得写在全局。
   显示尺寸很小，实际内容仍是现场从笔画数据渲染出来的。 */
/* 小画一律透明底 —— 画本身是透明的，垫白底会盖住笔记的纸纹、
   也会在会话里糊出一块白方块。去掉背景，也去掉外框和投影
   （投影是按元素矩形画的，透明画布上会留一个方块影子）。 */
.dk-mini{
  display:inline-block;vertical-align:middle;
  width:96px;height:96px;border-radius:10px;background:transparent;
  display:block;image-rendering:auto;cursor:zoom-in;
}
.memo-doodles{display:flex;flex-wrap:wrap;gap:8px;padding:9px 0 2px}
.memo-doodles:empty{display:none}
.ann-detail-body + .memo-doodles{margin-top:6px}
@media (max-width:760px){
  .dk-mini{width:78px;height:78px}
}

/* ================= 开灯时房车玻璃的暖光 =================
   车厢里点了灯，两块毛玻璃背板应该从背面被暖白黄照亮一点 ——
   不是盖一层色块（那会脏），而是：
     ① 玻璃底色叠一层极淡的暖黄（用 background-image 渐变叠加，
        不动 background-color，所以不影响玻璃本身的透明度）
     ② 加一层很轻的暖色内发光（inset box-shadow）
     ③ 边缘描一圈暖光，像光从玻璃四周透出来
   只在夜晚开灯时生效（body[data-lamp="1"]，由 syncLampWarmth() 标记）。
   白天 / 关灯时属性整个拿掉，自动回落，不留残留。 */
body[data-lamp="1"] #sidebar,
body[data-lamp="1"] #main{
  /* 玻璃被从背面照亮：先铺一层暖白，再叠暖黄，白多于黄 → "亮白亮黄"不是脏黄 */
  background-image:
    radial-gradient(130% 100% at 50% 0%,rgba(255,247,224,.46),transparent 66%),
    radial-gradient(90% 70% at 50% 100%,rgba(255,232,186,.26),transparent 70%),
    linear-gradient(180deg,rgba(255,238,198,.30),rgba(255,222,164,.17));
  box-shadow:
    inset 0 1px 0 rgba(255,250,236,.42),
    inset 0 0 52px rgba(255,209,142,.26),
    inset 0 0 120px rgba(255,226,178,.14),
    0 0 38px rgba(255,200,120,.15);
  border-color:rgba(255,229,182,.34);
  /* 玻璃里的分隔线、卡片也带一点暖调，整体才协调 */
  --stroke-2:rgba(255,226,178,.30);
  /* 关键：把毛玻璃的"冷紫"换成"暖白黄"，这才是"亮起来"的本体。
     注意不能动 --panel-a（那是不透明度，调高只会更实更暗），
     要改的是色相 --panel-rgb —— 车厢里点了灯，玻璃该是暖的。 */
  --panel-rgb:104,86,62; --panel-rgb2:118,98,70}
/* 车厢里的小面板（卡片、输入框）跟着一起暖、一起亮 */
body[data-lamp="1"] #sidebar,
body[data-lamp="1"] #main{--glass-hi:rgba(255,240,214,.16)}
/* ★ 关键纠正：开灯时文字必须是"浅色"，不能是深色。
   玻璃的不透明度 --panel-a 只有 .46，本体始终是深紫/深棕；
   上面那几层暖光是半透明渐变，叠上去整体依然偏暗 ——
   玻璃并没有真的变成"亮白底"。所以深色字压上去 = 糊死，完全看不见。
   点灯后正确的观感是：玻璃透出暖光，夜色依旧暗，文字是暖白色。
   → 这里统一提亮，比默认的夜间文字还要亮一档。 */
body[data-lamp="1"] #sidebar,
body[data-lamp="1"] #main{--text:#fffaf0;--text-dim:#f2e6d3;--text-faint:#d9c9b3}
/* 管理区里那些「行」的底色在亮玻璃上太淡，边框也偏白，
   开灯时整体压深一档，字才浮得出来。 */
body[data-lamp="1"] .log-row,
body[data-lamp="1"] .log-conv{background:rgba(38,28,20,.30);
  border-color:rgba(255,226,178,.16)}
body[data-lamp="1"] .admin-note,
body[data-lamp="1"] .log-head small{color:#e8dcc8}
/* 删除类按钮原本是浅红（#ff9a8a），在暖亮底上发灰 —— 换成深红才压得住 */
/* 删除类按钮：暗底上要亮红才看得见，深红会糊掉 */
body[data-lamp="1"] .log-del{color:#ff9c85;border-color:rgba(255,156,133,.5)}
body[data-lamp="1"] .log-del:hover{background:rgba(255,156,133,.16)}
body[data-lamp="1"] .log-del.danger{color:#ffb3a0;border-color:rgba(255,179,160,.6)}
body[data-lamp="1"] .log-del.danger:hover{background:rgba(255,156,133,.22)}
/* 管理页卡片在亮玻璃上再垫一点底，避免正文和背景糊在一起 */
body[data-lamp="1"] .card{background:rgba(38,28,20,.34)}
/* 输入框/下拉框在开灯时也常常是"白底白字"，统一交给变量管 */
body[data-lamp="1"] .admin-wrap select,
body[data-lamp="1"] .admin-wrap input,
body[data-lamp="1"] .admin-wrap textarea{color:#fff6e8;
  background:rgba(46,34,24,.62);border-color:rgba(255,226,178,.26)}
/* 最小的字（时间 10.5px、ID 11px）不加阴影 —— 小字加阴影只会糊成一团，
   改用"提亮 + 加字重"，在暗玻璃上一样清楚。 */
body[data-lamp="1"] .i-time,
body[data-lamp="1"] .item .i-id,
body[data-lamp="1"] .empty-tip{color:#e8dcc8;font-weight:600}
/* 14px 的标题名字号够大，可以承受一层深色描边，进一步压住背景 */
body[data-lamp="1"] .item .i-title b{text-shadow:0 1px 2px rgba(0,0,0,.5)}

/* 开灯的暖光是渐变的，别一下跳出来 */
#sidebar,#main{transition:background-image .8s ease,box-shadow .8s ease,border-color .8s ease}

/* ================= 我的家（全屏实景） ================= */
#home-layer{position:fixed;inset:0;z-index:30;
  display:flex;flex-direction:column;
  padding:calc(env(safe-area-inset-top, 0px) + 14px) 14px calc(env(safe-area-inset-bottom, 0px) + 14px);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .45s ease,visibility .45s}
body.home #home-layer{opacity:1;visibility:visible;pointer-events:none}
body.home #app{opacity:0;transform:scale(.97);pointer-events:none;transition:opacity .4s,transform .4s}

/* 关键：#home-layer 是 pointer-events:none，子元素必须显式打开 auto，
   否则手指/鼠标事件根本到不了背景层，拖动和缩放会完全没反应。 */
.home-bg{position:absolute;inset:0;overflow:hidden;background:#1a1328;
  pointer-events:auto;touch-action:none;cursor:grab;z-index:0;
  -webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}
.home-bg.dragging{cursor:grabbing}
#home-img{position:absolute;left:50%;top:50%;transform-origin:50% 50%;
  will-change:transform;max-width:none;pointer-events:none;
  -webkit-user-drag:none}
.home-bg.none{background-image:linear-gradient(160deg,#3c2d4e,#241a38 60%,#1a1328)}
.home-bg.none #home-img{display:none}
/* 上下文字层要盖在图片之上 */
.home-top,.home-bottom,.home-pan-hint{position:relative;z-index:4}
.home-top{z-index:5}

/* ================= 休息页光线 =================
   静态图靠一层可呼吸的光罩模拟光线变化：
   白天暖白极缓呼吸，黄昏偏橙，夜晚关灯冷暗，开灯暖黄。 */
.home-light{position:absolute;inset:0;pointer-events:none;z-index:1;overflow:hidden}
/* 双层光罩：glow 提亮、shade 压暗，两者 opacity 反相呼吸。
   只加亮的话在明亮实景图上几乎看不出来，必须有压暗的一半才形成明暗起伏。
   模式切换用 background-color（可 transition），
   不能再用 background-image —— 渐变无法插值，会导致开关灯瞬切、丢掉过渡。 */
.lit-glow,.lit-shade{position:absolute;inset:0;display:block;
  transition:background-color 1.1s ease}
.lit-glow{background-repeat:no-repeat;background-size:180% 180%;
  background-position:50% 28%}

/* ---------- 各时辰的亮/暗配色 ---------- */
.home-light[data-mode="day"] .lit-glow{background-color:rgba(255,240,208,.26)}
.home-light[data-mode="day"] .lit-shade{background-color:rgba(30,22,16,.10)}
.home-light[data-mode="dawn"] .lit-glow{background-color:rgba(255,210,190,.30)}
.home-light[data-mode="dawn"] .lit-shade{background-color:rgba(64,44,80,.20)}
.home-light[data-mode="dusk"] .lit-glow{background-color:rgba(255,152,90,.34)}
.home-light[data-mode="dusk"] .lit-shade{background-color:rgba(56,28,48,.26)}
/* 开灯：原来 glow .32 / shade .34 叠起来太厚，像蒙了一层雾，
   实景图都被糊掉了。两层各减一半左右，只留暖意不挡画面。 */
.home-light[data-mode="night-on"] .lit-glow{background-color:rgba(255,190,110,.16)}
.home-light[data-mode="night-on"] .lit-shade{background-color:rgba(8,6,20,.17)}
.home-light[data-mode="night-off"] .lit-glow{background-color:rgba(96,116,176,.16)}
.home-light[data-mode="night-off"] .lit-shade{background-color:rgba(4,6,22,.60)}

/* 缺省（JS 未设 data-mode 时也有微光） */
.lit-glow{background-color:rgba(255,240,208,.22)}
.lit-shade{background-color:rgba(30,22,16,.12)}

/* ---------- 呼吸：亮部与暗部反相 ---------- */
.lit-glow {animation:lit-glow-breathe 9s ease-in-out infinite}
.lit-shade{animation:lit-shade-breathe 9s ease-in-out infinite}
.home-light[data-mode="dawn"] .lit-glow,
.home-light[data-mode="dawn"] .lit-shade{animation-duration:7.5s}
.home-light[data-mode="dusk"] .lit-glow,
.home-light[data-mode="dusk"] .lit-shade{animation-duration:6.5s}
.home-light[data-mode="night-on"] .lit-glow,
.home-light[data-mode="night-on"] .lit-shade{animation-duration:5.5s}
.home-light[data-mode="night-off"] .lit-glow,
.home-light[data-mode="night-off"] .lit-shade{animation-duration:12s}

@keyframes lit-glow-breathe{
  0%  {opacity:.42}
  35% {opacity:.88}
  55% {opacity:1}
  78% {opacity:.6}
  100%{opacity:.42}}
@keyframes lit-shade-breathe{
  0%  {opacity:1}
  35% {opacity:.62}
  55% {opacity:.5}
  78% {opacity:.84}
  100%{opacity:1}}

/* 开灯时叠一层灯丝跳动（幅度不大，但能看出在闪） */
.home-light[data-mode="night-on"] .lit-glow{animation-name:lit-glow-flicker}
/* 开灯的灯丝跳动：原来在 .5~1.0 之间跳（差 0.5），忽明忽暗太夸张。
   现在收窄到 .84~1.0（差 0.16），只在 47%~51% 那一下有可见的"跳"，
   其余时间基本平稳 —— 是灯丝在抖，不是有人在开关灯。 */
@keyframes lit-glow-flicker{
  0%  {opacity:.88}
  20% {opacity:.96}
  38% {opacity:.90}
  47% {opacity:1}
  49% {opacity:.84}
  51% {opacity:.98}
  70% {opacity:.92}
  86% {opacity:.88}
  100%{opacity:.88}}

/* ---------- 浮尘：静态图上最有说服力的「假动态」 ---------- */
.home-dust{position:absolute;inset:0;pointer-events:none;z-index:2;overflow:hidden;
  opacity:0;transition:opacity 1.2s ease}
.home-dust.on{opacity:1}
.dust{position:absolute;bottom:-12px;border-radius:50%;
  background:rgba(255,246,224,.9);
  box-shadow:0 0 4px 1px rgba(255,240,210,.55);
  animation:dust-rise linear infinite;will-change:transform,opacity}
@keyframes dust-rise{
  0%  {transform:translate3d(0,0,0) scale(.7);opacity:0}
  12% {opacity:.75}
  50% {transform:translate3d(22px,-46vh,0) scale(1);opacity:.9}
  80% {transform:translate3d(-14px,-76vh,0) scale(1.1);opacity:.5}
  100%{transform:translate3d(8px,-104vh,0) scale(.9);opacity:0}}

/* ================= 雷雨闪电 =================
   室内场景，只让画面「微微泛白」一下，不做刺目白屏。 */
.home-flash{position:absolute;inset:0;pointer-events:none;z-index:3;
  background:radial-gradient(ellipse at 50% 10%,rgba(226,236,255,.5),rgba(200,216,255,.22) 55%,transparent);
  opacity:0}
.home-flash.flash{animation:flash-strike 1.05s ease-out}
@keyframes flash-strike{
  0%{opacity:0}
  3%{opacity:.34}
  7%{opacity:.06}
  11%{opacity:.26}
  17%{opacity:.02}
  100%{opacity:0}}

@media (prefers-reduced-motion: reduce){
  .lit-glow,.lit-shade{animation:none!important}
  .dust{display:none}
  .home-flash{display:none}
}

/* 竖屏提示：横图被裁时告诉用户可以拖 */
.home-pan-hint{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  font-size:12px;letter-spacing:2px;color:var(--on-dark);
  background:rgba(0,0,0,.42);padding:7px 16px;border-radius:20px;
  pointer-events:none;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  animation:pan-hint-fade 3.6s ease forwards;z-index:2}
@keyframes pan-hint-fade{0%{opacity:0}12%{opacity:1}72%{opacity:1}100%{opacity:0}}

.home-top{flex:none;display:flex;flex-direction:column;align-items:center;gap:5px;
  text-align:center;pointer-events:auto}
/* 「休息中···」是可点按钮：点一下收起下方按钮，画面更纯净。
   外观上要看起来还是个标题，所以清掉按钮默认样式。
   注意 #home-layer 是 pointer-events:none，必须在这里显式打开，
   否则按钮点不动（整层都不接收事件）。只给标题本身开，避免挡住图片拖动。 */
/* 「休息中···」是可点按钮：点一下收起下方按钮，画面更纯净。
   要让它看得出来是按钮（半透明底 + 描边 + 按下反馈），
   但又要保持标题的气质，所以不用实心色块。
   注意 #home-layer 是 pointer-events:none，必须在这里显式打开，
   否则按钮点不动（整层都不接收事件）。只给标题本身开，避免挡住图片拖动。 */
.home-title-row{display:flex;align-items:center;gap:9px}
.home-title{font-size:17px;letter-spacing:3px;color:var(--on-dark);
  text-shadow:0 2px 14px rgba(0,0,0,.75);
  padding:6px 18px;border-radius:20px;
  border:1px solid rgba(255,226,196,.3);
  background:rgba(24,16,36,.42);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  font-family:inherit;font-weight:700;line-height:1.3;cursor:pointer;
  pointer-events:auto;
  transition:opacity .3s ease,transform .3s ease,border-color .3s ease}
.home-title:hover{border-color:var(--amber);color:var(--amber)}
.home-title:active{transform:scale(.96)}
/* 旁边的「收起 / 展开」小字，随状态切换 */
.home-toggle{font-size:10.5px;letter-spacing:1px;color:var(--on-dark);opacity:.7;
  text-shadow:0 1px 6px rgba(0,0,0,.7);white-space:nowrap}

/* 纯净模式：收起底部按钮与拖动提示 */
body.home-quiet .home-bottom,
body.home-quiet .home-pan-hint{opacity:0;pointer-events:none;
  transform:translateY(10px);transition:opacity .45s ease,transform .45s ease}
.home-bottom,.home-pan-hint{transition:opacity .45s ease,transform .45s ease}
.home-tip{font-size:11.5px;letter-spacing:1.2px;color:var(--on-dark);opacity:.85;
  background:rgba(0,0,0,.3);padding:3px 12px;border-radius:12px;
  text-shadow:0 1px 6px rgba(0,0,0,.7)}
.home-mid{flex:1;min-height:0;pointer-events:none}
.home-bottom{flex:none;display:flex;flex-direction:column;align-items:center;gap:10px;
  pointer-events:auto}
.home-ctrl{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}
.home-ctrl button{padding:7px 14px;border-radius:20px;font-size:12px;letter-spacing:1px;
  background:rgba(24,16,36,.5);border:1px solid rgba(255,226,196,.2);color:var(--on-dark);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
.home-ctrl button:hover{border-color:var(--amber);color:var(--amber)}
.home-exit{padding:9px 20px;border-radius:24px;
  background:rgba(24,16,36,.5);border:1px solid rgba(255,226,196,.25);color:var(--on-dark);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);letter-spacing:1.5px}
.home-exit:hover{border-color:var(--amber);color:var(--amber)}

/* 主题选择卡片 */
.theme-picker{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.theme-card{display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:14px 8px;border-radius:12px;background:var(--glass-hi)}
.theme-card .theme-emoji{font-size:26px;line-height:1}
.theme-card b{font-size:12.5px;letter-spacing:1px}
.theme-card:hover{background:rgba(var(--tint),.18);border-color:rgba(var(--tint),.45);transform:none}
.theme-card.sel{border-color:var(--amber);background:rgba(var(--tint),.22)}

/* ================= 登录页 ================= */
.login-body{overflow:auto;display:flex;align-items:center;justify-content:center;padding:20px}
.login-card{position:relative;z-index:1;width:352px;padding:34px 30px 30px;border-radius:24px;
  background:var(--glass);border:1px solid var(--stroke);box-shadow:var(--shadow);
  backdrop-filter:blur(24px) saturate(1.4);-webkit-backdrop-filter:blur(24px) saturate(1.4);
  animation:card-in .6s cubic-bezier(.22,1.2,.36,1) both}
@keyframes card-in{from{opacity:0;transform:translateY(24px) scale(.97)}to{opacity:1;transform:none}}
.login-card .rv{display:block;margin:0 auto 8px;width:132px;color:var(--text);animation:rv-idle 5s ease-in-out infinite}
@keyframes rv-idle{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
.login-card h1{font-size:22px;margin:6px 0 3px;text-align:center;letter-spacing:1.5px}
.login-card .sub{margin:0 0 24px;color:var(--text-dim);font-size:12.5px;text-align:center;letter-spacing:2.5px}
.login-card label{display:block;font-size:11.5px;color:var(--text-dim);margin:14px 0 5px;letter-spacing:.6px}
.login-card button{width:100%;margin-top:24px;padding:11px;font-size:15px;letter-spacing:3px}
.err{background:rgba(255,111,97,.15);border:1px solid rgba(255,111,97,.42);color:var(--ember);
  padding:9px 12px;border-radius:10px;font-size:13px;margin-bottom:6px}

/* ================= 响应式 ================= */
@media (max-width:760px){
  #app{padding:0;gap:0}
  #sidebar{width:100%;border-radius:0;border:0;position:absolute;inset:0;z-index:10;
    transition:transform .26s cubic-bezier(.4,0,.2,1)}
  body.chat-open #sidebar{transform:translateX(-102%)}
  #main{width:100%;border-radius:0;border:0}
  /* 手机端：返回按钮统一放大到易点的尺寸（原来 24px 光秃秃一个 ‹，
     在角落里既看不清也不好点） */
  .back-btn{display:inline-flex;align-items:center;justify-content:center;
    min-height:44px;min-width:44px;padding:10px 14px;font-size:22px;
    border-radius:22px;border:1px solid var(--stroke);
    background:rgba(255,255,255,.06);color:var(--text)}
  .back-btn:active{transform:scale(.96);background:rgba(var(--tint),.2)}
  .msg .col{max-width:78%}
  .scenery{height:54vh}
  /* 注意：body.camp .scenery 特异性更高，必须同样写法才能覆盖 */
  body.camp .scenery{height:max(70vh, 480px)}
  .t2,.t6{display:none}

  /* 热点用固定像素定位，不受 vh 波动影响，永远在底部条上方 */
  .spot-rv  {left:4%;  bottom:155px;width:62px}
  .spot-tent{left:24%; bottom:155px;width:40px}
  .spot-sign{left:44%; bottom:155px;width:38px}
  .spot-fire{right:5%; bottom:160px;width:42px}
  .spot .cap{font-size:10.5px;letter-spacing:.3px}
  .spot .badge-dot{min-width:15px;font-size:9px;line-height:15px;padding:0 4px}

  .home-pan-hint{font-size:10.5px;padding:6px 12px}

  /* 窄屏入口挤在 4%~44% 与右侧，装饰树缩小并退到 50%~78% 的空隙 */
  .palm{width:44px;height:74px;bottom:24%}
  .palm.p1{left:50%}
  .palm.p2{left:72%;width:36px;height:62px}
  .willow{width:58px;height:72px;bottom:25%}
  /* 窄屏只留两岸各一棵（岸很窄，放不下 3 棵） */
  .willow.wl1{left:6%;bottom:29%;width:50px;height:62px}
  .willow.wl2{display:none}
  .willow.wl3{left:76%;bottom:29%;width:50px;height:62px}
  .willow.wl4{display:none}
  .willow.wl5{display:none}
  .willow.wl6{display:none}
  .bush.b1{left:11%;bottom:24%;width:34px;height:23px}
  .bush.b2{display:none}
  .bush.b3{left:80%;bottom:24%;width:34px;height:23px}
  .bush.b4{display:none}
  .sailboat{width:38px;height:30px;left:60%}
  .reeds{width:32px;height:50px}
  .reeds.r-a{left:2%}
  .reeds.r-b{left:90%;width:26px;height:42px}
  .dock{width:80px;height:24px;left:26%}
  .lily{width:30px;height:13px}
  .camp-title{font-size:17px}
  .camp-tip{font-size:11px;letter-spacing:.8px}
  .camp-ctrl{gap:6px}
  .camp-ctrl button{padding:6px 12px;font-size:11.5px}
  .camp-exit{padding:8px 18px;font-size:12.5px}
}
@media (max-width:420px){.admin-wrap{padding:14px}.card{padding:14px}}

/* 毛玻璃降级 */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  #sidebar,#main{background:var(--solid)}
  .camp-ctrl button,.camp-exit{background:var(--solid)}
}

@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}
}


/* ================= 广播列表 + 详情 + 营地气泡 ================= */
.ann-row{cursor:pointer}
.ann-row.unread .i-sub{color:var(--text)}
.ann-row.pinned .i-title{color:var(--amber)}
.ann-pin-tag{font-size:9.5px;padding:1px 6px;border-radius:20px;flex:none;
  background:rgba(255,180,84,.18);color:var(--amber);border:1px solid rgba(255,180,84,.35)}
.ann-dot{font-size:9.5px;padding:1px 6px;border-radius:20px;flex:none;
  background:rgba(140,230,180,.18);color:#8ce6b4;border:1px solid rgba(140,230,180,.35)}
.i-time{font-size:10.5px;color:var(--text-faint);margin-top:3px}
/* 放进标题行里的时间（会话列表）：同一行右侧，不单独占一行 */
.i-title .i-time{margin-top:0;margin-left:auto;flex:none;padding-left:6px;
  font-variant-numeric:tabular-nums}
.grow{flex:1}

.ann-detail-head{display:flex;align-items:center;gap:7px;margin-bottom:11px;
  font-size:12.5px;flex-wrap:wrap}
.ann-detail-head small{color:var(--text-faint);font-size:11px}
.ann-detail-body{font-size:14px;line-height:1.95;white-space:pre-wrap;
  word-break:break-word;color:var(--text)}

/* 营地告示牌上方的气泡：像一朵浮云，浅白底 + 深色字，
   原来的深紫底在夜色里和背景糊成一团，字也看不清。
   bottom 从 212px 提到 268px，避免压住告示牌本身。 */
/* 气泡必须正对告示牌头顶 —— 告示牌在 left:37%、宽 56px，
   所以它的中心是 calc(37% + 28px)。原来写死 44%（那是窄屏下木牌的位置），
   电脑上就整个偏到右边去了，看着像"气泡长在别的东西头上"。
   ⚠️ 窄屏木牌位置不一样（见下方 media query），要各算各的。 */
.ann-bubble{position:absolute;left:calc(37% + 28px);bottom:232px;transform:translateX(-50%);
  z-index:6;max-width:min(250px,62vw);cursor:pointer;
  padding:9px 13px;border-radius:16px;
  background:rgba(252,250,246,.94);
  border:1px solid rgba(255,255,255,.9);
  box-shadow:0 6px 20px rgba(30,20,45,.22),0 1px 3px rgba(30,20,45,.1);
  animation:annBubIn .5s cubic-bezier(.22,1.2,.36,1) both}
.ann-bubble[hidden]{display:none}
@keyframes annBubIn{from{opacity:0;transform:translateX(-50%) translateY(8px) scale(.9)}
  to{opacity:1;transform:translateX(-50%) translateY(0) scale(1)}}
.ann-bubble:hover{background:rgba(255,253,250,.99);
  box-shadow:0 8px 26px rgba(30,20,45,.28)}
.ann-bub-tag{display:none}          /* 不再显示「置顶」「新公告」标签 */
.ann-bub-tag[hidden]{display:none}
/* 云朵里的文字必须是深色，浅底配浅字等于看不见。
   ⚠️ 两处坑：
     ① 之前没写 white-space，长公告被挤成一行又被手动截断 —— 看着像"不换行"。
     ② 用 -webkit-line-clamp 做三行截断时容器变成 -webkit-box，
        小画会被当成独立的一行盒子排到最后 —— 这就是"画作永远在最后"。
   现在改成普通块 + 最大高度裁剪，换行正常，画也按原文顺序跟着文字走。 */
.ann-bub-text{font-size:12.5px;line-height:1.65;color:#3a2f26;font-weight:500;
  white-space:pre-wrap;word-break:break-word;overflow:hidden;
  max-height:5.6em}
/* 气泡里的小画：跟着文字排在一起，比详情里的小一号 */
.ann-bub-text .dk-mini{display:inline-block;width:54px;height:54px;
  margin:3px 4px 1px 0;vertical-align:middle;border-radius:8px}
.ann-bub-arrow{position:absolute;left:50%;bottom:-6px;margin-left:-6px;
  width:11px;height:11px;transform:rotate(45deg);
  background:rgba(252,250,246,.94);
  border-right:1px solid rgba(255,255,255,.9);
  border-bottom:1px solid rgba(255,255,255,.9);
  box-shadow:2px 2px 4px rgba(30,20,45,.08)}

/* ================= 夜里看管理页 =================
   白天玻璃是亮的、字是深的，清清楚楚；夜里整块玻璃变暗，
   那些在白天刚好的深字就糊进背景里了，开灯时更糟
   （玻璃被照成暖白黄，深字浅字都发飘）。

   所以夜里（含黄昏）给管理区单独垫一层深色底 + 统一用浅色字：
   不论开灯关灯，字都是白的，一眼就看得清。
   变量写在 .admin-wrap 自己身上 —— 自身声明优先于从 #main 继承，
   所以能盖掉开灯时那套"深字"的写法。 */
html[data-scene="night"] .admin-wrap,
html[data-scene="dusk"] .admin-wrap{
  --text:#f4efe6; --text-dim:#ddd5c6; --text-faint:#c3b9a6;
  background:rgba(24,19,32,.58);
  border-radius:14px;
  margin:-8px;padding:30px;
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
}
/* 标题、说明、表头这些在夜里也统一提亮 */
html[data-scene="night"] .admin-wrap h2,
html[data-scene="night"] .admin-wrap h3,
html[data-scene="night"] .admin-wrap b,
html[data-scene="dusk"] .admin-wrap h2,
html[data-scene="dusk"] .admin-wrap h3,
html[data-scene="dusk"] .admin-wrap b{color:#f6f1e8}
html[data-scene="night"] .admin-note,
html[data-scene="night"] .log-head small,
html[data-scene="dusk"] .admin-note,
html[data-scene="dusk"] .log-head small{color:#c9bfab}
/* 记录行：夜里换成深色底 + 浅字 */
html[data-scene="night"] .log-row,
html[data-scene="night"] .log-conv,
html[data-scene="dusk"] .log-row,
html[data-scene="dusk"] .log-conv{
  background:rgba(255,255,255,.07);border-color:rgba(255,236,208,.16)}
html[data-scene="night"] .log-body,
html[data-scene="dusk"] .log-body{color:#eee7da}
/* 删除按钮：夜里不能用深红（会看不见），换成亮一点的珊瑚色 */
html[data-scene="night"] .log-del,
html[data-scene="dusk"] .log-del{color:#ffb3a3;border-color:rgba(255,150,130,.5)}
html[data-scene="night"] .log-del:hover,
html[data-scene="dusk"] .log-del:hover{background:rgba(255,150,130,.18)}
/* 卡片：夜里再压深一档，浅字才浮得出来 */
html[data-scene="night"] .card,
html[data-scene="dusk"] .card{background:rgba(28,22,36,.55)}
/* 输入框 / 下拉框：夜里改成深底浅字（默认的白底白字等于看不见） */
html[data-scene="night"] .admin-wrap select,
html[data-scene="night"] .admin-wrap input,
html[data-scene="night"] .admin-wrap textarea,
html[data-scene="dusk"] .admin-wrap select,
html[data-scene="dusk"] .admin-wrap input,
html[data-scene="dusk"] .admin-wrap textarea{
  color:#f4efe6;background:rgba(18,14,26,.72);border-color:rgba(255,236,208,.28)}
html[data-scene="night"] .admin-wrap ::placeholder,
html[data-scene="dusk"] .admin-wrap ::placeholder{color:#a89e8c}
/* 普通按钮：夜里边框太暗，提亮一点 */
html[data-scene="night"] .admin-wrap button,
html[data-scene="dusk"] .admin-wrap button{
  border-color:rgba(255,236,208,.30);color:#f0e9dc}

/* ================= 管理员：聊天记录 ================= */
.admin-note{font-size:11.5px;line-height:1.75;color:var(--text-faint);margin:6px 0 10px}
.log-wrap{max-height:46vh;overflow-y:auto;padding-right:4px}
.log-row{padding:9px 11px;border-radius:11px;margin-bottom:7px;
  background:rgba(255,255,255,.04);border:1px solid rgba(255,226,196,.12)}
.log-conv{padding:9px 11px;border-radius:11px;margin-bottom:7px;
  background:rgba(255,255,255,.045);border:1px solid rgba(255,226,196,.13)}
.log-conv .log-head{margin-bottom:0;align-items:center;flex-wrap:wrap}
.log-head{display:flex;align-items:center;gap:7px;font-size:11.5px;margin-bottom:5px}
.log-head small{color:var(--text-faint)}
.log-body{font-size:13px;line-height:1.75;white-space:pre-wrap;word-break:break-word}
.log-del{padding:2px 8px;font-size:10.5px;border-radius:7px;flex:none;
  background:transparent;border:1px solid rgba(255,111,97,.4);color:#ff9a8a;cursor:pointer}
.log-del:hover{background:rgba(255,111,97,.14)}
.log-del.danger{border-color:rgba(255,111,97,.55);color:#ff8f7a}
.log-del.danger:hover{background:rgba(255,111,97,.2)}

@media (max-width:760px){
  /* 窄屏木牌在 left:44%、宽 38px → 中心 calc(44% + 19px) */
  .ann-bubble{left:calc(44% + 19px);bottom:226px;max-width:54vw;padding:8px 11px}
  .ann-bub-text{font-size:11.5px}
}


/* 消息时间戳：可点，点一下显示精确时间 */
.msg-time-toggle{cursor:pointer;user-select:none;-webkit-user-select:none;
  transition:color .15s}
.msg-time-toggle:hover{color:var(--amber)}
.msg-time-toggle.show-full{color:var(--amber)}

/* 夜里树冠提亮一档：夜色背景本身很暗，如果沿用白天的绿色会被压成黑影，
   看不出树的本色。这里不是"变亮"，而是补偿 —— 让它在暗背景上仍然可读。 */
html[data-scene="night"]{--tree-c:#4f9a58; --tree-c2:#63ad63; --trunk:#6b4a30}
html[data-scene="night"][data-season="summer"]{--tree-c:#3f9a4a; --tree-c2:#52ab57}
html[data-scene="night"][data-season="autumn"]{--tree-c:#b8762e; --tree-c2:#d08f3e}
html[data-scene="night"][data-season="winter"]{--tree-c:#8fa5b5; --tree-c2:#a0b6c4}
html[data-scene="dusk"]{--tree-c:#4a8a55; --tree-c2:#5c9c5c}


/* ================= 聊天管理页面 ================= */
.logs-sub{font-size:11.5px;color:var(--text-faint);margin-left:10px}
.log-bar{display:flex;gap:7px;flex-wrap:wrap;align-items:center;margin-bottom:11px}
.log-bar input{flex:1;min-width:110px}
.log-bar input[type="date"]{flex:none;max-width:150px}
#log-msg-meta{display:block;margin:0 0 9px}
.log-msg-item{display:block;padding:10px 12px;border-radius:11px;margin-bottom:7px;
  background:rgba(255,255,255,.045);border:1px solid rgba(255,226,196,.13)}
.log-msg-item:hover{border-color:rgba(var(--tint),.34)}
.log-act{padding:2px 9px;font-size:10.5px;border-radius:7px;flex:none;
  background:transparent;border:1px solid var(--stroke);color:var(--text-dim);cursor:pointer}
.log-act:hover{border-color:rgba(var(--tint),.55);color:var(--amber)}
.log-act.danger{border-color:rgba(255,111,97,.42);color:#ff9a8a}
.log-act.danger:hover{background:rgba(255,111,97,.14)}

.log-footer{margin-top:12px;padding-top:11px;border-top:1px solid rgba(255,226,196,.12)}
.log-footer button{width:100%;padding:9px;border-radius:10px;font-size:12.5px}


/* ================= 侧栏列表折叠 ================= */
.fold-head{display:flex;align-items:center;gap:7px;width:100%;
  padding:9px 13px;margin:0 0 6px;border:0;border-radius:10px;
  background:transparent;color:var(--text-dim);
  font-size:12.5px;letter-spacing:.3px;cursor:pointer;text-align:left;
  transition:background .18s ease,color .18s ease}
.fold-head:hover{background:rgba(var(--tint),.10);color:var(--amber)}
.fh-arrow{display:inline-block;font-size:9.5px;opacity:.75;
  transition:transform .22s cubic-bezier(.34,1.4,.64,1);flex:none}
.fh-title{flex:none;font-weight:600}
.fh-count{margin-left:auto;font-size:11px;opacity:.6;
  font-variant-numeric:tabular-nums;flex:none}
/* 有未读时高亮 —— 列表折叠后这是唯一提示 */
.fh-count.hot{opacity:1;color:var(--amber);font-weight:700}

/* 折叠时：箭头转过去，内容收起 */
.pane.folded .fold-body{display:none}
.pane.folded .fh-arrow{transform:rotate(-90deg)}
.pane.folded .fold-head{margin-bottom:2px;opacity:.85}

/* 折叠后留一条细分隔，视觉上知道这里还有东西 */
.pane.folded{border-bottom:1px solid rgba(255,226,196,.08);padding-bottom:4px}

/* 管理面板：两个入口按钮。窄屏上并排会挤，允许换行并各自撑开 */
[data-pane="admin"] .pane-bar{flex-wrap:wrap;gap:8px}
[data-pane="admin"] .pane-bar button{flex:1 1 46%;min-width:130px;
  padding:9px 10px;white-space:nowrap}

/* ---- 隐藏会话 / 好友（在「管理 → 隐藏管理」里操作） ----
   主列表里隐藏项彻底不显示、不留痕迹，管理只在这里做。 */
.hide-note{padding:10px 13px;margin:10px 0 4px;border-radius:11px;
  background:rgba(var(--tint),.07);border:1px solid var(--stroke-2);
  color:var(--text-dim);font-size:12px;line-height:1.7}
.hide-note b{color:var(--amber);font-weight:600}
.hide-sec{margin:14px 0 2px;padding:0 13px;font-size:12px;font-weight:600;
  letter-spacing:1px;color:var(--text-faint)}
/* 「已隐藏」小标签 */
.hid-tag{flex:none;margin-left:6px;padding:1px 7px;border-radius:8px;
  background:rgba(var(--tint),.16);color:var(--amber);
  font-size:10px;font-weight:700;letter-spacing:.5px}
/* 隐藏管理里，被隐藏的条目加左侧竖条，一眼分得清 */
#view-hide .item.is-hidden{border-left:2px solid rgba(var(--tint),.5)}
/* 隐藏 / 恢复按钮（管理页里常显，比列表里的更明显） */
.i-hide{flex:none;border:1px solid var(--stroke-2);background:none;cursor:pointer;
  padding:5px 9px;border-radius:9px;font-size:11.5px;line-height:1;
  color:var(--text-dim);white-space:nowrap;
  transition:opacity .16s,background .16s,color .16s}
.i-hide:hover{background:rgba(var(--tint),.14);color:var(--amber)}
#view-hide .item .i-hide{opacity:1}
.item.is-hidden .i-hide{color:var(--amber);border-color:rgba(var(--tint),.4)}

/* ============================================================
   节日装饰（圣诞）—— 12/24 ~ 12/25 自动生效
   所有样式都挂在 html[data-xmas="1"] 下，非圣诞期完全不参与渲染
   ============================================================ */

/* ---------- 通用：星星 / 月亮 ---------- */
.xm-deco,.xm-snow,.xm-sleigh,.xm-rv{position:absolute;pointer-events:none}
.xm-deco{inset:0;z-index:3}

.xm-stars{position:absolute;inset:0 0 40% 0}
.xm-stars i{position:absolute;width:2px;height:2px;background:#fff;border-radius:50%;
  opacity:0;animation:xm-tw 3s ease-in-out infinite}
@keyframes xm-tw{0%,100%{opacity:.25}50%{opacity:1}}

.xm-moon{position:absolute;top:26px;right:40px;width:44px;height:44px;border-radius:50%;
  background:radial-gradient(circle at 35% 35%,#fff8e0,#f0e0b0);
  box-shadow:0 0 26px rgba(255,240,190,.45)}

/* ---------- 彩灯串 ---------- */
.xm-strand{position:absolute;top:44px;left:0;right:0;height:34px}
.xm-strand i{position:absolute;width:7px;height:7px;border-radius:50%;
  animation:xm-blink 1.6s ease-in-out infinite}
@keyframes xm-blink{0%,100%{opacity:.35;transform:scale(.8)}50%{opacity:1;transform:scale(1.15)}}
.xm-rv .xm-strand{top:14px;height:26px}
.xm-rv .xm-strand i{width:8px;height:8px;animation-duration:1.8s}

/* ---------- 圣诞树 ---------- */
.xm-tree{position:absolute;bottom:31%;width:0;height:0}
.xm-tree svg{position:absolute;bottom:0;left:50%;transform:translateX(-50%);
  transform-origin:bottom center;animation:xm-sway 4.5s ease-in-out infinite}
@keyframes xm-sway{0%,100%{transform:translateX(-50%) rotate(-1.5deg)}
  50%{transform:translateX(-50%) rotate(1.5deg)}}
.xm-star{animation:xm-shine 2s ease-in-out infinite}
@keyframes xm-shine{0%,100%{opacity:.6}50%{opacity:1}}

/* ---------- 雪人 / 礼物 / 花环 ---------- */
.xm-snowman{position:absolute;bottom:31%;width:46px;transform:translateX(-50%)}
.xm-snowman svg{width:100%;display:block;animation:xm-bob 5s ease-in-out infinite}
@keyframes xm-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-2px)}}

.xm-gifts{position:absolute;bottom:31%;display:flex;gap:4px;align-items:flex-end}
.xm-gifts i{display:block;border-radius:3px;animation:xm-bob 4s ease-in-out infinite}

.xm-wreath{position:absolute;width:52px;height:52px;animation:xm-spin 30s linear infinite}
@keyframes xm-spin{to{transform:rotate(360deg)}}

.xm-bow{position:absolute;bottom:32%;font-size:15px}

/* ---------- 雪 ---------- */
.xm-snow{inset:0;z-index:4}
.xm-flake{position:absolute;top:-12px;background:#fff;border-radius:50%;
  animation:xm-fall linear infinite;will-change:transform}
@keyframes xm-fall{
  0%{transform:translate3d(0,-20px,0);opacity:0}
  8%{opacity:.95}92%{opacity:.9}
  100%{transform:translate3d(24px,360px,0);opacity:0}}

/* ---------- 圣诞老人雪橇 ---------- */
/* ⚠️ 原来终点写死 1240px：在 1440px 宽的屏幕上，起点 left:-260px，
   飞到 980px 就结束了（没出屏），看着像"飞一半突然淡掉"。
   现在用 100vw 计算，保证任何屏幕宽度都能真正飞出右侧。 */
.xm-sleigh{top:56px;left:-260px;width:230px;height:78px;z-index:8;opacity:0}
/* ⚠️ 之前为了塞进 15~25 秒的间隔，把飞行压到 10 秒，结果快得像射出去的箭。
   现在改成"慢飞 + 更长间隔"：飞行 24 秒，间隔 30~50 秒，
   保证上一趟飞完 6 秒以上才起下一趟（24 < 30，不重叠）。
   速度慢下来后，上下起伏的波浪感才看得出来。 */
/* ⚠️ 之前 X 用 calc(14vw)/calc(28vw)... 且 88%→100% 只走 4vw+320px，
   X 不是线性的 → JS 那边按进度估算位置算不准，礼物掉在错误的地方甚至不掉。
   现在 X 严格线性（每 12.5% 走 15vw），终点 120vw 保证真正飞出屏。
   这样 JS 用「已飞时间 / 总时长 × 1.2vw」就能精确算出雪橇位置。 */
.xm-sleigh.run{animation:xm-fly 24s linear forwards}
@keyframes xm-fly{
  /* X 线性递增，Y 上下起伏（4 个波峰，不是平飞） */
  0%    {transform:translate(0,0);opacity:0}
  4%    {opacity:1}
  12.5% {transform:translate(15vw,-30px);opacity:1}
  25%   {transform:translate(30vw,6px);opacity:1}
  37.5% {transform:translate(45vw,-38px);opacity:1}
  50%   {transform:translate(60vw,10px);opacity:1}
  62.5% {transform:translate(75vw,-32px);opacity:1}
  75%   {transform:translate(90vw,4px);opacity:1}
  87.5% {transform:translate(105vw,-18px);opacity:1}
  96%   {opacity:1}
  100%  {transform:translate(120vw,0);opacity:0}}
.xm-sleigh svg{width:100%;height:100%;overflow:visible}
.xm-deer{animation:xm-gallop .55s ease-in-out infinite}
@keyframes xm-gallop{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}
.xm-glow{position:absolute;left:6px;top:26px;width:16px;height:16px;border-radius:50%;
  background:#ff5a4a;box-shadow:0 0 18px 6px rgba(255,90,74,.75);
  animation:xm-pulse 1s ease-in-out infinite}
@keyframes xm-pulse{0%,100%{opacity:.6;transform:scale(.9)}50%{opacity:1;transform:scale(1.2)}}
.xm-trail{position:absolute;inset:0;opacity:0}
.xm-sleigh.run .xm-trail{animation:xm-twinkle .7s ease-in-out infinite}
@keyframes xm-twinkle{0%,100%{opacity:0}50%{opacity:.85}}

/* ---------- 营地：结冰 ---------- */
html[data-xmas="1"] .grass-fill,
html[data-xmas="1"] .grass-fill-2{fill:#b9d0e2}
html[data-xmas="1"] .hill-far,
html[data-xmas="1"] .hill-mid{fill:#a8c2d8}
html[data-xmas="1"] .water-body,
html[data-xmas="1"] .sea-water,
html[data-xmas="1"] .lake-water{fill:#c2d8ea}

/* ---------- 房车里 ---------- */
.xm-rv{top:0;left:0;right:0;bottom:0;z-index:60}
.xm-minitree{position:absolute;bottom:56px;right:24px;width:54px;height:74px}
.xm-minitree svg{width:100%;height:100%;animation:xm-sway2 5s ease-in-out infinite}
@keyframes xm-sway2{0%,100%{transform:rotate(-1deg)}50%{transform:rotate(1deg)}}

.xm-stock{position:absolute;bottom:118px;left:190px;width:34px;height:46px}

.xm-orn{position:absolute;font-size:16px;animation:xm-bob 3.6s ease-in-out infinite}

.xm-fireside{position:absolute;bottom:40px;left:50%;transform:translateX(-50%);
  width:150px;height:60px;border-radius:8px;
  background:radial-gradient(ellipse at 50% 80%,rgba(255,150,60,.5),transparent 70%);
  animation:xm-fire 2.6s ease-in-out infinite}
@keyframes xm-fire{0%,100%{opacity:.75}50%{opacity:1}}

/* 房车车窗结冰 */
html[data-xmas="1"] #rv-bg::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse at 30% 70%,rgba(220,240,255,.30),transparent 60%),
             radial-gradient(ellipse at 72% 40%,rgba(220,240,255,.24),transparent 55%)}

/* ---------- 圣诞老人掉落的礼物 / 星星 ---------- */
/* --xm-land 由 JS 按视口高度设置（62vh 附近），
   写死 324px 的话在高屏上礼物会悬在半空就化掉。 */
.xm-drop{position:absolute;top:0;z-index:7;pointer-events:none;
  --xm-land:320px;
  animation:xm-drop 3.6s cubic-bezier(.5,.05,.85,.4) forwards}
/* 落下时带一点摇晃，不是直上直下 */
@keyframes xm-drop{
  0%  {transform:translateY(70px) rotate(0deg);opacity:0}
  8%  {opacity:1}
  30% {transform:translateY(calc(var(--xm-land) * .36)) rotate(-14deg);opacity:1}
  55% {transform:translateY(calc(var(--xm-land) * .70)) rotate(12deg);opacity:1}
  78% {transform:translateY(calc(var(--xm-land) * .92)) rotate(-6deg);opacity:1}
  92% {transform:translateY(var(--xm-land)) rotate(3deg);opacity:1}
  100%{transform:translateY(var(--xm-land)) rotate(0deg);opacity:1}}
/* 落地后融化：像被雪盖住一样慢慢化掉 */
.xm-drop.melt{animation:xm-melt 1.6s ease-in forwards}
@keyframes xm-melt{
  0%  {transform:translateY(var(--xm-land)) scale(1);opacity:1;filter:blur(0)}
  45% {transform:translateY(calc(var(--xm-land) + 2px)) scale(.94);opacity:.75;filter:blur(.5px)}
  100%{transform:translateY(calc(var(--xm-land) + 6px)) scale(.7);opacity:0;filter:blur(2.5px)}}
.xm-drop.star{filter:drop-shadow(0 0 8px rgba(255,215,106,.8))}

/* ============================================================
   春节装饰（.cj- 前缀，与圣诞 .xm- 完全独立）
   ============================================================ */

/* 营地：夜色加一层暖红，营造"张灯结彩"（叠加，不破坏原背景） */
html[data-chunjie="1"] #camp-layer::before{
  content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(rgba(120,26,20,.30),transparent 55%),
             radial-gradient(ellipse at 50% 30%,rgba(255,150,60,.14),transparent 62%)}

/* ---------- 灯笼串 ---------- */
.cj-strand{position:absolute;left:0;right:0;height:60px;z-index:6;pointer-events:none}
.cj-lant{position:absolute;top:0;transform-origin:top center;
  animation:cj-swing 3.4s ease-in-out infinite}
@keyframes cj-swing{0%,100%{transform:rotate(-7deg)}50%{transform:rotate(7deg)}}
.cj-cord{width:1px;height:var(--cj-cord,10px);background:rgba(255,215,106,.55);margin:0 auto}
.cj-lbody{border-radius:50%/42%;position:relative;margin:0 auto;
  background:radial-gradient(ellipse at 34% 32%,#ff6b52,#d93b30 60%,#a8261f);
  box-shadow:0 0 16px rgba(255,120,60,.6),inset 0 0 8px rgba(255,200,120,.4)}
.cj-lbody::before,.cj-lbody::after{content:'';position:absolute;left:50%;
  transform:translateX(-50%);width:12px;height:4px;background:#ffd76a;border-radius:1px}
.cj-lbody::before{top:-2px}
.cj-lbody::after{bottom:-2px}
.cj-fu{position:absolute;top:9px;left:0;right:0;text-align:center;
  font-size:9px;color:rgba(255,235,180,.92);font-weight:700}
.cj-tas{width:2px;height:11px;background:#ffd76a;margin:1px auto 0;border-radius:0 0 2px 2px;
  box-shadow:0 0 6px rgba(255,215,106,.8)}

/* ---------- 营地静态装饰 ---------- */
.cj-deco{position:absolute;inset:0;z-index:5;pointer-events:none}
.cj-knot{position:absolute;left:60%;top:120px;width:44px;
  animation:cj-sway 5s ease-in-out infinite}
@keyframes cj-sway{0%,100%{transform:rotate(-3deg)}50%{transform:rotate(3deg)}}

.cj-fucard{position:absolute;width:46px;height:46px;border-radius:6px;
  background:linear-gradient(135deg,#e8503f,#b8271f);border:2px solid #ffd76a;
  display:flex;align-items:center;justify-content:center;
  font-size:24px;color:#ffd76a;font-weight:700;
  box-shadow:0 0 18px rgba(255,120,60,.55);
  animation:cj-bob 4s ease-in-out infinite}
@keyframes cj-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-3px)}}

.cj-peach{position:absolute;left:11%;bottom:31%;width:94px;height:122px}
.cj-peach svg{position:absolute;bottom:0;left:0;transform-origin:bottom center;
  animation:cj-sway3 5.5s ease-in-out infinite}
@keyframes cj-sway3{0%,100%{transform:rotate(-1.2deg)}50%{transform:rotate(1.2deg)}}

.cj-kumquat{position:absolute;left:52%;bottom:31%;width:52px;height:66px}
.cj-kumquat svg{width:100%;height:100%;transform-origin:bottom center;
  animation:cj-sway 6s ease-in-out infinite}

.cj-pillar{position:absolute;bottom:31%;width:8px;height:56px;border-radius:2px;
  background:linear-gradient(#6b3a2a,#4a2618)}
.cj-pillar::before{content:'';position:absolute;top:-14px;left:50%;
  transform:translateX(-50%);width:20px;height:18px;border-radius:50%/40%;
  background:radial-gradient(ellipse at 34% 32%,#ff6b52,#c0392b);
  box-shadow:0 0 14px rgba(255,120,60,.7)}

/* ---------- 烟花 ---------- */
.cj-fw{position:absolute;inset:0;z-index:6;pointer-events:none}
/* --cj-dx / --cj-dy 由 JS 按角度设置。这里给兜底默认值，
   避免 JS 还没设值时 calc() 拿到空值导致粒子不动。 */
.cj-fwp{position:absolute;width:4px;height:4px;border-radius:50%;
  --cj-dx:0px;--cj-dy:-40px;
  animation:cj-fw 1.8s cubic-bezier(.15,.7,.4,1) forwards}
@keyframes cj-fw{
  0%  {transform:translate(0,0) scale(1);opacity:1}
  60% {transform:translate(var(--cj-dx),var(--cj-dy)) scale(1);opacity:1}
  100%{transform:translate(calc(var(--cj-dx) * 1.18),calc(var(--cj-dy) * 1.18 + 40px)) scale(.25);opacity:0}}
.cj-flash{position:absolute;width:14px;height:14px;border-radius:50%;
  background:radial-gradient(circle,#fff8d0,rgba(255,215,106,.5),transparent 70%);
  animation:cj-flash .5s ease-out forwards}
@keyframes cj-flash{0%{transform:scale(.3);opacity:1}100%{transform:scale(3.4);opacity:0}}

/* ---------- 红包掉落 ---------- */
/* --cj-land 由 JS 按视口高度设置（62%），写死会在高屏上悬在半空 */
.cj-hongbao{position:absolute;top:0;z-index:7;pointer-events:none;--cj-land:320px;
  animation:cj-hb 3.3s cubic-bezier(.5,.05,.85,.4) forwards}
@keyframes cj-hb{
  0%  {transform:translateY(74px) rotate(0deg);opacity:0}
  8%  {opacity:1}
  35% {transform:translateY(calc(var(--cj-land) * .42)) rotate(-16deg);opacity:1}
  65% {transform:translateY(calc(var(--cj-land) * .76)) rotate(14deg);opacity:1}
  90% {transform:translateY(var(--cj-land)) rotate(-5deg);opacity:1}
  100%{transform:translateY(var(--cj-land)) rotate(0deg);opacity:1}}
/* 落地后"被收走"（红包不融化） */
.cj-hongbao.gone{animation:cj-hbout 1.4s ease-in forwards}
@keyframes cj-hbout{
  0%  {transform:translateY(var(--cj-land)) scale(1);opacity:1}
  100%{transform:translateY(calc(var(--cj-land) - 14px)) scale(.55);opacity:0}}

/* ---------- 孔明灯 ---------- */
.cj-airlant{position:absolute;bottom:22%;width:24px;height:32px;z-index:5;
  pointer-events:none;animation:cj-rise 22s linear forwards}
@keyframes cj-rise{
  0%  {transform:translate(0,0) scale(.85);opacity:0}
  8%  {opacity:.95}
  50% {transform:translate(90px,-130px) scale(1);opacity:.95}
  92% {opacity:.7}
  100%{transform:translate(210px,-290px) scale(.7);opacity:0}}
.cj-airlant i{position:absolute;inset:0;border-radius:50%/40%;display:block;
  background:radial-gradient(ellipse at 40% 62%,#ffca6a,#e8722e);
  box-shadow:0 0 22px rgba(255,150,60,.75)}
.cj-airlant i::after{content:'';position:absolute;bottom:-5px;left:50%;
  transform:translateX(-50%);width:8px;height:5px;background:#ffdf9a;border-radius:1px;
  box-shadow:0 0 8px rgba(255,200,100,.9)}

/* ---------- 房车里 ---------- */
.cj-rv{position:fixed;top:0;left:0;right:0;bottom:0;z-index:58;pointer-events:none}
.cj-papercut{position:absolute;top:74px;left:50%;transform:translateX(-50%);
  width:74px;height:74px;opacity:.94}
.cj-minikum{position:absolute;bottom:60px;right:200px;width:48px;height:60px}
.cj-minikum svg{width:100%;height:100%;transform-origin:bottom center;
  animation:cj-sway 6s ease-in-out infinite}
.cj-fusmall{position:absolute;bottom:124px;left:200px;width:38px;height:38px;
  border-radius:5px;background:linear-gradient(135deg,#e8503f,#b8271f);
  border:2px solid #ffd76a;display:flex;align-items:center;justify-content:center;
  font-size:20px;color:#ffd76a;font-weight:700;
  box-shadow:0 0 14px rgba(255,120,60,.5);
  animation:cj-bob 4.2s ease-in-out infinite}
.cj-warm{position:absolute;bottom:40px;left:50%;transform:translateX(-50%);
  width:170px;height:66px;border-radius:8px;
  background:radial-gradient(ellipse at 50% 80%,rgba(255,140,60,.42),transparent 70%);
  animation:cj-fire 3s ease-in-out infinite}
@keyframes cj-fire{0%,100%{opacity:.72}50%{opacity:1}}

/* 房车车窗也映一层暖色 */
html[data-chunjie="1"] #rv-bg::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse at 50% 60%,rgba(255,150,70,.16),transparent 62%)}

/* ---------- 减少动态效果：只留静态 ---------- */
@media (prefers-reduced-motion: reduce){
  .xm-stars i,.xm-strand i,.xm-tree svg,.xm-star,.xm-snowman svg,
  .xm-gifts i,.xm-wreath,.xm-sleigh.run,.xm-deer,.xm-glow,
  .xm-trail,.xm-minitree svg,.xm-orn,.xm-fireside{animation:none!important}
  .xm-snow{display:none}
  .xm-sleigh{display:none}

  /* 春节：同样只留静态装饰 */
  .cj-lant,.cj-knot,.cj-fucard,.cj-peach svg,.cj-kumquat svg,
  .cj-fwp,.cj-flash,.cj-hongbao,.cj-airlant,
  .cj-minikum svg,.cj-fusmall,.cj-warm{animation:none!important}
  .cj-airlant{display:none}
}

/* ---------- 窄屏收缩 ---------- */
@media (max-width:640px){
  .xm-tree svg{width:64px;height:88px}
  .xm-snowman{width:34px}
  .xm-wreath{width:40px;height:40px;top:76px}
  .xm-strand i{width:6px;height:6px}
  .xm-minitree{width:42px;height:58px;right:12px}
  .xm-stock{left:auto;right:76px;bottom:96px;width:28px;height:38px}
}

/* ================= 消息和笔记里的小画 =================
   画只存笔画意图，收到后现场画到 canvas 上，所以显示的是矢量、不糊。 */
.dk-inline{display:inline-block;vertical-align:middle}
/* 透明底：画直接浮在会话背景上，不糊白块 */
.dk-inline-cv{width:132px;height:132px;border-radius:12px;background:transparent;
  display:block}
.memo-doodles{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px}
/* 透明底：直接透出笔记的纸 */
.memo-doodles canvas{width:96px;height:96px;border-radius:11px;background:transparent;
  border:0;cursor:pointer}
.memo-doodles canvas:hover{transform:scale(1.04);transition:.15s}

/* ---- 管理员：画作管理里的缩略图 ----
   透明底，露出卡片底色；圆角跟卡片一致，不抢眼。 */
.udoodle-row{display:flex;align-items:center;gap:10px;margin-top:7px}
.udoodle-cv{width:58px;height:58px;border-radius:10px;background:transparent;
  border:1px solid var(--stroke);flex:0 0 auto}
.udoodle-meta{font-size:11px;color:var(--text-faint);font-weight:600}

/* ---- 管理页里的大号操作按钮 ----
   原来的 .log-act 是 2px 上下内边距 + 10.5px 字，实际高度只有 20px 出头，
   在列表里又小又不好点（手机上尤其明显）。
   这个 lg 变体把触控目标撑到 34px，字也放大到 12.5px。 */
.log-act.lg{min-height:34px;padding:7px 15px;font-size:12.5px;border-radius:9px;
  font-weight:600}
.log-act.lg:active{transform:scale(.96)}

/* ---- 管理页：看全文 / 看大图 的浮层 ----
   跟画板弹窗同一套玻璃质感，不再自己造一套浅色块。 */
.admin-reader{position:fixed;inset:0;z-index:80;background:rgba(0,0,0,.55);
  display:flex;align-items:center;justify-content:center;padding:16px;
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.admin-reader-box{background:var(--glass-2);border:1px solid var(--stroke);
  border-radius:16px;max-width:640px;width:100%;max-height:84vh;overflow:auto;
  padding:18px;box-shadow:var(--shadow);color:var(--text);
  -webkit-overflow-scrolling:touch}
.admin-reader-box h3{margin:0 0 4px;font-size:16px;color:var(--text)}
.admin-reader-meta{font-size:11px;color:var(--text-faint);font-weight:600}
.admin-reader-body{white-space:pre-wrap;word-break:break-word;
  font-size:14px;line-height:1.9;margin-top:12px;color:var(--text)}
.admin-reader-bar{display:flex;gap:8px;justify-content:flex-end;
  margin-top:16px;flex-wrap:wrap}
.admin-reader-bar button{min-height:40px;padding:9px 18px;border-radius:10px;
  border:1px solid var(--stroke);background:var(--glass);color:var(--text);
  font-size:13px;cursor:pointer}
.admin-reader-bar button.amber{background:rgba(var(--tint),.20);
  border-color:var(--amber);color:var(--amber);font-weight:600}
.admin-reader-cv{display:block;margin:12px auto 0;max-width:100%;
  border-radius:12px;background:transparent;
  border:1px solid var(--stroke)}

/* ================= 自定义头像 =================
   点房车页自己的头像可以换：默认首字 / 16 种内置底色 / 画夹里的画 / 导入图片。
   画和图片是渲染到 <img> 上的，所以要让图片撑满圆角方块。 */
.avatar.av-pic{padding:0;overflow:hidden;background:none;box-shadow:none}
.avatar.av-pic img{width:100%;height:100%;object-fit:cover;display:block;
  border-radius:inherit}
/* 自己的头像：可点，鼠标上去给点提示。
   ⚠️ 必须用 #me-avatar 而不是 class —— paintAvatar 每次都会重写 className，
   用 class 的话一刷新头像（比如改完昵称）就被清掉了。 */
#me-avatar{cursor:pointer;transition:transform .15s,box-shadow .15s}
#me-avatar:hover{transform:scale(1.06);
  box-shadow:0 4px 16px rgba(var(--tint),.5)}
#me-avatar:active{transform:scale(.97)}

/* ---- 换头像的弹窗 ---- */
.av-pick-prev{display:flex;flex-direction:column;align-items:center;gap:8px;
  padding:14px 0 16px;border-bottom:1px solid var(--stroke);margin-bottom:14px}
.av-pick-prev .avatar{width:64px;height:64px;border-radius:18px;font-size:26px}
.av-pick-prev b{font-size:11.5px;color:var(--text-dim);font-weight:600;
  letter-spacing:.5px}
.av-pick-sec{font-size:10.5px;letter-spacing:1.5px;color:var(--amber);
  font-weight:800;margin:14px 0 8px;border-left:3px solid var(--amber);
  padding-left:7px}
.av-pick-sec:first-of-type{margin-top:4px}
.av-pick-row{display:flex;gap:8px;flex-wrap:wrap}
.av-pick-row button{flex:1;min-width:130px;min-height:40px;padding:9px 12px;
  border-radius:10px;border:1px solid var(--stroke);background:var(--glass);
  color:var(--text);font-size:12.5px;cursor:pointer;transition:.15s}
.av-pick-row button:hover{border-color:var(--amber);background:var(--glass-2)}
.av-pick-row button.sel{border-color:var(--amber);
  background:rgba(var(--tint),.20);color:var(--amber);font-weight:600}
/* 自定义一个字：左边说明，右边输入框。
   颜色沿用全局 input 的 var(--text) / var(--glass-hi)，
   所以白天深字浅底、夜里浅字深底，不会出现在某种背景下看不见的情况。 */
.av-text-row{display:flex;align-items:center;gap:9px;margin-top:9px}
.av-text-row label{flex:none;font-size:11.5px;font-weight:600;color:var(--text-dim)}
.av-text-row input{flex:1;min-width:0;min-height:38px;padding:8px 11px;
  border-radius:10px;border:1px solid var(--stroke);font-size:13px;outline:none;
  transition:border-color .15s,background .15s}
.av-text-row input:focus{border-color:var(--amber);background:var(--glass-2)}
/* 16 个底色格子 */
.av-swatches{display:grid;grid-template-columns:repeat(8,1fr);gap:7px}
.av-sw{aspect-ratio:1;border-radius:10px;border:2px solid transparent;
  cursor:pointer;padding:0;transition:.15s;
  box-shadow:0 0 0 1px var(--stroke)}
.av-sw:hover{transform:scale(1.1)}
.av-sw.sel{border-color:var(--amber);transform:scale(1.1);
  box-shadow:0 0 0 2px rgba(var(--tint),.45)}
.av-pick-tip{font-size:11px;color:var(--text-faint);line-height:1.7;
  margin-top:14px}

/* 「从画夹挑一张」的独立浮层 —— 不能复用主站 modal（那是单例，
   会把换头像弹窗整个顶掉），所以自己建一个，样式跟玻璃弹窗一致 */
.av-mask{position:fixed;inset:0;z-index:120;
  background:rgba(10,8,14,.62);backdrop-filter:blur(3px);
  display:flex;align-items:center;justify-content:center;padding:18px}
.av-overlay{width:100%;max-width:460px;max-height:86vh;display:flex;
  flex-direction:column;gap:11px;padding:16px 16px 13px;
  background:var(--glass);border:1px solid var(--stroke);
  border-radius:16px;box-shadow:0 16px 46px rgba(0,0,0,.5);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px)}
.av-overlay>b{font-size:15px;color:var(--text);flex:none}
.av-overlay-body{min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch}
.av-overlay-bar{display:flex;justify-content:flex-end;flex:none}
.av-overlay-btn{padding:8px 18px;min-height:36px;border-radius:11px;
  border:1px solid var(--stroke);background:var(--glass-2);
  color:var(--text);font-size:13.5px;cursor:pointer;transition:.15s}
.av-overlay-btn:hover{border-color:var(--amber);color:var(--amber)}
.av-overlay-btn:active{transform:scale(.96)}

/* 从画夹挑：一行三个，手机上两个 */
.av-folder-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;
  max-height:52vh;overflow-y:auto;padding:2px;-webkit-overflow-scrolling:touch}
.av-folder-item{display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:8px 5px;border:1px solid var(--stroke);border-radius:12px;
  background:var(--glass);cursor:pointer;transition:.15s;min-width:0}
.av-folder-item:hover{border-color:var(--amber);background:var(--glass-2)}
.av-folder-item:active{transform:scale(.96)}
.av-folder-item canvas{width:100%;height:auto;aspect-ratio:1;
  border-radius:9px;background:none;image-rendering:auto;
  box-shadow:0 0 0 1px var(--stroke)}
.av-folder-item span{font-size:11px;color:var(--text-dim);max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* 夜里（含黄昏）弹窗里的字提亮一点，跟开灯那套保持一致 */
html[data-scene="night"] .av-pick-sec,
html[data-scene="dusk"] .av-pick-sec{color:var(--amber)}
html[data-scene="night"] .av-pick-row button,
html[data-scene="dusk"] .av-pick-row button{color:var(--text)}

@media (max-width:520px){
  .av-swatches{grid-template-columns:repeat(8,1fr);gap:5px}
  .av-folder-grid{grid-template-columns:repeat(2,1fr)}
  .av-pick-row button{min-width:0;flex:1 1 100%}
}
