* { margin: 0; padding: 0; box-sizing: border-box; }
  body { font-family: "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", sans-serif; background: #f3f4f6; color: #1f2937; min-height: 100vh; }
  button { font-family: inherit; cursor: pointer; }
  .hide { display: none !important; }

  /* ---------- 顶栏（展示版只保留：刷新 / 视角 / 全屏） ---------- */
  header { position: sticky; top: 0; z-index: 20; background: #fff; border-bottom: 1px solid #e5e7eb; padding: 10px 16px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
  header h1 { font-size: 18px; letter-spacing: 1px; white-space: nowrap; }
  header .cls { font-size: 13px; color: #6b7280; }
  .spacer { flex: 1; }
  .btn { padding: 8px 14px; border-radius: 8px; border: 1px solid #c7d2fe; background: #eef2ff; color: #4f46e5; font-size: 13.5px; }
  .btn.plain { background: #fff; border-color: #e5e7eb; color: #374151; }
  .btn:active { transform: scale(.97); }
  .btn[disabled] { opacity: .45; cursor: not-allowed; }

  /* 提示条（加载失败等） */
  .note { max-width: 1180px; margin: 12px auto 0; padding: 10px 16px; display: none; border-radius: 10px; font-size: 13.5px; align-items: center; gap: 10px; }
  /* Y26 修复：红框默认必须隐藏（此前写死 display:flex 导致常驻"重试"条）；只在 showErr 时显示 */
  .note.err { background: #fef2f2; border: 1px solid #fca5a5; color: #b91c1c; }

  /* 请假摘要行 */
  .leaveline { max-width: 1180px; margin: 12px auto 0; padding: 0 16px; font-size: 13.5px; color: #6b7280; }
  .leaveline b { color: #b45309; }

  /* ---------- 教室座位图（与座位表编辑器/每日点评同一套布局语言） ---------- */
  .queue { max-width: 1180px; margin: 12px auto 0; padding: 0 16px 40px; }
  .room { display: flex; width: 100%; background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 12px; }
  .vside { width: 30px; flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 60px; }
  .vside .mk { writing-mode: vertical-lr; letter-spacing: 5px; font-size: 12px; color: #9ca3af; background: #f9fafb; border: 1px solid #f3f4f6; border-radius: 6px; padding: 9px 4px; }
  .main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
  .bb { background: #1f2937; color: #fff; text-align: center; padding: 9px; border-radius: 6px; letter-spacing: 8px; font-size: 14px; }
  .frontstrip { display: flex; gap: 6px; align-items: stretch; margin: 2px 0; }
  .podium { flex: 1; background: #e5e7eb; color: #374151; text-align: center; padding: 8px; border-radius: 6px; letter-spacing: 6px; font-size: 13px; }
  .bhead { display: flex; gap: 6px; margin-top: 3px; }
  .bh { text-align: center; font-size: 12.5px; color: #6b7280; letter-spacing: 2px; padding: 2px 0; overflow: hidden; white-space: nowrap; }
  .srow { display: flex; gap: 6px; align-items: stretch; }   /* Y90f：排距回 6px——组框各退 1px 后组间有 2px 白隙 */
  .srow.gcut { margin-top: 9px; }   /* Y90f：组与组之间的间隙（组界排）——组框自动跟随 */
  .rowno { width: 34px; flex: none; font-size: 11px; color: #9ca3af; display: flex; align-items: center; justify-content: center; }
  .blk { display: flex; gap: 5px; min-width: 0; }
  .ais { width: 12px; flex: none; }
  .rseat { flex: 1; min-width: 0; min-height: 52px; display: flex; align-items: center; justify-content: center; font-size: 13px; position: relative; user-select: none; }   /* Y90d：字号 14→13、高 54→52 */
  /* Y89 P2：三样式（课桌线/表格线/圆角卡片）下线，统一采用皮肤预览页的卡片样式：
     白卡 + 圆角 + 小组色左边条（--gc）；组色另由组框（.gfl）承担。类名沿用 desk 以保持既有旋转补偿链。 */
  #queue .rseat { border: 1px solid #eaedf3; background: #fff; border-radius: 10px;
    box-shadow: 0 2px 7px rgba(31, 42, 68, .09); }   /* Y89 P2c：去小组色左边带（组框已有颜色），改淡阴影 */
  #queue .rseat:hover { box-shadow: 0 5px 12px rgba(31, 42, 68, .12); }
  .rseat.empty { background: #fafbfd; color: #d1d5db; font-size: 11px; border: 1px dashed #e8ecf3; box-shadow: none; }
  .rseat .sx { position: absolute; top: 2px; right: 4px; font-size: 10px; font-weight: 700; line-height: 1.4; z-index: 2; }
  .rseat .sx.m { color: #3b82f6; } .rseat .sx.f { color: #ec4899; }
  .rseat .nm { position: relative; z-index: 1; }
  .rseat .nm.wk { color: #dc2626; font-weight: 600; }
  .rseat .mks { position: absolute; right: 3px; bottom: 2px; display: flex; gap: 2px; align-items: center; z-index: 2; }
  .rseat .mks i { font-style: normal; font-size: 7.5px; line-height: 1.5; color: #fff; border-radius: 3px; padding: 0 2px; font-weight: 700; }   /* Y90d：9.5→7.5（老师：很小的提醒就够） */
  /* 请假：明度/饱和度双降 + 左下角「请假」角标 */
  .rseat.leave { filter: brightness(.72) saturate(.5); }
  .rseat.leave::after { content: "请假"; position: absolute; bottom: 2px; left: 4px; font-size: 9.5px; line-height: 1.5; color: #fff; background: #f59e0b; border-radius: 3px; padding: 0 3px; font-weight: 700; z-index: 2; }
  /* 课桌线模式：请假更醒目——名字淡黄底；「请假」章与下划线是同一伪元素，
     必须显式补回 content 并重置线的几何（左右拉伸/高3px/z0），否则章被清空压扁 */
  #queue .rseat.leave::after { content: "假"; white-space: nowrap; height: auto; width: auto; left: 6px; right: auto; bottom: 3px; font-size: 8.5px; line-height: 1.5; padding: 0 4px; border-radius: 4px; background: #d97706; color: #fff; font-weight: 700; z-index: 2; }
  /* 课桌线：请假章随视角换位（屏幕上恒在左下、垫在内容之下不被遮）；a90/a270 规则随竖排下线暂不生效 */
  #queue .a180 .rseat.leave::after { top: 3px; bottom: auto; left: auto; right: 6px; transform: rotate(-180deg); }
  #queue.desk .a90 .rseat.leave::after { top: auto; bottom: 12px; left: auto; right: 4px; transform: rotate(-90deg); }
  #queue.desk .a270 .rseat.leave::after { top: auto; bottom: 12px; left: 4px; right: auto; transform: rotate(90deg); }
  /* 卡片/表格线模式：同样按角度把章换到屏幕左下 */
  .a90 .rseat.leave::after { left: auto; right: 4px; transform: rotate(-90deg); }
  .a180 .rseat.leave::after { top: 12px; bottom: auto; left: auto; right: 4px; transform: rotate(-180deg); }
  .a270 .rseat.leave::after { top: 12px; bottom: auto; transform: rotate(90deg); }
  #queue .rseat.leave .nm { background: #fef3c7; border-radius: 6px; padding: 0 4px; }

  /* 名单兜底（该班尚未上传座位数据） */
  .namegrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 6px; }
  .namegrid .ncard { background: #fff; border: 1px solid #e5e7eb; border-radius: 6px; min-height: 44px; display: flex; align-items: center; justify-content: center; font-size: 13.5px; position: relative; }
  .namegrid .ncard.leave { filter: brightness(.72) saturate(.5); }
  .namegrid .ncard.leave::after { content: "假"; position: absolute; bottom: 1px; left: 3px; font-size: 9px; color: #fff; background: #f59e0b; border-radius: 3px; padding: 0 2px; font-weight: 700; }

  .unote { max-width: 1180px; margin: 10px auto 0; padding: 0 16px 40px; font-size: 12.5px; color: #9ca3af; line-height: 1.9; }
  .dedline { max-width: 1180px; margin: 6px auto 0; padding: 0 16px; font-size: 13.5px; color: #6b7280; }
  .dedline b { color: #b91c1c; }

  /* ---------- 学生只读信息卡（仅查看，无任何操作按钮） ---------- */
  #queue .rseat[data-sid] { cursor: pointer; }
  .rdmask { position: fixed; inset: 0; background: rgba(17,24,39,.45); z-index: 40; display: none; }
  .rdmask.show { display: block; }
  .rdlg { position: fixed; z-index: 41; top: 50%; left: 50%; transform: translate(-50%,-50%); width: min(430px, 92vw); max-height: 86vh; overflow-y: auto; background: #fff; border-radius: 14px; padding: 18px 20px; display: none; }
  .rdlg.show { display: block; }
  /* Y97b 背包打开时锁滚动：.bagPane 绝对定位钉在可视区（不被内容滚动带走），关闭时 JS 还原滚动位 */
  .rdlg.bag-on { overflow: hidden; }
  .rdlg .rdx { position: absolute; top: 10px; right: 12px; border: none; background: none; font-size: 20px; color: #9ca3af; }
  .rdlg h2 { font-size: 17px; margin-bottom: 2px; }
  .rdlg .rsub { font-size: 12.5px; color: #6b7280; margin-bottom: 10px; line-height: 1.7; }
  .rdRow { display: flex; gap: 8px; align-items: flex-start; border-bottom: 1px solid #f3f4f6; padding: 6px 2px; font-size: 13px; }
  .rdRow .dt { flex: none; color: #9ca3af; font-size: 11.5px; width: 70px; padding-top: 1px; }
  .rdRow .fp { flex: none; font-weight: 700; width: 36px; }
  .rdRow .fp.p { color: #16a34a; } .rdRow .fp.n { color: #dc2626; } .rdRow .fp.l { color: #d97706; }
  .rdRow .gtag { flex: none; font-style: normal; font-size: 10px; color: #fff; border-radius: 3px; padding: 1px 5px; margin-top: 1px; font-weight: 700; height: fit-content; }
  .rdRow .gtag.g { background: #6366f1; }   /* 组连坐（蓝）——与 dp 点评页 .gt 同色 */
  .rdRow .gtag.d { background: #0d9488; }   /* 寝室连坐（青）——与 dp 点评页 .gt2 同色 */
  .rdRow .fi { flex: 1; line-height: 1.5; }
  .rdlg .rhint { font-size: 12px; color: #9ca3af; margin-top: 10px; }

  /* 四维分数汇总（今日/一周/两周/累计） */
  .rdSum { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-bottom: 12px; }
  .rdSum div { background: #f9fafb; border: 1px solid #f3f4f6; border-radius: 8px; padding: 7px 2px; text-align: center; }
  .rdSum b { display: block; font-size: 16px; color: #4f46e5; }
  .rdSum b.neg { color: #dc2626; }
  .rdSum span { font-size: 10.5px; color: #9ca3af; }

  /* ---------- 积分排名弹窗（今日/一周/两周/累计） ---------- */
  .rktabs { display: flex; gap: 6px; margin: 12px 0 8px; }
  .rktabs button { flex: 1; padding: 7px 0; border: 1px solid #e5e7eb; background: #fff; border-radius: 8px; font-size: 13px; color: #374151; }
  .rktabs button.on { background: #4f46e5; color: #fff; border-color: #4f46e5; font-weight: 700; }
  .rkRow { display: flex; align-items: center; gap: 10px; border-bottom: 1px solid #f3f4f6; padding: 7px 4px; font-size: 13.5px; }
  .rkRow .no { width: 26px; text-align: center; color: #9ca3af; font-weight: 700; }
  .rkRow .no.top { color: #f59e0b; }
  .rkRow .nm { flex: 1; }
  .rkRow .sc { font-weight: 800; color: #4f46e5; }
  .rkRow .sc.neg { color: #dc2626; }
  .rkmode { display: flex; gap: 6px; margin-bottom: 8px; }
  .rkmode button { flex: 1; padding: 8px 0; border: none; background: #f3f4f6; border-radius: 8px; font-size: 13.5px; color: #374151; font-weight: 700; }
  .rkmode button.on { background: #4f46e5; color: #fff; }

  /* ---------- 视角旋转（与每日点评同一套：基底渲染一次 + 容器 transform + 文字反向补偿。
     不做过渡动画（Y21：切换直接到位，避免刷新/操作时转圈） ---------- */
  .rotstage { position: relative; }
  .rotwrap { position: relative; transform-origin: top left; }
  .rotwrap .bb .bt, .rotwrap .podium .bt, .rotwrap .bh .bt, .rotwrap .rowno .rt, .rotwrap .rseat .et { display: inline-block; }
  .a90 .vside .mk, .a270 .vside .mk { writing-mode: horizontal-tb; background: none; border: none; padding: 0; }
  .a90 .vside .mk .bt, .a270 .vside .mk .bt { display: inline-block; transform: rotate(-90deg); white-space: nowrap; }
  .a180 .vside .mk .bt { display: inline-block; transform: rotate(-180deg); }
  .a90 .rseat .gb, .a90 .rseat .sx, .a90 .rseat .nm, .a90 .rseat .mks, .a90 .rseat .et,
  .a90 .bb .bt, .a90 .podium .bt, .a90 .bh .bt, .a90 .rowno .rt { transform: rotate(-90deg); }
  .a180 .rseat .gb, .a180 .rseat .sx, .a180 .rseat .nm, .a180 .rseat .mks, .a180 .rseat .et,
  .a180 .bb .bt, .a180 .podium .bt, .a180 .bh .bt, .a180 .rowno .rt { transform: rotate(-180deg); }
  .a270 .rseat .gb, .a270 .rseat .sx, .a270 .rseat .nm, .a270 .rseat .mks, .a270 .rseat .et,
  .a270 .bb .bt, .a270 .podium .bt, .a270 .bh .bt, .a270 .rowno .rt { transform: rotate(90deg); }
  .a90 .rseat .gb { top: auto; bottom: 2px; }
  .a90 .rseat .sx { right: auto; left: 4px; }
  .a90 .rseat .mks { bottom: auto; top: 2px; }
  .a180 .rseat .gb { top: auto; bottom: 2px; left: auto; right: 4px; }
  .a180 .rseat .sx { top: auto; bottom: 2px; right: auto; left: 4px; }
  .a180 .rseat .mks { bottom: auto; top: 2px; right: auto; left: 3px; }
  .a270 .rseat .gb { left: auto; right: 4px; }
  .a270 .rseat .sx { top: auto; bottom: 2px; }
  .a270 .rseat .mks { right: auto; left: 3px; }
  .a90 .rseat.leave::after { left: auto; right: 4px; transform: rotate(-90deg); }
  .a180 .rseat.leave::after { top: 2px; bottom: auto; left: auto; right: 4px; transform: rotate(-180deg); }
  .a270 .rseat.leave::after { top: 2px; bottom: auto; transform: rotate(90deg); }

  @media (max-width: 760px) {
    header h1 { font-size: 16px; }
    .queue { padding: 0 10px 40px; }
    .leaveline { padding: 0 10px; }
    .unote { padding: 0 10px 40px; }
    .room { padding: 8px; }
    .srow { gap: 3px; } .blk { gap: 3px; } .ais { width: 7px; } .vside { width: 20px; }
    .vside .mk { font-size: 10px; letter-spacing: 3px; padding: 6px 3px; }
    .bb { font-size: 11px; letter-spacing: 4px; padding: 6px; }
    .podium { font-size: 11px; letter-spacing: 4px; padding: 6px; }
    .bh { font-size: 10px; letter-spacing: 1px; }
    .rowno { width: 20px; font-size: 9px; }
    .rseat { font-size: 10.5px; min-height: 44px; }
    .rseat .nm { white-space: normal; word-break: break-all; line-height: 1.15; padding: 0 1px; }
    .rseat .gb { font-size: 8px; padding: 0 2px; }
    .rseat .sx { font-size: 8px; right: 2px; }
    .rseat .mks { right: 2px; bottom: 1px; gap: 1px; }
    .rseat .mks i { font-size: 7px; padding: 0 1.5px; }
    .rseat.leave::after { font-size: 8px; padding: 0 2px; }
  }

  /* ---------- 留言板入口（Y39 v2.0：独立留言页 ly.html）----------
     座位表只保留顶栏按钮 + 红点（未确认数）；列表/确认/回复/学生留言全部在 ly.html。
     红点语义 Y39 起改为"未确认条数"（/api/msg/count 的 unconfirmed），确认过的不再提醒 */
  .mbdot { display: inline-block; margin-left: 5px; min-width: 18px; padding: 0 5px; border-radius: 9px; background: #ef4444; color: #fff; font-size: 11px; line-height: 18px; text-align: center; font-weight: 700; vertical-align: middle; }

/* ===== Y89 P2d 同组合并 —— **Y90b 已下线（10-11 老师终版口径：组内保持个体卡+缝隙）** =====
   组框 5% 填充透过缝隙显色才是老师说的"组内彩色分割线"，已随组框去填充根治；
   合并函数 applySeatJoins 已空转，下列规则永不命中，留档防误删（恢复合并时整段启用）。 */
#queue .rseat.infr { border: none; background: #fff; border-radius: 0; box-shadow: none; }
#queue .rseat.infr.rt-tl { border-top-left-radius: 10px; }
#queue .rseat.infr.rt-tr { border-top-right-radius: 10px; }
#queue .rseat.infr.rt-bl { border-bottom-left-radius: 10px; }
#queue .rseat.infr.rt-br { border-bottom-right-radius: 10px; }
/* 组块整体投影（画在 SVG 轮廓上——去填充后跟随描边轮廓，组块仍有柔和浮起感） */
#queue .gfl .gcomp svg { filter: drop-shadow(0 3px 8px rgba(31, 42, 68, .16)); }

/* ===== Y89 P1b 小组框 + 组长星（2026-10-11） =====
   组身份 = 组框（矩形块容器）+ 单标签；每卡组徽章 .gb 已下线（消除 63 处重复标签）。
   堆叠：.gfl 不加 z-index（不进堆叠上下文）→ 框背景/描边在卡片下层（DOM 靠前）；
        标签 z-index:3 → 在卡片上层（卡片为 z-auto）；皮肤挂章 z-index:4 仍在标签之上。
   视角补偿只做现行 0°/180°（90°/270° 已下线；恢复竖排时参照 .gb 的补偿补两行即可）。 */
.gfl { position: absolute; inset: 0; pointer-events: none; z-index: 1; }   /* Y90i：提一层——skin-layer.css 加的 #queue .room{position:relative}（公共皮肤背景挂点）让 room 整体画到 gfl 之上，组框彩线全被盖住（层级压制无报错，第二次踩同类坑） */
.gcomp { position: absolute; }
.gsvg { position: absolute; left: 0; top: 0; pointer-events: none; overflow: visible; }
.gfl .gfl-label { position: absolute; top: -10px; left: 12px; z-index: 3; font-size: 11px; font-weight: 800;   /* Y90m：照预览页对齐——全圆角小胶囊，更精致 */
  color: #fff; border-radius: 999px; padding: 1px 10px; line-height: 1.55; white-space: nowrap;
  box-shadow: 0 2px 6px rgba(31, 42, 68, .18); }
.a180 .gfl .gfl-label { top: auto; bottom: -10px; left: auto; right: 12px; transform: rotate(-180deg); }
.rseat .ld { position: absolute; top: 2px; left: 4px; z-index: 2; font-size: 7px; font-weight: 800; line-height: 1.5;   /* Y90d：8→7 */
  color: #5b4200; background: linear-gradient(135deg, #f7e7a3, #ffe9a8 55%, #f7e7a3);
  border: 1px solid #d4af37; border-radius: 5px; padding: 0 3px; }
  .a180 .rseat .ld { top: auto; bottom: 2px; left: auto; right: 4px; transform: rotate(-180deg); }

  /* ---------- Y97b 背包：详情页头部按钮 + 右滑子页面（手机兑换券） ----------
     老师口径：详情页页眉放「🎒 背包」按钮，点一下往右滑进入另一个小页面（覆盖式 slide，非弹窗）。
     全部走 transform+transition（250ms）——白板低端机也流畅，不用动画库。
     结构约束：#rdlg 保持扁平（skin-layer.openCard 以 .rhint 为锚挂皮肤柜，不能加内容包裹层），
     子页绝对定位覆盖右侧 85%，主内容不动。
     视角说明：#rdlg 不随 0/180° 视角旋转（旋转只作用于 #queue 的 rotwrap），子页面任何视角下都正向可读。 */
  .rdHead { display: flex; align-items: flex-start; gap: 10px; padding-right: 24px; }   /* 右侧留空避让 ✕ */
  .rdHead h2 { flex: 1; min-width: 0; }
  .rdbag { flex: none; margin-top: 3px; border: 1px solid #f59e0b; border-radius: 999px; padding: 6px 13px;
    background: linear-gradient(135deg, #fcd34d, #f59e0b); color: #fff; font-size: 13px; font-weight: 800; letter-spacing: .5px;
    box-shadow: 0 3px 9px rgba(245, 158, 11, .38); }
  .rdbag:active { transform: scale(.96); }
  /* 子页从右滑入（覆盖右侧 85%；102% 连同左侧投影一起滑出视口，.rdlg overflow 裁切） */
  .bagPane { position: absolute; top: 0; bottom: 0; right: 0; width: 85%; z-index: 5;
    display: flex; flex-direction: column; background: #fff; border: 1px solid #f0e6d2; border-radius: 12px;
    box-shadow: -8px 0 22px rgba(17, 24, 39, .16);
    transform: translateX(102%); transition: transform .25s ease; }
  .rdlg.bag-on .bagPane { transform: translateX(0); }
  .bagHead { flex: none; display: flex; align-items: center; gap: 8px; padding: 10px 30px 10px 12px; border-bottom: 1px solid #f3efe3; }
  .bagBack { flex: none; border: 1px solid #e5e7eb; background: #fff; color: #374151; border-radius: 8px; padding: 5px 10px; font-size: 13px; font-weight: 700; }
  .bagBack:active { transform: scale(.96); }
  .bagTt { font-size: 13.5px; font-weight: 700; color: #92400e; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bagBody { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 12px; }
  /* 券卡片：🎟️ 图标 + 券名 + 持有大数字 + 使用说明（Y98 多券种：types 每券种一张卡，纵向堆叠） */
  .bagVou { display: flex; align-items: center; gap: 10px; border: 1px solid #f0d9a8; border-radius: 12px; padding: 10px 12px;
    background: linear-gradient(135deg, #fffbeb, #fef3c7); }
  .bagVou + .bagVou { margin-top: 8px; }
  .bagVou.none { opacity: .55; filter: saturate(.55); border-style: dashed; }   /* 没持有的券种：0 张弱化展示 */
  .bagVou .bvIco { flex: none; font-size: 26px; line-height: 1; }
  .bagVou .bvInfo { flex: 1; min-width: 0; }
  .bagVou .bvName { font-size: 14.5px; font-weight: 800; color: #78350f; }
  .bagVou .bvNote { font-size: 11.5px; color: #a16207; line-height: 1.5; margin-top: 2px; }
  .bagVou .bvN { flex: none; text-align: center; background: #fff; border: 1px solid #f0d9a8; border-radius: 10px; padding: 6px 10px; }
  .bagVou .bvN b { display: block; font-size: 22px; font-weight: 800; color: #b45309; line-height: 1.15; }
  .bagVou .bvN span { font-size: 10px; color: #a16207; }
  /* Y100 券有效期行：exp 实算「最早 X 天后过期」（exp 缺席回退 publicCfg「有效期 N 天」），持有>0 才显示 */
  .bagVou .bvN .bvExp { display: block; margin-top: 2px; white-space: nowrap; color: #b45309; }
  /* Y100 皮肤券「✨ 使用」激活按钮（紫色系与券卡琥珀区分；0 张 disabled 灰化） */
  .bagVou .bvAct { flex: none; border: 1px solid #7c3aed; background: linear-gradient(135deg, #c4b5fd, #8b5cf6);
    color: #fff; border-radius: 999px; padding: 7px 12px; font-size: 12.5px; font-weight: 800; letter-spacing: .5px;
    box-shadow: 0 2px 7px rgba(124, 58, 237, .35); }
  .bagVou .bvAct:active { transform: scale(.95); }
  .bagVou .bvAct:disabled { opacity: .45; box-shadow: none; filter: grayscale(.5); cursor: not-allowed; }
  /* 最近记录（沿用 rdRow 的排版语言：左时间 + 中标签 + 右说明） */
  .bagSec { font-size: 12px; font-weight: 800; color: #6b7280; margin: 12px 2px 4px; }
  .bagRow { display: flex; gap: 8px; align-items: flex-start; border-bottom: 1px solid #f3f4f6; padding: 6px 2px; font-size: 12.5px; }
  .bagRow .vi { flex: none; width: 18px; text-align: center; padding-top: 1px; }   /* Y98：券种图标（跨券种合并台账区分用） */
  .bagRow .dt { flex: none; color: #9ca3af; font-size: 11px; width: 78px; padding-top: 1px; }
  .bagRow .tag { flex: none; font-weight: 700; font-size: 11px; border-radius: 4px; padding: 0 5px; line-height: 1.6; }
  .bagRow .tag.tg-in { color: #15803d; background: #f0fdf4; border: 1px solid #bbf7d0; }
  .bagRow .tag.tg-use { color: #b45309; background: #fffbeb; border: 1px solid #fde68a; }
  .bagRow .fi { flex: 1; line-height: 1.55; }
  .bagRow .fi .why { color: #9ca3af; }
  /* 加载 / 失败 / 空态 */
  .bagLoad { font-size: 13px; color: #6b7280; text-align: center; padding: 26px 10px; line-height: 1.8; }
  .bagErr { font-size: 13px; color: #b91c1c; text-align: center; padding: 24px 10px; line-height: 1.9; }
  .bagRetry { margin-top: 8px; border: 1px solid #fca5a5; background: #fef2f2; color: #b91c1c; border-radius: 8px; padding: 6px 16px; font-size: 13px; font-weight: 700; }
  .bagEmpty { text-align: center; color: #6b7280; font-size: 13px; line-height: 1.9; padding: 30px 8px; }
  .bagEmpty span { display: block; font-size: 34px; margin-bottom: 6px; opacity: .45; }
  /* Y100 顶部小提示（激活成功"已激活"）：背包头部下方滑入，2s 后 JS 摘 .show 淡出 */
  .bagToast { position: absolute; top: 48px; left: 50%; z-index: 6; transform: translate(-50%, -8px);
    opacity: 0; pointer-events: none; background: #16a34a; color: #fff; font-size: 13px; font-weight: 800;
    border-radius: 999px; padding: 6px 16px; box-shadow: 0 4px 14px rgba(22, 163, 74, .4);
    transition: opacity .25s ease, transform .25s ease; }
  .bagToast.show { opacity: 1; transform: translate(-50%, 0); }
  @media (prefers-reduced-motion: reduce) { .bagPane, .bagToast { transition: none; } }

  /* ---------- Y99 天气：顶栏徽章 + 预报弹窗（Open-Meteo 免key，断网走缓存） ----------
     徽章常显「emoji 温度·短提醒」，点开弹窗看三天预报；无数据整枚隐藏（不留死按钮）。
     天气与班级无关（全校同址），缓存键 seatShow.weather 各班共用。 */
  .btn.wxchip { padding: 7px 11px; font-size: 13px; color: #0284c7; border-color: #bae6fd; background: #f0f9ff; white-space: nowrap; }
  .btn.wxchip:active { transform: scale(.97); }
  .wxLoad { font-size: 13px; color: #6b7280; text-align: center; padding: 30px 10px; line-height: 1.9; }
  /* 当前天气行：大温度 + 描述 + 体征数据 */
  .wxNow { display: flex; align-items: center; gap: 12px; margin: 6px 0 4px; }
  .wxNow .we { font-size: 42px; line-height: 1; }
  .wxNow .wt { font-size: 40px; font-weight: 800; letter-spacing: -1px; line-height: 1; }
  .wxNow .wm { flex: 1; min-width: 0; }
  .wxNow .wm b { font-size: 16px; display: block; }
  .wxNow .wm span { font-size: 12px; color: #6b7280; display: block; line-height: 1.6; }
  .wxNow .wd { flex: none; text-align: right; font-size: 13.5px; font-weight: 700; color: #0284c7; white-space: nowrap; }
  .wxNow .wd span { display: block; font-size: 11px; color: #9ca3af; font-weight: 400; }
  /* 三天预报：概览格子（Y99b 改为后两天两列——今天/明天由时段条承担） */
  .wxDays { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; margin: 12px 0 10px; }
  .wxDays .dd { background: #f9fafb; border: 1px solid #f3f4f6; border-radius: 10px; padding: 8px 2px 7px; text-align: center; min-width: 0; }
  .wxDays .dd .dn { font-size: 12px; color: #6b7280; }
  .wxDays .dd .de { font-size: 23px; line-height: 1.4; }
  .wxDays .dd .dt2 { font-size: 11.5px; color: #6b7280; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .wxDays .dd .dt2 b { color: #e11d48; font-weight: 700; margin-left: 2px; }   /* 降水概率≥50%标红 */
  .wxDays .dd .dp { font-size: 14px; font-weight: 700; }
  .wxDays .dd .dp span { font-weight: 400; color: #9ca3af; font-size: 11.5px; }
  /* 穿衣/带伞提醒条 */
  .wxTip { background: #f0f9ff; border: 1px solid #bae6fd; color: #075985; border-radius: 10px; padding: 6px 12px; font-size: 13.5px; line-height: 1.7; }
  /* Y99b 3小时时段条：全天6段（6-24点），今天已过置灰、当前段高亮 */
  .wxSec { font-size: 12.5px; font-weight: 700; color: #6b7280; margin: 12px 2px 6px; }
  .wxStrip { display: grid; grid-template-columns: repeat(6, 1fr); gap: 4px; }
  .wxStrip .bk { background: #f9fafb; border: 1px solid #f3f4f6; border-radius: 9px; padding: 6px 1px 5px; text-align: center; min-width: 0; }
  .wxStrip .bk .bn { font-size: 10px; color: #9ca3af; white-space: nowrap; }
  .wxStrip .bk .be { font-size: 18px; line-height: 1.45; }
  .wxStrip .bk .bt3 { font-size: 12.5px; font-weight: 700; white-space: nowrap; }
  .wxStrip .bk .bt3 b { color: #e11d48; font-weight: 700; margin-left: 1px; font-size: 10px; }   /* 时段降水概率≥30%标红 */
  .wxStrip .bk.now { background: #eef2ff; border-color: #c7d2fe; }
  .wxStrip .bk.now .bn { color: #4f46e5; font-weight: 800; }
  .wxStrip .bk.past { opacity: .45; filter: saturate(.35); }   /* 今天已过时段：看得见但不抢眼 */
  @media (max-width: 760px) {
    .wxNow .wt { font-size: 32px; } .wxNow .we { font-size: 34px; }
    .wxDays .dd .de { font-size: 20px; }
    .wxStrip { gap: 3px; }
    .wxStrip .bk .be { font-size: 15px; } .wxStrip .bk .bn { font-size: 8.5px; } .wxStrip .bk .bt3 { font-size: 11px; }
  }
