/* ==========================================================================
   顶栏（.topbar）—— **前台首页 / 后台 / 学生作品页 三处共用这一个文件**

   为什么单独抽出来（2026-10-06 老师问"是不是同一个标题栏"）：
     · 以前前台那份写在 `style.css` 里、学生作品页那份是 `submit.js` **自己拼的一串内联样式**
       —— 两份实现，改一边忘一边就会"两边不一样"（老师已经抓到过高度差 2.6px）。
       现在**同一段 HTML 结构 + 同一个 CSS 文件**，物理上不可能不一致。
     · 学生作品页**不能**引 `style.css`：它带着 `*{box-sizing}`、`body{}`、`input[type]{}`、
       `.card`、`table.data` 这些**全局规则**，注入作品页会把作品自己的样式改掉
       （老师原话："点了作品看板，作品突然变宽了"）。
       所以 **这个文件必须自包含**：不许依赖 `style.css` 里的任何变量或类。
     · 作品页那份由**服务端注入**（`server.js` 的 `sendWorkPage`）而不是脚本后注入 ——
       脚本注入永远晚一帧，表现为"内容先画出来、再被顶下去"地跳一下（老师："进入作品时有跳的感觉"）。

   改这里的数字时记住：它同时影响前台、后台、作品页。
   ========================================================================== */

.topbar,
.topbar * { box-sizing: border-box; }

.topbar {
  /* ★★★ 第二百四十三批（老师 2026-10-24 定稿）：顶栏的**高度 / 字号 / 图标 / 内边距 / 圆角**都跟着
     作品同一个比例尺走（`--tb-k`）：窗口变小 → 一起变小；浏览器放大 → 一起放大。
     ⚠️ **宽度**只能是视口宽（满宽 = 视口宽，物理上限），这里不缩宽度。
     ⚠️ 前台 / 后台没有 `--hw-scale`（不引 h5kit）⇒ 兜底 1，**行为完全不变**；
        只有作品页（h5kit 会算）才真正跟着缩。
     ⚠️ 区间收在 0.88～1.14：顶栏是"框架"，不能跟作品一样大起大落。
     ★ **第二百四十六批试过"顶栏物理尺寸固定"（除以页面缩放倍数），老师看过实际效果后否掉了**
       （"这个效果不如原来的"）⇒ 已整体撤回，就是现在这一版：**跟着页面一起放大缩小**。 */
  --tb-k: clamp(0.88, var(--hw-scale, 1), 1.14);
  background: #fff;
  border-bottom: 1px solid #e5e7eb;
  position: sticky;
  top: 0;
  z-index: 50;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
  line-height: 1.6;
  color: #1f2937;
}

.topbar-inner {
  max-width: 1120px;      /* 与 --page-w 一致（那个变量在 style.css，这里写死以免依赖它） */
  margin: 0 auto;
  padding: calc(10px * var(--tb-k, 1)) calc(16px * var(--tb-k, 1));
  display: flex;
  align-items: center;
  gap: calc(12px * var(--tb-k, 1));
}

.brand { display: flex; align-items: center; gap: calc(9px * var(--tb-k, 1)); text-decoration: none; color: inherit; }
.brand:hover { text-decoration: none; }
.brand-logo {
  width: calc(30px * var(--tb-k, 1)); height: calc(30px * var(--tb-k, 1));
  border-radius: calc(8px * var(--tb-k, 1)); object-fit: contain; background: #eff4ff;
}
.brand-dot {
  width: calc(26px * var(--tb-k, 1)); height: calc(26px * var(--tb-k, 1));
  border-radius: calc(8px * var(--tb-k, 1)); background: #2563eb; color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: calc(15px * var(--tb-k, 1)); font-weight: 700;
}
.brand-name { font-size: calc(16px * var(--tb-k, 1)); font-weight: 700; letter-spacing: .3px; }
.brand-slogan { font-size: calc(12px * var(--tb-k, 1)); color: #6b7280; margin-left: calc(4px * var(--tb-k, 1)); }
.topbar-spacer { flex: 1; }

/* ⚠️ 这条把顶栏里所有链接/按钮的字号抬到 13.5px（比 `.tb-btn` 自己写的更大），
   正是它让顶栏是 54.6 高而不是 50 —— 别删，删了整条栏会变矮。 */
.topbar a,
.topbar button { font-size: calc(13.5px * var(--tb-k, 1)); }

/* 顶栏右侧的「谁在登录」与按钮。
   ⚠️ 不要换成 `style.css` 的 `.muted.small` / `.btn.btn-sm` —— 作品页引不到那个文件，
   在这里自带一份等价样式，三处才长得一样。
   ⚠️ 按钮的 `line-height` 必须是 1.6（= 原先 `.btn.btn-sm` 从 body 继承来的值）。
   写成 1.4 会让按钮矮 2.7px、整条顶栏从 54.6 变成 51.9 —— 前台的样子是老师的基准，不能变。 */
/* ★★ 第一百二十八批：身份文字**必须一行、超长省略**。
   实测（1280 宽、学生身份「危妙辰 · 华中师范大学附属小学 · 二年级(3)班 · 28 号」）：
   这段文字会被压成 3 行，把 55px 的顶栏撑到 90px，作品舞台跟着往下掉。
   ⇒ `nowrap` + 限宽 + 省略号；窄屏（≤640）本来就整段隐藏，不受影响。 */
.tb-who {
  font-size: calc(12.5px * var(--tb-k, 1)); color: #6b7280;
  min-width: 0; max-width: 46vw;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  flex: 0 1 auto;
}
/* 右侧那组按钮（教师中心 / 学生中心 / 登录 / 退出）。
   ★ 2026-10-12 第十批加的：以前顶栏右侧是**写死的两个按钮**，现在由
     `assets/session.js` 按身份重画 —— 包一层 span 才有统一间距。 */
.tb-actions { display: inline-flex; align-items: center; gap: calc(8px * var(--tb-k, 1)); }
.tb-actions:empty { display: none; }
.tb-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: calc(6px * var(--tb-k, 1));
  padding: calc(5px * var(--tb-k, 1)) calc(10px * var(--tb-k, 1));
  border-radius: calc(9px * var(--tb-k, 1)); border: 1px solid #e5e7eb; background: #fff;
  color: #1f2937; font-family: inherit; font-size: calc(13.5px * var(--tb-k, 1)); line-height: 1.6;
  cursor: pointer; text-decoration: none; white-space: nowrap;
  /* ★★ 第一百一十批（老师）："不想把按钮变长，能不能变显示在右上角，不改变按钮的大小"
     ⇒ 角标改成**绝对定位**（脱离文档流，不占宽度、不撑按钮），所以要给定位上下文。 */
  position: relative;
}
.tb-btn:hover { background: #f9fafb; text-decoration: none; }

/* ★★ 第一百零六批（老师）：学生端「学生中心」按钮上的未读红数字
   ★★ 第一百一十批（老师）：挪到**按钮右上角**，不占按钮宽度、不改变按钮大小。
      白边（box-shadow）是为了和按钮边框分开，看起来像"贴在角上"。
      0 条时元素带 hidden，不占位也不露头。 */
.tb-badge {
  position: absolute; top: calc(-6px * var(--tb-k, 1)); right: calc(-6px * var(--tb-k, 1));
  min-width: calc(16px * var(--tb-k, 1)); height: calc(16px * var(--tb-k, 1));
  padding: 0 calc(4px * var(--tb-k, 1)); border-radius: 999px;
  background: #dc2626; color: #fff; font-size: calc(10.5px * var(--tb-k, 1)); font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1; white-space: nowrap;
  box-shadow: 0 0 0 calc(2px * var(--tb-k, 1)) #fff;
  pointer-events: none;
}
.tb-badge[hidden] { display: none; }

/* --------------------------------------------------------------------------
   作品页那份：宿主作品的布局不可控（body 可能是 flex / grid 居中），
   `sticky` 会变成"跟正文并排的一个 flex item" → 用 `fixed` 脱离文档流，
   视觉上与前台完全一样（都吸顶）。
   随之而来的"会盖住正文顶部"由服务端注入的一行**首帧同步脚本**补 padding 解决
   （所以不会跳 —— 那一行在顶栏后面立刻执行，比第一次绘制还早）。
   -------------------------------------------------------------------------- */
.topbar-embedded {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 8500;
}

/* 窄屏：标语与"谁在登录"让位，保证站名和按钮不被挤出屏幕。
   （第二百四十六批曾加过 `:not(.hw-zoomed)` 把"浏览器放大"排除掉，老师否掉了"顶栏固定"，
     已撤回 —— 现在放大到很窄时也按窄屏处理，跟浏览器自己的响应式行为一致。） */
@media (max-width: 640px) {
  .brand-slogan,
  .tb-who { display: none; }
}

/* --------------------------------------------------------------------------
   ★★ 让"有没有滚动条"不再影响顶栏的**水平位置**
   （老师 2026-10-06 第三次反馈："进入后感觉往左跳了一点，我希望标题栏完全不动"）

   真机量到的数字：同一个作品页，内容溢出时 `documentElement.clientWidth = 1225`、
   不溢出时 `1240` —— 差的就是那 15px 滚动条。而 `.topbar-inner` 是**居中**的，
   于是它的 left 在 (1225−1120)/2 = 52.5 与 (1240−1120)/2 = 60 之间跳 **7.5px**。
   前台首页（作品列表，通常很短、没有滚动条）和作品页（内容长、有滚动条）正好常常是这两种状态，
   所以一进作品，标题就横向挪了一下。

   做法：**两边都预留滚动条槽位**。内容不够长时那里只是一条空白（不画轨道），
   两边可用宽度就都是"视口−15"，居中位置永远一致。
   不支持的浏览器退回 `overflow-y: scroll`（代价是常年显示一条滚动条，但同样不跳）。
   -------------------------------------------------------------------------- */
html { scrollbar-gutter: stable; }
@supports not (scrollbar-gutter: stable) {
  html { overflow-y: scroll; }
}

/* --------------------------------------------------------------------------
   ★★★ 2026-10-15（第四十批）作品页「全屏」（与 `assets/fullscreen.js` 配套）

   老师："我上传的 html 文件，可能有一个按钮，控制是全屏运行么？"
   ⇒ 平台在**作品页**顶栏给一颗「全屏」。这条规则与那颗按钮的关系：

   · `.hw-fs-on` 挂在 `<html>` 上（进全屏 / 沉浸时由 fullscreen.js 加）→ **顶栏整条收起**；
     不收起来的话，真全屏时顶上仍占着 55px，就不是"整屏"了。
   · 「退出全屏」那颗球平时**半透明**（不挡作品内容），鼠标移上去才亮 ——
     只靠 Esc 对学生（尤其小学生）不够用，得有个看得见、点得着的出口。
   · ⚠️ 这个文件必须**自包含**（作品页引不到 style.css）→ 下面的值全部写死。
   -------------------------------------------------------------------------- */
.hw-fs-on .topbar { display: none !important; }
/* ★ 第四十七批：老师在全屏状态下，应该不允许上下滑动，否则还是会影响游戏效果，退出全屏后，才能上下滑动
   ⇒ 全屏/沉浸时把**页面级**滚动关掉（舞台内部该滚还是会滚，那里是作品自己的事）。 */
html.hw-fs-on, html.hw-fs-on body { overflow: hidden !important; }
/* ★ 第二百四十三批：**全屏 + 浏览器放大**时例外 —— 那时作品按"跟着网页放大"处理（尺寸冻结），
   会比窗口大一截；再锁滚动就等于"下半截作品永远看不到"。只在这种情况下放开。 */
html.hw-zoomed.hw-fs-on, html.hw-zoomed.hw-fs-on body { overflow: auto !important; }

/* ★★★ 第四十九批：这颗球（`[data-hw-fs-exit]`）现在**一直显示**，而且**可以拖**：
   老师："全屏后我没有看到退出全屏的悬浮球……有没有可能在电脑上也能看到？
   如果有退出全屏的悬浮球，是否可以加一个进入全屏的悬浮球？悬浮球的位置是否可以随意拖动？"
   ⇒ 不再只在全屏时露出来（也不再三成透明 —— "没看到"就是这两条造成的）；
     文案由 `fullscreen.js` 按状态切换（不在全屏「全屏显示」/ 在全屏「退出全屏」）；
     默认落在**右侧中间**（不压顶栏、也不压右下角那颗「作品看板」），拖过之后位置记在 localStorage。

   ★★★ 第五十批：老师"希望设置成一个圆的，像玻璃材质的，半透明的那种，现在感觉是不透明的"
   ⇒ **圆形 + 磨砂玻璃**：半透明白底 + `backdrop-filter: blur()`（身后的天/内容透上来）、
     一圈半透明高光描边 + 内高光 + 柔和投影。文字换成**图标**（圆里放不下四个字）：
     不在全屏画"四角向外"、在全屏画"四角向内"，鼠标悬停时用 title 说明。 */
/* ★★★ 第二百三十七批（老师 2026-10-24）两条：
   ① "这个按钮是随着页面的放大而放大的，并没有随着作品变，也就是实际变化方向是相反的"
      —— 它是写死 54px 的**浮动球**，钉在窗口上，所以作品缩小时它反而显得**更大**。
      ⇒ 尺寸改成**跟着作品的比例走**：`--hw-fs-k = clamp(0.78, --hw-scale, 1.5)`
         （下限保证手指能点到，上限别占满半个屏）。
   ② "这个按钮的功能似乎不太明显……能不能在上面加上全屏两个字，等到全屏时，再加返回两个字"
      —— 从"圆球 + 图标"改成**胶囊**：图标 + 文字；文字用 `::after` 按 `.is-exit` 切换，
         不用改 `fullscreen.js`（那个类本来就在切）。 */
.hw-fs-exit {
  /* ★ 第二百三十七批：上限从 1.5 收到 **1.15** —— 它到底还是**浮在作品上**的，
     放太大就会把作品自己的按钮（「重新开始」那种满宽按钮）挡掉一半。
     ★ 第二百四十八批（老师 2026-10-24）："这个按钮还是想做成圆形的" ——
     从胶囊改回**正圆**，但要保住第 237 批加的「全屏 / 返回」两个字 ⇒ **图标在上、文字在下**，
     直径 64 设计像素（图标 22 + 缝 2 + 文字 11 ≈ 35，圆里放得开）。 */
  --hw-fs-k: clamp(0.82, var(--hw-scale, 1), 1.15);
  box-sizing: border-box;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(2px * var(--hw-fs-k));
  position: fixed;
  top: 46%;
  right: 12px;
  z-index: 8600;              /* 顶栏是 8500 —— 这颗球要在它上面 */
  width: calc(64px * var(--hw-fs-k));
  height: calc(64px * var(--hw-fs-k));
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .62);
  border-radius: 50%;
  background: rgba(255, 255, 255, .3);
  /* ⚠️ 半透明底 + 磨砂：`backdrop-filter` 只有背景**不完全不透明**时才看得出效果 */
  -webkit-backdrop-filter: blur(10px) saturate(1.6);
  backdrop-filter: blur(10px) saturate(1.6);
  color: #16324f;
  font-family: inherit;
  font-size: calc(11px * var(--hw-fs-k));
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  box-shadow: 0 6px 18px rgba(15, 23, 42, .18), inset 0 1px 0 rgba(255, 255, 255, .75);
  cursor: grab;
  opacity: 1;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;         /* 拖动时别让页面跟着滚 */
  transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}
/* 两个字：不在全屏「全屏」、在全屏「返回」 */
.hw-fs-exit::after { content: "全屏"; }
.hw-fs-exit.is-exit::after { content: "返回"; }
.hw-fs-exit svg.hw-fs-ico {
  width: calc(22px * var(--hw-fs-k));
  height: calc(22px * var(--hw-fs-k));
  flex: none;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* 两个图标只露一个：不在全屏 → "向外"；在全屏 → "向内"
   ⚠️ 选择器要带上 `svg.` —— 上面那条 `.hw-fs-exit svg.hw-fs-ico{display:block}` 比
   `.hw-fs-exit .hw-fs-ico-out` 更具体，不加 `svg.` 压不住它 ⇒ **两个图标会同时出现**（真机量出来的）。 */
.hw-fs-exit svg.hw-fs-ico-out { display: none; }
.hw-fs-exit.is-exit svg.hw-fs-ico-in { display: none; }
.hw-fs-exit.is-exit svg.hw-fs-ico-out { display: block; }
.hw-fs-exit:hover {
  background: rgba(255, 255, 255, .52);
  border-color: rgba(255, 255, 255, .9);
}
.hw-fs-exit.hw-fs-drag { cursor: grabbing; box-shadow: 0 10px 26px rgba(15, 23, 42, .3); }
/* ★ 第四十六批：触屏设备没有 hover，所以小屏 / 无指针设备上点按区域再放大一点。
   ★ 第二百三十七批：不再写死 64px（那会盖掉"跟着作品缩放"），只把**下限**抬到 1：
   `--hw-fs-k` 最小 1 ⇒ 54px 起，手指点得着；作品放大时照样跟着放大。 */
@media (max-width: 640px), (hover: none) {
  .hw-fs-exit {
    --hw-fs-k: clamp(1, var(--hw-scale, 1), 1.15);
    box-shadow: 0 8px 22px rgba(15, 23, 42, .22), inset 0 1px 0 rgba(255, 255, 255, .8);
  }
}

/* --------------------------------------------------------------------------
   分享弹窗（老师 2026-10-19 第七十六批：作品要能通过微信分享）

   为什么弹窗而不是"直接调微信"：朋友圈**不能由网页自己发**（公众号推文也一样，
   都是用户自己在微信里点右上角 ···）。所以这里给的是**最短路径**：
   在微信里 → 告诉他点右上角；不在微信里 → 给二维码，扫码就在微信里打开了。

   ⚠️ z-index 要比顶栏（8500）和全屏悬浮球（8600）都高，否则弹窗被压在下面。
   -------------------------------------------------------------------------- */
.hw-share { position: fixed; inset: 0; z-index: 9000; display: flex; align-items: center; justify-content: center; padding: 16px; }
.hw-share[hidden] { display: none; }
.hw-share-mask { position: absolute; inset: 0; background: rgba(15, 23, 42, .46); }
.hw-share-card {
  position: relative; width: 100%; max-width: 340px; margin: 0 auto;
  background: #fff; border-radius: 16px; padding: 20px 18px 16px;
  box-shadow: 0 22px 60px rgba(15, 23, 42, .30);
  text-align: center; font-family: inherit; color: #1f2937;
}
.hw-share-x {
  position: absolute; top: 6px; right: 8px; width: 30px; height: 30px;
  border: 0; border-radius: 8px; background: transparent; color: #9ca3af;
  font-size: 20px; line-height: 1; cursor: pointer;
}
.hw-share-x:hover { background: #f3f4f6; color: #4b5563; }
.hw-share-h { margin: 0 0 6px; font-size: 17px; font-weight: 700; }
.hw-share-sub { margin: 0 0 14px; font-size: 13px; color: #6b7280; line-height: 1.55; }
.hw-share-qr {
  display: flex; align-items: center; justify-content: center;
  padding: 8px; border-radius: 12px; background: #fff; border: 1px solid #eef1f6;
}
.hw-share-qr img { display: block; width: 200px; height: 200px; border-radius: 6px; }
.hw-share-qr img:not([src]) { width: 200px; height: 200px; background: #f3f4f6; }
.hw-share-url { margin-top: 12px; }
.hw-share-url input {
  width: 100%; box-sizing: border-box; padding: 8px 10px; border-radius: 10px;
  border: 1px solid #e5e7eb; background: #f9fafb; color: #374151;
  font-size: 12.5px; font-family: inherit; text-align: center;
}
.hw-share-url input:focus { outline: none; border-color: #93c5fd; background: #fff; }
.hw-share-btns { display: flex; gap: 8px; margin-top: 12px; }
.hw-share-btn {
  flex: 1 1 0; padding: 9px 8px; border-radius: 10px; border: 1px solid #e5e7eb;
  background: #fff; color: #1f2937; font-family: inherit; font-size: 13.5px;
  line-height: 1.5; cursor: pointer; white-space: nowrap;
}
.hw-share-btn:hover { background: #f9fafb; }
.hw-share-btn-main { background: #2563eb; border-color: #2563eb; color: #fff; }
.hw-share-btn-main:hover { background: #1d4ed8; }
.hw-share-btn[hidden] { display: none; }
.hw-share-tip { margin: 10px 0 0; font-size: 12.5px; color: #6b7280; line-height: 1.6; }
.hw-share-tip[hidden] { display: none; }

/* 顶栏按钮多了「分享」一颗 —— 窄屏别把站名挤成好几行（挤扁品牌名会让整条栏从 55 变 117）。
   （第二百四十六批那套"放大时不算窄屏"的补丁已按老师要求撤回。） */
@media (max-width: 640px) {
  .topbar-inner { gap: 8px; padding: 10px 12px; }
  .brand-name { font-size: 15px; }
}
/* ⚠️ 品牌名**不许被压**：它是 flex 项，允许收缩时会被挤成"慧/玩/云/2.0"四行，
   整条顶栏跟着长高（实测 360 宽时 55 → 117）。所以给它 nowrap + 不收缩，
   再由下面那条"窄到放不下就只留 LOGO"的规则兜底。 */
.brand { flex-shrink: 0; }
.brand-name { white-space: nowrap; }
.tb-actions { flex-shrink: 0; }
.tb-btn { flex-shrink: 0; }
@media (max-width: 480px) {
  .brand-name { display: none; }
  .topbar-inner { gap: 6px; padding: 10px 10px; }
  .tb-btn { padding: 5px 8px; }
}
/* 320 宽（老 iPhone SE / 小屏安卓）四颗按钮还差十来个像素 —— 再收一点内边距与字号 */
@media (max-width: 360px) {
  .topbar-inner { gap: 5px; padding: 10px 8px; }
  .tb-btn { padding: 5px 6px; font-size: 12.5px; }
}
