/* ============================================================================
   多资产链策略看板 · 样式（黑板报 / 手绘漫画风）
   ────────────────────────────────────────────────────────────────────────────
   三层结构：
     ① 房间层（.room）        天花板 / 墙 / 地面，纯背景
     ② 板面层（.board + 内容） 一块挂在墙上的大黑板，全部文字都写在板上；
                              黑板与所有卡片的"手绘外框"由 sketch.js(RoughJS) 画，
                              所以本文件里这些盒子一律是透明底、无边框，
                              只有圆角/阴影这类 CSS 能做到的东西。
     ③ 光效层               .beam2d / .lightpool / .shade / #lightCanvas / .tavern
     另加过场层 #wipe（擦黑板）。

   配色纪律：粉笔色板刻意保持 7 色（白·奶油·金·红·绿·蓝·紫·橙），
   任何一张图里都同时出现 3~4 种，避免"单色蓝"或"蓝橙双色"的单调。

   字体：Patrick Hand（拉丁/数字，手写）+ ZCOOL KuaiLe（中文，站酷快乐体）。
   ========================================================================== */
@font-face{
  font-family:"Patrick Hand";
  src:url("fonts/patrick-hand-latin-400.woff2") format("woff2");
  font-weight:400; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"ZCOOL KuaiLe";
  src:url("fonts/zcool-kuaile-cn-400.woff2") format("woff2");
  font-weight:400; font-style:normal; font-display:swap;
}

:root {
  /* ---------------- 粉笔色板 ---------------- */
  --bg: #0a0f0e;
  --bg2: #101918;
  --board1: #1d2b28;      /* 黑板受光面（偏冷墨绿） */
  --board2: #16211f;
  --board3: #0f1716;
  --txt: #eef4ef;         /* 白粉笔 */
  --mut: #a4b8b1;         /* 灰粉笔（次要文字） */
  --gold: #ffd166;
  --red: #ff7a85;
  --grn: #6ee7a8;
  --blu: #7cc4ff;
  --purp: #c8a2ff;
  --org: #ffa657;
  --cream: #ffe9c2;
  --gold-glow: rgba(255,209,102,.34);
  --blu-glow: rgba(124,196,255,.30);
  --grn-glow: rgba(110,231,168,.30);
  --red-glow: rgba(255,122,133,.30);
  --line: rgba(226,238,231,.16);          /* 粉笔细线 */
  --line2: rgba(226,238,231,.28);
  --ink: rgba(12,20,18,.42);              /* 卡片上的淡淡墨底 */
  --shadow: 0 10px 28px rgba(0,0,0,.45);

  /* 手写字体：Patrick Hand 只有拉丁字形，所以数字/英文会落到它，
     中文自动落到 ZCOOL KuaiLe；再用系统楷体兜底（离线也能看）。 */
  --f-hand: "Patrick Hand", "ZCOOL KuaiLe", "Comic Sans MS", "Segoe Print",
            "楷体", "KaiTi", "华文行楷", "STXingkai", cursive, system-ui, sans-serif;

  /* ---------------- 房间的纵向预算 ----------------
     天花板带 / 吧台高度 / 内容底距必须由同一套变量驱动，否则某些视口高度下
     内容会被前景吧台吃掉。约束（两者都由 check_light.py 的断言守住）：
       首屏：band-top + 内容高 ≤ 视口高 - tavern-h   → 最后一行仍在吧台之上
       滚底：pad-bottom ≥ tavern-h                  → 滚到底也不会被台面盖住
     实测（2026-09-19，_probe_pages.py 跨 5 个视口）：
       吧台从固定选择栏(~56px)换成一整幅手绘吧台之后，曲线页页脚一度被压 47px、
       F17·保险页被压 13px，1366×768 上保险页更是差 44px —— 这是改造引入的
       回归，不是既有行为。反推出的硬约束是：
         band_top(vh) + tavern_h(vh) ≤ vh − K(vh)
       其中 K 是"内容栈"高度（去掉 band-top 后，顶栏+页面+页脚+段距）：
         K ≈ 427(home) / 450(curve) / 547(insure,矮档) / 584(insure,≤940档)
      下面两个 clamp 就是按这条约束（留 20~40px 余量）标定出来的；
      再配合 #eqChart 的自适应高度与矮视口的卡片收紧，才做到 5 个视口全部为正。
       注意 band-top 不能再往下压太多：吊灯静止时下端约在 y≈100（与视口高成比例），
       标题顶边必须留出余量（灯是可拖的，拖动时允许压标题）。 */
  /* 2026-09-19 第二次标定：吧台换成实拍图（web/bar.png）后高度从 113px 涨到 188px
     @1440（--tavern-h = 100vw×0.13058，宽度铺满、高度按图比例），内容区少了约 75px。
     天花板带跟着收：126/17vh/200 -> 92/11vh/160，把板整体上移换回空间。 */
  --band-top: clamp(92px, 11vh, 160px);
  /* 吧台改成实拍图 web/bar.png（2688×351，比例 0.13058）之后，高度就由"宽度铺满"推出来：
     1440 宽 -> 188px、1920 宽 -> 251px（原来是手绘的 clamp(84px,12.5vh,152px)）。
     纵向预算跟着它走：--pad-bottom = tavern-h + 26px。 */
  --tavern-h: calc(100vw * 0.13058);
  --pad-bottom: calc(var(--tavern-h) + 26px);
  /* 墙面顶沿：黑板顶边必须远高于吊灯下端，让灯"吊在板前面"而不是贴在板边。
     板顶到内容之间那一段空白正好承接体积光锥。 */
  --wall-top: max(10px, calc(var(--band-top) - 158px));
  /* 黑板比内容外扩多少（做出"板比内容大一圈"的框）。
     视口不够宽时必须收为 0，否则负 inset 会撑出横向滚动条。 */
  --board-pad: 30px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  background: #0a0f0e;
  color: var(--txt);
  font-family: var(--f-hand);
  font-size: 15px;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  /* 兜底：装饰层（黑板/吊灯画布等）一律不许产生横向滚动条。
     用 clip 而不是 hidden —— clip 不建立滚动容器，不会影响表头的 sticky。 */
  overflow-x: clip;
  /* 拖拽吊灯时不要刷蓝选中文字：整站文字不可选中、不可拖拽。 */
  -webkit-user-select: none; user-select: none;
  -webkit-user-drag: none;
  -webkit-tap-highlight-color: transparent;
}

/* ================================================================
   场景层（纯装饰、无逻辑；整段删掉不影响看板功能）
   → 把页面当一个房间分层（z-index 由低到高）：
     0  .room          天花板 / 后墙 / 地面（fixed）
     1  .board         挂在墙上的大黑板，全部文字都在这块板上
     3  .beam2d        空气中的体积光束（顶点=灯的像素坐标）
     4  .lightpool     光池：灯正下方那一片，把内容"照亮"
     5  .shade         阴影：聚光外圈的暗部，压在内容之上
     6  .room__vig2    暗角
     7  .light-canvas  吊灯本体（Three.js）
     8  .tavern        最前景的手绘吧台
     60 #wipe          擦黑板过场
   ================================================================ */

/* ---------- -1. 门禁（SCENE-0）：访问口令 ---------- */
/* 未放行时 html[data-gate="locked"]：body 只显示 #gate，其余节点全部不显示 ——
   连房间/光效/吧台都不出现，第一屏零信息泄露。放行后属性变 open，#gate 消失。
   画风对齐看板：黑板底 + 粉笔字 + 手绘虚线框 + 徽章站标。 */
#gate{ display:none; }
html[data-gate="locked"] #gate{
  display:flex; position:fixed; inset:0; z-index:80;
  align-items:center; justify-content:center; padding:24px;
  background:
    repeating-linear-gradient(104deg, rgba(255,255,255,.016) 0 1.5px, transparent 1.5px 13px),
    radial-gradient(126% 84% at 50% 2%, #17201f 0%, #101918 40%, #0a100f 72%, #050908 100%);
}
html[data-gate="locked"] body > *:not(#gate){ display:none !important; }
.gate__box{
  position:relative; width:min(430px, 100%);
  display:flex; flex-direction:column; align-items:center; gap:13px;
  padding:30px 30px 22px; border-radius:16px; margin:0;
  background:linear-gradient(160deg, #1b2926 0%, #131d1b 58%, #0f1716 100%);
  border:2px dashed rgba(255,209,102,.42);
  box-shadow:0 20px 64px rgba(0,0,0,.62), inset 0 0 0 1px rgba(255,255,255,.045);
  rotate:-.6deg;
}
.gate__logo{
  width:74px; height:74px;
  filter:drop-shadow(0 0 20px rgba(124,196,255,.38));
}
.gate__title{
  /* font-weight 必须显式给 400：h2 默认 bold，而两个手写体都只有 400 字重，
     浏览器会做"伪粗"合成 —— 笔画被描粗，手写感全毁（看起来像黑体）。
     字号与看板 h1(26px) 对齐。 */
  margin:0; font-size:26px; font-weight:400; letter-spacing:.08em; color:#fbfdf8;
  text-shadow:0 0 2px rgba(255,255,255,.3), 0 0 22px rgba(255,255,255,.16);
}
.gate__sub{ margin:0; color:var(--mut); font-size:13.5px; letter-spacing:.03em; }
.gate__row{ display:flex; gap:10px; width:100%; }
.gate__row input{
  flex:1 1 auto; min-width:0; font:inherit; font-size:15px; color:var(--txt);
  padding:11px 14px; border-radius:10px;
  background:rgba(255,255,255,.055);
  border:1px dashed rgba(255,255,255,.30);
}
.gate__row input::placeholder{ color:rgba(164,184,177,.6); }
.gate__row input:focus{
  outline:none; border-color:rgba(255,209,102,.62);
  box-shadow:0 0 0 3px rgba(255,209,102,.13);
}
/* 门禁按钮：不依赖 sketch.js（locked 时手绘层不一定画）→ 自带粉笔边框 */
.gate__row .btn{
  flex:0 0 auto; padding:10px 20px 11px; border-radius:10px;
  border:1px dashed rgba(110,231,168,.5); color:var(--grn);
  background:rgba(110,231,168,.08);
  transition:background .18s, color .18s;
}
.gate__row .btn:hover{ background:rgba(110,231,168,.16); color:#eafff3; }
.gate__err{ margin:0; color:var(--red); font-size:13px; letter-spacing:.02em; }
.gate__tip{
  margin:0; color:rgba(164,184,177,.72); font-size:12px;
  text-align:center; line-height:1.6;
}
@keyframes gateShake{
  0%,100%{ transform:translateX(0); }
  20%{ transform:translateX(-7px); }
  40%{ transform:translateX(6px); }
  60%{ transform:translateX(-4px); }
  80%{ transform:translateX(3px); }
}
.gate__box.shake{ animation:gateShake .38s ease; }

/* ---------- 0. 房间 ---------- */
.room{ position:fixed; inset:0; z-index:0; pointer-events:none; overflow:hidden; }
.room__wall{
  position:absolute; inset:0;
  background:
    /* 墙面的手绘排线：稀疏的斜向细纹，让"墙"也有笔触 */
    repeating-linear-gradient(104deg, rgba(255,255,255,.016) 0 1.5px, transparent 1.5px 13px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.012) 0 1px, transparent 1px 128px),
    radial-gradient(126% 84% at 50% 2%, #17201f 0%, #101918 40%, #0a100f 72%, #050908 100%);
}
.room__ceil{
  position:absolute; left:0; right:0; top:0; height:26vh;
  background:linear-gradient(180deg, #040807 0%, #070c0b 44%, rgba(7,12,11,0) 100%);
}
.room__ceil::after{          /* 顶棚与后墙的交界压一道暗线 → 有"顶"的感觉 */
  content:""; position:absolute; left:0; right:0; bottom:0; height:3px;
  background:linear-gradient(90deg, transparent, rgba(0,0,0,.85), transparent);
}
.room__floor{
  position:absolute; left:0; right:0; bottom:0; height:34vh;
  background:linear-gradient(0deg, rgba(26,17,8,.95) 0%, rgba(17,12,7,.55) 32%, transparent 100%);
}

/* ---------- 1. 大黑板 ---------- */
/* 绝对定位子元素的包含块是 .wrap 的 padding box，inset 以它为基准，
   所以 top 必须显式减掉要留出的墙面高度，否则板会顶到屏幕最上沿。
   bottom 用 (pad-bottom - 40px)：板的底沿恰好落在最后一行内容之下 40px。 */
.board{
  position:absolute;
  left:calc(-1 * var(--board-pad)); right:calc(-1 * var(--board-pad));
  top:var(--wall-top); bottom:calc(var(--pad-bottom) - 40px);
  z-index:-1; border-radius:7px;
  background:
    radial-gradient(120% 44% at 50% -6%, rgba(255,206,150,.09), transparent 58%),
    linear-gradient(170deg, var(--board1) 0%, var(--board2) 46%, var(--board3) 100%);
  box-shadow:
    0 44px 98px -22px rgba(0,0,0,.94),     /* 板挂在墙上投下的影 */
    0 12px 30px -14px rgba(0,0,0,.88),
    0 0 0 1px rgba(0,0,0,.55);
}
/* 粉笔擦痕 / 灰：一层不规则的浅色扫痕 + 几处抹过的淡斑 */
.board__grain{
  position:absolute; inset:0; z-index:-2; border-radius:inherit;
  pointer-events:none; overflow:hidden;
  background:
    radial-gradient(34% 24% at 15% 20%, rgba(240,248,244,.055), transparent 70%),
    radial-gradient(28% 20% at 78% 58%, rgba(240,248,244,.045), transparent 72%),
    radial-gradient(44% 16% at 48% 94%, rgba(240,248,244,.032), transparent 74%),
    repeating-linear-gradient(78deg, rgba(255,255,255,.022) 0 2px, transparent 2px 10px),
    repeating-linear-gradient(96deg, rgba(255,255,255,.014) 0 3px, transparent 3px 27px);
  mix-blend-mode:screen;
}

/* ---------- 3. 空气中的体积光束 ---------- */
/* 锥角 ±20°：铺太宽会把两侧也照亮 → 轴心/两侧对比掉到 2.8×，
   光束会读成一团"雾"。实测收窄 + 降底色后对比 4~6×，才有光束感。 */
.beam2d{
  position:fixed; inset:0; z-index:3; pointer-events:none;
  /* 抛物线形打光（对照 jinruozai/HTML-Light-Demo 的 SpotLight 锥体投影）：
     光锥不是固定竖直的扇形，而是以灯口为顶点、沿光轴方向 --beam-from 张开的
     锥形投影。--beam-from / --beam-half 由 light-scene.js 每帧下发
     （--beam-half = SpotLight.angle × 0.75 视觉系数，竖直时 25.5deg，见
     light-scene.js BEAM_VISUAL 注释）——拖动灯时锥体跟着转、
     落点光池跟着走，页面像真的被一盏会转的聚光灯照亮。
     from = 锥轴角 - 半角：stop 从 0 扫到 2×half 恰好画出一个对称张开的锥，
     锥轴处最亮（等效 penumbra 0.88 的中心浓、边缘软）。 */
  background:conic-gradient(from calc(var(--beam-from,180deg) - var(--beam-half,25.5deg)) at var(--lamp-x,50%) var(--lamp-y,6%),
    transparent 0deg,
    color-mix(in srgb, var(--lamp-color,#ffb36b) 30%, transparent) calc(var(--beam-half,25.5deg) - 9deg),
    color-mix(in srgb, var(--lamp-color,#ffb36b) 42%, transparent) calc(var(--beam-half,25.5deg) - 2deg),
    color-mix(in srgb, var(--lamp-color,#ffb36b) 52%, transparent) var(--beam-half,25.5deg),
    color-mix(in srgb, var(--lamp-color,#ffb36b) 42%, transparent) calc(var(--beam-half,25.5deg) + 2deg),
    color-mix(in srgb, var(--lamp-color,#ffb36b) 30%, transparent) calc(var(--beam-half,25.5deg) + 9deg),
    transparent calc(var(--beam-half,25.5deg) * 2));
  /* 衰减放缓、底部不归零（旧版 92% 处已归零 → 光束半路蒸发，与光池断开，
     "照到页面"的实体感出不来）。留 ~12% 残影让锥体一路贯穿、接进光池。 */
  -webkit-mask-image:linear-gradient(180deg, rgba(0,0,0,.98) 0%, rgba(0,0,0,.84) 16%, rgba(0,0,0,.66) 34%, rgba(0,0,0,.48) 54%, rgba(0,0,0,.30) 74%, rgba(0,0,0,.17) 90%, rgba(0,0,0,.12) 100%);
  mask-image:linear-gradient(180deg, rgba(0,0,0,.98) 0%, rgba(0,0,0,.84) 16%, rgba(0,0,0,.66) 34%, rgba(0,0,0,.48) 54%, rgba(0,0,0,.30) 74%, rgba(0,0,0,.17) 90%, rgba(0,0,0,.12) 100%);
  mix-blend-mode:screen; opacity:.95; filter:blur(12px);
}
/* 紧束亮芯：光子最密的那一段。别用接近纯白的颜色，否则整道光的观感会发灰。 */
.beam2d::before{
  content:""; position:absolute; inset:0;
  background:conic-gradient(from calc(var(--beam-from,180deg) - var(--beam-half,25.5deg)) at var(--lamp-x,50%) var(--lamp-y,6%),
    transparent 0deg,
    color-mix(in srgb, #ffdca8 26%, transparent) calc(var(--beam-half,25.5deg) - 6deg),
    color-mix(in srgb, #ffe9c8 40%, transparent) var(--beam-half,25.5deg),
    color-mix(in srgb, #ffdca8 26%, transparent) calc(var(--beam-half,25.5deg) + 6deg),
    transparent calc(var(--beam-half,25.5deg) * 2));
  filter:blur(16px);
  -webkit-mask-image:linear-gradient(180deg, rgba(0,0,0,1) 0%, rgba(0,0,0,.60) 28%, rgba(0,0,0,.30) 56%, rgba(0,0,0,.10) 84%, transparent 100%);
  mask-image:linear-gradient(180deg, rgba(0,0,0,1) 0%, rgba(0,0,0,.60) 28%, rgba(0,0,0,.30) 56%, rgba(0,0,0,.10) 84%, transparent 100%);
}

/* ---------- 4. 光池（中心 --lx/--ly 由 light-scene.js 实时下发） ---------- */
/* 光锥 ∩ 页面的亮斑：竖向略拉长（锥体与页面的交线就是竖向张开的喇叭口），
   亮度给到 26%——与 .beam2d 底部残影衔接成"锥体→光斑"连续体。 */
.lightpool{
  position:fixed; inset:0; z-index:4; pointer-events:none;
  background:radial-gradient(600px 470px at var(--lx,50%) var(--ly,34%),
    color-mix(in srgb, var(--lamp-color,#ffb36b) 26%, transparent) 0%,
    color-mix(in srgb, var(--lamp-color,#ffb36b) 10%, transparent) 38%,
    transparent 70%);
  mix-blend-mode:screen; opacity:.85; transition:opacity .25s;
}

/* ---------- 5. 阴影：聚光外圈的暗部 ---------- */
/* 这一层是"灯在内容之上"最直观的证据：拖动灯时暗部与亮斑一起平移。
   multiply → 只在光圈外压暗，光圈内保持透明（不牺牲可读性）。
   外圈压得不那么狠（.58）：黑板本身已经很暗，再狠就吃掉粉笔字了。 */
.shade{
  position:fixed; inset:0; z-index:5; pointer-events:none;
  background:radial-gradient(900px 720px at var(--lx,50%) var(--ly,36%),
    rgba(0,0,0,0) 0%, rgba(0,0,0,0) 26%,
    rgba(0,0,0,.20) 54%, rgba(0,0,0,.44) 78%, rgba(0,0,0,.58) 100%);
  mix-blend-mode:multiply;
}

/* ---------- 6. 暗角 ---------- */
.room__vig2{
  position:fixed; inset:0; z-index:6; pointer-events:none;
  background:radial-gradient(120% 92% at 50% 28%, transparent 48%, rgba(0,0,0,.12) 72%, rgba(0,0,0,.36) 100%);
}

/* ---------- 7. 吊灯画布：Three.js，在内容之上（灯挡在内容前面） ---------- */
.light-canvas{
  position:fixed; inset:0; z-index:7; width:100%; height:100%;
  display:block; pointer-events:none;
}
.light-canvas--off{ display:none; }   /* Three.js 加载失败时隐藏，看板正常 */

/* 操作提示 */
.lamp-hint{
  position:fixed; right:18px; bottom:calc(var(--tavern-h) + 46px); z-index:9;
  pointer-events:none; font-size:12px; letter-spacing:.04em;
  color:rgba(255,209,102,.66);
  background:rgba(9,14,13,.6); border:1px dashed rgba(255,209,102,.30);
  padding:6px 13px; border-radius:14px; transform:rotate(-.7deg);
  transition:opacity .6s, transform .6s;
}
.lamp-hint--gone{ opacity:0; transform:translateY(6px) rotate(-.7deg); }
body.is-pulling-light{ cursor:grabbing; }

/* ---------- 8. 最前景：手绘吧台 ---------- */
/* 实拍吧台图（.tavern__img）铺满宽度，高度由 --tavern-h 按图比例定。
   这里只负责"从暗场里淡出"和背光。 */
/* ===== 场景层 C-1：吧台后的调酒师（web/barmaid1.png、barmaid2.png）
   层叠：z-index 与 .tavern 同为 8 —— 同层时靠**文档顺序**决定谁在上，所以人物在
   HTML 里必须写在 .tavern **之前**：吧台画在人物之上，把下半身挡住（= 站在吧台后）。
   又因为它在光照合成层（canvas, z7）之上，不会被暗角压暗（板框曾栽在这个坑里）。
   位置与尺寸：右下角，右缘距视口 1.6vw。
   【腰部贴台面】bar.png 里台面实体（宽 >55% 图宽）从图高 61.8% 处才开始，上面是
   透明区+摆着的酒瓶酒杯——所以"台面顶沿"距视口底部 = tavern-h × 0.382，**不是**
   .tavern 盒子的上沿（此前按盒子上沿定位，人物腰切边悬空在台面上方约 76px）。
   现在底边沉到台面顶沿之下 0.6vw：腰切边贴住台面，腰以下被台面挡住。
   人物高 = 100vw × 0.140（1440 时 202px）；姿势2 = 0.147（×1.05：姿势2 原生脸比
   姿势1 小约 4~6%，放大 1.05 后脸部观感齐平——×1.10 实测过头约 5~8%）。
   两张 bottom 对齐 → 腰线同高、只有头部升高。
   同一人的两种姿势按页面切换：概览/历史信息 = 姿势1，收益曲线/F17保险 = 姿势2
   （映射表在 sketch.js 的 MAID_POSE）。
   硬约束：人物顶端必须落在"当前持仓明细"面板里 70%/30% 标签的下方（标签底 y约 552；
   现顶 y约 615~635，比旧位置更低更安全）。想调大人物时先量这两个值，别压住数据标签。 */
.barmaid{
  position:fixed; right:1.6vw; z-index:8;
  bottom:calc(var(--tavern-h) * 0.382 - 0.6vw);
  pointer-events:none;
}
/* 两张姿势图叠在**同一个位置**（第 1 张撑开容器、第 2 张绝对定位盖上去），
   靠 opacity 交叉淡入淡出切换：.on 的那张显示、另一张淡出。
   切换由 sketch.js 的 syncMaid() 完成（听 .page 的 hidden 属性变化）。
   注意：两张都走 CSS transition，所以是真正的"交叉溶解"，不是先隐后显。 */
.barmaid img{
  display:block; height:calc(100vw * 0.140); width:auto;
  opacity:0; transition:opacity .55s ease;
  /* 与暗场融合：轻微降饱和 + 降亮 + 落影，避免"贴纸感" */
  filter:saturate(.93) brightness(.95) drop-shadow(0 6px 16px rgba(0,0,0,.6));
}
.barmaid img:not(:first-child){ position:absolute; left:0; bottom:0; }
/* 姿势2 略放大（×1.05）：姿势2 原生脸略小，放大到脸部观感与姿势1 齐平。
   两张 bottom 对齐 → 腰线同高，只有头部升高 */
.barmaid img[data-pose="2"]{ height:calc(100vw * 0.147); }
.barmaid img.on{ opacity:1; }

.tavern{
  position:fixed; left:0; right:0; bottom:0; height:var(--tavern-h); z-index:8;
  pointer-events:none;
  /* 渐隐带只留 3%：手绘酒瓶的瓶颈能到 6%~10% 高度，
     渐隐带开大一点就会把瓶口那一截吃掉，整排瓶子看起来"没长齐"。 */
  -webkit-mask-image:linear-gradient(180deg, transparent 0, #000 3%, #000 100%);
  mask-image:linear-gradient(180deg, transparent 0, #000 3%, #000 100%);
}
/* 手绘吧台时代这里有一层"瓶墙受光"的径向暖光（.tavern::before）；
   换成实拍图后照片自带背景，留着只会在透明区域露出光斑，已删除。 */
/* 实拍吧台图：宽度铺满视口，高度按图比例（.tavern 的高度就是它算出来的）。
   object-fit:cover 只是保险 —— 万一比例常数有极小误差，宁可微裁也不要拉伸变形。 */
.tavern__img{ display:block; width:100%; height:100%; object-fit:cover; object-position:center bottom; }


/* ================================================================
   过场层：擦黑板
   #wipe 整体平移；真正"挡住旧页"的是里面的 .wipe__sheet（带毛边遮罩），
   粉笔灰条挂在 sheet 前后两条边上，所以不能被遮罩裁掉 → 放在 sheet 之外。
   ================================================================ */
.wipe{
  position:fixed; inset:0; z-index:60; pointer-events:none;
  visibility:hidden; will-change:transform;
}
.wipe__sheet{
  position:absolute; inset:0;
  background:
    radial-gradient(90% 40% at 50% 0%, rgba(255,206,150,.06), transparent 62%),
    repeating-linear-gradient(102deg, rgba(255,255,255,.02) 0 2px, transparent 2px 11px),
    linear-gradient(170deg, var(--board1) 0%, var(--board2) 46%, var(--board3) 100%);
}
.wipe__dust{
  position:absolute; top:-4%; bottom:-4%; width:clamp(38px,6vw,90px);
  opacity:.9; filter:blur(1px);
  background:
    radial-gradient(closest-side at 70% 6%,  rgba(246,252,248,.24), transparent 70%),
    radial-gradient(closest-side at 34% 22%, rgba(246,252,248,.16), transparent 70%),
    radial-gradient(closest-side at 76% 38%, rgba(246,252,248,.20), transparent 70%),
    radial-gradient(closest-side at 28% 55%, rgba(246,252,248,.14), transparent 70%),
    radial-gradient(closest-side at 72% 72%, rgba(246,252,248,.20), transparent 70%),
    radial-gradient(closest-side at 36% 88%, rgba(246,252,248,.15), transparent 70%),
    linear-gradient(90deg, transparent, rgba(246,252,248,.10) 62%, transparent);
}
.wipe__dust--lead{ right:-10px; }
.wipe__dust--trail{ left:-10px; transform:scaleX(-1); }

.wipe--in{ visibility:visible; animation:wipeIn .33s cubic-bezier(.24,.72,.32,1) forwards; }
.wipe--out{ visibility:visible; animation:wipeOut .43s cubic-bezier(.55,.06,.72,.30) forwards; }
@keyframes wipeIn{  from{ transform:translateX(-103%);} to{ transform:translateX(0);} }
@keyframes wipeOut{ from{ transform:translateX(0);}    to{ transform:translateX(103%);} }

/* 旧页被"擦掉"：一层不规则条纹遮罩扫过去 + 整体失焦变淡 */
@keyframes chalkErase{
  0%   { -webkit-mask-position:0 0;   opacity:1;   filter:blur(0); }
  55%  { opacity:.52; }
  100% { -webkit-mask-position:-200% 0; opacity:.10; filter:blur(1.4px); }
}
#mainView.is-erasing > .page:not([hidden]){
  -webkit-mask-image:repeating-linear-gradient(93deg,
    rgba(0,0,0,1) 0 33px, rgba(0,0,0,.20) 33px 40px,
    rgba(0,0,0,.86) 40px 57px, rgba(0,0,0,.10) 57px 65px,
    rgba(0,0,0,1) 65px 97px);
  mask-image:repeating-linear-gradient(93deg,
    rgba(0,0,0,1) 0 33px, rgba(0,0,0,.20) 33px 40px,
    rgba(0,0,0,.86) 40px 57px, rgba(0,0,0,.10) 57px 65px,
    rgba(0,0,0,1) 65px 97px);
  -webkit-mask-size:200% 100%; mask-size:200% 100%;
  -webkit-mask-repeat:repeat-x; mask-repeat:repeat-x;
  animation:chalkErase .33s linear both;
}

/* 新页"写出来"：错峰淡入 + 由左向右揭开 + 轻微失焦收回 */
@keyframes chalkWrite{
  from{ opacity:0; filter:blur(3px); clip-path:inset(0 100% 0 0); }
  to  { opacity:1; filter:blur(0);   clip-path:inset(0 0 0 0); }
}
.write-in{ animation:chalkWrite .42s cubic-bezier(.2,.72,.32,1) both; animation-delay:calc(var(--ci, 0) * 40ms); }


/* ================================================================
   内容层：坐在黑板上
   padding-bottom 由 --pad-bottom 给出（= 吧台高 + 26px），保证最后一行内容
   滚到底时也不会被前景台面挡住。
   ================================================================ */
.wrap{
  position:relative; z-index:2; max-width:1180px; margin:0 auto;
  padding:var(--band-top) 22px var(--pad-bottom);
}

/* ---------- 顶栏：标题 + 手绘页签（原底部固定选择栏已撤掉） ---------- */
header.top { margin-bottom:22px; }
.top__row{
  display:flex; align-items:center; justify-content:space-between;
  gap:14px 26px; flex-wrap:wrap;
}
h1 {
  position:relative; isolation:isolate;
  font-size:26px; line-height:1.35; letter-spacing:.4px;
  display:flex; align-items:center; gap:11px;
  color:#fbfdf8;
  text-shadow:0 0 2px rgba(255,255,255,.30), 0 0 22px rgba(255,255,255,.16);
}
/* 站标(雪花少女徽章 web/logo.png):顶栏标题旁 + 浏览器标签 favicon。
   插画自带深蓝描边,深色黑板上天然高对比;drop-shadow 与标题 text-shadow 呼应。 */
h1 .logo{
  height:1.5em; width:auto; flex:0 0 auto;
  filter:drop-shadow(0 0 10px rgba(124,196,255,.35));
}
.meta{
  color:var(--mut); font-size:13px; margin-top:9px;
  text-shadow:0 1px 5px rgba(0,0,0,.85), 0 0 14px rgba(0,0,0,.6);
}
.who--foot{
  /* 使用人标识（唯一一处）= 写在吧台台面上的字（fixed，不占文档流）。
     · 位置标定：bar.png 台面实体从图高 61.8% 起，经 --tavern-h(=100vw*0.13058)
       映射后，**桌面顶面可见带 = 距视口底 100vw*0.019 ~ 0.050**（27~72px @1440）；
       再往下（<0.019）就落到吧台立面上了。取 0.028 → 落在带内偏"前"，
       正对左下角那盘水果（水果盘 x 约 100vw*0.040~0.078）。
       ⚠ 旧值 0.055 落在桌面顶面**之上**的暗区（物件后方），所以"写了但看不见"。
     · 形态：perspective + rotateX 把字压扁贴到桌面上（桌面在这个视角下是俯视的），
       再加一点微旋 —— 像随手写在木头上，而不是飘在黑板前的水印。
     · 低对比但不隐形：深棕 + 上缘浅色压痕高光（截图仍可辨认 = 追溯功能的前提）。
     · 放文档流里会把"内容底沿"顶低 30px、顶穿前景遮挡断言（真踩过）；
       fixed 定位顺带被测量脚本的 position 过滤排除，不影响几何断言。
     · 顶栏那处标识已按用户要求去掉（2026-09-20），所以这里不再有 .who 基类可复用，
       nowrap 等公共属性直接内联在本规则里。 */
  position:fixed;
  left:calc(100vw * 0.033);
  bottom:calc(100vw * 0.028);
  z-index:9;
  white-space:nowrap;
  padding:0; border:0; border-radius:0; background:none;
  font-size:13px; letter-spacing:.05em;
  /* 深棕近黑（像烙在木头上的字）：初版 rgba(...,.60) 在亮橙桌面上实测
     "写了等于没写"（该区暗像素仅 24% vs 桌面 7%，人眼在截图里看不见）。
     追溯功能的前提是"能被认出来"，所以给到 .85 但仍不做背景/描边。 */
  color:rgba(58,30,8,.85);
  text-shadow:0 1px 0 rgba(255,236,204,.5), 0 0 8px rgba(255,190,110,.25);
  transform-origin:50% 100%;
  transform:perspective(240px) rotateX(34deg) rotate(-1.2deg);
}
/* 窄屏按设计隐藏吧台（.tavern display:none）——桌上就没有位置了，标识随之隐藏。 */
@media(max-width:760px){
  .who--foot{ display:none; }
}

/* 手绘页签：黑板右上角贴的一排标签，轻微歪斜 → 不死板。
   每个按钮 isolation:isolate，sketch 画的 svg(z-index:-1) 就在背景与文字之间。 */
/* 手绘框的硬约束：相邻两个"有框"元素的盒间距必须 >= 18px。
   每个框都向内缩 6px 画（sketch.js 的 INSET），两侧就是 12px；
   若盒间距只有 6/9/12px，两条框线会贴住甚至互相穿插 —— 看起来就是"框画得很乱"。
   18px = 12 + 6px 视觉留白。改间距时别低于这个值。 */
.tabs{ display:flex; gap:18px; flex-wrap:wrap; }
.tabs button{
  position:relative; isolation:isolate;
  background:transparent; border:0; cursor:pointer;
  font-family:inherit; font-size:15px; color:var(--mut);
  padding:9px 17px 11px; letter-spacing:.4px;
  rotate:-.7deg;
  transition:color .18s, translate .18s;
}
.tabs button:nth-child(even){ rotate:.8deg; }
.tabs button:nth-child(3){ rotate:-.3deg; }
.tabs button:hover{ color:var(--cream); translate:0 -2px; }
.tabs button.on{ color:var(--gold); font-weight:700; text-shadow:0 0 12px var(--gold-glow); }

/* sketch.js 画的手绘 SVG 挂件：永远在卡片背景之上、文字之下 */
svg.sk{ position:absolute; inset:0; z-index:-1; pointer-events:none; display:block; }

/* 黑板那一圈框是唯一的例外：它必须画在"光束/光池/暗角/暗角2/吊灯画布"
   这些场景层**之上**（z-index 7 > shade 5、room__vig2 6、light-canvas 7 同层靠后）。
   原因：贴板的框在 .board 里是 z-index:-1，会被 multiply 暗角压掉近七成亮度 ——
   板的下边框正好落在底部暗区，肉眼完全看不见，观感就成了"最大的框没有画到黑板结束"。
   粉笔线本来就在黑板表面上、光照之下，提到场景层之上才是对的。
   它只出现在板的四边（内容离板边至少 28px），所以不会压住任何文字。
   几何位置由 sketch.js 的 syncOverlays() 跟随 .board 的矩形同步。 */
/* 选择器必须写成 svg.sk--board：它和上面的 svg.sk 特异性相同（元素+类），
   靠"后写者胜"覆盖 position/inset/z-index。只写 .sk--board（单类）会被 svg.sk 压住。 */
svg.sk--board{ position:fixed; left:0; top:0; right:auto; bottom:auto; width:0; height:0; z-index:7; }

/* ---------------- 登录 / 注册 ---------------- */
.authwrap{ display:flex; justify-content:center; align-items:flex-start; padding-top:7vh; }
.authcard{
  position:relative; isolation:isolate;
  width:100%; max-width:430px; background:var(--ink);
  padding:30px 30px 26px; backdrop-filter:blur(3px);
}
.auth-tabs{ display:flex; gap:10px; margin-bottom:22px; }
.auth-tabs button{
  flex:1; padding:10px; border:1px dashed var(--line2); border-radius:12px;
  background:transparent; color:var(--mut); font-family:inherit; font-size:15px; cursor:pointer;
}
.auth-tabs button.on{ background:rgba(124,196,255,.16); border-color:var(--blu); color:var(--cream); font-weight:600; }
.authform{ display:flex; flex-direction:column; gap:14px; }
.authform label{ font-size:13.5px; color:var(--mut); display:flex; flex-direction:column; gap:7px; }
.authform label.chk{ flex-direction:row; align-items:center; color:var(--txt); font-size:14px; gap:8px; cursor:pointer;}
.authform input{
  background:rgba(9,15,14,.72); border:1px dashed var(--line2); border-radius:10px;
  padding:11px 13px; color:var(--txt); font-family:inherit; font-size:15px; outline:none;
}
.authform input:focus{ border-color:var(--blu); border-style:solid; }
.authform .btn{ margin-top:6px; }
.formmsg{ font-size:13px; color:var(--red); min-height:16px; }

/* ---------------- action card ---------------- */
.action {
  position:relative; isolation:isolate; margin-bottom:22px;
  background:linear-gradient(135deg, rgba(255,166,87,.10), rgba(255,255,255,.015));
  padding:24px 26px 22px;
  rotate:-.25deg;
}
.action .row1{display:flex; align-items:center; gap:14px; flex-wrap:wrap;}
.badge{
  padding:5px 15px; border-radius:12px; font-weight:700; font-size:14.5px;
  letter-spacing:.8px; transform:rotate(-1.6deg);
  border:1.6px solid var(--line2); background:rgba(255,255,255,.05); color:var(--mut);
}
.badge.HOLD{ color:var(--mut); border-color:rgba(164,184,177,.5); }
.badge.BUY{ background:rgba(110,231,168,.14); color:var(--grn); border-color:var(--grn); box-shadow:0 0 16px var(--grn-glow); }
.badge.SELL{ background:rgba(255,122,133,.14); color:var(--red); border-color:var(--red); box-shadow:0 0 16px var(--red-glow); }
.action .txt{ font-size:18px; line-height:1.6; color:#fbfdf8; }
/* 「下一交易日操作」红色加粗：比其它信息更醒目。
   由 app.js 的 actionView() 按"是否有动作(非 HOLD)"切换 .hl。 */
.action .txt.hl{ color:var(--red); font-weight:700; }
.action .sub{ color:var(--mut); font-size:13px; margin-top:10px;}

/* ---------------- 14:30 盘中预估（独立 preview.json） ----------------
   只用盘中现价代理收盘价，用来判断"今天收盘前要不要先卖避险腿"；
   与上面的正式操作区分：底色/左边框用琥珀色，正文小一号。 */
.preview{
  margin-top:14px; padding:12px 14px; border-radius:10px;
  background:rgba(255,196,0,.07); border-left:3px solid #ffc400;
  font-size:13.5px; line-height:1.7;
}
.pvhead{ color:#ffe6a8; }
.pvtag{
  display:inline-block; padding:1px 8px; border-radius:8px; margin-right:6px;
  background:rgba(255,196,0,.18); color:#ffd76a; font-size:12px; font-weight:700;
  transform:rotate(-1.2deg);
}
.pvbody{ margin-top:6px; color:var(--mut); }
.pvline{ color:#fbfdf8; }
.pvact{ color:var(--red); font-weight:700; margin-top:8px; }
.pvnote{ color:#9fd3a8; margin-top:8px; }
.pvfoot{ margin-top:8px; font-size:12.5px; color:var(--mut); opacity:.85; }

/* 收益曲线页的「末点是预估」提示（14:30 预估 / 盘中快照 / 分时兜底） */
.curvenote{
  margin:0 0 12px; padding:7px 12px; border-radius:8px;
  background:rgba(255,196,0,.07); border-left:3px solid #ffc400;
  font-size:12.5px; color:#ffe6a8; line-height:1.6;
}

/* ---------------- KPI ---------------- */
/* 6 张卡在宽屏上一行铺满；窄屏 3 列 / 2 列。
   下限取 150px：1024 宽下可用约 980px，170px 只能排 5 列会出现"孤儿卡"。 */
.kpis{ display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:18px; margin-bottom:24px;}
.kpi{
  position:relative; isolation:isolate;
  padding:20px 16px 18px;
  /* min-width:0 —— grid 轨道默认 min 是 min-content，长数字会把轨道顶出容器。 */
  min-width:0;
  background:rgba(255,255,255,.030);
  transition:translate .2s, background .2s;
  rotate:-.5deg;
}
.kpi:nth-child(even){ rotate:.5deg; }
.kpi:nth-child(3n){ rotate:-.25deg; }
.kpi:hover{ translate:0 -3px; background:rgba(255,255,255,.055); }
.kpi .l{ color:var(--mut); font-size:13px; margin-bottom:10px; letter-spacing:.4px; }
/* 数字等宽对齐；字号 23px 是实测反推的上限——
   最长值 "+31480.89%" 必须单行放进卡片内宽(~140px)，再加就会顶破 grid 轨道。 */
.kpi .v{
  font-size:23px; line-height:1.1; letter-spacing:-.01em;
  color:var(--txt);
  text-shadow:0 0 1px rgba(255,255,255,.35), 0 0 18px rgba(255,255,255,.10);
}
.kpi .v.up{color:var(--grn); text-shadow:0 0 2px rgba(110,231,168,.6), 0 0 20px var(--grn-glow);}
.kpi .v.dn{color:var(--red); text-shadow:0 0 2px rgba(255,122,133,.6), 0 0 20px var(--red-glow);}
.kpi .v.gold{color:var(--gold); text-shadow:0 0 2px rgba(255,209,102,.6), 0 0 22px var(--gold-glow);}

/* ---------------- panels ---------------- */
.grid{ display:grid; gap:22px; }
.page{ display:flex; flex-direction:column; gap:22px; }
.panel{
  position:relative; isolation:isolate;
  background:rgba(255,255,255,.022);
  padding:22px 24px;
  rotate:-.18deg;
}
.page > .panel:nth-child(even){ rotate:.22deg; }
.panel h2{
  font-size:15px; color:var(--cream); font-weight:600; margin-bottom:15px; letter-spacing:.4px;
  display:flex; justify-content:space-between; align-items:center; gap:10px; flex-wrap:wrap;
}
.chart{ width:100%; }
/* 手绘折线图的高度做成"随视口高度自适应"，而不是每个断点手打一个数字：
   曲线页是纵向最满的一页（面板 + 折线 + 一行 KPI），固定 320/348px 在
   1366×768 ~ 1920×1080 之间必然有一档放不下（实测 1440×900 差 47px）。
   下面的 618px 是"曲线页除图表以外的一切"：band-top(175) + 顶栏(68) + 两处
   gap(14+12) + 面板内非图表部分(107) + 页脚(12+19) + 与吧台的余量(约 24)，
   在 1440×900 上标定；改版时用 _probe_pages.py 重新标定即可。
   上限仍保留 372px（高视口下别把图画得太高），下限 198px（再矮就读不出形状）。 */
/* 618 -> 686：吧台高了约 75px，曲线页是纵向最满的一页（没有别的可压），
   这条常数就是曲线页除图表以外的一切，重新标定后各视口余量重新转正。 */
#eqChart{ height:clamp(180px, calc(100vh - 686px), 356px); }
#yearlyChart{ height:264px; }
canvas.skchart{ display:block; width:100%; height:100%; }

/* ---------------- 持仓条形 ---------------- */
.holdbars{ display:flex; flex-direction:column; gap:13px; }
.hrow{ display:grid; grid-template-columns:1fr auto; grid-template-rows:auto auto; gap:4px 12px; align-items:center; }
/* 手绘填充感：斜向排线（!important 是为了盖过 app.js 里写死的 background 颜色） */
.hbar{
  grid-row:1; grid-column:1/3; height:16px; border-radius:8px; opacity:.95;
  min-width:6px; transition:width .6s;
  box-shadow:inset 0 0 0 1.4px rgba(255,255,255,.22);
  background-image:repeating-linear-gradient(76deg, rgba(0,0,0,.32) 0 2px, rgba(0,0,0,0) 2px 5px) !important;
}
.hname{ grid-row:2; grid-column:1; color:var(--mut); font-size:13px; }
.hval{ grid-row:2; grid-column:2; font-size:14px; font-weight:600; }
.holdmeta{ color:var(--mut); font-size:12.5px; margin-top:15px; }

/* 逐年收益收起头 */
.yearhead{ display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:4px;}
.yearhead > span{ font-size:15px; color:var(--cream); font-weight:600; letter-spacing:.4px; }
#yearlyWrap{ margin-top:10px; }

/* ---------------- table ---------------- */
table{ width:100%; border-collapse:collapse; font-size:14px;}
th,td{ padding:9px 10px; text-align:left; border-bottom:1px dashed var(--line);}
th{
  color:var(--cream); font-weight:600; position:sticky; top:0;
  background:rgba(17,26,24,.97); backdrop-filter:blur(3px);
  border-bottom:1.4px solid var(--line2);
  /* z-index 必须有：单元格里的 .tag 带 transform:rotate(-1deg)，
     会创建自己的层叠上下文 —— 没有 z-index 的 sticky 表头会被它们盖住，
     滚动时"风险腿/黄金腿/买入/卖出"这些标签就从表头文字里穿过去（其他列是纯文本，不创建上下文，所以看不出问题）。 */
  z-index:3;
}
tr:hover td{ background:rgba(255,209,102,.06);}
.up{color:var(--grn);} .dn{color:var(--red);}
.tag{ padding:2px 9px; border-radius:9px; font-size:12.5px; display:inline-block; transform:rotate(-1deg); border:1.3px solid transparent;}
.tag.buy{background:rgba(110,231,168,.14);color:var(--grn);border-color:rgba(110,231,168,.5);}
.tag.sell{background:rgba(255,122,133,.14);color:var(--red);border-color:rgba(255,122,133,.5);}
.tag.risk{background:rgba(124,196,255,.14);color:var(--blu);border-color:rgba(124,196,255,.5);}
.tag.gold{background:rgba(255,209,102,.14);color:var(--gold);border-color:rgba(255,209,102,.5);}
.tag.act{background:rgba(255,122,133,.16);color:var(--red);border-color:rgba(255,122,133,.6);}
.tag.hum{background:rgba(110,231,168,.14);color:var(--grn);border-color:rgba(110,231,168,.5);}

.legend{ display:flex; gap:14px; flex-wrap:wrap; font-size:13px; color:var(--mut);}
/* 「当前持仓明细」标题后的持仓日期（app.js 的 renderHoldings 填） */
.holddate{ color:var(--mut); font-size:13px; font-weight:400; letter-spacing:0; }
/* 「标的实时状态」里源站尚未更新的标的（app.js 的 renderInstruments 填） */
.staletag{ color:var(--gold); font-size:12px; white-space:nowrap; }
.legend span i{ display:inline-block; width:11px;height:11px;border-radius:3px;margin-right:6px; transform:rotate(-4deg);}
.tblwrap{ max-height:430px; overflow:auto; border-radius:6px;}

.filters{ display:flex; gap:18px; flex-wrap:wrap;}
.filters button{
  position:relative; isolation:isolate;
  background:transparent; border:0; color:var(--mut); cursor:pointer;
  padding:7px 15px 8px; font-family:inherit; font-size:14px; letter-spacing:.3px;
  rotate:-.6deg; transition:color .15s, translate .15s;
}
.filters button:nth-child(even){ rotate:.7deg; }
.filters button:hover{ color:var(--cream); translate:0 -1px; }
.filters button.on{ color:var(--blu); font-weight:700; text-shadow:0 0 10px var(--blu-glow); }

/* ---------------- 按钮 ---------------- */
.btn{
  position:relative; isolation:isolate;
  background:transparent; border:0; color:var(--txt); cursor:pointer;
  padding:9px 18px 10px; font-family:inherit; font-size:14.5px;
}
.btn:hover{ color:var(--cream); }
.btn.primary{ color:var(--blu); font-weight:700; }
.btn.danger{ color:var(--red); }
.btn:disabled{ opacity:.45; cursor:default;}
.btn.mini{ padding:4px 13px 5px; font-size:13.5px;}

/* ---------------- 保险层 ---------------- */
.fusehead{display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-bottom:6px;}
.fusecards{display:grid; grid-template-columns:repeat(3,1fr); gap:18px; margin-top:12px;}
.fusecard{
  position:relative; isolation:isolate;
  background:rgba(200,162,255,.055); padding:15px 17px;
  rotate:.35deg;
}
.fusecard:nth-child(even){ rotate:-.4deg; }
.fusecard h3{font-size:15px; margin-bottom:8px; color:var(--purp);}
.fusecard .desc{color:var(--mut); font-size:13px; margin-bottom:10px; line-height:1.55;}
.fusecard .stats{display:grid; grid-template-columns:1fr 1fr; gap:6px 12px; font-size:13.5px;}
.fusecard .stats div{display:flex; justify-content:space-between; gap:8px;}
.fusecard .stats span{color:var(--mut);}
.fusecard .stats b{color:var(--txt);}
.fusecard .ok{color:var(--grn);} .fusecard .warn{color:var(--red);}
.fuseext{color:var(--mut); font-size:13px; line-height:1.6;}

/* ---------------- 账户 ---------------- */
.acctgrid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(160px,1fr)); gap:18px; margin-bottom:18px;}
.acctacts{ display:flex; gap:18px; flex-wrap:wrap; margin-top:6px;}
.accthead{ font-size:16px; color:var(--cream); margin-bottom:16px;}
.ded{ color:var(--mut); font-size:12.5px; font-weight:400;}
.authform.slim{ max-width:360px; margin-top:16px; }

/* ---------------- footer / toast ---------------- */
.footmeta{
  color:var(--mut); font-size:12.5px; margin-top:26px; text-align:center;
  line-height:1.65; opacity:.9;
}
.loading{ color:var(--mut); padding:30px; text-align:center;}
#toast{
  position:fixed; left:50%; bottom:92px; transform:translateX(-50%); z-index:99;
  background:rgba(17,26,24,.96); border:1.5px dashed var(--line2); color:var(--txt);
  padding:10px 20px; border-radius:14px; font-size:14px; box-shadow:var(--shadow);
  opacity:0; pointer-events:none; transition:opacity .25s;
}
#toast.show{ opacity:1; }

[hidden]{ display:none !important; }

/* ================================================================
   断点
   ================================================================ */
/* 视口收窄时黑板的外扩必须跟着收，否则左右各 30px 的负 inset 会撑出横向滚动条。 */
@media(max-width:1290px){ :root{ --board-pad: 18px; } }
@media(max-width:1250px){ :root{ --board-pad: 0px; } }

/* 中屏收口：让 6 张 KPI 卡尽量保持"一行 6 张"，
   一旦折成两行内容高度多吃近 110px，矮视口下会顶到前景吧台。 */
@media(max-width:1150px){
  .kpi .v{ font-size:20px; }
}
@media(max-width:1000px){
  .kpis{ grid-template-columns:repeat(3,1fr); }
  /* 平板竖屏 / 窄桌面：宽度不足以让"内容 + 前景吧台"同时站住，只关掉吧台。 */
  .tavern{ display:none; }
  .barmaid{ display:none; }
  :root{ --pad-bottom:120px; }
}

@media(max-width:760px){
  /* 手机断点：关掉房间里的空间场景，只保留"内容在一整块黑板上"的观感。
     导航此时折到标题下面一行，所以 band-top 要留够两行的高度。 */
  :root{ --band-top:clamp(122px,16vh,158px); --pad-bottom:96px; }
  /* minmax(0,1fr)：grid 的 1fr 默认是 minmax(auto,1fr)，不会收缩到内容最小宽度以下，
     大数字会把轨道撑出容器造成横向溢出。 */
  .kpis{grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px;}
  .kpi{padding:15px 13px 14px;}
  .kpi .l{margin-bottom:7px;}
  .kpi .v{font-size:22px;}
  h1{font-size:20px;}
  .top__row{ gap:8px; }
  .tabs{ width:100%; gap:14px; overflow-x:auto; padding-bottom:2px; }
  .tabs button{ padding:7px 12px 9px; font-size:14px; }
  .action{padding:19px 17px;}
  .action .txt{font-size:15.5px;}
  .panel{padding:18px 17px;}
  .panel{ rotate:0deg; } .kpi, .kpi:nth-child(even), .kpi:nth-child(3n){ rotate:0deg; }
  .action{ rotate:0deg; }
  .fusecards{grid-template-columns:1fr;}
  .wrap{ padding:var(--band-top) 14px var(--pad-bottom); }
  .tavern{ display:none; }
  .barmaid{ display:none; }
  .shade{ display:none; }          /* 窄屏上压暗会吃掉可读性 */
  .lamp-hint{ display:none; }      /* 手机端无拖拽场景，别占地方 */
  .beam2d{ opacity:.5; }
}
/* 超窄屏（小手机）：数字再降一档，并给极端长数字兜底，杜绝横向滚动 */
@media(max-width:430px){
  .kpi .v{font-size:20px; overflow-wrap:anywhere;}
  .kpi{padding:13px 11px 12px;}
  .kpis{gap:16px;}
}

/* ---------------- 按视口高度收口 ----------------
   目标是让"最后一行内容"始终落在吧台之上（首屏不被台面压住）。
   垂直方向只有两个旋钮：--band-top（天花板带）与 #eqChart 的高度。
   这两个已经调过一轮（见文件顶部纵向预算的实测记录），下面三段只负责
   把段距/内距收紧，别再回头给 #eqChart 写固定高度 —— 那会盖掉自适应规则，
   1366×768 与 1920×1080 之间必然有一档放不下。 */
@media(max-height:1120px){
  .page{ gap:18px; }
  .kpis{ margin-bottom:18px; }
  .kpi{ padding:17px 15px 15px; }
  .panel{ padding:19px 21px; }
  .footmeta{ margin-top:18px; }
}
@media(max-height:940px){
  .page{ gap:18px; }
  header.top{ margin-bottom:14px; }
  .action{ margin-bottom:16px; padding:17px 21px; }
  .action .txt{ font-size:16px; line-height:1.5; }
  .action .sub{ margin-top:7px; }
  .kpis{ gap:18px; margin-bottom:16px; }
  .kpi{ padding:14px 14px 13px; }
  .kpi .l{ margin-bottom:6px; }
  /* panel 的 padding 同时就是"panel 框线 ↔ 内部卡片框线"的净距（两边各内缩 6px，
     所以 padding 值直接等于净距）。低于 18px 时两条粉笔线会贴住/交错 —— 见文件里
     ".tabs" 上方那段手绘框硬约束的说明。 */
  .panel{ padding:18px 20px; }
  .panel h2{ margin-bottom:9px; }
  .footmeta{ margin-top:12px; font-size:12px; line-height:1.55; }
}
@media(max-height:880px){
  .page{ gap:18px; }
  header.top{ margin-bottom:9px; }
  /* 段距全部交给 .page 的 gap 控制，子元素 margin 归零，避免叠加 */
  .action{ margin-bottom:0; padding:12px 17px; }
  .action .txt{ font-size:15px; }
  .action .sub{ margin-top:5px; }
  .kpis{ gap:18px; margin-bottom:0; }
  .kpi{ padding:10px 12px 9px; }
  .kpi .l{ margin-bottom:5px; }
  .panel{ padding:18px 18px; }
  .panel h2{ margin-bottom:6px; }
  .holdbars{ gap:8px; }
  .holdmeta{ margin-top:9px; }
  .footmeta{ margin-top:6px; }
  /* 1366x768 / 1280x800 这一档，"F17·保险"页是全站最满的一页（没有折线图可压），
     只能靠收紧卡片内距把 44px / 23px 的缺口补回来。 */
  .fusehead{ margin-bottom:4px; }
  .fusecards{ gap:18px; margin-top:9px; }
  .fusecard{ padding:11px 14px; }
  .fusecard h3{ margin-bottom:6px; }
  .fusecard .desc{ margin-bottom:7px; font-size:12.5px; }
}
/* 极矮视口：吧台已经挤不下（会压住内容），直接关掉，与手机端同策略 */
@media(max-height:640px){
  .tavern{ display:none; }
  .barmaid{ display:none; }
  :root{ --pad-bottom:96px; }
}

/* ---------------- 无障碍：尊重"减少动效" ---------------- */
@media (prefers-reduced-motion: reduce){
  .wipe, .wipe--in, .wipe--out{ animation:none !important; visibility:hidden !important; }
  #mainView.is-erasing > .page:not([hidden]){ animation:none !important; -webkit-mask-image:none; mask-image:none; }
  .write-in{ animation:none !important; }
  *{ transition-duration:.01ms !important; }
}
